Implement stonith levels resource
This resource implements a stonith levels definition. This is used so that we can define a specific sequence of stonith operations on a node. More documentation about stonith levels can be found here: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html-single/high_availability_add-on_reference/#s1-fencelevels-HAAR Change-Id: I9cc5064e776a3771e30d853d9453026d2731c98d
This commit is contained in:
51
lib/puppet/provider/pcmk_stonith_level/default.rb
Normal file
51
lib/puppet/provider/pcmk_stonith_level/default.rb
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
require_relative '../pcmk_common'
|
||||||
|
|
||||||
|
Puppet::Type.type(:pcmk_stonith_level).provide(:default) do
|
||||||
|
desc 'A base resource definition for a pacemaker stonith level definition'
|
||||||
|
|
||||||
|
### overloaded methods
|
||||||
|
def create
|
||||||
|
level = @resource[:level]
|
||||||
|
target = @resource[:target]
|
||||||
|
stonith_resources = @resource[:stonith_resources]
|
||||||
|
res = stonith_resources.join(',')
|
||||||
|
cmd = 'stonith level add ' + level.to_s + ' ' + target + ' ' + res
|
||||||
|
|
||||||
|
pcs('create', "#{name}-#{target}-#{res}", cmd, @resource[:tries],
|
||||||
|
@resource[:try_sleep], @resource[:verify_on_create], @resource[:post_success_sleep])
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
# Any corresponding location rules will be deleted by
|
||||||
|
# pcs automatically, if present
|
||||||
|
target = @resource[:target]
|
||||||
|
level = @resource[:level]
|
||||||
|
cmd = 'stonith level remove ' + level.to_s + ' ' + target
|
||||||
|
pcs('delete', @resource[:name], cmd, @resource[:tries],
|
||||||
|
@resource[:try_sleep], @resource[:verify_on_create], @resource[:post_success_sleep])
|
||||||
|
end
|
||||||
|
|
||||||
|
def exists?
|
||||||
|
# stonith level output is a bit cumbersome to parse:
|
||||||
|
# Target: overcloud-galera-0
|
||||||
|
# Level 1 - stonith-fence_ipmilan-006809859383,stonith-fence_compute-fence-nova
|
||||||
|
# Target: overcloud-novacompute-0
|
||||||
|
# Level 1 - stonith-fence_ipmilan-006809859383,stonith-fence_compute-fence-nova
|
||||||
|
# Level 2 - stonith-fence_ipmilan-006809859383,stonith-fence_compute-fence-nova
|
||||||
|
# Target: overcloud-rabbit-0
|
||||||
|
# Level 2 - stonith-fence_ipmilan-006809859383,stonith-fence_compute-fence-nova
|
||||||
|
target = @resource[:target]
|
||||||
|
level = @resource[:level]
|
||||||
|
stonith_resources = @resource[:stonith_resources]
|
||||||
|
res = stonith_resources.join(',')
|
||||||
|
Puppet.debug("Exists: stonith level exists #{level} #{target} #{res}")
|
||||||
|
# The below cmd return the "Level X - ...." strings after the Target: string until the next
|
||||||
|
# Target: string (or until the bottom of the file if it is the last Target in the output
|
||||||
|
cmd = 'stonith level | sed -n "/^Target: ' + target + '$/,/^Target:/{/^Target: ' + target + '$/b;/^Target:/b;p}"'
|
||||||
|
cmd += ' | grep -e "Level[[:space:]]*' + level.to_s + '[[:space:]]*-[[:space:]]*' + res + '"'
|
||||||
|
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
|
||||||
|
end
|
99
lib/puppet/type/pcmk_stonith_level.rb
Normal file
99
lib/puppet/type/pcmk_stonith_level.rb
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
require 'puppet/parameter/boolean'
|
||||||
|
|
||||||
|
Puppet::Type.newtype(:pcmk_stonith_level) do
|
||||||
|
@doc = "Base resource definition for a pacemaker stonith level resource"
|
||||||
|
|
||||||
|
ensurable
|
||||||
|
|
||||||
|
newparam(:name) do
|
||||||
|
desc "A unique name for the stonith level"
|
||||||
|
end
|
||||||
|
|
||||||
|
newparam(:level) do
|
||||||
|
desc "The stonith level"
|
||||||
|
munge do |value|
|
||||||
|
if value.is_a?(String)
|
||||||
|
unless value =~ /^[\d]+$/
|
||||||
|
raise ArgumentError, "The stonith level must be an integer"
|
||||||
|
end
|
||||||
|
value = Integer(value)
|
||||||
|
end
|
||||||
|
raise ArgumentError, "Level must be an integer >= 1" if value < 1
|
||||||
|
value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
newparam(:target) do
|
||||||
|
desc "The pacemaker stonith target to apply the level to"
|
||||||
|
end
|
||||||
|
|
||||||
|
newparam(:stonith_resources) do
|
||||||
|
desc "The array containing the list of stonith devices"
|
||||||
|
# FIXME: check for an array of strings
|
||||||
|
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
|
90
manifests/stonith/level.pp
Normal file
90
manifests/stonith/level.pp
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
# == Define: pacemaker::stonith::level
|
||||||
|
#
|
||||||
|
# A resource type to create pacemaker stonith levels
|
||||||
|
#
|
||||||
|
# === Parameters
|
||||||
|
#
|
||||||
|
# [*level*]
|
||||||
|
# (required) The stonith level
|
||||||
|
#
|
||||||
|
# [*target*]
|
||||||
|
# (required) The stonith level target
|
||||||
|
#
|
||||||
|
# [*stonith_resources*]
|
||||||
|
# (required) Array containing the list of stonith devices
|
||||||
|
#
|
||||||
|
# [*ensure*]
|
||||||
|
# (optional) Whether to make sure resource is created or removed
|
||||||
|
# Defaults to present
|
||||||
|
#
|
||||||
|
# [*post_success_sleep*]
|
||||||
|
# (optional) How long to wait acfter successful action
|
||||||
|
# Defaults to 0
|
||||||
|
#
|
||||||
|
# [*tries*]
|
||||||
|
# (optional) How many times to attempt to perform the action
|
||||||
|
# Defaults to 1
|
||||||
|
#
|
||||||
|
# [*try_sleep*]
|
||||||
|
# (optional) How long to wait between tries
|
||||||
|
# Defaults to 0
|
||||||
|
#
|
||||||
|
# [*verify_on_create*]
|
||||||
|
# (optional) Whether to verify creation of resource
|
||||||
|
# Defaults to false
|
||||||
|
#
|
||||||
|
# === Dependencies
|
||||||
|
#
|
||||||
|
# None
|
||||||
|
#
|
||||||
|
# === Authors
|
||||||
|
#
|
||||||
|
# Michele Baldessari <michele@acksyn.org>
|
||||||
|
#
|
||||||
|
# === Copyright
|
||||||
|
#
|
||||||
|
# Copyright (C) 2017 Red Hat 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.
|
||||||
|
#
|
||||||
|
define pacemaker::stonith::level(
|
||||||
|
$level,
|
||||||
|
$target,
|
||||||
|
$stonith_resources,
|
||||||
|
$ensure = 'present',
|
||||||
|
$post_success_sleep = 0,
|
||||||
|
$tries = 1,
|
||||||
|
$try_sleep = 0,
|
||||||
|
$verify_on_create = false,
|
||||||
|
) {
|
||||||
|
if $level == undef {
|
||||||
|
fail('Must provide level')
|
||||||
|
}
|
||||||
|
if $target == undef {
|
||||||
|
fail('Must provide target')
|
||||||
|
}
|
||||||
|
if $stonith_resources == undef {
|
||||||
|
fail('Must provide stonith_resources')
|
||||||
|
}
|
||||||
|
$res = join($stonith_resources, '_')
|
||||||
|
pcmk_stonith_level{ "stonith-level-${level}-${target}-${res}":
|
||||||
|
ensure => $ensure,
|
||||||
|
level => $level,
|
||||||
|
target => $target,
|
||||||
|
stonith_resources => $stonith_resources,
|
||||||
|
post_success_sleep => $post_success_sleep,
|
||||||
|
tries => $tries,
|
||||||
|
try_sleep => $try_sleep,
|
||||||
|
verify_on_create => $verify_on_create,
|
||||||
|
}
|
||||||
|
}
|
86
spec/defines/pacemaker_stonith_level_spec.rb
Normal file
86
spec/defines/pacemaker_stonith_level_spec.rb
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
#
|
||||||
|
# Copyright (C) 2017 Red Hat, 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.
|
||||||
|
#
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe 'pacemaker::stonith::level', type: :define do
|
||||||
|
|
||||||
|
let(:title) { 'test' }
|
||||||
|
|
||||||
|
let(:pre_condition) { [
|
||||||
|
'class pacemaker::corosync {}',
|
||||||
|
'class { "pacemaker::corosync" : }'
|
||||||
|
] }
|
||||||
|
|
||||||
|
|
||||||
|
shared_examples_for 'pacemaker::stonith::level' do
|
||||||
|
context 'with ensure absent' do
|
||||||
|
let(:params) { {
|
||||||
|
:ensure => 'absent',
|
||||||
|
:level => '1',
|
||||||
|
:target => 'node-foo',
|
||||||
|
:stonith_resources => ['ipmi-node-foo','fence-bar'],
|
||||||
|
:tries => 1,
|
||||||
|
:try_sleep => 5,
|
||||||
|
:verify_on_create => false,
|
||||||
|
} }
|
||||||
|
it {
|
||||||
|
is_expected.to contain_pcmk_stonith_level("stonith-level-1-node-foo-ipmi-node-foo_fence-bar").with(
|
||||||
|
:ensure => 'absent',
|
||||||
|
:level => '1',
|
||||||
|
:target => 'node-foo',
|
||||||
|
:stonith_resources => ['ipmi-node-foo','fence-bar'],
|
||||||
|
:tries => 1,
|
||||||
|
:try_sleep => 5,
|
||||||
|
:verify_on_create => false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with params' do
|
||||||
|
let(:params) { {
|
||||||
|
:level => '1',
|
||||||
|
:target => 'node-foo',
|
||||||
|
:stonith_resources => ['ipmi-node-foo','fence-bar'],
|
||||||
|
:tries => 1,
|
||||||
|
:try_sleep => 5,
|
||||||
|
:verify_on_create => false,
|
||||||
|
} }
|
||||||
|
|
||||||
|
it {
|
||||||
|
is_expected.to contain_pcmk_stonith_level("stonith-level-1-node-foo-ipmi-node-foo_fence-bar").with(
|
||||||
|
:ensure => 'present',
|
||||||
|
:level => '1',
|
||||||
|
:target => 'node-foo',
|
||||||
|
:stonith_resources => ['ipmi-node-foo','fence-bar'],
|
||||||
|
:tries => 1,
|
||||||
|
:try_sleep => 5,
|
||||||
|
:verify_on_create => false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
on_supported_os.each do |os, facts|
|
||||||
|
context "on #{os}" do
|
||||||
|
let(:facts) do
|
||||||
|
facts.merge({ :hostname => 'node.example.com' })
|
||||||
|
end
|
||||||
|
|
||||||
|
it_behaves_like 'pacemaker::stonith::level'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Reference in New Issue
Block a user