Merge pull request #66 from aspiers/default-stopped-resources
prevent LWRPs starting newly-created resources by default
This commit is contained in:
@@ -45,8 +45,45 @@ class Chef
|
|||||||
init_current_resource
|
init_current_resource
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# In Pacemaker, target-role defaults to 'Started', but we want
|
||||||
|
# to allow consumers of the LWRPs the choice whether their
|
||||||
|
# newly created resource gets started or not, and we also want
|
||||||
|
# to adhere to the Principle of Least Surprise. Therefore we
|
||||||
|
# stick to the intuitive semantics that
|
||||||
|
#
|
||||||
|
# action :create
|
||||||
|
#
|
||||||
|
# creates the resource with target-role="Stopped" in order to
|
||||||
|
# prevent it from starting immediately, whereas
|
||||||
|
#
|
||||||
|
# action [:create, :start]
|
||||||
|
#
|
||||||
|
# creates the resource and then starts it.
|
||||||
|
#
|
||||||
|
# Consequently we deprecate setting target-role values directly
|
||||||
|
# via the meta attribute.
|
||||||
|
def deprecate_target_role
|
||||||
|
if new_resource.respond_to? :meta
|
||||||
|
meta = new_resource.meta
|
||||||
|
if meta && meta['target-role']
|
||||||
|
::Chef::Log.warn "#{new_resource} used deprecated target-role " +
|
||||||
|
"#{meta['target-role']}; use action :start / :stop instead"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def standard_create_resource
|
def standard_create_resource
|
||||||
|
deprecate_target_role
|
||||||
|
|
||||||
cib_object = cib_object_class.from_chef_resource(new_resource)
|
cib_object = cib_object_class.from_chef_resource(new_resource)
|
||||||
|
|
||||||
|
# We don't want resources to automatically start on creation;
|
||||||
|
# only when the :create action is invoked. However Pacemaker
|
||||||
|
# defaults target-role to "Started", so we need to override it.
|
||||||
|
if cib_object.respond_to? :meta # might be a constraint
|
||||||
|
cib_object.meta['target-role'] = 'Stopped'
|
||||||
|
end
|
||||||
|
|
||||||
cmd = cib_object.configure_command
|
cmd = cib_object.configure_command
|
||||||
|
|
||||||
::Chef::Log.info "Creating new #{cib_object}"
|
::Chef::Log.info "Creating new #{cib_object}"
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
# A mixin for Pacemaker::Resource subclasses which support meta attributes
|
# A mixin for Pacemaker::Resource subclasses which support meta attributes
|
||||||
# (priority, target-role, is-managed)
|
# (priority, target-role, is-managed, etc.)
|
||||||
|
|
||||||
module Pacemaker
|
module Pacemaker
|
||||||
module Mixins
|
module Mixins
|
||||||
|
@@ -17,11 +17,11 @@ module Pacemaker
|
|||||||
end
|
end
|
||||||
|
|
||||||
def crm_start_command
|
def crm_start_command
|
||||||
"crm resource start '#{name}'"
|
"crm --force resource start '#{name}'"
|
||||||
end
|
end
|
||||||
|
|
||||||
def crm_stop_command
|
def crm_stop_command
|
||||||
"crm resource stop '#{name}'"
|
"crm --force resource stop '#{name}'"
|
||||||
end
|
end
|
||||||
|
|
||||||
# CIB object definitions look something like:
|
# CIB object definitions look something like:
|
||||||
|
3
spec/fixtures/keystone_primitive.rb
vendored
3
spec/fixtures/keystone_primitive.rb
vendored
@@ -14,7 +14,6 @@ module Chef::RSpec
|
|||||||
[ "user", "openstack-keystone" ],
|
[ "user", "openstack-keystone" ],
|
||||||
]
|
]
|
||||||
KEYSTONE_PRIMITIVE.meta = [
|
KEYSTONE_PRIMITIVE.meta = [
|
||||||
[ "target-role", "Started" ],
|
|
||||||
[ "is-managed", "true" ]
|
[ "is-managed", "true" ]
|
||||||
]
|
]
|
||||||
KEYSTONE_PRIMITIVE.op = [
|
KEYSTONE_PRIMITIVE.op = [
|
||||||
@@ -24,7 +23,7 @@ module Chef::RSpec
|
|||||||
KEYSTONE_PRIMITIVE_DEFINITION = <<'EOF'.chomp
|
KEYSTONE_PRIMITIVE_DEFINITION = <<'EOF'.chomp
|
||||||
primitive keystone ocf:openstack:keystone \
|
primitive keystone ocf:openstack:keystone \
|
||||||
params os_auth_url="http://node1:5000/v2.0" os_password="adminpw" os_tenant_name="openstack" os_username="admin" user="openstack-keystone" \
|
params os_auth_url="http://node1:5000/v2.0" os_password="adminpw" os_tenant_name="openstack" os_username="admin" user="openstack-keystone" \
|
||||||
meta is-managed="true" target-role="Started" \
|
meta is-managed="true" \
|
||||||
op monitor interval="10s" timeout="60" op start interval="10s" timeout="240"
|
op monitor interval="10s" timeout="60" op start interval="10s" timeout="240"
|
||||||
EOF
|
EOF
|
||||||
end
|
end
|
||||||
|
3
spec/fixtures/resource_group.rb
vendored
3
spec/fixtures/resource_group.rb
vendored
@@ -8,12 +8,11 @@ module Chef::RSpec
|
|||||||
::Pacemaker::Resource::Group.new('group1')
|
::Pacemaker::Resource::Group.new('group1')
|
||||||
RESOURCE_GROUP.members = ['resource1', 'resource2']
|
RESOURCE_GROUP.members = ['resource1', 'resource2']
|
||||||
RESOURCE_GROUP.meta = [
|
RESOURCE_GROUP.meta = [
|
||||||
[ "target-role", "Started" ],
|
|
||||||
[ "is-managed", "true" ]
|
[ "is-managed", "true" ]
|
||||||
]
|
]
|
||||||
RESOURCE_GROUP_DEFINITION = <<'EOF'.chomp
|
RESOURCE_GROUP_DEFINITION = <<'EOF'.chomp
|
||||||
group group1 resource1 resource2 \
|
group group1 resource1 resource2 \
|
||||||
meta is-managed="true" target-role="Started"
|
meta is-managed="true"
|
||||||
EOF
|
EOF
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@@ -7,6 +7,15 @@ this_dir = File.dirname(__FILE__)
|
|||||||
require File.expand_path('provider', this_dir)
|
require File.expand_path('provider', this_dir)
|
||||||
require File.expand_path('shellout', this_dir)
|
require File.expand_path('shellout', this_dir)
|
||||||
|
|
||||||
|
shared_context "stopped resource" do
|
||||||
|
def stopped_fixture
|
||||||
|
new_fixture = fixture.dup
|
||||||
|
new_fixture.meta = fixture.meta.dup
|
||||||
|
new_fixture.meta << ['target-role', 'Stopped']
|
||||||
|
new_fixture
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
shared_examples "a runnable resource" do |fixture|
|
shared_examples "a runnable resource" do |fixture|
|
||||||
def expect_running(running)
|
def expect_running(running)
|
||||||
expect_any_instance_of(cib_object_class) \
|
expect_any_instance_of(cib_object_class) \
|
||||||
@@ -18,6 +27,19 @@ shared_examples "a runnable resource" do |fixture|
|
|||||||
|
|
||||||
include Chef::RSpec::Mixlib::ShellOut
|
include Chef::RSpec::Mixlib::ShellOut
|
||||||
|
|
||||||
|
describe ":create action" do
|
||||||
|
include_context "stopped resource"
|
||||||
|
|
||||||
|
it "should not start a newly-created resource" do
|
||||||
|
stub_shellout("", fixture.definition_string)
|
||||||
|
|
||||||
|
provider.run_action :create
|
||||||
|
|
||||||
|
expect(@chef_run).to run_execute(stopped_fixture.configure_command)
|
||||||
|
expect(@resource).to be_updated
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe ":delete action" do
|
describe ":delete action" do
|
||||||
it "should not delete a running resource" do
|
it "should not delete a running resource" do
|
||||||
stub_shellout(fixture.definition_string)
|
stub_shellout(fixture.definition_string)
|
||||||
@@ -47,7 +69,7 @@ shared_examples "a runnable resource" do |fixture|
|
|||||||
describe ":start action" do
|
describe ":start action" do
|
||||||
it_should_behave_like "action on non-existent resource", \
|
it_should_behave_like "action on non-existent resource", \
|
||||||
:start,
|
:start,
|
||||||
"crm resource start #{fixture.name}", \
|
"crm --force resource start #{fixture.name}", \
|
||||||
"Cannot start non-existent #{fixture}"
|
"Cannot start non-existent #{fixture}"
|
||||||
|
|
||||||
it "should do nothing to a started resource" do
|
it "should do nothing to a started resource" do
|
||||||
@@ -56,7 +78,7 @@ shared_examples "a runnable resource" do |fixture|
|
|||||||
|
|
||||||
provider.run_action :start
|
provider.run_action :start
|
||||||
|
|
||||||
cmd = "crm resource start #{fixture.name}"
|
cmd = "crm --force resource start #{fixture.name}"
|
||||||
expect(@chef_run).not_to run_execute(cmd)
|
expect(@chef_run).not_to run_execute(cmd)
|
||||||
expect(@resource).not_to be_updated
|
expect(@resource).not_to be_updated
|
||||||
end
|
end
|
||||||
@@ -68,7 +90,7 @@ shared_examples "a runnable resource" do |fixture|
|
|||||||
|
|
||||||
provider.run_action :start
|
provider.run_action :start
|
||||||
|
|
||||||
cmd = "crm resource start '#{fixture.name}'"
|
cmd = "crm --force resource start '#{fixture.name}'"
|
||||||
expect(@chef_run).to run_execute(cmd)
|
expect(@chef_run).to run_execute(cmd)
|
||||||
expect(@resource).to be_updated
|
expect(@resource).to be_updated
|
||||||
end
|
end
|
||||||
@@ -77,7 +99,7 @@ shared_examples "a runnable resource" do |fixture|
|
|||||||
describe ":stop action" do
|
describe ":stop action" do
|
||||||
it_should_behave_like "action on non-existent resource", \
|
it_should_behave_like "action on non-existent resource", \
|
||||||
:stop,
|
:stop,
|
||||||
"crm resource stop #{fixture.name}", \
|
"crm --force resource stop #{fixture.name}", \
|
||||||
"Cannot stop non-existent #{fixture}"
|
"Cannot stop non-existent #{fixture}"
|
||||||
|
|
||||||
it "should do nothing to a stopped resource" do
|
it "should do nothing to a stopped resource" do
|
||||||
@@ -86,7 +108,7 @@ shared_examples "a runnable resource" do |fixture|
|
|||||||
|
|
||||||
provider.run_action :stop
|
provider.run_action :stop
|
||||||
|
|
||||||
cmd = "crm resource start #{fixture.name}"
|
cmd = "crm --force resource start #{fixture.name}"
|
||||||
expect(@chef_run).not_to run_execute(cmd)
|
expect(@chef_run).not_to run_execute(cmd)
|
||||||
expect(@resource).not_to be_updated
|
expect(@resource).not_to be_updated
|
||||||
end
|
end
|
||||||
@@ -97,7 +119,7 @@ shared_examples "a runnable resource" do |fixture|
|
|||||||
|
|
||||||
provider.run_action :stop
|
provider.run_action :stop
|
||||||
|
|
||||||
cmd = "crm resource stop '#{fixture.name}'"
|
cmd = "crm --force resource stop '#{fixture.name}'"
|
||||||
expect(@chef_run).to run_execute(cmd)
|
expect(@chef_run).to run_execute(cmd)
|
||||||
expect(@resource).to be_updated
|
expect(@resource).to be_updated
|
||||||
end
|
end
|
||||||
|
@@ -40,10 +40,11 @@ describe "Chef::Provider::PacemakerGroup" do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it "should modify the group if it has different member resources" do
|
it "should modify the group if it has different member resources" do
|
||||||
fixture.members = %w(resource1 resource3)
|
expected = fixture.dup
|
||||||
expected_configure_cmd_args = [fixture.reconfigure_command]
|
expected.members = %w(resource1 resource3)
|
||||||
|
expected_configure_cmd_args = [expected.reconfigure_command]
|
||||||
test_modify(expected_configure_cmd_args) do
|
test_modify(expected_configure_cmd_args) do
|
||||||
@resource.members fixture.members
|
@resource.members expected.members
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@@ -46,11 +46,11 @@ describe "Chef::Provider::PacemakerPrimitive" do
|
|||||||
|
|
||||||
it "should modify the primitive if it has different meta" do
|
it "should modify the primitive if it has different meta" do
|
||||||
expected_configure_cmd_args = [
|
expected_configure_cmd_args = [
|
||||||
%'--set-parameter "target-role" --parameter-value "Stopped" --meta',
|
%'--set-parameter "is-managed" --parameter-value "false" --meta',
|
||||||
].map { |args| "crm_resource --resource #{fixture.name} #{args}" }
|
].map { |args| "crm_resource --resource #{fixture.name} #{args}" }
|
||||||
test_modify(expected_configure_cmd_args) do
|
test_modify(expected_configure_cmd_args) do
|
||||||
@resource.params Hash[fixture.params]
|
@resource.params Hash[fixture.params]
|
||||||
@resource.meta Hash[fixture.meta].merge("target-role" => "Stopped")
|
@resource.meta Hash[fixture.meta].merge("is-managed" => "false")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -58,13 +58,13 @@ describe "Chef::Provider::PacemakerPrimitive" do
|
|||||||
expected_configure_cmd_args = [
|
expected_configure_cmd_args = [
|
||||||
%'--set-parameter "os_password" --parameter-value "newpasswd"',
|
%'--set-parameter "os_password" --parameter-value "newpasswd"',
|
||||||
%'--delete-parameter "os_tenant_name"',
|
%'--delete-parameter "os_tenant_name"',
|
||||||
%'--set-parameter "target-role" --parameter-value "Stopped" --meta',
|
%'--set-parameter "is-managed" --parameter-value "false" --meta',
|
||||||
].map { |args| "crm_resource --resource #{fixture.name} #{args}" }
|
].map { |args| "crm_resource --resource #{fixture.name} #{args}" }
|
||||||
test_modify(expected_configure_cmd_args) do
|
test_modify(expected_configure_cmd_args) do
|
||||||
new_params = Hash[fixture.params].merge("os_password" => "newpasswd")
|
new_params = Hash[fixture.params].merge("os_password" => "newpasswd")
|
||||||
new_params.delete("os_tenant_name")
|
new_params.delete("os_tenant_name")
|
||||||
@resource.params new_params
|
@resource.params new_params
|
||||||
@resource.meta Hash[fixture.meta].merge("target-role" => "Stopped")
|
@resource.meta Hash[fixture.meta].merge("is-managed" => "false")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -81,38 +81,42 @@ describe "Chef::Provider::PacemakerPrimitive" do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should create a primitive if it doesn't already exist" do
|
context "creation from scratch" do
|
||||||
# The first time, Mixlib::ShellOut needs to return an empty definition.
|
include_context "stopped resource"
|
||||||
# Then the resource gets created so the second time it needs to return
|
|
||||||
# the definition used for creation.
|
|
||||||
stub_shellout("", fixture.definition_string)
|
|
||||||
|
|
||||||
provider.run_action :create
|
it "should create a primitive if it doesn't already exist" do
|
||||||
|
# The first time, Mixlib::ShellOut needs to return an empty definition.
|
||||||
|
# Then the resource gets created so the second time it needs to return
|
||||||
|
# the definition used for creation.
|
||||||
|
stub_shellout("", fixture.definition_string)
|
||||||
|
|
||||||
expect(@chef_run).to run_execute(fixture.configure_command)
|
provider.run_action :create
|
||||||
expect(@resource).to be_updated
|
|
||||||
end
|
|
||||||
|
|
||||||
it "should barf if crm fails to create the primitive" do
|
expect(@chef_run).to run_execute(stopped_fixture.configure_command)
|
||||||
stub_shellout("", ["crm configure failed", "oh noes", 3])
|
expect(@resource).to be_updated
|
||||||
|
end
|
||||||
|
|
||||||
expect { provider.run_action :create }.to \
|
it "should barf if crm fails to create the primitive" do
|
||||||
raise_error(RuntimeError, "Failed to create #{fixture}")
|
stub_shellout("", ["crm configure failed", "oh noes", 3])
|
||||||
|
|
||||||
expect(@chef_run).to run_execute(fixture.configure_command)
|
expect { provider.run_action :create }.to \
|
||||||
expect(@resource).not_to be_updated
|
raise_error(RuntimeError, "Failed to create #{fixture}")
|
||||||
end
|
|
||||||
|
|
||||||
# This scenario seems rather artificial and unlikely, but it doesn't
|
expect(@chef_run).to run_execute(stopped_fixture.configure_command)
|
||||||
# do any harm to test it.
|
expect(@resource).not_to be_updated
|
||||||
it "should barf if crm creates a primitive with empty definition" do
|
end
|
||||||
stub_shellout("", "")
|
|
||||||
|
|
||||||
expect { provider.run_action :create }.to \
|
# This scenario seems rather artificial and unlikely, but it doesn't
|
||||||
raise_error(RuntimeError, "Failed to create #{fixture}")
|
# do any harm to test it.
|
||||||
|
it "should barf if crm creates a primitive with empty definition" do
|
||||||
|
stub_shellout("", "")
|
||||||
|
|
||||||
expect(@chef_run).to run_execute(fixture.configure_command)
|
expect { provider.run_action :create }.to \
|
||||||
expect(@resource).not_to be_updated
|
raise_error(RuntimeError, "Failed to create #{fixture}")
|
||||||
|
|
||||||
|
expect(@chef_run).to run_execute(stopped_fixture.configure_command)
|
||||||
|
expect(@resource).not_to be_updated
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should barf if the primitive is already defined with the wrong agent" do
|
it "should barf if the primitive is already defined with the wrong agent" do
|
||||||
|
Reference in New Issue
Block a user