Add pcmk_stonith provider

This new pcmk_stonith provider exists in order to create
stonith resources and location constraints using the common
pcs() function. The reason for this is that this function
contains the retry logic needed in case the CIB gets updated
from another node.

In this provider we also create the location constraint in
a race-free way by first creating the stonith resource in
disabled mode, then we create the location constraint and
finally we enable the stonith resource.

This is to avoid races when creating stonith resources from
multiple nodes which is the how they are created within
TripleO.

Change-Id: I424302bbf8d0d5f233e3a7debc082be1c9a170bb
Partial-Bug: #1717566
This commit is contained in:
Michele Baldessari 2017-09-17 10:01:33 +02:00
parent 6c50831a77
commit 375ff16503
2 changed files with 171 additions and 0 deletions

View File

@ -0,0 +1,83 @@
require_relative '../pcmk_common'
Puppet::Type.type(:pcmk_stonith).provide(:default) do
desc 'A base resource definition for a pacemaker stonith'
### overloaded methods
def create
name = @resource[:name]
stonith_type = @resource[:stonith_type]
pcmk_host_list = @resource[:pcmk_host_list]
pcs_param_string = @resource[:pcs_param_string]
# We need to probe the existance of both location and resource
# because we do not know why we're being created (if for both or
# only for one)
did_stonith_location_exist = stonith_location_exists?
did_stonith_resource_exist = stonith_resource_exists?
Puppet.debug("Create: stonith exists #{did_stonith_resource_exist} location exists #{did_stonith_location_exist}")
cmd = 'stonith create ' + name + ' ' + stonith_type + ' ' \
'pcmk_host_list=' + pcmk_host_list + ' ' + @resource[:pcs_param_string]
# If both the stonith resource and the location do not exist, we create them both
# if a location_rule is specified otherwise only the resource
if not did_stonith_location_exist and not did_stonith_resource_exist
pcs('create', name, "#{cmd} --disabled", @resource[:tries],
@resource[:try_sleep], @resource[:verify_on_create], @resource[:post_success_sleep])
stonith_location_rule_create()
pcs('create', name, "resource enable #{name}", @resource[:tries],
@resource[:try_sleep], @resource[:verify_on_create], @resource[:post_success_sleep])
# If the location_rule already existed, we only create the resource
elsif did_stonith_location_exist and not did_stonith_resource_exist
pcs('create', name, cmd, @resource[:tries],
@resource[:try_sleep], @resource[:verify_on_create], @resource[:post_success_sleep])
# The location_rule does not exist and the resource does exist
elsif not did_stonith_location_exist and did_stonith_resource_exist
stonith_location_rule_create()
else
raise Puppet::Error, "Invalid create: #{name} stonith resource exists #{did_stonith_resource_exist} "
"stonith location exists #{did_stonith_location_exist}"
end
end
def destroy
# Any corresponding location rules will be deleted by
# pcs automatically, if present
cmd = 'resource delete ' + @resource[:name]
pcs('delete', @resource[:name], cmd, @resource[:tries],
@resource[:try_sleep], @resource[:verify_on_create], @resource[:post_success_sleep])
end
def exists?
did_stonith_location_exist = stonith_location_exists?
did_stonith_resource_exist = stonith_resource_exists?
Puppet.debug("Exists: stonith resource exists #{did_stonith_resource_exist} location exists #{did_stonith_location_exist}")
if did_stonith_resource_exist and did_stonith_location_exist
return true
end
return false
end
def stonith_resource_exists?
cmd = 'stonith show ' + @resource[:name] + ' > /dev/null 2>&1'
ret = pcs('show', @resource[:name], cmd, @resource[:tries],
@resource[:try_sleep], @resource[:verify_on_create], @resource[:post_success_sleep])
return ret == false ? false : true
end
def stonith_location_exists?
constraint_name = "#{@resource[:name]}"
cmd = "constraint location | grep #{constraint_name} > /dev/null 2>&1"
ret = pcs('show', @resource[:name], cmd, @resource[:tries],
@resource[:try_sleep], @resource[:verify_on_create], @resource[:post_success_sleep])
return ret == false ? false : true
end
def stonith_location_rule_create()
location_cmd = "constraint location #{@resource[:name]} avoids #{@resource[:pcmk_host_list]}"
Puppet.debug("stonith_location_rule_create: #{location_cmd}")
pcs('create', @resource[:name], location_cmd, @resource[:tries],
@resource[:try_sleep], @resource[:verify_on_create], @resource[:post_success_sleep])
end
end

View File

@ -0,0 +1,88 @@
require 'puppet/parameter/boolean'
Puppet::Type.newtype(:pcmk_stonith) do
@doc = "Base resource definition for a pacemaker stonith resource"
ensurable
newparam(:name) do
desc "A unique name for the stonith resource"
end
newparam(:stonith_type) do
desc "the pacemaker stonith type to create"
end
newparam(:pcmk_host_list) do
desc "the pcmk_host_list parameter for pcs"
end
newparam(:pcs_param_string) do
desc "the pacemaker pcs string to use"
end
## borrowed from exec.rb
newparam(:tries) do
desc "The number of times to attempt to create a pcs resource.
Defaults to '1'."
munge do |value|
if value.is_a?(String)
unless value =~ /^[\d]+$/
raise ArgumentError, "Tries must be an integer"
end
value = Integer(value)
end
raise ArgumentError, "Tries must be an integer >= 1" if value < 1
value
end
defaultto 1
end
newparam(:try_sleep) do
desc "The time to sleep in seconds between 'tries'."
munge do |value|
if value.is_a?(String)
unless value =~ /^[-\d.]+$/
raise ArgumentError, "try_sleep must be a number"
end
value = Float(value)
end
raise ArgumentError, "try_sleep cannot be a negative number" if value < 0
value
end
defaultto 0
end
newparam(:verify_on_create, :boolean => true, :parent => Puppet::Parameter::Boolean) do
desc "Whether to verify pcs resource creation with an additional
call to 'pcs resource show' rather than just relying on the exit
status of 'pcs resource create'. When true, $try_sleep
determines how long to wait to verify and $post_success_sleep is
ignored. Defaults to `false`."
defaultto false
end
newparam(:post_success_sleep) do
desc "The time to sleep after successful pcs action. The reason to set
this is to avoid immediate back-to-back 'pcs resource create' calls
when creating multiple resources. Defaults to '0'."
munge do |value|
if value.is_a?(String)
unless value =~ /^[-\d.]+$/
raise ArgumentError, "post_success_sleep must be a number"
end
value = Float(value)
end
raise ArgumentError, "post_success_sleep cannot be a negative number" if value < 0
value
end
defaultto 0
end
end