initial commit

This commit is contained in:
Robert 2013-04-15 17:27:39 +09:00
commit 85b08983de
21 changed files with 1200 additions and 0 deletions

53
README.md Normal file
View File

@ -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 <taeilchoi1@gmail.com>
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.

76
attributes/default.rb Normal file
View File

@ -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"]

327
files/default/cinder-volume Normal file
View File

@ -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 <<UEND
usage: $0 (start|stop|validate-all|meta-data|status|monitor)
$0 manages an OpenStack Cinder Volume (cinder-volume) process as an HA resource
The 'start' operation starts the volume service.
The 'stop' operation stops the volume service.
The 'validate-all' operation reports whether the parameters are valid
The 'meta-data' operation reports this RA's meta-data information
The 'status' operation reports whether the volume service is running
The 'monitor' operation reports whether the volume service seems to be working
UEND
}
meta_data() {
cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="cinder-volume">
<version>1.0</version>
<longdesc lang="en">
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.
</longdesc>
<shortdesc lang="en">Manages the OpenStack Cinder Volume (cinder-volume)</shortdesc>
<parameters>
<parameter name="binary" unique="0" required="0">
<longdesc lang="en">
Location of the OpenStack Cinder Volume server binary (cinder-volume)
</longdesc>
<shortdesc lang="en">OpenStack Cinder Volume server binary (cinder-volume)</shortdesc>
<content type="string" default="${OCF_RESKEY_binary_default}" />
</parameter>
<parameter name="config" unique="0" required="0">
<longdesc lang="en">
Location of the OpenStack Cinder Volume (cinder-volume) configuration file
</longdesc>
<shortdesc lang="en">OpenStack Cinder Volume (cinder-volume) config file</shortdesc>
<content type="string" default="${OCF_RESKEY_config_default}" />
</parameter>
<parameter name="user" unique="0" required="0">
<longdesc lang="en">
User running OpenStack Cinder Volume (cinder-volume)
</longdesc>
<shortdesc lang="en">OpenStack Cinder Volume (cinder-volume) user</shortdesc>
<content type="string" default="${OCF_RESKEY_user_default}" />
</parameter>
<parameter name="pid" unique="0" required="0">
<longdesc lang="en">
The pid file to use for this OpenStack Cinder Volume (cinder-volume) instance
</longdesc>
<shortdesc lang="en">OpenStack Cinder Volume (cinder-volume) pid file</shortdesc>
<content type="string" default="${OCF_RESKEY_pid_default}" />
</parameter>
<parameter name="amqp_server_port" unique="0" required="0">
<longdesc lang="en">
The listening port number of the AMQP server. Mandatory to perform a monitor check
</longdesc>
<shortdesc lang="en">AMQP listening port</shortdesc>
<content type="integer" default="${OCF_RESKEY_amqp_server_port_default}" />
</parameter>
<parameter name="additional_parameters" unique="0" required="0">
<longdesc lang="en">
Additional parameters to pass on to the OpenStack Cinder Volume (cinder-volume)
</longdesc>
<shortdesc lang="en">Additional parameters for cinder-volume</shortdesc>
<content type="string" />
</parameter>
</parameters>
<actions>
<action name="start" timeout="10" />
<action name="stop" timeout="10" />
<action name="status" timeout="10" />
<action name="monitor" timeout="5" interval="10" />
<action name="validate-all" timeout="5" />
<action name="meta-data" timeout="5" />
</actions>
</resource-agent>
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

7
metadata.rb Normal file
View File

@ -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"

57
providers/clone.rb Normal file
View File

@ -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

68
providers/colocation.rb Normal file
View File

@ -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

11
providers/helper.rb Normal file
View File

@ -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

51
providers/location.rb Normal file
View File

@ -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

56
providers/ms.rb Normal file
View File

@ -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

40
providers/node.rb Normal file
View File

@ -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

53
providers/order.rb Normal file
View File

@ -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

82
providers/primitive.rb Normal file
View File

@ -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

106
recipes/config.rb Normal file
View File

@ -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

27
recipes/default.rb Normal file
View File

@ -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

26
resources/clone.rb Normal file
View File

@ -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

29
resources/colocation.rb Normal file
View File

@ -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

27
resources/location.rb Normal file
View File

@ -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

26
resources/ms.rb Normal file
View File

@ -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

24
resources/node.rb Normal file
View File

@ -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

26
resources/order.rb Normal file
View File

@ -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

28
resources/primitive.rb Normal file
View File

@ -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