diff --git a/devops-client/lib/devops-client/handler/server.rb b/devops-client/lib/devops-client/handler/server.rb index 28d7338..07027b6 100644 --- a/devops-client/lib/devops-client/handler/server.rb +++ b/devops-client/lib/devops-client/handler/server.rb @@ -41,6 +41,8 @@ class Server < Handler unreserve_handler when :add add_static_handler + when :add_and_bootstrap_list + add_and_bootstrap_list_handler end end @@ -140,7 +142,7 @@ class Server < Handler reports_urls(job_ids) end - def add_static_handler # add --public-ip -k + def add_static_handler # add --public-ip r = inspect_parameters @options_parser.add_params, @args[2], @args[3], @args[4], @args[5], @args[6] unless r.nil? @options_parser.invalid_add_command @@ -157,6 +159,25 @@ class Server < Handler post "/server/add", q end + def add_and_bootstrap_list_handler + project, env, user, key, ips_file_path = @args[2..6] + r = inspect_parameters @options_parser.add_and_bootstrap_list_params, project, env, user, key, ips_file_path + unless r.nil? + @options_parser.invalid_add_and_bootstrap_list_command + abort(r) + end + q = { + project: project, + deploy_env: env, + remote_user: user, + key: key, + ips_with_names: get_file_contents(ips_file_path) + } + q[:public_ip] = options[:public_ip] if options[:public_ip] + report_ids = post "/server/add_and_bootstrap_servers", q + reports_urls(report_ids) + end + def pause_handler r = inspect_parameters @options_parser.pause_params, @args[2] unless r.nil? diff --git a/devops-client/lib/devops-client/options/server_options.rb b/devops-client/lib/devops-client/options/server_options.rb index 455c6f8..6b844f6 100644 --- a/devops-client/lib/devops-client/options/server_options.rb +++ b/devops-client/lib/devops-client/options/server_options.rb @@ -2,7 +2,7 @@ require "devops-client/options/common_options" class ServerOptions < CommonOptions - commands :add, :bootstrap, :create, :delete, :list, :pause, :reserve, :show, :unpause, :unreserve, :delete_list + commands :add, :bootstrap, :create, :delete, :list, :pause, :reserve, :show, :unpause, :unreserve, :delete_list, :add_and_bootstrap_list def initialize args, def_options super(args, def_options) @@ -19,6 +19,7 @@ class ServerOptions < CommonOptions self.unreserve_params = node_params self.bootstrap_params = ["INSTANCE_ID"] self.add_params = ["PROJECT_ID", "DEPLOY_ENV", "IP", "SSH_USER", "KEY_ID"] + self.add_and_bootstrap_list_params = ["PROJECT_ID", "DEPLOY_ENV", "SSH_USER", "KEY_ID", "IPS_FILE"] end def delete_options @@ -157,6 +158,16 @@ class ServerOptions < CommonOptions end end + def add_and_bootstrap_list_options + options do |parser, options| + parser.banner << self.add_and_bootstrap_list_banner + parser.separator '' + parser.separator "\tIPS_FILE is path to a file with list of ip:node_name pairs; example of such file:" + parser.separator "\type127.0.0.1:node1" + parser.separator "\type127.0.0.2:node2" + end + end + def delete_banner self.banner_header + " delete NODE_NAME [NODE_NAME ...]\n" end diff --git a/devops-service/app/api2/handlers/server.rb b/devops-service/app/api2/handlers/server.rb index 88c2683..2ac05e5 100644 --- a/devops-service/app/api2/handlers/server.rb +++ b/devops-service/app/api2/handlers/server.rb @@ -212,7 +212,6 @@ module Devops owner: parser.current_user ) - sleep 1 [jid] end @@ -249,26 +248,25 @@ module Devops 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 + project, deploy_env, server_attrs = parser.add_server + Devops::Db.connector.check_project_auth project, deploy_env, parser.current_user - d = p.deploy_env(deploy_env) + server = add_static_server(server_attrs) + "Server '#{server.id}' has been added" + end - 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" + # returns jobs ids + def add_and_bootstrap_servers + body, servers_attrs = parser.add_and_bootstrap_servers + Devops::Db.connector.check_project_auth body['project'], body['deploy_env'], parser.current_user + servers_attrs.map do |attrs| + server = add_static_server(attrs) + Worker.start_async(BootstrapWorker, + server_attrs: server.to_mongo_hash, + bootstrap_template: body['bootstrap_template'], + owner: parser.current_user + ) + end end def set_tags node_name @@ -318,6 +316,33 @@ module Devops private + # Security checks should be already done here. + # @attrs should be a hash with: + # :project + # :deploy_env + # :key + # :remote_user + # :private_ip + # :public_ip + # :chef_node_name + # :run_list + def add_static_server(attrs) + server = Devops::Model::Server.new( + '_id' => "static_#{attrs[:key]}-#{attrs[:chef_node_name]}-#{Time.now.to_i}", + 'provider' => ::Provider::ProviderFactory.get('static').name, + 'project' => attrs[:project], + 'deploy_env' => attrs[:deploy_env], + 'remote_user' => attrs[:remote_user], + 'private_ip' => attrs[:private_ip], + 'public_ip' => attrs[:public_ip], + 'key' => attrs[:key], + 'chef_node_name' => attrs[:chef_node_name], + 'run_list' => attrs[:run_list] + ) + Devops::Db.connector.server_insert(server) + server + end + def check_if_server_attrs_are_valid(body, user) key_name = body["key"] Devops::Db.connector.key(key_name) unless key_name.nil? diff --git a/devops-service/app/api2/parsers/server.rb b/devops-service/app/api2/parsers/server.rb index b9c1a6f..c6e9c1a 100644 --- a/devops-service/app/api2/parsers/server.rb +++ b/devops-service/app/api2/parsers/server.rb @@ -60,7 +60,41 @@ module Devops public_ip = check_string(@body["public_ip"], "Parameter 'public_ip' should be a not empty string", true) rl = check_array(@body["run_list"], "Parameter 'run_list' should be a not empty array of string", String, true, true) Validators::Helpers::RunList.new(rl).validate! unless rl.nil? - @body + server_attrs = { + project: project, + deploy_env: deploy_env, + key: key, + remote_user: remote_user, + private_ip: private_ip, + public_ip: public_ip, + run_list: rl + } + [project, deploy_env, server_attrs] + end + + def add_and_bootstrap_servers + @body ||= create_object_from_json_body + project = check_string(@body["project"], "Parameter 'project' must be a not empty string") + deploy_env = check_string(@body["deploy_env"], "Parameter 'deploy_env' must be a not empty string") + key = check_string(@body["key"], "Parameter 'key' must be a not empty string") + remote_user = check_string(@body["remote_user"], "Parameter 'remote_user' must be a not empty string") + rl = check_array(@body["run_list"], "Parameter 'run_list' should be a not empty array of string", String, true, true) + check_string(@body["bootstrap_template"], "Parameter 'bootstrap_template' should be a not empty string", true) + Validators::Helpers::RunList.new(rl).validate! unless rl.nil? + + ips_with_names = parse_list_of_ips_with_names(@body['ips_with_names']) + servers_attrs = ips_with_names.map do |ip, chef_node_name| + { + project: project, + deploy_env: deploy_env, + key: key, + remote_user: remote_user, + private_ip: ip, + chef_node_name: chef_node_name, + run_list: rl + } + end + [@body, servers_attrs] end def tags @@ -80,6 +114,17 @@ module Devops check_array(@body["servers_ids"], "Parameter 'servers_ids' should be a not empty array of string", String, false) end + private + + def parse_list_of_ips_with_names(text) + hash = {} + text.each_line do |line| + ip, name = line.split(':').map(&:strip) + hash[ip] = name + end + hash + end + end end end diff --git a/devops-service/app/api2/routes/server.rb b/devops-service/app/api2/routes/server.rb index 51c6e6b..b2d5c17 100644 --- a/devops-service/app/api2/routes/server.rb +++ b/devops-service/app/api2/routes/server.rb @@ -375,6 +375,34 @@ module Devops create_response(info) end + + # Add list of external servers to devops and bootstrap them + # + # * *Request* + # - method : POST + # - headers : + # - Accept: application/json + # - Content-Type: application/json + # - body : + # { + # "project": "project name", -> required + # "deploy_env": "env", -> required + # "key": "ssh key", -> required + # "remote_user": "ssh user", -> required + # "ips_with_names": multiline string like, required + # 127.0.0.1:node1 + # 127.0.0.2:node2 + # "private_ip": "ip", -> required + # "public_ip": "ip" + # } + # + # * *Returns* : + # ["report1", "report2"] + app.post_with_headers "/server/add_and_bootstrap_servers", :headers => [:accept, :content_type] do + check_privileges("server", "w") + json Devops::API2_0::Handler::Server.new(request).add_and_bootstrap_servers() + end + hash = {} # Add instance tags #