commit 85b08983de89e0cdce7512f3eea41dc2efe99194 Author: Robert Date: Mon Apr 15 17:27:39 2013 +0900 initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..fc68a4e --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +Description +=========== +This is a cookbook for installing and configuring pacemaker. + +Recipes +======= +default +------- +Installs and start `pacemaker`. + +config +------- +Configures pacemaker resources such as primitive, location, colocation and order. + +Resources/Providers +=================== +There are 7 LWRPs for interacting with pacemaker. + +primitive +---------- +Configure and delete primitive resource. + +- `:create` configures a `primitive` +- `:delete` deletes a `primitive` + +### Examples +``` ruby +pacemaker_primitive drbd do + agent "ocf:linbit:drbd" + params {'drbd_resource' => 'r0'} + op {'monitor' => { 'interval' => '5s', 'role' => 'Master' } } + action :create +end +``` + +License and Author +================== + +Author:: Robert Choi + +Copyright:: 2013 Robert Choi + +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. diff --git a/attributes/default.rb b/attributes/default.rb new file mode 100644 index 0000000..a18b22b --- /dev/null +++ b/attributes/default.rb @@ -0,0 +1,76 @@ +default['pacemaker']['nodes'] = ['node1', 'node2'] + +default['pacemaker']['primitive']['drbd']['agent'] = "ocf:linbit:drbd" +default['pacemaker']['primitive']['drbd']['params']['drbd_resource'] = "pair" +default['pacemaker']['primitive']['drbd']['op']['monitor']['interval'] = "5s" +default['pacemaker']['primitive']['drbd']['op']['monitor']['role'] = "Master" +default['pacemaker']['primitive']['drbd']['active'] = ["node1", "node2"] + +default['pacemaker']['primitive']['cinder-volume']['agent'] = "ocf:openstack:cinder-volume" +default['pacemaker']['primitive']['cinder-volume']['meta']['is-managed'] = "true" +default['pacemaker']['primitive']['cinder-volume']['meta']['target-role'] = "Started" +default['pacemaker']['primitive']['cinder-volume']['op']['monitor']['interval'] = "10s" +default['pacemaker']['primitive']['cinder-volume']['active'] = ["node1", "node2"] + +default['pacemaker']['primitive']['clvm']['agent'] = "ocf:lvm2:clvmd" +default['pacemaker']['primitive']['clvm']['params']['daemon_timeout'] = "30" +default['pacemaker']['primitive']['clvm']['op']['monitor']['interval'] = "10s" +default['pacemaker']['primitive']['clvm']['active'] = ["node1", "node2"] + +# Temporary attribute for vip resource. +# Later, vip address will be set by 'ktc-cinder' cookcook and be fetched here. +default['pacemaker']['primitive']['vip']['agent'] = "ocf:heartbeat:IPaddr2" +default['pacemaker']['primitive']['vip']['params']['ip'] = "10.5.2.200" +default['pacemaker']['primitive']['vip']['params']['cidr_netmask'] = "24" +default['pacemaker']['primitive']['vip']['op']['monitor']['interval'] = "3s" +default['pacemaker']['primitive']['vip']['op']['monitor']['nic'] = "eth0" +default['pacemaker']['primitive']['vip']['meta']['target-role'] = "Started" +default['pacemaker']['primitive']['vip']['active'] = ["node1", "node2"] + +default['pacemaker']['primitive']['st-node1']['agent'] = "stonith:null" +default['pacemaker']['primitive']['st-node1']['params']['hostlist'] = "node1" +default['pacemaker']['primitive']['st-node1']['active'] = ["node2"] + +default['pacemaker']['primitive']['st-node2']['agent'] = "stonith:null" +default['pacemaker']['primitive']['st-node2']['params']['hostlist'] = "node2" +default['pacemaker']['primitive']['st-node2']['active'] = ["node1"] + +default['pacemaker']['location']['l-st-node1']['rsc_name'] = "st-node1" +default['pacemaker']['location']['l-st-node1']['priority'] = "-inf" +default['pacemaker']['location']['l-st-node1']['node'] = "node1" +default['pacemaker']['location']['l-st-node1']['active'] = ["node2"] + +default['pacemaker']['location']['l-st-node2']['rsc_name'] = "st-node2" +default['pacemaker']['location']['l-st-node2']['priority'] = "-inf" +default['pacemaker']['location']['l-st-node2']['node'] = "node2" +default['pacemaker']['location']['l-st-node2']['active'] = ["node1"] + +default['pacemaker']['ms']['drbd-cluster']['rsc_name'] = "drbd" +default['pacemaker']['ms']['drbd-cluster']['meta']['master-max'] = "2" +default['pacemaker']['ms']['drbd-cluster']['meta']['master-node-max'] = "1" +default['pacemaker']['ms']['drbd-cluster']['meta']['clone-max'] = "2" +default['pacemaker']['ms']['drbd-cluster']['meta']['clone-node-max'] = "1" +default['pacemaker']['ms']['drbd-cluster']['meta']['notify'] = "true" +default['pacemaker']['ms']['drbd-cluster']['meta']['target-role'] = "Started" +default['pacemaker']['ms']['drbd-cluster']['active'] = ["node1", "node2"] + +default['pacemaker']['clone']['clvm-clone']['rsc_name'] = "clvm" +default['pacemaker']['clone']['clvm-clone']['meta']['globally-unique'] = "false" +default['pacemaker']['clone']['clvm-clone']['meta']['interleave'] = "true" +default['pacemaker']['clone']['clvm-clone']['meta']['ordered'] = "true" +default['pacemaker']['clone']['clvm-clone']['active'] = ["node1", "node2"] + +default['pacemaker']['colocation']['c-cinder-volume']['priority'] = "inf" +default['pacemaker']['colocation']['c-cinder-volume']['is_multiple'] = "yes" + +# Single colocation (if multiple is 'no') +default['pacemaker']['colocation']['c-cinder-volume']['rsc'] = nil +default['pacemaker']['colocation']['c-cinder-volume']['with_rsc'] = nil + +# Multiple colocation (if multiple is 'yes') +default['pacemaker']['colocation']['c-cinder-volume']['multiple_rscs'] = ['drbd-cluster', 'vip', 'cinder-volume'] +default['pacemaker']['colocation']['c-cinder-volume']['active'] = ["node1", "node2"] + +default['pacemaker']['order']['o-lvm']['priority'] = "inf" +default['pacemaker']['order']['o-lvm']['resources'] = ['drbd-cluster', 'clvm-clone', 'vip', 'cinder-volume'] +default['pacemaker']['order']['o-lvm']['active'] = ["node1", "node2"] diff --git a/files/default/cinder-volume b/files/default/cinder-volume new file mode 100644 index 0000000..23dbbb6 --- /dev/null +++ b/files/default/cinder-volume @@ -0,0 +1,327 @@ +#!/bin/sh +# +# +# OpenStack Cinder Volume (cinder-volume) +# +# Description: Manages an OpenStack Volumes (cinder-volume) process as an HA resource +# +# Authors: Sébastien Han +# Mainly inspired by the Glance API resource agent written by Martin Gerhard Loschwitz from Hastexo: http://goo.gl/whLpr +# +# Support: openstack@lists.launchpad.net +# License: Apache Software License (ASL) 2.0 +# +# +# See usage() function below for more details ... +# +# OCF instance parameters: +# OCF_RESKEY_binary +# OCF_RESKEY_config +# OCF_RESKEY_user +# OCF_RESKEY_pid +# OCF_RESKEY_amqp_server_port +# OCF_RESKEY_additional_parameters +####################################################################### +# Initialization: + +: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} +. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs + +####################################################################### + +# Fill in some defaults if no values are specified + +OCF_RESKEY_binary_default="cinder-volume" +OCF_RESKEY_config_default="/etc/cinder/cinder.conf" +OCF_RESKEY_user_default="cinder" +OCF_RESKEY_pid_default="$HA_RSCTMP/$OCF_RESOURCE_INSTANCE.pid" +OCF_RESKEY_amqp_server_port_default="5672" + +: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}} +: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}} +: ${OCF_RESKEY_user=${OCF_RESKEY_user_default}} +: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}} +: ${OCF_RESKEY_amqp_server_port=${OCF_RESKEY_amqp_server_port_default}} + +####################################################################### + +usage() { + cat < + + +1.0 + + +Resource agent for the OpenStack Cinder Volume (cinder-volume) +May manage a cinder-volume instance or a clone set that +creates a distributed cinder-volume cluster. + +Manages the OpenStack Cinder Volume (cinder-volume) + + + + +Location of the OpenStack Cinder Volume server binary (cinder-volume) + +OpenStack Cinder Volume server binary (cinder-volume) + + + + + +Location of the OpenStack Cinder Volume (cinder-volume) configuration file + +OpenStack Cinder Volume (cinder-volume) config file + + + + + +User running OpenStack Cinder Volume (cinder-volume) + +OpenStack Cinder Volume (cinder-volume) user + + + + + +The pid file to use for this OpenStack Cinder Volume (cinder-volume) instance + +OpenStack Cinder Volume (cinder-volume) pid file + + + + + +The listening port number of the AMQP server. Mandatory to perform a monitor check + +AMQP listening port + + + + + + +Additional parameters to pass on to the OpenStack Cinder Volume (cinder-volume) + +Additional parameters for cinder-volume + + + + + + + + + + + + + + +END +} + +####################################################################### +# Functions invoked by resource manager actions + +cinder_volume_validate() { + local rc + + check_binary $OCF_RESKEY_binary + check_binary netstat + + # A config file on shared storage that is not available + # during probes is OK. + if [ ! -f $OCF_RESKEY_config ]; then + if ! ocf_is_probe; then + ocf_log err "Config $OCF_RESKEY_config doesn't exist" + return $OCF_ERR_INSTALLED + fi + ocf_log_warn "Config $OCF_RESKEY_config not available during a probe" + fi + + getent passwd $OCF_RESKEY_user >/dev/null 2>&1 + rc=$? + if [ $rc -ne 0 ]; then + ocf_log err "User $OCF_RESKEY_user doesn't exist" + return $OCF_ERR_INSTALLED + fi + + true +} + +cinder_volume_status() { + local pid + local rc + + if [ ! -f $OCF_RESKEY_pid ]; then + ocf_log info "OpenStack Cinder Volume (cinder-volume) is not running" + return $OCF_NOT_RUNNING + else + pid=`cat $OCF_RESKEY_pid` + fi + + ocf_run -warn kill -s 0 $pid + rc=$? + if [ $rc -eq 0 ]; then + return $OCF_SUCCESS + else + ocf_log info "Old PID file found, but OpenStack Cinder Volume (cinder-volume) is not running" + return $OCF_NOT_RUNNING + fi +} + +cinder_volume_monitor() { + local rc + local pid + local volume_amqp_check + + cinder_volume_status + rc=$? + + # If status returned anything but success, return that immediately + if [ $rc -ne $OCF_SUCCESS ]; then + return $rc + fi + + # Check the connections according to the PID + # We are sure to hit the scheduler process and not other nova process with the same connection behavior (for example nova-cert) + + pid=`cat $OCF_RESKEY_pid` + # check the connections according to the PID + volume_amqp_check=`netstat -punt | grep -s "$OCF_RESKEY_amqp_server_port" | grep -s "$pid" | grep -qs "ESTABLISHED"` + rc=$? + if [ $rc -ne 0 ]; then + ocf_log err "Cinder Volume is not connected to the AMQP server: $rc" + return $OCF_NOT_RUNNING + fi + + ocf_log debug "OpenStack Cinder Volume (cinder-volume) monitor succeeded" + return $OCF_SUCCESS +} + +cinder_volume_start() { + local rc + + cinder_volume_status + rc=$? + if [ $rc -eq $OCF_SUCCESS ]; then + ocf_log info "OpenStack Cinder Volume (cinder-volume) already running" + return $OCF_SUCCESS + fi + + # run the actual cinder-volume daemon. Don't use ocf_run as we're sending the tool's output + # straight to /dev/null anyway and using ocf_run would break stdout-redirection here. + su ${OCF_RESKEY_user} -s /bin/sh -c "${OCF_RESKEY_binary} --config-file=$OCF_RESKEY_config \ + $OCF_RESKEY_additional_parameters"' >> /dev/null 2>&1 & echo $!' > $OCF_RESKEY_pid + + # Spin waiting for the server to come up. + # Let the CRM/LRM time us out if required + while true; do + cinder_volume_monitor + rc=$? + [ $rc -eq $OCF_SUCCESS ] && break + if [ $rc -ne $OCF_NOT_RUNNING ]; then + ocf_log err "OpenStack Cinder Volume (cinder-volume) start failed" + exit $OCF_ERR_GENERIC + fi + sleep 1 + done + + ocf_log info "OpenStack Cinder Volume (cinder-volume) started" + return $OCF_SUCCESS +} + +cinder_volume_stop() { + local rc + local pid + + cinder_volume_status + rc=$? + if [ $rc -eq $OCF_NOT_RUNNING ]; then + ocf_log info "OpenStack Cinder Volume (cinder-volume) already stopped" + return $OCF_SUCCESS + fi + + # Try SIGTERM + pid=`cat $OCF_RESKEY_pid` + ocf_run kill -s TERM $pid + rc=$? + if [ $rc -ne 0 ]; then + ocf_log err "OpenStack Cinder Volume (cinder-volume) couldn't be stopped" + exit $OCF_ERR_GENERIC + fi + + # stop waiting + shutdown_timeout=15 + if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then + shutdown_timeout=$((($OCF_RESKEY_CRM_meta_timeout/1000)-5)) + fi + count=0 + while [ $count -lt $shutdown_timeout ]; do + cinder_volume_status + rc=$? + if [ $rc -eq $OCF_NOT_RUNNING ]; then + break + fi + count=`expr $count + 1` + sleep 1 + ocf_log debug "OpenStack Cinder Volume (cinder-volume) still hasn't stopped yet. Waiting ..." + done + + cinder_volume_status + rc=$? + if [ $rc -ne $OCF_NOT_RUNNING ]; then + # SIGTERM didn't help either, try SIGKILL + ocf_log info "OpenStack Cinder Volume (cinder-volume) failed to stop after ${shutdown_timeout}s \ + using SIGTERM. Trying SIGKILL ..." + ocf_run kill -s KILL $pid + fi + + ocf_log info "OpenStack Cinder Volume (cinder-volume) stopped" + + rm -f $OCF_RESKEY_pid + + return $OCF_SUCCESS +} + +####################################################################### + +case "$1" in + meta-data) meta_data + exit $OCF_SUCCESS;; + usage|help) usage + exit $OCF_SUCCESS;; +esac + +# Anything except meta-data and help must pass validation +cinder_volume_validate || exit $? + +# What kind of method was invoked? +case "$1" in + start) cinder_volume_start;; + stop) cinder_volume_stop;; + status) cinder_volume_status;; + monitor) cinder_volume_monitor;; + validate-all) ;; + *) usage + exit $OCF_ERR_UNIMPLEMENTED;; +esac diff --git a/metadata.rb b/metadata.rb new file mode 100644 index 0000000..f22b9fe --- /dev/null +++ b/metadata.rb @@ -0,0 +1,7 @@ +name "pacemaker" +maintainer "Robert Choi" +maintainer_email "taeilchoi1@gmail.com" +license "Apache 2.0" +description "Installs/Configures Pacemaker" +long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) +version "0.1" diff --git a/providers/clone.rb b/providers/clone.rb new file mode 100644 index 0000000..5e73b90 --- /dev/null +++ b/providers/clone.rb @@ -0,0 +1,57 @@ +# Author:: Robert Choi +# Cookbook Name:: pacemaker +# Provider:: clone +# +# Copyright:: 2013, Robert Choi +# +# 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. +# + +require ::File.join(::File.dirname(__FILE__), 'helper') + +action :create do + name = new_resource.name + rsc = new_resource.rsc + + unless resource_exists?(name) + cmd = "crm configure clone #{name} #{rsc}" + + if new_resource.meta + cmd << " meta" + new_resource.meta.each do |key, value| + cmd << " #{key}=\"#{value}\"" + end + end + + e = execute "configure clone #{name}" do + command cmd + end + + new_resource.updated_by_last_action(true) + Chef::Log.info "configured clone '#{name}'." + end +end + +action :delete do + name = new_resource.name + cmd = "crm resource stop #{name}; crm configure delete #{name}" + + e = execute "delete clone #{name}" do + command cmd + only_if { resource_exists?(name) } + end + + new_resource.updated_by_last_action(true) + Chef::Log.info "Deleted clone '#{name}'." + +end diff --git a/providers/colocation.rb b/providers/colocation.rb new file mode 100644 index 0000000..24ee83a --- /dev/null +++ b/providers/colocation.rb @@ -0,0 +1,68 @@ +# Author:: Robert Choi +# Cookbook Name:: pacemaker +# Provider:: colocation +# +# Copyright:: 2013, Robert Choi +# +# 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. +# + +require ::File.join(::File.dirname(__FILE__), 'helper') + +action :create do + name = new_resource.name + priority = new_resource.priority + multiple = new_resource.multiple + + unless resource_exists?(name) + if multiple + multiple_rscs = new_resource.multiple_rscs + + cmd = "crm configure colocation #{name} #{priority}:" + multiple_rscs.each do |rsc| + cmd << " #{rsc}" + end + + e = execute "configure colocation #{name}" do + command cmd + end + + new_resource.updated_by_last_action(true) + Chef::Log.info "Configured colocation '#{name}'." + else + rsc = new_resource.rsc + with_rsc = new_resource.with_rsc + + cmd = "crm configure colocation #{name} #{priority}: #{rsc} #{with_rsc}" + e = execute "configure colocation #{name}" do + command cmd + end + + new_resource.updated_by_last_action(true) + Chef::Log.info "Configured colocation '#{name}'." + end + end +end + +action :delete do + name = new_resource.name + cmd = "crm resource stop #{name}; crm configure delete #{name}" + + e = execute "delete colocation #{name}" do + command cmd + only_if { resource_exists?(name) } + end + + new_resource.updated_by_last_action(true) + Chef::Log.info "Deleted colocation '#{name}'." +end diff --git a/providers/helper.rb b/providers/helper.rb new file mode 100644 index 0000000..9c9a46f --- /dev/null +++ b/providers/helper.rb @@ -0,0 +1,11 @@ +def resource_exists?(name) + cmd = Mixlib::ShellOut.new("crm configure show | grep #{name}") + cmd.environment['HOME'] = ENV.fetch('HOME', '/root') + cmd.run_command + begin + cmd.error! + true + rescue + false + end +end diff --git a/providers/location.rb b/providers/location.rb new file mode 100644 index 0000000..67ea394 --- /dev/null +++ b/providers/location.rb @@ -0,0 +1,51 @@ +# Author:: Robert Choi +# Cookbook Name:: pacemaker +# Provider:: location +# +# Copyright:: 2013, Robert Choi +# +# 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. +# + +require ::File.join(::File.dirname(__FILE__), 'helper') + +action :create do + name = new_resource.name + rsc = new_resource.rsc + priority = new_resource.priority + node = new_resource.node + + unless resource_exists?(name) + cmd = "crm configure location #{name} #{rsc} #{priority}: #{node}" + + e = execute "configure location #{name}" do + command cmd + end + + new_resource.updated_by_last_action(true) + Chef::Log.info "Configured location '#{name}'." + end +end + +action :delete do + name = new_resource.name + cmd = "crm resource stop #{name}; crm configure delete #{name}" + + e = execute "delete location #{name}" do + command cmd + only_if { resource_exists?(name) } + end + + new_resource.updated_by_last_action(e.updated?) + Chef::Log.info "Deleted location '#{name}'." +end diff --git a/providers/ms.rb b/providers/ms.rb new file mode 100644 index 0000000..c527463 --- /dev/null +++ b/providers/ms.rb @@ -0,0 +1,56 @@ +# Author:: Robert Choi +# Cookbook Name:: pacemaker +# Provider:: +# +# Copyright:: 2013, Robert Choi +# +# 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. +# + +require ::File.join(::File.dirname(__FILE__), 'helper') + +action :create do + name = new_resource.name + rsc = new_resource.rsc + + unless resource_exists?(name) + cmd = "crm configure ms #{name} #{rsc}" + + if new_resource.meta + cmd << " meta" + new_resource.meta.each do |key, value| + cmd << " #{key}=\"#{value}\"" + end + end + + e = execute "configure ms #{name}" do + command cmd + end + + new_resource.updated_by_last_action(true) + Chef::Log.info "configured ms '#{name}'." + end +end + +action :delete do + name = new_resource.name + cmd = "crm resource stop #{name}; crm configure delete #{name}" + + e = execute "delete ms #{name}" do + command cmd + only_if { resource_exists?(name) } + end + + new_resource.updated_by_last_action(true) + Chef::Log.info "Deleted ms '#{name}'." +end diff --git a/providers/node.rb b/providers/node.rb new file mode 100644 index 0000000..5dd623c --- /dev/null +++ b/providers/node.rb @@ -0,0 +1,40 @@ +# Author:: Robert Choi +# Cookbook Name:: pacemaker +# Provider:: node +# +# Copyright:: 2013, Robert Choi +# +# 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. +# + +require ::File.join(::File.dirname(__FILE__), 'helper') + +action :add do + name = new_resource.name + + unless resource_exists?(name) + cmd = "crm configure node #{name}" + + e = execute "add node #{name}" do + command cmd + end + + new_resource.updated_by_last_action(true) + Chef::Log.info "Node '#{name}' has been added.." + end +end + +action :delete do + #TBU + +end diff --git a/providers/order.rb b/providers/order.rb new file mode 100644 index 0000000..fa8fed6 --- /dev/null +++ b/providers/order.rb @@ -0,0 +1,53 @@ +# Author:: Robert Choi +# Cookbook Name:: pacemaker +# Provider:: order +# +# Copyright:: 2013, Robert Choi +# +# 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. +# + +require ::File.join(::File.dirname(__FILE__), 'helper') + +action :create do + name = new_resource.name + priority = new_resource.priority + resources = new_resource.resources + + unless resource_exists?(name) + cmd = "crm configure order #{name} #{priority}:" + resources.each do |rsc| + cmd << " #{rsc}" + end + + e = execute "configure order #{name}" do + command cmd + end + + new_resource.updated_by_last_action(true) + Chef::Log.info "Configured order '#{name}'." + end +end + +action :delete do + name = new_resource.name + cmd = "crm resource stop #{name}; crm configure delete #{name}" + + e = execute "delete order #{name}" do + command cmd + only_if { resource_exists?(name) } + end + + new_resource.updated_by_last_action(true) + Chef::Log.info "Deleted order '#{name}'." +end diff --git a/providers/primitive.rb b/providers/primitive.rb new file mode 100644 index 0000000..2edbb82 --- /dev/null +++ b/providers/primitive.rb @@ -0,0 +1,82 @@ +# Author:: Robert Choi +# Cookbook Name:: pacemaker +# Provider:: primitive +# +# Copyright:: 2013, Robert Choi +# +# 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. +# + +require ::File.join(::File.dirname(__FILE__), 'helper') + +# For vagrant env, switch to the following 'require' command. +#require "/srv/chef/file_store/cookbooks/pacemaker/providers/helper" + +action :create do + name = new_resource.name + agent = new_resource.agent + + unless resource_exists?(name) + cmd = "crm configure primitive #{name} #{agent}" + + if new_resource.params and !(new_resource.params.empty?) + cmd << " params" + new_resource.params.each do |key, value| + cmd << " #{key}=\"#{value}\"" + end + end + + if new_resource.meta and !(new_resource.meta.empty?) + cmd << " meta" + new_resource.meta.each do |key, value| + cmd << " #{key}=\"#{value}\"" + end + end + + if new_resource.op and !(new_resource.op.empty?) + cmd << " op" + new_resource.op.each do |op, attrs| + cmd << " #{op}" + attrs.each do |key, value| + cmd << " #{key}=\"#{value}\"" + end + end + end + + e = execute "configure primitive #{name}" do + command cmd + end + +# With the below commands, 'e.updated?' is always 'false' even though the execute command ran successfully. +# new_resource.updated_by_last_action(e.updated?) +# if e.updated? +# Chef::Log.info "Done creating primitive '#{name}'." +# end + + new_resource.updated_by_last_action(true) + Chef::Log.info "Configured primitive '#{name}'." + end +end + +action :delete do + name = new_resource.name + cmd = "crm resource stop #{name}; crm configure delete #{name}" + + e = execute "delete primitive #{name}" do + command cmd + only_if { resource_exists?(name) } + end + + new_resource.updated_by_last_action(true) + Chef::Log.info "Deleted primitive '#{name}'." +end diff --git a/recipes/config.rb b/recipes/config.rb new file mode 100644 index 0000000..eeda325 --- /dev/null +++ b/recipes/config.rb @@ -0,0 +1,106 @@ +# +# Author:: Robert Choi +# Cookbook Name:: pacemaker +# Recipe:: config +# +# Copyright 2013, Robert Choi +# +# 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. +# + +include_recipe "pacemaker::default" + +directory "/usr/lib/ocf/resource.d/openstack" do + owner "root" + group "root" + mode 0755 + action :create + notifies :create, "cookbook_file[/usr/lib/ocf/resource.d/openstack/cinder-volume]", :immediately +end + +cookbook_file "/usr/lib/ocf/resource.d/openstack/cinder-volume" do + source "cinder-volume" + owner "root" + group "root" + mode 0755 + action :nothing +end + +node['pacemaker']['nodes'].each do |node| + pacemaker_node node do + action :add + end +end + +node['pacemaker']['primitive'].each do |name, attr| + Chef::Log.debug "Pacemaker::primitive #{name}" + Chef::Log.debug "Attrs: #{attr}" + + pacemaker_primitive name do + agent attr['agent'] + params attr['params'] + meta attr['meta'] + op attr['op'] + action :create + only_if attr['active'].include?(node.name) + end +end + +node['pacemaker']['location'].each do |name, attr| + pacemaker_location name do + rsc attr['rsc_name'] + priority attr['priority'] + node attr['node'] + action :create + only_if attr['active'].include?(node.name) + end +end + +node['pacemaker']['ms'].each do |name, attr| + pacemaker_ms name do + rsc attr['rsc_name'] + meta attr['meta'] + action :create + only_if attr['active'].include?(node.name) + end +end + +node['pacemaker']['clone'].each do |name, attr| + pacemaker_clone name do + rsc attr['rsc_name'] + meta attr['meta'] + action :create + only_if attr['active'].include?(node.name) + end +end + +node['pacemaker']['colocation'].each do |name, attr| + pacemaker_colocation name do + priority attr['priority'] + multiple attr['is_multiple'] + rsc attr['rsc'] + with_rsc attr['with_rsc'] + multiple_rscs attr['multiple_rscs'] + action :create + only_if { attr['active'].include?(node.name) } + end +end + +node['pacemaker']['order'].each do |name, attr| + pacemaker_order name do + priority attr['priority'] + resources attr['resources'] + action :create + only_if { attr['active'].include?(node.name) } + end +end diff --git a/recipes/default.rb b/recipes/default.rb new file mode 100644 index 0000000..b78d527 --- /dev/null +++ b/recipes/default.rb @@ -0,0 +1,27 @@ +# +# Author:: Robert Choi +# Cookbook Name:: pacemaker +# Recipe:: default +# +# Copyright 2013, Robert Choi +# +# 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. +# + +package "pacemaker" do + action :install +end + +service "pacemaker" do + action [:enable, :start] +end diff --git a/resources/clone.rb b/resources/clone.rb new file mode 100644 index 0000000..522aad3 --- /dev/null +++ b/resources/clone.rb @@ -0,0 +1,26 @@ +# Author:: Robert Choi +# Cookbook Name:: pacemaker +# Resource:: clone +# +# Copyright:: 2013, Robert Choi +# +# 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. +# + +actions :create, :delete + +default_action :create + +attribute :name, :kind_of => String, :name_attribute => true +attribute :rsc, :kind_of => String +attribute :meta, :kind_of => Hash diff --git a/resources/colocation.rb b/resources/colocation.rb new file mode 100644 index 0000000..0ae5f96 --- /dev/null +++ b/resources/colocation.rb @@ -0,0 +1,29 @@ +# Author:: Robert Choi +# Cookbook Name:: pacemaker +# Resource:: colocation +# +# Copyright:: 2013, Robert Choi +# +# 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. +# + +actions :create, :delete + +default_action :create + +attribute :name, :kind_of => String, :name_attribute => true +attribute :priority, :kind_of => String +attribute :multiple, :default => false +attribute :rsc, :kind_of => String +attribute :with_rsc, :kind_of => String +attribute :multiple_rscs, :kind_of => Array diff --git a/resources/location.rb b/resources/location.rb new file mode 100644 index 0000000..db33d88 --- /dev/null +++ b/resources/location.rb @@ -0,0 +1,27 @@ +# Author:: Robert Choi +# Cookbook Name:: pacemaker +# Resource:: location +# +# Copyright:: 2013, Robert Choi +# +# 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. +# + +actions :create, :delete + +default_action :create + +attribute :name, :kind_of => String, :name_attribute => true +attribute :rsc, :kind_of => String +attribute :priority, :kind_of => String +attribute :node, :kind_of => String diff --git a/resources/ms.rb b/resources/ms.rb new file mode 100644 index 0000000..56d0c8a --- /dev/null +++ b/resources/ms.rb @@ -0,0 +1,26 @@ +# Author:: Robert Choi +# Cookbook Name:: pacemaker +# Resource:: ms +# +# Copyright:: 2013, Robert Choi +# +# 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. +# + +actions :create, :delete + +default_action :create + +attribute :name, :kind_of => String, :name_attribute => true +attribute :rsc, :kind_of => String +attribute :meta, :kind_of => Hash diff --git a/resources/node.rb b/resources/node.rb new file mode 100644 index 0000000..6f2c6b1 --- /dev/null +++ b/resources/node.rb @@ -0,0 +1,24 @@ +# Author:: Robert Choi +# Cookbook Name:: pacemaker +# Resource:: node +# +# Copyright:: 2013, Robert Choi +# +# 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. +# + +actions :add, :delete + +default_action :add + +attribute :name, :kind_of => String, :name_attribute => true diff --git a/resources/order.rb b/resources/order.rb new file mode 100644 index 0000000..41287fe --- /dev/null +++ b/resources/order.rb @@ -0,0 +1,26 @@ +# Author:: Robert Choi +# Cookbook Name:: pacemaker +# Resource:: order +# +# Copyright:: 2013, Robert Choi +# +# 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. +# + +actions :create, :delete + +default_action :create + +attribute :name, :kind_of => String, :name_attribute => true +attribute :priority, :kind_of => String +attribute :resources, :kind_of => Array diff --git a/resources/primitive.rb b/resources/primitive.rb new file mode 100644 index 0000000..925a051 --- /dev/null +++ b/resources/primitive.rb @@ -0,0 +1,28 @@ +# Author:: Robert Choi +# Cookbook Name:: pacemaker +# Resource:: primitive +# +# Copyright:: 2013, Robert Choi +# +# 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. +# + +actions :create, :delete + +default_action :create + +attribute :name, :kind_of => String, :name_attribute => true +attribute :agent, :kind_of => String +attribute :params, :default => Hash +attribute :meta, :kind_of => Hash +attribute :op, :kind_of => Hash