require "uri" require "commands/status" require "commands/bootstrap_templates" require "lib/executors/server_executor" 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 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 KnifeFactory.instance.chef_node_list end def provider_servers provider ::Provider::ProviderFactory.get(provider).servers end def server id get_server_by_key(id, parser.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 Devops::Executor::ServerExecutor.new(s, "").delete_server end def create_server_stream out status = [] prepare_create_server do |project, env, user, body| e = Devops::Executor::ServerExecutor.new(nil, out) e.project = project e.deploy_env = env body["created_by"] = user res = e.create_server(body) status.push res end status end def create_server body = parser.create user = parser.current_user check_if_server_attrs_are_valid(body, user) uri = Worker.start_async(CreateServerWorker, @request, server_attrs: body, owner: user ) [uri] 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 = s.provider_instance 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 = s.provider_instance 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, rl, bt = prepare_bootstrap_server status = [] cert = Devops::Db.connector.key s.key DevopsLogger.logger.debug "Bootstrap certificate path: #{cert.path}" #bootstrap s, out, cert.path, logger options = { :bootstrap_template => bt, :cert_path => cert.path, :run_list => rl } r = two_phase_bootstrap s, options, out str = nil r = if check_server(s) Devops::Db.connector.server_set_chef_node_name s str = "Server with id '#{s.id}' is bootstraped" DevopsLogger.logger.info str 0 else str = "Server with id '#{s.id}' is not bootstraped" DevopsLogger.logger.warn str 1 end status.push r out << str out << "\n" status end def bootstrap_server server, rl, bootstrap_template = prepare_bootstrap_server dir = DevopsConfig[:report_dir_v2] files = [] uri = URI.parse(@request.url) uri = Worker.start_async(BootstrapWorker, @request, provider_name: server.provider, server_attrs: server.to_mongo_hash, bootstrap_template: bootstrap_template, owner: parser.current_user ) sleep 1 [uri] end def prepare_bootstrap_server body = parser.bootstrap id = body["instance_id"] name = body["name"] rl = body["run_list"] t = body["bootstrap_template"] 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 = s.provider_instance check_chef_node_name(name, provider, KnifeFactory.instance) unless name.nil? unless t.nil? templates = get_templates halt_response("Invalid bootstrap template '#{t}', available values: #{templates.join(", ")}", 400) unless templates.include?(t) end s.chef_node_name = name || provider.create_default_chef_node_name(s) return s, rl || d.run_list, t end def unbootstrap_server 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 Devops::Executor::ServerExecutor.new(s, "").unbootstrap 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.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 tags = parser.tags prepare_tags do |id, provider| provider.set_tags id, tags end end def unset_tags node_name tags = parser.tags prepare_tags do |id, provider| provider.unset_tags id, tags end end def prepare_tags 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 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) Devops::Db.connector.check_project_auth s.project, s.deploy_env, parser.current_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, knife Devops::Db.connector.server_by_chef_node_name(name) raise InvalidRecord.new("Server with name '#{name}' already exist") rescue RecordNotFound => e # server not found - OK s = provider.servers.detect {|s| s["name"] == name} raise InvalidRecord.new("#{provider.name} node with name '#{name}' already exist") unless s.nil? s = knife.chef_node_list.detect {|n| n == name} raise InvalidRecord.new("Chef node with name '#{name}' already exist") unless s.nil? s = knife.chef_client_list.detect {|c| c == name} raise InvalidRecord.new("Chef client with name '#{name}' already exist") unless s.nil? end private def check_if_server_attrs_are_valid(body, user) key_name = body["key"] Devops::Db.connector.key(key_name) unless key_name.nil? project = Devops::Db.connector.check_project_auth(body["project"], body["deploy_env"], user) env = project.deploy_env(body["deploy_env"]) provider = env.provider_instance server_name = body["name"] check_chef_node_name(server_name, provider, KnifeFactory.instance) 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 end end end end end