diff --git a/README.md b/README.md index 6452c4ec..d5c8405b 100644 --- a/README.md +++ b/README.md @@ -448,6 +448,21 @@ cs_clone { 'nginx_service-clone' : } ``` +Configure a Promotable (Active/Passive) resource + +```puppet +cs_clone { 'redis-clone': + ensure => present, + primitive => 'redis', + clone_max => 2, + clone_node_max => 1, + promotable => true, + promoted_max => 1, + promoted_node_max => 1, + notify_clones => true, +} +``` + ### Corosync Properties A few global settings can be changed with the "cs_property" section. diff --git a/REFERENCE.md b/REFERENCE.md index b376293b..2a616b36 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -1048,6 +1048,31 @@ Default value: `absent` The corosync resource primitive to be cloned. +##### `promotable` + +Valid values: `true`, `false`, `absent` + +If true, clone instances can perform a special role that Pacemaker will manage via the resource agent’s +promote and demote actions. The resource agent must support these actions. Allowed values: false, true + +Default value: `absent` + +##### `promoted_max` + +Valid values: `%r{\d+}`, `absent` + +If promotable is true, the number of instances that can be promoted at one time across the entire cluster + +Default value: `absent` + +##### `promoted_node_max` + +Valid values: `%r{\d+}`, `absent` + +If promotable is true and globally-unique is false, the number of clone instances can be promoted at one time on a single node + +Default value: `absent` + #### Parameters The following parameters are available in the `cs_clone` type. diff --git a/lib/puppet/provider/cs_clone/crm.rb b/lib/puppet/provider/cs_clone/crm.rb index 3d775be3..44e44881 100644 --- a/lib/puppet/provider/cs_clone/crm.rb +++ b/lib/puppet/provider/cs_clone/crm.rb @@ -33,14 +33,17 @@ def self.instances items = nvpairs_to_hash(e.elements['meta_attributes']) clone_instance = { - name: e.attributes['id'], - ensure: :present, - clone_max: items['clone-max'], - clone_node_max: items['clone-node-max'], - notify_clones: items['notify'], - globally_unique: items['globally-unique'], - ordered: items['ordered'], - interleave: items['interleave'], + name: e.attributes['id'], + ensure: :present, + clone_max: items['clone-max'], + clone_node_max: items['clone-node-max'], + notify_clones: items['notify'], + globally_unique: items['globally-unique'], + ordered: items['ordered'], + interleave: items['interleave'], + promotable: items['promotable'], + promoted_max: items['promoted-max'], + promoted_node_max: items['promoted-node-max'], existing_resource: :true } @@ -56,16 +59,19 @@ def self.instances # of actually doing the work. def create @property_hash = { - name: @resource[:name], - ensure: :present, - primitive: @resource[:primitive], - clone_max: @resource[:clone_max], - clone_node_max: @resource[:clone_node_max], - notify_clones: @resource[:notify_clones], - globally_unique: @resource[:globally_unique], - ordered: @resource[:ordered], - interleave: @resource[:interleave], - cib: @resource[:cib], + name: @resource[:name], + ensure: :present, + primitive: @resource[:primitive], + clone_max: @resource[:clone_max], + clone_node_max: @resource[:clone_node_max], + notify_clones: @resource[:notify_clones], + globally_unique: @resource[:globally_unique], + ordered: @resource[:ordered], + interleave: @resource[:interleave], + cib: @resource[:cib], + promotable: @resource[:promotable], + promoted_max: @resource[:promoted_max], + promoted_node_max: @resource[:promoted_node_max], existing_resource: :false } end @@ -104,7 +110,10 @@ def flush notify_clones: 'notify', globally_unique: 'globally-unique', ordered: 'ordered', - interleave: 'interleave' + interleave: 'interleave', + promotable: 'promotable', + promoted_max: 'promoted-max', + promoted_node_max: 'promoted-node-max' }.each do |property, clone_property| meta << "#{clone_property}=#{@resource.should(property)}" unless @resource.should(property) == :absent end diff --git a/lib/puppet/provider/cs_clone/pcs.rb b/lib/puppet/provider/cs_clone/pcs.rb index 5dee868f..814f5d21 100644 --- a/lib/puppet/provider/cs_clone/pcs.rb +++ b/lib/puppet/provider/cs_clone/pcs.rb @@ -45,14 +45,17 @@ def self.instances items = nvpairs_to_hash(e.elements['meta_attributes']) clone_instance = { - name: e.attributes['id'], - ensure: :present, - clone_max: items['clone-max'], - clone_node_max: items['clone-node-max'], - notify_clones: items['notify'], - globally_unique: items['globally-unique'], - ordered: items['ordered'], - interleave: items['interleave'] + name: e.attributes['id'], + ensure: :present, + clone_max: items['clone-max'], + clone_node_max: items['clone-node-max'], + notify_clones: items['notify'], + globally_unique: items['globally-unique'], + ordered: items['ordered'], + interleave: items['interleave'], + promotable: items['promotable'], + promoted_max: items['promoted-max'], + promoted_node_max: items['promoted-node-max'] } if e.elements['primitive'] @@ -76,16 +79,19 @@ def self.instances # of actually doing the work. def create @property_hash = { - name: @resource[:name], - ensure: :present, - primitive: @resource[:primitive], - group: @resource[:group], - clone_max: @resource[:clone_max], - clone_node_max: @resource[:clone_node_max], - notify_clones: @resource[:notify_clones], - globally_unique: @resource[:globally_unique], - ordered: @resource[:ordered], - interleave: @resource[:interleave] + name: @resource[:name], + ensure: :present, + primitive: @resource[:primitive], + group: @resource[:group], + clone_max: @resource[:clone_max], + clone_node_max: @resource[:clone_node_max], + notify_clones: @resource[:notify_clones], + globally_unique: @resource[:globally_unique], + ordered: @resource[:ordered], + interleave: @resource[:interleave], + promotable: @resource[:promotable], + promoted_max: @resource[:promoted_max], + promoted_node_max: @resource[:promoted_node_max] } end @@ -128,7 +134,10 @@ def flush notify_clones: 'notify', globally_unique: 'globally-unique', ordered: 'ordered', - interleave: 'interleave' + interleave: 'interleave', + promotable: 'promotable', + promoted_max: 'promoted-max', + promoted_node_max: 'promoted-node-max' }.each do |property, clone_property| cmd << "#{clone_property}=#{@resource.should(property)}" unless @resource.should(property) == :absent end diff --git a/lib/puppet/type/cs_clone.rb b/lib/puppet/type/cs_clone.rb index 5cc551e4..c6762294 100644 --- a/lib/puppet/type/cs_clone.rb +++ b/lib/puppet/type/cs_clone.rb @@ -78,6 +78,31 @@ defaultto :absent end + newproperty(:promotable) do + desc 'If true, clone instances can perform a special role that Pacemaker will manage via the resource agent’s + promote and demote actions. The resource agent must support these actions. Allowed values: false, true' + + newvalues(:true, :false, :absent) + + defaultto :absent + end + + newproperty(:promoted_max) do + desc 'If promotable is true, the number of instances that can be promoted at one time across the entire cluster' + + newvalues(%r{\d+}, :absent) + + defaultto :absent + end + + newproperty(:promoted_node_max) do + desc 'If promotable is true and globally-unique is false, the number of clone instances can be promoted at one time on a single node' + + newvalues(%r{\d+}, :absent) + + defaultto :absent + end + newparam(:cib) do desc "Corosync applies its configuration immediately. Using a CIB allows you to group multiple primitives and relationships to be applied at diff --git a/spec/acceptance/cs_clone_spec.rb b/spec/acceptance/cs_clone_spec.rb index add7f18c..08494dd0 100755 --- a/spec/acceptance/cs_clone_spec.rb +++ b/spec/acceptance/cs_clone_spec.rb @@ -120,14 +120,17 @@ def fetch_value_command(name) it 'creates the clone' do pp = <<-EOS cs_clone { 'duncan_vip_complex_clone_#{type}': - ensure => present, - #{type} => '#{property_value}', - clone_max => 42, - notify_clones => false, - clone_node_max => 2, - globally_unique => true, - ordered => false, - interleave => false, + ensure => present, + #{type} => '#{property_value}', + clone_max => 42, + notify_clones => false, + clone_node_max => 2, + globally_unique => true, + ordered => false, + interleave => false, + promotable => false, + promoted_max => 5, + promoted_node_max => 2, } EOS apply_manifest(pp, catch_failures: true, debug: false, trace: true) @@ -178,17 +181,38 @@ def fetch_value_command(name) end end + it 'sets promotable' do + shell(fetch_value_command('promotable')) do |r| + expect(r.stdout).to match(%r{value="false"}) + end + end + + it 'sets promoted_max' do + shell(fetch_value_command('promoted-max')) do |r| + expect(r.stdout).to match(%r{value="5"}) + end + end + + it 'sets promoted_node_max' do + shell(fetch_value_command('promoted-node-max')) do |r| + expect(r.stdout).to match(%r{value="2"}) + end + end + it 'changes the clone' do pp = <<-EOS cs_clone { 'duncan_vip_complex_clone_#{type}': - ensure => present, - #{type} => '#{property_value}', - clone_max => 43, - clone_node_max => 1, - notify_clones => true, - globally_unique => false, - ordered => true, - interleave => true, + ensure => present, + #{type} => '#{property_value}', + clone_max => 43, + clone_node_max => 1, + notify_clones => true, + globally_unique => false, + ordered => true, + interleave => true, + promotable => true, + promoted_max => 6, + promoted_node_max => 1, } EOS apply_manifest(pp, catch_failures: true, debug: false, trace: true) @@ -235,6 +259,24 @@ def fetch_value_command(name) end end + it 'sets promotable' do + shell(fetch_value_command('promotable')) do |r| + expect(r.stdout).to match(%r{value="true"}) + end + end + + it 'sets promoted_max' do + shell(fetch_value_command('promoted-max')) do |r| + expect(r.stdout).to match(%r{value="6"}) + end + end + + it 'sets promoted_node_max' do + shell(fetch_value_command('promoted-node-max')) do |r| + expect(r.stdout).to match(%r{value="1"}) + end + end + it 'removes some parameters' do pp = <<-EOS cs_clone { 'duncan_vip_complex_clone_#{type}': @@ -287,6 +329,24 @@ def fetch_value_command(name) expect(r.stdout).to match(%r{value="true"}) end end + + it 'deletes promotable' do + assert_raises(Beaker::Host::CommandFailure) do + shell(fetch_value_command('promotable')) + end + end + + it 'deletes promoted-max' do + assert_raises(Beaker::Host::CommandFailure) do + shell(fetch_value_command('promoted-max')) + end + end + + it 'deletes promoted-node-max' do + assert_raises(Beaker::Host::CommandFailure) do + shell(fetch_value_command('promoted-node-max')) + end + end end # rubocop:enable RSpec/RepeatedExample end diff --git a/spec/unit/puppet/provider/cs_clone_crm_spec.rb b/spec/unit/puppet/provider/cs_clone_crm_spec.rb index 4b3b03d4..a98e38ab 100644 --- a/spec/unit/puppet/provider/cs_clone_crm_spec.rb +++ b/spec/unit/puppet/provider/cs_clone_crm_spec.rb @@ -193,5 +193,23 @@ def expect_update(pattern) expect_update(%r{\sinterleave=true}) instance.flush end + + it 'sets promotable' do + instance.resource[:interleave] = :true + expect_update(%r{\spromotable=true}) + instance.flush + end + + it 'sets max promoted' do + instance.resource[:promoted_max] = 3 + expect_update(%r{\spromoted-max=3}) + instance.flush + end + + it 'sets max node promoted' do + instance.resource[:promoted_node_max] = 3 + expect_update(%r{\spromoted-node-max=3}) + instance.flush + end end end diff --git a/spec/unit/puppet/provider/cs_clone_pcs_spec.rb b/spec/unit/puppet/provider/cs_clone_pcs_spec.rb index ca96419b..f4782389 100644 --- a/spec/unit/puppet/provider/cs_clone_pcs_spec.rb +++ b/spec/unit/puppet/provider/cs_clone_pcs_spec.rb @@ -178,6 +178,24 @@ expect_commands(%r{interleave=true}) instance.flush end + + it 'sets promotable' do + instance.resource[:promotable] = :true + expect_commands(%r{promotable=true}) + instance.flush + end + + it 'sets max promoted' do + instance.resource[:promoted_max] = 3 + expect_commands(%r{promoted-max=3}) + instance.flush + end + + it 'sets max node promotable' do + instance.resource[:promoted_node_max] = 3 + expect_commands(%r{promoted-node-max=3}) + instance.flush + end end context 'when changing clone id' do diff --git a/spec/unit/puppet/type/cs_clone_spec.rb b/spec/unit/puppet/type/cs_clone_spec.rb index 47a83409..d7b9e388 100644 --- a/spec/unit/puppet/type/cs_clone_spec.rb +++ b/spec/unit/puppet/type/cs_clone_spec.rb @@ -30,7 +30,7 @@ end %i[primitive clone_max clone_node_max notify_clones globally_unique - ordered interleave].each do |property| + ordered interleave promotable promoted_max promoted_node_max].each do |property| it "has a #{property} property" do expect(subject).to be_validproperty(property) end @@ -42,7 +42,7 @@ end describe 'when validating attributes' do - %i[notify_clones globally_unique ordered interleave].each do |attribute| + %i[notify_clones globally_unique ordered interleave promotable].each do |attribute| it "validates that the #{attribute} attribute can be true/false" do [true, false].each do |value| expect(subject.new(