From 763fc61aef841bc4ffc5c293013e3df52cee5ff2 Mon Sep 17 00:00:00 2001 From: Javier Pena Date: Fri, 23 Jan 2015 17:58:15 +0100 Subject: [PATCH] Add Pacemaker service wrapper This patch adds a service wrapper based on the existing support from stackforge/puppet-openstack_extras. It allows wrapping an OpenStack service as a Pacemaker resource, including options for cloned resources, resource colocation and resource start ordering. Change-Id: Iccfebb758874f53d8e6a0d1aaf4c0368dda74dce --- manifests/clustering/pacemaker_colocation.pp | 56 +++++++++ manifests/clustering/pacemaker_order.pp | 56 +++++++++ manifests/clustering/pacemaker_service.pp | 113 ++++++++++++++++++ ...ud_clustering_pacemaker_colocation_spec.rb | 47 ++++++++ .../cloud_clustering_pacemaker_order_spec.rb | 49 ++++++++ ...cloud_clustering_pacemaker_service_spec.rb | 92 ++++++++++++++ 6 files changed, 413 insertions(+) create mode 100644 manifests/clustering/pacemaker_colocation.pp create mode 100644 manifests/clustering/pacemaker_order.pp create mode 100644 manifests/clustering/pacemaker_service.pp create mode 100644 spec/defines/cloud_clustering_pacemaker_colocation_spec.rb create mode 100644 spec/defines/cloud_clustering_pacemaker_order_spec.rb create mode 100644 spec/defines/cloud_clustering_pacemaker_service_spec.rb diff --git a/manifests/clustering/pacemaker_colocation.pp b/manifests/clustering/pacemaker_colocation.pp new file mode 100644 index 00000000..ce433ffe --- /dev/null +++ b/manifests/clustering/pacemaker_colocation.pp @@ -0,0 +1,56 @@ +# +# Copyright (C) 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Configure a Pacemaker colocation rule +# +# === Parameters +# +# [*service*] +# (required) Name of the service to be colocated with others +# Defaults to $name +# +# [*colocated_with*] +# (optional) List of services to be colocated with service1 +# Should be an array. +# Defaults to [] +# +# [*order*] +# (optional) Do not use in a manifest. It is used to iterate +# through the list of services to be colocated with $service. +# Defaults to '0' + +define cloud::clustering::pacemaker_colocation( + $service = $name, + $colocated_with = [], + $order = '0' +) { + $service1 = inline_template('<%= @colocated_with[@order.to_i] %>') + if $service1 { + $colocation_name = "${service}-with-${service1}" + + cs_colocation { $colocation_name : + primitives => [ "p_${service}", "p_${service1}" ], + } + + $neworder = inline_template('<%= @order.to_i + 1 %>') + + cloud::clustering::pacemaker_colocation { "${service}-${neworder}": + service => $service, + colocated_with => $colocated_with, + order => $neworder + } + } +} + diff --git a/manifests/clustering/pacemaker_order.pp b/manifests/clustering/pacemaker_order.pp new file mode 100644 index 00000000..103cb5f9 --- /dev/null +++ b/manifests/clustering/pacemaker_order.pp @@ -0,0 +1,56 @@ +# +# Copyright (C) 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Configure a Pacemaker order constraint +# +# === Parameters +# +# [*first*] +# (required) List of services to be executed before $service +# Should be an array. +# Defaults to [] +# +# [*service*] +# (optional) Service to be executed after all services in $first +# Defaults to $name +# +# [*order*] +# (optional) Do not use in a manifest. It is used to iterate +# through the list of services to be executed before $service. +# Defaults to '0' + +define cloud::clustering::pacemaker_order( + $first = [], + $service = $name, + $order = '0' +) { + $service1 = inline_template('<%= @first[@order.to_i] %>') + if $service1 { + $order_name = "${service1}-before-${service}" + + cs_order { $order_name : + first => "p_${service1}", + second => "p_${service}", + } + + $neworder = inline_template('<%= @order.to_i + 1 %>') + + cloud::clustering::pacemaker_order { "${service}-${neworder}": + first => $first, + service => $service, + order => $neworder + } + } +} diff --git a/manifests/clustering/pacemaker_service.pp b/manifests/clustering/pacemaker_service.pp new file mode 100644 index 00000000..8e0a0214 --- /dev/null +++ b/manifests/clustering/pacemaker_service.pp @@ -0,0 +1,113 @@ +# +# Copyright (C) 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Configure a service to be controlled by Pacemaker +# +# +# === Parameters +# +# [*service_name*] +# (optional) Name of the service to be put under Pacemaker control +# Defaults to $name +# +# [*primitive_class*] +# (optional) Pacemaker primitive class +# Defaults to 'systemd' +# +# [*primitive_provider*] +# (optional) Pacemaker primitive provider for OCF scripts +# Examples: 'ocf','heartbeat' +# Defaults to false +# +# [*primitive_type*] +# (optional) The type of the primitive: OCF file name, or operating +# system-native service if using systemd, upstart or lsb as +# primitive_class +# Defaults to $service_name +# +# [*clone*] +# (optional) Create a cloned resource +# Defaults to false +# +# [*colocated_services*] +# (optional) A list of resources that should be colocated with this +# one +# Example: ["service2","service3"] +# Defaults to [] +# +# [*start_after*] +# (optional) A list of resources that should be started before this +# resource can be started. This will create a set of order constraints +# where every resourece in $start_after should be started before this +# resource can start +# Example: ["service2","service3"] +# Defaults to [] +# +# [*requires*] +# (optional) A list of required Puppet resources +# Defaults to [] +# +# Example: +# cloud::clustering::pacemaker_service { 'openstack-glance-api' : +# service_name => 'openstack-glance-api', +# primitive_class => 'systemd', +# primitive_provider => false, +# primitive_type => 'openstack-glance-api', +# clone => false, +# colocated_services => ["openstack-keystone"], +# start_after => ["openstack-keystone"], +# requires => Package['openstack-glance'], +# } + + +define cloud::clustering::pacemaker_service ( + $service_name = $name, + $primitive_class = 'systemd', + $primitive_provider = false, + $primitive_type = $service_name, + $clone = false, + $colocated_services = [], + $start_after = [], + $requires = [], +) { + + openstack_extras::pacemaker::service { $service_name : + ensure => present, + metadata => {}, + ms_metadata => {}, + operations => {}, + parameters => {}, + primitive_class => $primitive_class, + primitive_provider => $primitive_provider, + primitive_type => $primitive_type, + use_handler => false, + clone => $clone, + require => $requires, + } + + if $colocated_services { + cloud::clustering::pacemaker_colocation { $service_name : + service => $service_name, + colocated_with => $colocated_services + } + } + + if $start_after { + cloud::clustering::pacemaker_order { $service_name : + first => $start_after, + service => $service_name + } + } +} diff --git a/spec/defines/cloud_clustering_pacemaker_colocation_spec.rb b/spec/defines/cloud_clustering_pacemaker_colocation_spec.rb new file mode 100644 index 00000000..d8736aeb --- /dev/null +++ b/spec/defines/cloud_clustering_pacemaker_colocation_spec.rb @@ -0,0 +1,47 @@ + +# +# Copyright (C) 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Spec tests for cloud::clustering::pacemaker_colocation + +require 'spec_helper' + +describe 'cloud::clustering::pacemaker_colocation', :type => :define do + + let (:title) { 'service1' } + + let :params do + { + :service => 'service1', + :colocated_with => ['service2','service3'] + } + end + + context 'with default parameters' do + it 'should create a colocation constraint' do + should contain_cs_colocation('service1-with-service2').with( + { + 'primitives' => ["p_service1", "p_service2"], + } + ) + + should contain_cs_colocation('service1-with-service3').with( + { + 'primitives' => ["p_service1", "p_service3"], + } + ) + end + end +end diff --git a/spec/defines/cloud_clustering_pacemaker_order_spec.rb b/spec/defines/cloud_clustering_pacemaker_order_spec.rb new file mode 100644 index 00000000..6beb6994 --- /dev/null +++ b/spec/defines/cloud_clustering_pacemaker_order_spec.rb @@ -0,0 +1,49 @@ + +# +# Copyright (C) 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Spec tests for cloud::clustering::pacemaker_order + +require 'spec_helper' + +describe 'cloud::clustering::pacemaker_order', :type => :define do + + let (:title) { 'service1' } + + let :params do + { + :service => 'service1', + :first => ['service2','service3'] + } + end + + context 'with default parameters' do + it 'should create two order constraints' do + should contain_cs_order('service2-before-service1').with( + { + 'first' => "p_service2", + 'second' => "p_service1" + } + ) + + should contain_cs_order('service3-before-service1').with( + { + 'first' => "p_service3", + 'second' => "p_service1" + } + ) + end + end +end diff --git a/spec/defines/cloud_clustering_pacemaker_service_spec.rb b/spec/defines/cloud_clustering_pacemaker_service_spec.rb new file mode 100644 index 00000000..bb224434 --- /dev/null +++ b/spec/defines/cloud_clustering_pacemaker_service_spec.rb @@ -0,0 +1,92 @@ + +# +# Copyright (C) 2015 Red Hat Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Spec tests for cloud::clustering::pacemaker_service + +require 'spec_helper' + +describe 'cloud::clustering::pacemaker_service', :type => :define do + + let :pre_condition do + "service { ['foo-api','bar-api']: + ensure => running + }" + end + + let (:title) { 'foo-api' } + + let :params do + { + :service_name => 'foo-api', + :primitive_class => 'systemd', + :primitive_provider => false, + :primitive_type => 'foo-api', + :clone => false, + :colocated_services => [], + :start_after => [], + :requires => [] + } + end + + context 'with default parameters' do + it 'should create a Pacemaker service' do + should contain_openstack_extras__pacemaker__service('foo-api').with( + { + 'ensure' => :present, + 'primitive_class' => params[:primitive_class], + 'primitive_provider' => params[:primitive_provider], + 'primitive_type' => params[:primitive_type], + 'clone' => params[:clone], + 'require' => params[:requires] + } + ) + end + end + + context 'with colocated services and start ordering' do + before :each do + params.merge!( + :colocated_services => ["bar-api"], + :start_after => ["foo-api"], + ) + end + + it 'creates a colocation constraint' do + is_expected.to contain_cloud__clustering__pacemaker_colocation('foo-api') + end + + it 'creates an order constraint' do + is_expected.to contain_cloud__clustering__pacemaker_order('foo-api') + end + end + + context 'with clone=true' do + before :each do + params.merge!( + :clone => true, + ) + end + + it 'creates a cloned resource' do + is_expected.to contain_openstack_extras__pacemaker__service('foo-api').with( + { + 'clone' => :true + } + ) + end + end + +end