Retire stackforge/cookbook-pacemaker
This commit is contained in:
parent
5b4bb9262d
commit
5f8b586576
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +0,0 @@
|
|||||||
Gemfile.lock
|
|
||||||
tmp/
|
|
21
Gemfile
21
Gemfile
@ -1,21 +0,0 @@
|
|||||||
source 'https://rubygems.org'
|
|
||||||
|
|
||||||
#gem 'berkshelf', '~> 2.0'
|
|
||||||
|
|
||||||
group :test, :development do
|
|
||||||
gem 'chefspec', '~> 3.0'
|
|
||||||
gem 'rspec-expectations', '~> 2.14.0'
|
|
||||||
gem 'rubydeps'
|
|
||||||
end
|
|
||||||
|
|
||||||
group :development do
|
|
||||||
gem 'foodcritic', '~> 3.0'
|
|
||||||
gem 'rubocop'
|
|
||||||
gem 'jazz_hands'
|
|
||||||
gem 'guard-rspec'
|
|
||||||
gem 'guard-bundler'
|
|
||||||
# Prevent "Error: can't modify string; temporarily locked"
|
|
||||||
# http://stackoverflow.com/a/19505033/179332
|
|
||||||
gem "rb-readline", "~> 0.5.0"
|
|
||||||
end
|
|
||||||
|
|
49
Guardfile
49
Guardfile
@ -1,49 +0,0 @@
|
|||||||
#!/usr/bin/ruby
|
|
||||||
#
|
|
||||||
# More info at https://github.com/guard/guard#readme
|
|
||||||
|
|
||||||
guard_opts = {
|
|
||||||
all_on_start: true,
|
|
||||||
all_after_pass: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG = false
|
|
||||||
|
|
||||||
def reload(target)
|
|
||||||
puts "-> #{target}" if DEBUG
|
|
||||||
target
|
|
||||||
end
|
|
||||||
|
|
||||||
def all_specs; reload 'all_specs'; 'spec' end
|
|
||||||
def library_specs; reload 'library_specs'; 'spec/libraries' end
|
|
||||||
def provider_specs; reload 'provider_specs'; 'spec/providers' end
|
|
||||||
|
|
||||||
group :rspec do
|
|
||||||
guard 'rspec', guard_opts do
|
|
||||||
watch(%r{^Gemfile$}) { all_specs }
|
|
||||||
watch(%r{^Gemfile.lock$}) { all_specs }
|
|
||||||
watch(%r{^spec/spec_helper\.rb$}) { all_specs }
|
|
||||||
watch(%r{^spec/helpers/.+\.rb$}) { all_specs }
|
|
||||||
watch(%r{^spec/fixtures/.+\.rb$}) { all_specs }
|
|
||||||
watch(%r{^libraries/pacemaker\.rb$}) { all_specs }
|
|
||||||
watch(%r{^libraries/pacemaker/[^/]+\.rb$}) \
|
|
||||||
{ all_specs }
|
|
||||||
watch(%r{^libraries/(.*mixin.*)\.rb$}) { all_specs }
|
|
||||||
watch(%r{^(spec/.+_spec\.rb)$}) { |m| reload m[1] }
|
|
||||||
watch(%r{^libraries/(.+)\.rb$}) { |m|
|
|
||||||
reload "spec/libraries/#{m[1]}_spec.rb"
|
|
||||||
}
|
|
||||||
watch(%r{^recipes/.+\.rb$}) { provider_specs }
|
|
||||||
watch(%r{^providers/common\.rb$}) { provider_specs }
|
|
||||||
watch(%r{^providers/(.*mixin.*)\.rb$}) { provider_specs }
|
|
||||||
watch(%r{^(?:resources|providers)/(.+)\.rb$}) { |m|
|
|
||||||
reload "spec/providers/#{m[1]}_spec.rb"
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
group :bundler do
|
|
||||||
guard 'bundler' do
|
|
||||||
watch('Gemfile')
|
|
||||||
end
|
|
||||||
end
|
|
77
README.md
77
README.md
@ -1,77 +0,0 @@
|
|||||||
[](https://travis-ci.org/crowbar/barclamp-pacemaker)
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
===========
|
|
||||||
|
|
||||||
This is a cookbook for installing and configuring pacemaker.
|
|
||||||
|
|
||||||
Recipes
|
|
||||||
=======
|
|
||||||
default
|
|
||||||
-------
|
|
||||||
Installs and start `pacemaker`.
|
|
||||||
|
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
clone
|
|
||||||
-----
|
|
||||||
TBU
|
|
||||||
|
|
||||||
ms
|
|
||||||
--
|
|
||||||
TBU
|
|
||||||
|
|
||||||
location
|
|
||||||
--------
|
|
||||||
TBU
|
|
||||||
|
|
||||||
colocation
|
|
||||||
----------
|
|
||||||
TBU
|
|
||||||
|
|
||||||
order
|
|
||||||
-----
|
|
||||||
TBU
|
|
||||||
|
|
||||||
node
|
|
||||||
----
|
|
||||||
TBU
|
|
||||||
|
|
||||||
|
|
||||||
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.
|
|
7
README.rst
Normal file
7
README.rst
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
This project is no longer maintained.
|
||||||
|
|
||||||
|
The contents of this repository are still available in the Git source code
|
||||||
|
management system. To see the contents of this repository before it reached
|
||||||
|
its end of life, please check out the previous commit with
|
||||||
|
"git checkout HEAD^1".
|
||||||
|
|
47
Rakefile
47
Rakefile
@ -1,47 +0,0 @@
|
|||||||
IGNORED_CLASSES = ['RSpec::Core::ExampleGroup']
|
|
||||||
DUMP_FILE = 'rubydeps.dump'
|
|
||||||
DOT_FILE = 'rubydeps.dot'
|
|
||||||
SVG_FILE = 'rubydeps.svg'
|
|
||||||
|
|
||||||
task :default => "rubydeps:svg"
|
|
||||||
|
|
||||||
file DUMP_FILE do
|
|
||||||
sh 'RUBYDEPS=y rspec'
|
|
||||||
end
|
|
||||||
|
|
||||||
file DOT_FILE => DUMP_FILE do
|
|
||||||
ignore_regexp = IGNORED_CLASSES.join "|"
|
|
||||||
sh "rubydeps --class-name-filter='^(?!#{ignore_regexp})'"
|
|
||||||
dot = File.read(DOT_FILE)
|
|
||||||
dot.gsub!('rankdir=LR', 'rankdir=TB')
|
|
||||||
# Unfortunately due to https://github.com/dcadenas/rubydeps/issues/4
|
|
||||||
# we need to manually exclude some superfluous dependencies which
|
|
||||||
# go in the wrong direction.
|
|
||||||
dot.gsub!(/\\\n/, '')
|
|
||||||
dot.gsub!(/^(?=\s+Object )/, '#')
|
|
||||||
dot.gsub!(/^(?=\s+"Pacemaker::Resource::Meta" ->)/, '#')
|
|
||||||
dot.gsub!(/^(?=\s+"Pacemaker::CIBObject" ->)/, '#')
|
|
||||||
dot.gsub!(/^(?=\s+"Chef::Mixin::Pacemaker::StandardCIBObject" -> "(?!Pacemaker::CIBObject))/, '#')
|
|
||||||
dot.gsub!(/^(?=\s+"Chef::Mixin::Pacemaker::RunnableResource" -> "(?!Pacemaker::CIBObject))/, '#')
|
|
||||||
File.open(DOT_FILE, 'w') { |f| f.write(dot) }
|
|
||||||
end
|
|
||||||
|
|
||||||
file SVG_FILE => DOT_FILE do
|
|
||||||
sh "dot -Tsvg #{DOT_FILE} > #{SVG_FILE}"
|
|
||||||
end
|
|
||||||
|
|
||||||
namespace :rubydeps do
|
|
||||||
desc "Clean rubydeps dump"
|
|
||||||
task :clean do
|
|
||||||
FileUtils.rm_f([DUMP_FILE])
|
|
||||||
end
|
|
||||||
|
|
||||||
desc "Regenerate #{DUMP_FILE}"
|
|
||||||
task :dump => DUMP_FILE
|
|
||||||
|
|
||||||
desc "Regenerate #{DOT_FILE}"
|
|
||||||
task :dot => DOT_FILE
|
|
||||||
|
|
||||||
desc "Regenerate #{SVG_FILE}"
|
|
||||||
task :svg => SVG_FILE
|
|
||||||
end
|
|
@ -1,72 +0,0 @@
|
|||||||
# Copyright 2011, Dell, 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
case node.platform
|
|
||||||
when 'suse'
|
|
||||||
default[:pacemaker][:platform][:packages] = %w(pacemaker crmsh)
|
|
||||||
|
|
||||||
# pacemaker-mgmt-client provides hb_gui, which it's useful
|
|
||||||
# to run over ssh. Note that pacemaker-mgmt needs to be installed
|
|
||||||
# *before* the openais service is started, otherwise the mgmtd
|
|
||||||
# plugin won't be forked as a child process.
|
|
||||||
default[:pacemaker][:platform][:graphical_packages] = %w(
|
|
||||||
pacemaker-mgmt pacemaker-mgmt-client
|
|
||||||
xorg-x11-xauth xorg-x11-fonts
|
|
||||||
)
|
|
||||||
else
|
|
||||||
Chef::Application.fatal! "FIXME: #{node.platform} platform not supported yet"
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
default[:pacemaker][:founder] = false
|
|
||||||
default[:pacemaker][:crm][:initial_config_file] = "/etc/corosync/crm-initial.conf"
|
|
||||||
default[:pacemaker][:crm][:no_quorum_policy] = "ignore"
|
|
||||||
default[:pacemaker][:crm][:op_default_timeout] = 60
|
|
||||||
|
|
||||||
# Values can be "disabled", "manual", "sbd", "shared", "per_node"
|
|
||||||
default[:pacemaker][:stonith][:mode] = "disabled"
|
|
||||||
|
|
||||||
# This hash will contain devices for each node.
|
|
||||||
# For instance:
|
|
||||||
# default[:pacemaker][:stonith][:sbd][:nodes][$node][:devices] = ['/dev/disk/by-id/foo-part1', '/dev/disk/by-id/bar-part1']
|
|
||||||
default[:pacemaker][:stonith][:sbd][:nodes] = {}
|
|
||||||
|
|
||||||
default[:pacemaker][:stonith][:shared][:agent] = ""
|
|
||||||
# This can be either a string (containing a list of parameters) or a hash.
|
|
||||||
# For instance:
|
|
||||||
# default[:pacemaker][:stonith][:shared][:params] = 'hostname="foo" password="bar"'
|
|
||||||
# will give the same result as:
|
|
||||||
# default[:pacemaker][:stonith][:shared][:params] = {"hostname" => "foo", "password" => "bar"}
|
|
||||||
default[:pacemaker][:stonith][:shared][:params] = {}
|
|
||||||
|
|
||||||
default[:pacemaker][:stonith][:per_node][:agent] = ""
|
|
||||||
# This can be "all" or "self":
|
|
||||||
# - if set to "all", then every node will configure the stonith resources for
|
|
||||||
# all nodes in the cluster
|
|
||||||
# - if set to "self", then every node will configure the stonith resource for
|
|
||||||
# itself only
|
|
||||||
default[:pacemaker][:stonith][:per_node][:mode] = "all"
|
|
||||||
# This hash will contain parameters for each node. See documentation for
|
|
||||||
# default[:pacemaker][:stonith][:shared][:params] about the format.
|
|
||||||
# For instance:
|
|
||||||
# default[:pacemaker][:stonith][:per_node][:nodes][$node][:params] = 'hostname="foo" password="bar"'
|
|
||||||
default[:pacemaker][:stonith][:per_node][:nodes] = {}
|
|
||||||
|
|
||||||
default[:pacemaker][:notifications][:agent] = "ocf:heartbeat:ClusterMon"
|
|
||||||
default[:pacemaker][:notifications][:smtp][:enabled] = false
|
|
||||||
default[:pacemaker][:notifications][:smtp][:to] = ""
|
|
||||||
default[:pacemaker][:notifications][:smtp][:from] = ""
|
|
||||||
default[:pacemaker][:notifications][:smtp][:server] = ""
|
|
||||||
default[:pacemaker][:notifications][:smtp][:prefix] = ""
|
|
@ -1,3 +0,0 @@
|
|||||||
# managed by Chef
|
|
||||||
# start corosync at boot [yes|no]
|
|
||||||
START=yes
|
|
@ -1,3 +0,0 @@
|
|||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('pacemaker/standard_cib_object.rb', this_dir)
|
|
||||||
require File.expand_path('pacemaker/runnable_resource.rb', this_dir)
|
|
@ -1,46 +0,0 @@
|
|||||||
require ::File.expand_path('standard_cib_object', File.dirname(__FILE__))
|
|
||||||
|
|
||||||
# Common code used by Pacemaker LWRP providers for resources supporting
|
|
||||||
# the :run action.
|
|
||||||
|
|
||||||
class Chef
|
|
||||||
module Mixin::Pacemaker
|
|
||||||
module RunnableResource
|
|
||||||
include StandardCIBObject
|
|
||||||
|
|
||||||
def start_runnable_resource
|
|
||||||
name = new_resource.name
|
|
||||||
unless @current_resource
|
|
||||||
raise "Cannot start non-existent #{cib_object_class.description} '#{name}'"
|
|
||||||
end
|
|
||||||
return if @current_cib_object.running?
|
|
||||||
execute @current_cib_object.crm_start_command do
|
|
||||||
action :nothing
|
|
||||||
end.run_action(:run)
|
|
||||||
new_resource.updated_by_last_action(true)
|
|
||||||
Chef::Log.info "Successfully started #{@current_cib_object}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def stop_runnable_resource
|
|
||||||
name = new_resource.name
|
|
||||||
unless @current_resource
|
|
||||||
raise "Cannot stop non-existent #{cib_object_class.description} '#{name}'"
|
|
||||||
end
|
|
||||||
return unless @current_cib_object.running?
|
|
||||||
execute @current_cib_object.crm_stop_command do
|
|
||||||
action :nothing
|
|
||||||
end.run_action(:run)
|
|
||||||
new_resource.updated_by_last_action(true)
|
|
||||||
Chef::Log.info "Successfully stopped #{@current_cib_object}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def delete_runnable_resource
|
|
||||||
return unless @current_resource
|
|
||||||
if @current_cib_object.running?
|
|
||||||
raise "Cannot delete running #{@current_cib_object}"
|
|
||||||
end
|
|
||||||
standard_delete_resource
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,116 +0,0 @@
|
|||||||
require ::File.expand_path('../../../pacemaker/cib_object',
|
|
||||||
File.dirname(__FILE__))
|
|
||||||
|
|
||||||
# Common code used by Pacemaker LWRP providers
|
|
||||||
|
|
||||||
class Chef
|
|
||||||
module Mixin::Pacemaker
|
|
||||||
module StandardCIBObject
|
|
||||||
def standard_create_action
|
|
||||||
name = new_resource.name
|
|
||||||
|
|
||||||
if @current_resource_definition.nil?
|
|
||||||
create_resource(name)
|
|
||||||
else
|
|
||||||
maybe_modify_resource(name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Instantiate @current_resource and read details about the existing
|
|
||||||
# primitive (if any) via "crm configure show" into it, so that we
|
|
||||||
# can compare it against the resource requested by the recipe, and
|
|
||||||
# create / delete / modify as necessary.
|
|
||||||
#
|
|
||||||
# http://docs.opscode.com/lwrp_custom_provider_ruby.html#load-current-resource
|
|
||||||
def standard_load_current_resource
|
|
||||||
name = @new_resource.name
|
|
||||||
|
|
||||||
cib_object = ::Pacemaker::CIBObject.from_name(name)
|
|
||||||
unless cib_object
|
|
||||||
::Chef::Log.debug "CIB object definition nil or empty"
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
unless cib_object.is_a? cib_object_class
|
|
||||||
expected_type = cib_object_class.description
|
|
||||||
::Chef::Log.warn "CIB object '#{name}' was a #{cib_object.type} not a #{expected_type}"
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
::Chef::Log.debug "CIB object definition #{cib_object.definition}"
|
|
||||||
@current_resource_definition = cib_object.definition
|
|
||||||
cib_object.parse_definition
|
|
||||||
|
|
||||||
@current_cib_object = cib_object
|
|
||||||
init_current_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
# In Pacemaker, target-role defaults to 'Started', but we want
|
|
||||||
# to allow consumers of the LWRPs the choice whether their
|
|
||||||
# newly created resource gets started or not, and we also want
|
|
||||||
# to adhere to the Principle of Least Surprise. Therefore we
|
|
||||||
# stick to the intuitive semantics that
|
|
||||||
#
|
|
||||||
# action :create
|
|
||||||
#
|
|
||||||
# creates the resource with target-role="Stopped" in order to
|
|
||||||
# prevent it from starting immediately, whereas
|
|
||||||
#
|
|
||||||
# action [:create, :start]
|
|
||||||
#
|
|
||||||
# creates the resource and then starts it.
|
|
||||||
#
|
|
||||||
# Consequently we deprecate setting target-role values directly
|
|
||||||
# via the meta attribute.
|
|
||||||
def deprecate_target_role
|
|
||||||
if new_resource.respond_to? :meta
|
|
||||||
meta = new_resource.meta
|
|
||||||
if meta && meta['target-role']
|
|
||||||
::Chef::Log.warn "#{new_resource} used deprecated target-role " +
|
|
||||||
"#{meta['target-role']}; use action :start / :stop instead"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def standard_create_resource
|
|
||||||
deprecate_target_role
|
|
||||||
|
|
||||||
cib_object = cib_object_class.from_chef_resource(new_resource)
|
|
||||||
|
|
||||||
# We don't want resources to automatically start on creation;
|
|
||||||
# only when the :create action is invoked. However Pacemaker
|
|
||||||
# defaults target-role to "Started", so we need to override it.
|
|
||||||
if cib_object.respond_to? :meta # might be a constraint
|
|
||||||
cib_object.meta['target-role'] = 'Stopped'
|
|
||||||
end
|
|
||||||
|
|
||||||
cmd = cib_object.configure_command
|
|
||||||
|
|
||||||
::Chef::Log.info "Creating new #{cib_object}"
|
|
||||||
|
|
||||||
execute cmd do
|
|
||||||
action :nothing
|
|
||||||
end.run_action(:run)
|
|
||||||
|
|
||||||
created_cib_object = ::Pacemaker::CIBObject.from_name(new_resource.name)
|
|
||||||
|
|
||||||
raise "Failed to create #{cib_object}" if created_cib_object.nil?
|
|
||||||
unless created_cib_object.exists?
|
|
||||||
# This case seems pretty unlikely
|
|
||||||
raise "Definition missing for #{created_cib_object} after creation"
|
|
||||||
end
|
|
||||||
|
|
||||||
new_resource.updated_by_last_action(true)
|
|
||||||
::Chef::Log.info "Successfully configured #{created_cib_object}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def standard_delete_resource
|
|
||||||
execute @current_cib_object.delete_command do
|
|
||||||
action :nothing
|
|
||||||
end.run_action(:run)
|
|
||||||
new_resource.updated_by_last_action(true)
|
|
||||||
Chef::Log.info "Deleted #{@current_cib_object}'."
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,7 +0,0 @@
|
|||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
|
|
||||||
require File.expand_path('pacemaker/resource/primitive', this_dir)
|
|
||||||
require File.expand_path('pacemaker/resource/clone', this_dir)
|
|
||||||
require File.expand_path('pacemaker/resource/ms', this_dir)
|
|
||||||
require File.expand_path('pacemaker/resource/group', this_dir)
|
|
||||||
require File.expand_path('pacemaker/constraint/colocation', this_dir)
|
|
@ -1,165 +0,0 @@
|
|||||||
require 'mixlib/shellout'
|
|
||||||
|
|
||||||
module Pacemaker
|
|
||||||
class CIBObject
|
|
||||||
attr_accessor :name, :definition
|
|
||||||
|
|
||||||
@@subclasses = { } unless class_variable_defined?(:@@subclasses)
|
|
||||||
|
|
||||||
class << self
|
|
||||||
attr_reader :object_type
|
|
||||||
|
|
||||||
def register_type(type_name)
|
|
||||||
@object_type = type_name
|
|
||||||
@@subclasses[type_name] = self
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_definition(name)
|
|
||||||
cmd = Mixlib::ShellOut.new("crm configure show #{name}")
|
|
||||||
cmd.environment['HOME'] = ENV.fetch('HOME', '/root')
|
|
||||||
cmd.run_command
|
|
||||||
begin
|
|
||||||
cmd.error!
|
|
||||||
cmd.stdout
|
|
||||||
rescue
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def definition_type(definition)
|
|
||||||
unless definition =~ /\A(\w+)\s/
|
|
||||||
raise "Couldn't extract CIB object type from '#{definition}'"
|
|
||||||
end
|
|
||||||
return $1
|
|
||||||
end
|
|
||||||
|
|
||||||
def from_name(name)
|
|
||||||
definition = get_definition(name)
|
|
||||||
return nil unless definition and ! definition.empty?
|
|
||||||
from_definition(definition)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Make sure this works on Ruby 1.8.7 which is missing
|
|
||||||
# Object#singleton_class.
|
|
||||||
def singleton_class
|
|
||||||
class << self; self; end
|
|
||||||
end
|
|
||||||
|
|
||||||
def from_definition(definition)
|
|
||||||
calling_class = self.singleton_class
|
|
||||||
this_class = method(__method__).owner
|
|
||||||
if calling_class == this_class
|
|
||||||
# Invoked via (this) base class
|
|
||||||
obj_type = definition_type(definition)
|
|
||||||
subclass = @@subclasses[obj_type]
|
|
||||||
unless subclass
|
|
||||||
raise "No subclass of #{self.name} was registered with type '#{obj_type}'"
|
|
||||||
end
|
|
||||||
return subclass.from_definition(definition)
|
|
||||||
else
|
|
||||||
# Invoked via subclass
|
|
||||||
obj = new(name)
|
|
||||||
unless name == obj.name
|
|
||||||
raise "Name '#{obj.name}' in definition didn't match name '#{name}' used for retrieval"
|
|
||||||
end
|
|
||||||
obj.definition = definition
|
|
||||||
obj.parse_definition
|
|
||||||
obj
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def from_chef_resource(resource)
|
|
||||||
new(resource.name).copy_attrs_from_chef_resource(resource,
|
|
||||||
*attrs_to_copy_from_chef)
|
|
||||||
end
|
|
||||||
|
|
||||||
def attrs_to_copy_from_chef
|
|
||||||
raise NotImplementedError, "#{self.class} didn't implement attrs_to_copy_from_chef"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize(name)
|
|
||||||
@name = name
|
|
||||||
@definition = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def copy_attrs_from_chef_resource(resource, *attrs)
|
|
||||||
attrs.each do |attr|
|
|
||||||
value = resource.send(attr.to_sym)
|
|
||||||
writer = (attr + '=').to_sym
|
|
||||||
send(writer, value)
|
|
||||||
end
|
|
||||||
self
|
|
||||||
end
|
|
||||||
|
|
||||||
def copy_attrs_to_chef_resource(resource, *attrs)
|
|
||||||
attrs.each do |attr|
|
|
||||||
value = send(attr.to_sym)
|
|
||||||
writer = attr.to_sym
|
|
||||||
resource.send(writer, value)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def load_definition
|
|
||||||
@definition = self.class.get_definition(name)
|
|
||||||
|
|
||||||
if @definition and ! @definition.empty? and type != self.class.object_type
|
|
||||||
raise CIBObject::TypeMismatch, \
|
|
||||||
"Expected #{self.class.object_type} type but loaded definition was type #{type}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse_definition
|
|
||||||
raise NotImplementedError, "#{self.class} must implement #parse_definition"
|
|
||||||
end
|
|
||||||
|
|
||||||
def exists?
|
|
||||||
!! (definition && ! definition.empty?)
|
|
||||||
end
|
|
||||||
|
|
||||||
def type
|
|
||||||
self.class.definition_type(definition)
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_s
|
|
||||||
"%s '%s'" % [self.class.description, name]
|
|
||||||
end
|
|
||||||
|
|
||||||
def definition_indent
|
|
||||||
' ' * 9
|
|
||||||
end
|
|
||||||
|
|
||||||
def continuation_line(text)
|
|
||||||
" \\\n#{definition_indent}#{text}"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns a single-quoted shell-escaped version of the definition
|
|
||||||
# string, suitable for use in a command like:
|
|
||||||
#
|
|
||||||
# echo '...' | crm configure load update -
|
|
||||||
def quoted_definition_string
|
|
||||||
"'%s'" % \
|
|
||||||
definition_string \
|
|
||||||
.gsub('\\') { '\\\\' } \
|
|
||||||
.gsub("'") { "\\'" }
|
|
||||||
end
|
|
||||||
|
|
||||||
def configure_command
|
|
||||||
"crm configure " + definition_string
|
|
||||||
end
|
|
||||||
|
|
||||||
def reconfigure_command
|
|
||||||
"echo #{quoted_definition_string} | crm configure load update -"
|
|
||||||
end
|
|
||||||
|
|
||||||
def delete_command
|
|
||||||
"crm configure delete '#{name}'"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
class CIBObject::DefinitionParseError < StandardError
|
|
||||||
end
|
|
||||||
|
|
||||||
class CIBObject::TypeMismatch < StandardError
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,10 +0,0 @@
|
|||||||
require File.expand_path('cib_object', File.dirname(__FILE__))
|
|
||||||
|
|
||||||
module Pacemaker
|
|
||||||
class Constraint < Pacemaker::CIBObject
|
|
||||||
def self.description
|
|
||||||
type = self.to_s.split('::').last
|
|
||||||
"#{type} constraint"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,30 +0,0 @@
|
|||||||
require File.expand_path('../constraint', File.dirname(__FILE__))
|
|
||||||
|
|
||||||
class Pacemaker::Constraint::Colocation < Pacemaker::Constraint
|
|
||||||
TYPE = 'colocation'
|
|
||||||
register_type TYPE
|
|
||||||
|
|
||||||
attr_accessor :score, :resources
|
|
||||||
|
|
||||||
def self.attrs_to_copy_from_chef
|
|
||||||
%w(score resources)
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse_definition
|
|
||||||
# FIXME: this is incomplete. It probably doesn't handle resource
|
|
||||||
# sets correctly, and certainly doesn't handle node attributes.
|
|
||||||
# See the crm(8) man page for the official BNF grammar.
|
|
||||||
unless definition =~ /^#{self.class::TYPE} (\S+) (\d+|[-+]?inf): (.+?)\s*$/
|
|
||||||
raise Pacemaker::CIBObject::DefinitionParseError, \
|
|
||||||
"Couldn't parse definition '#{definition}'"
|
|
||||||
end
|
|
||||||
self.name = $1
|
|
||||||
self.score = $2
|
|
||||||
self.resources = $3.split
|
|
||||||
end
|
|
||||||
|
|
||||||
def definition_string
|
|
||||||
"#{self.class::TYPE} #{name} #{score}: " + resources.join(' ')
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -1,31 +0,0 @@
|
|||||||
require File.expand_path('../constraint', File.dirname(__FILE__))
|
|
||||||
|
|
||||||
class Pacemaker::Constraint::Location < Pacemaker::Constraint
|
|
||||||
TYPE = 'location'
|
|
||||||
register_type TYPE
|
|
||||||
|
|
||||||
attr_accessor :rsc, :score, :node
|
|
||||||
|
|
||||||
def self.attrs_to_copy_from_chef
|
|
||||||
%w(rsc score node)
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse_definition
|
|
||||||
# FIXME: this is woefully incomplete, and doesn't cope with any of
|
|
||||||
# the rules syntax. See the crm(8) man page for the official BNF
|
|
||||||
# grammar.
|
|
||||||
unless definition =~ /^#{self.class::TYPE} (\S+) (\S+) (\d+|[-+]?inf): (\S+)\s*$/
|
|
||||||
raise Pacemaker::CIBObject::DefinitionParseError, \
|
|
||||||
"Couldn't parse definition '#{definition}'"
|
|
||||||
end
|
|
||||||
self.name = $1
|
|
||||||
self.rsc = $2
|
|
||||||
self.score = $3
|
|
||||||
self.node = $4
|
|
||||||
end
|
|
||||||
|
|
||||||
def definition_string
|
|
||||||
"#{self.class::TYPE} #{name} #{rsc} #{score}: #{node}"
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -1,31 +0,0 @@
|
|||||||
require File.expand_path('../constraint', File.dirname(__FILE__))
|
|
||||||
|
|
||||||
class Pacemaker::Constraint::Order < Pacemaker::Constraint
|
|
||||||
TYPE = 'order'
|
|
||||||
register_type TYPE
|
|
||||||
|
|
||||||
attr_accessor :score, :ordering
|
|
||||||
|
|
||||||
def self.attrs_to_copy_from_chef
|
|
||||||
%w(score ordering)
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse_definition
|
|
||||||
# FIXME: add support for symmetrical=<bool>
|
|
||||||
# Currently we take the easy way out and don't bother parsing the ordering.
|
|
||||||
# See the crm(8) man page for the official BNF grammar.
|
|
||||||
score_regexp = %r{\d+|[-+]?inf|Mandatory|Optional|Serialize}
|
|
||||||
unless definition =~ /^#{self.class::TYPE} (\S+) (#{score_regexp}): (.+?)\s*$/
|
|
||||||
raise Pacemaker::CIBObject::DefinitionParseError, \
|
|
||||||
"Couldn't parse definition '#{definition}'"
|
|
||||||
end
|
|
||||||
self.name = $1
|
|
||||||
self.score = $2
|
|
||||||
self.ordering = $3
|
|
||||||
end
|
|
||||||
|
|
||||||
def definition_string
|
|
||||||
"#{self.class::TYPE} #{name} #{score}: #{ordering}"
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -1,30 +0,0 @@
|
|||||||
# A mixin for Pacemaker::Resource subclasses which support meta attributes
|
|
||||||
# (priority, target-role, is-managed, etc.)
|
|
||||||
|
|
||||||
module Pacemaker
|
|
||||||
module Mixins
|
|
||||||
module Resource
|
|
||||||
module Meta
|
|
||||||
def self.included(base)
|
|
||||||
base.extend ClassMethods
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_accessor :meta
|
|
||||||
|
|
||||||
def meta_string
|
|
||||||
self.class.meta_string(meta)
|
|
||||||
end
|
|
||||||
|
|
||||||
module ClassMethods
|
|
||||||
def meta_string(meta)
|
|
||||||
return "" if ! meta or meta.empty?
|
|
||||||
"meta " +
|
|
||||||
meta.sort.map do |key, value|
|
|
||||||
%'#{key}="#{value}"'
|
|
||||||
end.join(' ')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,53 +0,0 @@
|
|||||||
require 'chef/mixin/shell_out'
|
|
||||||
require File.expand_path('cib_object', File.dirname(__FILE__))
|
|
||||||
|
|
||||||
module Pacemaker
|
|
||||||
class Resource < Pacemaker::CIBObject
|
|
||||||
include Chef::Mixin::ShellOut
|
|
||||||
|
|
||||||
def self.description
|
|
||||||
type = self.to_s.split('::').last.downcase
|
|
||||||
"#{type} resource"
|
|
||||||
end
|
|
||||||
|
|
||||||
def running?
|
|
||||||
cmd = shell_out! "crm", "resource", "status", name
|
|
||||||
Chef::Log.info cmd.stdout
|
|
||||||
!! cmd.stdout.include?("resource #{name} is running")
|
|
||||||
end
|
|
||||||
|
|
||||||
def crm_start_command
|
|
||||||
"crm --force --wait resource start '#{name}'"
|
|
||||||
end
|
|
||||||
|
|
||||||
def crm_stop_command
|
|
||||||
"crm --force --wait resource stop '#{name}'"
|
|
||||||
end
|
|
||||||
|
|
||||||
# CIB object definitions look something like:
|
|
||||||
#
|
|
||||||
# primitive keystone ocf:openstack:keystone \
|
|
||||||
# params os_username="crowbar" os_password="crowbar" os_tenant_name="openstack" \
|
|
||||||
# meta target-role="Started" is-managed="true" \
|
|
||||||
# op monitor interval="10" timeout=30s \
|
|
||||||
# op start interval="10s" timeout="240" \
|
|
||||||
#
|
|
||||||
# This method extracts a Hash from one of the params / meta / op lines.
|
|
||||||
def self.extract_hash(obj_definition, data_type)
|
|
||||||
unless obj_definition =~ /\s+#{data_type} (.+?)\s*\\?$/
|
|
||||||
return {}
|
|
||||||
end
|
|
||||||
|
|
||||||
h = {}
|
|
||||||
Shellwords.split($1).each do |kvpair|
|
|
||||||
break if kvpair == 'op'
|
|
||||||
unless kvpair =~ /^(.+?)=(.*)$/
|
|
||||||
raise "Couldn't understand '#{kvpair}' for '#{data_type}' section "\
|
|
||||||
"of #{name} primitive (definition was [#{obj_definition}])"
|
|
||||||
end
|
|
||||||
h[$1] = $2.sub(/^"(.*)"$/, "\1")
|
|
||||||
end
|
|
||||||
h
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,37 +0,0 @@
|
|||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../resource', this_dir)
|
|
||||||
require File.expand_path('../mixins/resource_meta', this_dir)
|
|
||||||
|
|
||||||
class Pacemaker::Resource::Clone < Pacemaker::Resource
|
|
||||||
TYPE = 'clone'
|
|
||||||
register_type TYPE
|
|
||||||
|
|
||||||
include Pacemaker::Mixins::Resource::Meta
|
|
||||||
|
|
||||||
# FIXME: need to handle params as well as meta
|
|
||||||
|
|
||||||
attr_accessor :rsc
|
|
||||||
|
|
||||||
def self.attrs_to_copy_from_chef
|
|
||||||
%w(rsc meta)
|
|
||||||
end
|
|
||||||
|
|
||||||
def definition_string
|
|
||||||
str = "#{self.class::TYPE} #{name} #{rsc}"
|
|
||||||
unless meta.empty?
|
|
||||||
str << continuation_line(meta_string)
|
|
||||||
end
|
|
||||||
str
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse_definition
|
|
||||||
unless definition =~ /^#{self.class::TYPE} (\S+) (\S+)/
|
|
||||||
raise Pacemaker::CIBObject::DefinitionParseError, \
|
|
||||||
"Couldn't parse definition '#{definition}'"
|
|
||||||
end
|
|
||||||
self.name = $1
|
|
||||||
self.rsc = $2
|
|
||||||
self.meta = self.class.extract_hash(definition, 'meta')
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -1,40 +0,0 @@
|
|||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../resource', this_dir)
|
|
||||||
require File.expand_path('../mixins/resource_meta', this_dir)
|
|
||||||
|
|
||||||
class Pacemaker::Resource::Group < Pacemaker::Resource
|
|
||||||
TYPE = 'group'
|
|
||||||
register_type TYPE
|
|
||||||
|
|
||||||
include Pacemaker::Mixins::Resource::Meta
|
|
||||||
|
|
||||||
# FIXME: need to handle params as well as meta
|
|
||||||
|
|
||||||
attr_accessor :members
|
|
||||||
|
|
||||||
def self.attrs_to_copy_from_chef
|
|
||||||
%w(members meta)
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse_definition
|
|
||||||
unless definition =~ /^#{self.class::TYPE} (\S+) (.+?)(\s+\\)?$/
|
|
||||||
raise Pacemaker::CIBObject::DefinitionParseError, \
|
|
||||||
"Couldn't parse definition '#{definition}'"
|
|
||||||
end
|
|
||||||
self.name = $1
|
|
||||||
members = $2.split
|
|
||||||
trim_from = members.find_index('meta')
|
|
||||||
members = members[0..trim_from-1] if trim_from
|
|
||||||
self.members = members
|
|
||||||
self.meta = self.class.extract_hash(definition, 'meta')
|
|
||||||
end
|
|
||||||
|
|
||||||
def definition_string
|
|
||||||
str = "#{self.class::TYPE} #{name} " + members.join(' ')
|
|
||||||
unless meta.empty?
|
|
||||||
str << continuation_line(meta_string)
|
|
||||||
end
|
|
||||||
str
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -1,10 +0,0 @@
|
|||||||
require File.expand_path('clone', File.dirname(__FILE__))
|
|
||||||
|
|
||||||
class Pacemaker::Resource::MasterSlave < Pacemaker::Resource::Clone
|
|
||||||
TYPE = 'ms'
|
|
||||||
register_type TYPE
|
|
||||||
|
|
||||||
#include Pacemaker::Mixins::Resource::Meta
|
|
||||||
|
|
||||||
attr_accessor :rsc
|
|
||||||
end
|
|
@ -1,89 +0,0 @@
|
|||||||
require 'shellwords'
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../resource', this_dir)
|
|
||||||
require File.expand_path('../mixins/resource_meta', this_dir)
|
|
||||||
|
|
||||||
class Pacemaker::Resource::Primitive < Pacemaker::Resource
|
|
||||||
TYPE = 'primitive'
|
|
||||||
register_type TYPE
|
|
||||||
|
|
||||||
include Pacemaker::Mixins::Resource::Meta
|
|
||||||
|
|
||||||
attr_accessor :agent, :params, :op
|
|
||||||
|
|
||||||
def initialize(*args)
|
|
||||||
super(*args)
|
|
||||||
|
|
||||||
@agent = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.attrs_to_copy_from_chef
|
|
||||||
%w(agent params meta op)
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse_definition
|
|
||||||
unless definition =~ /\A#{self.class::TYPE} (\S+) (\S+)/
|
|
||||||
raise Pacemaker::CIBObject::DefinitionParseError, \
|
|
||||||
"Couldn't parse definition '#{definition}'"
|
|
||||||
end
|
|
||||||
self.name = $1
|
|
||||||
self.agent = $2
|
|
||||||
|
|
||||||
%w(params meta).each do |data_type|
|
|
||||||
hash = self.class.extract_hash(definition, data_type)
|
|
||||||
writer = (data_type + '=').to_sym
|
|
||||||
send(writer, hash)
|
|
||||||
end
|
|
||||||
|
|
||||||
self.op = {}
|
|
||||||
%w(start stop monitor).each do |op|
|
|
||||||
h = self.class.extract_hash(definition, "op #{op}")
|
|
||||||
self.op[op] = h unless h.empty?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def params_string
|
|
||||||
self.class.params_string(params)
|
|
||||||
end
|
|
||||||
|
|
||||||
def op_string
|
|
||||||
self.class.op_string(op)
|
|
||||||
end
|
|
||||||
|
|
||||||
def definition_string
|
|
||||||
str = "#{self.class::TYPE} #{name} #{agent}"
|
|
||||||
%w(params meta op).each do |data_type|
|
|
||||||
unless send(data_type).empty?
|
|
||||||
data_string = send("#{data_type}_string")
|
|
||||||
str << continuation_line(data_string)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
str
|
|
||||||
end
|
|
||||||
|
|
||||||
def configure_command
|
|
||||||
args = %w(crm configure primitive)
|
|
||||||
args << [name, agent, params_string, meta_string, op_string]
|
|
||||||
args.join " "
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.params_string(params)
|
|
||||||
return "" if ! params or params.empty?
|
|
||||||
"params " +
|
|
||||||
params.sort.map do |key, value|
|
|
||||||
%'#{key}="#{value}"'
|
|
||||||
end.join(' ')
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.op_string(ops)
|
|
||||||
return "" if ! ops or ops.empty?
|
|
||||||
ops.sort.map do |op, attrs|
|
|
||||||
attrs.empty? ? nil : "op #{op} " + \
|
|
||||||
attrs.sort.map do |key, value|
|
|
||||||
%'#{key}="#{value}"'
|
|
||||||
end.join(' ')
|
|
||||||
end.compact.join(' ')
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -1,24 +0,0 @@
|
|||||||
module PacemakerStonithHelper
|
|
||||||
@@stonith_agents = nil
|
|
||||||
|
|
||||||
def self.stonith_agent_valid?(agent)
|
|
||||||
if agent.nil? || agent.empty?
|
|
||||||
false
|
|
||||||
else
|
|
||||||
if @@stonith_agents.nil?
|
|
||||||
out = %x{stonith -L}
|
|
||||||
if $?.success?
|
|
||||||
@@stonith_agents = out.split("\n")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
!@@stonith_agents.nil? && @@stonith_agents.include?(agent)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.assert_stonith_agent_valid(agent)
|
|
||||||
unless stonith_agent_valid? agent
|
|
||||||
raise "STONITH fencing agent #{agent} is not available!"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,9 +0,0 @@
|
|||||||
name "pacemaker"
|
|
||||||
maintainer "Crowbar Project"
|
|
||||||
maintainer_email "crowbar@dell.com"
|
|
||||||
license "Apache 2.0"
|
|
||||||
description "Installs/configures Pacemaker"
|
|
||||||
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
|
|
||||||
version "0.1"
|
|
||||||
|
|
||||||
depends "corosync"
|
|
@ -1,72 +0,0 @@
|
|||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
this_dir = ::File.dirname(__FILE__)
|
|
||||||
require ::File.expand_path('../libraries/pacemaker', this_dir)
|
|
||||||
require ::File.expand_path('../libraries/chef/mixin/pacemaker', this_dir)
|
|
||||||
|
|
||||||
include Chef::Mixin::Pacemaker::RunnableResource
|
|
||||||
|
|
||||||
action :create do
|
|
||||||
standard_create_action
|
|
||||||
end
|
|
||||||
|
|
||||||
action :delete do
|
|
||||||
delete_runnable_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
action :start do
|
|
||||||
start_runnable_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
action :stop do
|
|
||||||
stop_runnable_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def cib_object_class
|
|
||||||
::Pacemaker::Resource::Clone
|
|
||||||
end
|
|
||||||
|
|
||||||
def load_current_resource
|
|
||||||
standard_load_current_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def init_current_resource
|
|
||||||
name = @new_resource.name
|
|
||||||
@current_resource = Chef::Resource::PacemakerClone.new(name)
|
|
||||||
@current_cib_object.copy_attrs_to_chef_resource(@current_resource, :rsc)
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_resource(name)
|
|
||||||
standard_create_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def maybe_modify_resource(name)
|
|
||||||
Chef::Log.info "Checking existing #{@current_cib_object} for modifications"
|
|
||||||
|
|
||||||
desired_clone = cib_object_class.from_chef_resource(new_resource)
|
|
||||||
if desired_clone.definition_string != @current_cib_object.definition_string
|
|
||||||
Chef::Log.debug "changed from [#{@current_cib_object.definition_string}] to [#{desired_clone.definition_string}]"
|
|
||||||
cmd = desired_clone.reconfigure_command
|
|
||||||
execute cmd do
|
|
||||||
action :nothing
|
|
||||||
end.run_action(:run)
|
|
||||||
new_resource.updated_by_last_action(true)
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,72 +0,0 @@
|
|||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
this_dir = ::File.dirname(__FILE__)
|
|
||||||
require ::File.expand_path('../libraries/pacemaker', this_dir)
|
|
||||||
require ::File.expand_path('../libraries/chef/mixin/pacemaker', this_dir)
|
|
||||||
|
|
||||||
include Chef::Mixin::Pacemaker::StandardCIBObject
|
|
||||||
|
|
||||||
action :create do
|
|
||||||
name = new_resource.name
|
|
||||||
|
|
||||||
if @current_resource_definition.nil?
|
|
||||||
create_resource(name)
|
|
||||||
else
|
|
||||||
maybe_modify_resource(name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
action :delete do
|
|
||||||
next unless @current_resource
|
|
||||||
standard_delete_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def cib_object_class
|
|
||||||
::Pacemaker::Constraint::Colocation
|
|
||||||
end
|
|
||||||
|
|
||||||
def load_current_resource
|
|
||||||
standard_load_current_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def init_current_resource
|
|
||||||
name = @new_resource.name
|
|
||||||
@current_resource = Chef::Resource::PacemakerColocation.new(name)
|
|
||||||
attrs = [:score, :resources]
|
|
||||||
@current_cib_object.copy_attrs_to_chef_resource(@current_resource, *attrs)
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_resource(name)
|
|
||||||
standard_create_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def maybe_modify_resource(name)
|
|
||||||
Chef::Log.info "Checking existing #{@current_cib_object} for modifications"
|
|
||||||
|
|
||||||
desired_colocation = cib_object_class.from_chef_resource(new_resource)
|
|
||||||
if desired_colocation.definition_string != @current_cib_object.definition_string
|
|
||||||
Chef::Log.debug "changed from [#{@current_cib_object.definition_string}] to [#{desired_colocation.definition_string}]"
|
|
||||||
cmd = desired_colocation.reconfigure_command
|
|
||||||
execute cmd do
|
|
||||||
action :nothing
|
|
||||||
end.run_action(:run)
|
|
||||||
new_resource.updated_by_last_action(true)
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,71 +0,0 @@
|
|||||||
# Cookbook Name:: pacemaker
|
|
||||||
# Provider:: group
|
|
||||||
#
|
|
||||||
# Copyright:: 2014, SUSE
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
this_dir = ::File.dirname(__FILE__)
|
|
||||||
require ::File.expand_path('../libraries/pacemaker', this_dir)
|
|
||||||
require ::File.expand_path('../libraries/chef/mixin/pacemaker', this_dir)
|
|
||||||
|
|
||||||
include Chef::Mixin::Pacemaker::RunnableResource
|
|
||||||
|
|
||||||
action :create do
|
|
||||||
standard_create_action
|
|
||||||
end
|
|
||||||
|
|
||||||
action :delete do
|
|
||||||
delete_runnable_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
action :start do
|
|
||||||
start_runnable_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
action :stop do
|
|
||||||
stop_runnable_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def cib_object_class
|
|
||||||
::Pacemaker::Resource::Group
|
|
||||||
end
|
|
||||||
|
|
||||||
def load_current_resource
|
|
||||||
standard_load_current_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def init_current_resource
|
|
||||||
name = @new_resource.name
|
|
||||||
@current_resource = Chef::Resource::PacemakerGroup.new(name)
|
|
||||||
@current_cib_object.copy_attrs_to_chef_resource(@current_resource, :members)
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_resource(name)
|
|
||||||
standard_create_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def maybe_modify_resource(name)
|
|
||||||
Chef::Log.info "Checking existing #{@current_cib_object} for modifications"
|
|
||||||
|
|
||||||
desired_group = cib_object_class.from_chef_resource(new_resource)
|
|
||||||
if desired_group.definition_string != @current_cib_object.definition_string
|
|
||||||
Chef::Log.debug "changed from [#{@current_cib_object.definition_string}] to [#{desired_group.definition_string}]"
|
|
||||||
cmd = desired_group.reconfigure_command
|
|
||||||
execute cmd do
|
|
||||||
action :nothing
|
|
||||||
end.run_action(:run)
|
|
||||||
new_resource.updated_by_last_action(true)
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,72 +0,0 @@
|
|||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
this_dir = ::File.dirname(__FILE__)
|
|
||||||
require ::File.expand_path('../libraries/pacemaker', this_dir)
|
|
||||||
require ::File.expand_path('../libraries/chef/mixin/pacemaker', this_dir)
|
|
||||||
|
|
||||||
include Chef::Mixin::Pacemaker::StandardCIBObject
|
|
||||||
|
|
||||||
action :create do
|
|
||||||
name = new_resource.name
|
|
||||||
|
|
||||||
if @current_resource_definition.nil?
|
|
||||||
create_resource(name)
|
|
||||||
else
|
|
||||||
maybe_modify_resource(name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
action :delete do
|
|
||||||
next unless @current_resource
|
|
||||||
standard_delete_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def cib_object_class
|
|
||||||
::Pacemaker::Constraint::Location
|
|
||||||
end
|
|
||||||
|
|
||||||
def load_current_resource
|
|
||||||
standard_load_current_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def init_current_resource
|
|
||||||
name = @new_resource.name
|
|
||||||
@current_resource = Chef::Resource::PacemakerLocation.new(name)
|
|
||||||
attrs = [:rsc, :score, :node]
|
|
||||||
@current_cib_object.copy_attrs_to_chef_resource(@current_resource, *attrs)
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_resource(name)
|
|
||||||
standard_create_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def maybe_modify_resource(name)
|
|
||||||
Chef::Log.info "Checking existing #{@current_cib_object} for modifications"
|
|
||||||
|
|
||||||
desired_location = cib_object_class.from_chef_resource(new_resource)
|
|
||||||
if desired_location.definition_string != @current_cib_object.definition_string
|
|
||||||
Chef::Log.debug "changed from [#{@current_cib_object.definition_string}] to [#{desired_location.definition_string}]"
|
|
||||||
cmd = desired_location.reconfigure_command
|
|
||||||
execute cmd do
|
|
||||||
action :nothing
|
|
||||||
end.run_action(:run)
|
|
||||||
new_resource.updated_by_last_action(true)
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,72 +0,0 @@
|
|||||||
# Cookbook Name:: pacemaker
|
|
||||||
# Provider:: ms
|
|
||||||
#
|
|
||||||
# Copyright:: 2013, Robert Choi
|
|
||||||
# Copyright:: 2014, SUSE
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
this_dir = ::File.dirname(__FILE__)
|
|
||||||
require ::File.expand_path('../libraries/pacemaker', this_dir)
|
|
||||||
require ::File.expand_path('../libraries/chef/mixin/pacemaker', this_dir)
|
|
||||||
|
|
||||||
include Chef::Mixin::Pacemaker::RunnableResource
|
|
||||||
|
|
||||||
action :create do
|
|
||||||
standard_create_action
|
|
||||||
end
|
|
||||||
|
|
||||||
action :delete do
|
|
||||||
delete_runnable_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
action :start do
|
|
||||||
start_runnable_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
action :stop do
|
|
||||||
stop_runnable_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def cib_object_class
|
|
||||||
::Pacemaker::Resource::MasterSlave
|
|
||||||
end
|
|
||||||
|
|
||||||
def load_current_resource
|
|
||||||
standard_load_current_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def init_current_resource
|
|
||||||
name = @new_resource.name
|
|
||||||
@current_resource = Chef::Resource::PacemakerMs.new(name)
|
|
||||||
@current_cib_object.copy_attrs_to_chef_resource(@current_resource, :rsc)
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_resource(name)
|
|
||||||
standard_create_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def maybe_modify_resource(name)
|
|
||||||
Chef::Log.info "Checking existing #{@current_cib_object} for modifications"
|
|
||||||
|
|
||||||
desired_clone = cib_object_class.from_chef_resource(new_resource)
|
|
||||||
if desired_clone.definition_string != @current_cib_object.definition_string
|
|
||||||
Chef::Log.debug "changed from [#{@current_cib_object.definition_string}] to [#{desired_clone.definition_string}]"
|
|
||||||
cmd = desired_clone.reconfigure_command
|
|
||||||
execute cmd do
|
|
||||||
action :nothing
|
|
||||||
end.run_action(:run)
|
|
||||||
new_resource.updated_by_last_action(true)
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,73 +0,0 @@
|
|||||||
# Cookbook Name:: pacemaker
|
|
||||||
# Provider:: order
|
|
||||||
#
|
|
||||||
# Copyright:: 2013, Robert Choi
|
|
||||||
# Copyright:: 2014, SUSE
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
this_dir = ::File.dirname(__FILE__)
|
|
||||||
require ::File.expand_path('../libraries/pacemaker/cib_object', this_dir)
|
|
||||||
require ::File.expand_path('../libraries/pacemaker', this_dir)
|
|
||||||
require ::File.expand_path('../libraries/chef/mixin/pacemaker', this_dir)
|
|
||||||
|
|
||||||
include Chef::Mixin::Pacemaker::StandardCIBObject
|
|
||||||
|
|
||||||
action :create do
|
|
||||||
name = new_resource.name
|
|
||||||
|
|
||||||
if @current_resource_definition.nil?
|
|
||||||
create_resource(name)
|
|
||||||
else
|
|
||||||
maybe_modify_resource(name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
action :delete do
|
|
||||||
next unless @current_resource
|
|
||||||
standard_delete_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def cib_object_class
|
|
||||||
::Pacemaker::Constraint::Order
|
|
||||||
end
|
|
||||||
|
|
||||||
def load_current_resource
|
|
||||||
standard_load_current_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def init_current_resource
|
|
||||||
name = @new_resource.name
|
|
||||||
@current_resource = Chef::Resource::PacemakerOrder.new(name)
|
|
||||||
attrs = [:score, :ordering]
|
|
||||||
@current_cib_object.copy_attrs_to_chef_resource(@current_resource, *attrs)
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_resource(name)
|
|
||||||
standard_create_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def maybe_modify_resource(name)
|
|
||||||
Chef::Log.info "Checking existing #{@current_cib_object} for modifications"
|
|
||||||
|
|
||||||
desired_order = cib_object_class.from_chef_resource(new_resource)
|
|
||||||
if desired_order.definition_string != @current_cib_object.definition_string
|
|
||||||
Chef::Log.debug "changed from [#{@current_cib_object.definition_string}] to [#{desired_order.definition_string}]"
|
|
||||||
cmd = desired_order.reconfigure_command
|
|
||||||
execute cmd do
|
|
||||||
action :nothing
|
|
||||||
end.run_action(:run)
|
|
||||||
new_resource.updated_by_last_action(true)
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,146 +0,0 @@
|
|||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
this_dir = ::File.dirname(__FILE__)
|
|
||||||
require ::File.expand_path('../libraries/pacemaker', this_dir)
|
|
||||||
require ::File.expand_path('../libraries/chef/mixin/pacemaker', this_dir)
|
|
||||||
|
|
||||||
include Chef::Mixin::Pacemaker::RunnableResource
|
|
||||||
|
|
||||||
action :create do
|
|
||||||
name = new_resource.name
|
|
||||||
|
|
||||||
if @current_resource_definition.nil?
|
|
||||||
create_resource(name)
|
|
||||||
else
|
|
||||||
if @current_resource.agent != new_resource.agent
|
|
||||||
raise "Existing %s has agent '%s' " \
|
|
||||||
"but recipe wanted '%s'" % \
|
|
||||||
[ @current_cib_object, @current_resource.agent, new_resource.agent ]
|
|
||||||
end
|
|
||||||
|
|
||||||
maybe_modify_resource(name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
action :delete do
|
|
||||||
delete_runnable_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
action :start do
|
|
||||||
start_runnable_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
action :stop do
|
|
||||||
stop_runnable_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def cib_object_class
|
|
||||||
::Pacemaker::Resource::Primitive
|
|
||||||
end
|
|
||||||
|
|
||||||
def load_current_resource
|
|
||||||
standard_load_current_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def init_current_resource
|
|
||||||
name = @new_resource.name
|
|
||||||
@current_resource = Chef::Resource::PacemakerPrimitive.new(name)
|
|
||||||
@current_cib_object.copy_attrs_to_chef_resource(@current_resource,
|
|
||||||
:agent, :params, :meta)
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_resource(name)
|
|
||||||
standard_create_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def maybe_modify_resource(name)
|
|
||||||
deprecate_target_role
|
|
||||||
|
|
||||||
Chef::Log.info "Checking existing #{@current_cib_object} for modifications"
|
|
||||||
|
|
||||||
cmds = []
|
|
||||||
|
|
||||||
desired_primitive = cib_object_class.from_chef_resource(new_resource)
|
|
||||||
|
|
||||||
# We deprecated setting target-role values via the meta attribute, in favor
|
|
||||||
# of :start/:stop actions on the resource. So this should not be relied upon
|
|
||||||
# anymore, and it's safe to drop this if we want to.
|
|
||||||
#
|
|
||||||
# There is one racy case where this matters:
|
|
||||||
# - node1 and node2 try to create a primitive with the chef resource;
|
|
||||||
# on initial creation, we set target-role='Stopped' because we do not
|
|
||||||
# want to autostart primitives.
|
|
||||||
# - because they can't create it at the same time, node2 will fail on
|
|
||||||
# creation. If the chef resource is configured to retry, then node2 will
|
|
||||||
# then try to update the primitive (since it now exists); but the chef
|
|
||||||
# resource is not reloaded so still has target-role='Stopped'.
|
|
||||||
# - if node1 had also started the primitive before node2 retries the
|
|
||||||
# :create, then the target-role will be changed from 'Started' to
|
|
||||||
# 'Stopped' with the update.
|
|
||||||
#
|
|
||||||
# This can result in a primitive not being started with [:create, :start].
|
|
||||||
# Therefore, we just delete this deprecated bit from meta to avoid any issue.
|
|
||||||
desired_primitive.meta.delete('target-role')
|
|
||||||
|
|
||||||
if desired_primitive.op_string != @current_cib_object.op_string
|
|
||||||
Chef::Log.debug "op changed from [#{@current_cib_object.op_string}] to [#{desired_primitive.op_string}]"
|
|
||||||
cmds = [desired_primitive.reconfigure_command]
|
|
||||||
else
|
|
||||||
maybe_configure_params(name, cmds, :params)
|
|
||||||
maybe_configure_params(name, cmds, :meta)
|
|
||||||
end
|
|
||||||
|
|
||||||
cmds.each do |cmd|
|
|
||||||
execute cmd do
|
|
||||||
action :nothing
|
|
||||||
end.run_action(:run)
|
|
||||||
end
|
|
||||||
|
|
||||||
new_resource.updated_by_last_action(true) unless cmds.empty?
|
|
||||||
end
|
|
||||||
|
|
||||||
def maybe_configure_params(name, cmds, data_type)
|
|
||||||
configure_cmd_prefix = "crm_resource --resource #{name}"
|
|
||||||
|
|
||||||
new_resource.send(data_type).each do |param, new_value|
|
|
||||||
current_value = @current_resource.send(data_type)[param]
|
|
||||||
# Value from recipe might be a TrueClass instance, but the same
|
|
||||||
# value would be retrieved from the cluster resource as the String
|
|
||||||
# "true". So we force a string-wise comparison to adhere to
|
|
||||||
# Postel's Law whilst minimising activity on the Chef client node.
|
|
||||||
if current_value.to_s == new_value.to_s
|
|
||||||
Chef::Log.info("#{name}'s #{param} #{data_type} didn't change")
|
|
||||||
else
|
|
||||||
Chef::Log.info("#{name}'s #{param} #{data_type} changed from #{current_value} to #{new_value}")
|
|
||||||
cmd = configure_cmd_prefix + %' --set-parameter "#{param}" --parameter-value "#{new_value}"'
|
|
||||||
cmd += " --meta" if data_type == :meta
|
|
||||||
cmds << cmd
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@current_resource.send(data_type).each do |param, value|
|
|
||||||
unless new_resource.send(data_type).has_key? param
|
|
||||||
Chef::Log.info("#{name}'s #{param} #{data_type} was removed")
|
|
||||||
cmd = configure_cmd_prefix + %' --delete-parameter "#{param}"'
|
|
||||||
cmd += " --meta" if data_type == :meta
|
|
||||||
cmds << cmd
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,45 +0,0 @@
|
|||||||
# Author:: Robert Choi
|
|
||||||
# Cookbook Name:: pacemaker
|
|
||||||
# Provider:: property
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
this_dir = ::File.dirname(__FILE__)
|
|
||||||
require ::File.expand_path('../libraries/pacemaker/cib_object', this_dir)
|
|
||||||
|
|
||||||
action :create do
|
|
||||||
name = new_resource.name
|
|
||||||
val = new_resource.value
|
|
||||||
|
|
||||||
unless resource_exists?(name)
|
|
||||||
cmd = "crm configure property #{name}=#{val}"
|
|
||||||
|
|
||||||
cmd_ = Mixlib::ShellOut.new(cmd)
|
|
||||||
cmd_.environment['HOME'] = ENV.fetch('HOME', '/root')
|
|
||||||
cmd_.run_command
|
|
||||||
begin
|
|
||||||
cmd_.error!
|
|
||||||
if resource_exists?(name)
|
|
||||||
new_resource.updated_by_last_action(true)
|
|
||||||
Chef::Log.info "Successfully configured property '#{name}'."
|
|
||||||
else
|
|
||||||
Chef::Log.error "Failed to configure property #{name}."
|
|
||||||
end
|
|
||||||
rescue
|
|
||||||
Chef::Log.error "Failed to configure property #{name}."
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,84 +0,0 @@
|
|||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
node[:pacemaker][:platform][:packages].each do |pkg|
|
|
||||||
package pkg
|
|
||||||
end
|
|
||||||
|
|
||||||
if node[:pacemaker][:setup_hb_gui]
|
|
||||||
node[:pacemaker][:platform][:graphical_packages].each do |pkg|
|
|
||||||
package pkg
|
|
||||||
end
|
|
||||||
|
|
||||||
# required to run hb_gui
|
|
||||||
if platform_family? "suse"
|
|
||||||
cmd = "SuSEconfig --module gtk2"
|
|
||||||
execute cmd do
|
|
||||||
user "root"
|
|
||||||
command cmd
|
|
||||||
not_if { File.exists? "/etc/gtk-2.0/gdk-pixbuf64.loaders" }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if Chef::Config[:solo]
|
|
||||||
unless ENV['RSPEC_RUNNING']
|
|
||||||
Chef::Application.fatal! \
|
|
||||||
"pacemaker::default needs corosync::default which uses search, " \
|
|
||||||
"but Chef Solo does not support search."
|
|
||||||
return
|
|
||||||
end
|
|
||||||
else
|
|
||||||
include_recipe "corosync::default"
|
|
||||||
end
|
|
||||||
|
|
||||||
ruby_block "wait for cluster to be online" do
|
|
||||||
block do
|
|
||||||
require 'timeout'
|
|
||||||
begin
|
|
||||||
Timeout.timeout(60) do
|
|
||||||
cmd = "crm_mon -1 | grep -qi online"
|
|
||||||
while ! ::Kernel.system(cmd)
|
|
||||||
Chef::Log.debug("cluster not online yet")
|
|
||||||
sleep(5)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
rescue Timeout::Error
|
|
||||||
message = "Pacemaker cluster not online yet; our first configuration changes might get lost (but will be reapplied on next chef run)."
|
|
||||||
Chef::Log.warn(message)
|
|
||||||
end
|
|
||||||
end # block
|
|
||||||
end # ruby_block
|
|
||||||
|
|
||||||
if node[:pacemaker][:founder]
|
|
||||||
include_recipe "pacemaker::setup"
|
|
||||||
end
|
|
||||||
|
|
||||||
if platform_family? "rhel"
|
|
||||||
execute "sleep 2"
|
|
||||||
|
|
||||||
service "pacemaker" do
|
|
||||||
action [ :enable, :start ]
|
|
||||||
notifies :restart, "service[clvm]", :immediately
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
include_recipe "pacemaker::stonith"
|
|
||||||
include_recipe "pacemaker::notifications"
|
|
@ -1,66 +0,0 @@
|
|||||||
#
|
|
||||||
# Author:: Vincent Untz
|
|
||||||
# Cookbook Name:: pacemaker
|
|
||||||
# Recipe:: notifications
|
|
||||||
#
|
|
||||||
# Copyright 2014, SUSE
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
smtp_resource = "smtp-notifications"
|
|
||||||
clone_smtp_resource = "cl-#{smtp_resource}"
|
|
||||||
|
|
||||||
if node[:pacemaker][:notifications][:smtp][:enabled]
|
|
||||||
raise "No SMTP server for mail notifications!" if node[:pacemaker][:notifications][:smtp][:server].empty?
|
|
||||||
raise "No sender address for mail notifications!" if node[:pacemaker][:notifications][:smtp][:to].empty?
|
|
||||||
raise "No recipient address for mail notifications!" if node[:pacemaker][:notifications][:smtp][:from].empty?
|
|
||||||
|
|
||||||
require 'shellwords'
|
|
||||||
|
|
||||||
server = Shellwords.shellescape(node[:pacemaker][:notifications][:smtp][:server])
|
|
||||||
to = Shellwords.shellescape(node[:pacemaker][:notifications][:smtp][:to])
|
|
||||||
from = Shellwords.shellescape(node[:pacemaker][:notifications][:smtp][:from])
|
|
||||||
|
|
||||||
options = "-H #{server}"
|
|
||||||
options += " -T #{to}"
|
|
||||||
options += " -F #{from}"
|
|
||||||
|
|
||||||
unless node[:pacemaker][:notifications][:smtp][:prefix].nil? || node[:pacemaker][:notifications][:smtp][:prefix].empty?
|
|
||||||
prefix = Shellwords.shellescape(node[:pacemaker][:notifications][:smtp][:prefix])
|
|
||||||
options += " -P #{prefix}"
|
|
||||||
end
|
|
||||||
|
|
||||||
pacemaker_primitive smtp_resource do
|
|
||||||
agent node[:pacemaker][:notifications][:agent]
|
|
||||||
params ({ "extra_options" => options })
|
|
||||||
action :create
|
|
||||||
end
|
|
||||||
|
|
||||||
pacemaker_clone clone_smtp_resource do
|
|
||||||
rsc smtp_resource
|
|
||||||
action [:create, :start]
|
|
||||||
end
|
|
||||||
else
|
|
||||||
pacemaker_clone clone_smtp_resource do
|
|
||||||
rsc smtp_resource
|
|
||||||
action [:stop, :delete]
|
|
||||||
only_if "crm configure show #{clone_smtp_resource}"
|
|
||||||
end
|
|
||||||
|
|
||||||
pacemaker_primitive smtp_resource do
|
|
||||||
agent node[:pacemaker][:notifications][:agent]
|
|
||||||
action [:stop, :delete]
|
|
||||||
only_if "crm configure show #{smtp_resource}"
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,40 +0,0 @@
|
|||||||
#
|
|
||||||
# Author:: Robert Choi
|
|
||||||
# Cookbook Name:: pacemaker
|
|
||||||
# Recipe:: setup
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
crm_conf = node[:pacemaker][:crm][:initial_config_file]
|
|
||||||
|
|
||||||
template crm_conf do
|
|
||||||
source "crm-initial.conf.erb"
|
|
||||||
owner "root"
|
|
||||||
group "root"
|
|
||||||
mode 0600
|
|
||||||
variables(
|
|
||||||
:stonith_enabled => (node[:pacemaker][:stonith][:mode] != "disabled"),
|
|
||||||
:no_quorum_policy => node[:pacemaker][:crm][:no_quorum_policy],
|
|
||||||
:op_default_timeout => node[:pacemaker][:crm][:op_default_timeout]
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
execute "crm initial configuration" do
|
|
||||||
user "root"
|
|
||||||
command "crm configure load replace #{crm_conf}"
|
|
||||||
subscribes :run, resources(:template => crm_conf), :immediately
|
|
||||||
action :nothing
|
|
||||||
end
|
|
@ -1,169 +0,0 @@
|
|||||||
#
|
|
||||||
# Author:: Vincent Untz
|
|
||||||
# Cookbook Name:: pacemaker
|
|
||||||
# Recipe:: stonith
|
|
||||||
#
|
|
||||||
# Copyright 2014, SUSE
|
|
||||||
#
|
|
||||||
# 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
# FIXME: delete old resources when switching mode (or agent!)
|
|
||||||
|
|
||||||
case node[:pacemaker][:stonith][:mode]
|
|
||||||
when "disabled"
|
|
||||||
when "manual"
|
|
||||||
# nothing!
|
|
||||||
|
|
||||||
when "sbd"
|
|
||||||
require 'shellwords'
|
|
||||||
|
|
||||||
sbd_devices = nil
|
|
||||||
sbd_devices ||= (node[:pacemaker][:stonith][:sbd][:nodes][node[:fqdn]][:devices] rescue nil)
|
|
||||||
sbd_devices ||= (node[:pacemaker][:stonith][:sbd][:nodes][node[:hostname]][:devices] rescue nil)
|
|
||||||
raise "No SBD devices defined!" if sbd_devices.nil? || sbd_devices.empty?
|
|
||||||
|
|
||||||
sbd_cmd = "sbd"
|
|
||||||
sbd_devices.each do |sbd_device|
|
|
||||||
sbd_cmd += " -d #{Shellwords.shellescape(sbd_device)}"
|
|
||||||
end
|
|
||||||
|
|
||||||
execute "Check if watchdog is present" do
|
|
||||||
command "test -c /dev/watchdog"
|
|
||||||
end
|
|
||||||
|
|
||||||
execute "Check that SBD was initialized using '#{sbd_cmd} create'." do
|
|
||||||
command "#{sbd_cmd} dump &> /dev/null"
|
|
||||||
end
|
|
||||||
|
|
||||||
if node.platform == 'suse'
|
|
||||||
# We will want to explicitly allocate a slot the first time we come here
|
|
||||||
# (hence the use of a notification to trigger this execute).
|
|
||||||
# According to the man page, it should not be required, but apparently,
|
|
||||||
# I've hit bugs where I had to do that. So better be safe.
|
|
||||||
execute "Allocate SBD slot" do
|
|
||||||
command "#{sbd_cmd} allocate #{node[:hostname]}"
|
|
||||||
not_if "#{sbd_cmd} list | grep -q \" #{node[:hostname]} \""
|
|
||||||
action :nothing
|
|
||||||
end
|
|
||||||
|
|
||||||
template "/etc/sysconfig/sbd" do
|
|
||||||
source "sysconfig_sbd.erb"
|
|
||||||
owner "root"
|
|
||||||
group "root"
|
|
||||||
mode 0644
|
|
||||||
variables(
|
|
||||||
:sbd_devices => sbd_devices
|
|
||||||
)
|
|
||||||
# We want to allocate slots before restarting corosync
|
|
||||||
notifies :run, "execute[Allocate SBD slot]", :immediately
|
|
||||||
notifies :restart, "service[#{node[:corosync][:platform][:service_name]}]", :immediately
|
|
||||||
# After restarting corosync, we need to wait for the cluster to be online again
|
|
||||||
notifies :create, "ruby_block[wait for cluster to be online]", :immediately
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
pacemaker_primitive "stonith-sbd" do
|
|
||||||
agent "stonith:external/sbd"
|
|
||||||
action [:create, :start]
|
|
||||||
end
|
|
||||||
|
|
||||||
when "shared"
|
|
||||||
agent = node[:pacemaker][:stonith][:shared][:agent]
|
|
||||||
params = node[:pacemaker][:stonith][:shared][:params]
|
|
||||||
|
|
||||||
# This needs to be done in the second phase of chef, because we need
|
|
||||||
# cluster-glue to be installed first; hence ruby_block
|
|
||||||
ruby_block "Check if STONITH fencing agent #{agent} is available" do
|
|
||||||
block do
|
|
||||||
PacemakerStonithHelper.assert_stonith_agent_valid agent
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if params.respond_to?('to_hash')
|
|
||||||
primitive_params = params.to_hash
|
|
||||||
elsif params.is_a?(String)
|
|
||||||
primitive_params = ::Pacemaker::Resource.extract_hash(" params #{params}", "params")
|
|
||||||
else
|
|
||||||
message = "Unknown format for shared fencing agent parameters: #{params.inspect}."
|
|
||||||
Chef::Log.fatal(message)
|
|
||||||
raise message
|
|
||||||
end
|
|
||||||
|
|
||||||
unless primitive_params.has_key?("hostlist")
|
|
||||||
message = "Missing hostlist parameter for shared fencing agent!"
|
|
||||||
Chef::Log.fatal(message)
|
|
||||||
raise message
|
|
||||||
end
|
|
||||||
|
|
||||||
pacemaker_primitive "stonith-shared" do
|
|
||||||
agent "stonith:#{agent}"
|
|
||||||
params primitive_params
|
|
||||||
action [:create, :start]
|
|
||||||
end
|
|
||||||
|
|
||||||
when "per_node"
|
|
||||||
agent = node[:pacemaker][:stonith][:per_node][:agent]
|
|
||||||
|
|
||||||
# This needs to be done in the second phase of chef, because we need
|
|
||||||
# cluster-glue to be installed first; hence ruby_block
|
|
||||||
ruby_block "Check if STONITH fencing agent #{agent} is available" do
|
|
||||||
block do
|
|
||||||
PacemakerStonithHelper.assert_stonith_agent_valid agent
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
node[:pacemaker][:stonith][:per_node][:nodes].keys.each do |node_name|
|
|
||||||
if node[:pacemaker][:stonith][:per_node][:mode] == "self"
|
|
||||||
next unless node_name == node[:hostname]
|
|
||||||
end
|
|
||||||
|
|
||||||
stonith_resource = "stonith-#{node_name}"
|
|
||||||
params = node[:pacemaker][:stonith][:per_node][:nodes][node_name][:params]
|
|
||||||
|
|
||||||
if params.respond_to?('to_hash')
|
|
||||||
primitive_params = params.to_hash
|
|
||||||
elsif params.is_a?(String)
|
|
||||||
primitive_params = ::Pacemaker::Resource.extract_hash(" params #{params}", "params")
|
|
||||||
else
|
|
||||||
message = "Unknown format for per-node fencing agent parameters of #{node_name}: #{params.inspect}."
|
|
||||||
Chef::Log.fatal(message)
|
|
||||||
raise message
|
|
||||||
end
|
|
||||||
|
|
||||||
# Only set one of hostname / hostlist param if none of them are present; we
|
|
||||||
# do not overwrite it as the user might have passed more information than
|
|
||||||
# just the hostname (some agents accept hostname:data in hostlist)
|
|
||||||
unless primitive_params.has_key?("hostname") || primitive_params.has_key?("hostlist")
|
|
||||||
primitive_params["hostname"] = node_name
|
|
||||||
end
|
|
||||||
|
|
||||||
pacemaker_primitive stonith_resource do
|
|
||||||
agent "stonith:#{agent}"
|
|
||||||
params primitive_params
|
|
||||||
action [:create, :start]
|
|
||||||
end
|
|
||||||
|
|
||||||
pacemaker_location "l-#{stonith_resource}" do
|
|
||||||
rsc stonith_resource
|
|
||||||
score "-inf"
|
|
||||||
node node_name
|
|
||||||
action :create
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
else
|
|
||||||
message = "Unknown STONITH mode: #{node[:pacemaker][:stonith][:mode]}."
|
|
||||||
Chef::Log.fatal(message)
|
|
||||||
raise message
|
|
||||||
end
|
|
@ -1,25 +0,0 @@
|
|||||||
# Cookbook Name:: pacemaker
|
|
||||||
# Resource:: clone
|
|
||||||
#
|
|
||||||
# Copyright:: 2013, Robert Choi, SUSE
|
|
||||||
#
|
|
||||||
# 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, :start, :stop
|
|
||||||
|
|
||||||
default_action :create
|
|
||||||
|
|
||||||
attribute :name, :kind_of => String, :name_attribute => true
|
|
||||||
attribute :rsc, :kind_of => String
|
|
||||||
attribute :meta, :kind_of => Hash, :default => {}
|
|
@ -1,29 +0,0 @@
|
|||||||
# 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 :score, :kind_of => String
|
|
||||||
|
|
||||||
# If more than two resources are given, Pacemaker will treat this
|
|
||||||
# as a resource set.
|
|
||||||
attribute :resources, :kind_of => Array
|
|
@ -1,25 +0,0 @@
|
|||||||
# Cookbook Name:: pacemaker
|
|
||||||
# Resource:: group
|
|
||||||
#
|
|
||||||
# Copyright:: 2014, SUSE
|
|
||||||
#
|
|
||||||
# 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, :start, :stop
|
|
||||||
|
|
||||||
default_action :create
|
|
||||||
|
|
||||||
attribute :name, :kind_of => String, :name_attribute => true
|
|
||||||
attribute :members, :kind_of => Array
|
|
||||||
attribute :meta, :kind_of => Hash, :default => {}
|
|
@ -1,27 +0,0 @@
|
|||||||
# 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 :score, :kind_of => String
|
|
||||||
attribute :node, :kind_of => String
|
|
@ -1,25 +0,0 @@
|
|||||||
# Cookbook Name:: pacemaker
|
|
||||||
# Resource:: ms
|
|
||||||
#
|
|
||||||
# Copyright:: 2013, Robert Choi, SUSE
|
|
||||||
#
|
|
||||||
# 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, :start, :stop
|
|
||||||
|
|
||||||
default_action :create
|
|
||||||
|
|
||||||
attribute :name, :kind_of => String, :name_attribute => true
|
|
||||||
attribute :rsc, :kind_of => String
|
|
||||||
attribute :meta, :kind_of => Hash, :default => {}
|
|
@ -1,26 +0,0 @@
|
|||||||
# 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 :score, :kind_of => String
|
|
||||||
attribute :ordering, :kind_of => String
|
|
@ -1,28 +0,0 @@
|
|||||||
# 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, :start, :stop
|
|
||||||
|
|
||||||
default_action :create
|
|
||||||
|
|
||||||
attribute :name, :kind_of => String, :name_attribute => true
|
|
||||||
attribute :agent, :kind_of => String
|
|
||||||
attribute :params, :kind_of => Hash, :default => {}
|
|
||||||
attribute :meta, :kind_of => Hash, :default => {}
|
|
||||||
attribute :op, :kind_of => Hash, :default => {}
|
|
@ -1,25 +0,0 @@
|
|||||||
# Author:: Robert Choi
|
|
||||||
# Cookbook Name:: pacemaker
|
|
||||||
# Resource:: property
|
|
||||||
#
|
|
||||||
# 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
|
|
||||||
|
|
||||||
default_action :create
|
|
||||||
|
|
||||||
attribute :name, :kind_of => String, :name_attribute => true
|
|
||||||
attribute :value, :kind_of => String
|
|
20
spec/fixtures/clone_resource.rb
vendored
20
spec/fixtures/clone_resource.rb
vendored
@ -1,20 +0,0 @@
|
|||||||
require File.expand_path('../../libraries/pacemaker/resource/clone',
|
|
||||||
File.dirname(__FILE__))
|
|
||||||
|
|
||||||
module Chef::RSpec
|
|
||||||
module Pacemaker
|
|
||||||
module Config
|
|
||||||
CLONE_RESOURCE = ::Pacemaker::Resource::Clone.new('clone1')
|
|
||||||
CLONE_RESOURCE.rsc = 'primitive1'
|
|
||||||
CLONE_RESOURCE.meta = [
|
|
||||||
[ "globally-unique", "true" ],
|
|
||||||
[ "clone-max", "2" ],
|
|
||||||
[ "clone-node-max", "2" ]
|
|
||||||
]
|
|
||||||
CLONE_RESOURCE_DEFINITION = <<'EOF'.chomp
|
|
||||||
clone clone1 primitive1 \
|
|
||||||
meta clone-max="2" clone-node-max="2" globally-unique="true"
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
14
spec/fixtures/colocation_constraint.rb
vendored
14
spec/fixtures/colocation_constraint.rb
vendored
@ -1,14 +0,0 @@
|
|||||||
require ::File.expand_path('../../libraries/pacemaker/constraint/colocation',
|
|
||||||
File.dirname(__FILE__))
|
|
||||||
|
|
||||||
module Chef::RSpec
|
|
||||||
module Pacemaker
|
|
||||||
module Config
|
|
||||||
COLOCATION_CONSTRAINT = \
|
|
||||||
::Pacemaker::Constraint::Colocation.new('colocation1')
|
|
||||||
COLOCATION_CONSTRAINT.score = 'inf'
|
|
||||||
COLOCATION_CONSTRAINT.resources = ['foo']
|
|
||||||
COLOCATION_CONSTRAINT_DEFINITION = 'colocation colocation1 inf: foo'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
31
spec/fixtures/keystone_primitive.rb
vendored
31
spec/fixtures/keystone_primitive.rb
vendored
@ -1,31 +0,0 @@
|
|||||||
require ::File.expand_path('../../libraries/pacemaker/resource/primitive',
|
|
||||||
File.dirname(__FILE__))
|
|
||||||
|
|
||||||
module Chef::RSpec
|
|
||||||
module Pacemaker
|
|
||||||
module Config
|
|
||||||
KEYSTONE_PRIMITIVE = ::Pacemaker::Resource::Primitive.new('keystone')
|
|
||||||
KEYSTONE_PRIMITIVE.agent = "ocf:openstack:keystone"
|
|
||||||
KEYSTONE_PRIMITIVE.params = [
|
|
||||||
[ "os_password", "adminpw" ],
|
|
||||||
[ "os_auth_url", "http://node1:5000/v2.0" ],
|
|
||||||
[ "os_username", "admin" ],
|
|
||||||
[ "os_tenant_name", "openstack" ],
|
|
||||||
[ "user", "openstack-keystone" ],
|
|
||||||
]
|
|
||||||
KEYSTONE_PRIMITIVE.meta = [
|
|
||||||
[ "is-managed", "true" ]
|
|
||||||
]
|
|
||||||
KEYSTONE_PRIMITIVE.op = [
|
|
||||||
[ "monitor", { "timeout" => "60", "interval" => "10s" } ],
|
|
||||||
[ "start", { "timeout" => "240", "interval" => "10s" } ]
|
|
||||||
]
|
|
||||||
KEYSTONE_PRIMITIVE_DEFINITION = <<'EOF'.chomp
|
|
||||||
primitive keystone ocf:openstack:keystone \
|
|
||||||
params os_auth_url="http://node1:5000/v2.0" os_password="adminpw" os_tenant_name="openstack" os_username="admin" user="openstack-keystone" \
|
|
||||||
meta is-managed="true" \
|
|
||||||
op monitor interval="10s" timeout="60" op start interval="10s" timeout="240"
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
15
spec/fixtures/location_constraint.rb
vendored
15
spec/fixtures/location_constraint.rb
vendored
@ -1,15 +0,0 @@
|
|||||||
require ::File.expand_path('../../libraries/pacemaker/constraint/location',
|
|
||||||
File.dirname(__FILE__))
|
|
||||||
|
|
||||||
module Chef::RSpec
|
|
||||||
module Pacemaker
|
|
||||||
module Config
|
|
||||||
LOCATION_CONSTRAINT = \
|
|
||||||
::Pacemaker::Constraint::Location.new('location1')
|
|
||||||
LOCATION_CONSTRAINT.rsc = 'primitive1'
|
|
||||||
LOCATION_CONSTRAINT.score = '-inf'
|
|
||||||
LOCATION_CONSTRAINT.node = 'node1'
|
|
||||||
LOCATION_CONSTRAINT_DEFINITION = 'location location1 primitive1 -inf: node1'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
22
spec/fixtures/ms_resource.rb
vendored
22
spec/fixtures/ms_resource.rb
vendored
@ -1,22 +0,0 @@
|
|||||||
require File.expand_path('../../libraries/pacemaker/resource/ms',
|
|
||||||
File.dirname(__FILE__))
|
|
||||||
|
|
||||||
module Chef::RSpec
|
|
||||||
module Pacemaker
|
|
||||||
module Config
|
|
||||||
MS_RESOURCE = ::Pacemaker::Resource::MasterSlave.new('ms1')
|
|
||||||
MS_RESOURCE.rsc = 'primitive1'
|
|
||||||
MS_RESOURCE.meta = [
|
|
||||||
[ "globally-unique", "true" ],
|
|
||||||
[ "clone-max", "2" ],
|
|
||||||
[ "clone-node-max", "2" ],
|
|
||||||
[ "master-max", "1" ],
|
|
||||||
[ "master-node-max", "1" ]
|
|
||||||
]
|
|
||||||
MS_RESOURCE_DEFINITION = <<'EOF'.chomp
|
|
||||||
ms ms1 primitive1 \
|
|
||||||
meta clone-max="2" clone-node-max="2" globally-unique="true" master-max="1" master-node-max="1"
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
14
spec/fixtures/order_constraint.rb
vendored
14
spec/fixtures/order_constraint.rb
vendored
@ -1,14 +0,0 @@
|
|||||||
require ::File.expand_path('../../libraries/pacemaker/constraint/order',
|
|
||||||
File.dirname(__FILE__))
|
|
||||||
|
|
||||||
module Chef::RSpec
|
|
||||||
module Pacemaker
|
|
||||||
module Config
|
|
||||||
ORDER_CONSTRAINT = \
|
|
||||||
::Pacemaker::Constraint::Order.new('order1')
|
|
||||||
ORDER_CONSTRAINT.score = 'Mandatory'
|
|
||||||
ORDER_CONSTRAINT.ordering = 'primitive1 clone1'
|
|
||||||
ORDER_CONSTRAINT_DEFINITION = 'order order1 Mandatory: primitive1 clone1'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
19
spec/fixtures/resource_group.rb
vendored
19
spec/fixtures/resource_group.rb
vendored
@ -1,19 +0,0 @@
|
|||||||
require File.expand_path('../../libraries/pacemaker/resource/group',
|
|
||||||
File.dirname(__FILE__))
|
|
||||||
|
|
||||||
module Chef::RSpec
|
|
||||||
module Pacemaker
|
|
||||||
module Config
|
|
||||||
RESOURCE_GROUP = \
|
|
||||||
::Pacemaker::Resource::Group.new('group1')
|
|
||||||
RESOURCE_GROUP.members = ['resource1', 'resource2']
|
|
||||||
RESOURCE_GROUP.meta = [
|
|
||||||
[ "is-managed", "true" ]
|
|
||||||
]
|
|
||||||
RESOURCE_GROUP_DEFINITION = <<'EOF'.chomp
|
|
||||||
group group1 resource1 resource2 \
|
|
||||||
meta is-managed="true"
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,37 +0,0 @@
|
|||||||
# Shared code used to test subclasses of Pacemaker::CIBObject
|
|
||||||
|
|
||||||
require 'mixlib/shellout'
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../../libraries/pacemaker/cib_object', this_dir)
|
|
||||||
require File.expand_path('shellout', this_dir)
|
|
||||||
|
|
||||||
shared_examples "a CIB object" do
|
|
||||||
include Chef::RSpec::Mixlib::ShellOut
|
|
||||||
|
|
||||||
def expect_to_match_fixture(obj)
|
|
||||||
expect(obj.class).to eq(pacemaker_object_class)
|
|
||||||
fields.each do |field|
|
|
||||||
method = field.to_sym
|
|
||||||
expect(obj.send(method)).to eq(fixture.send(method))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should be instantiated via Pacemaker::CIBObject.from_name" do
|
|
||||||
stub_shellout(fixture.definition_string)
|
|
||||||
obj = Pacemaker::CIBObject.from_name(fixture.name)
|
|
||||||
expect_to_match_fixture(obj)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should instantiate by parsing a definition" do
|
|
||||||
obj = Pacemaker::CIBObject.from_definition(fixture.definition_string)
|
|
||||||
expect_to_match_fixture(obj)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should barf if the loaded definition's type is not right" do
|
|
||||||
stub_shellout("sometype foo blah blah")
|
|
||||||
expect { fixture.load_definition }.to \
|
|
||||||
raise_error(Pacemaker::CIBObject::TypeMismatch,
|
|
||||||
"Expected #{object_type} type but loaded definition was type sometype")
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,21 +0,0 @@
|
|||||||
shared_examples "with meta attributes" do
|
|
||||||
describe "#meta_string" do
|
|
||||||
it "should return empty string with nil meta" do
|
|
||||||
fixture.meta = nil
|
|
||||||
expect(fixture.meta_string).to eq("")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return empty string with empty meta" do
|
|
||||||
fixture.meta = {}
|
|
||||||
expect(fixture.meta_string).to eq("")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return a resource meta string" do
|
|
||||||
fixture.meta = {
|
|
||||||
"foo" => "bar",
|
|
||||||
"baz" => "qux",
|
|
||||||
}
|
|
||||||
expect(fixture.meta_string).to eq(%'meta baz="qux" foo="bar"')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,26 +0,0 @@
|
|||||||
# Shared code used to test providers of non-runnable Chef resources
|
|
||||||
# representing Pacemaker CIB objects. For example the provider for
|
|
||||||
# primitives is runnable (since primitives can be started and stopped)
|
|
||||||
# but constraints cannot.
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('provider', this_dir)
|
|
||||||
require File.expand_path('shellout', this_dir)
|
|
||||||
|
|
||||||
shared_examples "a non-runnable resource" do |fixture|
|
|
||||||
include Chef::RSpec::Mixlib::ShellOut
|
|
||||||
|
|
||||||
it_should_behave_like "all Pacemaker LWRPs", fixture
|
|
||||||
|
|
||||||
describe ":delete action" do
|
|
||||||
it "should delete a resource" do
|
|
||||||
stub_shellout(fixture.definition_string)
|
|
||||||
|
|
||||||
provider.run_action :delete
|
|
||||||
|
|
||||||
cmd = "crm configure delete '#{fixture.name}'"
|
|
||||||
expect(@chef_run).to run_execute(cmd)
|
|
||||||
expect(@resource).to be_updated
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,74 +0,0 @@
|
|||||||
# Shared code used to test providers of CIB objects
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('shellout', this_dir)
|
|
||||||
require File.expand_path('cib_object', this_dir)
|
|
||||||
|
|
||||||
shared_context "a Pacemaker LWRP" do
|
|
||||||
before(:each) do
|
|
||||||
stub_command("crm configure show smtp-notifications")
|
|
||||||
stub_command("crm configure show cl-smtp-notifications")
|
|
||||||
|
|
||||||
runner_opts = {
|
|
||||||
:step_into => [lwrp_name]
|
|
||||||
}
|
|
||||||
@chef_run = ::ChefSpec::Runner.new(runner_opts)
|
|
||||||
@chef_run.converge "pacemaker::default"
|
|
||||||
@node = @chef_run.node
|
|
||||||
@run_context = @chef_run.run_context
|
|
||||||
|
|
||||||
camelized_subclass_name = "Pacemaker" + lwrp_name.capitalize
|
|
||||||
@resource_class = ::Chef::Resource.const_get(camelized_subclass_name)
|
|
||||||
@provider_class = ::Chef::Provider.const_get(camelized_subclass_name)
|
|
||||||
|
|
||||||
@resource = @resource_class.new(fixture.name, @run_context)
|
|
||||||
end
|
|
||||||
|
|
||||||
let (:provider) { @provider_class.new(@resource, @run_context) }
|
|
||||||
end
|
|
||||||
|
|
||||||
module Chef::RSpec
|
|
||||||
module Pacemaker
|
|
||||||
module CIBObject
|
|
||||||
include Chef::RSpec::Mixlib::ShellOut
|
|
||||||
|
|
||||||
def test_modify(expected_cmds)
|
|
||||||
yield
|
|
||||||
|
|
||||||
stub_shellout(fixture.definition_string)
|
|
||||||
|
|
||||||
provider.run_action :create
|
|
||||||
|
|
||||||
expected_cmds.each do |cmd|
|
|
||||||
expect(@chef_run).to run_execute(cmd)
|
|
||||||
end
|
|
||||||
expect(@resource).to be_updated
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
shared_examples "action on non-existent resource" do |action, cmd, expected_error|
|
|
||||||
include Chef::RSpec::Mixlib::ShellOut
|
|
||||||
|
|
||||||
it "should not attempt to #{action.to_s} a non-existent resource" do
|
|
||||||
stub_shellout("")
|
|
||||||
|
|
||||||
if expected_error
|
|
||||||
expect { provider.run_action action }.to \
|
|
||||||
raise_error(RuntimeError, expected_error)
|
|
||||||
else
|
|
||||||
provider.run_action action
|
|
||||||
end
|
|
||||||
|
|
||||||
expect(@chef_run).not_to run_execute(cmd)
|
|
||||||
expect(@resource).not_to be_updated
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
shared_examples "all Pacemaker LWRPs" do |fixture|
|
|
||||||
describe ":delete action" do
|
|
||||||
it_should_behave_like "action on non-existent resource", \
|
|
||||||
:delete, "crm configure delete #{fixture.name}", nil
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,128 +0,0 @@
|
|||||||
# Shared code used to test providers of runnable Chef resources
|
|
||||||
# representing Pacemaker CIB objects. For example the provider
|
|
||||||
# for primitives is runnable (since primitives can be started
|
|
||||||
# and stopped) but constraints cannot.
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('provider', this_dir)
|
|
||||||
require File.expand_path('shellout', this_dir)
|
|
||||||
|
|
||||||
shared_context "stopped resource" do
|
|
||||||
def stopped_fixture
|
|
||||||
new_fixture = fixture.dup
|
|
||||||
new_fixture.meta = fixture.meta.dup
|
|
||||||
new_fixture.meta << ['target-role', 'Stopped']
|
|
||||||
new_fixture
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
shared_examples "a runnable resource" do |fixture|
|
|
||||||
def expect_running(running)
|
|
||||||
expect_any_instance_of(cib_object_class) \
|
|
||||||
.to receive(:running?) \
|
|
||||||
.and_return(running)
|
|
||||||
end
|
|
||||||
|
|
||||||
it_should_behave_like "all Pacemaker LWRPs", fixture
|
|
||||||
|
|
||||||
include Chef::RSpec::Mixlib::ShellOut
|
|
||||||
|
|
||||||
describe ":create action" do
|
|
||||||
include_context "stopped resource"
|
|
||||||
|
|
||||||
it "should not start a newly-created resource" do
|
|
||||||
stub_shellout("", fixture.definition_string)
|
|
||||||
|
|
||||||
provider.run_action :create
|
|
||||||
|
|
||||||
expect(@chef_run).to run_execute(stopped_fixture.configure_command)
|
|
||||||
expect(@resource).to be_updated
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe ":delete action" do
|
|
||||||
it "should not delete a running resource" do
|
|
||||||
stub_shellout(fixture.definition_string)
|
|
||||||
expect_running(true)
|
|
||||||
|
|
||||||
expected_error = "Cannot delete running #{fixture}"
|
|
||||||
expect { provider.run_action :delete }.to \
|
|
||||||
raise_error(RuntimeError, expected_error)
|
|
||||||
|
|
||||||
cmd = "crm configure delete '#{fixture.name}'"
|
|
||||||
expect(@chef_run).not_to run_execute(cmd)
|
|
||||||
expect(@resource).not_to be_updated
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should delete a non-running resource" do
|
|
||||||
stub_shellout(fixture.definition_string)
|
|
||||||
expect_running(false)
|
|
||||||
|
|
||||||
provider.run_action :delete
|
|
||||||
|
|
||||||
cmd = "crm configure delete '#{fixture.name}'"
|
|
||||||
expect(@chef_run).to run_execute(cmd)
|
|
||||||
expect(@resource).to be_updated
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe ":start action" do
|
|
||||||
it_should_behave_like "action on non-existent resource", \
|
|
||||||
:start,
|
|
||||||
"crm --force --wait resource start #{fixture.name}", \
|
|
||||||
"Cannot start non-existent #{fixture}"
|
|
||||||
|
|
||||||
it "should do nothing to a started resource" do
|
|
||||||
stub_shellout(fixture.definition_string)
|
|
||||||
expect_running(true)
|
|
||||||
|
|
||||||
provider.run_action :start
|
|
||||||
|
|
||||||
cmd = "crm --force --wait resource start #{fixture.name}"
|
|
||||||
expect(@chef_run).not_to run_execute(cmd)
|
|
||||||
expect(@resource).not_to be_updated
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should start a stopped resource" do
|
|
||||||
config = fixture.definition_string.sub("Started", "Stopped")
|
|
||||||
stub_shellout(config)
|
|
||||||
expect_running(false)
|
|
||||||
|
|
||||||
provider.run_action :start
|
|
||||||
|
|
||||||
cmd = "crm --force --wait resource start '#{fixture.name}'"
|
|
||||||
expect(@chef_run).to run_execute(cmd)
|
|
||||||
expect(@resource).to be_updated
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe ":stop action" do
|
|
||||||
it_should_behave_like "action on non-existent resource", \
|
|
||||||
:stop,
|
|
||||||
"crm --force --wait resource stop #{fixture.name}", \
|
|
||||||
"Cannot stop non-existent #{fixture}"
|
|
||||||
|
|
||||||
it "should do nothing to a stopped resource" do
|
|
||||||
stub_shellout(fixture.definition_string)
|
|
||||||
expect_running(false)
|
|
||||||
|
|
||||||
provider.run_action :stop
|
|
||||||
|
|
||||||
cmd = "crm --force --wait resource start #{fixture.name}"
|
|
||||||
expect(@chef_run).not_to run_execute(cmd)
|
|
||||||
expect(@resource).not_to be_updated
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should stop a started resource" do
|
|
||||||
stub_shellout(fixture.definition_string)
|
|
||||||
expect_running(true)
|
|
||||||
|
|
||||||
provider.run_action :stop
|
|
||||||
|
|
||||||
cmd = "crm --force --wait resource stop '#{fixture.name}'"
|
|
||||||
expect(@chef_run).to run_execute(cmd)
|
|
||||||
expect(@resource).to be_updated
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
@ -1,68 +0,0 @@
|
|||||||
require 'mixlib/shellout'
|
|
||||||
|
|
||||||
module Chef::RSpec
|
|
||||||
module Mixlib
|
|
||||||
module ShellOut
|
|
||||||
# Return a Mixlib::ShellOut double which mimics successful
|
|
||||||
# execution of a command, returning the given string on STDOUT.
|
|
||||||
def succeeding_shellout_double(string)
|
|
||||||
shellout = double(Mixlib::ShellOut)
|
|
||||||
shellout.stub(:environment).and_return({})
|
|
||||||
shellout.stub(:run_command)
|
|
||||||
shellout.stub(:error!)
|
|
||||||
expect(shellout).to receive(:stdout).and_return(string)
|
|
||||||
shellout
|
|
||||||
end
|
|
||||||
|
|
||||||
# Return a Mixlib::ShellOut double which mimics failed
|
|
||||||
# execution of a command, raising an exception when #error! is
|
|
||||||
# called. We expect #error! to be called, because if it isn't,
|
|
||||||
# that probably indicates the code isn't robust enough. This
|
|
||||||
# may need to be relaxed in the future.
|
|
||||||
def failing_shellout_double(stdout='', stderr='', exitstatus=1)
|
|
||||||
shellout = double(Mixlib::ShellOut)
|
|
||||||
shellout.stub(:environment).and_return({})
|
|
||||||
shellout.stub(:run_command)
|
|
||||||
shellout.stub(:stdout).and_return(stdout)
|
|
||||||
shellout.stub(:stderr).and_return(stderr)
|
|
||||||
shellout.stub(:exitstatus).and_return(exitstatus)
|
|
||||||
exception = ::Mixlib::ShellOut::ShellCommandFailed.new(
|
|
||||||
"Expected process to exit with 0, " +
|
|
||||||
"but received '#{exitstatus}'"
|
|
||||||
)
|
|
||||||
expect(shellout).to receive(:error!).and_raise(exception)
|
|
||||||
shellout
|
|
||||||
end
|
|
||||||
|
|
||||||
# This stubs Mixlib::ShellOut.new with a sequence of doubles
|
|
||||||
# with a corresponding sequence of behaviours. This allows us
|
|
||||||
# to simulate the output of a series of shell commands being run
|
|
||||||
# via Mixlib::ShellOut. Each double either mimics a successful
|
|
||||||
# command execution whose #stdout method returns the given
|
|
||||||
# string, or a failed execution with the given exit code and
|
|
||||||
# STDOUT/STDERR.
|
|
||||||
#
|
|
||||||
# results is an Array describing the sequence of behaviours;
|
|
||||||
# each element is either a string mimicking STDOUT from
|
|
||||||
# successful command execution, or a [stdout, stderr, exitcode]
|
|
||||||
# status mimicking command execution failure.
|
|
||||||
#
|
|
||||||
# For example, "crm configure show" is executed by
|
|
||||||
# #load_current_resource, and again later on for the :create
|
|
||||||
# action, to see whether to create or modify. So the first
|
|
||||||
# double in the sequence would return an empty definition if we
|
|
||||||
# wanted to test creation of a new CIB object, or an existing
|
|
||||||
# definition if we wanted to test modification of an existing
|
|
||||||
# one. If the test needs subsequent doubles to return different
|
|
||||||
# values then stdout_strings can have more than one element.
|
|
||||||
def stub_shellout(*results)
|
|
||||||
doubles = results.map { |result|
|
|
||||||
result.is_a?(String) ?
|
|
||||||
succeeding_shellout_double(result)
|
|
||||||
: failing_shellout_double(*result)
|
|
||||||
}
|
|
||||||
::Mixlib::ShellOut.stub(:new).and_return(*doubles)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,107 +0,0 @@
|
|||||||
require 'mixlib/shellout'
|
|
||||||
|
|
||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../../../libraries/pacemaker', this_dir)
|
|
||||||
require File.expand_path('../../fixtures/keystone_primitive', this_dir)
|
|
||||||
|
|
||||||
describe Pacemaker::CIBObject do
|
|
||||||
|
|
||||||
before(:each) do
|
|
||||||
Mixlib::ShellOut.any_instance.stub(:run_command)
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:cib_object) { Chef::RSpec::Pacemaker::Config::KEYSTONE_PRIMITIVE.dup }
|
|
||||||
|
|
||||||
#####################################################################
|
|
||||||
# examples start here
|
|
||||||
|
|
||||||
context "no CIB object" do
|
|
||||||
before(:each) do
|
|
||||||
expect_any_instance_of(Mixlib::ShellOut) \
|
|
||||||
.to receive(:error!) \
|
|
||||||
.and_raise(RuntimeError)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#load_definition" do
|
|
||||||
it "should return nil cluster config" do
|
|
||||||
cib_object.load_definition
|
|
||||||
expect(cib_object.definition).to eq(nil)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#exists?" do
|
|
||||||
it "should return false" do
|
|
||||||
cib_object.load_definition
|
|
||||||
expect(cib_object.exists?).to be(false)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "keystone primitive resource CIB object" do
|
|
||||||
before(:each) do
|
|
||||||
Mixlib::ShellOut.any_instance.stub(:error!)
|
|
||||||
expect_any_instance_of(Mixlib::ShellOut) \
|
|
||||||
.to receive(:stdout) \
|
|
||||||
.and_return(cib_object.definition_string)
|
|
||||||
end
|
|
||||||
|
|
||||||
context "with definition loaded" do
|
|
||||||
before(:each) do
|
|
||||||
cib_object.load_definition
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#exists?" do
|
|
||||||
it "should return true" do
|
|
||||||
expect(cib_object.exists?).to be(true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#load_definition" do
|
|
||||||
it "should retrieve cluster config" do
|
|
||||||
expect(cib_object.definition).to eq(cib_object.definition_string)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#type" do
|
|
||||||
it "should return primitive" do
|
|
||||||
expect(cib_object.type).to eq("primitive")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "CIB object with unregistered type" do
|
|
||||||
before(:each) do
|
|
||||||
Mixlib::ShellOut.any_instance.stub(:error!)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "::from_name" do
|
|
||||||
it "should refuse to instantiate from any subclass" do
|
|
||||||
expect_any_instance_of(Mixlib::ShellOut) \
|
|
||||||
.to receive(:stdout) \
|
|
||||||
.and_return("unregistered #{cib_object.name} <definition>")
|
|
||||||
expect {
|
|
||||||
Pacemaker::CIBObject.from_name(cib_object.name)
|
|
||||||
}.to raise_error "No subclass of Pacemaker::CIBObject was registered with type 'unregistered'"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "invalid CIB object definition" do
|
|
||||||
before(:each) do
|
|
||||||
Mixlib::ShellOut.any_instance.stub(:error!)
|
|
||||||
expect_any_instance_of(Mixlib::ShellOut) \
|
|
||||||
.to receive(:stdout) \
|
|
||||||
.and_return("nonsense")
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#type" do
|
|
||||||
it "should raise an error without a valid definition" do
|
|
||||||
expect { cib_object.load_definition }.to \
|
|
||||||
raise_error(RuntimeError, "Couldn't extract CIB object type from 'nonsense'")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,61 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../../../../libraries/pacemaker/constraint/colocation',
|
|
||||||
this_dir)
|
|
||||||
require File.expand_path('../../../fixtures/colocation_constraint', this_dir)
|
|
||||||
require File.expand_path('../../../helpers/cib_object', this_dir)
|
|
||||||
|
|
||||||
describe Pacemaker::Constraint::Colocation do
|
|
||||||
let(:fixture) { Chef::RSpec::Pacemaker::Config::COLOCATION_CONSTRAINT.dup }
|
|
||||||
let(:fixture_definition) {
|
|
||||||
Chef::RSpec::Pacemaker::Config::COLOCATION_CONSTRAINT_DEFINITION
|
|
||||||
}
|
|
||||||
|
|
||||||
def object_type
|
|
||||||
'colocation'
|
|
||||||
end
|
|
||||||
|
|
||||||
def pacemaker_object_class
|
|
||||||
Pacemaker::Constraint::Colocation
|
|
||||||
end
|
|
||||||
|
|
||||||
def fields
|
|
||||||
%w(name score resources)
|
|
||||||
end
|
|
||||||
|
|
||||||
it_should_behave_like "a CIB object"
|
|
||||||
|
|
||||||
describe "#definition_string" do
|
|
||||||
it "should return the definition string" do
|
|
||||||
expect(fixture.definition_string).to eq(fixture_definition)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return a short definition string" do
|
|
||||||
colocation = pacemaker_object_class.new('foo')
|
|
||||||
colocation.definition = \
|
|
||||||
%!colocation colocation1 -inf: rsc1 rsc2!
|
|
||||||
colocation.parse_definition
|
|
||||||
expect(colocation.definition_string).to eq(<<'EOF'.chomp)
|
|
||||||
colocation colocation1 -inf: rsc1 rsc2
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#parse_definition" do
|
|
||||||
before(:each) do
|
|
||||||
@parsed = pacemaker_object_class.new(fixture.name)
|
|
||||||
@parsed.definition = fixture_definition
|
|
||||||
@parsed.parse_definition
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse the score" do
|
|
||||||
expect(@parsed.score).to eq(fixture.score)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse the resources" do
|
|
||||||
expect(@parsed.resources).to eq(fixture.resources)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,64 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../../../../libraries/pacemaker/constraint/location',
|
|
||||||
this_dir)
|
|
||||||
require File.expand_path('../../../fixtures/location_constraint', this_dir)
|
|
||||||
require File.expand_path('../../../helpers/cib_object', this_dir)
|
|
||||||
|
|
||||||
describe Pacemaker::Constraint::Location do
|
|
||||||
let(:fixture) { Chef::RSpec::Pacemaker::Config::LOCATION_CONSTRAINT.dup }
|
|
||||||
let(:fixture_definition) {
|
|
||||||
Chef::RSpec::Pacemaker::Config::LOCATION_CONSTRAINT_DEFINITION
|
|
||||||
}
|
|
||||||
|
|
||||||
def object_type
|
|
||||||
'location'
|
|
||||||
end
|
|
||||||
|
|
||||||
def pacemaker_object_class
|
|
||||||
Pacemaker::Constraint::Location
|
|
||||||
end
|
|
||||||
|
|
||||||
def fields
|
|
||||||
%w(name rsc score node)
|
|
||||||
end
|
|
||||||
|
|
||||||
it_should_behave_like "a CIB object"
|
|
||||||
|
|
||||||
describe "#definition_string" do
|
|
||||||
it "should return the definition string" do
|
|
||||||
expect(fixture.definition_string).to eq(fixture_definition)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return a short definition string" do
|
|
||||||
location = pacemaker_object_class.new('foo')
|
|
||||||
location.definition = \
|
|
||||||
%!location location1 primitive1 -inf: node1!
|
|
||||||
location.parse_definition
|
|
||||||
expect(location.definition_string).to eq(<<'EOF'.chomp)
|
|
||||||
location location1 primitive1 -inf: node1
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#parse_definition" do
|
|
||||||
before(:each) do
|
|
||||||
@parsed = pacemaker_object_class.new(fixture.name)
|
|
||||||
@parsed.definition = fixture_definition
|
|
||||||
@parsed.parse_definition
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse the rsc" do
|
|
||||||
expect(@parsed.rsc).to eq(fixture.rsc)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse the score" do
|
|
||||||
expect(@parsed.score).to eq(fixture.score)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse the node" do
|
|
||||||
expect(@parsed.node).to eq(fixture.node)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,61 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../../../../libraries/pacemaker/constraint/order',
|
|
||||||
this_dir)
|
|
||||||
require File.expand_path('../../../fixtures/order_constraint', this_dir)
|
|
||||||
require File.expand_path('../../../helpers/cib_object', this_dir)
|
|
||||||
|
|
||||||
describe Pacemaker::Constraint::Order do
|
|
||||||
let(:fixture) { Chef::RSpec::Pacemaker::Config::ORDER_CONSTRAINT.dup }
|
|
||||||
let(:fixture_definition) {
|
|
||||||
Chef::RSpec::Pacemaker::Config::ORDER_CONSTRAINT_DEFINITION
|
|
||||||
}
|
|
||||||
|
|
||||||
def object_type
|
|
||||||
'order'
|
|
||||||
end
|
|
||||||
|
|
||||||
def pacemaker_object_class
|
|
||||||
Pacemaker::Constraint::Order
|
|
||||||
end
|
|
||||||
|
|
||||||
def fields
|
|
||||||
%w(name score ordering)
|
|
||||||
end
|
|
||||||
|
|
||||||
it_should_behave_like "a CIB object"
|
|
||||||
|
|
||||||
describe "#definition_string" do
|
|
||||||
it "should return the definition string" do
|
|
||||||
expect(fixture.definition_string).to eq(fixture_definition)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return a short definition string" do
|
|
||||||
order = pacemaker_object_class.new('foo')
|
|
||||||
order.definition = \
|
|
||||||
%!order order1 Mandatory: rsc1 rsc2!
|
|
||||||
order.parse_definition
|
|
||||||
expect(order.definition_string).to eq(<<'EOF'.chomp)
|
|
||||||
order order1 Mandatory: rsc1 rsc2
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#parse_definition" do
|
|
||||||
before(:each) do
|
|
||||||
@parsed = pacemaker_object_class.new(fixture.name)
|
|
||||||
@parsed.definition = fixture_definition
|
|
||||||
@parsed.parse_definition
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse the score" do
|
|
||||||
expect(@parsed.score).to eq(fixture.score)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse the ordering" do
|
|
||||||
expect(@parsed.ordering).to eq(fixture.ordering)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,59 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../../../../libraries/pacemaker/resource/clone', this_dir)
|
|
||||||
require File.expand_path('../../../fixtures/clone_resource', this_dir)
|
|
||||||
require File.expand_path('../../../helpers/cib_object', this_dir)
|
|
||||||
require File.expand_path('../../../helpers/meta_examples', this_dir)
|
|
||||||
|
|
||||||
describe Pacemaker::Resource::Clone do
|
|
||||||
let(:fixture) { Chef::RSpec::Pacemaker::Config::CLONE_RESOURCE.dup }
|
|
||||||
let(:fixture_definition) {
|
|
||||||
Chef::RSpec::Pacemaker::Config::CLONE_RESOURCE_DEFINITION
|
|
||||||
}
|
|
||||||
|
|
||||||
def object_type
|
|
||||||
'clone'
|
|
||||||
end
|
|
||||||
|
|
||||||
def pacemaker_object_class
|
|
||||||
Pacemaker::Resource::Clone
|
|
||||||
end
|
|
||||||
|
|
||||||
def fields
|
|
||||||
%w(name rsc)
|
|
||||||
end
|
|
||||||
|
|
||||||
it_should_behave_like "a CIB object"
|
|
||||||
|
|
||||||
it_should_behave_like "with meta attributes"
|
|
||||||
|
|
||||||
describe "#definition_string" do
|
|
||||||
it "should return the definition string" do
|
|
||||||
expect(fixture.definition_string).to eq(fixture_definition)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return a short definition string" do
|
|
||||||
clone = pacemaker_object_class.new('foo')
|
|
||||||
clone.definition = \
|
|
||||||
%!clone clone1 primitive1 meta globally-unique="true"!
|
|
||||||
clone.parse_definition
|
|
||||||
expect(clone.definition_string).to eq(<<'EOF'.chomp)
|
|
||||||
clone clone1 primitive1 \
|
|
||||||
meta globally-unique="true"
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#parse_definition" do
|
|
||||||
before(:each) do
|
|
||||||
@parsed = pacemaker_object_class.new(fixture.name)
|
|
||||||
@parsed.definition = fixture_definition
|
|
||||||
@parsed.parse_definition
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse the rsc" do
|
|
||||||
expect(@parsed.rsc).to eq(fixture.rsc)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,60 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
require File.expand_path('../../../../libraries/pacemaker/resource/group',
|
|
||||||
File.dirname(__FILE__))
|
|
||||||
require File.expand_path('../../../fixtures/resource_group', File.dirname(__FILE__))
|
|
||||||
require File.expand_path('../../../helpers/cib_object', File.dirname(__FILE__))
|
|
||||||
require File.expand_path('../../../helpers/meta_examples',
|
|
||||||
File.dirname(__FILE__))
|
|
||||||
|
|
||||||
describe Pacemaker::Resource::Group do
|
|
||||||
let(:fixture) { Chef::RSpec::Pacemaker::Config::RESOURCE_GROUP.dup }
|
|
||||||
let(:fixture_definition) {
|
|
||||||
Chef::RSpec::Pacemaker::Config::RESOURCE_GROUP_DEFINITION
|
|
||||||
}
|
|
||||||
|
|
||||||
def object_type
|
|
||||||
'group'
|
|
||||||
end
|
|
||||||
|
|
||||||
def pacemaker_object_class
|
|
||||||
Pacemaker::Resource::Group
|
|
||||||
end
|
|
||||||
|
|
||||||
def fields
|
|
||||||
%w(name members)
|
|
||||||
end
|
|
||||||
|
|
||||||
it_should_behave_like "a CIB object"
|
|
||||||
|
|
||||||
it_should_behave_like "with meta attributes"
|
|
||||||
|
|
||||||
describe "#definition_string" do
|
|
||||||
it "should return the definition string" do
|
|
||||||
expect(fixture.definition_string).to eq(fixture_definition)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return a short definition string" do
|
|
||||||
group = pacemaker_object_class.new('foo')
|
|
||||||
group.definition = \
|
|
||||||
%!group foo member1 member2 meta target-role="Started"!
|
|
||||||
group.parse_definition
|
|
||||||
expect(group.definition_string).to eq(<<'EOF'.chomp)
|
|
||||||
group foo member1 member2 \
|
|
||||||
meta target-role="Started"
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#parse_definition" do
|
|
||||||
before(:each) do
|
|
||||||
@parsed = pacemaker_object_class.new(fixture.name)
|
|
||||||
@parsed.definition = fixture_definition
|
|
||||||
@parsed.parse_definition
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse the members" do
|
|
||||||
expect(@parsed.members).to eq(fixture.members)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,59 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../../../../libraries/pacemaker/resource/ms', this_dir)
|
|
||||||
require File.expand_path('../../../fixtures/ms_resource', this_dir)
|
|
||||||
require File.expand_path('../../../helpers/cib_object', this_dir)
|
|
||||||
require File.expand_path('../../../helpers/meta_examples', this_dir)
|
|
||||||
|
|
||||||
describe Pacemaker::Resource::MasterSlave do
|
|
||||||
let(:fixture) { Chef::RSpec::Pacemaker::Config::MS_RESOURCE.dup }
|
|
||||||
let(:fixture_definition) {
|
|
||||||
Chef::RSpec::Pacemaker::Config::MS_RESOURCE_DEFINITION
|
|
||||||
}
|
|
||||||
|
|
||||||
def object_type
|
|
||||||
'ms'
|
|
||||||
end
|
|
||||||
|
|
||||||
def pacemaker_object_class
|
|
||||||
Pacemaker::Resource::MasterSlave
|
|
||||||
end
|
|
||||||
|
|
||||||
def fields
|
|
||||||
%w(name rsc)
|
|
||||||
end
|
|
||||||
|
|
||||||
it_should_behave_like "a CIB object"
|
|
||||||
|
|
||||||
it_should_behave_like "with meta attributes"
|
|
||||||
|
|
||||||
describe "#definition_string" do
|
|
||||||
it "should return the definition string" do
|
|
||||||
expect(fixture.definition_string).to eq(fixture_definition)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return a short definition string" do
|
|
||||||
ms = pacemaker_object_class.new('foo')
|
|
||||||
ms.definition = \
|
|
||||||
%!ms ms1 primitive1 meta globally-unique="true"!
|
|
||||||
ms.parse_definition
|
|
||||||
expect(ms.definition_string).to eq(<<'EOF'.chomp)
|
|
||||||
ms ms1 primitive1 \
|
|
||||||
meta globally-unique="true"
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#parse_definition" do
|
|
||||||
before(:each) do
|
|
||||||
@parsed = pacemaker_object_class.new(fixture.name)
|
|
||||||
@parsed.definition = fixture_definition
|
|
||||||
@parsed.parse_definition
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse the rsc" do
|
|
||||||
expect(@parsed.rsc).to eq(fixture.rsc)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,117 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../../../../libraries/pacemaker/resource/primitive',
|
|
||||||
this_dir)
|
|
||||||
require File.expand_path('../../../fixtures/keystone_primitive', this_dir)
|
|
||||||
require File.expand_path('../../../helpers/cib_object', this_dir)
|
|
||||||
require File.expand_path('../../../helpers/meta_examples', this_dir)
|
|
||||||
|
|
||||||
describe Pacemaker::Resource::Primitive do
|
|
||||||
let(:fixture) { Chef::RSpec::Pacemaker::Config::KEYSTONE_PRIMITIVE.dup }
|
|
||||||
let(:fixture_definition) {
|
|
||||||
Chef::RSpec::Pacemaker::Config::KEYSTONE_PRIMITIVE_DEFINITION
|
|
||||||
}
|
|
||||||
|
|
||||||
def object_type
|
|
||||||
'primitive'
|
|
||||||
end
|
|
||||||
|
|
||||||
def pacemaker_object_class
|
|
||||||
Pacemaker::Resource::Primitive
|
|
||||||
end
|
|
||||||
|
|
||||||
def fields
|
|
||||||
%w(name agent params_string meta_string op_string)
|
|
||||||
end
|
|
||||||
|
|
||||||
it_should_behave_like "a CIB object"
|
|
||||||
|
|
||||||
describe "#params_string" do
|
|
||||||
it "should return empty string with nil params" do
|
|
||||||
fixture.params = nil
|
|
||||||
expect(fixture.params_string).to eq("")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return empty string with empty params" do
|
|
||||||
fixture.params = {}
|
|
||||||
expect(fixture.params_string).to eq("")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return a resource params string" do
|
|
||||||
fixture.params = {
|
|
||||||
"foo" => "bar",
|
|
||||||
"baz" => "qux",
|
|
||||||
}
|
|
||||||
expect(fixture.params_string).to eq(%'params baz="qux" foo="bar"')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#op_string" do
|
|
||||||
it "should return empty string with nil op" do
|
|
||||||
fixture.op = nil
|
|
||||||
expect(fixture.op_string).to eq("")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return empty string with empty op" do
|
|
||||||
fixture.op = {}
|
|
||||||
expect(fixture.op_string).to eq("")
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return a resource op string" do
|
|
||||||
fixture.op = {
|
|
||||||
"monitor" => {
|
|
||||||
"foo" => "bar",
|
|
||||||
"baz" => "qux",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
expect(fixture.op_string).to eq(%'op monitor baz="qux" foo="bar"')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it_should_behave_like "with meta attributes"
|
|
||||||
|
|
||||||
describe "#definition_string" do
|
|
||||||
it "should return the definition string" do
|
|
||||||
expect(fixture.definition_string).to eq(fixture_definition)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return a short definition string" do
|
|
||||||
primitive = pacemaker_object_class.new('foo')
|
|
||||||
primitive.definition = \
|
|
||||||
%!primitive foo ocf:heartbeat:IPaddr2 params foo="bar"!
|
|
||||||
primitive.parse_definition
|
|
||||||
expect(primitive.definition_string).to eq(<<'EOF'.chomp)
|
|
||||||
primitive foo ocf:heartbeat:IPaddr2 \
|
|
||||||
params foo="bar"
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#quoted_definition_string" do
|
|
||||||
it "should return the quoted definition string" do
|
|
||||||
primitive = pacemaker_object_class.new('foo')
|
|
||||||
primitive.definition = <<'EOF'.chomp
|
|
||||||
primitive foo ocf:openstack:keystone \
|
|
||||||
params bar="baz\\qux" bar2="baz'qux"
|
|
||||||
EOF
|
|
||||||
primitive.parse_definition
|
|
||||||
expect(primitive.quoted_definition_string).to eq(<<'EOF'.chomp)
|
|
||||||
'primitive foo ocf:openstack:keystone \\
|
|
||||||
params bar="baz\\qux" bar2="baz\'qux"'
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "#parse_definition" do
|
|
||||||
before(:each) do
|
|
||||||
@parsed = pacemaker_object_class.new(fixture.name)
|
|
||||||
@parsed.definition = fixture_definition
|
|
||||||
@parsed.parse_definition
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should parse the agent" do
|
|
||||||
expect(@parsed.agent).to eq(fixture.agent)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,51 +0,0 @@
|
|||||||
require 'mixlib/shellout'
|
|
||||||
|
|
||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../../../libraries/pacemaker/resource', this_dir)
|
|
||||||
require File.expand_path('../../fixtures/keystone_primitive', this_dir)
|
|
||||||
|
|
||||||
describe Pacemaker::Resource do
|
|
||||||
describe "#running?" do
|
|
||||||
let(:rsc) { Pacemaker::Resource.new('keystone') }
|
|
||||||
|
|
||||||
before(:each) do
|
|
||||||
@cmd = double(Mixlib::ShellOut)
|
|
||||||
expect(rsc).to receive(:shell_out!) \
|
|
||||||
.with(*%w(crm resource status keystone)) \
|
|
||||||
.and_return(@cmd)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return true" do
|
|
||||||
expect(@cmd).to receive(:stdout).at_least(:once) \
|
|
||||||
.and_return("resource #{rsc.name} is running on: d52-54-00-e5-6b-a0")
|
|
||||||
expect(rsc.running?).to be(true)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should return false" do
|
|
||||||
expect(@cmd).to receive(:stdout).at_least(:once) \
|
|
||||||
.and_return("resource #{rsc.name} is NOT running")
|
|
||||||
expect(rsc.running?).to be(false)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe "::extract_hash" do
|
|
||||||
let(:fixture) { Chef::RSpec::Pacemaker::Config::KEYSTONE_PRIMITIVE.dup }
|
|
||||||
|
|
||||||
it "should extract a params hash from config" do
|
|
||||||
expect(fixture.class.extract_hash(fixture.definition_string, "params")).to \
|
|
||||||
eq(Hash[fixture.params])
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should extract an op start hash from config" do
|
|
||||||
expect(fixture.class.extract_hash(fixture.definition_string, 'op start')).to \
|
|
||||||
eq(Hash[fixture.op]['start'])
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should extract an op monitor hash from config" do
|
|
||||||
expect(fixture.class.extract_hash(fixture.definition_string, 'op monitor')).to \
|
|
||||||
eq(Hash[fixture.op]['monitor'])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
@ -1,46 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../helpers/runnable_resource', this_dir)
|
|
||||||
require File.expand_path('../fixtures/clone_resource', this_dir)
|
|
||||||
|
|
||||||
describe "Chef::Provider::PacemakerClone" do
|
|
||||||
# for use inside examples:
|
|
||||||
let(:fixture) { Chef::RSpec::Pacemaker::Config::CLONE_RESOURCE.dup }
|
|
||||||
# for use outside examples (e.g. when invoking shared_examples)
|
|
||||||
fixture = Chef::RSpec::Pacemaker::Config::CLONE_RESOURCE.dup
|
|
||||||
|
|
||||||
def lwrp_name
|
|
||||||
'clone'
|
|
||||||
end
|
|
||||||
|
|
||||||
include_context "a Pacemaker LWRP"
|
|
||||||
|
|
||||||
before(:each) do
|
|
||||||
@resource.rsc fixture.rsc.dup
|
|
||||||
@resource.meta Hash[fixture.meta.dup]
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
def cib_object_class
|
|
||||||
Pacemaker::Resource::Clone
|
|
||||||
end
|
|
||||||
|
|
||||||
describe ":create action" do
|
|
||||||
include Chef::RSpec::Pacemaker::CIBObject
|
|
||||||
|
|
||||||
it "should modify the clone if the resource is changed" do
|
|
||||||
expected = fixture.dup
|
|
||||||
expected.rsc = 'primitive2'
|
|
||||||
expected_configure_cmd_args = [expected.reconfigure_command]
|
|
||||||
test_modify(expected_configure_cmd_args) do
|
|
||||||
@resource.rsc expected.rsc
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
it_should_behave_like "a runnable resource", fixture
|
|
||||||
|
|
||||||
end
|
|
@ -1,66 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../helpers/provider', this_dir)
|
|
||||||
require File.expand_path('../helpers/non_runnable_resource', this_dir)
|
|
||||||
require File.expand_path('../fixtures/colocation_constraint', this_dir)
|
|
||||||
|
|
||||||
describe "Chef::Provider::PacemakerColocation" do
|
|
||||||
# for use inside examples:
|
|
||||||
let(:fixture) { Chef::RSpec::Pacemaker::Config::COLOCATION_CONSTRAINT.dup }
|
|
||||||
# for use outside examples (e.g. when invoking shared_examples)
|
|
||||||
fixture = Chef::RSpec::Pacemaker::Config::COLOCATION_CONSTRAINT.dup
|
|
||||||
|
|
||||||
def lwrp_name
|
|
||||||
'colocation'
|
|
||||||
end
|
|
||||||
|
|
||||||
include_context "a Pacemaker LWRP"
|
|
||||||
|
|
||||||
before(:each) do
|
|
||||||
@resource.score fixture.score
|
|
||||||
@resource.resources fixture.resources.dup
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
def cib_object_class
|
|
||||||
Pacemaker::Constraint::Colocation
|
|
||||||
end
|
|
||||||
|
|
||||||
describe ":create action" do
|
|
||||||
include Chef::RSpec::Pacemaker::CIBObject
|
|
||||||
|
|
||||||
it "should modify the constraint if it has a different score" do
|
|
||||||
new_score = '100'
|
|
||||||
fixture.score = new_score
|
|
||||||
expected_configure_cmd_args = [fixture.reconfigure_command]
|
|
||||||
test_modify(expected_configure_cmd_args) do
|
|
||||||
@resource.score new_score
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should modify the constraint if it has a resource added" do
|
|
||||||
new_resource = 'bar:Stopped'
|
|
||||||
expected = fixture.dup
|
|
||||||
expected.resources = expected.resources.dup + [new_resource]
|
|
||||||
expected_configure_cmd_args = [expected.reconfigure_command]
|
|
||||||
test_modify(expected_configure_cmd_args) do
|
|
||||||
@resource.resources expected.resources
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should modify the constraint if it has a different resource" do
|
|
||||||
new_resources = ['bar:Started']
|
|
||||||
fixture.resources = new_resources
|
|
||||||
expected_configure_cmd_args = [fixture.reconfigure_command]
|
|
||||||
test_modify(expected_configure_cmd_args) do
|
|
||||||
@resource.resources new_resources
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
it_should_behave_like "a non-runnable resource", fixture
|
|
||||||
|
|
||||||
end
|
|
@ -1,55 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../helpers/runnable_resource', this_dir)
|
|
||||||
require File.expand_path('../fixtures/resource_group', this_dir)
|
|
||||||
|
|
||||||
describe "Chef::Provider::PacemakerGroup" do
|
|
||||||
# for use inside examples:
|
|
||||||
let(:fixture) { Chef::RSpec::Pacemaker::Config::RESOURCE_GROUP.dup }
|
|
||||||
# for use outside examples (e.g. when invoking shared_examples)
|
|
||||||
fixture = Chef::RSpec::Pacemaker::Config::RESOURCE_GROUP.dup
|
|
||||||
|
|
||||||
def lwrp_name
|
|
||||||
'group'
|
|
||||||
end
|
|
||||||
|
|
||||||
include_context "a Pacemaker LWRP"
|
|
||||||
|
|
||||||
before(:each) do
|
|
||||||
@resource.members fixture.members.dup
|
|
||||||
@resource.meta Hash[fixture.meta.dup]
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
def cib_object_class
|
|
||||||
Pacemaker::Resource::Group
|
|
||||||
end
|
|
||||||
|
|
||||||
describe ":create action" do
|
|
||||||
include Chef::RSpec::Pacemaker::CIBObject
|
|
||||||
|
|
||||||
it "should modify the group if it has a member resource added" do
|
|
||||||
expected = fixture.dup
|
|
||||||
expected.members = expected.members.dup + %w(resource3)
|
|
||||||
expected_configure_cmd_args = [expected.reconfigure_command]
|
|
||||||
test_modify(expected_configure_cmd_args) do
|
|
||||||
@resource.members expected.members
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should modify the group if it has different member resources" do
|
|
||||||
expected = fixture.dup
|
|
||||||
expected.members = %w(resource1 resource3)
|
|
||||||
expected_configure_cmd_args = [expected.reconfigure_command]
|
|
||||||
test_modify(expected_configure_cmd_args) do
|
|
||||||
@resource.members expected.members
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
it_should_behave_like "a runnable resource", fixture
|
|
||||||
|
|
||||||
end
|
|
@ -1,65 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../helpers/provider', this_dir)
|
|
||||||
require File.expand_path('../helpers/non_runnable_resource', this_dir)
|
|
||||||
require File.expand_path('../fixtures/location_constraint', this_dir)
|
|
||||||
|
|
||||||
describe "Chef::Provider::PacemakerLocation" do
|
|
||||||
# for use inside examples:
|
|
||||||
let(:fixture) { Chef::RSpec::Pacemaker::Config::LOCATION_CONSTRAINT.dup }
|
|
||||||
# for use outside examples (e.g. when invoking shared_examples)
|
|
||||||
fixture = Chef::RSpec::Pacemaker::Config::LOCATION_CONSTRAINT.dup
|
|
||||||
|
|
||||||
def lwrp_name
|
|
||||||
'location'
|
|
||||||
end
|
|
||||||
|
|
||||||
include_context "a Pacemaker LWRP"
|
|
||||||
|
|
||||||
before(:each) do
|
|
||||||
@resource.rsc fixture.rsc
|
|
||||||
@resource.score fixture.score
|
|
||||||
@resource.node fixture.node.dup
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
def cib_object_class
|
|
||||||
Pacemaker::Constraint::Location
|
|
||||||
end
|
|
||||||
|
|
||||||
describe ":create action" do
|
|
||||||
include Chef::RSpec::Pacemaker::CIBObject
|
|
||||||
|
|
||||||
it "should modify the constraint if it has a different resource" do
|
|
||||||
new_resource = 'group2'
|
|
||||||
fixture.rsc = new_resource
|
|
||||||
expected_configure_cmd_args = [fixture.reconfigure_command]
|
|
||||||
test_modify(expected_configure_cmd_args) do
|
|
||||||
@resource.rsc new_resource
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should modify the constraint if it has a different score" do
|
|
||||||
new_score = '100'
|
|
||||||
fixture.score = new_score
|
|
||||||
expected_configure_cmd_args = [fixture.reconfigure_command]
|
|
||||||
test_modify(expected_configure_cmd_args) do
|
|
||||||
@resource.score new_score
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should modify the constraint if it has a different node" do
|
|
||||||
new_node = 'node2'
|
|
||||||
fixture.node = new_node
|
|
||||||
expected_configure_cmd_args = [fixture.reconfigure_command]
|
|
||||||
test_modify(expected_configure_cmd_args) do
|
|
||||||
@resource.node new_node
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
it_should_behave_like "a non-runnable resource", fixture
|
|
||||||
|
|
||||||
end
|
|
@ -1,46 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../helpers/runnable_resource', this_dir)
|
|
||||||
require File.expand_path('../fixtures/ms_resource', this_dir)
|
|
||||||
|
|
||||||
describe "Chef::Provider::PacemakerMs" do
|
|
||||||
# for use inside examples:
|
|
||||||
let(:fixture) { Chef::RSpec::Pacemaker::Config::MS_RESOURCE.dup }
|
|
||||||
# for use outside examples (e.g. when invoking shared_examples)
|
|
||||||
fixture = Chef::RSpec::Pacemaker::Config::MS_RESOURCE.dup
|
|
||||||
|
|
||||||
def lwrp_name
|
|
||||||
'ms'
|
|
||||||
end
|
|
||||||
|
|
||||||
include_context "a Pacemaker LWRP"
|
|
||||||
|
|
||||||
before(:each) do
|
|
||||||
@resource.rsc fixture.rsc.dup
|
|
||||||
@resource.meta Hash[fixture.meta.dup]
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
def cib_object_class
|
|
||||||
Pacemaker::Resource::MasterSlave
|
|
||||||
end
|
|
||||||
|
|
||||||
describe ":create action" do
|
|
||||||
include Chef::RSpec::Pacemaker::CIBObject
|
|
||||||
|
|
||||||
it "should modify the resource if it's changed" do
|
|
||||||
expected = fixture.dup
|
|
||||||
expected.rsc = 'primitive2'
|
|
||||||
expected_configure_cmd_args = [expected.reconfigure_command]
|
|
||||||
test_modify(expected_configure_cmd_args) do
|
|
||||||
@resource.rsc expected.rsc
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
it_should_behave_like "a runnable resource", fixture
|
|
||||||
|
|
||||||
end
|
|
@ -1,66 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../helpers/provider', this_dir)
|
|
||||||
require File.expand_path('../helpers/non_runnable_resource', this_dir)
|
|
||||||
require File.expand_path('../fixtures/order_constraint', this_dir)
|
|
||||||
|
|
||||||
describe "Chef::Provider::PacemakerOrder" do
|
|
||||||
# for use inside examples:
|
|
||||||
let(:fixture) { Chef::RSpec::Pacemaker::Config::ORDER_CONSTRAINT.dup }
|
|
||||||
# for use outside examples (e.g. when invoking shared_examples)
|
|
||||||
fixture = Chef::RSpec::Pacemaker::Config::ORDER_CONSTRAINT.dup
|
|
||||||
|
|
||||||
def lwrp_name
|
|
||||||
'order'
|
|
||||||
end
|
|
||||||
|
|
||||||
include_context "a Pacemaker LWRP"
|
|
||||||
|
|
||||||
before(:each) do
|
|
||||||
@resource.score fixture.score
|
|
||||||
@resource.ordering fixture.ordering.dup
|
|
||||||
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
def cib_object_class
|
|
||||||
Pacemaker::Constraint::Order
|
|
||||||
end
|
|
||||||
|
|
||||||
describe ":create action" do
|
|
||||||
include Chef::RSpec::Pacemaker::CIBObject
|
|
||||||
|
|
||||||
it "should modify the constraint if it has a different score" do
|
|
||||||
new_score = '100'
|
|
||||||
fixture.score = new_score
|
|
||||||
expected_configure_cmd_args = [fixture.reconfigure_command]
|
|
||||||
test_modify(expected_configure_cmd_args) do
|
|
||||||
@resource.score new_score
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should modify the constraint if it has a resource added" do
|
|
||||||
new_resource = 'bar:Stopped'
|
|
||||||
expected = fixture.dup
|
|
||||||
expected.ordering = expected.ordering.dup + ' ' + new_resource
|
|
||||||
expected_configure_cmd_args = [expected.reconfigure_command]
|
|
||||||
test_modify(expected_configure_cmd_args) do
|
|
||||||
@resource.ordering expected.ordering
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should modify the constraint if it has a different ordering" do
|
|
||||||
new_ordering = 'clone1 primitive1'
|
|
||||||
fixture.ordering = new_ordering
|
|
||||||
expected_configure_cmd_args = [fixture.reconfigure_command]
|
|
||||||
test_modify(expected_configure_cmd_args) do
|
|
||||||
@resource.ordering new_ordering
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
it_should_behave_like "a non-runnable resource", fixture
|
|
||||||
|
|
||||||
end
|
|
@ -1,139 +0,0 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
this_dir = File.dirname(__FILE__)
|
|
||||||
require File.expand_path('../helpers/runnable_resource', this_dir)
|
|
||||||
require File.expand_path('../fixtures/keystone_primitive', this_dir)
|
|
||||||
|
|
||||||
describe "Chef::Provider::PacemakerPrimitive" do
|
|
||||||
# for use inside examples:
|
|
||||||
let(:fixture) { Chef::RSpec::Pacemaker::Config::KEYSTONE_PRIMITIVE }
|
|
||||||
# for use outside examples (e.g. when invoking shared_examples)
|
|
||||||
fixture = Chef::RSpec::Pacemaker::Config::KEYSTONE_PRIMITIVE
|
|
||||||
|
|
||||||
def lwrp_name
|
|
||||||
'primitive'
|
|
||||||
end
|
|
||||||
|
|
||||||
include_context "a Pacemaker LWRP"
|
|
||||||
|
|
||||||
before(:each) do
|
|
||||||
@resource.agent fixture.agent
|
|
||||||
@resource.params Hash[fixture.params]
|
|
||||||
@resource.meta Hash[fixture.meta]
|
|
||||||
@resource.op Hash[fixture.op]
|
|
||||||
end
|
|
||||||
|
|
||||||
def cib_object_class
|
|
||||||
Pacemaker::Resource::Primitive
|
|
||||||
end
|
|
||||||
|
|
||||||
describe ":create action" do
|
|
||||||
include Chef::RSpec::Pacemaker::CIBObject
|
|
||||||
include Chef::RSpec::Mixlib::ShellOut
|
|
||||||
|
|
||||||
it "should modify the primitive if it has different params" do
|
|
||||||
expected_configure_cmd_args = [
|
|
||||||
%'--set-parameter "os_password" --parameter-value "newpasswd"',
|
|
||||||
%'--delete-parameter "os_tenant_name"',
|
|
||||||
].map { |args| "crm_resource --resource #{fixture.name} #{args}" }
|
|
||||||
test_modify(expected_configure_cmd_args) do
|
|
||||||
new_params = Hash[fixture.params].merge("os_password" => "newpasswd")
|
|
||||||
new_params.delete("os_tenant_name")
|
|
||||||
@resource.params new_params
|
|
||||||
@resource.meta Hash[fixture.meta].merge("target-role" => "Stopped")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should modify the primitive if it has different meta" do
|
|
||||||
expected_configure_cmd_args = [
|
|
||||||
%'--set-parameter "is-managed" --parameter-value "false" --meta',
|
|
||||||
].map { |args| "crm_resource --resource #{fixture.name} #{args}" }
|
|
||||||
test_modify(expected_configure_cmd_args) do
|
|
||||||
@resource.params Hash[fixture.params]
|
|
||||||
@resource.meta Hash[fixture.meta].merge("is-managed" => "false")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should modify the primitive if it has different params and meta" do
|
|
||||||
expected_configure_cmd_args = [
|
|
||||||
%'--set-parameter "os_password" --parameter-value "newpasswd"',
|
|
||||||
%'--delete-parameter "os_tenant_name"',
|
|
||||||
%'--set-parameter "is-managed" --parameter-value "false" --meta',
|
|
||||||
].map { |args| "crm_resource --resource #{fixture.name} #{args}" }
|
|
||||||
test_modify(expected_configure_cmd_args) do
|
|
||||||
new_params = Hash[fixture.params].merge("os_password" => "newpasswd")
|
|
||||||
new_params.delete("os_tenant_name")
|
|
||||||
@resource.params new_params
|
|
||||||
@resource.meta Hash[fixture.meta].merge("is-managed" => "false")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should modify the primitive if it has different op values" do
|
|
||||||
expected_configure_cmd_args = [
|
|
||||||
fixture.reconfigure_command.gsub('60', '120')
|
|
||||||
]
|
|
||||||
test_modify(expected_configure_cmd_args) do
|
|
||||||
new_op = Hash[fixture.op]
|
|
||||||
# Ensure we're not modifying our expectation as well as the input
|
|
||||||
new_op['monitor'] = new_op['monitor'].dup
|
|
||||||
new_op['monitor']['timeout'] = '120'
|
|
||||||
@resource.op new_op
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context "creation from scratch" do
|
|
||||||
include_context "stopped resource"
|
|
||||||
|
|
||||||
it "should create a primitive if it doesn't already exist" do
|
|
||||||
# The first time, Mixlib::ShellOut needs to return an empty definition.
|
|
||||||
# Then the resource gets created so the second time it needs to return
|
|
||||||
# the definition used for creation.
|
|
||||||
stub_shellout("", fixture.definition_string)
|
|
||||||
|
|
||||||
provider.run_action :create
|
|
||||||
|
|
||||||
expect(@chef_run).to run_execute(stopped_fixture.configure_command)
|
|
||||||
expect(@resource).to be_updated
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should barf if crm fails to create the primitive" do
|
|
||||||
stub_shellout("", ["crm configure failed", "oh noes", 3])
|
|
||||||
|
|
||||||
expect { provider.run_action :create }.to \
|
|
||||||
raise_error(RuntimeError, "Failed to create #{fixture}")
|
|
||||||
|
|
||||||
expect(@chef_run).to run_execute(stopped_fixture.configure_command)
|
|
||||||
expect(@resource).not_to be_updated
|
|
||||||
end
|
|
||||||
|
|
||||||
# This scenario seems rather artificial and unlikely, but it doesn't
|
|
||||||
# do any harm to test it.
|
|
||||||
it "should barf if crm creates a primitive with empty definition" do
|
|
||||||
stub_shellout("", "")
|
|
||||||
|
|
||||||
expect { provider.run_action :create }.to \
|
|
||||||
raise_error(RuntimeError, "Failed to create #{fixture}")
|
|
||||||
|
|
||||||
expect(@chef_run).to run_execute(stopped_fixture.configure_command)
|
|
||||||
expect(@resource).not_to be_updated
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should barf if the primitive is already defined with the wrong agent" do
|
|
||||||
existing_agent = "ocf:openstack:something-else"
|
|
||||||
definition = fixture.definition_string.sub(fixture.agent, existing_agent)
|
|
||||||
stub_shellout(definition)
|
|
||||||
|
|
||||||
expected_error = \
|
|
||||||
"Existing #{fixture} has agent '#{existing_agent}' " \
|
|
||||||
"but recipe wanted '#{@resource.agent}'"
|
|
||||||
expect { provider.run_action :create }.to \
|
|
||||||
raise_error(RuntimeError, expected_error)
|
|
||||||
|
|
||||||
expect(@resource).not_to be_updated
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it_should_behave_like "a runnable resource", fixture
|
|
||||||
|
|
||||||
end
|
|
@ -1,53 +0,0 @@
|
|||||||
require 'chefspec'
|
|
||||||
|
|
||||||
ENV['RSPEC_RUNNING'] = 'true'
|
|
||||||
|
|
||||||
RSpec.configure do |config|
|
|
||||||
# config.mock_with :rspec do |mocks|
|
|
||||||
# # This option should be set when all dependencies are being loaded
|
|
||||||
# # before a spec run, as is the case in a typical spec helper. It will
|
|
||||||
# # cause any verifying double instantiation for a class that does not
|
|
||||||
# # exist to raise, protecting against incorrectly spelt names.
|
|
||||||
# mocks.verify_doubled_constant_names = true
|
|
||||||
# end
|
|
||||||
|
|
||||||
# Specify the path for Chef Solo to find cookbooks (default: [inferred from
|
|
||||||
# the location of the calling spec file])
|
|
||||||
#config.cookbook_path = '/var/cookbooks'
|
|
||||||
|
|
||||||
# Specify the path for Chef Solo to find roles (default: [ascending search])
|
|
||||||
#config.role_path = '/var/roles'
|
|
||||||
|
|
||||||
# Specify the Chef log_level (default: :warn)
|
|
||||||
config.log_level = ENV['CHEF_LOG_LEVEL'].to_sym if ENV['CHEF_LOG_LEVEL']
|
|
||||||
|
|
||||||
# Specify the path to a local JSON file with Ohai data (default: nil)
|
|
||||||
#config.path = 'ohai.json'
|
|
||||||
|
|
||||||
# Specify the operating platform to mock Ohai data from (default: nil)
|
|
||||||
config.platform = 'suse'
|
|
||||||
|
|
||||||
# Specify the operating version to mock Ohai data from (default: nil)
|
|
||||||
config.version = '11.03'
|
|
||||||
|
|
||||||
# Disable deprecated "should" syntax
|
|
||||||
# https://github.com/rspec/rspec-expectations/blob/master/Should.md
|
|
||||||
config.expect_with :rspec do |c|
|
|
||||||
c.syntax = :expect
|
|
||||||
end
|
|
||||||
|
|
||||||
config.run_all_when_everything_filtered = true
|
|
||||||
config.filter_run :focus => true
|
|
||||||
end
|
|
||||||
|
|
||||||
# FIXME
|
|
||||||
#running_guard = ENV['GUARD_NOTIFY'] && ! ENV['GUARD_NOTIFY'].empty?
|
|
||||||
|
|
||||||
if ENV['RUBYDEPS']
|
|
||||||
require 'rubydeps'
|
|
||||||
Rubydeps.start
|
|
||||||
end
|
|
||||||
|
|
||||||
if false # ! running_guard
|
|
||||||
at_exit { ChefSpec::Coverage.report! }
|
|
||||||
end
|
|
@ -1,10 +0,0 @@
|
|||||||
property $id="cib-bootstrap-options" \
|
|
||||||
stonith-enabled="<%= @stonith_enabled %>" \
|
|
||||||
no-quorum-policy="<%= @no_quorum_policy %>" \
|
|
||||||
placement-strategy="balanced"
|
|
||||||
op_defaults $id="op-options" \
|
|
||||||
timeout="<%= @op_default_timeout %>" \
|
|
||||||
record-pending="true"
|
|
||||||
rsc_defaults $id="rsc-options" \
|
|
||||||
resource-stickiness="1" \
|
|
||||||
migration-threshold="3"
|
|
@ -1,20 +0,0 @@
|
|||||||
# Logging
|
|
||||||
debug 1
|
|
||||||
use_logd false
|
|
||||||
logfacility daemon
|
|
||||||
|
|
||||||
# Misc Options
|
|
||||||
traditional_compression off
|
|
||||||
compression bz2
|
|
||||||
coredumps true
|
|
||||||
|
|
||||||
# Communications
|
|
||||||
udpport 691
|
|
||||||
bcast eth0
|
|
||||||
autojoin any
|
|
||||||
|
|
||||||
# Thresholds (in seconds)
|
|
||||||
keepalive 1
|
|
||||||
warntime 6
|
|
||||||
deadtime 10
|
|
||||||
initdead 15
|
|
@ -1,3 +0,0 @@
|
|||||||
SBD_DEVICE="<%= @sbd_devices.join("; ") %>"
|
|
||||||
# The next line enables the watchdog support, and makes SBD checks Pacemaker quorum and node health:
|
|
||||||
SBD_OPTS="-W -P"
|
|
Loading…
x
Reference in New Issue
Block a user