Add new pcs 0.10 compatible remote addition implementation

New pcs 0.10 needs to implement remotes addition in a completely
different way. It is not sufficient anymore to just create the
ocf::pacemaker::remote resource and make sure that pacemaker_remote is
up and running with the same authkey on all nodes. Now we
need to setup pcsd on all nodes (remotes and controllers), setup the
hacluster user and then do a pcs cluster remote-add command.

We do this only when pcs 0.10 is detected in order to maintain
the old proven behaviour on pcs 0.9x.

Tested this on stein + rhel8 correctly get remotes working on an IHA
setup:
[root@controller-0 galera-bundle-1]# pcs status
Cluster name: tripleo_cluster
Stack: corosync
Current DC: controller-1 (version 2.0.1-4.el8-0eb7991564) - partition with quorum
Last updated: Thu May 23 05:52:33 2019
Last change: Tue May 21 14:20:14 2019 by root via cibadmin on controller-0

17 nodes configured
72 resources configured

Online: [ controller-0 controller-1 controller-2 ]
RemoteOnline: [ compute-0 compute-1 ]

Full list of resources:

 compute-0      (ocf::pacemaker:remote):        Started controller-0
 compute-1      (ocf::pacemaker:remote):        Started controller-1

Also tested on queens to make sure no regressions in the old codepaths
are introduced. Additionally tested a redeploy on stein to make sure
idempotency is preserved.

Change-Id: I852d5d7aa8578c45f0c7215827cedd4ea72c8d0b
This commit is contained in:
Michele Baldessari 2019-05-23 07:51:40 +02:00
parent 0c5d69921d
commit fde568564d
5 changed files with 379 additions and 36 deletions

View File

@ -0,0 +1,130 @@
require_relative '../pcmk_common'
Puppet::Type.type(:pcmk_remote).provide(:default) do
desc 'A remote resource definition for pacemaker resource'
def build_pcs_auth_cmd()
if @resource[:pcs_user] == '' or @resource[:pcs_password] == ''
raise(Puppet::Error, "When using the new pcs cluster node backend for remotes " +
"'pcs_user' and 'pcs_password must be both defined (#{@resource[:pcs_user]} " +
"#{@resource[:pcs_password]})")
end
# Build the 'pcs resource create' command. Check out the pcs man page :-)
cmd = 'host auth ' + @resource[:name]
if not_empty_string(@resource[:remote_address])
cmd += ' addr=' + @resource[:remote_address]
end
cmd += ' -u ' + @resource[:pcs_user] + ' -p "' + @resource[:pcs_password] + '"'
cmd
end
def build_pcs_remote_cmd()
resource_params = @resource[:resource_params]
meta_params = @resource[:meta_params]
op_params = @resource[:op_params]
# Build the 'pcs resource create' command. Check out the pcs man page :-)
cmd = 'cluster node add-remote ' + @resource[:name]
if not_empty_string(@resource[:remote_address])
cmd += ' ' + @resource[:remote_address]
end
if not_empty_string(resource_params)
cmd += ' ' + resource_params
end
if not_empty_string(meta_params)
cmd += ' meta ' + meta_params
end
if not_empty_string(op_params)
cmd += ' op ' + op_params
end
cmd
end
### overloaded methods
def initialize(*args)
super(*args)
Puppet.debug("puppet-pacemaker: initialize()")
# Hash to store the existance state of each resource
@resources_state = {}
end
def create
did_resource_exist = @resources_state[@resource[:name]] == PCMK_NOCHANGENEEDED
cmd_auth = build_pcs_auth_cmd()
cmd_remote = build_pcs_remote_cmd()
pcs_without_push('create', @resource[:name], cmd_auth, @resource[:tries],
@resource[:try_sleep], @resource[:post_success_sleep])
pcs_without_push('create', @resource[:name], cmd_remote, @resource[:tries],
@resource[:try_sleep], @resource[:post_success_sleep])
end
def destroy
cmd = 'cluster node delete-remote ' + @resource[:name]
pcs_without_push('delete', @resource[:name], cmd, @resource[:tries],
@resource[:try_sleep], @resource[:post_success_sleep])
end
def exists?
@resources_state[@resource[:name]] = resource_exists?
did_resource_exist = @resources_state[@resource[:name]] == PCMK_NOCHANGENEEDED
Puppet.debug("Exists: resource #{@resource[:name]} exists "\
"#{@resources_state[@resource[:name]]} "\
"resource deep_compare: #{@resource[:deep_compare]}")
if did_resource_exist
return true
end
return false
end
def resource_exists?
cmd = 'resource show ' + @resource[:name] + ' > /dev/null 2>&1'
ret = pcs('show', @resource[:name], cmd, @resource[:tries],
@resource[:try_sleep], false, @resource[:post_success_sleep])
if ret == false then
return PCMK_NOTEXISTS
end
return PCMK_NOCHANGENEEDED
end
### property methods
# It isn't an easy road if you want to make these true
# puppet-like resource properties. Here is a start if you are feeling brave:
# https://github.com/cwolferh/puppet-pacemaker/blob/pcmk_resource_improvements_try0/lib/puppet/provider/pcmk_resource/default.rb#L64
def resource_params
@resource[:resource_params]
end
def resource_params=(value)
end
def op_params
@resource[:op_params]
end
def op_params=(value)
end
def meta_params
@resource[:meta_params]
end
def meta_params=(value)
end
def reconnect_interval
@resource[:reconnect_interval]
end
def reconnect_interval=(value)
end
def remote_address
@resource[:remote_address]
end
def remote_address=(value)
end
end

