fluke/devops-service/workers/stack_bootstrap_worker.rb
2015-09-24 15:06:02 +03:00

161 lines
5.1 KiB
Ruby

require "providers/provider_factory"
require "commands/stack"
require "db/mongo/models/stack/stack_factory"
require "db/mongo/models/project"
require "db/mongo/models/report"
class StackCreatingError < StandardError; end
class BootstrapingStackServerError < StandardError; end
class DeployingStackServerError < StandardError; end
class StackBootstrapWorker < Worker
include StackCommands
def perform(options)
provider_name = options.fetch('provider_name')
stack_attrs = options.fetch('stack_attributes')
call(provider_name) do |provider, out, file|
@out = out
without_bootstrap = stack_attrs.delete('without_bootstrap')
@out.puts "Received 'without_bootstrap' option" if without_bootstrap
report = save_report(file, stack_attrs)
begin
stack = create_stack(provider_name, stack_attrs)
rescue StackCreatingError
return 1
end
begin
servers = persist_stack_servers!(stack, provider)
bootstrap_servers!(servers, report) unless without_bootstrap
rescue BootstrapingStackServerError
@out.puts "\nAn error occured during bootstraping stack servers. Initiating stack rollback."
rollback_stack!(stack)
1
rescue DeployingStackServerError => e
@out.puts "\nStack was launched, but an error occured during deploying stack servers."
@out.puts "You can redeploy stack after fixing the error."
1
rescue StandardError => e
@out.puts "\nAn error occured. Initiating stack rollback."
rollback_stack!(stack)
raise e
end
end
end
private
def rollback_stack!(stack)
@out.puts "\nStart rollback of a stack"
stack.delete_stack_in_cloud!
Devops::Db.connector.stack_servers_delete(stack.name)
Devops::Db.connector.stack_delete(stack.id)
@out.puts "Rollback has been completed"
end
def create_stack(provider_name, stack_attrs)
stack = Devops::Model::StackFactory.create(provider_name, stack_attrs, @out)
mongo.stack_insert(stack)
operation_result = sync_stack_proc.call(@out, stack, mongo)
if operation_result == 0
@out.puts "\nStack '#{stack.name}' has been created"
@out.flush
stack
else
human_readable_code = StackCommands.result_codes.key(operation_result)
@out.puts "An error ocurred during stack creating"
@out.puts "Stack creating operation result was #{human_readable_code}"
raise StackCreatingError
end
end
def bootstrap_servers!(servers, report)
@out << "\nStart bootstraping stack servers\n"
bootstraping_results = {}
servers.each do |server|
executor = Devops::Executor::ServerExecutor.new(server, @out)
executor.report = report
bootstraping_results[server.chef_node_name] = executor.two_phase_bootstrap({})
end
check_bootstrap_results!(bootstraping_results)
end
def check_bootstrap_results!(results)
if results.values.all?(&:zero?)
# everything is OK
@out.puts "Stack servers have been bootstraped"
@out.flush
return 0
end
@out.puts
results.each do |chef_node_name, code|
human_readable_code = Devops::Executor::ServerExecutor.symbolic_result_code(code)
@out.puts "Operation result for #{chef_node_name}: #{human_readable_code}"
end
if errors_in_bootstrapping_present?(results)
raise BootstrapingStackServerError # will cause rollback of a stack
else
raise DeployingStackServerError #will not cause rollback of a stack
end
end
def errors_in_bootstrapping_present?(results)
results.values.any? do |result|
result == Devops::Executor::ServerExecutor.result_code(:server_bootstrap_fail)
end
end
def save_report(file, stack_attrs)
report = ::Devops::Model::Report.new(
"file" => file,
"_id" => jid,
"created_by" => stack_attrs['owner'],
"project" => stack_attrs["project"],
"deploy_env" => stack_attrs["deploy_env"],
"type" => ::Devops::Model::Report::STACK_TYPE
)
mongo.save_report(report)
report
end
def persist_stack_servers!(stack, provider)
@out.puts "Start syncing stack servers with CID"
@out.flush
project = mongo.project(stack.project)
deploy_env = project.deploy_env(stack.deploy_env)
servers = provider.stack_servers(stack).map do |extended_info|
server_attrs = {
'provider' => provider.name,
'project' => project.id,
'deploy_env' => deploy_env.identifier,
'remote_user' => mongo.image(deploy_env.image).remote_user,
'key' => extended_info["key_name"] || provider.ssh_key,
'_id' => extended_info["id"],
'chef_node_name' => extended_info["name"],
'private_ip' => extended_info["private_ip"],
'public_ip' => extended_info["public_ip"],
'created_by' => stack.owner,
'run_list' => stack.run_list || [],
'stack' => stack.name
}
server = ::Devops::Model::Server.new(server_attrs)
mongo.server_insert(server)
# server.chef_node_name = provider.create_default_chef_node_name(server)
server
end
@out.puts "Stack servers have been synced with CID"
@out.flush
servers
end
end