diff --git a/devops-client/lib/devops-client/handler/handler_factory.rb b/devops-client/lib/devops-client/handler/handler_factory.rb index e1f9d9c..c5b7898 100644 --- a/devops-client/lib/devops-client/handler/handler_factory.rb +++ b/devops-client/lib/devops-client/handler/handler_factory.rb @@ -47,9 +47,9 @@ class HandlerFactory when "stack_template" require "devops-client/handler/stack_template" StackTemplate - when "stack_template_preset" - require "devops-client/handler/stack_template_preset" - StackTemplatePreset + when "stack_preset" + require "devops-client/handler/stack_preset" + StackPreset when "stack" require "devops-client/handler/stack" Stack diff --git a/devops-client/lib/devops-client/handler/helpers/outputtable.rb b/devops-client/lib/devops-client/handler/helpers/outputtable.rb index 9414054..8cb52b1 100644 --- a/devops-client/lib/devops-client/handler/helpers/outputtable.rb +++ b/devops-client/lib/devops-client/handler/helpers/outputtable.rb @@ -13,8 +13,8 @@ module Outputtable @outputter ||= outputter_class.new(data_to_output, options, additional_output_options) end - def output - outputter.output + def output(preferred_format=nil) + outputter.output(preferred_format) end diff --git a/devops-client/lib/devops-client/handler/stack.rb b/devops-client/lib/devops-client/handler/stack.rb index ef16309..2625d3e 100644 --- a/devops-client/lib/devops-client/handler/stack.rb +++ b/devops-client/lib/devops-client/handler/stack.rb @@ -13,7 +13,6 @@ class Stack < Handler end def handle - current_command = ARGV[1].to_sym @options, @args = @options_parser.parse_options_for!(current_command) case current_command when :list @@ -26,6 +25,12 @@ class Stack < Handler create_handler when :delete delete_handler + when :sync + sync_handler + output + when :resources + resources_handler + output('json') end end @@ -63,6 +68,30 @@ class Stack < Handler @show = get "/stack/#{stack_id}" end + def sync_handler + stack_id = @args[2] + r = inspect_parameters(@options_parser.sync_params, stack_id) + unless r.nil? + @options_parser.invalid_sync_command + abort(r) + end + @show = post "/stack/#{stack_id}/sync_details" + end + + def resources_handler + stack_id, resource_id = @args[2], @args[3] + r = inspect_parameters(@options_parser.sync_params, stack_id) + unless r.nil? + @options_parser.invalid_sync_command + abort(r) + end + if resource_id + @list = get "/stack/#{stack_id}/resources/#{resource_id}" + else + @list = get "/stack/#{stack_id}/resources" + end + end + def delete_handler stack_id = @args[2] r = inspect_parameters(@options_parser.delete_params, stack_id) diff --git a/devops-client/lib/devops-client/handler/stack_template_preset.rb b/devops-client/lib/devops-client/handler/stack_preset.rb similarity index 53% rename from devops-client/lib/devops-client/handler/stack_template_preset.rb rename to devops-client/lib/devops-client/handler/stack_preset.rb index 674284e..b1e9073 100644 --- a/devops-client/lib/devops-client/handler/stack_template_preset.rb +++ b/devops-client/lib/devops-client/handler/stack_preset.rb @@ -1,15 +1,14 @@ require "devops-client/handler/handler" -require "devops-client/options/stack_template_preset_options" -require "devops-client/output/stack_template_preset" -# require 'devops-client/helpers/select_available' +require "devops-client/options/stack_preset_options" +require "devops-client/output/stack_preset" -class StackTemplatePreset < Handler +class StackPreset < Handler - output_with Output::StackTemplatePreset + output_with Output::StackPreset def initialize(host, def_options={}) @host, @options = host, def_options - @options_parser = StackTemplatePresetOptions.new(ARGV, def_options) + @options_parser = StackPresetOptions.new(ARGV, def_options) end def handle @@ -21,8 +20,9 @@ class StackTemplatePreset < Handler when :show show_handler output - when :build - build_handler + when :apply + apply_handler + output end end @@ -32,29 +32,31 @@ class StackTemplatePreset < Handler @options_parser.invalid_show_command abort(wrong_params) end - @show = get "/stack_template_presets/#{@args[2]}" + @show = get "/stack_presets/#{@args[2]}" end def list_handler - @list = get('/stack_template_presets') + @list = get('/stack_presets') end - def build_handler - wrong_params = inspect_parameters(@options_parser.build_params, @args[2]) + def apply_handler + wrong_params = inspect_parameters(@options_parser.apply_params, @args[2]) if wrong_params - @options_parser.invalid_build_command + @options_parser.invalid_apply_command abort(wrong_params) end params = {} params[:id] = @args[2] params[:provider] = options[:provider] || resources_selector.select_available_provider - params[:stack] = options[:stack] || enter_parameter(I18n.t('handler.stack_template_preset.create.stack')) + params[:stack] = options[:stack] || enter_parameter(I18n.t('handler.stack_preset.create.stack')) + params[:project] = options[:project] || resources_selector.select_available_project + params[:deploy_env] = options[:deploy_env] || enter_parameter(I18n.t('handler.stack.create.deploy_env')) - filepath = options[:parameters_file] || enter_parameter(I18n.t('handler.stack_template_preset.create.parameters_file')) + 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_template_presets/#{params[:id]}/build_stack_template", 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_options.rb b/devops-client/lib/devops-client/options/stack_options.rb index f824002..ac64fe7 100644 --- a/devops-client/lib/devops-client/options/stack_options.rb +++ b/devops-client/lib/devops-client/options/stack_options.rb @@ -2,7 +2,7 @@ require "devops-client/options/common_options" class StackOptions < CommonOptions - commands :create, :delete, :list, :show + commands :create, :delete, :list, :show, :sync, :resources def initialize args, def_options super(args, def_options) @@ -11,6 +11,8 @@ class StackOptions < CommonOptions self.list_params = ["[provider]", "[ec2|openstack]"] self.show_params = ["STACK"] self.delete_params = ["STACK"] + self.sync_params = ["STACK"] + self.resources_params = ["STACK"] end def create_options diff --git a/devops-client/lib/devops-client/options/stack_preset_options.rb b/devops-client/lib/devops-client/options/stack_preset_options.rb new file mode 100644 index 0000000..0c8fde4 --- /dev/null +++ b/devops-client/lib/devops-client/options/stack_preset_options.rb @@ -0,0 +1,35 @@ +require "devops-client/options/common_options" + +class StackPresetOptions < CommonOptions + + commands :list, :show, :apply + + def initialize args, def_options + super(args, def_options) + self.header = I18n.t("headers.stack_preset") + self.banner_header = "stack_preset" + self.list_params = ["[provider]", "[ec2|openstack]"] + self.show_params = ["STACK"] + self.apply_params = ["PRESET"] + end + + def apply_options + self.options do |parser, options| + parser.banner << self.apply_banner + + parser.recognize_option_value(:provider, 'stack_preset') + parser.recognize_option_value(:project, 'stack_preset') + parser.recognize_option_value(:deploy_env, 'stack_preset') + parser.recognize_option_value(:stack, 'stack_preset') + parser.recognize_option_value(:parameters_file, 'stack_preset') + end + end + + + extend_options_method :list_options do |options| + if args[2] + options[:given_provider] = args[2] + end + end + +end diff --git a/devops-client/lib/devops-client/options/stack_template_preset_options.rb b/devops-client/lib/devops-client/options/stack_template_preset_options.rb deleted file mode 100644 index 237503d..0000000 --- a/devops-client/lib/devops-client/options/stack_template_preset_options.rb +++ /dev/null @@ -1,33 +0,0 @@ -require "devops-client/options/common_options" - -class StackTemplatePresetOptions < CommonOptions - - commands :list, :show, :build - - def initialize args, def_options - super(args, def_options) - self.header = I18n.t("headers.stack_template_preset") - self.banner_header = "stack_template_preset" - self.list_params = ["[provider]", "[ec2|openstack]"] - self.show_params = ["STACK"] - self.build_params = ["PRESET"] - end - - def build_options - self.options do |parser, options| - parser.banner << self.build_banner - - parser.recognize_option_value(:provider, 'stack_template_preset') - parser.recognize_option_value(:stack, 'stack_template_preset') - parser.recognize_option_value(:parameters_file, 'stack_template_preset') - end - end - - - extend_options_method :list_options do |options| - if args[2] - options[:given_provider] = args[2] - end - end - -end diff --git a/devops-client/lib/devops-client/output/base.rb b/devops-client/lib/devops-client/output/base.rb index b7049bb..04a1a42 100644 --- a/devops-client/lib/devops-client/output/base.rb +++ b/devops-client/lib/devops-client/output/base.rb @@ -18,8 +18,9 @@ module Output @data, @options, @additional_options = data_to_output, command_line_options, additional_options end - def output - case options[:format] + def output(format = nil) + format ||= options[:format] + case format when CommonOptions::TABLE_FORMAT table when CommonOptions::JSON_FORMAT diff --git a/devops-client/lib/devops-client/output/stack.rb b/devops-client/lib/devops-client/output/stack.rb index e87d5ec..2cf9e09 100644 --- a/devops-client/lib/devops-client/output/stack.rb +++ b/devops-client/lib/devops-client/output/stack.rb @@ -10,6 +10,7 @@ module Output 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 @@ -30,14 +31,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) + fields_to_output = %w(id 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)) + headers_and_rows([@data], %w(id deploy_env stack_template cloud_stack_id stack_status)) end end diff --git a/devops-client/lib/devops-client/output/stack_template_preset.rb b/devops-client/lib/devops-client/output/stack_preset.rb similarity index 77% rename from devops-client/lib/devops-client/output/stack_template_preset.rb rename to devops-client/lib/devops-client/output/stack_preset.rb index 6e61349..184c944 100644 --- a/devops-client/lib/devops-client/output/stack_template_preset.rb +++ b/devops-client/lib/devops-client/output/stack_preset.rb @@ -1,11 +1,11 @@ require "devops-client/output/base" module Output - class StackTemplatePreset < Base + class StackPreset < Base def table if outputting_list? - title = I18n.t("output.title.stack_template_preset.list") + title = I18n.t("output.title.stack_preset.list") headers, rows = create_list create_table headers, rows, title, with_num? else @@ -29,7 +29,7 @@ module Output private def create_list - abort(I18n.t("output.not_found.stack_template_preset.list")) if @data.empty? + abort(I18n.t("output.not_found.stack_preset.list")) if @data.empty? fields_to_output = %w(id) diff --git a/devops-client/locales/en.yml b/devops-client/locales/en.yml index f121224..1797aba 100644 --- a/devops-client/locales/en.yml +++ b/devops-client/locales/en.yml @@ -43,7 +43,7 @@ en: user: "User" stack: "Stack" stack_template: "Stack template" - stack_template_preset: "Stack template preset" + stack_preset: "Stack template preset" handler: flavor: list: @@ -118,10 +118,10 @@ en: question: create: "Are you sure to create stack?" delete: "Are you sure to delete stack '%{name}'?" - stack_template_preset: + stack_preset: create: parameters_file: 'Path to file with JSON parameters: ' - stack_template: 'Name of stack template to build: ' + stack: 'Name of stack to create: ' message: choose_list_default: "Choose %{name} (comma separated), like 1,2,3 or empty for default value '%{default}': " choose_list: "Choose %{name} (comma separated), like 1,2,3: " @@ -196,6 +196,7 @@ en: template_preset_body: "Template preset body" stack_template: "Stack Template" cloud_stack_id: "Cloud Stack id" + stack_status: Stack status title: flavor: list: "Flavors" @@ -234,7 +235,7 @@ en: stack_template: list: "Stack Templates" show: "Stack Template" - stack_template_preset: + stack_preset: list: "Stack Template Presets" show: "Stack Template Preset" stack: @@ -271,7 +272,7 @@ en: stack_template: list: "No stack templates found" show: "There isn't such stack template" - stack_template_preset: + stack_preset: list: "No stack template presets found" show: "There isn't such stack template preset" stack: @@ -377,7 +378,7 @@ en: provider: Stack template provider id: Stack template id template_file: Stack template file - stack_template_preset: + stack_preset: parameters_file: Path to file with JSON parameters stack: 'Name of stack to build: ' provider: Stack provider diff --git a/devops-service/app/api2/handlers/stack.rb b/devops-service/app/api2/handlers/stack.rb index b911acb..58566d3 100644 --- a/devops-service/app/api2/handlers/stack.rb +++ b/devops-service/app/api2/handlers/stack.rb @@ -10,8 +10,8 @@ module Devops Devops::Db.connector.stacks end - def stacks_for_provider - Devops::Db.connector.stacks(@params[:provider]) + def stacks_for_provider provider + Devops::Db.connector.stacks(provider) end def create_stack object @@ -30,6 +30,21 @@ module Devops Devops::Db.connector.stack_delete(id) end + def sync_details id + stack = self.stack(id) + stack.sync_details! + Devops::Db.connector.stack_update(stack) + end + + def resources id + stack = Devops::Db.connector.stack(id) + stack.resources + end + + def resources id, resource_id + stack = Devops::Db.connector.stack(id) + stack.resource(resource_id) + end end end end diff --git a/devops-service/app/api2/handlers/stack_preset.rb b/devops-service/app/api2/handlers/stack_preset.rb new file mode 100644 index 0000000..160afc1 --- /dev/null +++ b/devops-service/app/api2/handlers/stack_preset.rb @@ -0,0 +1,28 @@ +require 'json' +require 'lib/stack_presets/factory' +require_relative "request_handler" + +module Devops + module API2_0 + module Handler + class StackPreset < RequestHandler + + def presets + Devops::StackPresetsFactory.list + end + + def preset id + Devops::StackPresetsFactory.get(id) + end + + def apply id, body + preset = Devops::StackPresetsFactory.get(id) + preset.create_stack_from_preset(body) + Devops::Db.connector.stack_insert(stack) + end + + end + end + end +end + diff --git a/devops-service/app/api2/handlers/stack_template_preset.rb b/devops-service/app/api2/handlers/stack_template_preset.rb deleted file mode 100644 index 088bd32..0000000 --- a/devops-service/app/api2/handlers/stack_template_preset.rb +++ /dev/null @@ -1,29 +0,0 @@ -require 'json' -require 'lib/stack_template_presets/factory' -require_relative "request_handler" - -module Devops - module API2_0 - module Handler - class StackTemplatePreset < RequestHandler - - def templates - Devops::StackTemplatePresetsFactory.list - end - - def template id - Devops::StackTemplatePresetsFactory.get(id) - end - - def build_stack_template id, body - provider, stack_id, parameters = body.fetch('provider'), body.fetch('stack'), body.fetch('parameters') - - preset = Devops::StackTemplatePresetsFactory.get(id) - preset.create_stack_from_preset(provider, stack_id, parameters) - end - - end - end - end -end - diff --git a/devops-service/app/api2/routes/stack.rb b/devops-service/app/api2/routes/stack.rb index 05c9ce6..0b0144c 100644 --- a/devops-service/app/api2/routes/stack.rb +++ b/devops-service/app/api2/routes/stack.rb @@ -13,7 +13,7 @@ module Devops app.get_with_headers '/stacks/provider/:provider', :headers => [:accept] do |provider| check_privileges("stack", "r") check_provider(provider) - json Devops::API2_0::Handler::Stack.new(request, params).stacks_for_provider.map(&:to_hash) + json Devops::API2_0::Handler::Stack.new(request, params).stacks_for_provider(provider).map(&:to_hash) end app.post_with_headers "/stack", :headers => [:accept] do @@ -35,9 +35,23 @@ module Devops Devops::API2_0::Handler::Stack.new(request, params).delete_stack(stack_id) create_response("Stack '#{stack_id}' has been removed") } - app.multi_routes '/stack/:stack_id', {:headers => [:accept]}, hash + app.post_with_headers "/stack/:stack_id/sync_details", :headers => [:accept] do |stack_id| + check_privileges("stack", "w") + json Devops::API2_0::Handler::Stack.new(request, params).sync_details(stack_id).to_hash + end + + app.get_with_headers "/stack/:stack_id/resources", :headers => [:accept] do |stack_id| + check_privileges("stack", "r") + json Devops::API2_0::Handler::Stack.new(request, params).resources(stack_id) + end + + app.get_with_headers "/stack/:stack_id/resources/:resource_id", :headers => [:accept] do |stack_id, resource_id| + check_privileges("stack", "r") + json Devops::API2_0::Handler::Stack.new(request, params).resource(stack_id, resource_id) + end + puts "Stack routes initialized" end diff --git a/devops-service/app/api2/routes/stack_template_presets.rb b/devops-service/app/api2/routes/stack_presets.rb similarity index 74% rename from devops-service/app/api2/routes/stack_template_presets.rb rename to devops-service/app/api2/routes/stack_presets.rb index 1cf8b30..85c2889 100644 --- a/devops-service/app/api2/routes/stack_template_presets.rb +++ b/devops-service/app/api2/routes/stack_presets.rb @@ -1,7 +1,7 @@ module Devops module API2_0 module Routes - module StackTemplatePresetRoutes + module StackPresetRoutes def self.registered(app) # Get list of available stack_template_presets @@ -14,9 +14,9 @@ module Devops # * *Returns* : array of hashes # [ {id: 'preset id', template_preset_body: 'long body'} ] # - app.get_with_headers "/stack_template_presets", :headers => [:accept] do + app.get_with_headers "/stack_presets", :headers => [:accept] do # check_privileges("stack_template_presets", "r") - json Devops::API2_0::Handler::StackTemplatePreset.new(request, params).templates.map(&:to_hash) + json Devops::API2_0::Handler::StackPreset.new(request, params).presets.map(&:to_hash) end # Get information about stack_template_preset @@ -29,9 +29,9 @@ module Devops # * *Returns* : hash # {id: 'preset id', template_preset_body: 'long body'} # - app.get_with_headers "/stack_template_presets/:id", :headers => [:accept] do |id| + app.get_with_headers "/stack_presets/:id", :headers => [:accept] do |id| # check_privileges("stack_template_presets", "r") - json Devops::API2_0::Handler::StackTemplatePreset.new(request, params).template(id).to_hash + json Devops::API2_0::Handler::StackPreset.new(request, params).preset(id).to_hash end # Build stack template from preset @@ -54,11 +54,11 @@ module Devops # template_body: 'long body' # } # - app.post_with_headers "/stack_template_presets/:id/build_stack_template", :headers => [:accept] do |id| + app.post_with_headers "/stack_presets/:id/apply", :headers => [:accept] do |id| # check_privileges("stack_template_presets", "r") check_privileges('stack_template', 'w') body = create_object_from_json_body - stack = Devops::API2_0::Handler::StackTemplatePreset.new(request, params).build_stack_template(id, body) + stack = Devops::API2_0::Handler::StackPreset.new(request, params).apply(id, body) create_response 'Created', stack.to_hash, 201 end diff --git a/devops-service/app/devops-api2.rb b/devops-service/app/devops-api2.rb index b8be63d..32110d2 100644 --- a/devops-service/app/devops-api2.rb +++ b/devops-service/app/devops-api2.rb @@ -21,7 +21,7 @@ module Devops require_relative "api2/handlers/stack" require_relative "api2/handlers/stack_template" - require_relative "api2/handlers/stack_template_preset" + require_relative "api2/handlers/stack_preset" require 'lib/stubber' end @@ -58,6 +58,7 @@ module Devops require_relative "api2/routes/bootstrap_templates" require_relative "api2/routes/stack" require_relative "api2/routes/stack_template" + require_relative "api2/routes/stack_preset" require_relative "api2/routes/report" routes = Devops::API2_0::Routes.constants.collect{|s| Devops::API2_0::Routes.const_get(s)}.select {|const| const.class == Module} diff --git a/devops-service/config.rb b/devops-service/config.rb index 15b5b83..982b00b 100644 --- a/devops-service/config.rb +++ b/devops-service/config.rb @@ -40,4 +40,7 @@ config[:static_ssh_key] = "ssh_key" # or nil config[:static_certificate] = "/path/to/.ssh/static.pem" config[:debug] = true -config[:stub_classes] = true + +# set it to :all or [:ec2] to stub calls to selected providers +# or to false to disable stubbing +config[:stub_providers] = false diff --git a/devops-service/db/mongo/connectors/helpers/update_command.rb b/devops-service/db/mongo/connectors/helpers/update_command.rb index ac5d3bb..b661196 100644 --- a/devops-service/db/mongo/connectors/helpers/update_command.rb +++ b/devops-service/db/mongo/connectors/helpers/update_command.rb @@ -4,9 +4,8 @@ module Connectors module Helpers module UpdateCommand - # when included, this module adds method #update and alias for it. - # Alias name depends on base class name. - # We need this alias to forward methods from MongoConnector to resources connectors. + # this module adds methods #update and "#{resource_name}_update" (they are synonyms). + # We need second method name to forward methods from MongoConnector to resources connectors. def self.included(base) resource_name = StringHelper.underscore_class(base) diff --git a/devops-service/db/mongo/connectors/stack.rb b/devops-service/db/mongo/connectors/stack.rb index d2a7cac..d051670 100644 --- a/devops-service/db/mongo/connectors/stack.rb +++ b/devops-service/db/mongo/connectors/stack.rb @@ -3,7 +3,8 @@ module Connectors include Helpers::InsertCommand, Helpers::ShowCommand, Helpers::ListCommand, - Helpers::DeleteCommand + Helpers::DeleteCommand, + Helpers::UpdateCommand def initialize(db) self.collection = db.collection('stacks') diff --git a/devops-service/db/mongo/connectors/stack_template.rb b/devops-service/db/mongo/connectors/stack_template.rb index dc0b2f0..d1202b0 100644 --- a/devops-service/db/mongo/connectors/stack_template.rb +++ b/devops-service/db/mongo/connectors/stack_template.rb @@ -3,7 +3,8 @@ module Connectors include Helpers::InsertCommand, Helpers::ShowCommand, Helpers::ListCommand, - Helpers::DeleteCommand + Helpers::DeleteCommand, + Helpers::UpdateCommand def initialize(db) self.collection = db.collection('stack_templates') diff --git a/devops-service/db/mongo/models/project.rb b/devops-service/db/mongo/models/project.rb index fe68524..1fe6345 100644 --- a/devops-service/db/mongo/models/project.rb +++ b/devops-service/db/mongo/models/project.rb @@ -135,7 +135,7 @@ module Devops def to_hash_without_id h = {} h["deploy_envs"] = self.deploy_envs.map {|e| e.to_hash} unless self.deploy_envs.nil? - h["archived"] = self.archived + h["archived"] = self.archived if self.archived h["description"] = self.description if self.multi? h["type"] = MULTI_TYPE diff --git a/devops-service/db/mongo/models/stack/stack_base.rb b/devops-service/db/mongo/models/stack/stack_base.rb index dbcc6c2..ac7410f 100644 --- a/devops-service/db/mongo/models/stack/stack_base.rb +++ b/devops-service/db/mongo/models/stack/stack_base.rb @@ -2,26 +2,27 @@ module Devops module Model class StackBase < MongoModel - attr_accessor :id, :project, :deploy_env, :stack_template, :cloud_stack_id, :provider, :parameters, :template_body + attr_accessor :id, :project, :deploy_env, :stack_template, + :cloud_stack_id, :provider, :parameters, :details types id: {type: String, empty: false}, provider: {type: String, empty: false}, - project: {type: String, empty: true}, - deploy_env: {type: String, empty: true}, - stack_template: {type: String, empty: true}, - template_body: {type: String, empty: true} - # cloud_stack_id: {type: String, empty: true} - # TODO: add parameters Hash + project: {type: String}, + deploy_env: {type: String}, + stack_template: {type: String, empty: false}, + cloud_stack_id: {type: String, nil: true} + # details: {type: Hash, nil: true} # Hash type isn't supported yet def initialize attrs={} + self.provider = self.class.provider + self.id = attrs['id'] - self.provider = attrs['provider'] self.project = attrs['project'] self.deploy_env = attrs['deploy_env'] self.stack_template = attrs['stack_template'] - self.template_body = attrs['template_body'] - # self.cloud_stack_id = attrs['cloud_stack_id'] + self.cloud_stack_id = attrs['cloud_stack_id'] self.parameters = attrs['parameters'] + self.details = attrs['details'] self end @@ -32,40 +33,63 @@ module Devops deploy_env: deploy_env, stack_template: stack_template, cloud_stack_id: cloud_stack_id, - parameters: parameters + parameters: parameters, + details: details, + stack_status: stack_status } end - - # attrs should include: - # - id (String) - # - provider (String) - # - deploy_env (String) - # - stack_template (String) - def self.create(attrs) - model = new(attrs) - model.create_stack_in_cloud! - model - end - - def self.build_from_bson(attrs) - attrs['id'] = attrs["_id"] - self.new(attrs) - end - def create_stack_in_cloud! - raise 'override me' + begin + self.cloud_stack_id = provider_class.create_stack(self) + rescue ProviderErrors::NameConflict + raise InvalidRecord.new "Duplicate key error: stack with name '#{id}' already exists in cloud" + end end def delete_stack_in_cloud! - raise 'override me' + provider_class.delete_stack(self) + end + + def sync_details! + self.details = provider_class.stack_details(self) + end + + def resources + provider_class.stack_resources(self) + end + + def resource(resource_id) + provider_class.stack_resource(self, resource_id) end - # if not set in constructor, assume stack was created via stack_template. - # It is need to support presets. - # TODO: refactore it. def template_body - @template_body ||= Devops::Api2.settings.mongo.stack_template(stack_template).template_body + Devops::Api2.settings.mongo.stack_template(stack_template).template_body + end + + class << self + attr_accessor :provider + + # attrs should include: + # - id (String) + # - deploy_env (String) + # - stack_template (String) + def create(attrs) + model = new(attrs) + model.create_stack_in_cloud! + model + end + + def build_from_bson(attrs) + attrs['id'] = attrs["_id"] + self.new(attrs) + end + end + + private + + def provider_class + Provider::ProviderFactory.get(provider) end end diff --git a/devops-service/db/mongo/models/stack/stack_ec2.rb b/devops-service/db/mongo/models/stack/stack_ec2.rb index bd00161..693b9d2 100644 --- a/devops-service/db/mongo/models/stack/stack_ec2.rb +++ b/devops-service/db/mongo/models/stack/stack_ec2.rb @@ -1,12 +1,7 @@ module Devops module Model class StackEc2 < StackBase - - def create_stack_in_cloud! - # create stack in AWS - self.cloud_stack_id = 'arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83' - end - + self.provider = 'ec2' end end end diff --git a/devops-service/db/mongo/models/stack/stack_openstack.rb b/devops-service/db/mongo/models/stack/stack_openstack.rb index 83151ef..62918ae 100644 --- a/devops-service/db/mongo/models/stack/stack_openstack.rb +++ b/devops-service/db/mongo/models/stack/stack_openstack.rb @@ -1,21 +1,11 @@ module Devops module Model class StackOpenstack < StackBase + self.provider = 'openstack' - def create_stack_in_cloud! - begin - provider = Provider::ProviderFactory.get('openstack') - self.cloud_stack_id = provider.create_stack(self) - rescue ProviderErrors::NameConflict - raise InvalidRecord.new "Duplicate key error: stack with name '#{self.id}' already exists in cloud" - end + def stack_status + details[:stack_status] if details end - - def delete_stack_in_cloud! - provider = Provider::ProviderFactory.get('openstack') - provider.delete_stack(self) - end - end end end diff --git a/devops-service/db/mongo/mongo_connector.rb b/devops-service/db/mongo/mongo_connector.rb index 93fb641..c92c2f5 100644 --- a/devops-service/db/mongo/mongo_connector.rb +++ b/devops-service/db/mongo/mongo_connector.rb @@ -12,8 +12,8 @@ class MongoConnector delegate( [:images, :image, :image_insert, :image_delete, :image_update] => :images_connector, - [:stack_templates, :stack_template, :stack_template_insert, :stack_template_delete] => :stack_templates_connector, - [:stacks, :stack, :stack_insert, :stack_delete] => :stacks_connector, + [:stack_templates, :stack_template, :stack_template_insert, :stack_template_delete, :stack_template_update] => :stack_templates_connector, + [:stacks, :stack, :stack_insert, :stack_delete, :stack_update] => :stacks_connector, [:available_images, :add_available_images, :delete_available_images] => :filters_connector, [:project, :projects_all, :projects, :project_names_with_envs, :projects_by_image, :projects_by_user, :project_insert, :project_update, diff --git a/devops-service/lib/stack_presets/base.rb b/devops-service/lib/stack_presets/base.rb new file mode 100644 index 0000000..ae09ac7 --- /dev/null +++ b/devops-service/lib/stack_presets/base.rb @@ -0,0 +1,76 @@ +require 'lib/string_helper' +require 'db/mongo/models/stack_template/stack_template_factory' + +module Devops + module StackPresets + class Base + + def id + StringHelper.underscore_class(self.class) + end + + def to_hash + {id: id, template_body: template_body} + end + + # attrs should include + # 'provider' + # 'stack' + # 'parameters' + # 'project' + # 'deploy_env' + def create_stack_from_preset(attrs) + provider = attrs.fetch('provider') + template_name = find_or_create_stack_template!(provider) + + stack_attrs = attrs.merge( + 'id' => attrs['stack'], + 'stack_template' => template_name + ) + + Model::StackFactory.create(provider, stack_attrs) + end + + def template_body + @template_body ||= File.read("lib/stack_presets/#{id}.#{template_file_extension}") + end + + # some templates may be YAML files + def template_file_extension + :json + end + + private + + def find_or_create_stack_template!(provider) + name = stack_template_name(provider) + begin + stack_template = Devops::Api2.settings.mongo.stack_template(name) + update_stack_template(stack_template) if stack_template.template_body != template_body + rescue RecordNotFound + create_stack_template(provider) + end + name + end + + def stack_template_name(provider) + "#{id}_#{provider}_preset" + end + + def create_stack_template(provider) + stack_template = Model::StackTemplateFactory.create(provider, { + 'id' => stack_template_name(provider), + 'provider' => provider, + 'template_body' => template_body + }) + Devops::Api2.settings.mongo.stack_template_insert(stack_template) + end + + def update_stack_template(stack_template) + stack_template.template_body = template_body + Devops::Api2.settings.mongo.stack_template_update(stack_template) + end + + end + end +end \ No newline at end of file diff --git a/devops-service/lib/stack_template_presets/factory.rb b/devops-service/lib/stack_presets/factory.rb similarity index 56% rename from devops-service/lib/stack_template_presets/factory.rb rename to devops-service/lib/stack_presets/factory.rb index f3cb3ad..1bb613e 100644 --- a/devops-service/lib/stack_template_presets/factory.rb +++ b/devops-service/lib/stack_presets/factory.rb @@ -2,15 +2,15 @@ require_relative 'base' require_relative 'postgres_cluster' require_relative 'preset_not_found' -class Devops::StackTemplatePresetsFactory +class Devops::StackPresetsFactory - # find all classes in Devops::StackTemplatePresets modules excluding Base and factory. - # This list can be extended in external gems via defining new classes in Devops::StackTemplatePresets module. + # find all classes in Devops::StackPresets modules excluding Base and factory. + # This list can be extended in external gems via defining new classes in Devops::StackPresets module. def self.list - @list ||= Devops::StackTemplatePresets.constants.select do |class_name| + @list ||= Devops::StackPresets.constants.select do |class_name| class_name != :Base end.map do |class_name| - Devops::StackTemplatePresets.const_get(class_name).new + Devops::StackPresets.const_get(class_name).new end end diff --git a/devops-service/lib/stack_template_presets/postgres_cluster.rb b/devops-service/lib/stack_presets/postgres_cluster.rb similarity index 71% rename from devops-service/lib/stack_template_presets/postgres_cluster.rb rename to devops-service/lib/stack_presets/postgres_cluster.rb index 9f55456..21f165a 100644 --- a/devops-service/lib/stack_template_presets/postgres_cluster.rb +++ b/devops-service/lib/stack_presets/postgres_cluster.rb @@ -1,4 +1,4 @@ -module Devops::StackTemplatePresets +module Devops::StackPresets class PostgresCluster < Base def template_file_extension :yml diff --git a/devops-service/lib/stack_template_presets/postgres_cluster.yml b/devops-service/lib/stack_presets/postgres_cluster.yml similarity index 73% rename from devops-service/lib/stack_template_presets/postgres_cluster.yml rename to devops-service/lib/stack_presets/postgres_cluster.yml index 7f97c80..6b8bc1b 100644 --- a/devops-service/lib/stack_template_presets/postgres_cluster.yml +++ b/devops-service/lib/stack_presets/postgres_cluster.yml @@ -13,5 +13,7 @@ resources: type: OS::Nova::Server properties: key_name: { get_param: key_name } - image: 227f4be7-be1c-498d-ab88-54f8b5df249f - flavor: m1.small \ No newline at end of file + image: 5f4020a1-b6ab-47e4-a0ed-de4324a17c3a + flavor: m1.micro + networks: + - network: devops-net-1 \ No newline at end of file diff --git a/devops-service/lib/stack_template_presets/preset_not_found.rb b/devops-service/lib/stack_presets/preset_not_found.rb similarity index 100% rename from devops-service/lib/stack_template_presets/preset_not_found.rb rename to devops-service/lib/stack_presets/preset_not_found.rb diff --git a/devops-service/lib/stack_template_presets/base.rb b/devops-service/lib/stack_template_presets/base.rb deleted file mode 100644 index d637121..0000000 --- a/devops-service/lib/stack_template_presets/base.rb +++ /dev/null @@ -1,38 +0,0 @@ -require 'lib/string_helper' -require 'db/mongo/models/stack_template/stack_template_factory' - -module Devops - module StackTemplatePresets - class Base - - def id - StringHelper.underscore_class(self.class) - end - - def to_hash - {id: id, template_preset_body: template_preset_body} - end - - def create_stack_from_preset(provider, stack_id, parameters) - stack_attrs = { - 'id' => stack_id, - 'provider' => provider, - 'parameters' => parameters, - 'template_body' => template_preset_body - } - Model::StackFactory.create(provider, stack_attrs) - end - - def template_preset_body - file_name = File.join("lib/stack_template_presets/#{id}.#{template_file_extension}") - File.read(file_name) - end - - # some templates may be YAML files - def template_file_extension - :json - end - - end - end -end \ No newline at end of file diff --git a/devops-service/lib/stubber.rb b/devops-service/lib/stubber.rb index 18b530f..217ef91 100644 --- a/devops-service/lib/stubber.rb +++ b/devops-service/lib/stubber.rb @@ -1,5 +1,11 @@ module Stubber - def self.stub_providers! - Dir["tests/stubs/providers/*.rb"].each {|file| require file } + def self.stub_providers!(providers) + return unless providers + + providers = [:ec2, :openstack] if providers == :all + providers.each do |provider| + next unless [:ec2, :openstack].include?(provider) + require "tests/stubs/providers/#{provider}.rb" + end end end diff --git a/devops-service/providers/openstack.rb b/devops-service/providers/openstack.rb index b3f92f7..a927741 100644 --- a/devops-service/providers/openstack.rb +++ b/devops-service/providers/openstack.rb @@ -193,11 +193,12 @@ module Provider def create_stack(stack) begin - response = orchestration.create_stack(stack.id, { + response = orchestration.create_stack( + stack_name: stack.id, template: stack.template_body, tenant_id: connection_options[:openstack_tenant], parameters: stack.parameters - }) + ) response[:body]['stack']['id'] rescue Excon::Errors::Conflict => e raise ProviderErrors::NameConflict @@ -205,7 +206,19 @@ module Provider end def delete_stack(stack) - orchestration.delete_stack(stack.id, stack.cloud_stack_id) + fog_stack(stack).destroy + end + + def stack_details(stack) + fog_stack(stack).details.attributes + end + + def stack_resources(stack) + fog_stack(stack).resources + end + + def stack_resource(stack, resource_id) + fog_stack(stack).resources.get(resource_id) end private @@ -233,5 +246,9 @@ module Provider @connection ||= Fog::Orchestration.new(connection_options) end + def fog_stack(stack) + orchestration.stacks.get(stack.id, stack.cloud_stack_id) + end + end end diff --git a/devops-service/tests/generate_tests.rb b/devops-service/tests/generate_tests.rb index 5557cb2..2d097d9 100755 --- a/devops-service/tests/generate_tests.rb +++ b/devops-service/tests/generate_tests.rb @@ -77,7 +77,7 @@ templates = { #list "templates/api_v2/00_list/flavor.feature.erb" => "features/api_v2/00_list/flavor.feature", - "templates/api_v2/00_list/stack_template_preset.feature.erb" => "features/api_v2/00_list/stack_template_preset.feature", + "templates/api_v2/00_list/stack_preset.feature.erb" => "features/api_v2/00_list/stack_preset.feature", "templates/api_v2/00_list/10_user.feature.erb" => "features/api_v2/00_list/10_user.feature", #create diff --git a/devops-service/tests/stubs/providers/ec2.rb b/devops-service/tests/stubs/providers/ec2.rb index a1fd0be..0459307 100644 --- a/devops-service/tests/stubs/providers/ec2.rb +++ b/devops-service/tests/stubs/providers/ec2.rb @@ -62,4 +62,12 @@ class Provider::Ec2 ] end + def create_stack(stack) + 'arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83' + end + + def delete_stack(stack) + true + end + end \ No newline at end of file diff --git a/devops-service/tests/stubs/providers/openstack.rb b/devops-service/tests/stubs/providers/openstack.rb index 0247888..d6b477d 100644 --- a/devops-service/tests/stubs/providers/openstack.rb +++ b/devops-service/tests/stubs/providers/openstack.rb @@ -71,4 +71,16 @@ class Provider::Openstack true end + def stack_details(stack) + {stack_status: 'stubbed'} + end + + def stack_resources(stack) + [{'stubbed' => 'stubbed'}] + end + + def stack_resource(stack, resource_id) + {'stubbed' => 'stubbed'} + end + end \ No newline at end of file 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 69% 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 823f006..77690e4 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 @@ -1,8 +1,8 @@ -@stack_template_preset +@stack_preset Feature: stack template preset list Scenario: Get list of all stack template presets - When I send GET '/v2.0/stack_template_presets' query + When I send GET '/v2.0/stack_presets' query Then response should be '200' And the Content-Type header should include 'application/json' And the JSON response should be an array @@ -11,18 +11,18 @@ Feature: stack template preset list [ { "id": "test", - "template_preset_body": "long body" + "template_body": "long body" } ] """ Scenario: Get information about particular stack template preset - When I send GET '/v2.0/stack_template_presets/postgres_cluster' query + When I send GET '/v2.0/stack_presets/postgres_cluster' query Then response should be '200' And the Content-Type header should include 'application/json' And response should be JSON object like: """ { - "id": "postgres_cluster", "template_preset_body": "long body" + "id": "postgres_cluster", "template_body": "long body" } """ \ No newline at end of file