Merge pull request #66 from aspiers/default-stopped-resources

prevent LWRPs starting newly-created resources by default
This commit is contained in:
Vincent Untz
2014-04-26 09:55:41 +02:00
8 changed files with 106 additions and 44 deletions

View File

@@ -45,8 +45,45 @@ class Chef
init_current_resource
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
deprecate_target_role
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
::Chef::Log.info "Creating new #{cib_object}"

View File

@@ -1,5 +1,5 @@
# A mixin for Pacemaker::Resource subclasses which support meta attributes
# (priority, target-role, is-managed)
# (priority, target-role, is-managed, etc.)
module Pacemaker
module Mixins

View File

@@ -17,11 +17,11 @@ module Pacemaker
end
def crm_start_command
"crm resource start '#{name}'"
"crm --force resource start '#{name}'"
end
def crm_stop_command
"crm resource stop '#{name}'"
"crm --force resource stop '#{name}'"
end
# CIB object definitions look something like:

View File

@@ -14,7 +14,6 @@ module Chef::RSpec
[ "user", "openstack-keystone" ],
]
KEYSTONE_PRIMITIVE.meta = [
[ "target-role", "Started" ],
[ "is-managed", "true" ]
]
KEYSTONE_PRIMITIVE.op = [
@@ -24,7 +23,7 @@ module Chef::RSpec
KEYSTONE_PRIMITIVE_DEFINITION = <<'EOF'.chomp
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" \
meta is-managed="true" target-role="Started" \
meta is-managed="true" \
op monitor interval="10s" timeout="60" op start interval="10s" timeout="240"
EOF
end

View File

@@ -8,12 +8,11 @@ module Chef::RSpec
::Pacemaker::Resource::Group.new('group1')
RESOURCE_GROUP.members = ['resource1', 'resource2']
RESOURCE_GROUP.meta = [
[ "target-role", "Started" ],
[ "is-managed", "true" ]
]
RESOURCE_GROUP_DEFINITION = <<'EOF'.chomp
group group1 resource1 resource2 \
meta is-managed="true" target-role="Started"
meta is-managed="true"
EOF
end
end

View File

@@ -7,6 +7,15 @@ this_dir = File.dirname(__FILE__)
require File.expand_path('provider', 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|
def expect_running(running)
expect_any_instance_of(cib_object_class) \
@@ -18,6 +27,19 @@ shared_examples "a runnable resource" do |fixture|
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
it "should not delete a running resource" do
stub_shellout(fixture.definition_string)
@@ -47,7 +69,7 @@ shared_examples "a runnable resource" do |fixture|
describe ":start action" do
it_should_behave_like "action on non-existent resource", \
:start,
"crm resource start #{fixture.name}", \
"crm --force resource start #{fixture.name}", \
"Cannot start non-existent #{fixture}"
it "should do nothing to a started resource" do
@@ -56,7 +78,7 @@ shared_examples "a runnable resource" do |fixture|
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(@resource).not_to be_updated
end
@@ -68,7 +90,7 @@ shared_examples "a runnable resource" do |fixture|
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(@resource).to be_updated
end
@@ -77,7 +99,7 @@ shared_examples "a runnable resource" do |fixture|
describe ":stop action" do
it_should_behave_like "action on non-existent resource", \
:stop,
"crm resource stop #{fixture.name}", \
"crm --force resource stop #{fixture.name}", \
"Cannot stop non-existent #{fixture}"
it "should do nothing to a stopped resource" do
@@ -86,7 +108,7 @@ shared_examples "a runnable resource" do |fixture|
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(@resource).not_to be_updated
end
@@ -97,7 +119,7 @@ shared_examples "a runnable resource" do |fixture|
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(@resource).to be_updated
end

View File

@@ -40,10 +40,11 @@ describe "Chef::Provider::PacemakerGroup" do
end
it "should modify the group if it has different member resources" do
fixture.members = %w(resource1 resource3)
expected_configure_cmd_args = [fixture.reconfigure_command]
expected = fixture.dup
expected.members = %w(resource1 resource3)
expected_configure_cmd_args = [expected.reconfigure_command]
test_modify(expected_configure_cmd_args) do
@resource.members fixture.members
@resource.members expected.members
end
end

View File

@@ -46,11 +46,11 @@ describe "Chef::Provider::PacemakerPrimitive" do
it "should modify the primitive if it has different meta" do
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}" }
test_modify(expected_configure_cmd_args) do
@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
@@ -58,13 +58,13 @@ describe "Chef::Provider::PacemakerPrimitive" do
expected_configure_cmd_args = [
%'--set-parameter "os_password" --parameter-value "newpasswd"',
%'--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}" }
test_modify(expected_configure_cmd_args) do
new_params = Hash[fixture.params].merge("os_password" => "newpasswd")
new_params.delete("os_tenant_name")
@resource.params new_params
@resource.meta Hash[fixture.meta].merge("target-role" => "Stopped")
@resource.meta Hash[fixture.meta].merge("is-managed" => "false")
end
end
@@ -81,38 +81,42 @@ describe "Chef::Provider::PacemakerPrimitive" do
end
end
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)
context "creation from scratch" do
include_context "stopped resource"
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)
expect(@resource).to be_updated
end
provider.run_action :create
it "should barf if crm fails to create the primitive" do
stub_shellout("", ["crm configure failed", "oh noes", 3])
expect(@chef_run).to run_execute(stopped_fixture.configure_command)
expect(@resource).to be_updated
end
expect { provider.run_action :create }.to \
raise_error(RuntimeError, "Failed to create #{fixture}")
it "should barf if crm fails to create the primitive" do
stub_shellout("", ["crm configure failed", "oh noes", 3])
expect(@chef_run).to run_execute(fixture.configure_command)
expect(@resource).not_to be_updated
end
expect { provider.run_action :create }.to \
raise_error(RuntimeError, "Failed to create #{fixture}")
# This scenario seems rather artificial and unlikely, but it doesn't
# 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(stopped_fixture.configure_command)
expect(@resource).not_to be_updated
end
expect { provider.run_action :create }.to \
raise_error(RuntimeError, "Failed to create #{fixture}")
# This scenario seems rather artificial and unlikely, but it doesn't
# 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(@resource).not_to be_updated
expect { provider.run_action :create }.to \
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
it "should barf if the primitive is already defined with the wrong agent" do