add Pacemaker::Constraint::Colocation

This commit is contained in:
Adam Spiers
2014-01-30 16:35:53 +00:00
parent abd973937c
commit 5bc3db1141
8 changed files with 227 additions and 47 deletions

View File

@@ -1,2 +1,3 @@
require File.join(File.dirname(__FILE__), %w(pacemaker resource primitive))
require File.join(File.dirname(__FILE__), %w(pacemaker resource clone))
require File.join(File.dirname(__FILE__), %w(pacemaker constraint colocation))

View File

@@ -0,0 +1,10 @@
require File.join(File.dirname(__FILE__), 'cib_object')
module Pacemaker
class Constraint < Pacemaker::CIBObject
def self.description
type = self.to_s.split('::').last
"#{type} constraint"
end
end
end

View File

@@ -0,0 +1,33 @@
require File::join(File.dirname(__FILE__), %w(.. constraint))
class Pacemaker::Constraint::Colocation < Pacemaker::Constraint
TYPE = 'colocation'
register_type TYPE
attr_accessor :score, :resources
def self.from_chef_resource(resource)
attrs = %w(score resources)
new(resource.name).copy_attrs_from_chef_resource(resource, *attrs)
end
def parse_definition
rsc_re = /(\S+?)(?::(Started|Stopped))?/
unless definition =~ /^#{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
"colocation #{name} #{score}: " + resources.join(' ')
end
def crm_configure_command
"crm configure " + definition_string
end
end

View File

@@ -17,55 +17,60 @@
# limitations under the License.
#
require ::File.join(::File.dirname(__FILE__),
*%w(.. libraries pacemaker cib_object))
require ::File.join(::File.dirname(__FILE__), *%w(.. libraries pacemaker))
require ::File.join(::File.dirname(__FILE__), 'common')
include Chef::Mixin::PacemakerCommon
action :create do
name = new_resource.name
priority = new_resource.priority
multiple = new_resource.multiple
unless resource_exists?(name)
if multiple
multiple_rscs = new_resource.multiple_rscs
cmd = "crm configure colocation #{name} #{priority}:"
multiple_rscs.each do |rsc|
cmd << " #{rsc}"
end
else
rsc = new_resource.rsc
with_rsc = new_resource.with_rsc
cmd = "crm configure colocation #{name} #{priority}: #{rsc} #{with_rsc}"
end
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 colocation '#{name}'."
else
Chef::Log.error "Failed to configure colocation #{name}."
end
rescue
Chef::Log.error "Failed to configure colocation #{name}."
end
if @current_resource_definition.nil?
create_resource(name)
else
maybe_modify_resource(name)
end
end
action :delete do
name = new_resource.name
cmd = "crm resource stop #{name}; crm configure delete #{name}"
e = execute "delete colocation #{name}" do
command cmd
only_if { resource_exists?(name) }
end
new_resource.updated_by_last_action(true)
Chef::Log.info "Deleted colocation '#{name}'."
next unless @current_resource
rsc = cib_object_class.new(name)
execute rsc.delete_command do
action :nothing
end.run_action(:run)
new_resource.updated_by_last_action(true)
Chef::Log.info "Deleted #{@current_cib_object}'."
end
def cib_object_class
Pacemaker::Constraint::Colocation
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}]"
to_echo = desired_colocation.definition_string.chomp
to_echo.gsub!('\\') { '\\\\' }
to_echo.gsub!("'", "\\'")
cmd = "echo '#{to_echo}' | crm configure load update -"
execute cmd do
action :nothing
end.run_action(:run)
new_resource.updated_by_last_action(true)
end
end

View File

@@ -22,8 +22,5 @@ actions :create, :delete
default_action :create
attribute :name, :kind_of => String, :name_attribute => true
attribute :priority, :kind_of => String
attribute :multiple, :default => false
attribute :rsc, :kind_of => String
attribute :with_rsc, :kind_of => String
attribute :multiple_rscs, :kind_of => Array
attribute :score, :kind_of => String
attribute :resources, :kind_of => Array

14
spec/fixtures/colocation_constraint.rb vendored Normal file
View File

@@ -0,0 +1,14 @@
require ::File.join(::File.dirname(__FILE__),
*%w(.. .. libraries pacemaker constraint colocation))
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

View File

@@ -0,0 +1,27 @@
require 'spec_helper'
require File.join(File.dirname(__FILE__), %w(.. .. .. ..
libraries pacemaker constraint colocation))
require File.join(File.dirname(__FILE__), %w(.. .. .. fixtures colocation_constraint))
require File.join(File.dirname(__FILE__), %w(.. .. .. helpers common_object_examples))
describe Pacemaker::Constraint::Colocation do
let(:fixture) { Chef::RSpec::Pacemaker::Config::COLOCATION_CONSTRAINT.dup }
before(:each) do
Mixlib::ShellOut.any_instance.stub(:run_command)
end
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"
end

View File

@@ -0,0 +1,93 @@
require 'chef/application'
require File.join(File.dirname(__FILE__), %w(.. spec_helper))
require File.join(File.dirname(__FILE__), %w(.. helpers common))
require File.join(File.dirname(__FILE__), %w(.. fixtures colocation_constraint))
describe "Chef::Provider::PacemakerColocation" do
# for use inside examples:
let(:colo) { Chef::RSpec::Pacemaker::Config::COLOCATION_CONSTRAINT.dup }
# for use outside examples (e.g. when invoking shared_examples)
colo = Chef::RSpec::Pacemaker::Config::COLOCATION_CONSTRAINT.dup
before(:each) do
runner_opts = {
:step_into => ['pacemaker_colocation']
}
@chef_run = ::ChefSpec::Runner.new(runner_opts)
@chef_run.converge "pacemaker::default"
@node = @chef_run.node
@run_context = @chef_run.run_context
@resource = Chef::Resource::PacemakerColocation.new(colo.name, @run_context)
@resource.score colo.score
@resource.resources colo.resources.dup
end
let (:provider) { Chef::Provider::PacemakerColocation.new(@resource, @run_context) }
def cib_object_class
Pacemaker::Constraint::Colocation
end
include Chef::RSpec::Pacemaker::Common
describe ":create action" do
def test_modify(expected_cmds)
yield
expect_definition(colo.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
it "should modify the constraint if it has a different score" do
echo_string = colo.definition_string.chomp.gsub('inf', '100')
echo_string.gsub!('\\') { '\\\\' }
expected_configure_cmd_args = [
"echo '#{echo_string}' | crm configure load update -"
]
test_modify(expected_configure_cmd_args) do
@resource.score '100'
end
end
it "should modify the constraint if it has a resource added" do
new_resource = 'bar:Stopped'
expected = colo.dup
expected.resources = expected.resources.dup + [new_resource]
echo_string = expected.definition_string.chomp
echo_string.gsub!('\\') { '\\\\' }
expected_configure_cmd_args = [
"echo '#{echo_string}' | crm configure load update -"
]
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']
colo.resources = new_resources
echo_string = colo.definition_string.chomp
echo_string.gsub!('\\') { '\\\\' }
expected_configure_cmd_args = [
"echo '#{echo_string}' | crm configure load update -"
]
test_modify(expected_configure_cmd_args) do
@resource.resources new_resources
end
end
end
describe ":delete action" do
it_should_behave_like "action on non-existent resource", \
:delete, "crm configure delete #{colo.name}", nil
end
end