From 344514d08e6a6b09a8428b2a21eceab4fbe482dc Mon Sep 17 00:00:00 2001 From: Anton Chuchkalov Date: Mon, 20 Jul 2015 19:59:26 +0400 Subject: [PATCH 1/7] current_progress --- .../lib/devops-client/handler/stack_preset.rb | 3 +- .../options/stack_preset_options.rb | 2 ++ .../lib/devops-client/output/stack_preset.rb | 11 +++++-- devops-service/commands/stack.rb | 23 ++++++++++++++ devops-service/db/mongo/models/mongo_model.rb | 1 + devops-service/db/mongo/models/report.rb | 1 + .../db/mongo/models/stack/stack_base.rb | 13 ++++++++ .../routes/v2.0/handlers/stack_preset.rb | 16 ++++++++++ .../sinatra/methods_with_headers.rb | 2 +- devops-service/workers/run_workers.rb | 1 + devops-service/workers/stack_sync_worker.rb | 30 +++++++++++++++++++ 11 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 devops-service/commands/stack.rb create mode 100644 devops-service/workers/stack_sync_worker.rb diff --git a/devops-client/lib/devops-client/handler/stack_preset.rb b/devops-client/lib/devops-client/handler/stack_preset.rb index a6df6d9..b1e9073 100644 --- a/devops-client/lib/devops-client/handler/stack_preset.rb +++ b/devops-client/lib/devops-client/handler/stack_preset.rb @@ -22,6 +22,7 @@ class StackPreset < Handler output when :apply apply_handler + output end end @@ -55,7 +56,7 @@ class StackPreset < Handler filepath = options[:parameters_file] || enter_parameter(I18n.t('handler.stack_preset.create.parameters_file')) params[:parameters] = JSON.parse(File.read(filepath)) - result = post_body("/stack_presets/#{params[:id]}/apply", JSON.pretty_generate(params)) + @list = post_body("/stack_presets/#{params[:id]}/apply", JSON.pretty_generate(params)) end end diff --git a/devops-client/lib/devops-client/options/stack_preset_options.rb b/devops-client/lib/devops-client/options/stack_preset_options.rb index 919e2dc..5475210 100644 --- a/devops-client/lib/devops-client/options/stack_preset_options.rb +++ b/devops-client/lib/devops-client/options/stack_preset_options.rb @@ -19,6 +19,8 @@ class StackPresetOptions < CommonOptions parser.recognize_option_value(:provider, 'stack_preset') parser.recognize_option_value(:stack, 'stack_preset') + parser.recognize_option_value(:project, 'stack_preset') + parser.recognize_option_value(:deploy_env, 'stack_preset') parser.recognize_option_value(:parameters_file, 'stack_preset') end end diff --git a/devops-client/lib/devops-client/output/stack_preset.rb b/devops-client/lib/devops-client/output/stack_preset.rb index 184c944..76c9909 100644 --- a/devops-client/lib/devops-client/output/stack_preset.rb +++ b/devops-client/lib/devops-client/output/stack_preset.rb @@ -3,14 +3,15 @@ require "devops-client/output/base" module Output class StackPreset < Base - def table + def table if outputting_list? title = I18n.t("output.title.stack_preset.list") headers, rows = create_list - create_table headers, rows, title, with_num? else - @data["id"] + "\n" + @data["template_preset_body"] + title = I18n.t("output.title.stack.show", id: @data["id"]) + headers, rows = create_apply end + create_table headers, rows, title, with_num? end def csv @@ -36,5 +37,9 @@ module Output headers_and_rows(@data, fields_to_output) end + def create_apply + headers_and_rows([@data], %w(id deploy_env stack_template cloud_stack_id stack_status)) + end + end end diff --git a/devops-service/commands/stack.rb b/devops-service/commands/stack.rb new file mode 100644 index 0000000..b125d67 --- /dev/null +++ b/devops-service/commands/stack.rb @@ -0,0 +1,23 @@ +module StackCommands + + def sync_stack_till_not_in_progress_proc + lambda do |out, stack, mongo| + begin + 10.times do |i| + sleep 10 + out << "Syncing stack '#{stack.id}'..." + stack.sync_details! + if stack.stack_status != 'CREATE_IN_PROGRESS' + mongo.stack_update(stack) + out << "Stack '#{stack.id}' status is now #{stack.stack_status}" + break + end + end + rescue StandardError => e + logger.error e.message + return 5 + end + end + end + +end diff --git a/devops-service/db/mongo/models/mongo_model.rb b/devops-service/db/mongo/models/mongo_model.rb index 316276a..a32d764 100644 --- a/devops-service/db/mongo/models/mongo_model.rb +++ b/devops-service/db/mongo/models/mongo_model.rb @@ -1,6 +1,7 @@ require "providers/provider_factory" require "db/exceptions/invalid_record" require "json" +require 'db/validators/all' module Devops module Model diff --git a/devops-service/db/mongo/models/report.rb b/devops-service/db/mongo/models/report.rb index b4971f7..dce0489 100644 --- a/devops-service/db/mongo/models/report.rb +++ b/devops-service/db/mongo/models/report.rb @@ -9,6 +9,7 @@ module Devops SERVER_TYPE = 2 BOOTSTRAP_TYPE = 3 PROJECT_TEST_TYPE = 4 + STACK_TYPE = 5 attr_accessor :id, :file, :created_at, :created_by, :project, :deploy_env, :type diff --git a/devops-service/db/mongo/models/stack/stack_base.rb b/devops-service/db/mongo/models/stack/stack_base.rb index 695331f..3ae32c9 100644 --- a/devops-service/db/mongo/models/stack/stack_base.rb +++ b/devops-service/db/mongo/models/stack/stack_base.rb @@ -67,6 +67,18 @@ module Devops Devops::Api2.settings.mongo.stack_template(stack_template).template_body end + def stack_status + raise 'override me' + end + + def stack_statuses + # maybe they differ in different providers, so use method instead of hardcoding + { + in_progress: 'CREATE_IN_PROGRESS', + complete: 'CREATE_COMPLETE' + } + end + class << self attr_accessor :provider @@ -77,6 +89,7 @@ module Devops def create(attrs) model = new(attrs) model.create_stack_in_cloud! + model.sync_details! model end diff --git a/devops-service/routes/v2.0/handlers/stack_preset.rb b/devops-service/routes/v2.0/handlers/stack_preset.rb index 1b16e13..106d638 100644 --- a/devops-service/routes/v2.0/handlers/stack_preset.rb +++ b/devops-service/routes/v2.0/handlers/stack_preset.rb @@ -1,5 +1,6 @@ require 'json' require 'lib/stack_presets/factory' +require 'workers/stack_sync_worker' module Devops module Version2_0 @@ -30,6 +31,21 @@ module Devops stack = preset.create_stack_from_preset(attrs) settings.mongo.stack_insert(stack) + + jid = StackSyncWorker.perform_async( + DevopsConfig[:report_dir_v2], + stack.id, + request.env['REMOTE_USER'], # owner + DevopsConfig.config + ) + Worker.set_status jid, Worker::STATUS::IN_QUEUE + logger.info "Job '#{jid}' has been started" + uri = URI.parse(request.url) + uri.path = "#{DevopsConfig[:url_prefix]}/v2.0/report/" + jid + file = uri.to_s + + puts "Syncing report is located here: #{file}" + create_response 'Created', stack.to_hash, 201 } end diff --git a/devops-service/sinatra/methods_with_headers.rb b/devops-service/sinatra/methods_with_headers.rb index 1a36622..aeafdf9 100644 --- a/devops-service/sinatra/methods_with_headers.rb +++ b/devops-service/sinatra/methods_with_headers.rb @@ -101,7 +101,7 @@ module Sinatra # Can client works with JSON? def accept_json types = request.accept_media_types - unless types.include?('application/json')# or types.include?("*/*") + unless types.include?('application/json') or types.include?("*/*") response.headers['Accept'] = 'application/json' halt_response("Accept header should contains 'application/json' type", 406) end diff --git a/devops-service/workers/run_workers.rb b/devops-service/workers/run_workers.rb index bdf8c59..7bd89d8 100644 --- a/devops-service/workers/run_workers.rb +++ b/devops-service/workers/run_workers.rb @@ -4,6 +4,7 @@ require File.join(root, "create_server_worker") require File.join(root, "deploy_worker") require File.join(root, "bootstrap_worker") require File.join(root, "project_test_worker") +require File.join(root, "stack_sync_worker") config = {} #require File.join(root, "../proxy") diff --git a/devops-service/workers/stack_sync_worker.rb b/devops-service/workers/stack_sync_worker.rb new file mode 100644 index 0000000..de60193 --- /dev/null +++ b/devops-service/workers/stack_sync_worker.rb @@ -0,0 +1,30 @@ +#root = File.join(File.dirname(__FILE__), "..") +#$LOAD_PATH.push root unless $LOAD_PATH.include? root + +# require File.join(File.dirname(__FILE__), "workers") +require "providers/provider_factory" +require "commands/stack" +require "db/mongo/models/stack/stack_factory" +require "db/mongo/models/report" + +class StackSyncWorker < Worker + include StackCommands + + def perform(dir, stack_id, owner, conf) + call(conf, nil, dir) do |mongo, useless, out, file| + stack = mongo.stack(stack_id) + o = { + "file" => file, + "_id" => jid, + "created_by" => owner, + "project" => stack.project, + "deploy_env" => stack.deploy_env, + "type" => Report::STACK_TYPE + } + mongo.save_report(Report.new(o)) + + status = sync_stack_till_not_in_progress_proc.call(out, stack, mongo) + status + end + end +end From ef26dc19e427c9891b92c0d946846042e17607fd Mon Sep 17 00:00:00 2001 From: Anton Chuchkalov Date: Tue, 21 Jul 2015 18:13:10 +0400 Subject: [PATCH 2/7] autosync stack after creating till status not changed --- devops-service/commands/stack.rb | 10 +++++++--- devops-service/db/mongo/connectors/report.rb | 4 ++++ .../db/mongo/models/stack/stack_openstack.rb | 2 +- devops-service/db/mongo/mongo_connector.rb | 2 +- devops-service/routes/v2.0/handlers/stack_preset.rb | 1 + devops-service/workers/stack_sync_worker.rb | 8 ++++---- 6 files changed, 18 insertions(+), 9 deletions(-) diff --git a/devops-service/commands/stack.rb b/devops-service/commands/stack.rb index b125d67..0ea2316 100644 --- a/devops-service/commands/stack.rb +++ b/devops-service/commands/stack.rb @@ -2,16 +2,20 @@ module StackCommands def sync_stack_till_not_in_progress_proc lambda do |out, stack, mongo| + # two tries each 5 seconds, then 5 tries each 10 seconds, then 5 tries each minute. + sleep_times = [5]*2 + [10]*5 + [60]*5 + begin - 10.times do |i| - sleep 10 - out << "Syncing stack '#{stack.id}'..." + out << "Syncing stack '#{stack.id}'...\n" + sleep_times.each do |sleep_time| + sleep sleep_time stack.sync_details! if stack.stack_status != 'CREATE_IN_PROGRESS' mongo.stack_update(stack) out << "Stack '#{stack.id}' status is now #{stack.stack_status}" break end + out << "Next try...\n" end rescue StandardError => e logger.error e.message diff --git a/devops-service/db/mongo/connectors/report.rb b/devops-service/db/mongo/connectors/report.rb index 43ae963..b5ea994 100644 --- a/devops-service/db/mongo/connectors/report.rb +++ b/devops-service/db/mongo/connectors/report.rb @@ -38,6 +38,10 @@ module Connectors list(options) end + def set_report_status(jid, status) + # TODO: merge from novartis + end + private def model_from_bson(bson) diff --git a/devops-service/db/mongo/models/stack/stack_openstack.rb b/devops-service/db/mongo/models/stack/stack_openstack.rb index 62918ae..13818d9 100644 --- a/devops-service/db/mongo/models/stack/stack_openstack.rb +++ b/devops-service/db/mongo/models/stack/stack_openstack.rb @@ -4,7 +4,7 @@ module Devops self.provider = 'openstack' def stack_status - details[:stack_status] if details + details[:stack_status] || details['stack_status'] if details end end end diff --git a/devops-service/db/mongo/mongo_connector.rb b/devops-service/db/mongo/mongo_connector.rb index c92c2f5..2522759 100644 --- a/devops-service/db/mongo/mongo_connector.rb +++ b/devops-service/db/mongo/mongo_connector.rb @@ -26,7 +26,7 @@ class MongoConnector [:user_auth, :user, :users, :users_names, :user_insert, :user_delete, :user_update, :create_root_user, :check_user_privileges] => :users_connector, [:keys, :key, :key_insert, :key_delete] => :keys_connector, - [:save_report, :report, :reports] => :reports_connector, + [:save_report, :report, :reports, :set_report_status] => :reports_connector, [:statistic] => :statistics_connector ) diff --git a/devops-service/routes/v2.0/handlers/stack_preset.rb b/devops-service/routes/v2.0/handlers/stack_preset.rb index 106d638..63f5682 100644 --- a/devops-service/routes/v2.0/handlers/stack_preset.rb +++ b/devops-service/routes/v2.0/handlers/stack_preset.rb @@ -34,6 +34,7 @@ module Devops jid = StackSyncWorker.perform_async( DevopsConfig[:report_dir_v2], + stack.provider, stack.id, request.env['REMOTE_USER'], # owner DevopsConfig.config diff --git a/devops-service/workers/stack_sync_worker.rb b/devops-service/workers/stack_sync_worker.rb index de60193..7400436 100644 --- a/devops-service/workers/stack_sync_worker.rb +++ b/devops-service/workers/stack_sync_worker.rb @@ -10,8 +10,8 @@ require "db/mongo/models/report" class StackSyncWorker < Worker include StackCommands - def perform(dir, stack_id, owner, conf) - call(conf, nil, dir) do |mongo, useless, out, file| + def perform(dir, provider, stack_id, owner, conf) + call(conf, provider, dir) do |mongo, provider, out, file| stack = mongo.stack(stack_id) o = { "file" => file, @@ -19,9 +19,9 @@ class StackSyncWorker < Worker "created_by" => owner, "project" => stack.project, "deploy_env" => stack.deploy_env, - "type" => Report::STACK_TYPE + "type" => ::Devops::Model::Report::STACK_TYPE } - mongo.save_report(Report.new(o)) + mongo.save_report(::Devops::Model::Report.new(o)) status = sync_stack_till_not_in_progress_proc.call(out, stack, mongo) status From 75ffceaa7dd333e516d135ecb1564f76866b9012 Mon Sep 17 00:00:00 2001 From: Anton Chuchkalov Date: Tue, 21 Jul 2015 20:32:41 +0400 Subject: [PATCH 3/7] simplify outputting in client --- .../handler/helpers/outputtable.rb | 10 +++---- .../lib/devops-client/handler/project.rb | 16 +++--------- .../lib/devops-client/handler/stack.rb | 2 +- .../lib/devops-client/output/base.rb | 17 ++++-------- .../lib/devops-client/output/project.rb | 10 +++---- .../lib/devops-client/output/stack.rb | 26 ++++++++++++++----- 6 files changed, 37 insertions(+), 44 deletions(-) diff --git a/devops-client/lib/devops-client/handler/helpers/outputtable.rb b/devops-client/lib/devops-client/handler/helpers/outputtable.rb index 8cb52b1..e7b948c 100644 --- a/devops-client/lib/devops-client/handler/helpers/outputtable.rb +++ b/devops-client/lib/devops-client/handler/helpers/outputtable.rb @@ -4,17 +4,13 @@ module Outputtable @list || @show end - def additional_output_options - {} - end - def outputter raise 'You should use "output_with" method to define outputter' unless defined?(outputter_class) - @outputter ||= outputter_class.new(data_to_output, options, additional_output_options) + @outputter ||= outputter_class.new(data_to_output, options.merge(current_command: current_command)) end - def output(preferred_format=nil) - outputter.output(preferred_format) + def output(options={}) + outputter.output(options) end diff --git a/devops-client/lib/devops-client/handler/project.rb b/devops-client/lib/devops-client/handler/project.rb index 30ee118..6557a9f 100644 --- a/devops-client/lib/devops-client/handler/project.rb +++ b/devops-client/lib/devops-client/handler/project.rb @@ -48,7 +48,7 @@ class Project < Handler when "servers" self.options = @options_parser.servers_options servers_handler @options_parser.args - output + output(output_type: :servers) when "set" case ARGV[2] when "run_list" @@ -61,7 +61,7 @@ class Project < Handler when "show" self.options = @options_parser.show_options show_handler @options_parser.args - output + output(output_type: :show) when "update" self.options = @options_parser.update_options update_handler @options_parser.args @@ -80,7 +80,7 @@ class Project < Handler when "test" self.options = @options_parser.test_options test_handler @options_parser.args - output + output(output_type: :test) else @options_parser.invalid_command end @@ -422,14 +422,4 @@ protected @list || @show || @servers || @test end - def additional_output_options - output_type = case ARGV[1] - when 'servers', 'test', 'show' - ARGV[1].to_sym - else - :list - end - {output_type: output_type} - end - end diff --git a/devops-client/lib/devops-client/handler/stack.rb b/devops-client/lib/devops-client/handler/stack.rb index 2625d3e..503d9f3 100644 --- a/devops-client/lib/devops-client/handler/stack.rb +++ b/devops-client/lib/devops-client/handler/stack.rb @@ -30,7 +30,7 @@ class Stack < Handler output when :resources resources_handler - output('json') + output(resource: @args[3]) end end diff --git a/devops-client/lib/devops-client/output/base.rb b/devops-client/lib/devops-client/output/base.rb index 04a1a42..d5c8e71 100644 --- a/devops-client/lib/devops-client/output/base.rb +++ b/devops-client/lib/devops-client/output/base.rb @@ -7,20 +7,13 @@ module Output attr_reader :options - # QUESTION: - # Earlier I use additional parameter "output_type". Now I use - # detecting output_type from data_to_output.class: - # Array means we are outputting list command, - # Hash or something other - we are outputting show command. - # Is this OK? - - def initialize(data_to_output, command_line_options={}, additional_options={}) - @data, @options, @additional_options = data_to_output, command_line_options, additional_options + def initialize(data_to_output, options={}) + @data, @options = data_to_output, options end - def output(format = nil) - format ||= options[:format] - case format + def output(preferred_options) + @options = @options.merge(preferred_options) + case options[:format] when CommonOptions::TABLE_FORMAT table when CommonOptions::JSON_FORMAT diff --git a/devops-client/lib/devops-client/output/project.rb b/devops-client/lib/devops-client/output/project.rb index 6c847b9..052b94b 100644 --- a/devops-client/lib/devops-client/output/project.rb +++ b/devops-client/lib/devops-client/output/project.rb @@ -9,15 +9,12 @@ module Output def table title = nil with_separator = false - headers, rows = case @additional_options[:output_type] - when :list - title = I18n.t("output.title.project.list") - create_list(@data) + headers, rows = case options[:output_type] when :show title = I18n.t("output.title.project.show", :name => @data["name"]) with_separator = true create_show(@data) - when :server + when :servers title = ARGV[2] title += " " + ARGV[3] unless ARGV[3].nil? title = I18n.t("output.title.project.servers", :title => title) @@ -25,6 +22,9 @@ module Output when :test title = I18n.t("output.title.project.test", :project => ARGV[2], :env => ARGV[3]) create_test(@data) + else + title = I18n.t("output.title.project.list") + create_list(@data) end create_table(headers, rows, title, with_num?, with_separator) end diff --git a/devops-client/lib/devops-client/output/stack.rb b/devops-client/lib/devops-client/output/stack.rb index 2cf9e09..3731412 100644 --- a/devops-client/lib/devops-client/output/stack.rb +++ b/devops-client/lib/devops-client/output/stack.rb @@ -6,13 +6,19 @@ module Output include Concerns::HasProvider def table - if outputting_list? - title = I18n.t("output.title.stack.list") - headers, rows = create_list + if options[:current_command] == :resources + if options[:resource].nil? + headers, rows = create_servers_list + end else - puts 'Details are not displayed in table view' - title = I18n.t("output.title.stack.show", id: @data["id"]) - headers, rows = create_show + if outputting_list? + title = I18n.t("output.title.stack.list") + headers, rows = create_list + else + puts 'Details are not displayed in table view' + title = I18n.t("output.title.stack.show", id: @data["id"]) + headers, rows = create_show + end end create_table(headers, rows, title, with_num?) end @@ -41,5 +47,13 @@ module Output headers_and_rows([@data], %w(id deploy_env stack_template cloud_stack_id stack_status)) end + def create_servers_list + headers = ['Logical id', 'Physical id'] + rows = @data.map do |resource| + [resource['resource_name'], resource['physical_resource_id']] + end + [headers, rows] + end + end end From 0066b1cefde56ae0a6bfa182fe37b35003072154 Mon Sep 17 00:00:00 2001 From: Anton Chuchkalov Date: Tue, 21 Jul 2015 20:47:16 +0400 Subject: [PATCH 4/7] add ability to view stack servers via console --- devops-client/lib/devops-client/handler/stack.rb | 6 +++++- devops-service/providers/openstack.rb | 5 +++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/devops-client/lib/devops-client/handler/stack.rb b/devops-client/lib/devops-client/handler/stack.rb index 503d9f3..a323669 100644 --- a/devops-client/lib/devops-client/handler/stack.rb +++ b/devops-client/lib/devops-client/handler/stack.rb @@ -30,7 +30,11 @@ class Stack < Handler output when :resources resources_handler - output(resource: @args[3]) + if @args[3] + output(format: 'json', resource: true) + else + output + end end end diff --git a/devops-service/providers/openstack.rb b/devops-service/providers/openstack.rb index a927741..011007d 100644 --- a/devops-service/providers/openstack.rb +++ b/devops-service/providers/openstack.rb @@ -184,7 +184,7 @@ module Provider end def compute - connection_compute(self.connection_options) + @compute ||= connection_compute(connection_options) end def network @@ -218,7 +218,8 @@ module Provider end def stack_resource(stack, resource_id) - fog_stack(stack).resources.get(resource_id) + physical_id = fog_stack(stack).resources.get(resource_id).physical_resource_id + compute.servers.get(physical_id).attributes end private From 7ff7fd67319b79d99bc9d6af4ecee71e09843b4a Mon Sep 17 00:00:00 2001 From: Anton Chuchkalov Date: Wed, 22 Jul 2015 19:52:33 +0400 Subject: [PATCH 5/7] rename test template file --- ...ack_template_preset.feature.erb => stack_preset.feature.erb} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename devops-service/tests/templates/api_v2/00_list/{stack_template_preset.feature.erb => stack_preset.feature.erb} (99%) diff --git a/devops-service/tests/templates/api_v2/00_list/stack_template_preset.feature.erb b/devops-service/tests/templates/api_v2/00_list/stack_preset.feature.erb similarity index 99% rename from devops-service/tests/templates/api_v2/00_list/stack_template_preset.feature.erb rename to devops-service/tests/templates/api_v2/00_list/stack_preset.feature.erb index 77690e4..973279d 100644 --- a/devops-service/tests/templates/api_v2/00_list/stack_template_preset.feature.erb +++ b/devops-service/tests/templates/api_v2/00_list/stack_preset.feature.erb @@ -25,4 +25,4 @@ Feature: stack template preset list { "id": "postgres_cluster", "template_body": "long body" } - """ \ No newline at end of file + """ From 499d05ad3273547b9f27312475a3cf4d73f0f981 Mon Sep 17 00:00:00 2001 From: Anton Chuchkalov Date: Wed, 22 Jul 2015 20:29:42 +0400 Subject: [PATCH 6/7] add ability to view project stacks --- .../lib/devops-client/handler/project.rb | 18 +++++++++++++ .../devops-client/options/project_options.rb | 3 ++- .../lib/devops-client/output/project.rb | 15 ++++++++++- .../lib/devops-client/output/stack.rb | 4 +-- devops-client/locales/en.yml | 1 + devops-service/db/mongo/connectors/stack.rb | 5 ++-- .../routes/v2.0/handlers/project.rb | 10 +++++++ devops-service/routes/v2.0/handlers/stack.rb | 2 +- devops-service/routes/v2.0/project.rb | 27 +++++++++++++++++++ 9 files changed, 77 insertions(+), 8 deletions(-) diff --git a/devops-client/lib/devops-client/handler/project.rb b/devops-client/lib/devops-client/handler/project.rb index 6557a9f..f9b2211 100644 --- a/devops-client/lib/devops-client/handler/project.rb +++ b/devops-client/lib/devops-client/handler/project.rb @@ -49,6 +49,10 @@ class Project < Handler self.options = @options_parser.servers_options servers_handler @options_parser.args output(output_type: :servers) + when "stacks" + self.options = @options_parser.stacks_options + stacks_handler @options_parser.args + output(output_type: :stacks) when "set" case ARGV[2] when "run_list" @@ -162,6 +166,20 @@ class Project < Handler @servers = get "/project/#{args[2]}/servers", o end + def stacks_handler args + project, deploy_env = args[2], args[3] + r = inspect_parameters @options_parser.stacks_params, project, deploy_env + unless r.nil? + @options_parser.invalid_stacks_command + abort(r) + end + options = {} + unless deploy_env.nil? + options[:deploy_env] = deploy_env + end + @list = get "/project/#{args[2]}/stacks", options + end + def user_add_handler args r = inspect_parameters @options_parser.user_add_params, args[3], args[4] unless r.nil? diff --git a/devops-client/lib/devops-client/options/project_options.rb b/devops-client/lib/devops-client/options/project_options.rb index c6591ca..96ad738 100644 --- a/devops-client/lib/devops-client/options/project_options.rb +++ b/devops-client/lib/devops-client/options/project_options.rb @@ -3,7 +3,7 @@ require "set" class ProjectOptions < CommonOptions - commands :create, :delete, :deploy, :list, {:multi => [:create]}, :servers, {:set => [:run_list]}, :show, :test, :update, {:user => [:add, :delete]} + commands :create, :delete, :deploy, :list, {:multi => [:create]}, :servers, :stacks, {:set => [:run_list]}, :show, :test, :update, {:user => [:add, :delete]} def initialize args, def_options super(args, def_options) @@ -17,6 +17,7 @@ class ProjectOptions < CommonOptions self.deploy_params = [id, "[#{env}]"] self.set_run_list_params = [id, env, "[(recipe[mycookbook::myrecipe])|(role[myrole]) ...]"] self.servers_params = [id, "[#{env}]"] + self.stacks_params = [id, "[#{env}]"] self.multi_create_params = [id] self.update_params = [id, "FILE"] self.user_add_params = [id, "USER_NAME", "[USER_NAME ...]"] diff --git a/devops-client/lib/devops-client/output/project.rb b/devops-client/lib/devops-client/output/project.rb index 052b94b..256fd59 100644 --- a/devops-client/lib/devops-client/output/project.rb +++ b/devops-client/lib/devops-client/output/project.rb @@ -19,6 +19,11 @@ module Output title += " " + ARGV[3] unless ARGV[3].nil? title = I18n.t("output.title.project.servers", :title => title) create_servers(@data) + when :stacks + title = ARGV[2] + title += " " + ARGV[3] unless ARGV[3].nil? + title = I18n.t("output.title.project.stacks", :title => title) + create_stacks(@data) when :test title = I18n.t("output.title.project.test", :project => ARGV[2], :env => ARGV[3]) create_test(@data) @@ -101,7 +106,7 @@ module Output end def create_servers servers - abort(I18n.t("output.not_found.project.servers")) if servers.empty? + abort(I18n.t("output.not_found.project.servers", name: ARGV[2])) if servers.empty? rows = [] servers.each do |s| rows.push [ s["project"], s["deploy_env"], s["chef_node_name"], s["remote_user"], s["provider"], s["id"] ] @@ -136,5 +141,13 @@ module Output return headers, rows end + def create_stacks(stacks) + abort(I18n.t("output.not_found.project.stacks", name: ARGV[2])) if stacks.empty? + + fields_to_output = %w(id deploy_env stack_template cloud_stack_id stack_status provider) + + headers_and_rows(stacks, fields_to_output) + end + end end diff --git a/devops-client/lib/devops-client/output/stack.rb b/devops-client/lib/devops-client/output/stack.rb index 3731412..2051fae 100644 --- a/devops-client/lib/devops-client/output/stack.rb +++ b/devops-client/lib/devops-client/output/stack.rb @@ -37,14 +37,14 @@ module Output def create_list abort(I18n.t("output.not_found.stack.list")) if @data.empty? - fields_to_output = %w(id deploy_env stack_template cloud_stack_id stack_status) + fields_to_output = %w(id project deploy_env stack_template cloud_stack_id stack_status) fields_to_output << 'provider' unless provider_given? headers_and_rows(@data, fields_to_output) end def create_show - headers_and_rows([@data], %w(id deploy_env stack_template cloud_stack_id stack_status)) + headers_and_rows([@data], %w(id project deploy_env stack_template cloud_stack_id stack_status)) end def create_servers_list diff --git a/devops-client/locales/en.yml b/devops-client/locales/en.yml index 1797aba..a67352d 100644 --- a/devops-client/locales/en.yml +++ b/devops-client/locales/en.yml @@ -259,6 +259,7 @@ en: project: list: "No project found" servers: "No servers for project '%{name}' found" + stacks: "No stacks for project '%{name}' found" provider: list: "Empty providers list" script: diff --git a/devops-service/db/mongo/connectors/stack.rb b/devops-service/db/mongo/connectors/stack.rb index d051670..3024821 100644 --- a/devops-service/db/mongo/connectors/stack.rb +++ b/devops-service/db/mongo/connectors/stack.rb @@ -10,9 +10,8 @@ module Connectors self.collection = db.collection('stacks') end - def stacks(provider=nil) - query = (provider.nil? ? {} : {'provider' => provider}) - list(query) + def stacks(options={}) + list(options) end private diff --git a/devops-service/routes/v2.0/handlers/project.rb b/devops-service/routes/v2.0/handlers/project.rb index e6b0eb0..de941a6 100644 --- a/devops-service/routes/v2.0/handlers/project.rb +++ b/devops-service/routes/v2.0/handlers/project.rb @@ -42,6 +42,16 @@ module Devops } end + def self.get_project_stacks + lambda { + check_privileges("project", "r") + settings.mongo.project(params[:project]) + options = {project: params[:project]} + options[:deploy_env] = params[:deploy_env] if params[:deploy_env] + json settings.mongo.stacks(options).map{|s| s.to_hash} + } + end + # TODO: multi project def self.create_project lambda { diff --git a/devops-service/routes/v2.0/handlers/stack.rb b/devops-service/routes/v2.0/handlers/stack.rb index c8a9731..5dc410e 100644 --- a/devops-service/routes/v2.0/handlers/stack.rb +++ b/devops-service/routes/v2.0/handlers/stack.rb @@ -17,7 +17,7 @@ module Devops lambda { check_privileges("stack", "r") check_provider(params[:provider]) - stacks = settings.mongo.stacks(params[:provider]) + stacks = settings.mongo.stacks(provider: params[:provider]) json stacks.map(&:to_hash) } end diff --git a/devops-service/routes/v2.0/project.rb b/devops-service/routes/v2.0/project.rb index 7a2eb1c..b314c21 100644 --- a/devops-service/routes/v2.0/project.rb +++ b/devops-service/routes/v2.0/project.rb @@ -137,6 +137,33 @@ module Devops # ] app.get_with_headers "/project/:project/servers", :headers => [:accept], &Devops::Version2_0::Handler::Project.get_project_servers + # Get project stacks + # + # * *Request* + # - method : GET + # - headers : + # - Accept: application/json + # - parameters : + # - deploy_env=:env -> show stacks with environment :env + # + # * *Returns* : + # [ + # "provider": "openstack", + # "project": "test_openstack", + # "deploy_env": "test", + # "stack_template": "openstack_template", + # "cloud_stack_id": "4c712026-dcd5-4664-90b8-0915494c1332", + # "parameters": { + # "admin_pass": "Pass12", + # "key_name": "devops", + # "image": "CirrOS_0.3.1" + # }, + # "details": null, + # "stack_status": null, + # "id": "openstack_stack" + # ] + app.get_with_headers "/project/:project/stacks", :headers => [:accept], &Devops::Version2_0::Handler::Project.get_project_stacks + # Create project and chef roles # # * *Request* From 673c74aa3ac2c9dbf16b9c2ada1da2ecb860bcce Mon Sep 17 00:00:00 2001 From: Anton Chuchkalov Date: Thu, 23 Jul 2015 13:54:36 +0400 Subject: [PATCH 7/7] provide convinient way to start jobs --- devops-service/commands/commands_storage.rb | 9 +++++ devops-service/commands/stack.rb | 35 +++++++++++++++++-- .../db/mongo/models/stack/stack_base.rb | 1 + .../routes/v2.0/handlers/stack_preset.rb | 17 +++------ devops-service/workers/job_starter.rb | 28 +++++++++++++++ devops-service/workers/stack_sync_worker.rb | 18 +++++----- devops-service/workers/workers_storage.rb | 9 +++++ 7 files changed, 95 insertions(+), 22 deletions(-) create mode 100644 devops-service/commands/commands_storage.rb create mode 100644 devops-service/workers/job_starter.rb create mode 100644 devops-service/workers/workers_storage.rb diff --git a/devops-service/commands/commands_storage.rb b/devops-service/commands/commands_storage.rb new file mode 100644 index 0000000..97a255c --- /dev/null +++ b/devops-service/commands/commands_storage.rb @@ -0,0 +1,9 @@ +module CommandsStorage + def self.add_job_lambda(job_with_lambda) + job_lambdas.merge!(job_with_lambda) + end + + def self.job_lambdas + @job_lambdas ||= {} + end +end \ No newline at end of file diff --git a/devops-service/commands/stack.rb b/devops-service/commands/stack.rb index 0ea2316..fb60cfc 100644 --- a/devops-service/commands/stack.rb +++ b/devops-service/commands/stack.rb @@ -1,9 +1,14 @@ +require "commands/server" +require 'commands/commands_storage' + module StackCommands + include ServerCommands + extend self def sync_stack_till_not_in_progress_proc lambda do |out, stack, mongo| - # two tries each 5 seconds, then 5 tries each 10 seconds, then 5 tries each minute. - sleep_times = [5]*2 + [10]*5 + [60]*5 + # two tries each 2 seconds, then 5 tries each 10 seconds, then 5 tries each minute. + sleep_times = [2]*2 + [10]*5 + [60]*5 begin out << "Syncing stack '#{stack.id}'...\n" @@ -24,4 +29,30 @@ module StackCommands end end + def create_devops_servers_from_stack_resources + lambda do |out, stack, mongo, owner| + project = mongo.project(stack.project) + deploy_env = project.deploy_envs.detect {|env| env.identifier == stack.deploy_env} + provider = ::Provider::ProviderFactory.get(stack.provider) + + stack.resources.each do |resource| + logical_name = resource['resource_name'] + attrs = stack.resource(logical_name) + body = { + 'name' => logical_name, + 'key' => attrs['key_name'] + } + + server = extract_servers(provider, project, deploy_env, body, owner, mongo) + server.private_ip = attrs['addresses']['devops-net-1'].first['addr'] + + end + end + end + + CommandsStorage.add_job_lambda( + sync_stack_till_not_in_progress: sync_stack_till_not_in_progress_proc, + create_devops_servers_from_stack_resources: create_devops_servers_from_stack_resources + ) + end diff --git a/devops-service/db/mongo/models/stack/stack_base.rb b/devops-service/db/mongo/models/stack/stack_base.rb index 3ae32c9..b704aea 100644 --- a/devops-service/db/mongo/models/stack/stack_base.rb +++ b/devops-service/db/mongo/models/stack/stack_base.rb @@ -59,6 +59,7 @@ module Devops provider_class.stack_resources(self) end + # resource_id is logical def resource(resource_id) provider_class.stack_resource(self, resource_id) end diff --git a/devops-service/routes/v2.0/handlers/stack_preset.rb b/devops-service/routes/v2.0/handlers/stack_preset.rb index 63f5682..2cf3953 100644 --- a/devops-service/routes/v2.0/handlers/stack_preset.rb +++ b/devops-service/routes/v2.0/handlers/stack_preset.rb @@ -1,6 +1,7 @@ require 'json' require 'lib/stack_presets/factory' require 'workers/stack_sync_worker' +require 'workers/job_starter' module Devops module Version2_0 @@ -31,19 +32,11 @@ module Devops stack = preset.create_stack_from_preset(attrs) settings.mongo.stack_insert(stack) - - jid = StackSyncWorker.perform_async( - DevopsConfig[:report_dir_v2], - stack.provider, - stack.id, - request.env['REMOTE_USER'], # owner - DevopsConfig.config + file = JobStarter.start_job(:worker, :sync_stack_till_not_in_progress, + provider: stack.provider, + stack_id: stack.id, + request: request ) - Worker.set_status jid, Worker::STATUS::IN_QUEUE - logger.info "Job '#{jid}' has been started" - uri = URI.parse(request.url) - uri.path = "#{DevopsConfig[:url_prefix]}/v2.0/report/" + jid - file = uri.to_s puts "Syncing report is located here: #{file}" diff --git a/devops-service/workers/job_starter.rb b/devops-service/workers/job_starter.rb new file mode 100644 index 0000000..052874c --- /dev/null +++ b/devops-service/workers/job_starter.rb @@ -0,0 +1,28 @@ +require 'commands/commands_storage' +require 'workers/workers_storage' + +module JobStarter + def self.start_job(strategy, job_name, job_options) + case strategy + when :worker + start_job_as_worker(WorkersStorage.workers[job_name], job_options) + end + end + + def self.start_job_as_worker(worker_class, options) + job_options = options.dup + job_options[:owner] ||= options[:request].env['REMOTE_USER'] + job_options[:config] ||= DevopsConfig.config + job_options[:dir] ||= DevopsConfig[:report_dir_v2] + job_options[:url] ||= options[:request].url + + jid = worker_class.perform_async(job_options) + Worker.set_status jid, Worker::STATUS::IN_QUEUE + DevopsLogger.logger.info "Job '#{jid}' has been started" + + + uri = URI.parse(job_options[:url]) + uri.path = "#{job_options[:config][:url_prefix]}/v2.0/report/#{jid}" + uri.to_s + end +end diff --git a/devops-service/workers/stack_sync_worker.rb b/devops-service/workers/stack_sync_worker.rb index 7400436..1258beb 100644 --- a/devops-service/workers/stack_sync_worker.rb +++ b/devops-service/workers/stack_sync_worker.rb @@ -1,22 +1,22 @@ -#root = File.join(File.dirname(__FILE__), "..") -#$LOAD_PATH.push root unless $LOAD_PATH.include? root - -# require File.join(File.dirname(__FILE__), "workers") require "providers/provider_factory" require "commands/stack" require "db/mongo/models/stack/stack_factory" require "db/mongo/models/report" +require 'workers/workers_storage' class StackSyncWorker < Worker include StackCommands - def perform(dir, provider, stack_id, owner, conf) - call(conf, provider, dir) do |mongo, provider, out, file| - stack = mongo.stack(stack_id) + # besides options came from JobStarter we need: + # :provider + # :stack_id + def perform(options) + call(options['config'], options['provider'], options['dir']) do |mongo, provider, out, file| + stack = mongo.stack(options['stack_id']) o = { "file" => file, "_id" => jid, - "created_by" => owner, + "created_by" => options['owner'], "project" => stack.project, "deploy_env" => stack.deploy_env, "type" => ::Devops::Model::Report::STACK_TYPE @@ -28,3 +28,5 @@ class StackSyncWorker < Worker end end end + +WorkersStorage.add_worker(sync_stack_till_not_in_progress: StackSyncWorker) diff --git a/devops-service/workers/workers_storage.rb b/devops-service/workers/workers_storage.rb new file mode 100644 index 0000000..d789fd5 --- /dev/null +++ b/devops-service/workers/workers_storage.rb @@ -0,0 +1,9 @@ +module WorkersStorage + def self.add_worker(job_with_worker) + workers.merge!(job_with_worker) + end + + def self.workers + @job_workers ||= {} + end +end \ No newline at end of file