295 lines
9.7 KiB
Ruby
295 lines
9.7 KiB
Ruby
require "lib/knife/knife_factory"
|
|
require "lib/puts_and_flush"
|
|
require "hooks"
|
|
require_relative "server_executor/expiration_scheduler"
|
|
require_relative 'server_executor/server_operation_result'
|
|
require "lib/ssh/ssh_utils"
|
|
require "exceptions/bootstrap_error"
|
|
require "exceptions/deploy_error"
|
|
require "exceptions/deploy_info_error"
|
|
require "exceptions/creation_error"
|
|
require "db/mongo/models/image"
|
|
require "db/mongo/models/server"
|
|
require "db/mongo/models/key"
|
|
require "db/mongo/models/project"
|
|
|
|
module Devops
|
|
module Executor
|
|
class ServerExecutor
|
|
include Hooks
|
|
include PutsAndFlush
|
|
include ServerOperationResultCode
|
|
|
|
# waiting for 5*60 seconds (5 min)
|
|
MAX_SSH_RETRIES_AMOUNT = 60
|
|
|
|
define_hook :before_create
|
|
define_hook :after_create
|
|
|
|
#params:
|
|
# out - container for output data
|
|
define_hook :before_bootstrap
|
|
define_hook :after_bootstrap
|
|
|
|
#before_deploy :add_run_list_to_deploy_info
|
|
|
|
attr_accessor :server, :environment, :job_task, :project
|
|
attr_reader :out, :current_user
|
|
|
|
def initialize server, out, current_user, options={}
|
|
if server
|
|
@project = Devops::Model::Project.find_with_environment(server.project, server.environment)
|
|
@environment = @project.environment(server.environment)
|
|
@category = @environment.get_category(server.category)
|
|
@server = server
|
|
end
|
|
@out = out
|
|
@out.class.send(:define_method, :flush) { } unless @out.respond_to?(:flush)
|
|
@current_user = current_user
|
|
end
|
|
|
|
# TODO: refactore attr_accessors to constructor options,
|
|
# because these values don't change after object initializing
|
|
def job_task= task
|
|
@job_task = task
|
|
end
|
|
|
|
def project= p
|
|
@project = p
|
|
end
|
|
|
|
def environment= e
|
|
@environment = e
|
|
end
|
|
|
|
def server
|
|
@server
|
|
end
|
|
|
|
def category= category
|
|
@category = category
|
|
end
|
|
|
|
def create_server_object options
|
|
Devops::Model::Server.new({
|
|
"project" => @project.id,
|
|
"environment" => @environment.id,
|
|
"category" => @category.id,
|
|
"created_by" => @current_user,
|
|
"provider" => @category.provider.name,
|
|
"provider_account" => @category.provider.account,
|
|
"private_ip" => options["private_ip"]
|
|
})
|
|
end
|
|
|
|
def create_server options
|
|
@server = create_server_object(options)
|
|
@server.set_last_operation(Devops::Model::Server::OperationType::CREATION, @current_user, @job_task.id)
|
|
provider = @category.provider
|
|
@out.puts "Create server..."
|
|
@server.run_list = options["run_list"] || []
|
|
@server.ssh_key = options["ssh_key"] || provider.account_instance.ssh_key
|
|
@server.name = options["name"] || @server.provider_instance.create_default_server_name(@server)
|
|
|
|
image = Devops::Model::Image.where(image_id: provider.image, provider: provider.name, provider_account: provider.account).first
|
|
@server.remote_user = image.remote_user
|
|
|
|
res = {}
|
|
@out << "\nBefore create hooks...\n"
|
|
res[:before] = self.run_hook :before_create
|
|
@out << "Done\n"
|
|
|
|
@out.puts "Running cloud instance...\nUsing provider '#{provider.name}' and account '#{provider.account}'\n"
|
|
@out.flush
|
|
|
|
unless provider.create_server(@server, @out)
|
|
raise Devops::Exception::CreationError.new("Can not create server in cloud with provider '#{provider.name}' and account '#{provider.account}'")
|
|
end
|
|
@server.save
|
|
|
|
provider.waiting_server @server, @out
|
|
@server.save
|
|
|
|
@out << @server.info
|
|
@out.flush
|
|
|
|
@out << "\n\nAfter create hooks...\n"
|
|
res[:after] = self.run_hook :after_create
|
|
@out << "Done\n"
|
|
@out.flush
|
|
DevopsLogger.logger.info "Server with parameters: #{@server.to_hash.inspect} is running"
|
|
|
|
schedule_expiration()
|
|
0
|
|
end
|
|
|
|
def deploy_info options
|
|
@server.set_last_operation(Devops::Model::Server::OperationType::DEPLOY_INFO, @current_user, @job_task.id)
|
|
options[:deploy_info] || @project.deploy_info(@environment)
|
|
end
|
|
|
|
def bootstrap_server options, deploy_info
|
|
@server.set_last_operation(Devops::Model::Server::OperationType::BOOTSTRAP, @current_user, @job_task.id)
|
|
=begin
|
|
<<<<<<< HEAD
|
|
if @project.is_sandbox?
|
|
bootstrap_options[:deployers] = [options['created_by']]
|
|
bootstrap_options[:deployers] += (options['project_info']['deployers'] || []) if options['project_info']
|
|
end
|
|
=======
|
|
=end
|
|
|
|
@job_task.bootstrap_info = @category.cm_tool.bootstrap_instance(@server, deploy_info, @out, options)
|
|
@job_task.save
|
|
@server.save
|
|
DevopsLogger.logger.info "Server #{@server.id} has been bootstraped with cm name '#{@server.cm_name}'"
|
|
0
|
|
end
|
|
|
|
def deploy_server options, deploy_info
|
|
@server.set_last_operation(Devops::Model::Server::OperationType::DEPLOY, @current_user, @job_task.id)
|
|
deploy_info[:run_list] = compute_run_list
|
|
@job_task.deploy_info = deploy_info
|
|
@job_task.save
|
|
@category.cm_tool.deploy_instance(@server, deploy_info, @out)
|
|
DevopsLogger.logger.info "Server #{@server.id} has been deployed"
|
|
0
|
|
end
|
|
|
|
def unbootstrap_server
|
|
res = @category.cm_tool.delete_instance(@server, @out)
|
|
res
|
|
end
|
|
|
|
def deploy_server_with_tags tags, deploy_info
|
|
unless tags.empty?
|
|
deploy_info[tags: tags]
|
|
end
|
|
|
|
@job_task.deploy_info = deploy_info
|
|
@job_task.save
|
|
r = @category.cm_tool.deploy_instance(@server, deploy_info, @out)
|
|
|
|
@server.set_last_operation(Devops::Model::Server::OperationType::DEPLOY, @current_user, @job_task.id)
|
|
@server.save
|
|
return r
|
|
end
|
|
|
|
def delete_server
|
|
if @server.static?
|
|
@out << "'#{@server.id}' is a static server"
|
|
@out.flush
|
|
unless @server.cm_name.nil?
|
|
unbootstrap_server
|
|
end
|
|
@server.delete
|
|
msg = "Static server '#{@server.id}' is removed"
|
|
DevopsLogger.logger.info msg
|
|
return msg, nil
|
|
end
|
|
puts_and_flush "'#{@server.id}' is not a static server"
|
|
puts_and_flush @server.to_hash
|
|
@category.cm_tool.delete_instance(@server, @out)
|
|
provider = @server.provider_instance
|
|
msg = nil
|
|
begin
|
|
msg = provider.delete_server @server
|
|
rescue Fog::Compute::OpenStack::NotFound, Fog::Compute::AWS::NotFound
|
|
msg = "Server with id '#{@server.id}' not found in '#{provider.name}' servers"
|
|
DevopsLogger.logger.warn msg
|
|
end
|
|
@out.puts msg
|
|
@server.delete
|
|
info = "Server '#{@server.id}' with name '#{@server.name}' for project '#{@server.project}-#{@server.environment}' is removed"
|
|
puts_and_flush info
|
|
DevopsLogger.logger.info info
|
|
return 0
|
|
end
|
|
|
|
def roll_back
|
|
@out.puts "Trying to roll back..."
|
|
unless @server.id.nil?
|
|
unless @server.name.nil?
|
|
@out.puts "Server '#{@server.name}' with id '#{@server.id}' is not created"
|
|
@category.cm_tool.delete_instance(@server, @out)
|
|
end
|
|
begin
|
|
@out.puts @server.provider_instance.delete_server(@server)
|
|
rescue => e
|
|
@out.puts e.message
|
|
end
|
|
@out << "\nRolled back\n"
|
|
end
|
|
end
|
|
|
|
def add_run_list_to_deploy_info out, deploy_info
|
|
out << "\nGenerate run list hook...\n"
|
|
if deploy_info["run_list"]
|
|
out << "Deploy info already contains 'run_list': #{deploy_info["run_list"].join(", ")}\n"
|
|
return
|
|
end
|
|
out << "Project run list: #{@project.run_list.join(", ")}\n"
|
|
out << "Deploy environment run list: #{@environment.run_list.join(", ")}\n"
|
|
out << "Server run list: #{@server.run_list.join(", ")}\n"
|
|
deploy_info["run_list"] = compute_run_list
|
|
out << "New deploy run list: #{deploy_info["run_list"].join(", ")}\nRun list has been generated\n\n"
|
|
end
|
|
|
|
def compute_run_list
|
|
rlist = []
|
|
[@server.provider_instance.run_list, @project.run_list, @environment.run_list, @server.run_list].each do |sub_run_list|
|
|
rlist += sub_run_list if sub_run_list.is_a?(Array)
|
|
end
|
|
if @server.stack
|
|
#TODO
|
|
stack = Devops::Db.connector.stack(@server.stack)
|
|
srl = stack.run_list
|
|
rlist += srl if srl
|
|
end
|
|
rlist.uniq
|
|
end
|
|
|
|
def waiting_ssh
|
|
ip = @server.private_ip
|
|
unless @server.public_ip.nil?
|
|
ip = server.public_ip
|
|
@out.puts "\nPublic IP is present"
|
|
end
|
|
|
|
@out << "Waiting for SSH"
|
|
k = Devops::Model::Key.find(@server.ssh_key)
|
|
|
|
retries_amount = 0
|
|
begin
|
|
sleep(5)
|
|
res = Devops::SSH::Utils.try_ssh(ip, @server.remote_user, k.path)
|
|
if res
|
|
@out.puts "\n"
|
|
@out.flush
|
|
return true
|
|
else
|
|
retries_amount += 1
|
|
if retries_amount > MAX_SSH_RETRIES_AMOUNT
|
|
raise Devops::Exception::BootstrapError.new("Can not connect to #{@server.remote_user}@#{ip}")
|
|
end
|
|
raise ArgumentError.new
|
|
end
|
|
rescue ArgumentError => e
|
|
@out << "."
|
|
@out.flush
|
|
retry
|
|
end
|
|
end
|
|
|
|
private
|
|
def schedule_expiration
|
|
if @environment.expires
|
|
job_id = ExpirationScheduler.new(@environment.expires, @server).schedule_expiration!
|
|
puts_and_flush "Planning expiration in #{@environment.expires}, job_id: #{job_id}"
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|