From f02b905716aeb1e34c8cb1f526e5179556e02a57 Mon Sep 17 00:00:00 2001 From: Anton Chuchkalov Date: Tue, 1 Sep 2015 16:31:31 +0300 Subject: [PATCH] refactore job starter --- devops-service/app/api2/handlers/key.rb | 3 +- devops-service/app/api2/handlers/stack.rb | 21 +-- .../app/api2/handlers/stack_preset.rb | 1 - devops-service/commands/commands_storage.rb | 9 -- devops-service/commands/stack.rb | 8 +- devops-service/config.ru | 8 +- devops-service/core/devops-config.rb | 2 + .../lib/executors/server_executor.rb | 2 +- devops-service/workers/job_starter.rb | 27 ---- .../workers/stack_bootstrap_worker.rb | 58 ++++---- devops-service/workers/worker.rb | 139 ++++++++++++------ devops-service/workers/workers_storage.rb | 9 -- 12 files changed, 133 insertions(+), 154 deletions(-) delete mode 100644 devops-service/commands/commands_storage.rb delete mode 100644 devops-service/workers/job_starter.rb delete mode 100644 devops-service/workers/workers_storage.rb diff --git a/devops-service/app/api2/handlers/key.rb b/devops-service/app/api2/handlers/key.rb index 2cfd872..eb1a228 100644 --- a/devops-service/app/api2/handlers/key.rb +++ b/devops-service/app/api2/handlers/key.rb @@ -11,7 +11,8 @@ module Devops set_parser Devops::API2_0::Parser::KeyParser def keys - Devops::Db.connector.keys({}, {path: false}) + # Devops::Db.connector.keys({}, {path: false}) + Devops::Db.connector.keys({}) end def create diff --git a/devops-service/app/api2/handlers/stack.rb b/devops-service/app/api2/handlers/stack.rb index 0dbc850..a8a695d 100644 --- a/devops-service/app/api2/handlers/stack.rb +++ b/devops-service/app/api2/handlers/stack.rb @@ -18,20 +18,6 @@ module Devops Devops::Db.connector.stacks(provider) end -=begin - def create_stack object - object[:owner] = owner_from_request - file = JobStarter.start_job(:worker, :stack_bootstrap, - provider: object['provider'], - stack_attributes: object, - request: @request - ) - puts "Syncing report is located here: #{file}" - - stack - end -=end - def create_stack object = parser.create project = Devops::Db.connector.project(object["project"]) @@ -40,10 +26,9 @@ module Devops object["stack_template"] = env.stack_template object["owner"] = parser.current_user - file = JobStarter.start_job(:worker, :stack_bootstrap, - provider: env.provider, - stack_attributes: object, - request: @request + file = Worker.start_async(StackBootstrapWorker, @request, + provider_name: env.provider, + stack_attributes: object ) puts "Syncing report is located here: #{file}" [file] diff --git a/devops-service/app/api2/handlers/stack_preset.rb b/devops-service/app/api2/handlers/stack_preset.rb index cd4bb71..f812f9f 100644 --- a/devops-service/app/api2/handlers/stack_preset.rb +++ b/devops-service/app/api2/handlers/stack_preset.rb @@ -1,7 +1,6 @@ require 'json' require 'lib/stack_presets/factory' require 'workers/stack_bootstrap_worker' -require 'workers/job_starter' require "app/api2/parsers/stack_preset" require_relative "request_handler" diff --git a/devops-service/commands/commands_storage.rb b/devops-service/commands/commands_storage.rb deleted file mode 100644 index 97a255c..0000000 --- a/devops-service/commands/commands_storage.rb +++ /dev/null @@ -1,9 +0,0 @@ -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 e2742e0..862794d 100644 --- a/devops-service/commands/stack.rb +++ b/devops-service/commands/stack.rb @@ -1,9 +1,7 @@ -require 'commands/commands_storage' - module StackCommands extend self - def sync_bootstrap_proc + def sync_stack_proc lambda do |out, stack, mongo| # two tries each 4 seconds, then 5 tries each 10 seconds, then 10 tries each 30 seconds. sleep_times = [4]*2 + [10]*5 + [30]*10 @@ -47,8 +45,4 @@ module StackCommands end =end - CommandsStorage.add_job_lambda( - sync_bootstrap: sync_bootstrap_proc - ) - end diff --git a/devops-service/config.ru b/devops-service/config.ru index 6626b13..d64be0c 100644 --- a/devops-service/config.ru +++ b/devops-service/config.ru @@ -21,10 +21,10 @@ unless File.exists?(config[:devops_dir]) puts "Directory '#{config[:devops_dir]}' has been created" end -config[:report_dir_v2] = File.expand_path(File.join(config[:devops_dir], "report", "v2")) unless config[:report_dir_v2] -[ - :report_dir_v2 -].each {|key| d = config[key]; FileUtils.mkdir_p(d) unless File.exists?(d) } +[:report_dir_v2].each do |key| + directory = config[key] + FileUtils.mkdir_p(directory) unless File.exists?(directory) +end DevopsService.init puts Devops::Routes.routes diff --git a/devops-service/core/devops-config.rb b/devops-service/core/devops-config.rb index 2e16dba..c319ba9 100644 --- a/devops-service/core/devops-config.rb +++ b/devops-service/core/devops-config.rb @@ -27,6 +27,8 @@ class DevopsConfig addr.ip_address end + config[:report_dir_v2] = File.expand_path(File.join(config[:devops_dir], "report", "v2")) + DevopsConfig.config = config end diff --git a/devops-service/lib/executors/server_executor.rb b/devops-service/lib/executors/server_executor.rb index af27aa5..92543bb 100644 --- a/devops-service/lib/executors/server_executor.rb +++ b/devops-service/lib/executors/server_executor.rb @@ -199,7 +199,7 @@ module Devops # @out << roll_back # mongo.server_delete @server.id end - return status + status end def check_server diff --git a/devops-service/workers/job_starter.rb b/devops-service/workers/job_starter.rb deleted file mode 100644 index bfa6299..0000000 --- a/devops-service/workers/job_starter.rb +++ /dev/null @@ -1,27 +0,0 @@ -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[: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_bootstrap_worker.rb b/devops-service/workers/stack_bootstrap_worker.rb index 5e958a4..a300a65 100644 --- a/devops-service/workers/stack_bootstrap_worker.rb +++ b/devops-service/workers/stack_bootstrap_worker.rb @@ -7,46 +7,50 @@ require "db/mongo/models/report" class StackBootstrapWorker < Worker include StackCommands - # besides options came from JobStarter we need: - # :provider - # :stack_id def perform(options) - call(options['config'], options['provider'], options['dir']) do |provider, out, file| - attrs = options['stack_attributes'] - mongo = ::Devops::Db.connector - report = ::Devops::Model::Report.new( - "file" => file, - "_id" => jid, - "created_by" => attrs['owner'], - "project" => attrs["project"], - "deploy_env" => attrs["deploy_env"], - "type" => ::Devops::Model::Report::STACK_TYPE - ) - mongo.save_report(report) + provider_name = options.fetch('provider_name') + stack_attrs = options.fetch('stack_attributes') - stack = Devops::Model::StackFactory.create(options['provider'], options['stack_attributes'], out) -# stack.owner = attrs['owner'] + call(provider_name) do |provider, out, file| + without_bootstrap = stack_attrs.delete('without_bootstrap') + save_report(file, stack_attrs) + + stack = Devops::Model::StackFactory.create(provider_name, stack_attrs, out) mongo.stack_insert(stack) - r = sync_bootstrap_proc.call(out, stack, mongo) - if r == 0 + operation_result = sync_stack_proc.call(out, stack, mongo) + if operation_result == 0 out << "\nStack '#{stack.name}' has been created\n" out.flush servers = persist_stack_servers!(stack, provider) - out << "\n" - unless attrs['without_bootstrap'] - statuses = servers.map do |s| - Devops::Executor::ServerExecutor.new(s, out).two_phase_bootstrap({}) - end - end + bootstrap_servers(servers, out) unless without_bootstrap end + operation_result end end private + def bootstrap_servers(servers, out) + out << "\n" + servers.map do |server| + Devops::Executor::ServerExecutor.new(server, out).two_phase_bootstrap({}) + end + end + + def save_report(file, stack_attrs) + report = ::Devops::Model::Report.new( + "file" => file, + "_id" => jid, + "created_by" => stack_attrs['owner'], + "project" => stack_attrs["project"], + "deploy_env" => stack_attrs["deploy_env"], + "type" => ::Devops::Model::Report::STACK_TYPE + ) + mongo.save_report(report) + end + def persist_stack_servers!(stack, provider) - mongo = ::Devops::Db.connector project = mongo.project(stack.project) deploy_env = project.deploy_env(stack.deploy_env) @@ -74,5 +78,3 @@ class StackBootstrapWorker < Worker end end - -WorkersStorage.add_worker(stack_bootstrap: StackBootstrapWorker) diff --git a/devops-service/workers/worker.rb b/devops-service/workers/worker.rb index 6d6a628..bbb783b 100644 --- a/devops-service/workers/worker.rb +++ b/devops-service/workers/worker.rb @@ -11,7 +11,6 @@ require "core/devops-config" require "core/devops-logger" require "core/devops-db" require "providers/provider_factory" -require 'workers/workers_storage' require "lib/knife/knife_factory" class Worker @@ -25,6 +24,95 @@ class Worker IN_QUEUE = "queued" end + def self.start_async(worker_class, request, job_options) + jid = worker_class.perform_async(job_options.dup) + Worker.set_status jid, Worker::STATUS::IN_QUEUE + DevopsLogger.logger.info "Job '#{jid}' has been started" + + uri = URI.parse(request.url) + uri.path = "#{DevopsConfig[:url_prefix]}/v2.0/report/#{jid}" + uri.to_s + end + + def self.set_status id, status + Sidekiq.redis {|con| con.hset "devops", id, status} + end + + def call provider_name, &block + begin + initialize_devops(provider_name) + provider = ::Provider::ProviderFactory.get(provider_name) if provider_name + if jid + call_async(provider, &block) + else + call_sync(provider, &block) + end + rescue StandardError => e + puts e.message + puts e.backtrace.join("\n") + DevopsLogger.logger.error e.message + end + end + + private + + def initialize_devops(provider_name) + DevopsLogger.logger = logger + DevopsConfig.read + DevopsService.init + ::Provider::ProviderFactory.init(DevopsConfig.config) + end + + # outputs to file + def call_async(provider) + dir = DevopsConfig[:report_dir_v2] + # directory is created on server start in config.ru + file = File.join(dir, jid) + + update_job_status(STATUS::INIT) + File.open(file, "w") do |out| + begin + update_job_status(STATUS::RUNNING) + + job_result = yield(provider, out, file) + canonical_status = (job_result == 0 ? STATUS::COMPLETED : STATUS::FAILED) + update_job_status(canonical_status) + rescue StandardError, RecordNotFound => e + out << "\n #{e.class}\n #{e.message}\n" + out << e.backtrace.join("\n") + update_job_status(STATUS::FAILED) + end + end + end + + # outputs to STDOUT + def call_sync + out = STDOUT + begin + yield(provider, out, '') + rescue StandardError, RecordNotFound => e + out << "\n" + out << e.message + out << "\n" + out << e.backtrace.join("\n") + end + end + + def mongo + ::Devops::Db.connector + end + + def update_job_status(status) + set_status(jid, status) + mongo.set_report_status(jid, status) + status + end + + def init_provider(provider_name) + ::Provider::ProviderFactory.init(DevopsConfig.config) + ::Provider::ProviderFactory.get(provider_name) if provider_name + end + def convert_config conf config = {} conf.each {|k,v| config[k.is_a?(String) ? k.to_sym : k] = v} @@ -33,54 +121,7 @@ class Worker end def set_status id, status - Sidekiq.redis {|con| con.hset "devops", id, status} - end - - # it is called from creating server handler. But maybe we can somehow refactore code - # to get rid of duplication? - # TODO: check it - def self.set_status id, status - Sidekiq.redis {|con| con.hset "devops", id, status} - end - - def call conf, e_provider, dir - DevopsLogger.logger = logger - FileUtils.mkdir_p(dir) unless File.exists?(dir) - set_status jid, "init" - DevopsConfig.config = convert_config(conf) - DevopsService.init - file = File.join(dir, jid) - error = nil - provider = nil - begin - ::Provider::ProviderFactory.init(DevopsConfig.config) - unless e_provider.nil? - provider = ::Provider::ProviderFactory.get(e_provider) - end - rescue Exception => e - error = e - DevopsLogger.logger.error e.message - return - end - mongo = ::Devops::Db.connector - File.open(file, "w") do |out| - begin - set_status jid, STATUS::RUNNING - raise error unless error.nil? - status = yield(provider, out, file) - status = (status == 0 ? STATUS::COMPLETED : STATUS::FAILED) - set_status jid, status - mongo.set_report_status(jid, status) - status - rescue Exception => e - out << "\n" - out << e.message - out << "\n" - out << e.backtrace.join("\n") - set_status jid, STATUS::FAILED - mongo.set_report_status(jid, STATUS::FAILED) unless mongo.nil? - end - end + self.class.set_status(id, status) end end diff --git a/devops-service/workers/workers_storage.rb b/devops-service/workers/workers_storage.rb deleted file mode 100644 index d789fd5..0000000 --- a/devops-service/workers/workers_storage.rb +++ /dev/null @@ -1,9 +0,0 @@ -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