View File

@ -0,0 +1,131 @@
require 'puppet/parameter/boolean'
Puppet::Type.newtype(:pcmk_remote) do
@doc = "Remote resource definition for a pacemaker"
ensurable
newparam(:name) do
desc "A unique name for the resource"
end
newparam(:pcs_user) do
desc "Pcs user to use when authenticating a remote node"
defaultto ''
end
newparam(:pcs_password) do
desc "Pcs password to use when authenticating a remote node"
defaultto ''
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
## 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
newproperty(:op_params) do
desc "op parameters"
end
newproperty(:meta_params) do
desc "meta parameters"
end
newproperty(:resource_params) do
desc "resource parameters"
end
newproperty(:remote_address) do
desc "Address for remote resources"
end
newproperty(:reconnect_interval) do
desc "reconnection interval for remote resources"
munge do |value|
if value.is_a?(String)
unless value =~ /^[-\d.]+$/
raise ArgumentError, "reconnect_interval must be a number"
end
value = Float(value)
end
raise ArgumentError, "reconnect_interval cannot be a negative number" if value < 0
value
end
defaultto 60
end
newparam(:deep_compare, :boolean => true, :parent => Puppet::Parameter::Boolean) do
desc "Whether to enable deep comparing of resource
When set to true a resource will be compared in full (options, meta parameters,..)
to the existing one and in case of difference it will be repushed to the CIB
Defaults to `false`."
defaultto false
end
newparam(:update_settle_secs) do
desc "The time in seconds to wait for the cluster to settle after resource has been updated
when :deep_compare kicked in. Defaults to '600'."
munge do |value|
if value.is_a?(String)
unless value =~ /^[-\d.]+$/
raise ArgumentError, "update_settle_secs must be a number"
end
value = Float(value)
end
raise ArgumentError, "update_settle_secs cannot be a negative number" if value < 0
value
end
defaultto 600
end
end

View File

