require 'rufus-scheduler' require "uri" require "commands/status" require "commands/server" require "commands/bootstrap_templates" require "commands/knife_commands" require "providers/provider_factory" require "db/mongo/models/server" require "workers/create_server_worker" require "workers/bootstrap_worker" require "app/api2/parsers/server" require_relative "request_handler" module Devops module API2_0 module Handler class Server < RequestHandler set_parser Devops::API2_0::Parser::ServerParser extend StatusCommands extend ServerCommands extend BootstrapTemplatesCommands scheduler = Rufus::Scheduler.new def servers fields, reserved = parser.servers Devops::DB.connector.servers(nil, nil, nil, reserved, fields).map {|s| s.to_hash} end def chef_servers KnifeCommands.chef_node_list end def provider_servers provider ::Provider::ProviderFactory.get(provider).servers end def server id get_server_by_key(id, parse.server) end def delete id s = get_server_by_key(id, parser.instance_key) ### Authorization Devops::Db.connector.check_project_auth s.project, s.deploy_env, parser.current_user delete_server(s, Devops::Db.connector, DevopsLogger.logger) end def create_server_stream out, body status = [] prepare_create_server(body).each do |s| res = create_server_proc.call(out, s, provider) status.push res end status end def create_server dir = DevopsConfig[:report_dir_v2] files = [] uri = URI.parse(parser.request.url) prepare_create_server.each do |s| h = s.to_hash h["options"] = s.options jid = CreateServerWorker.perform_async(dir, s.provider, h, parser.current_user, DevopsConfig.config) Worker.set_status jid, Worker::STATUS::IN_QUEUE #logger.info "Job '#{jid}' has been started" uri.path = "#{DevopsConfig[:url_prefix]}/v2.0/report/" + jid files.push uri.to_s end sleep 1 files end def prepare_create_server body = parser.create user = parser.current_user key_name = body["key"] new_key = Devops::Db.connector.key(key_name) unless key_name.nil? p = Devops::Db.connector.check_project_auth(body["project"], body["deploy_env"], user) env = p.deploy_env(body["deploy_env"]) provider = ::Provider::ProviderFactory.get(env.provider) server_name = body["name"] check_chef_node_name(server_name, provider) unless server_name.nil? groups = body["groups"] unless groups.nil? buf = groups - provider.groups.keys halt_response("Invalid security groups '#{buf.join("', '")}' for provider '#{provider.name}'") if buf.empty? end Server.extract_servers(provider, p, env, body, user) end def pause_server node_name s = Server.get_server_by_key(node_name, parser.instance_key) ## Authorization Devops::Db.connector.check_project_auth s.project, s.deploy_env, parser.current_user provider = ::Provider::ProviderFactory.get(s.provider) r = provider.pause_server s if r.nil? "Server with instance ID '#{s.id}' and node name '#{node_name}' is paused" else raise ConflictException.new("Server with instance ID '#{s.id}' and node name '#{node_name}' can not be paused, It in state '#{r}'", 409) end end def unpause_server node_name s = Server.get_server_by_key(node_name, parser.instance_key) ## Authorization Devops::Db.connector.check_project_auth s.project, s.deploy_env, parser.current_user provider = ::Provider::ProviderFactory.get(s.provider) r = provider.unpause_server s if r.nil? "Server with instance ID '#{s.id}' and node name '#{node_name}' is unpaused" else raise ConflictException.new("Server with instance ID '#{s.id}' and node name '#{node_name}' can not be unpaused, It in state '#{r}'") end end def reserve_server node_name s = get_server_by_key(node_name, parser.instance_key) user = parser.current_user Devops::Db.connector.check_project_auth s.project, s.deploy_env, user raise ConflictException.new("Server '#{node_name}' already reserved") unless s.reserved_by.nil? s.reserved_by = user Devops::Db.connector.server_update(s) end def unreserve_server node_name s = get_server_by_key(node_name, parser.instance_key) Devops::Db.connector.check_project_auth s.project, s.deploy_env, parser.current_user raise ConflictException.new("Server '#{node_name}' is not reserved") if s.reserved_by.nil? s.reserved_by = nil Devops::Db.connector.server_update(s) end # TODO: check bootstrap template name def bootstrap_server_stream out s = prepare_create_server status = [] cert = Devops::Db.connector.key s.key logger.debug "Bootstrap certificate path: #{cert.path}" bootstrap s, out, cert.path, logger str = nil r = if check_server(s) Devops::Db.connector.server_set_chef_node_name s str = "Server with id '#{s.id}' is bootstraped" logger.info str 0 else str = "Server with id '#{s.id}' is not bootstraped" logger.warn str 1 end status.push r out << str out << "\n" status end def bootstrap_server s = prepare_bootstrap_server dir = DevopsConfig[:report_dir_v2] files = [] uri = URI.parse(@request.url) h = s.to_hash h["options"] = s.options h["_id"] = s.id jid = BootstrapWorker.perform_async(dir, d.provider, h, parser.current_user, DevopsConfig.config) Worker.set_status jid, Worker::STATUS::IN_QUEUE logger.info "Job '#{jid}' has been started" uri.path = "#{DevopsConfig[:url_prefix]}/v2.0/report/" + jid uri.query = nil uri.fragment = nil files.push uri.to_s sleep 1 files end def prepare_bootstrap_server body = parser.bootstrap id = body["instance_id"] name = body["name"] s = Devops::Db.connector.server_by_instance_id(id) p = Devops::Db.connector.check_project_auth s.project, s.deploy_env, parser.current_user d = p.deploy_env s.deploy_env provider = ::Provider::ProviderFactory.get(s.provider) check_chef_node_name(name, provider) unless name.nil? s.options = { :run_list => rl || d.run_list, } unless t.nil? templates = get_templates halt_response("Invalid bootstrap template '#{t}', available values: #{templates.join(", ")}", 400) unless templates.include?(t) s.options[:bootstrap_template] = t end s.chef_node_name = name || provider.create_default_chef_node_name(s) s end def add_server body = parser.add_server project = body["project"] deploy_env = body["deploy_env"] p = Devops::Db.connector.check_project_auth project, deploy_env, parser.current_user d = p.deploy_env(deploy_env) cert = Devops::Db.connector.key(body["key"]) provider = ::Provider::ProviderFactory.get("static") s = Devops::Model::Server.new s.provider = provider.name s.project = project s.deploy_env = deploy_env s.remote_user = body["remote_user"] s.private_ip = body["private_ip"] s.public_ip = body["public_ip"] s.static = true s.id = "static_#{cert.id}-#{Time.now.to_i}" s.key = cert.id Devops::Db.connector.server_insert s "Server '#{s.id}' has been added" end def set_tags node_name prepare_tags do |id, provider| provider.set_tags id, parser.tags end end def unset_tags node_name prepare_tags do |id, provider| provider.unset_tags id, parser.tags end end def prepare_tags node_name s = get_server_by_key(node_name, parser.instance_key) user = parser.current_user Devops::Db.connector.check_project_auth s.project, s.deploy_env, user provider = ::Provider::ProviderFactory.get(s.provider) yield s.id, provider end def set_run_list node_name s = get_server_by_key(node_name, parser.instance_key) user = parser.current_user Devops::Db.connector.check_project_auth s.project, s.deploy_env, user Devops::Db.connector.set_server_run_list(s.id, parser.run_list) end def get_server_by_key id, key mongo = Devops::Db.connector key == "instance" ? mongo.server_by_instance_id(id) : mongo.server_by_chef_node_name(id) end def check_chef_node_name name, provider mongo = Devops::Db.connector mongo.server_by_chef_node_name name halt(400, "Server with name '#{name}' already exist") rescue RecordNotFound => e # server not found - OK s = provider.servers.detect {|s| s["name"] == name} halt(400, "#{provider.name} node with name '#{name}' already exist") unless s.nil? s = KnifeCommands.chef_node_list.detect {|n| n == name} halt(400, "Chef node with name '#{name}' already exist") unless s.nil? s = KnifeCommands.chef_client_list.detect {|c| c == name} halt(400, "Chef client with name '#{name}' already exist") unless s.nil? end end class ExpireHandler include ServerCommands def initialize server, logger @server = server @logger = logger end def call(job) @logger.info("Removing node '#{@server.chef_node_name}' form project '#{@server.project}' and env '#{@server.deploy_env}'") begin delete_server(@server, Devops::Db.connector, @logger) rescue => e logger.error "ExpiredHandler error: " + e.message end end end end end end