1384 lines
42 KiB
Ruby
1384 lines
42 KiB
Ruby
# Copyright 2013 Mirantis, Inc.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
|
|
require File.join(File.dirname(__FILE__), '../spec_helper')
|
|
|
|
include Astute
|
|
|
|
describe Astute::NailgunHooks do
|
|
include SpecHelpers
|
|
|
|
let(:ctx) { mock_ctx }
|
|
|
|
around(:each) do |example|
|
|
max_nodes_old_value = Astute.config.max_nodes_per_call
|
|
mc_retries_old_value = Astute.config.mc_retries
|
|
example.run
|
|
Astute.config.max_nodes_per_call = max_nodes_old_value
|
|
Astute.config.mc_retries = mc_retries_old_value
|
|
end
|
|
|
|
let(:upload_file_hook) do
|
|
{
|
|
"priority" => 100,
|
|
"type" => "upload_file",
|
|
"fail_on_error" => false,
|
|
"diagnostic_name" => "upload-example-1.0",
|
|
"uids" => ['2', '3'],
|
|
"parameters" => {
|
|
"path" => "/etc/yum.repos.d/fuel_awesome_plugin-0.1.0.repo",
|
|
"data" => "[fuel_awesome_plugin-0.1.0]\\nname=Plugin fuel_awesome_plugin-0.1.0 repository\\nbaseurl=http => //10.20.0.2 => 8080/plugins/fuel_awesome_plugin-0.1.0/repositories/centos\\ngpgcheck=0"
|
|
}
|
|
}
|
|
end
|
|
|
|
let(:sync_hook) do
|
|
{
|
|
"priority" => 200,
|
|
"type" => "sync",
|
|
"fail_on_error" => false,
|
|
"diagnostic_name" => "sync-example-1.0",
|
|
"uids" => ['1', '2'],
|
|
"parameters" => {
|
|
"src" => "rsync://10.20.0.2/plugins/fuel_awesome_plugin-0.1.0/deployment_scripts/",
|
|
"dst" => "/etc/fuel/plugins/fuel_awesome_plugin-0.1.0/"
|
|
}
|
|
}
|
|
end
|
|
|
|
let(:shell_hook) do
|
|
{
|
|
"priority" => 100,
|
|
"type" => "shell",
|
|
"fail_on_error" => false,
|
|
"id" => "shell-example-1.0",
|
|
"uids" => ['1','2','3'],
|
|
"parameters" => {
|
|
"cmd" => "./deploy.sh",
|
|
"cwd" => "/etc/fuel/plugins/fuel_awesome_plugin-0.1.0/",
|
|
"timeout" => 60
|
|
}
|
|
}
|
|
end
|
|
|
|
let(:puppet_hook) do
|
|
{
|
|
"priority" => 300,
|
|
"type" => "puppet",
|
|
"fail_on_error" => false,
|
|
"diagnostic_name" => "puppet-example-1.0",
|
|
"uids" => ['1', '3'],
|
|
"parameters" => {
|
|
"puppet_manifest" => "cinder_glusterfs.pp",
|
|
"puppet_modules" => "modules",
|
|
"cwd" => "/etc/fuel/plugins/plugin_name-1.0",
|
|
"timeout" => 42,
|
|
"retries" => 21
|
|
}
|
|
}
|
|
end
|
|
|
|
let(:reboot_hook) do
|
|
{
|
|
"priority" => 600,
|
|
"type" => "reboot",
|
|
"fail_on_error" => false,
|
|
"diagnostic_name" => "reboot-example-1.0",
|
|
"uids" => ['2', '3'],
|
|
"parameters" => {
|
|
"timeout" => 42
|
|
}
|
|
}
|
|
end
|
|
|
|
let(:copy_files_hook) do
|
|
{
|
|
"priority" => 100,
|
|
"type" => "copy_files",
|
|
"fail_on_error" => false,
|
|
"diagnostic_name" => "copy-example-1.0",
|
|
"uids" => ['2', '3'],
|
|
"parameters" => {
|
|
"files" => [{
|
|
"src" => "/etc/fuel/nova.key",
|
|
"dst" => "/etc/astute/nova.key"}],
|
|
"permissions" => "0600",
|
|
"dir_permissions" => "0700"
|
|
}
|
|
}
|
|
end
|
|
|
|
let(:upload_files_hook) do
|
|
{
|
|
"priority" => 100,
|
|
"type" => "upload_files",
|
|
"fail_on_error" => false,
|
|
"diagnostic_name" => "copy-example-1.0",
|
|
"uids" => ['1'],
|
|
"parameters" => {
|
|
"nodes" =>[
|
|
"uid" => '1',
|
|
"files" => [{
|
|
"dst" => "/etc/fuel/nova.key",
|
|
"data" => "",
|
|
"permissions" => "0600",
|
|
"dir_permissions" => "0700"}],
|
|
]
|
|
}
|
|
}
|
|
end
|
|
|
|
let (:cobbler_sync_hook) do
|
|
{
|
|
"priority" => 800,
|
|
"type" => "cobbler_sync",
|
|
"fail_on_error" => false,
|
|
"diagnostic_name" => "copy-example-1.0",
|
|
"uids" => ['master'],
|
|
"parameters" => {
|
|
"provisioning_info" => {
|
|
"engine" => {
|
|
"url" => "http://10.20.0.2:80/cobbler_api",
|
|
"username" => "cobbler",
|
|
"password" => "cobblerpassword",
|
|
"master_ip" => "10.20.0.2"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
end
|
|
|
|
let(:hooks_data) do
|
|
[
|
|
upload_file_hook,
|
|
sync_hook,
|
|
shell_hook,
|
|
puppet_hook,
|
|
copy_files_hook,
|
|
upload_files_hook,
|
|
reboot_hook
|
|
]
|
|
end
|
|
|
|
context '#new' do
|
|
it 'should use default run type if no type setting' do
|
|
hooks = Astute::NailgunHooks.new(hooks_data, ctx)
|
|
expect(hooks.instance_variable_get("@type")).to eql('deploy')
|
|
end
|
|
|
|
it 'should use type if it set' do
|
|
hooks = Astute::NailgunHooks.new(hooks_data, ctx, 'execute_tasks')
|
|
expect(hooks.instance_variable_get("@type")).to eql('execute_tasks')
|
|
end
|
|
end
|
|
|
|
context "#process" do
|
|
it 'should process known hook type' do
|
|
hooks = Astute::NailgunHooks.new(hooks_data, ctx)
|
|
|
|
hooks.expects(:upload_file_hook).returns({'error' => nil})
|
|
hooks.expects(:puppet_hook).returns({'error' => nil})
|
|
hooks.expects(:shell_hook).returns({'error' => nil})
|
|
hooks.expects(:sync_hook).returns({'error' => nil})
|
|
hooks.expects(:reboot_hook).returns({'error' => nil})
|
|
hooks.expects(:copy_files_hook).returns({'error' => nil})
|
|
hooks.expects(:upload_files_hook).returns({'error' => nil})
|
|
|
|
hooks.process
|
|
end
|
|
|
|
it 'should raise exception if hook type is unknown' do
|
|
wrong_hook = [{
|
|
"priority" => 300,
|
|
"type" => "unknown",
|
|
"uids" => ['1', '3'],
|
|
"parameters" => {
|
|
"parameter" => "1"
|
|
}
|
|
}]
|
|
hooks = Astute::NailgunHooks.new(wrong_hook, ctx)
|
|
|
|
expect {hooks.process}.to raise_error(StandardError, /Unknown hook type/)
|
|
end
|
|
|
|
it 'should run hooks by priority order' do
|
|
File.stubs(:file?).returns(true)
|
|
File.stubs(:readable?).returns(true)
|
|
File.stubs(:read).returns('')
|
|
hooks = Astute::NailgunHooks.new(hooks_data, ctx)
|
|
|
|
hook_order = sequence('hook_order')
|
|
hooks.expects(:upload_file_hook).returns({'error' => nil}).in_sequence(hook_order)
|
|
hooks.expects(:copy_files_hook).returns({'error' => nil}).in_sequence(hook_order)
|
|
hooks.expects(:upload_files_hook).returns({'error' => nil}).in_sequence(hook_order)
|
|
hooks.expects(:shell_hook).returns({'error' => nil}).in_sequence(hook_order)
|
|
hooks.expects(:sync_hook).returns({'error' => nil}).in_sequence(hook_order)
|
|
hooks.expects(:puppet_hook).returns({'error' => nil}).in_sequence(hook_order)
|
|
hooks.expects(:reboot_hook).returns({'error' => nil}).in_sequence(hook_order)
|
|
|
|
hooks.process
|
|
end
|
|
|
|
context 'critical hook' do
|
|
|
|
before(:each) do
|
|
hooks_data[2]['fail_on_error'] = true
|
|
ctx.stubs(:report_and_update_status)
|
|
end
|
|
|
|
it 'should raise exception if critical hook failed' do
|
|
hooks = Astute::NailgunHooks.new(hooks_data, ctx)
|
|
hooks.expects(:copy_files_hook).returns({'error' => nil})
|
|
hooks.expects(:upload_file_hook).returns({'error' => nil})
|
|
hooks.expects(:upload_files_hook).returns({'error' => nil})
|
|
hooks.expects(:shell_hook).returns({'error' => 'Shell error'})
|
|
|
|
expect {hooks.process}.to raise_error(Astute::DeploymentEngineError, /Failed to execute hook 'shell-example-1.0'/)
|
|
end
|
|
|
|
it 'should not process next hooks if critical hook failed' do
|
|
hooks = Astute::NailgunHooks.new(hooks_data, ctx)
|
|
hooks.expects(:upload_file_hook).returns({'error' => nil})
|
|
hooks.expects(:upload_files_hook).returns({'error' => nil})
|
|
hooks.expects(:shell_hook).returns({'error' => 'Shell error'})
|
|
hooks.expects(:sync_hook).never
|
|
hooks.expects(:puppet_hook).never
|
|
hooks.expects(:reboot_hook).never
|
|
|
|
hooks.process rescue nil
|
|
end
|
|
|
|
it 'should process next hooks if non critical hook failed' do
|
|
hooks = Astute::NailgunHooks.new(hooks_data, ctx)
|
|
hooks.expects(:upload_files_hook).returns({'error' => nil})
|
|
hooks.expects(:upload_file_hook).returns({'error' => 'Upload error'})
|
|
hooks.expects(:shell_hook).returns({'error' => nil})
|
|
hooks.expects(:sync_hook).returns({'error' => 'Sync error'})
|
|
hooks.expects(:puppet_hook).returns({'error' => nil})
|
|
hooks.expects(:reboot_hook).returns({'error' => nil})
|
|
|
|
hooks.process
|
|
end
|
|
|
|
it 'should report error node status if critical hook failed' do
|
|
hooks = Astute::NailgunHooks.new(hooks_data, ctx)
|
|
hooks.expects(:upload_files_hook).returns({'error' => nil})
|
|
hooks.expects(:upload_file_hook).returns({'error' => nil})
|
|
hooks.expects(:shell_hook).returns({'error' => 'Shell error'})
|
|
error_msg = 'Shell error'
|
|
|
|
ctx.expects(:report_and_update_status).with(
|
|
{'nodes' =>
|
|
[
|
|
{ 'uid' => '1',
|
|
'status' => 'error',
|
|
'error_type' => 'deploy',
|
|
'role' => 'hook',
|
|
'hook' => "shell-example-1.0",
|
|
'error_msg' => error_msg
|
|
},
|
|
{ 'uid' => '2',
|
|
'status' => 'error',
|
|
'error_type' => 'deploy',
|
|
'role' => 'hook',
|
|
'hook' => "shell-example-1.0",
|
|
'error_msg' => error_msg
|
|
},
|
|
{ 'uid' => '3',
|
|
'status' => 'error',
|
|
'error_type' => 'deploy',
|
|
'role' => 'hook',
|
|
'hook' => "shell-example-1.0",
|
|
'error_msg' => error_msg
|
|
},
|
|
],
|
|
'error' => "Failed to execute hook 'shell-example-1.0'\n\n#{error_msg}"
|
|
}
|
|
)
|
|
|
|
hooks.process rescue nil
|
|
end
|
|
|
|
it 'should not send report if non critical hook failed' do
|
|
hooks = Astute::NailgunHooks.new(hooks_data, ctx)
|
|
hooks.expects(:upload_files_hook).returns({'error' => nil})
|
|
hooks.expects(:upload_file_hook).returns({'error' => 'Upload error'})
|
|
hooks.expects(:shell_hook).returns({'error' => nil})
|
|
hooks.expects(:sync_hook).returns({'error' => 'Sync error'})
|
|
hooks.expects(:puppet_hook).returns({'error' => nil})
|
|
hooks.expects(:reboot_hook).returns({'error' => nil})
|
|
|
|
ctx.expects(:report_and_update_status).never
|
|
|
|
hooks.process
|
|
end
|
|
|
|
end #hook
|
|
|
|
end #process
|
|
|
|
context '#upload_files_hook' do
|
|
it 'should validate presence of nodes' do
|
|
upload_files_hook['parameters']['nodes'] = []
|
|
hooks = Astute::NailgunHooks.new([upload_files_hook], ctx)
|
|
|
|
expect {hooks.process}.to raise_error(StandardError, /Missing a required parameter/)
|
|
end
|
|
|
|
|
|
it 'should uploads files' do
|
|
hooks = Astute::NailgunHooks.new([upload_files_hook], ctx)
|
|
|
|
hooks.expects(:upload_file).once.with(
|
|
ctx,
|
|
'1',
|
|
has_entries(
|
|
'content' => upload_files_hook['parameters']['nodes'][0]['files'][0]['data'],
|
|
'path' => upload_files_hook['parameters']['nodes'][0]['files'][0]['dst']
|
|
)
|
|
)
|
|
|
|
hooks.process
|
|
end
|
|
|
|
context 'process data from mcagent in case of critical hook' do
|
|
before(:each) do
|
|
upload_files_hook['fail_on_error'] = true
|
|
ctx.stubs(:report_and_update_status)
|
|
end
|
|
|
|
it 'mcagent success' do
|
|
hooks = Astute::NailgunHooks.new([upload_files_hook], ctx)
|
|
hooks.expects(:upload_file).returns(true).once
|
|
|
|
expect {hooks.process}.to_not raise_error
|
|
end
|
|
|
|
it 'mcagent fail' do
|
|
hooks = Astute::NailgunHooks.new([upload_files_hook], ctx)
|
|
hooks.expects(:upload_file).returns(false).once
|
|
|
|
expect {hooks.process}.to raise_error(Astute::DeploymentEngineError, /Failed to execute hook/)
|
|
end
|
|
end #context
|
|
|
|
end #upload_files_hook
|
|
|
|
context '#copy_files_hook' do
|
|
|
|
it 'should validate presence of node uids' do
|
|
copy_files_hook['uids'] = []
|
|
hooks = Astute::NailgunHooks.new([copy_files_hook], ctx)
|
|
|
|
expect {hooks.process}.to raise_error(StandardError, /Missing a required parameter/)
|
|
end
|
|
|
|
it 'should validate presence files' do
|
|
copy_files_hook['parameters'].delete('files')
|
|
hooks = Astute::NailgunHooks.new([copy_files_hook], ctx)
|
|
|
|
expect {hooks.process}.to raise_error(StandardError, /Missing a required parameter/)
|
|
end
|
|
|
|
it 'should upload file' do
|
|
File.stubs(:file?).returns(true)
|
|
File.stubs(:readable?).returns(true)
|
|
File.stubs(:binread).returns("")
|
|
hooks = Astute::NailgunHooks.new([copy_files_hook], ctx)
|
|
|
|
hooks.expects(:upload_file).once.with(
|
|
ctx,
|
|
['2', '3'],
|
|
has_entries(
|
|
'content' => "",
|
|
'path' => copy_files_hook['parameters']['files'][0]['dst']
|
|
)
|
|
)
|
|
|
|
hooks.process
|
|
end
|
|
|
|
it 'should limit nodes processing in parallel' do
|
|
Astute.config.max_nodes_per_call = 1
|
|
File.stubs(:file?).returns(true)
|
|
File.stubs(:readable?).returns(true)
|
|
File.stubs(:binread).returns("")
|
|
hooks = Astute::NailgunHooks.new([copy_files_hook], ctx)
|
|
|
|
hooks.expects(:upload_file).once.with(
|
|
ctx,
|
|
['2'],
|
|
has_entries(
|
|
'content' => "",
|
|
'path' => copy_files_hook['parameters']['files'][0]['dst']
|
|
)
|
|
)
|
|
hooks.expects(:upload_file).once.with(
|
|
ctx,
|
|
['3'],
|
|
has_entries(
|
|
'content' => "",
|
|
'path' => copy_files_hook['parameters']['files'][0]['dst']
|
|
)
|
|
)
|
|
hooks.process
|
|
end
|
|
|
|
context 'process data from mcagent in case of critical hook' do
|
|
before(:each) do
|
|
copy_files_hook['fail_on_error'] = true
|
|
#ctx.stubs(:report_and_update_status)
|
|
end
|
|
|
|
it 'mcagent success' do
|
|
File.stubs(:file?).returns(true)
|
|
File.stubs(:readable?).returns(true)
|
|
File.stubs(:binread).returns("")
|
|
hooks = Astute::NailgunHooks.new([copy_files_hook], ctx)
|
|
hooks.expects(:upload_file).returns(true).once
|
|
|
|
expect {hooks.process}.to_not raise_error
|
|
end
|
|
|
|
it 'mcagent fail' do
|
|
File.stubs(:file?).returns(true)
|
|
File.stubs(:readable?).returns(true)
|
|
File.stubs(:binread).returns("")
|
|
|
|
hooks = Astute::NailgunHooks.new([copy_files_hook], ctx)
|
|
hooks.expects(:upload_file).returns(false).once
|
|
error_msg = 'Upload not successful'
|
|
ctx.expects(:report_and_update_status).once.with(
|
|
{'nodes' =>
|
|
[
|
|
{ 'uid' => '2',
|
|
'status' => 'error',
|
|
'error_type' => 'deploy',
|
|
'role' => 'hook',
|
|
'hook' => "copy-example-1.0",
|
|
'error_msg' => error_msg
|
|
},
|
|
{ 'uid' => '3',
|
|
'status' => 'error',
|
|
'error_type' => 'deploy',
|
|
'role' => 'hook',
|
|
'hook' => "copy-example-1.0",
|
|
'error_msg' => error_msg
|
|
},
|
|
],
|
|
'error' => "Failed to execute hook 'copy-example-1.0'\n\n#{error_msg}"
|
|
}
|
|
)
|
|
|
|
expect {hooks.process}.to raise_error(Astute::DeploymentEngineError, /Failed to execute hook/)
|
|
|
|
end
|
|
end #context
|
|
end#copy_files_hook
|
|
|
|
context '#shell_hook' do
|
|
|
|
it 'should validate presence of node uids' do
|
|
shell_hook['uids'] = []
|
|
hooks = Astute::NailgunHooks.new([shell_hook], ctx)
|
|
|
|
expect {hooks.process}.to raise_error(StandardError, /Missing a required parameter/)
|
|
end
|
|
|
|
it 'should validate presence cmd hooks' do
|
|
shell_hook['parameters'].delete('cmd')
|
|
hooks = Astute::NailgunHooks.new([shell_hook], ctx)
|
|
|
|
expect {hooks.process}.to raise_error(StandardError, /Missing a required parameter/)
|
|
end
|
|
|
|
it 'should run shell command with timeout' do
|
|
hooks = Astute::NailgunHooks.new([shell_hook], ctx)
|
|
hooks.expects(:run_shell_command).once.with(
|
|
ctx,
|
|
['1','2','3'],
|
|
regexp_matches(/deploy/),
|
|
Astute.config.mc_retries,
|
|
Astute.config.mc_retry_interval,
|
|
shell_hook['parameters']['timeout'],
|
|
shell_hook['parameters']['cwd']
|
|
)
|
|
.returns(:data => {:exit_code => 0})
|
|
|
|
hooks.process
|
|
end
|
|
|
|
it 'should run shell command with global timeout (including retries)' do
|
|
hooks = Astute::NailgunHooks.new([shell_hook], ctx)
|
|
hooks.stubs(:run_shell_command).once.with(
|
|
ctx,
|
|
['1','2','3'],
|
|
regexp_matches(/deploy/),
|
|
Astute.config.mc_retries,
|
|
Astute.config.mc_retry_interval,
|
|
shell_hook['parameters']['timeout'],
|
|
shell_hook['parameters']['cwd']
|
|
)
|
|
.raises(Timeout::Error)
|
|
|
|
expect {hooks.process}.to_not raise_error
|
|
end
|
|
|
|
it 'should use default timeout if it does not set' do
|
|
shell_hook['parameters'].delete('timeout')
|
|
hooks = Astute::NailgunHooks.new([shell_hook], ctx)
|
|
hooks.expects(:run_shell_command).once.with(
|
|
ctx,
|
|
['1','2','3'],
|
|
regexp_matches(/deploy/),
|
|
Astute.config.mc_retries,
|
|
Astute.config.mc_retry_interval,
|
|
300,
|
|
shell_hook['parameters']['cwd']
|
|
)
|
|
.returns(:data => {:exit_code => 0})
|
|
|
|
hooks.process
|
|
end
|
|
|
|
it 'should limit nodes processing in parallel' do
|
|
Astute.config.max_nodes_per_call = 2
|
|
|
|
hooks = Astute::NailgunHooks.new([shell_hook], ctx)
|
|
hooks.expects(:run_shell_command).once.with(
|
|
ctx,
|
|
['1', '2'],
|
|
regexp_matches(/deploy/),
|
|
Astute.config.mc_retries,
|
|
Astute.config.mc_retry_interval,
|
|
shell_hook['parameters']['timeout'],
|
|
shell_hook['parameters']['cwd']
|
|
)
|
|
.returns(:data => {:exit_code => 0})
|
|
|
|
hooks.expects(:run_shell_command).once.with(
|
|
ctx,
|
|
['3'],
|
|
regexp_matches(/deploy/),
|
|
Astute.config.mc_retries,
|
|
Astute.config.mc_retry_interval,
|
|
shell_hook['parameters']['timeout'],
|
|
shell_hook['parameters']['cwd']
|
|
)
|
|
.returns(:data => {:exit_code => 0})
|
|
|
|
hooks.process
|
|
end
|
|
|
|
context 'process data from mcagent in case of critical hook' do
|
|
before(:each) do
|
|
shell_hook['fail_on_error'] = true
|
|
ctx.stubs(:report_and_update_status)
|
|
end
|
|
|
|
it 'if exit code eql 0 -> do not raise error' do
|
|
hooks = Astute::NailgunHooks.new([shell_hook], ctx)
|
|
hooks.expects(:run_shell_command).returns(nil).once
|
|
|
|
expect {hooks.process}.to_not raise_error
|
|
end
|
|
|
|
it 'if exit code not eql 0 -> raise error' do
|
|
hooks = Astute::NailgunHooks.new([shell_hook], ctx)
|
|
hooks.expects(:run_shell_command).returns("err").once
|
|
|
|
expect {hooks.process}.to raise_error(Astute::DeploymentEngineError, /Failed to execute hook/)
|
|
end
|
|
|
|
it 'if exit code not presence -> raise error' do
|
|
hooks = Astute::NailgunHooks.new([shell_hook], ctx)
|
|
hooks.expects(:run_shell_command).returns("err").once
|
|
|
|
expect {hooks.process}.to raise_error(Astute::DeploymentEngineError, /Failed to execute hook/)
|
|
end
|
|
|
|
it 'if timeout -> raise error' do
|
|
hooks = Astute::NailgunHooks.new([shell_hook], ctx)
|
|
hooks.expects(:run_shell_command).raises(Timeout::Error)
|
|
|
|
expect {hooks.process}.to raise_error(Astute::DeploymentEngineError, /Failed to execute hook/)
|
|
end
|
|
end #context
|
|
|
|
context "#run_shell_command" do
|
|
|
|
let(:hooks) { Astute::NailgunHooks.new([shell_hook], ctx) }
|
|
|
|
let(:mclient) do
|
|
mclient = mock_rpcclient
|
|
Astute::MClient.any_instance.stubs(:rpcclient).returns(mclient)
|
|
Astute::MClient.any_instance.stubs(:log_result).returns(mclient)
|
|
Astute::MClient.any_instance.stubs(:check_results_with_retries).returns(mclient)
|
|
mclient
|
|
end
|
|
|
|
def mc_result(sender, succeed=true)
|
|
{
|
|
:sender => sender,
|
|
:data => { :exit_code => succeed ? 0 : 1}
|
|
}
|
|
end
|
|
|
|
before(:each) do
|
|
ctx.stubs(:report_and_update_status)
|
|
shell_hook['fail_on_error'] = true
|
|
end
|
|
|
|
it 'should use retries' do
|
|
mclient.expects(:execute).times(2).returns([
|
|
mc_result('1', true),
|
|
mc_result('2', false),
|
|
mc_result('3', true)
|
|
]).then.returns([mc_result('2', true)])
|
|
|
|
hooks.process
|
|
end
|
|
|
|
it 'should fail if retries end' do
|
|
Astute.config.mc_retries = 1
|
|
|
|
mclient.expects(:execute).times(2).returns([
|
|
mc_result('1', true),
|
|
mc_result('2', false),
|
|
mc_result('3', true)
|
|
]).then.returns([mc_result('2', false)])
|
|
|
|
expect {hooks.process}.to raise_error(Astute::DeploymentEngineError)
|
|
end
|
|
|
|
it 'should fail if retries end and some nodes never answered' do
|
|
Astute.config.mc_retries = 1
|
|
|
|
mclient.expects(:execute).times(2)
|
|
.returns([mc_result('1', true)])
|
|
.then.returns([mc_result('2', true)])
|
|
|
|
expect {hooks.process}.to raise_error(Astute::DeploymentEngineError)
|
|
end
|
|
|
|
it 'should retry if raise error' do
|
|
Astute.config.mc_retries = 3
|
|
|
|
mclient.expects(:execute).times(4)
|
|
.returns([mc_result('1', true), mc_result('2', true)])
|
|
.then.raises(Astute::MClientTimeout)
|
|
.then.raises(Astute::MClientError)
|
|
.then.returns([mc_result('3', true)])
|
|
|
|
expect {
|
|
hooks.process
|
|
}.not_to raise_error
|
|
end
|
|
|
|
it 'should fail if it still raise error after retries' do
|
|
Astute.config.mc_retries = 1
|
|
|
|
# we retry 3 times on every mc retries (1 main + 1 retries) * 3 = 6
|
|
mclient.expects(:execute).times(6)
|
|
.then.raises(Astute::MClientTimeout)
|
|
.then.raises(Astute::MClientError)
|
|
|
|
expect {hooks.process}.to raise_error(Astute::DeploymentEngineError)
|
|
end
|
|
end
|
|
|
|
end #shell_hook
|
|
|
|
context '#upload_file_hook' do
|
|
it 'should validate presence of node uids' do
|
|
upload_file_hook['uids'] = []
|
|
hooks = Astute::NailgunHooks.new([upload_file_hook], ctx)
|
|
|
|
expect {hooks.process}.to raise_error(StandardError, /Missing a required parameter/)
|
|
end
|
|
|
|
it 'should validate presence of file destination' do
|
|
upload_file_hook['parameters'].delete('path')
|
|
hooks = Astute::NailgunHooks.new([upload_file_hook], ctx)
|
|
|
|
expect {hooks.process}.to raise_error(StandardError, /Missing a required parameter/)
|
|
end
|
|
|
|
it 'should validate presence of file source' do
|
|
upload_file_hook['parameters'].delete('data')
|
|
hooks = Astute::NailgunHooks.new([upload_file_hook], ctx)
|
|
|
|
expect {hooks.process}.to raise_error(StandardError, /Missing a required parameter/)
|
|
end
|
|
|
|
it 'should upload file' do
|
|
hooks = Astute::NailgunHooks.new([upload_file_hook], ctx)
|
|
|
|
hooks.expects(:upload_file).once.with(
|
|
ctx,
|
|
['2', '3'],
|
|
has_entries(
|
|
'content' => upload_file_hook['parameters']['data'],
|
|
'path' => upload_file_hook['parameters']['path']
|
|
)
|
|
)
|
|
|
|
hooks.process
|
|
end
|
|
|
|
it 'should limit nodes processing in parallel' do
|
|
Astute.config.max_nodes_per_call = 1
|
|
hooks = Astute::NailgunHooks.new([upload_file_hook], ctx)
|
|
|
|
hooks.expects(:upload_file).once.with(
|
|
ctx,
|
|
['2'],
|
|
has_entries(
|
|
'content' => upload_file_hook['parameters']['data'],
|
|
'path' => upload_file_hook['parameters']['path']
|
|
)
|
|
)
|
|
|
|
hooks.expects(:upload_file).once.with(
|
|
ctx,
|
|
['3'],
|
|
has_entries(
|
|
'content' => upload_file_hook['parameters']['data'],
|
|
'path' => upload_file_hook['parameters']['path']
|
|
)
|
|
)
|
|
|
|
hooks.process
|
|
end
|
|
|
|
context 'process data from mcagent in case of critical hook' do
|
|
before(:each) do
|
|
upload_file_hook['fail_on_error'] = true
|
|
ctx.stubs(:report_and_update_status)
|
|
end
|
|
|
|
it 'mcagent success' do
|
|
hooks = Astute::NailgunHooks.new([upload_file_hook], ctx)
|
|
hooks.expects(:upload_file).returns(true).once
|
|
|
|
expect {hooks.process}.to_not raise_error
|
|
end
|
|
|
|
it 'mcagent fail' do
|
|
hooks = Astute::NailgunHooks.new([upload_file_hook], ctx)
|
|
hooks.expects(:upload_file).returns(false).once
|
|
|
|
expect {hooks.process}.to raise_error(Astute::DeploymentEngineError, /Failed to execute hook/)
|
|
end
|
|
end #context
|
|
|
|
end #upload_file_hook
|
|
|
|
context '#sync_hook' do
|
|
it 'should validate presence of node uids' do
|
|
sync_hook['uids'] = []
|
|
hooks = Astute::NailgunHooks.new([sync_hook], ctx)
|
|
|
|
expect {hooks.process}.to raise_error(StandardError, /Missing a required parameter/)
|
|
end
|
|
|
|
it 'should validate presence of destination' do
|
|
sync_hook['parameters'].delete('dst')
|
|
hooks = Astute::NailgunHooks.new([sync_hook], ctx)
|
|
|
|
expect {hooks.process}.to raise_error(StandardError, /Missing a required parameter/)
|
|
end
|
|
|
|
it 'should validate presence of source' do
|
|
sync_hook['parameters'].delete('src')
|
|
hooks = Astute::NailgunHooks.new([sync_hook], ctx)
|
|
|
|
expect {hooks.process}.to raise_error(StandardError, /Missing a required parameter/)
|
|
end
|
|
|
|
it 'should run sync command with timeout' do
|
|
sync_hook['parameters']['timeout'] = '60'
|
|
hooks = Astute::NailgunHooks.new([sync_hook], ctx)
|
|
hooks.expects(:run_shell_command).once.with(
|
|
ctx,
|
|
['1','2'],
|
|
regexp_matches(/deploy/),
|
|
10,
|
|
Astute.config.mc_retry_interval,
|
|
sync_hook['parameters']['timeout']
|
|
)
|
|
.returns(:data => {:exit_code => 0})
|
|
|
|
hooks.process
|
|
end
|
|
|
|
it 'should use default timeout if it does not set' do
|
|
shell_hook['parameters'].delete('timeout')
|
|
hooks = Astute::NailgunHooks.new([sync_hook], ctx)
|
|
hooks.expects(:run_shell_command).once.with(
|
|
ctx,
|
|
['1','2'],
|
|
regexp_matches(/rsync/),
|
|
10,
|
|
Astute.config.mc_retry_interval,
|
|
300
|
|
)
|
|
.returns(:data => {:exit_code => 0})
|
|
|
|
hooks.process
|
|
end
|
|
|
|
it 'should limit nodes processing in parallel' do
|
|
Astute.config.max_nodes_per_call = 1
|
|
|
|
hooks = Astute::NailgunHooks.new([sync_hook], ctx)
|
|
hooks.expects(:run_shell_command).once.with(
|
|
ctx,
|
|
['1'],
|
|
regexp_matches(/rsync/),
|
|
10,
|
|
Astute.config.mc_retry_interval,
|
|
is_a(Integer)
|
|
)
|
|
.returns(:data => {:exit_code => 0})
|
|
|
|
hooks.expects(:run_shell_command).once.with(
|
|
ctx,
|
|
['2'],
|
|
regexp_matches(/rsync/),
|
|
10,
|
|
Astute.config.mc_retry_interval,
|
|
is_a(Integer)
|
|
)
|
|
.returns(:data => {:exit_code => 0})
|
|
|
|
hooks.process
|
|
end
|
|
|
|
context 'process data from mcagent in case of critical hook' do
|
|
before(:each) do
|
|
sync_hook['fail_on_error'] = true
|
|
ctx.stubs(:report_and_update_status)
|
|
end
|
|
|
|
it 'if exit code eql 0 -> do not raise error' do
|
|
hooks = Astute::NailgunHooks.new([sync_hook], ctx)
|
|
hooks.expects(:run_shell_command).returns(nil).once
|
|
|
|
expect {hooks.process}.to_not raise_error
|
|
end
|
|
|
|
it 'if exit code not eql 0 -> raise error' do
|
|
hooks = Astute::NailgunHooks.new([sync_hook], ctx)
|
|
hooks.expects(:run_shell_command).returns("err").once
|
|
|
|
expect {hooks.process}.to raise_error(Astute::DeploymentEngineError, /Failed to execute hook/)
|
|
end
|
|
|
|
it 'if exit code not presence -> raise error' do
|
|
hooks = Astute::NailgunHooks.new([sync_hook], ctx)
|
|
hooks.expects(:run_shell_command).returns("err").once
|
|
|
|
expect {hooks.process}.to raise_error(Astute::DeploymentEngineError, /Failed to execute hook/)
|
|
end
|
|
end #context
|
|
|
|
end #sync_hook
|
|
|
|
context '#puppet_hook' do
|
|
it 'should validate presence of node uids' do
|
|
puppet_hook['uids'] = []
|
|
hooks = Astute::NailgunHooks.new([puppet_hook], ctx)
|
|
|
|
expect {hooks.process}.to raise_error(StandardError, /Missing a required parameter/)
|
|
end
|
|
|
|
it 'should validate presence of manifest parameter' do
|
|
puppet_hook['parameters'].delete('puppet_manifest')
|
|
hooks = Astute::NailgunHooks.new([puppet_hook], ctx)
|
|
|
|
expect {hooks.process}.to raise_error(StandardError, /Missing a required parameter/)
|
|
end
|
|
|
|
it 'should validate presence of modules parameter' do
|
|
puppet_hook['parameters'].delete('puppet_modules')
|
|
hooks = Astute::NailgunHooks.new([puppet_hook], ctx)
|
|
|
|
expect {hooks.process}.to raise_error(StandardError, /Missing a required parameter/)
|
|
end
|
|
|
|
it 'should validate presence of cwd parameter' do
|
|
puppet_hook['parameters'].delete('cwd')
|
|
hooks = Astute::NailgunHooks.new([puppet_hook], ctx)
|
|
|
|
expect {hooks.process}.to raise_error(StandardError, /Missing a required parameter/)
|
|
end
|
|
|
|
it 'should run puppet command using main mechanism' do
|
|
hooks = Astute::NailgunHooks.new([puppet_hook], ctx)
|
|
PuppetdDeployer.expects(:deploy).once.with(
|
|
instance_of(Astute::Context),
|
|
[
|
|
{'uid' => '1', 'role' => 'hook'},
|
|
{'uid' => '3', 'role' => 'hook'}
|
|
],
|
|
_retries=puppet_hook['parameters']['retries'],
|
|
puppet_hook['parameters']['puppet_manifest'],
|
|
puppet_hook['parameters']['puppet_modules'],
|
|
puppet_hook['parameters']['cwd']
|
|
)
|
|
|
|
Astute::Context.any_instance.stubs(:status).returns({'1' => 'success', '3' => 'success'})
|
|
hooks.process
|
|
end
|
|
|
|
it 'should run puppet command with timeout' do
|
|
hooks = Astute::NailgunHooks.new([puppet_hook], ctx)
|
|
hooks.expects(:run_puppet).once.with(
|
|
ctx,
|
|
['1','3'],
|
|
puppet_hook['parameters']['puppet_manifest'],
|
|
puppet_hook['parameters']['puppet_modules'],
|
|
puppet_hook['parameters']['cwd'],
|
|
puppet_hook['parameters']['timeout'],
|
|
puppet_hook['parameters']['retries']
|
|
).returns(true)
|
|
Astute::Context.any_instance.stubs(:status).returns({'1' => 'success', '3' => 'success'})
|
|
|
|
hooks.process
|
|
end
|
|
|
|
it 'should use default timeout if it does not set' do
|
|
puppet_hook['parameters'].delete('timeout')
|
|
hooks = Astute::NailgunHooks.new([puppet_hook], ctx)
|
|
hooks.expects(:run_puppet).once.with(
|
|
ctx,
|
|
['1','3'],
|
|
puppet_hook['parameters']['puppet_manifest'],
|
|
puppet_hook['parameters']['puppet_modules'],
|
|
puppet_hook['parameters']['cwd'],
|
|
300,
|
|
puppet_hook['parameters']['retries']
|
|
).returns(true)
|
|
Astute::Context.any_instance.stubs(:status).returns({'1' => 'success', '3' => 'success'})
|
|
|
|
hooks.process
|
|
end
|
|
|
|
it 'should use default retries if it does not set' do
|
|
puppet_hook['parameters'].delete('retries')
|
|
hooks = Astute::NailgunHooks.new([puppet_hook], ctx)
|
|
hooks.expects(:run_puppet).once.with(
|
|
ctx,
|
|
['1','3'],
|
|
puppet_hook['parameters']['puppet_manifest'],
|
|
puppet_hook['parameters']['puppet_modules'],
|
|
puppet_hook['parameters']['cwd'],
|
|
puppet_hook['parameters']['timeout'],
|
|
Astute.config.puppet_retries,
|
|
).returns(true)
|
|
Astute::Context.any_instance.stubs(:status).returns({'1' => 'success', '3' => 'success'})
|
|
|
|
hooks.process
|
|
end
|
|
|
|
it 'should limit nodes processing in parallel' do
|
|
Astute.config.max_nodes_per_call = 1
|
|
|
|
hooks = Astute::NailgunHooks.new([puppet_hook], ctx)
|
|
hooks.expects(:run_puppet).once.with(
|
|
ctx,
|
|
['1'],
|
|
puppet_hook['parameters']['puppet_manifest'],
|
|
puppet_hook['parameters']['puppet_modules'],
|
|
puppet_hook['parameters']['cwd'],
|
|
puppet_hook['parameters']['timeout'],
|
|
puppet_hook['parameters']['retries']
|
|
).returns(true)
|
|
|
|
hooks.expects(:run_puppet).once.with(
|
|
ctx,
|
|
['3'],
|
|
puppet_hook['parameters']['puppet_manifest'],
|
|
puppet_hook['parameters']['puppet_modules'],
|
|
puppet_hook['parameters']['cwd'],
|
|
puppet_hook['parameters']['timeout'],
|
|
puppet_hook['parameters']['retries']
|
|
).returns(true)
|
|
|
|
Astute::Context.any_instance.stubs(:status).returns({'1' => 'success', '3' => 'success'})
|
|
hooks.process
|
|
end
|
|
|
|
it 'if mclient failed and task is not critical -> do not raise error' do
|
|
hooks = Astute::NailgunHooks.new([puppet_hook], ctx)
|
|
PuppetdDeployer.expects(:deploy).once.raises(Astute::MClientError)
|
|
|
|
expect {hooks.process}.to_not raise_error
|
|
end
|
|
|
|
context 'process data from mcagent in case of critical hook' do
|
|
before(:each) do
|
|
puppet_hook['fail_on_error'] = true
|
|
ctx.stubs(:report_and_update_status)
|
|
end
|
|
|
|
it 'if puppet success do not raise error' do
|
|
hooks = Astute::NailgunHooks.new([puppet_hook], ctx)
|
|
PuppetdDeployer.expects(:deploy).once
|
|
Astute::Context.any_instance.stubs(:status).returns({'1' => 'success', '3' => 'success'})
|
|
|
|
expect {hooks.process}.to_not raise_error
|
|
end
|
|
|
|
it 'if puppet fail -> raise error' do
|
|
hooks = Astute::NailgunHooks.new([puppet_hook], ctx)
|
|
PuppetdDeployer.expects(:deploy).once
|
|
Astute::Context.any_instance.stubs(:status).returns({'1' => 'error', '3' => 'success'})
|
|
|
|
expect {hooks.process}.to raise_error(Astute::DeploymentEngineError, /Failed to execute hook/)
|
|
end
|
|
|
|
it 'if mclient failed -> raise error' do
|
|
hooks = Astute::NailgunHooks.new([puppet_hook], ctx)
|
|
error_msg = "Puppet run failed. Check puppet logs for details"
|
|
PuppetdDeployer.expects(:deploy).once.raises(Astute::MClientError)
|
|
ctx.expects(:report_and_update_status).with(
|
|
{'nodes' =>
|
|
[
|
|
{ 'uid' => '1',
|
|
'status' => 'error',
|
|
'error_type' => 'deploy',
|
|
'role' => 'hook',
|
|
'hook' => "puppet-example-1.0",
|
|
'error_msg' => error_msg
|
|
},
|
|
{ 'uid' => '3',
|
|
'status' => 'error',
|
|
'error_type' => 'deploy',
|
|
'role' => 'hook',
|
|
'hook' => "puppet-example-1.0",
|
|
'error_msg' => error_msg
|
|
},
|
|
],
|
|
'error' => "Failed to execute hook 'puppet-example-1.0'\n\n#{error_msg}"
|
|
}
|
|
)
|
|
|
|
expect {hooks.process}.to raise_error(Astute::DeploymentEngineError, /Failed to execute hook/)
|
|
end
|
|
end #context
|
|
end # puppet_hook
|
|
|
|
context '#reboot_hook' do
|
|
|
|
it 'should validate presence of node uids' do
|
|
reboot_hook['uids'] = []
|
|
hooks = Astute::NailgunHooks.new([reboot_hook], ctx)
|
|
|
|
expect {hooks.process}.to raise_error(StandardError, /Missing a required parameter/)
|
|
end
|
|
|
|
it 'should run reboot command with timeout - 10 sec' do
|
|
hooks = Astute::NailgunHooks.new([reboot_hook], ctx)
|
|
|
|
time = Time.now.to_i
|
|
hooks.stubs(:run_shell_without_check).twice.with(
|
|
ctx,
|
|
['2','3'],
|
|
regexp_matches(/stat/),
|
|
10,
|
|
)
|
|
.returns('2' => (time - 5).to_s, '3' => (time - 5).to_s).then
|
|
.returns('2' => time.to_s, '3' => time.to_s)
|
|
|
|
hooks.expects(:run_shell_without_check).once.with(
|
|
ctx,
|
|
['2','3'],
|
|
regexp_matches(/reboot/),
|
|
60,
|
|
)
|
|
.returns('2' => '', '3' => '')
|
|
|
|
hooks.expects(:run_shell_without_check).once.with(
|
|
ctx,
|
|
['2','3'],
|
|
regexp_matches(/nailgun-agent/),
|
|
60,
|
|
)
|
|
.returns('2' => '', '3' => '')
|
|
|
|
hooks.stubs(:sleep)
|
|
|
|
hooks.process
|
|
end
|
|
|
|
it 'should run reboot validation command with timeout - 10 sec' do
|
|
hooks = Astute::NailgunHooks.new([reboot_hook], ctx)
|
|
|
|
time = Time.now.to_i
|
|
hooks.stubs(:run_shell_without_check).twice.with(
|
|
ctx,
|
|
['2','3'],
|
|
regexp_matches(/stat/),
|
|
10,
|
|
)
|
|
.returns('2' => (time - 5).to_s, '3' => (time - 5).to_s).then
|
|
.returns('2' => time.to_s, '3' => time.to_s)
|
|
|
|
hooks.stubs(:run_shell_without_check).once.with(
|
|
ctx,
|
|
['2','3'],
|
|
regexp_matches(/reboot/),
|
|
60,
|
|
)
|
|
.returns('2' => '', '3' => '')
|
|
|
|
hooks.stubs(:update_node_status).once
|
|
hooks.stubs(:sleep)
|
|
|
|
hooks.process
|
|
end
|
|
|
|
it 'should sleep between checks for one-tenth of timeout' do
|
|
hooks = Astute::NailgunHooks.new([reboot_hook], ctx)
|
|
|
|
time = Time.now.to_i
|
|
hooks.stubs(:run_shell_without_check).twice.with(
|
|
ctx,
|
|
['2','3'],
|
|
regexp_matches(/stat/),
|
|
10,
|
|
)
|
|
.returns('2' => (time - 5).to_s, '3' => (time - 5).to_s).then
|
|
.returns('2' => time.to_s, '3' => time.to_s)
|
|
|
|
hooks.stubs(:run_shell_without_check).once.with(
|
|
ctx,
|
|
['2','3'],
|
|
regexp_matches(/reboot/),
|
|
60,
|
|
)
|
|
.returns('2' => '', '3' => '')
|
|
|
|
hooks.stubs(:update_node_status).once
|
|
|
|
hooks.expects(:sleep).with(reboot_hook['parameters']['timeout']/10)
|
|
|
|
hooks.process
|
|
end
|
|
|
|
it 'should use default timeout if it does not set' do
|
|
reboot_hook['parameters'].delete('timeout')
|
|
hooks = Astute::NailgunHooks.new([reboot_hook], ctx)
|
|
|
|
time = Time.now.to_i
|
|
hooks.stubs(:run_shell_without_check).twice.with(
|
|
ctx,
|
|
['2','3'],
|
|
regexp_matches(/stat/),
|
|
10,
|
|
)
|
|
.returns('2' => (time - 5).to_s, '3' => (time - 5).to_s).then
|
|
.returns('2' => time.to_s, '3' => time.to_s)
|
|
|
|
hooks.stubs(:run_shell_without_check).once.with(
|
|
ctx,
|
|
['2','3'],
|
|
regexp_matches(/reboot/),
|
|
60,
|
|
)
|
|
.returns('2' => '', '3' => '')
|
|
hooks.stubs(:update_node_status).once
|
|
|
|
hooks.expects(:sleep).with(300/10)
|
|
|
|
hooks.process
|
|
end
|
|
|
|
it 'should limit nodes processing in parallel' do
|
|
Astute.config.max_nodes_per_call = 1
|
|
|
|
hooks = Astute::NailgunHooks.new([reboot_hook], ctx)
|
|
|
|
time = Time.now.to_i
|
|
hooks.stubs(:run_shell_without_check).once.with(
|
|
ctx,
|
|
['2'],
|
|
regexp_matches(/stat/),
|
|
10,
|
|
)
|
|
.returns('2' => time.to_s)
|
|
|
|
hooks.stubs(:run_shell_without_check).once.with(
|
|
ctx,
|
|
['3'],
|
|
regexp_matches(/stat/),
|
|
10,
|
|
)
|
|
.returns('3' => time.to_s)
|
|
|
|
hooks.expects(:run_shell_without_check).once.with(
|
|
ctx,
|
|
['2'],
|
|
regexp_matches(/reboot/),
|
|
60,
|
|
)
|
|
.returns('2' => '')
|
|
|
|
hooks.expects(:run_shell_without_check).once.with(
|
|
ctx,
|
|
['3'],
|
|
regexp_matches(/reboot/),
|
|
60,
|
|
)
|
|
.returns('3' => '')
|
|
|
|
hooks.stubs(:sleep)
|
|
hooks.stubs(:update_node_status).once
|
|
|
|
time = Time.now.to_i + 100
|
|
hooks.stubs(:run_shell_without_check).once.with(
|
|
ctx,
|
|
['2','3'],
|
|
"stat --printf='%Y' /proc/1",
|
|
10,
|
|
)
|
|
.returns('2' => time.to_s, '3' => time.to_s)
|
|
|
|
hooks.process
|
|
end
|
|
|
|
context 'process data from mcagent in case of critical hook' do
|
|
|
|
let(:hooks) do
|
|
reboot_hook['fail_on_error'] = true
|
|
reboot_hook['parameters']['timeout'] = 1
|
|
|
|
hooks = Astute::NailgunHooks.new([reboot_hook], ctx)
|
|
|
|
hooks.stubs(:run_shell_without_check).once.with(
|
|
ctx,
|
|
['2','3'],
|
|
regexp_matches(/reboot/),
|
|
60,
|
|
)
|
|
.returns('2' => '', '3' => '')
|
|
|
|
hooks.stubs(:sleep)
|
|
|
|
hooks
|
|
end
|
|
|
|
before(:each) do
|
|
ctx.stubs(:report_and_update_status)
|
|
end
|
|
|
|
it 'if reboot succeed -> do not raise error' do
|
|
time = Time.now.to_i
|
|
hooks.stubs(:run_shell_without_check).twice.with(
|
|
ctx,
|
|
['2','3'],
|
|
regexp_matches(/stat/),
|
|
10,
|
|
)
|
|
.returns('2' => (time - 5).to_s, '3' => (time - 5).to_s).then
|
|
.returns('2' => time.to_s, '3' => time.to_s)
|
|
hooks.stubs(:update_node_status).once
|
|
expect {hooks.process}.to_not raise_error
|
|
end
|
|
|
|
it 'if reboot failed -> raise error' do
|
|
time = Time.now.to_i
|
|
hooks.stubs(:run_shell_without_check).with(
|
|
ctx,
|
|
['2','3'],
|
|
regexp_matches(/stat/),
|
|
10,
|
|
)
|
|
.returns('2' => time.to_s, '3' => (time - 5).to_s).then
|
|
.returns('2' => time.to_s, '3' => (time - 5).to_s)
|
|
|
|
hooks.stubs(:run_shell_without_check).with(
|
|
ctx,
|
|
['2'],
|
|
regexp_matches(/stat/),
|
|
10,
|
|
)
|
|
.returns('2' => (time - 5).to_s, '3' => time.to_s)
|
|
hooks.expects(:update_node_status).with([])
|
|
|
|
expect {hooks.process}.to raise_error(Astute::DeploymentEngineError, /Failed to execute hook/)
|
|
end
|
|
|
|
it 'should successed if creation time is smaller' do
|
|
time = Time.now.to_i
|
|
hooks.stubs(:run_shell_without_check).twice.with(
|
|
ctx,
|
|
['2','3'],
|
|
regexp_matches(/stat/),
|
|
10,
|
|
)
|
|
.returns('2' => time.to_s, '3' => time.to_s).then
|
|
.returns('2' => (time - 1).to_s, '3' => (time - 2).to_s)
|
|
hooks.expects(:update_node_status).with(['2', '3'])
|
|
expect {hooks.process}.to_not raise_error
|
|
end
|
|
|
|
it 'if reboot validate info not presence -> raise error' do
|
|
time = Time.now.to_i
|
|
hooks.stubs(:run_shell_without_check).with(
|
|
ctx,
|
|
['2','3'],
|
|
regexp_matches(/stat/),
|
|
10,
|
|
)
|
|
.returns('2' => time.to_s, '3' => (time - 5).to_s).then
|
|
.returns('3' => time.to_s)
|
|
|
|
hooks.stubs(:run_shell_without_check).with(
|
|
ctx,
|
|
['2'],
|
|
regexp_matches(/stat/),
|
|
10,
|
|
).returns({})
|
|
hooks.stubs(:update_node_status)
|
|
|
|
expect {hooks.process}.to raise_error(Astute::DeploymentEngineError, /Failed to execute hook/)
|
|
end
|
|
end #context
|
|
|
|
end #reboot_hook
|
|
|
|
context '#cobbler_sync_hook' do
|
|
|
|
it 'should validate presence of provisioning_info' do
|
|
cobbler_sync_hook['parameters']['provisioning_info'] = {}
|
|
hooks = Astute::NailgunHooks.new([cobbler_sync_hook], ctx)
|
|
|
|
expect {hooks.process}.to raise_error(StandardError, /Missing a required parameter/)
|
|
end
|
|
|
|
it 'should call Astute::CobblerManager sync method ' do
|
|
hooks = Astute::NailgunHooks.new([cobbler_sync_hook], ctx)
|
|
Astute::CobblerManager.any_instance.expects(:sync).once
|
|
|
|
hooks.process
|
|
end
|
|
|
|
end #cobbler_sync_hook
|
|
|
|
end # 'describe'
|