fluke/devops-service/spec/executors/server_executor_spec.rb

369 lines
12 KiB
Ruby
Raw Normal View History

2015-12-21 18:23:17 +03:00
require 'lib/executors/server_executor'
RSpec.describe Devops::Executor::ServerExecutor, type: :executor, stubbed_connector: true, stubbed_logger: true do
2015-12-21 18:23:17 +03:00
let(:project) { build(:project) }
let(:deploy_env) { project.deploy_env('foo') }
let(:server) { build(:server, project: project.id, deploy_env: 'foo') }
let(:output) { File.open(File::NULL, "w") }
2015-12-28 13:07:13 +03:00
let(:provider) { double('Provider instance') }
let(:executor) { described_class.new(server, output) }
2015-12-21 18:23:17 +03:00
2015-12-28 13:07:13 +03:00
2015-12-21 18:23:17 +03:00
before do
allow(stubbed_connector).to receive(:project) { project }
2015-12-28 13:07:13 +03:00
allow(executor.deploy_env).to receive(:provider_instance) { provider }
allow(server).to receive(:provider_instance) { provider }
2015-12-21 18:23:17 +03:00
end
describe '#initialize' do
it 'sets server, project, deploy_env, out instance variables' do
expect(executor.server).to eq server
expect(executor.deploy_env).to eq deploy_env
2015-12-21 18:23:17 +03:00
expect(executor).to have_instance_variable_value(:project, project)
expect(executor).to have_instance_variable_value(:out, output)
2015-12-21 18:23:17 +03:00
end
it 'defines :flush method on @out if it is absent' do
out = Class.new.new
expect(out).not_to respond_to(:flush)
described_class.new(server, out)
expect(out).to respond_to(:flush)
end
it 'sets current_user from options' do
user = double
executor = described_class.new(server, '', {current_user: user})
expect(executor).to have_instance_variable_value(:current_user, user)
end
end
describe '#create_server_object' do
it 'builds Server object' do
server = executor.create_server_object('created_by' => 'me')
expect(server).to be_a(Devops::Model::Server)
expect(server.project).to eq 'my_project'
expect(server.deploy_env).to eq 'foo'
expect(server.created_by).to eq 'me'
end
end
describe '#create_server' do
let!(:without_bootstrap) { @without_bootstrap = true }
let!(:run_list) { @run_list = %w(role[asd]) }
let!(:key) { @key = 'key' }
2015-12-28 13:07:13 +03:00
let!(:image) { double('Image instance', remote_user: 'remote_user') }
subject {
executor.create_server(
'created_by' => 'user',
'run_list' => @run_list,
'name' => 'node_name',
'key' => @key,
'without_bootstrap' => @without_bootstrap
)
}
before do
2015-12-28 13:07:13 +03:00
allow(provider).to receive(:create_server) { true }
allow(stubbed_connector).to receive(:image) { image }
allow(stubbed_connector).to receive(:server_insert)
end
it 'builds server model from given options' do
subject
expect(executor.server.created_by).to eq 'user'
expect(executor.server.chef_node_name).to eq 'node_name'
expect(executor.server.key).to eq @key
expect(executor.server.run_list).to eq @run_list
end
it 'sets run list to an empty array by default' do
@run_list = nil
subject
expect(executor.server.run_list).to eq []
end
it 'sets key to default provider ssh key by default' do
@key = nil
2015-12-28 13:07:13 +03:00
allow(provider).to receive(:ssh_key) { 'default_key' }
subject
expect(executor.server.key).to eq 'default_key'
end
it 'runs hooks' do
expect(executor).to receive(:run_hook).with(:before_create).ordered
expect(executor).to receive(:run_hook).with(:after_create).ordered
subject
end
it 'creates server in cloud' do
2015-12-28 13:07:13 +03:00
expect(provider).to receive(:create_server).with(
an_instance_of(Devops::Model::Server), deploy_env.image, deploy_env.flavor, deploy_env.subnets, deploy_env.groups, output
)
subject
end
it 'inserts built server into mongo' do
expect(stubbed_connector).to receive(:server_insert)
subject
end
it 'schedules expiration for server' do
expect(executor).to receive(:schedule_expiration).with(an_instance_of(Devops::Model::Server))
subject
end
context 'without_bootstrap option is false' do
it 'launches bootstrap' do
@without_bootstrap = false
2015-12-28 13:07:13 +03:00
allow(image).to receive(:bootstrap_template) { 'template' }
allow(executor).to receive(:two_phase_bootstrap)
expect(executor).to receive(:two_phase_bootstrap)
subject
end
end
context 'without_bootstrap option is nil' do
it 'launches bootstrap' do
@without_bootstrap = nil
2015-12-28 13:07:13 +03:00
allow(image).to receive(:bootstrap_template) { 'template' }
allow(executor).to receive(:two_phase_bootstrap)
expect(executor).to receive(:two_phase_bootstrap)
subject
end
end
context 'without_bootstrap option is true' do
it "doesn't launch bootstrap" do
@without_bootstrap = true
expect(executor).not_to receive(:two_phase_bootstrap)
subject
end
end
context 'if error has been raised during execution' do
before do
allow(stubbed_connector).to receive(:server_delete)
2015-12-28 13:07:13 +03:00
allow(provider).to receive(:create_server) { raise }
end
it 'rollbacks server creating' do
expect(executor).to receive(:roll_back)
subject
end
it 'deletes server from mongo' do
expect(stubbed_connector).to receive(:server_delete)
subject
end
2015-12-28 13:07:13 +03:00
end
context "if creating server in cloud wasn't successful" do
it 'returns creating_server_in_cloud_failed error code' do
2015-12-28 13:07:13 +03:00
allow(provider).to receive(:create_server) { false }
expect(subject).to eq 10
end
end
end
describe '#bootstrap', stubbed_knife: true do
2015-12-28 13:07:13 +03:00
subject { executor.bootstrap({}) }
let(:image) { double('Key instance', path: 'path') }
before do
allow(executor).to receive(:sleep)
allow(executor).to receive(:connected_successfully?).and_return(true)
allow(executor).to receive(:execute_system_command)
allow(provider).to receive(:create_default_chef_node_name).and_return('chef_node')
allow(stubbed_connector).to receive(:key).and_return(image)
allow(stubbed_connector).to receive(:server_set_chef_node_name)
allow(stubbed_knife).to receive(:knife_bootstrap).and_return(0)
end
it 'run before hook' do
expect(executor).to receive(:run_hook).with(:before_bootstrap, output).ordered
expect(executor).to receive(:run_hook).with(:after_bootstrap, output).ordered
subject
end
context "when server's private ip is unset" do
it 'returns server_bootstrap_private_ip_unset error code' do
2015-12-28 13:07:13 +03:00
server.private_ip = nil
expect(subject).to eq 3
end
end
2015-12-28 13:07:13 +03:00
it 'tries to ssh to server' do
expect(executor).to receive(:execute_system_command).with(/ssh/)
subject
end
context "couldn't ssh to server" do
before { allow(executor).to receive(:connected_successfully?) { false } }
it 'tries to ssh to server maximum MAX_SSH_RETRIES_AMOUNT times' do
max_retries = Devops::Executor::ServerExecutor::MAX_SSH_RETRIES_AMOUNT
expect(executor).to receive(:execute_system_command).exactly(max_retries).times
subject
end
it 'returns server_bootstrap_fail error code' do
2015-12-28 13:07:13 +03:00
expect(subject).to eq 2
end
end
context 'after successful ssh check' do
before { allow(executor).to receive(:connected_successfully?).and_return(false, true) }
it "sets default chef node name if it's nil" do
executor.server.chef_node_name = nil
expect {subject}.to change {executor.server.chef_node_name}.to 'chef_node'
end
it 'executes knife bootstrap' do
expect(stubbed_knife).to receive(:knife_bootstrap).with(output, server.private_ip, instance_of(Array))
subject
end
it "bootstraps to public ip if it's set" do
server.public_ip = '8.8.8.8'
expect(stubbed_knife).to receive(:knife_bootstrap).with(output, '8.8.8.8', instance_of(Array))
subject
end
context 'after successful bootstrap' do
it "updates server's chef node name in db" do
expect(stubbed_connector).to receive(:server_set_chef_node_name).with(instance_of(Devops::Model::Server))
subject
end
end
context "if bootstraping wasn't successful" do
before { allow(stubbed_knife).to receive(:knife_bootstrap).and_return(123) }
it 'returns :server_bootstrap_fail code' do
2015-12-28 13:07:13 +03:00
expect(subject).to eq 2
end
it "doesn't run after hook" do
expect(executor).to receive(:run_hook).with(:before_bootstrap, output)
subject
end
end
end
end
describe '#two_phase_bootstrap', stubbed_knife: true do
subject { executor.two_phase_bootstrap({}) }
before do
allow(provider).to receive(:run_list) {[]}
allow(stubbed_connector).to receive(:server_delete)
end
context 'when bootstrap was successful' do
before do
allow(executor).to receive(:bootstrap) { 0 }
allow(executor).to receive(:check_server_on_chef_server) { false }
end
context 'if node presents on chef server' do
before do
allow(executor).to receive(:check_server_on_chef_server) { true }
allow(executor).to receive(:deploy_server)
allow(stubbed_knife).to receive(:set_run_list)
end
it 'builds run list' do
expect(executor).to receive(:compute_run_list)
subject
end
it 'sets run list to chef node' do
expect(stubbed_knife).to receive(:set_run_list)
subject
end
it 'deploys server' do
expect(executor).to receive(:deploy_server)
subject
end
context 'if deploy was successful' do
it 'returns 0' do
allow(executor).to receive(:deploy_server) { 0 }
expect(subject).to eq 0
end
end
context "if deploy wasn't successful" do
it 'returns :deploy_failed code' do
allow(executor).to receive(:deploy_server) { 1 }
expect(subject).to eq 8
end
end
context 'when an error occured during deploy' do
it 'returns :deploy_unknown_error code' do
allow(executor).to receive(:deploy_server) { raise }
expect(subject).to eq 6
end
end
end
context "if node doesn't present on chef server" do
it 'roll backs and then deletes server from mongo' do
allow(executor).to receive(:check_server_on_chef_server) { false }
allow(executor).to receive(:roll_back)
allow(stubbed_connector).to receive(:server_delete)
expect(executor).to receive(:roll_back).ordered
expect(stubbed_connector).to receive(:server_delete).ordered
subject
end
end
end
context "when bootstrap wasn't successful" do
it 'returns :server_bootstrap_fail error code' do
allow(executor).to receive(:bootstrap) { 1 }
expect(subject).to eq 2
end
end
context 'when an error occured during bootstrap' do
it 'returns :server_bootstrap_unknown_error error code' do
allow(executor).to receive(:bootstrap) { raise }
expect(subject).to eq 7
end
end
end
describe '#check_server_on_chef_server', stubbed_knife: true do
subject { executor.check_server_on_chef_server }
before do
server.chef_node_name = 'a'
allow(stubbed_knife).to receive(:chef_node_list) { @node_list }
allow(stubbed_knife).to receive(:chef_client_list) { @client_list }
end
it 'returns true when node_name in node list and in client list' do
@node_list = %w(a); @client_list = %w(a)
expect(subject).to be true
end
it "returns false if node name isn't in node list" do
@node_list = []; @client_list = %w(a)
expect(subject).to be false
end
it "returns false if node name isn't in node list" do
@node_list = %w(a); @client_list = []
expect(subject).to be false
end
end
2015-12-21 18:23:17 +03:00
end