Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Offline disable #687

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
4 changes: 4 additions & 0 deletions lib/mb/cli_gateway.rb
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,10 @@ def enable(hostname)
desc: "Perform HOST disable even if the environment is locked",
default: false,
aliases: "-f"
method_option :offline,
type: :boolean,
desc: "Do not attempt to connect to the node to disable services. Assume it is offline.",
default: false
desc "disable HOST", "Stop services on HOST and prevent chef-client from running until reenabled."
def disable(hostname)
job = node_querier.async_disable(hostname, options.to_hash.symbolize_keys)
Expand Down
58 changes: 43 additions & 15 deletions lib/mb/node_querier.rb
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ def async_purge(host, options = {})
# @param [Hash] options
#
# @option options [Boolean] :force (false) Ignore environment lock and execute anyway.
# @option options [Boolean] :offline (false) Do not attempt to connect to the node to
# disable services. Assume it is offline.
#
# @return [MB::JobTicket]
def async_disable(host, options = {})
Expand Down Expand Up @@ -423,17 +425,25 @@ def enable(job, host, options = {})
# @param [Hash] options
#
# @option options [Boolean] :force (false) Ignore environment lock and execute anyway.
# @option options [Boolean] :offline (false) Do not attempt to connect to the node to
# disable services. Assume it is offline.
#
def disable(job, host, options = {})
job.report_running("Discovering host's registered node name")
node_name = registered_as(host)
if !node_name
# TODO auth could fail and cause this to throw
job.report_failure("Could not discover the host's node name. The host may not be " +
"registered with Chef or the embedded Ruby used to identify the " +
"node name may not be available. #{host} was not disabled!")
end
job.set_status("Host registered as #{node_name}.")
node_name = if options[:offline]
job.report_running("Using #{host} as node name as --offline was passed")
host
else
job.report_running("Discovering host's registered node name")
discovered_name = registered_as(host)
if !node_name
# TODO auth could fail and cause this to throw
job.report_failure("Could not discover the host's node name. The host may not be " +
"registered with Chef or the embedded Ruby used to identify the " +
"node name may not be available. #{host} was not disabled!")
end
job.set_status("Host registered as #{discovered_name}.")
discovered_name
end

node = fetch_node(job, node_name)

Expand All @@ -444,12 +454,30 @@ def disable(job, host, options = {})
job.set_status("#{node.name} is already disabled.")
success = true
else
required_run_list = on_dynamic_services(job, node) do |dynamic_service, plugin|
dynamic_service.node_state_change(job,
plugin,
node,
MB::Gear::DynamicService::STOP,
false)
required_run_list = []
unless options[:offline]
required_run_list = on_dynamic_services(job, node) do |dynamic_service, plugin|
dynamic_service.node_state_change(job,
plugin,
node,
MB::Gear::DynamicService::STOP,
false)
end
if !required_run_list.empty?
job.set_status "Running chef with the following run list: #{required_run_list.inspect}"
bulk_chef_run(job, [node], required_run_list)
else
job.set_status "No recipes required to run."
end
end

node.run_list = [DISABLED_RUN_LIST_ENTRY].concat(node.run_list)

if node.save
job.set_status "#{node.name} disabled."
success = true
else
job.set_status "#{node.name} did not save! Disabled run_list entry was unable to be added to the node due to node save failure."
end
end

Expand Down
38 changes: 33 additions & 5 deletions spec/unit/mb/node_querier_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@
let(:host) { "192.168.1.1" }
let(:options) { Hash.new }

it "creates a Job and delegates to #disable" do
it "creates a Job and delegates to #enable" do
ticket = double('ticket')
job = double('job', ticket: ticket)
MB::Job.should_receive(:new).and_return(job)
Expand All @@ -275,7 +275,7 @@

describe "#enable" do
let(:host) { "192.168.1.1" }
let(:job) { MB::Job.new(:disable) }
let(:job) { MB::Job.new(:enable) }
let(:future_stub) { double(Celluloid::Future, value: nil) }
let(:node_stub) {
double(Ridley::NodeObject,
Expand Down Expand Up @@ -422,6 +422,17 @@
e.message.should == "exit"
end
end

it "reports failure when using --offline" do
subject.should_not_receive(:registered_as)
job.should_receive(:report_failure).with("The node #{host} is not registered with the Chef server.").and_return { raise "exit" }
subject.stub_chain("chef_connection.node.find").and_return { raise Ridley::Errors::ResourceNotFound }
begin
subject.disable(job, host, offline: true)
rescue => e
e.message.should == "exit"
end
end
end

context "when the node is registered" do
Expand Down Expand Up @@ -452,11 +463,16 @@
components: [send(:"#{x}_component")]) }
let(:"environment") { "theenv" }
end

before do
subject.stub_chain(:chef_connection, :node, :find).with(node_name).and_return(node)
node.should_receive(:run_list).and_return(run_list)
node.stub(:run_list=)
end

it "disables the node" do
subject.stub(:plugin_manager).and_return(plugin_manager)
subject.should_receive(:registered_as).with(host).and_return(node_name)
subject.stub_chain(:chef_connection, :node, :find).with(node_name).and_return(node)
%w[foo bar].each_with_index do |x, i|
plugin_manager
.should_receive(:for_run_list_entry)
Expand All @@ -466,13 +482,25 @@
send(:"#{x}_service").stub(:dynamic_service?).and_return(true)
send(:"#{x}_group").should_receive(:includes_recipe?).with(run_list[i]).and_return(true)
send(:"dynamic_#{x}_service").should_receive(:node_state_change).with(job, send(:"#{x}_plugin"), node, MB::Gear::DynamicService::STOP, false)
node.should_receive(:run_list).and_return(run_list)
node.stub(:run_list=)
end
subject.should_receive(:bulk_chef_run).with(job, [node], %w[foo bar].collect { |x| send(:"service_#{x}_recipe") })

subject.disable(job, host)
end

it "disables the node without running the service command when provided --offline" do
subject.should_not_receive(:on_dynamic_services)
subject.should_not_receive(:bulk_chef_run)
node.should_receive(:save).and_return true
job.should_receive(:report_success).with("#{node.name} disabled.")
subject.disable(job, node_name, offline: true)
end

it "reports failure when unable to disable the node" do
node.should_receive(:save).and_return false
job.should_receive(:report_failure).with("#{node.name} did not save! Disabled run_list entry was unable to be added to the node due to node save failure.")
subject.disable(job, node_name, offline: true)
end
end
end

Expand Down