fluke/devops-service/commands/server.rb

198 lines
6.1 KiB
Ruby
Raw Normal View History

2014-05-08 15:34:26 +04:00
require "commands/knife_commands"
require "db/exceptions/record_not_found"
module ServerCommands
def extract_servers provider, project, env, params, user, mongo
flavors = provider.flavors
projects = {}
env_name = env.identifier
project_name = project.id
servers_info = []
if project.multi?
#TODO: fix multi project
images = {}
env.servers.each do |name, server|
images[server["image"]] = mongo.image(server["image"]) unless images.has_key?(server["image"])
flavor = flavors.detect {|f| f["name"] == server["flavor"]}
raise RecordNotFound.new("Flavor with name '#{server["flavor"]}' not found") if flavor.nil?
run_list = []
project_ids = server["subprojects"].map{|sp| sp["project_id"]}
db_subprojects = mongo.projects project_ids
ids = project_ids - db_subprojects.map{|sp| sp.id}
unless ids.empty?
return [400, "Subproject(s) '#{ids.join("', '")}' is/are not exists"]
end
server["subprojects"].each do |sp|
p = db_subprojects.detect{|db_sp| db_sp.id == sp["project_id"]}
run_list += p.deploy_env(sp["project_env"]).run_list
end
o = {
:image => images[server["image"]],
:name => "#{name}_#{Time.now.to_i}",
:flavor => flavor["id"],
:groups => server["groups"],
:run_list => run_list
}
servers_info.push(o)
end
else
i = mongo.image env.image
flavor = flavors.detect {|f| f["id"] == env.flavor}
raise RecordNotFound.new("Flavor with id '#{env.flavor}' not found") if flavor.nil?
o = {
:image => i,
:name => params["name"],
:flavor => flavor["id"],
:groups => params["groups"] || env.groups,
:run_list => env.run_list,
:subnets => env.subnets,
:key => params["key"]
}
servers_info.push(o)
end
servers = []
servers_info.each do |info|
image = info[:image]
s = Server.new
s.provider = provider.name
s.project = project_name
s.deploy_env = env_name
s.remote_user = image.remote_user
2014-06-11 12:13:02 +04:00
s.chef_node_name = info[:name] || provider.create_default_chef_node_name(s)
2014-05-08 15:34:26 +04:00
s.key = info[:key] || provider.ssh_key
s.options = {
:image => image.id,
:flavor => info[:flavor],
:name => info[:name],
:groups => info[:groups],
:run_list => info[:run_list],
:bootstrap_template => image.bootstrap_template,
:subnets => info[:subnets]
}
s.created_by = user
servers.push s
end
return servers
end
def delete_from_chef_server node_name
{
:chef_node => KnifeCommands.chef_node_delete(node_name),
:chef_client => KnifeCommands.chef_client_delete(node_name)
}
end
def check_server s
KnifeCommands.chef_node_list.include?(s.chef_node_name) and KnifeCommands.chef_client_list.include?(s.chef_node_name)
end
def bootstrap s, out, cert_path, logger
if s.private_ip.nil?
out << "Error: Private IP is null"
return false
end
ja = {
:provider => s.provider,
:devops_host => `hostname`.strip
}
bootstrap_options = [
"-x #{s.remote_user}",
"-i #{cert_path}",
"--json-attributes '#{ja.to_json}'"
]
bootstrap_options.push "--sudo" unless s.remote_user == "root"
bootstrap_options.push "-N #{s.chef_node_name}" if s.chef_node_name
bootstrap_options.push "-d #{s.options[:bootstrap_template]}" if s.options[:bootstrap_template]
bootstrap_options.push "-r #{s.options[:run_list].join(",")}" unless s.options[:run_list].empty?
ip = s.private_ip
unless s.public_ip.nil? || s.public_ip.strip.empty?
ip = s.public_ip
out << "\nPublic IP is present\n"
end
out << "\nWaiting for SSH..."
i = 0
begin
sleep(1)
`ssh -i #{cert_path} -q #{s.remote_user}@#{ip} exit`
i += 1
if i == 300
res = `ssh -i #{cert_path} #{s.remote_user}@#{ip} "exit" 2>&1`
out << "\nCan not connect to #{s.remote_user}@#{ip}"
out << "\n" + res
logger.error "Can not connect with command 'ssh -i #{cert_path} #{s.remote_user}@#{ip}':\n#{res}"
return false
end
raise unless $?.success?
rescue
retry
end
bootstrap_cmd = "knife bootstrap #{bootstrap_options.join(" ")} #{ip}"
out << "\nExecuting '#{bootstrap_cmd}' \n\n"
status = nil
IO.popen(bootstrap_cmd + " 2>&1") do |bo|
while line = bo.gets do
out << line
end
bo.close
status = $?.to_i
end
return status
end
def self.unbootstrap s, cert_path
2014-05-08 15:34:26 +04:00
i = 0
begin
r = `ssh -i #{cert_path} -q #{s.remote_user}@#{s.private_ip} rm -Rf /etc/chef`
raise(r) unless $?.success?
2014-05-08 15:34:26 +04:00
rescue => e
logger.error "Unbootstrap error: " + e.message
2014-05-08 15:34:26 +04:00
i += 1
sleep(1)
retry unless i == 5
return e.message
2014-05-08 15:34:26 +04:00
end
nil
2014-05-08 15:34:26 +04:00
end
def delete_server s, mongo, logger
if s.chef_node_name.nil?
mongo.server_delete s.id
msg = "Added server '#{s.id}' is removed"
logger.info msg
return msg, nil
end
r = delete_from_chef_server(s.chef_node_name)
provider = ::Provider::ProviderFactory.get(s.provider)
begin
r[:server] = provider.delete_server s
rescue Fog::Compute::OpenStack::NotFound, Fog::Compute::AWS::NotFound
r[:server] = "Server with id '#{s.id}' not found in '#{provider.name}' servers"
logger.warn r[:server]
2014-05-08 15:34:26 +04:00
end
mongo.server_delete s.id
info = "Server '#{s.id}' with name '#{s.chef_node_name}' for project '#{s.project}-#{s.deploy_env}' is removed"
logger.info info
2014-05-08 15:34:26 +04:00
r.each{|key, log| logger.info("#{key} - #{log}")}
return info, r
end
2014-05-23 17:58:49 +04:00
def roll_back s, provider
str = ""
unless s.id.nil?
str << "Server '#{s.chef_node_name}' with id '#{s.id}' is not created\n"
str << delete_from_chef_server(s.chef_node_name).values.join("\n")
begin
str << provider.delete_server(s)
2014-05-23 17:58:49 +04:00
rescue => e
str << e.message
end
str << "\nRolled back\n"
end
return str
end
2014-05-08 15:34:26 +04:00
end