@ -271,7 +271,8 @@ class pacemaker::corosync(
Exec['wait-for-settle']
}
if $remote_authkey {
# pcs 0.10/pcmk 2.0 take care of the authkey internally by themselves
if $remote_authkey and !$::pacemaker::pcs_010 {
file { 'etc-pacemaker':
ensure => directory,
path => '/etc/pacemaker',

View File

@ -20,33 +20,95 @@
#
# === Parameters
#
# [*use_pcsd*]
# (optional) Should the remote use pcsd to be setup
# Defaults to false
#
# [*manage_fw*]
# (optional) Manage or not IPtables rules.
# Defaults to true
#
# [*remote_authkey*]
# (Required) Authkey for pacemaker remote nodes
# Defaults to undef
#
class pacemaker::remote ($remote_authkey) {
# [*pcsd_debug*]
# (optional) Enable pcsd debugging
# Defaults to false
#
class pacemaker::remote (
$remote_authkey,
$use_pcsd = false,
$pcs_user = 'hacluster',
$pcs_password = undef,
$manage_fw = true,
$pcsd_debug = false,
) {
include ::pacemaker::params
ensure_resource('package', $::pacemaker::params::pcmk_remote_package_list, {
ensure => present
})
Package<| title == 'pacemaker-remote' |> -> File <| title == 'etc-pacemaker' |>
file { 'etc-pacemaker':
ensure => directory,
path => '/etc/pacemaker',
owner => 'hacluster',
group => 'haclient',
mode => '0750',
} ->
file { 'etc-pacemaker-authkey':
path => '/etc/pacemaker/authkey',
owner => 'hacluster',
group => 'haclient',
mode => '0640',
content => $remote_authkey,
} ->
service { 'pacemaker_remote':
ensure => running,
enable => true,
# pacemaker remote needs pcsd only with pcs >= 0.10
if $use_pcsd {
include ::pacemaker::install
if $manage_fw {
firewall { '001 pcsd':
proto => 'tcp',
dport => ['2224'],
action => 'accept',
}
firewall { '001 pcsd ipv6':
proto => 'tcp',
dport => ['2224'],
action => 'accept',
provider => 'ip6tables',
}
}
$pcsd_debug_str = bool2str($pcsd_debug)
file_line { 'pcsd_debug_ini':
path => $::pacemaker::params::pcsd_sysconfig,
line => "PCSD_DEBUG=${pcsd_debug_str}",
match => '^PCSD_DEBUG=',
require => Class['::pacemaker::install'],
before => Service['pcsd'],
notify => Service['pcsd'],
}
user { $pcs_user:
password => pw_hash($pcs_password, 'SHA-512', fqdn_rand_string(10)),
groups => 'haclient',
require => Class['::pacemaker::install'],
before => Service['pcsd'],
}
# only set up pcsd, not the other cluster services which have
# very specific setup and when-to-start-up requirements
# that are taken care of in corosync.pp
service { 'pcsd':
ensure => running,
hasstatus => true,
hasrestart => true,
enable => true,
require => Class['::pacemaker::install'],
}
} else {
# This gets managed by pcsd directly when pcs is < 0.10
Package<| title == 'pacemaker-remote' |> -> File <| title == 'etc-pacemaker' |>
file { 'etc-pacemaker':
ensure => directory,
path => '/etc/pacemaker',
owner => 'hacluster',
group => 'haclient',
mode => '0750',
} ->
file { 'etc-pacemaker-authkey':
path => '/etc/pacemaker/authkey',
owner => 'hacluster',
group => 'haclient',
mode => '0640',
content => $remote_authkey,
} ->
service { 'pacemaker_remote':
ensure => running,
enable => true,
}
}
}

View File

@ -106,24 +106,43 @@ define pacemaker::resource::remote(
$tries = 1,
$try_sleep = 0,
$verify_on_create = false,
$pcs_user = 'hacluster',
$pcs_password = undef,
$location_rule = undef,
$deep_compare = hiera('pacemaker::resource::remote::deep_compare', false),
$update_settle_secs = hiera('pacemaker::resource::remote::update_settle_secs', 600),
) {
pcmk_resource { $name:
ensure => $ensure,
resource_type => 'remote',
remote_address => $remote_address,
reconnect_interval => $reconnect_interval,
resource_params => $resource_params,
meta_params => $meta_params,
op_params => $op_params,
bundle => $bundle,
tries => $tries,
try_sleep => $try_sleep,
verify_on_create => $verify_on_create,
location_rule => $location_rule,
deep_compare => $deep_compare,
update_settle_secs => $update_settle_secs,
if $::pacemaker::params::pcs_010 {
pcmk_remote { $name:
ensure => $ensure,
remote_address => $remote_address,
reconnect_interval => $reconnect_interval,
resource_params => $resource_params,
meta_params => $meta_params,
op_params => $op_params,
tries => $tries,
try_sleep => $try_sleep,
pcs_user => $pcs_user,
pcs_password => $pcs_password,
deep_compare => $deep_compare,
update_settle_secs => $update_settle_secs,
}
} else {
pcmk_resource { $name:
ensure => $ensure,
resource_type => 'remote',
remote_address => $remote_address,
reconnect_interval => $reconnect_interval,
resource_params => $resource_params,
meta_params => $meta_params,
op_params => $op_params,
bundle => $bundle,
tries => $tries,
try_sleep => $try_sleep,
verify_on_create => $verify_on_create,
location_rule => $location_rule,
deep_compare => $deep_compare,
update_settle_secs => $update_settle_secs,
}
}
}