diff --git a/devops-client/lib/devops-client/handler/handler_factory.rb b/devops-client/lib/devops-client/handler/handler_factory.rb index c5b7898..03ac0a4 100644 --- a/devops-client/lib/devops-client/handler/handler_factory.rb +++ b/devops-client/lib/devops-client/handler/handler_factory.rb @@ -47,9 +47,6 @@ class HandlerFactory when "stack_template" require "devops-client/handler/stack_template" StackTemplate - 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/image.rb b/devops-client/lib/devops-client/handler/image.rb index 3ee06d0..9fdc0d0 100644 --- a/devops-client/lib/devops-client/handler/image.rb +++ b/devops-client/lib/devops-client/handler/image.rb @@ -15,7 +15,6 @@ class Image < Handler end def handle - current_command = ARGV[1].to_sym @options, @args = @options_parser.parse_options_for!(current_command) case current_command when :list diff --git a/devops-client/lib/devops-client/handler/server.rb b/devops-client/lib/devops-client/handler/server.rb index 9febf16..1d85e02 100644 --- a/devops-client/lib/devops-client/handler/server.rb +++ b/devops-client/lib/devops-client/handler/server.rb @@ -71,7 +71,7 @@ class Server < Handler :deploy_env => @args[3] } - [:key, :without_bootstrap, :name, :groups, :force].each do |k| + [:key, :without_bootstrap, :name, :groups, :force, :private_ip].each do |k| q[k] = self.options[k] unless self.options[k].nil? end diff --git a/devops-client/lib/devops-client/handler/stack_preset.rb b/devops-client/lib/devops-client/handler/stack_preset.rb deleted file mode 100644 index b1e9073..0000000 --- a/devops-client/lib/devops-client/handler/stack_preset.rb +++ /dev/null @@ -1,62 +0,0 @@ -require "devops-client/handler/handler" -require "devops-client/options/stack_preset_options" -require "devops-client/output/stack_preset" - -class StackPreset < Handler - - output_with Output::StackPreset - - def initialize(host, def_options={}) - @host, @options = host, def_options - @options_parser = StackPresetOptions.new(ARGV, def_options) - end - - def handle - @options, @args = @options_parser.parse_options_for!(current_command) - case current_command - when :list - list_handler - output - when :show - show_handler - output - when :apply - apply_handler - output - end - end - - def show_handler - wrong_params = inspect_parameters(@options_parser.show_params, @args[2]) - if wrong_params - @options_parser.invalid_show_command - abort(wrong_params) - end - @show = get "/stack_presets/#{@args[2]}" - end - - def list_handler - @list = get('/stack_presets') - end - - def apply_handler - wrong_params = inspect_parameters(@options_parser.apply_params, @args[2]) - if wrong_params - @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_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_preset.create.parameters_file')) - params[:parameters] = JSON.parse(File.read(filepath)) - - @list = post_body("/stack_presets/#{params[:id]}/apply", JSON.pretty_generate(params)) - end - -end diff --git a/devops-client/lib/devops-client/handler/stack_template.rb b/devops-client/lib/devops-client/handler/stack_template.rb index c305e18..d1754c4 100644 --- a/devops-client/lib/devops-client/handler/stack_template.rb +++ b/devops-client/lib/devops-client/handler/stack_template.rb @@ -14,7 +14,6 @@ class StackTemplate < Handler end def handle - current_command = ARGV[1].to_sym @options, @args = @options_parser.parse_options_for!(current_command) case current_command when :list @@ -27,6 +26,8 @@ class StackTemplate < Handler create_handler when :delete delete_handler + when :update_url + update_url_handler end end @@ -76,6 +77,16 @@ class StackTemplate < Handler end end + def update_url_handler + r = inspect_parameters @options_parser.update_url_params, @args[2] + unless r.nil? + @options_parser.invalid_update_url_command + abort(r) + end + stack_template = post "/stack_template/#{@args[2]}/update_template_url" + puts stack_template['template_url'] + end + def provider_stack_templates(provider) if Providers.has_functionality?(provider, :stack_templates) @provider = true diff --git a/devops-client/lib/devops-client/options/deploy_options.rb b/devops-client/lib/devops-client/options/deploy_options.rb index a23443d..abb657d 100644 --- a/devops-client/lib/devops-client/options/deploy_options.rb +++ b/devops-client/lib/devops-client/options/deploy_options.rb @@ -14,7 +14,7 @@ class DeployOptions < CommonOptions options do |parser, options| parser.banner << self.banner - parser.recognize_option_value(:tag, 'deploy', variable_name: 'TAG1,TAG2...') do |tags| + parser.recognize_option_value(:tag, resource_name: :deploy, variable_name: 'TAG1,TAG2...') do |tags| options[:tags] = tags.split(",") end diff --git a/devops-client/lib/devops-client/options/helpers/devops_options_parser.rb b/devops-client/lib/devops-client/options/helpers/devops_options_parser.rb index c3fc63e..e0bd6ef 100644 --- a/devops-client/lib/devops-client/options/helpers/devops_options_parser.rb +++ b/devops-client/lib/devops-client/options/helpers/devops_options_parser.rb @@ -7,6 +7,7 @@ module Options class DevopsOptionsParser extend Forwardable attr_reader :parsed_options + attr_accessor :resource_name, :command_name # leave this duplication for a while TABLE_FORMAT = "table" @@ -46,8 +47,9 @@ module Options # it is used to set options values without later quiz. # Arguments description: # option_name - name of option; - # resource_name - used for description lookup. Lookup path is "options.descriptions.#{resource_name}.#{option_name}". # attrs - hash with following options: + # :resource_name - used for description lookup. Could be set with attr_accessor. Lookup path is "options.descriptions.#{resource_name}.#{option_name}". + # :command_name - Also could be set with attr_accessor. Changes description lookup to "options.descriptions.#{resource_name}.#{command_name}.#{option_name}" # :type - could be one of following values: # :required (default) # :optional @@ -57,48 +59,59 @@ module Options # :option_key - key in result_options hash. Default - option_name.to_sym # :variable - default - option_name.upcase # :description - default - I18n.t("options.descriptions.#{resource_name}.#{option_name}") - # :i18n_scope - if present, change I18n lookup path to "options.descriptions.#{resource_name}.#{i18n_scope}.#{option_name}" # :short - short option name # # EXAMPLES: # 1) - # parser.recognize_option_value(:provider, 'stack') - # is equal to + # parser.resource_name = :stack + # parser.recognize_option_value(:provider) + # is equal to # opts.on("--provider provider", I18n.t("options.descriptions.stack.provider)) do |provider| # options[:provider] = provider # end # + # Also, you could pass resource name in attributes without need to use attr_accessor: + # parser.recognize_option_value(:provider, resource_name: :stack) + # # 2) - # parser.recognize_option_value(:provider, 'stack', type: :optional, default: 'openstack') - # is equal to + # parser.recognize_option_value(:provider, type: :optional, default: 'openstack') + # is equal to # options[:provider] = 'openstack' # opts.on("--provider [provider]", I18n.t("options.descriptions.stack.provider)) do |provider| # options[:provider] = provider # end # # 3) - # parser.recognize_option_value(:no_template, 'image', type: :switch, default: false, switch_value: true) - # is equal to + # parser.recognize_option_value(:no_template, type: :switch, default: false, switch_value: true) + # is equal to # options[:no_template] = false # opts.on("--no_template", I18n.t("options.descriptions.image.no_template)) do # options[:no_template] = true # end # # 4) - # parser.recognize_option_value(:parameters, 'stack') do |parameters| + # parser.recognize_option_value(:parameters) do |parameters| # options[:parameters] = JSON.parse(parameters) # end - # is equal to + # is equal to # opts.on("--parameters parameters", I18n.t("options.descriptions.stack.parameters)) do |parameters| # options[:parameters] = JSON.parse(parameters) # end - def recognize_option_value(option_name, resource_name, attrs={}, &block) - recognizer = OptionValueRecognizer.new(option_name, resource_name, attrs) + def recognize_option_value(option_name, attrs={}, &block) + scope = i18n_scope(attrs.delete(:resource_name), attrs.delete(:command_name), option_name) + recognizer = OptionValueRecognizer.new(option_name, scope, attrs) recognizer.recognize(@parser, @parsed_options, &block) end private + def i18n_scope(specified_resource_name, specified_command_name, option_name) + resource = specified_resource_name || resource_name + raise "Resource name isn't specified. Use parser.resource= or :resource_name attribute" unless resource + segments = [:options, :descriptions, resource, specified_command_name || command_name, option_name] + segments.compact.join('.') + end + def banner_usage @parser.banner = "\n" + I18n.t("options.usage", :cmd => $0) + "\n\n" + I18n.t("options.commands") + ":\n" end diff --git a/devops-client/lib/devops-client/options/helpers/option_value_recognizer.rb b/devops-client/lib/devops-client/options/helpers/option_value_recognizer.rb index 6c1735a..e4ea362 100644 --- a/devops-client/lib/devops-client/options/helpers/option_value_recognizer.rb +++ b/devops-client/lib/devops-client/options/helpers/option_value_recognizer.rb @@ -3,14 +3,16 @@ # Description and examples of usage are in devops_option_parser.rb. class OptionValueRecognizer - def initialize(option_name, resource_name, attrs={}) - @option_name, @attrs = option_name, attrs + attr_reader :option_name, :i18n_scope, :attrs - set_type(option_name, resource_name) - set_option_key(option_name, resource_name) - set_description(option_name, resource_name) - set_variable(option_name, resource_name) - set_options_to_recognize(option_name, resource_name) + def initialize(option_name, i18n_scope, attrs={}) + @option_name, @i18n_scope, @attrs = option_name, i18n_scope, attrs + + set_type + set_option_key + set_description + set_variable + set_options_to_recognize end def recognize(parser, parsed_options, &block) @@ -29,7 +31,9 @@ class OptionValueRecognizer private - def set_type(option_name, resource_name) + + + def set_type @type = @attrs[:type] || :required raise "Illegal optional type: '#{@type}'" unless [:required, :optional, :switch].include?(@type) if @type == :switch && !@attrs.keys.include?(:switch_value) @@ -37,22 +41,15 @@ class OptionValueRecognizer end end - def set_option_key(option_name, resource_name) + def set_option_key @option_key = @attrs[:option_key] || option_name.to_sym end - def set_description(option_name, resource_name) - if @attrs[:description] - @description = @attrs[:description] - else - lookup_path = [:options, :descriptions, resource_name] - lookup_path << @attrs[:i18n_scope] if @attrs[:i18n_scope] - lookup_path << option_name - @description = I18n.t(lookup_path.join('.')) - end + def set_description + @description = @attrs[:description] || I18n.t(i18n_scope) end - def set_variable(option_name, resource_name) + def set_variable variable = @attrs[:variable] || option_name.upcase @variable = case @type @@ -65,7 +62,7 @@ class OptionValueRecognizer end end - def set_options_to_recognize(option_name, resource_name) + def set_options_to_recognize full = "--#{@option_name}#{@variable}" @options_to_recognize = [full] @options_to_recognize.unshift(@attrs[:short]) if @attrs[:short] diff --git a/devops-client/lib/devops-client/options/image_options.rb b/devops-client/lib/devops-client/options/image_options.rb index df737ad..587488b 100644 --- a/devops-client/lib/devops-client/options/image_options.rb +++ b/devops-client/lib/devops-client/options/image_options.rb @@ -17,12 +17,13 @@ class ImageOptions < CommonOptions def create_options self.options do |parser, options| parser.banner << self.create_banner + parser.resource_name = :image - parser.recognize_option_value(:provider, 'image') - parser.recognize_option_value(:image_id, 'image') - parser.recognize_option_value(:ssh_username, 'image') - parser.recognize_option_value(:bootstrap_template, 'image') - parser.recognize_option_value(:no_bootstrap_template, 'image', type: :switch, switch_value: true, default: false) + parser.recognize_option_value(:provider) + parser.recognize_option_value(:image_id) + parser.recognize_option_value(:ssh_username) + parser.recognize_option_value(:bootstrap_template) + parser.recognize_option_value(:no_bootstrap_template, type: :switch, switch_value: true, default: false) end end diff --git a/devops-client/lib/devops-client/options/project_options.rb b/devops-client/lib/devops-client/options/project_options.rb index 3bbd72e..64727e0 100644 --- a/devops-client/lib/devops-client/options/project_options.rb +++ b/devops-client/lib/devops-client/options/project_options.rb @@ -29,31 +29,32 @@ class ProjectOptions < CommonOptions def create_options self.options do |parser, options| parser.banner << self.create_banner + parser.resource_name = :project - parser.recognize_option_value(:groups, 'project', variable: 'GROUP_1,GROUP_2...') do |groups| + parser.recognize_option_value(:groups, variable: 'GROUP_1,GROUP_2...') do |groups| options[:groups] = groups.split(",") end - parser.recognize_option_value(:file, 'project') do |file| + parser.recognize_option_value(:file) do |file| abort("File '#{file}' does not exist") unless File.exist?(file) options[:file] = file end - parser.recognize_option_value(:subnets, 'project', variable: 'SUBNET_1,SUBNET_2...') do |subnets| + parser.recognize_option_value(:subnets, variable: 'SUBNET_1,SUBNET_2...') do |subnets| options[:subnets] = subnets.split(",") end - parser.recognize_option_value(:users, 'project', variable: 'USER_1,USER_2...') do |users| + parser.recognize_option_value(:users, variable: 'USER_1,USER_2...') do |users| options[:users] = Set.new(users.split(",")) end - parser.recognize_option_value(:deploy_env, 'project', option_key: :identifier) - parser.recognize_option_value(:flavor, 'project') - parser.recognize_option_value(:image, 'project') - parser.recognize_option_value(:run_list, 'project') - parser.recognize_option_value(:provider, 'project') - parser.recognize_option_value(:no_expires, 'project', type: :switch, switch_value: true, default: false) - parser.recognize_option_value(:expires, 'project') + parser.recognize_option_value(:deploy_env, option_key: :identifier) + parser.recognize_option_value(:flavor) + parser.recognize_option_value(:image) + parser.recognize_option_value(:run_list) + parser.recognize_option_value(:provider) + parser.recognize_option_value(:no_expires, type: :switch, switch_value: true, default: false) + parser.recognize_option_value(:expires) # TODO: @@ -72,7 +73,7 @@ class ProjectOptions < CommonOptions self.options do |parser, options| parser.banner << self.user_add_banner - parser.recognize_option_value(:deploy_env, 'project', i18n_scope: 'user_add') + parser.recognize_option_value(:deploy_env, resource_name: :project, command_name: 'user_add') end end @@ -80,7 +81,7 @@ class ProjectOptions < CommonOptions self.options do |parser, options| parser.banner << self.user_delete_banner - parser.recognize_option_value(:deploy_env, 'project', i18n_scope: 'user_delete') + parser.recognize_option_value(:deploy_env, resource_name: :project, command_name: 'user_delete') end end @@ -88,7 +89,7 @@ class ProjectOptions < CommonOptions options do |parser, options| parser.banner << self.deploy_banner - parser.recognize_option_value(:servers, 'project', i18n_scope: 'deploy') do |servers| + parser.recognize_option_value(:servers, resource_name: :project, command_name: 'deploy') do |servers| options[:servers] = servers.split(",") end end @@ -96,7 +97,7 @@ class ProjectOptions < CommonOptions def delete_servers_options self.options do |parser, options| - parser.recognize_option_value(:dry_run, 'project', type: :switch, default: false, switch_value: true, i18n_scope: 'delete_servers') + parser.recognize_option_value(:dry_run, resource_name: :project, type: :switch, default: false, switch_value: true, command_name: 'delete_servers') end end diff --git a/devops-client/lib/devops-client/options/script_options.rb b/devops-client/lib/devops-client/options/script_options.rb index caab4a0..42ffe54 100644 --- a/devops-client/lib/devops-client/options/script_options.rb +++ b/devops-client/lib/devops-client/options/script_options.rb @@ -19,7 +19,7 @@ class ScriptOptions < CommonOptions options do |parser, options| parser.banner << self.delete_banner - parser.recognize_option_value(:params, 'script') do |params| + parser.recognize_option_value(:params, resource_name: :script) do |params| options[:params] = params.split(",") end end diff --git a/devops-client/lib/devops-client/options/server_options.rb b/devops-client/lib/devops-client/options/server_options.rb index 71461d0..7a44bc0 100644 --- a/devops-client/lib/devops-client/options/server_options.rb +++ b/devops-client/lib/devops-client/options/server_options.rb @@ -24,22 +24,21 @@ class ServerOptions < CommonOptions def delete_options options do |parser, options| parser.banner << self.delete_banner + parser.resource_name = :server + parser.command_name = :delete - parser.recognize_option_value(:instance, 'server', + parser.recognize_option_value(:instance, type: :switch, default: 'node', switch_value: 'instance', - option_key: :key, - i18n_scope: 'delete' + option_key: :key ) - parser.recognize_option_value(:no_ask, 'server', + parser.recognize_option_value(:no_ask, type: :switch, default: false, - switch_value: true, - i18n_scope: 'delete' + switch_value: true ) - end end @@ -47,12 +46,13 @@ class ServerOptions < CommonOptions options do |parser, options| parser.banner << self.delete_banner - parser.recognize_option_value(:instance, 'server', + parser.recognize_option_value(:instance, + resource_name: :server, + command_name: :pause, type: :switch, default: 'node', switch_value: 'instance', - option_key: :key, - i18n_scope: 'pause' + option_key: :key ) end end @@ -61,12 +61,13 @@ class ServerOptions < CommonOptions options do |parser, options| parser.banner << self.delete_banner - parser.recognize_option_value(:instance, 'server', + parser.recognize_option_value(:instance, + resource_name: :server, + command_name: :unpause, type: :switch, default: 'node', switch_value: 'instance', - option_key: :key, - i18n_scope: 'unpause' + option_key: :key ) end end @@ -75,12 +76,13 @@ class ServerOptions < CommonOptions options do |parser, options| parser.banner << self.delete_banner - parser.recognize_option_value(:instance, 'server', + parser.recognize_option_value(:instance, + resource_name: :server, + command_name: :reserve, type: :switch, default: 'node', switch_value: 'instance', - option_key: :key, - i18n_scope: 'reserve' + option_key: :key ) end end @@ -89,12 +91,13 @@ class ServerOptions < CommonOptions options do |parser, options| parser.banner << self.delete_banner - parser.recognize_option_value(:instance, 'server', + parser.recognize_option_value(:instance, + resource_name: :server, + command_name: :unreserve, type: :switch, default: 'node', switch_value: 'instance', - option_key: :key, - i18n_scope: 'unreserve' + option_key: :key ) end end @@ -102,26 +105,29 @@ class ServerOptions < CommonOptions def create_options options do |parser, options| parser.banner << self.create_banner + parser.resource_name = :server + parser.command_name = :create - parser.recognize_option_value('without_bootstrap', 'server', + parser.recognize_option_value('without_bootstrap', type: :switch, switch_value: true, option_key: :without_bootstrap, i18n_scope: 'create' ) - parser.recognize_option_value(:name, 'server', short: '-N', i18n_scope: 'create') - parser.recognize_option_value(:force, 'server', short: '-f', i18n_scope: 'create') - parser.recognize_option_value(:key, 'server', i18n_scope: 'create') + parser.recognize_option_value(:name, short: '-N') + parser.recognize_option_value(:force, short: '-f') + parser.recognize_option_value(:key) - parser.recognize_option_value(:groups, 'server', + parser.recognize_option_value(:groups, short: '-G', - variable: 'GROUP_1,GROUP_2...', - i18n_scope: 'create' + variable: 'GROUP_1,GROUP_2...' ) do |groups| options[:groups] = groups.split(",") end + parser.recognize_option_value(:private_ip, 'server', short: '-N', i18n_scope: 'create') + # it was disabled somewhy # parser.on('--public-ip', "Associate public IP with server") do # options[:public_ip] = true @@ -132,10 +138,12 @@ class ServerOptions < CommonOptions def bootstrap_options options do |parser, options| parser.banner << self.bootstrap_banner + parser.resource_name = :server + parser.command_name = :bootstrap - parser.recognize_option_value(:name, 'server', short: '-N', i18n_scope: 'bootstrap') - parser.recognize_option_value(:bootstrap_template, 'server', i18n_scope: 'bootstrap') - parser.recognize_option_value(:run_list, 'server', i18n_scope: 'bootstrap') do |list| + parser.recognize_option_value(:name, short: '-N') + parser.recognize_option_value(:bootstrap_template) + parser.recognize_option_value(:run_list) do |list| options[:run_list] = list.split(",") end end @@ -145,7 +153,7 @@ class ServerOptions < CommonOptions options do |parser, options| parser.banner << self.add_banner - parser.recognize_option_value('public-ip', 'server', i18n_scope: 'add', option_key: :public_ip) + parser.recognize_option_value('public-ip', resource_name: :server, command_name: :add, option_key: :public_ip) 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 c33c25a..325e629 100644 --- a/devops-client/lib/devops-client/options/stack_options.rb +++ b/devops-client/lib/devops-client/options/stack_options.rb @@ -21,16 +21,16 @@ class StackOptions < CommonOptions def create_options self.options do |parser, options| parser.banner << self.create_banner + parser.resource_name = :stack - parser.recognize_option_value(:provider, 'stack') - parser.recognize_option_value(:id, 'stack') - parser.recognize_option_value(:project, 'stack') - parser.recognize_option_value(:deploy_env, 'stack') - parser.recognize_option_value(:stack_template, 'stack') - parser.recognize_option_value(:parameters_file, 'stack') - parser.recognize_option_value(:run_list, 'stack') - parser.recognize_option_value(:without_bootstrap, 'stack', type: :switch, switch_value: true) - + parser.recognize_option_value(:provider) + parser.recognize_option_value(:id) + parser.recognize_option_value(:project) + parser.recognize_option_value(:deploy_env) + parser.recognize_option_value(:stack_template) + parser.recognize_option_value(:parameters_file) + parser.recognize_option_value(:run_list) + parser.recognize_option_value(:without_bootstrap, type: :switch, switch_value: true) 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 deleted file mode 100644 index 5aa4d62..0000000 --- a/devops-client/lib/devops-client/options/stack_preset_options.rb +++ /dev/null @@ -1,37 +0,0 @@ -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(:project, 'stack_preset') - parser.recognize_option_value(:deploy_env, '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_options.rb b/devops-client/lib/devops-client/options/stack_template_options.rb index 67f8498..3da56a9 100644 --- a/devops-client/lib/devops-client/options/stack_template_options.rb +++ b/devops-client/lib/devops-client/options/stack_template_options.rb @@ -2,7 +2,7 @@ require "devops-client/options/common_options" class StackTemplateOptions < CommonOptions - commands :create, :delete, :list, :show + commands :create, :delete, :list, :show, :update_url def initialize args, def_options super(args, def_options) @@ -11,15 +11,17 @@ class StackTemplateOptions < CommonOptions self.list_params = ["[provider]", "[ec2|openstack]"] self.show_params = ["STACK_TEMPLATE"] self.delete_params = ["STACK_TEMPLATE"] + self.update_url_params = ["STACK_TEMPLATE"] end def create_options self.options do |parser, options| parser.banner << self.create_banner + parser.resource_name = :stack_template - parser.recognize_option_value(:provider, 'stack_template', default: nil) - parser.recognize_option_value(:id, 'stack_template') - parser.recognize_option_value(:template_file, 'stack_template') + parser.recognize_option_value(:provider, default: nil) + parser.recognize_option_value(:id) + parser.recognize_option_value(:template_file) end end diff --git a/devops-client/lib/devops-client/options/user_options.rb b/devops-client/lib/devops-client/options/user_options.rb index e224431..f6da6e0 100644 --- a/devops-client/lib/devops-client/options/user_options.rb +++ b/devops-client/lib/devops-client/options/user_options.rb @@ -18,7 +18,7 @@ class UserOptions < CommonOptions self.options do |parser, options| parser.banner << self.create_banner - parser.recognize_option_value(:new_password, 'user') + parser.recognize_option_value(:new_password, resource_name: :user) end end diff --git a/devops-client/lib/devops-client/output/stack_preset.rb b/devops-client/lib/devops-client/output/stack_preset.rb deleted file mode 100644 index 76c9909..0000000 --- a/devops-client/lib/devops-client/output/stack_preset.rb +++ /dev/null @@ -1,45 +0,0 @@ -require "devops-client/output/base" - -module Output - class StackPreset < Base - - def table - if outputting_list? - title = I18n.t("output.title.stack_preset.list") - headers, rows = create_list - else - 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 - if outputting_list? - headers, rows = create_list - else - headers, rows = create_show - end - create_csv headers, rows, with_num? - end - - def json - JSON.pretty_generate(@data) - end - - private - - def create_list - abort(I18n.t("output.not_found.stack_preset.list")) if @data.empty? - - fields_to_output = %w(id) - - 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-client/locales/en.yml b/devops-client/locales/en.yml index 58f1d9f..119e419 100644 --- a/devops-client/locales/en.yml +++ b/devops-client/locales/en.yml @@ -43,7 +43,6 @@ en: user: "User" stack: "Stack" stack_template: "Stack template" - stack_preset: "Stack template preset" handler: flavor: list: @@ -119,10 +118,6 @@ en: question: create: "Are you sure to create stack?" delete: "Are you sure to delete stack '%{name}'?" - stack_preset: - create: - parameters_file: "Path to file with JSON parameters: " - 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: " @@ -236,9 +231,6 @@ en: stack_template: list: "Stack Templates" show: "Stack Template" - stack_preset: - list: "Stack Template Presets" - show: "Stack Template Preset" stack: list: "Stacks" show: "Stack" @@ -274,9 +266,6 @@ en: stack_template: list: "No stack templates found" show: "There isn't such stack template" - stack_preset: - list: "No stack template presets found" - show: "There isn't such stack template preset" stack: list: "No stacks found" show: "There isn't such stack" @@ -360,11 +349,12 @@ en: unreserve: instance: Unreserve server by instance id create: - without-bootstrap: 'Run server without bootsraping phase' + without_bootstrap: 'Run server without bootsraping phase' name: Set node name groups: The security groups for this server force: Cancel rollback operation on error key: User another key for server + private_ip: Private ip for this server bootstrap: name: Set chef name bootstrap_template: Bootstrap template @@ -377,14 +367,12 @@ en: deploy_env: Deploy env project: Stack project stack_template: Stack template - parameters: Parameters hash as single quoted JSON string + parameters_file: File with parameters JSON + run_list: Stack run list + without_bootstrap: Skip bootsraping phase on created instances stack_template: provider: Stack template provider id: Stack template id template_file: Stack template file - stack_preset: - parameters_file: Path to file with JSON parameters - stack: 'Name of stack to build: ' - provider: Stack provider user: new_password: New user password diff --git a/devops-service/Guardfile b/devops-service/Guardfile index 9248c74..13d5834 100644 --- a/devops-service/Guardfile +++ b/devops-service/Guardfile @@ -36,8 +36,9 @@ guard :rspec, cmd: "rspec" do watch(rspec.spec_support) { rspec.spec_dir } watch(rspec.spec_files) - # Factories files + # Spec config files watch(%r{spec/factories/.+\.rb}) { rspec.spec_dir } + watch(%r{spec/shared_contexts.+\.rb}) { rspec.spec_dir } # Devops files watch(%r{db/.+\.rb}) { rspec.spec_dir } diff --git a/devops-service/app/api2/handlers/stack.rb b/devops-service/app/api2/handlers/stack.rb index 6f5a910..17531e2 100644 --- a/devops-service/app/api2/handlers/stack.rb +++ b/devops-service/app/api2/handlers/stack.rb @@ -1,6 +1,7 @@ require "lib/executors/server_executor" require 'db/mongo/models/stack/stack_factory' require "app/api2/parsers/stack" +require 'workers/stack_bootstrap_worker' require_relative "request_handler" module Devops diff --git a/devops-service/app/api2/handlers/stack_preset.rb b/devops-service/app/api2/handlers/stack_preset.rb deleted file mode 100644 index f812f9f..0000000 --- a/devops-service/app/api2/handlers/stack_preset.rb +++ /dev/null @@ -1,43 +0,0 @@ -require 'json' -require 'lib/stack_presets/factory' -require 'workers/stack_bootstrap_worker' -require "app/api2/parsers/stack_preset" -require_relative "request_handler" - -module Devops - module API2_0 - module Handler - class StackPreset < RequestHandler - - set_parser Devops::API2_0::Parser::StackPresetParser - - def presets - Devops::StackPresetsFactory.list - end - - def preset id - Devops::StackPresetsFactory.get(id) - end - - def apply id - body = parser.apply - preset = Devops::StackPresetsFactory.get(id) - stack = preset.create_stack_from_preset(body) - stack.owner = owner_from_request - Devops::Db.connector.stack_insert(stack) - - file = JobStarter.start_job(:worker, :stack_bootstrap, - provider: stack.provider, - stack_id: stack.id, - request: @request - ) - puts "Syncing report is located here: #{file}" - - stack - end - - end - end - end -end - diff --git a/devops-service/app/api2/handlers/stack_template.rb b/devops-service/app/api2/handlers/stack_template.rb index 49718a9..ecb28a2 100644 --- a/devops-service/app/api2/handlers/stack_template.rb +++ b/devops-service/app/api2/handlers/stack_template.rb @@ -39,6 +39,14 @@ module Devops end end + # temp solution to update url on existing stacks + def update_template_url(id) + template = Devops::Db.connector.stack_template(id) + template.update_template_url + Devops::Db.connector.stack_template_update(template) + template + end + private # returns: diff --git a/devops-service/app/api2/parsers/stack_preset.rb b/devops-service/app/api2/parsers/stack_preset.rb deleted file mode 100644 index 6c921ff..0000000 --- a/devops-service/app/api2/parsers/stack_preset.rb +++ /dev/null @@ -1,16 +0,0 @@ -require_relative "request_parser" - -module Devops - module API2_0 - module Parser - class StackPresetParser < RequestParser - - def apply - create_object_from_json_body - end - - end - end - end -end - diff --git a/devops-service/app/api2/routes/server.rb b/devops-service/app/api2/routes/server.rb index b00d983..69bd54e 100644 --- a/devops-service/app/api2/routes/server.rb +++ b/devops-service/app/api2/routes/server.rb @@ -196,6 +196,7 @@ module Devops # "force": null, -> do not delete server on error # "groups": [], -> specify special security groups, overrides value from project env # "key": "ssh key" -> specify ssh key for server, overrides value from project env + # "private_ip": null -> should be string like "172.31.31.203" if present # } # # * *Returns* : text stream diff --git a/devops-service/app/api2/routes/stack_presets.rb b/devops-service/app/api2/routes/stack_presets.rb deleted file mode 100644 index 2619f6b..0000000 --- a/devops-service/app/api2/routes/stack_presets.rb +++ /dev/null @@ -1,70 +0,0 @@ -module Devops - module API2_0 - module Routes - module StackPresetRoutes - - def self.registered(app) - # Get list of available stack_template_presets - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * *Returns* : array of hashes - # [ {id: 'preset id', template_preset_body: 'long body'} ] - # - app.get_with_headers "/stack_presets", :headers => [:accept] do - # check_privileges("stack_template_presets", "r") - json Devops::API2_0::Handler::StackPreset.new(request).presets.map(&:to_hash) - end - - # Get information about stack_template_preset - # - # * *Request* - # - method : GET - # - headers : - # - Accept: application/json - # - # * *Returns* : hash - # {id: 'preset id', template_preset_body: 'long body'} - # - app.get_with_headers "/stack_presets/:id", :headers => [:accept] do |id| - # check_privileges("stack_template_presets", "r") - json Devops::API2_0::Handler::StackPreset.new(request).preset(id).to_hash - end - - # Build stack template from preset - # - # * *Request* - # - method : POST - # - headers : - # - Accept: application/json - # - params : - # - provider: string - # - stack_template_id: id of stack template to create - # - template_attrs: hash with template attributes - # - # TODO: not stack template, but stack itself - # - # * *Returns* : created stack template model - # { - # id: 'template id', - # provider: 'provider', - # template_body: 'long body' - # } - # - app.post_with_headers "/stack_presets/:id/apply", :headers => [:accept] do |id| - # check_privileges("stack_template_presets", "r") - check_privileges('stack_template', 'w') - stack = Devops::API2_0::Handler::StackPreset.new(request).apply(id) - create_response 'Created', stack.to_hash, 201 - end - - puts "Stack template presets routes initialized" - end - - end - end - end -end diff --git a/devops-service/app/api2/routes/stack_template.rb b/devops-service/app/api2/routes/stack_template.rb index d825191..1b18fd9 100644 --- a/devops-service/app/api2/routes/stack_template.rb +++ b/devops-service/app/api2/routes/stack_template.rb @@ -22,6 +22,11 @@ module Devops create_response 'Created', model.to_hash, 201 end + app.post_with_headers "/stack_template/:id/update_template_url", :headers => [:accept] do |template_id| + check_privileges('stack_template', 'w') + json Devops::API2_0::Handler::StackTemplate.new(request).update_template_url(template_id).to_hash + end + hash = {} hash['GET'] = lambda {|stack_template_id| diff --git a/devops-service/app/devops-api2.rb b/devops-service/app/devops-api2.rb index 5e650de..37ba7ac 100644 --- a/devops-service/app/devops-api2.rb +++ b/devops-service/app/devops-api2.rb @@ -22,7 +22,6 @@ module Devops require_relative "api2/handlers/stack" require_relative "api2/handlers/stack_template" - require_relative "api2/handlers/stack_preset" require 'lib/stubber' end @@ -69,7 +68,6 @@ module Devops require_relative "api2/routes/bootstrap_templates" require_relative "api2/routes/stack" require_relative "api2/routes/stack_template" - require_relative "api2/routes/stack_presets" require_relative "api2/routes/statistic" require_relative "api2/routes/report" diff --git a/devops-service/config.rb b/devops-service/config.rb index 5bc27b3..1751eb7 100644 --- a/devops-service/config.rb +++ b/devops-service/config.rb @@ -37,6 +37,7 @@ config[:aws_certificate] = "/path/to/.ssh/ec2.pem" config[:aws_availability_zone] = "aws_zone" config[:aws_proxy] = "" config[:aws_no_proxy] = "" +config[:aws_stack_templates_bucket] = 'stacktemplates' # static settings config[:static_ssh_key] = "ssh_key" # or nil @@ -46,4 +47,4 @@ config[:debug] = true # set it to :all or [:ec2] to stub calls to selected providers # or to false to disable stubbing -config[:stub_providers] = false +config[:stub_providers] = false \ No newline at end of file diff --git a/devops-service/db/mongo/models/image.rb b/devops-service/db/mongo/models/image.rb index dace22e..0263562 100644 --- a/devops-service/db/mongo/models/image.rb +++ b/devops-service/db/mongo/models/image.rb @@ -23,13 +23,13 @@ module Devops set_field_validators :id, [::Validators::FieldValidator::NotNil, ::Validators::FieldValidator::FieldType::String, ::Validators::FieldValidator::NotEmpty, - ::Validators::FieldValidator::ImageName, + ::Validators::FieldValidator::ImageId, ::Validators::Image::ImageInFilter] set_field_validators :remote_user, [::Validators::FieldValidator::NotNil, ::Validators::FieldValidator::FieldType::String, ::Validators::FieldValidator::NotEmpty, - ::Validators::FieldValidator::ImageName] + ::Validators::FieldValidator::ImageUsername] set_field_validators :name, [::Validators::FieldValidator::NotNil, ::Validators::FieldValidator::FieldType::String, diff --git a/devops-service/db/mongo/models/project.rb b/devops-service/db/mongo/models/project.rb index a4a4a23..c4edc04 100644 --- a/devops-service/db/mongo/models/project.rb +++ b/devops-service/db/mongo/models/project.rb @@ -146,6 +146,7 @@ module Devops h end + # TODO: why symbols here? def to_hash_list { name: self.id, @@ -207,6 +208,7 @@ module Devops Project.new p end + # maybe it worth to move components functionality to devops-nibr? #TODO: create validator def validate_components raise InvalidRecord.new "Components is not a hash" unless self.components.is_a?(Hash) diff --git a/devops-service/db/mongo/models/provider_accounts/openstack_provider_account.rb b/devops-service/db/mongo/models/provider_accounts/openstack_provider_account.rb index 9aa6ca2..ef723ac 100644 --- a/devops-service/db/mongo/models/provider_accounts/openstack_provider_account.rb +++ b/devops-service/db/mongo/models/provider_accounts/openstack_provider_account.rb @@ -17,6 +17,7 @@ module Devops def initialize a={} super(a) + self.provider = Provider::Openstack::PROVIDER self.username = a["username"] self.auth_url = a["auth_url"] self.tenant = a["tenant"] diff --git a/devops-service/db/mongo/models/stack/stack_base.rb b/devops-service/db/mongo/models/stack/stack_base.rb index cf118e5..e631bf6 100644 --- a/devops-service/db/mongo/models/stack/stack_base.rb +++ b/devops-service/db/mongo/models/stack/stack_base.rb @@ -131,7 +131,11 @@ module Devops end def template_body - Devops::Db.connector.stack_template(stack_template).template_body + stack_template_model.template_body + end + + def stack_template_model + Devops::Db.connector.stack_template(stack_template) end class << self diff --git a/devops-service/db/mongo/models/stack_template/stack_template_ec2.rb b/devops-service/db/mongo/models/stack_template/stack_template_ec2.rb index 89f7a0d..20b3d03 100644 --- a/devops-service/db/mongo/models/stack_template/stack_template_ec2.rb +++ b/devops-service/db/mongo/models/stack_template/stack_template_ec2.rb @@ -20,34 +20,25 @@ module Devops raise 'Implement me' end + def update_template_url + self.template_url = generate_template_file_and_upload_to_storage(id, template_body) + end + class << self - def create(attrs) - template = attrs['template_body'] - attrs['template_url'] = generate_template_file_and_upload_to_storage(attrs['id'], template) - super(attrs) + model = super(attrs) + model.update_template_url + model end + end - private + private def generate_template_file_and_upload_to_storage(id, json) - begin - tempfile = Tempfile.new('foo') - tempfile.write(json) - tempfile.close - secure_filename = "#{id}-#{SecureRandom.hex}.template" - upload_file_to_storage(secure_filename, tempfile.path) - ensure - tempfile.unlink - end + uniq_filename = "#{id}-#{SecureRandom.hex}.template" + provider_instance.store_stack_template(uniq_filename, json)['url'] end - def upload_file_to_storage(filename, file_path) - "https://s3.amazonaws.com/#{filename}" - end - - end - end end end diff --git a/devops-service/db/validators/all.rb b/devops-service/db/validators/all.rb index e64b6d0..c40f2f2 100644 --- a/devops-service/db/validators/all.rb +++ b/devops-service/db/validators/all.rb @@ -9,11 +9,12 @@ end require "db/validators/base" [ - 'db/validators/helpers/*.rb', - 'db/validators/deploy_env/*.rb', - 'db/validators/key/*.rb', - 'db/validators/image/*.rb', - 'db/validators/field_validators/*.rb' + 'helpers/*.rb', + 'deploy_env/*.rb', + 'key/*.rb', + 'image/*.rb', + 'field_validators/*.rb' ].each do |files_regexp| - Dir[File.join(Devops::Application.root, files_regexp)].each {|file| require file } + current_dir = File.dirname(__FILE__) + Dir[File.join(current_dir, files_regexp)].each {|file| require file } end diff --git a/devops-service/db/validators/base.rb b/devops-service/db/validators/base.rb index 6e3b488..677e9f2 100644 --- a/devops-service/db/validators/base.rb +++ b/devops-service/db/validators/base.rb @@ -9,6 +9,7 @@ module Validators def validate! raise InvalidRecord.new(message) unless valid? rescue StandardError => e + DevopsLogger.logger.error [e.message, e.backtrace].join("\n") raise InvalidRecord.new("An error raised during validation with #{self.class}: #{e.class}: #{e.message}") end diff --git a/devops-service/db/validators/field_validators/image_id.rb b/devops-service/db/validators/field_validators/image_id.rb new file mode 100644 index 0000000..926a2f6 --- /dev/null +++ b/devops-service/db/validators/field_validators/image_id.rb @@ -0,0 +1,18 @@ +require_relative "base" +module Validators + module FieldValidator + class ImageId < Base + + MAX_LEN = 100 + NAME_REGEX = /\A[\w\-\.]{1,#{MAX_LEN}}\z/ + + def valid? + !NAME_REGEX.match(@value).nil? + end + + def message + "Invalid value '#{@value}': it should contains symbols 'a-zA-Z0-9_-.' and length should be more then 1 and less or equals then #{MAX_LEN}" + end + end + end +end diff --git a/devops-service/db/validators/field_validators/image_name.rb b/devops-service/db/validators/field_validators/image_name.rb index e886a53..c108246 100644 --- a/devops-service/db/validators/field_validators/image_name.rb +++ b/devops-service/db/validators/field_validators/image_name.rb @@ -3,15 +3,14 @@ module Validators module FieldValidator class ImageName < Base - MAX_NAME_LEN = 100 - NAME_REGEX = /\A[\w\-\.]{1,#{MAX_NAME_LEN}}\z/ + MAX_LEN = 100 def valid? - !NAME_REGEX.match(@value).nil? + @value.length <= MAX_LEN end def message - "Invalid value '#{@value}': it should contains symbols 'a-zA-Z0-9_-.' and length should be more then 1 and less or equals then #{MAX_NAME_LEN}" + "Invalid value '#{@value}': it should contains symbols 'a-zA-Z0-9_-.' and length should be more then 1 and less or equals then #{MAX_LEN}" end end end diff --git a/devops-service/db/validators/field_validators/image_username.rb b/devops-service/db/validators/field_validators/image_username.rb new file mode 100644 index 0000000..334011d --- /dev/null +++ b/devops-service/db/validators/field_validators/image_username.rb @@ -0,0 +1,18 @@ +require_relative "base" +module Validators + module FieldValidator + class ImageUsername < Base + + MAX_NAME_LEN = 100 + NAME_REGEX = /\A[\w\-\.]{1,#{MAX_NAME_LEN}}\z/ + + def valid? + !NAME_REGEX.match(@value).nil? + end + + def message + "Invalid value '#{@value}': it should contains symbols 'a-zA-Z0-9_-.' and length should be more then 1 and less or equals then #{MAX_NAME_LEN}" + end + end + end +end diff --git a/devops-service/db/validators/field_validators/provider_account.rb b/devops-service/db/validators/field_validators/provider_account.rb index 3d56074..bd72486 100644 --- a/devops-service/db/validators/field_validators/provider_account.rb +++ b/devops-service/db/validators/field_validators/provider_account.rb @@ -1,11 +1,12 @@ require_relative "base" + module Validators module FieldValidator class ProviderAccount < Base def valid? - accounts = AccountsFactory.accounts(@model.provider) + accounts = ::Provider::AccountsFactory.accounts(@model.provider) accounts.map{|a| a.account_name}.include?(@value) end diff --git a/devops-service/lib/executors/server_executor.rb b/devops-service/lib/executors/server_executor.rb index 0518211..88ac412 100644 --- a/devops-service/lib/executors/server_executor.rb +++ b/devops-service/lib/executors/server_executor.rb @@ -82,7 +82,8 @@ module Devops "deploy_env" => @deploy_env.identifier, "created_by" => options["created_by"], "provider" => @deploy_env.provider, - "provider_account" => @deploy_env.provider_account + "provider_account" => @deploy_env.provider_account, + "private_ip" => options["private_ip"] }) end diff --git a/devops-service/lib/stack_presets/base.rb b/devops-service/lib/stack_presets/base.rb deleted file mode 100644 index ae09ac7..0000000 --- a/devops-service/lib/stack_presets/base.rb +++ /dev/null @@ -1,76 +0,0 @@ -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_presets/factory.rb b/devops-service/lib/stack_presets/factory.rb deleted file mode 100644 index 1bb613e..0000000 --- a/devops-service/lib/stack_presets/factory.rb +++ /dev/null @@ -1,23 +0,0 @@ -require_relative 'base' -require_relative 'postgres_cluster' -require_relative 'preset_not_found' - -class Devops::StackPresetsFactory - - # 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::StackPresets.constants.select do |class_name| - class_name != :Base - end.map do |class_name| - Devops::StackPresets.const_get(class_name).new - end - end - - def self.get(id) - preset = list.detect { |preset| preset.id == id } - raise PresetNotFound, "Preset '#{preset}' not found" unless preset - preset - end - -end \ No newline at end of file diff --git a/devops-service/lib/stack_presets/postgres_cluster.rb b/devops-service/lib/stack_presets/postgres_cluster.rb deleted file mode 100644 index 21f165a..0000000 --- a/devops-service/lib/stack_presets/postgres_cluster.rb +++ /dev/null @@ -1,7 +0,0 @@ -module Devops::StackPresets - class PostgresCluster < Base - def template_file_extension - :yml - end - end -end \ No newline at end of file diff --git a/devops-service/lib/stack_presets/postgres_cluster.yml b/devops-service/lib/stack_presets/postgres_cluster.yml deleted file mode 100644 index 6b8bc1b..0000000 --- a/devops-service/lib/stack_presets/postgres_cluster.yml +++ /dev/null @@ -1,19 +0,0 @@ -heat_template_version: 2013-05-23 - -description: Simple template to deploy a single compute instance - -parameters: - key_name: - type: string - label: Key Name - description: Name of key-pair to be used for compute instance - -resources: - my_instance: - type: OS::Nova::Server - properties: - key_name: { get_param: key_name } - 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_presets/preset_not_found.rb b/devops-service/lib/stack_presets/preset_not_found.rb deleted file mode 100644 index 5b28c4d..0000000 --- a/devops-service/lib/stack_presets/preset_not_found.rb +++ /dev/null @@ -1,3 +0,0 @@ -class PresetNotFound < StandardError - -end \ No newline at end of file diff --git a/devops-service/providers/ec2.rb b/devops-service/providers/ec2.rb index dbb5d6b..be008f4 100644 --- a/devops-service/providers/ec2.rb +++ b/devops-service/providers/ec2.rb @@ -56,7 +56,7 @@ module Provider end def groups filters={} - g = self.compute.describe_security_groups(filters) + g = self.compute.describe_security_groups(filters || {}) convert_groups(g.body["securityGroupInfo"]) end @@ -99,7 +99,8 @@ module Provider options = { "InstanceType" => flavor, # "Placement.AvailabilityZone" => s.options[:availability_zone], - "KeyName" => self.ssh_key + "KeyName" => self.ssh_key, + "PrivateIpAddress" => s.private_ip } vpcId = nil unless subnets.empty? @@ -222,7 +223,7 @@ module Provider out.flush response = cloud_formation.create_stack(stack.name, { - 'TemplateBody' => stack.template_body, + 'TemplateURL' => stack.stack_template_model.template_url, 'Parameters' => stack.parameters || {}, 'Capabilities' => ['CAPABILITY_IAM'], 'Tags' => stack_tags(stack) @@ -320,6 +321,17 @@ module Provider def describe_vpcs self.compute.describe_vpcs.body["vpcSet"].select{|v| v["state"] == "available"}.map{|v| {"vpc_id" => v["vpcId"], "cidr" => v["cidrBlock"] } } end + + def store_stack_template(filename, json) + store_file(stack_templates_bucket, filename, json) + end + + def store_file(bucket, filename, body) + { + 'url' => bucket.files.create(key: filename, body: body, public: true).public_url + } + end + private def convert_groups list @@ -376,6 +388,16 @@ module Provider @orchestration ||= Fog::AWS::CloudFormation.new(connection_options) end + def storage + @storage ||= Fog::Storage.new(connection_options) + end + + def stack_templates_bucket + bucket_name = DevopsConfig.config[:aws_stack_templates_bucket] || 'stacktemplatesnibrdev' + bucket = storage.directories.get(bucket_name) + bucket ||= storage.directories.create(key: bucket_name) + end + def instance_name(instance) return instance["tagSet"]["Name"] if instance["tagSet"]["Name"] if instance['tagSet']['aws:autoscaling:groupName'] diff --git a/devops-service/spec/connectors/filter_connector_spec.rb b/devops-service/spec/connectors/filter_connector_spec.rb index 2850835..6eb808d 100644 --- a/devops-service/spec/connectors/filter_connector_spec.rb +++ b/devops-service/spec/connectors/filter_connector_spec.rb @@ -1,10 +1,8 @@ require 'db/mongo/connectors/filter' require 'spec/connectors/tester_connector/filter' -require_relative 'shared_connectors_context' RSpec.describe Connectors::Filter, type: :connector do set_tester_connector TesterConnector::Filter - include_context 'connectors' let(:provider) {'ec2'} describe '#available_images' do diff --git a/devops-service/spec/connectors/image_connector_spec.rb b/devops-service/spec/connectors/image_connector_spec.rb index 585d728..31653f5 100644 --- a/devops-service/spec/connectors/image_connector_spec.rb +++ b/devops-service/spec/connectors/image_connector_spec.rb @@ -1,10 +1,8 @@ require 'db/mongo/connectors/image' require 'spec/connectors/tester_connector/image' -require_relative 'shared_connectors_context' RSpec.describe Connectors::Image, type: :connector do set_tester_connector TesterConnector::Image - include_context 'connectors' let(:model_class) { Devops::Model::Image } include_examples 'mongo connector', { diff --git a/devops-service/spec/connectors/key_connector_spec.rb b/devops-service/spec/connectors/key_connector_spec.rb index 9be46ee..ae64bf1 100644 --- a/devops-service/spec/connectors/key_connector_spec.rb +++ b/devops-service/spec/connectors/key_connector_spec.rb @@ -1,11 +1,9 @@ require 'db/mongo/connectors/key' require 'db/mongo/models/key' require 'spec/connectors/tester_connector/key' -require_relative 'shared_connectors_context' RSpec.describe Connectors::Key, type: :connector do set_tester_connector TesterConnector::Key - include_context 'connectors' let(:model_class) { Devops::Model::Key } include_examples 'mongo connector', model_name: :key, only: [:insert, :list] diff --git a/devops-service/spec/connectors/project_connector_spec.rb b/devops-service/spec/connectors/project_connector_spec.rb index 2b86bd8..b286a24 100644 --- a/devops-service/spec/connectors/project_connector_spec.rb +++ b/devops-service/spec/connectors/project_connector_spec.rb @@ -1,10 +1,8 @@ require 'db/mongo/connectors/project' require 'spec/connectors/tester_connector/project' -require_relative 'shared_connectors_context' RSpec.describe Connectors::Project, type: :connector do set_tester_connector TesterConnector::Project - include_context 'connectors' let(:model_class) { Devops::Model::Project } include_examples 'mongo connector', { diff --git a/devops-service/spec/support/shared_connectors_specs.rb b/devops-service/spec/connectors/shared_connectors_specs.rb similarity index 100% rename from devops-service/spec/support/shared_connectors_specs.rb rename to devops-service/spec/connectors/shared_connectors_specs.rb diff --git a/devops-service/spec/connectors/stack_template_connector_spec.rb b/devops-service/spec/connectors/stack_template_connector_spec.rb index edb9fe7..b0bc860 100644 --- a/devops-service/spec/connectors/stack_template_connector_spec.rb +++ b/devops-service/spec/connectors/stack_template_connector_spec.rb @@ -1,10 +1,8 @@ require 'db/mongo/connectors/stack_template' require 'spec/connectors/tester_connector/stack_template' -require_relative 'shared_connectors_context' RSpec.describe Connectors::StackTemplate, type: :connector do set_tester_connector TesterConnector::StackTemplate - include_context 'connectors' let(:model_class) { Devops::Model::StackTemplateEc2 } include_examples 'mongo connector', { diff --git a/devops-service/spec/factories/provider_account.rb b/devops-service/spec/factories/provider_account.rb new file mode 100644 index 0000000..f239513 --- /dev/null +++ b/devops-service/spec/factories/provider_account.rb @@ -0,0 +1,25 @@ +require 'db/mongo/models/provider_accounts/ec2_provider_account' +require 'db/mongo/models/provider_accounts/openstack_provider_account' +require 'db/mongo/models/provider_accounts/static_provider_account' + +FactoryGirl.define do + factory :provider_account, class: Devops::Model::ProviderAccount do + account_name 'name' + description 'desc' + ssh_key 'user_key' + + + factory :static_provider_account, class: Devops::Model::StaticProviderAccount do + end + + factory :ec2_provider_account, class: Devops::Model::Ec2ProviderAccount do + provider 'ec2' + access_key_id 'access' + secret_access_key 'secret' + end + + factory :openstack_provider_account, class: Devops::Model::OpenstackProviderAccount do + provider 'openstack' + end + end +end \ No newline at end of file diff --git a/devops-service/spec/models/deploy_env/deploy_env_ec2_spec.rb b/devops-service/spec/models/deploy_env/deploy_env_ec2_spec.rb index 2d3b2d8..1886a1c 100644 --- a/devops-service/spec/models/deploy_env/deploy_env_ec2_spec.rb +++ b/devops-service/spec/models/deploy_env/deploy_env_ec2_spec.rb @@ -1,12 +1,14 @@ require 'db/mongo/models/deploy_env/deploy_env_ec2' -require_relative '../shared_models_context' +require_relative 'shared_deploy_env_specs' +require_relative 'shared_cloud_deploy_env_specs' RSpec.describe Devops::Model::DeployEnvEc2, type: :model do let(:env) { build(:deploy_env_ec2) } - include_context 'stubbed calls to connector in env validators' - it_behaves_like 'deploy env' - it_behaves_like 'cloud deploy env' + describe 'it inherits from cloud deploy_env', stubbed_env_validators: true, stubbed_logger: true do + it_behaves_like 'deploy env' + it_behaves_like 'cloud deploy env' + end describe '#initialize' do it 'keep only first subnet in given array' do diff --git a/devops-service/spec/models/deploy_env/deploy_env_openstack_spec.rb b/devops-service/spec/models/deploy_env/deploy_env_openstack_spec.rb index 08783b6..96fdfd7 100644 --- a/devops-service/spec/models/deploy_env/deploy_env_openstack_spec.rb +++ b/devops-service/spec/models/deploy_env/deploy_env_openstack_spec.rb @@ -1,12 +1,14 @@ require 'db/mongo/models/deploy_env/deploy_env_openstack' -require_relative '../shared_models_context' +require_relative 'shared_deploy_env_specs' +require_relative 'shared_cloud_deploy_env_specs' RSpec.describe Devops::Model::DeployEnvOpenstack, type: :model do let(:env) { build(:deploy_env_openstack) } - include_context 'stubbed calls to connector in env validators' - it_behaves_like 'deploy env' - it_behaves_like 'cloud deploy env' + describe 'it inherits from cloud deploy_env', stubbed_env_validators: true, stubbed_logger: true do + it_behaves_like 'deploy env' + it_behaves_like 'cloud deploy env' + end describe '.create' do it 'returns instance of DeployEnvOpenstack' do diff --git a/devops-service/spec/models/deploy_env/deploy_env_static_spec.rb b/devops-service/spec/models/deploy_env/deploy_env_static_spec.rb index 2f1d584..45ad446 100644 --- a/devops-service/spec/models/deploy_env/deploy_env_static_spec.rb +++ b/devops-service/spec/models/deploy_env/deploy_env_static_spec.rb @@ -1,14 +1,19 @@ require 'db/mongo/models/deploy_env/deploy_env_static' +require_relative 'shared_deploy_env_specs' RSpec.describe Devops::Model::DeployEnvStatic, type: :model do let(:env) { build(:deploy_env_static) } - before do - allow(Provider::ProviderFactory).to receive(:providers).and_return(%w(static)) - allow_any_instance_of(Validators::Helpers::Users).to receive(:available_users).and_return(['root']) + + describe 'it inherits from deploy env', stubbed_logger: true do + before do + allow(Provider::ProviderFactory).to receive(:providers).and_return(%w(static)) + allow_any_instance_of(Validators::Helpers::Users).to receive(:available_users).and_return(['root']) + end + + it_behaves_like 'deploy env' end - it_behaves_like 'deploy env' describe '.create' do it 'returns instance of DeployEnvStatic' do diff --git a/devops-service/spec/support/shared_cloud_deploy_env_specs.rb b/devops-service/spec/models/deploy_env/shared_cloud_deploy_env_specs.rb similarity index 100% rename from devops-service/spec/support/shared_cloud_deploy_env_specs.rb rename to devops-service/spec/models/deploy_env/shared_cloud_deploy_env_specs.rb diff --git a/devops-service/spec/support/shared_deploy_env_specs.rb b/devops-service/spec/models/deploy_env/shared_deploy_env_specs.rb similarity index 89% rename from devops-service/spec/support/shared_deploy_env_specs.rb rename to devops-service/spec/models/deploy_env/shared_deploy_env_specs.rb index a23b1b6..538f838 100644 --- a/devops-service/spec/support/shared_deploy_env_specs.rb +++ b/devops-service/spec/models/deploy_env/shared_deploy_env_specs.rb @@ -1,9 +1,5 @@ -require 'core/devops-application' -require 'core/devops-db' - RSpec.shared_examples 'deploy env' do validated_model_name = described_class.name.demodulize.underscore - include SpecSupport it 'is valid with correct attrs' do expect(env).to be_valid @@ -81,11 +77,10 @@ RSpec.shared_examples 'deploy env' do end end - describe '#update_field' do + describe '#update_field', stubbed_connector: true do subject { env.update_field('project_name', 'run_list', ['role[asd]']) } before do - allow_message_expectations_on_nil - allow(Devops::Db.connector).to receive(:set_project_deploy_env_field) + allow(stubbed_connector).to receive(:set_project_deploy_env_field) end it 'validate it' do @@ -98,12 +93,13 @@ RSpec.shared_examples 'deploy env' do end it 'saves it' do - expect(Devops::Db.connector).to receive(:set_project_deploy_env_field).with('project_name', env.identifier, {'run_list' => ['role[asd]']}) + expected_args = ['project_name', env.identifier, {'run_list' => ['role[asd]']}] + expect(stubbed_connector).to receive(:set_project_deploy_env_field).with(*expected_args) subject end end - describe '#create_role', stub_logger: true do + describe '#create_role', stubbed_logger: true do subject { env.create_role('project_name') } before do allow(env).to receive_message_chain('knife_instance.role_name') { 'role_name' } @@ -152,7 +148,7 @@ RSpec.shared_examples 'deploy env' do end end - describe '#rename', stub_logger: true do + describe '#rename', stubbed_logger: true do subject { env.rename('project_id', 'new_name') } let(:old_role_name) {'project_id_name'} let(:new_role_name) {'project_id_new_name'} @@ -174,15 +170,16 @@ RSpec.shared_examples 'deploy env' do stub_const('Devops::Model::Project', project_class_double) end - it 'raises InvalidRecord if env with such name already exists in project' do - allow(Devops::Db.connector).to receive_message_chain('project.deploy_env') + it 'raises InvalidRecord if env with such name already exists in project', stubbed_connector: true do + project = build(:project, with_deploy_env_identifiers: %w(new_name)) + allow(stubbed_connector).to receive(:project) { project } expect{subject}.to raise_error(InvalidRecord) end - context 'when there is no env with such name already' do + context 'when there is no env with such name already', stubbed_connector: true do before do - allow(Devops::Db.connector).to receive_message_chain('project.deploy_env') {raise RecordNotFound} - allow(Devops::Db.connector).to receive(:set_project_deploy_env_field) + allow(stubbed_connector).to receive(:project) { build(:project) } + allow(stubbed_connector).to receive(:set_project_deploy_env_field) end it 'validates new identifier' do diff --git a/devops-service/spec/models/image_spec.rb b/devops-service/spec/models/image_spec.rb index 769e04a..39e630d 100644 --- a/devops-service/spec/models/image_spec.rb +++ b/devops-service/spec/models/image_spec.rb @@ -2,35 +2,44 @@ require 'db/mongo/models/image' RSpec.describe Devops::Model::Image, type: :model do let(:image) { build(:image) } - let(:name_with_dash) { 'asd-asd' } - let(:name_with_slash) { 'asd/asd' } + let(:string_with_dash) { 'asd-asd' } + let(:string_with_slash) { 'asd/asd' } + let(:string_with_parenthesis) { 'centos 6.5 x86_64 (development instance)' } before do allow(Provider::ProviderFactory).to receive(:providers).and_return(%w(openstack ec2 static')) - allow_any_instance_of(Validators::Image::ImageInFilter).to receive(:available_images).and_return([{'id' => 'test_image'}, {'id' => name_with_dash}, {'id' => name_with_slash}]) + allow_any_instance_of(Validators::Image::ImageInFilter).to receive(:available_images).and_return([{'id' => 'test_image'}, {'id' => string_with_dash}, {'id' => string_with_slash}]) end it 'is valid with correct attrs' do expect(image).to be_valid end - describe 'validation' do + describe 'validation', stubbed_logger: true do include_examples 'field type validation', :id, :not_nil, :non_empty_string, :field_validator include_examples 'field type validation', :remote_user, :not_nil, :non_empty_string, :field_validator include_examples 'field type validation', :name, :not_nil, :non_empty_string, :field_validator include_examples 'field type validation', :bootstrap_template, :maybe_nil, :non_empty_string, :only_word_symbols, :field_validator it 'id should contain only letters, digits and dashes' do - expect(build(:image, id: name_with_dash)).to be_valid - expect(build(:image, id: name_with_slash)).not_to be_valid + expect(build(:image, id: string_with_dash)).to be_valid + expect(build(:image, id: string_with_slash)).not_to be_valid + expect(build(:image, id: string_with_parenthesis)).not_to be_valid end it "id should be included in image filters" do expect(build(:image, id: 'wrong')).not_to be_valid end - it 'name should contain only letters, digits and dashes' do - expect(build(:image, name: name_with_slash)).not_to be_valid + it 'name may contain everything' do + expect(build(:image, name: string_with_dash)).to be_valid + expect(build(:image, name: string_with_slash)).to be_valid + expect(build(:image, name: string_with_parenthesis)).to be_valid + end + + it 'name length should be less or equal than 100' do + expect(build(:image, name: 'a'*100)).to be_valid + expect(build(:image, name: 'a'*101)).not_to be_valid end it 'bootstrap_template should be included in available bootstrap templates' do diff --git a/devops-service/spec/models/key_spec.rb b/devops-service/spec/models/key_spec.rb index 8a2108c..bed5d79 100644 --- a/devops-service/spec/models/key_spec.rb +++ b/devops-service/spec/models/key_spec.rb @@ -7,7 +7,7 @@ RSpec.describe Devops::Model::Key, type: :model do expect(key).to be_valid end - describe 'validations' do + describe 'validations', stubbed_logger: true do it 'key file should exist in file system' do expect(build(:key, path: './not_exist')).not_to be_valid end diff --git a/devops-service/spec/models/project_spec.rb b/devops-service/spec/models/project_spec.rb index bed0128..6457ebb 100644 --- a/devops-service/spec/models/project_spec.rb +++ b/devops-service/spec/models/project_spec.rb @@ -1,11 +1,9 @@ require 'db/mongo/models/project' -require_relative 'shared_models_context' RSpec.describe Devops::Model::Project, type: :model do let(:project) { build(:project) } - include_context 'stubbed calls to connector in env validators' - describe 'validation rules:' do + describe 'validation rules:', stubbed_env_validators: true, stubbed_logger: true do include_examples 'field type validation', :id, :not_nil, :non_empty_string include_examples 'field type validation', :deploy_envs, :not_nil, :non_empty_array include_examples 'field type validation', :description, :maybe_nil, :maybe_empty_string @@ -90,7 +88,7 @@ RSpec.describe Devops::Model::Project, type: :model do end end - describe '#add_deploy_env', stub_logger: true do + describe '#add_deploy_env', stubbed_logger: true do let(:env) {build(:deploy_env_ec2)} subject { project.add_deploy_env(env) } before do @@ -235,9 +233,9 @@ RSpec.describe Devops::Model::Project, type: :model do end describe '#delete_deploy_env' do - it 'removes env' do - allow(Devops::Db).to receive_message_chain('connector.remove_deploy_env_from_project') - expect(Devops::Db).to receive_message_chain('connector.remove_deploy_env_from_project').with(project.id, 'foo') + it 'removes env', stubbed_connector: true do + allow(stubbed_connector).to receive(:remove_deploy_env_from_project) + expect(stubbed_connector).to receive(:remove_deploy_env_from_project).with(project.id, 'foo') project.delete_deploy_env('foo') expect(project.deploy_envs).to match_array [] end @@ -271,4 +269,93 @@ RSpec.describe Devops::Model::Project, type: :model do end end + describe '#to_hash_list' do + it 'returns hash' do + expect(project.to_hash_list).to be_a(Hash) + end + end + + describe '#deploy_info' do + subject { project.deploy_info(project.deploy_env('foo')) } + it 'returns hash' do + expect(subject).to be_a(Hash) + end + + it 'includes use_json_file, project and project_info' do + expect(subject).to include('use_json_file', 'project', 'project_info') + expect(subject['project_info']).to be_a(Hash) + end + end + + describe '#to_hash_without_id' do + subject { project.to_hash_without_id } + it 'returns a hash' do + expect(subject).to be_a(Hash) + end + + it "doesn't include id or name" do + expect(subject).not_to include('id', 'name') + end + end + + describe '#create', stubbed_connector: true do + before do + allow(stubbed_connector).to receive(:project_insert) + end + subject { project.create } + + it 'run hooks' do + expect(project).to receive(:run_hook).with(:before_create).ordered + expect(project).to receive(:run_hook).with(:after_create).ordered + subject + end + + it 'inserts record into DB' do + expect(stubbed_connector).to receive(:project_insert).with(project) + subject + end + + it 'returns a hash' do + expect(subject).to be_a(Hash) + end + end + + describe '#delete', stubbed_connector: true do + before do + allow(stubbed_connector).to receive(:project_delete) + end + subject { project.delete } + + it 'run hooks' do + expect(project).to receive(:run_hook).with(:before_delete).ordered + expect(project).to receive(:run_hook).with(:after_delete).ordered + subject + end + + it 'deletes record into DB' do + expect(stubbed_connector).to receive(:project_delete).with(project.id) + subject + end + + it 'returns a hash' do + expect(subject).to be_a(Hash) + end + end + + # maybe it worth to move components functionality to devops-nibr? + # describe '#validate_components' do + # it "raises InvalidRecord if one of component doesn't include filename" do + # project.components = {'name' => {}} + # expect{project.validate_components}.to raise_error(InvalidRecord) + # end + # end + + describe '.create_roles_response' do + it 'returns string' do + expect(described_class.create_roles_response('string')).to be_a(String) + hash = {new: %w(a), exist: %w(b), error: %w(c)} + expect(described_class.create_roles_response(hash)).to be_a(String) + end + end + end \ No newline at end of file diff --git a/devops-service/spec/models/provider_account/ec2_provider_account_spec.rb b/devops-service/spec/models/provider_account/ec2_provider_account_spec.rb new file mode 100644 index 0000000..8145ea0 --- /dev/null +++ b/devops-service/spec/models/provider_account/ec2_provider_account_spec.rb @@ -0,0 +1,70 @@ +require 'spec_helper' + +RSpec.describe Devops::Model::Ec2ProviderAccount, type: :model do + let(:provider_account) { build(:ec2_provider_account) } + + + describe 'validation rules', stubbed_connector: true do + before do + allow(Provider::ProviderFactory).to receive(:providers).and_return(%w(ec2 openstack)) + allow(stubbed_connector).to receive(:key) + end + + it 'set validators' do + expect(provider_account).to respond_to(:validate_access_key_id!) + end + + it 'is valid with valid attrs' do + provider_account.validate! + expect(provider_account).to be_valid + end + + include_examples 'field type validation', :account_name, :not_nil, :non_empty_string + include_examples 'field type validation', :description, :maybe_nil, :non_empty_string + include_examples 'field type validation', :ssh_key, :not_nil, :non_empty_string + include_examples 'field type validation', :access_key_id, :not_nil, :non_empty_string + include_examples 'field type validation', :secret_access_key, :not_nil, :non_empty_string + + it "isn't valid if description length is more than 500" do + provider_account.description = 'a' * 501 + expect(provider_account).not_to be_valid + expect{ provider_account.validate_description! }.to raise_error InvalidRecord + end + + it "isn't valid if keys collection doesn't include given key" do + allow(stubbed_connector).to receive(:key) { raise RecordNotFound} + expect(provider_account).not_to be_valid + end + end + + describe '#initialize' do + it 'sets provider to ec2' do + expect(described_class.new.provider).to eq 'ec2' + end + end + + describe '#to_mongo_hash' do + it 'returns hash with several keys' do + expect( + provider_account.to_mongo_hash.keys + ).to include(*%w(availability_zone access_key_id secret_access_key _id description ssh_key provider)) + end + end + + describe '.build_from_bson' do + subject { described_class.build_from_bson('_id' => 'asd') } + + it 'returns an instance of Devops::Model::Ec2ProviderAccount' do + expect(subject).to be_an_instance_of(described_class) + expect(subject.account_name).to eq 'asd' + end + end + + describe '.account_fields' do + it 'returns hash with several keys' do + expect( + described_class.account_fields.keys + ).to include(*%i(availability_zone access_key_id secret_access_key description ssh_key account_name)) + end + end +end \ No newline at end of file diff --git a/devops-service/spec/models/provider_account/openstack_provider_account_spec.rb b/devops-service/spec/models/provider_account/openstack_provider_account_spec.rb new file mode 100644 index 0000000..4e31025 --- /dev/null +++ b/devops-service/spec/models/provider_account/openstack_provider_account_spec.rb @@ -0,0 +1,13 @@ +require 'spec_helper' + +# не пытайся выделить в shared_specs, фигня выйдет +RSpec.describe Devops::Model::OpenstackProviderAccount, type: :model do + let(:provider_account) { build(:openstack_provider_account) } + + it "should not validate access_key_id", stubbed_logger: true do + pending "waiting for mongoid support to be finished" + fields = described_class.field_validators.values.flatten.flatten.map{|t| t[:field]} + expect(fields).not_to include(:access_key_id, :secret_access_key) + end + +end \ No newline at end of file diff --git a/devops-service/spec/models/server_spec.rb b/devops-service/spec/models/server_spec.rb index d49f328..c744618 100644 --- a/devops-service/spec/models/server_spec.rb +++ b/devops-service/spec/models/server_spec.rb @@ -11,7 +11,7 @@ RSpec.describe Devops::Model::Server, type: :model do expect(server).to be_valid end - describe 'validation rules:' do + describe 'validation rules:', stubbed_logger: true do include_examples 'field type validation', :id, :not_nil, :non_empty_string include_examples 'field type validation', :provider, :not_nil, :non_empty_string include_examples 'field type validation', :remote_user, :not_nil, :non_empty_string diff --git a/devops-service/spec/support/shared_validation_specs.rb b/devops-service/spec/models/shared_validation_specs.rb similarity index 100% rename from devops-service/spec/support/shared_validation_specs.rb rename to devops-service/spec/models/shared_validation_specs.rb diff --git a/devops-service/spec/models/stack/stack_ec2_spec.rb b/devops-service/spec/models/stack/stack_ec2_spec.rb index 17fa499..1e02927 100644 --- a/devops-service/spec/models/stack/stack_ec2_spec.rb +++ b/devops-service/spec/models/stack/stack_ec2_spec.rb @@ -11,7 +11,7 @@ RSpec.describe Devops::Model::StackEc2, type: :model do expect(build(:stack_ec2)).to be_valid end - describe 'validation rules:' do + describe 'validation rules:', stubbed_logger: true do include_examples 'field type validation', :id, :not_nil, :non_empty_string, :field_validator include_examples 'field type validation', :project, :not_nil, :non_empty_string, :field_validator include_examples 'field type validation', :deploy_env, :not_nil, :non_empty_string, :field_validator diff --git a/devops-service/spec/support/shared_stack_template_specs.rb b/devops-service/spec/models/stack_template/shared_stack_template_specs.rb similarity index 100% rename from devops-service/spec/support/shared_stack_template_specs.rb rename to devops-service/spec/models/stack_template/shared_stack_template_specs.rb diff --git a/devops-service/spec/models/stack_template/stack_template_ec2_spec.rb b/devops-service/spec/models/stack_template/stack_template_ec2_spec.rb index 1cb48af..3386445 100644 --- a/devops-service/spec/models/stack_template/stack_template_ec2_spec.rb +++ b/devops-service/spec/models/stack_template/stack_template_ec2_spec.rb @@ -1,4 +1,5 @@ require 'db/mongo/models/stack_template/stack_template_ec2' +require_relative 'shared_stack_template_specs' RSpec.describe Devops::Model::StackTemplateEc2, type: :model do let(:stack_template) { build(:stack_template_ec2) } @@ -6,8 +7,20 @@ RSpec.describe Devops::Model::StackTemplateEc2, type: :model do before do allow(Provider::ProviderFactory).to receive(:providers).and_return(%w(ec2)) allow_any_instance_of(Devops::Model::StackTemplateEc2).to receive_message_chain('provider_instance.validate_stack_template') { true } + allow_any_instance_of(Devops::Model::StackTemplateEc2).to receive_message_chain('provider_instance.store_stack_template') { {'url' => nil} } end it_behaves_like 'stack template' + it 'uploads file to S3' do + expect_any_instance_of(Devops::Model::StackTemplateEc2).to receive_message_chain('provider_instance.store_stack_template') + params = { + 'id' => 'foo', + 'template_body' => '{}', + 'owner' => 'root', + 'provider' => 'ec2' + } + expect(described_class.create(params)).to be_an_instance_of(described_class) + end + end \ No newline at end of file diff --git a/devops-service/spec/shared_contexts/auto_require_shared_specs.rb b/devops-service/spec/shared_contexts/auto_require_shared_specs.rb new file mode 100644 index 0000000..eeabd9a --- /dev/null +++ b/devops-service/spec/shared_contexts/auto_require_shared_specs.rb @@ -0,0 +1,7 @@ +RSpec.shared_context 'auto_model', type: :model do + require 'spec/models/shared_validation_specs' +end + +RSpec.shared_context 'auto_connector', type: :connector do + require 'spec/connectors/shared_connectors_specs' +end \ No newline at end of file diff --git a/devops-service/spec/shared_contexts/stubbed_connector.rb b/devops-service/spec/shared_contexts/stubbed_connector.rb new file mode 100644 index 0000000..7d6dabb --- /dev/null +++ b/devops-service/spec/shared_contexts/stubbed_connector.rb @@ -0,0 +1,6 @@ +RSpec.shared_context 'stubbed calls to connector', stubbed_connector: true do + let(:stubbed_connector) { double() } + before do + allow(Devops::Db).to receive(:connector) { stubbed_connector } + end +end \ No newline at end of file diff --git a/devops-service/spec/models/shared_models_context.rb b/devops-service/spec/shared_contexts/stubbed_env_validators.rb similarity index 79% rename from devops-service/spec/models/shared_models_context.rb rename to devops-service/spec/shared_contexts/stubbed_env_validators.rb index fe5e754..69f081c 100644 --- a/devops-service/spec/models/shared_models_context.rb +++ b/devops-service/spec/shared_contexts/stubbed_env_validators.rb @@ -1,4 +1,4 @@ -RSpec.shared_context 'stubbed calls to connector in env validators' do +RSpec.shared_context 'stubbed calls to connector in env validators', stubbed_env_validators: true do before do allow(Provider::ProviderFactory).to receive(:providers).and_return(%w(ec2 openstack)) allow_any_instance_of(Validators::Helpers::Users).to receive(:available_users).and_return(['root']) @@ -10,12 +10,4 @@ RSpec.shared_context 'stubbed calls to connector in env validators' do allow_any_instance_of(Validators::DeployEnv::StackTemplate).to receive(:available_stack_templates).and_return([{'id' => 'template'}]) allow_any_instance_of(Validators::FieldValidator::Image).to receive(:available_images).and_return([{'id' => 'image'}]) end -end - -RSpec.shared_context 'stubbed calls to logger', stub_logger: true do - before do - allow(DevopsLogger).to receive_message_chain('logger.debug') - allow(DevopsLogger).to receive_message_chain('logger.info') - allow(DevopsLogger).to receive_message_chain('logger.error') - end -end +end \ No newline at end of file diff --git a/devops-service/spec/shared_contexts/stubbed_logger.rb b/devops-service/spec/shared_contexts/stubbed_logger.rb new file mode 100644 index 0000000..f2d79e9 --- /dev/null +++ b/devops-service/spec/shared_contexts/stubbed_logger.rb @@ -0,0 +1,7 @@ +RSpec.shared_context 'stubbed calls to logger', stubbed_logger: true do + before do + allow(DevopsLogger).to receive_message_chain('logger.debug') + allow(DevopsLogger).to receive_message_chain('logger.info') + allow(DevopsLogger).to receive_message_chain('logger.error') + end +end \ No newline at end of file diff --git a/devops-service/spec/connectors/shared_connectors_context.rb b/devops-service/spec/shared_contexts/with_tester_connector.rb similarity index 85% rename from devops-service/spec/connectors/shared_connectors_context.rb rename to devops-service/spec/shared_contexts/with_tester_connector.rb index 3c0fedb..8bb586e 100644 --- a/devops-service/spec/connectors/shared_connectors_context.rb +++ b/devops-service/spec/shared_contexts/with_tester_connector.rb @@ -2,9 +2,10 @@ def set_tester_connector(klass) define_method :tester_connector_class do klass end + include_context 'with tester connector' end -RSpec.shared_context 'connectors' do +RSpec.shared_context 'with tester connector' do before(:all) do @connector = described_class.new(SpecSupport.db) @tester_connector = tester_connector_class.new diff --git a/devops-service/spec/spec_helper.rb b/devops-service/spec/spec_helper.rb index ac74d92..9f2500f 100644 --- a/devops-service/spec/spec_helper.rb +++ b/devops-service/spec/spec_helper.rb @@ -13,6 +13,7 @@ original_stdout = $stdout $stdout = File.open(File::NULL, "w") Dir[("./spec/support/**/*.rb")].each { |f| require f } +Dir[("./spec/shared_contexts/**/*.rb")].each { |f| require f } # Factory girl configuration FactoryGirl.define do diff --git a/devops-service/spec/support/spec_support.rb b/devops-service/spec/support/spec_support.rb index 14a684a..ab47bc6 100644 --- a/devops-service/spec/support/spec_support.rb +++ b/devops-service/spec/support/spec_support.rb @@ -5,7 +5,7 @@ module SpecSupport BLANK_FILE = File.join(ROOT, 'spec/support/blank_file') def self.db_params - @db ||= begin + @db_params ||= begin conf = config['mongo'] db_name = conf.fetch(:db) [db_name, conf[:host], conf[:port], conf[:user], conf[:password]] diff --git a/devops-service/tests/generate_tests.rb b/devops-service/tests/generate_tests.rb index b797fd3..2f8a4da 100755 --- a/devops-service/tests/generate_tests.rb +++ b/devops-service/tests/generate_tests.rb @@ -94,7 +94,6 @@ templates = { #list "templates/api_v2/00_list/flavor.feature.erb" => "features/api_v2/00_list/flavor.feature", - "templates/api_v2/00_list/stack_preset.feature.erb" => "features/api_v2/00_list/stack_preset.feature", "templates/api_v2/00_list/00_network.feature.erb" => "features/api_v2/00_list/00_network.feature", "templates/api_v2/00_list/10_user.feature.erb" => "features/api_v2/00_list/10_user.feature", "templates/api_v2/00_list/10_group.feature.erb" => "features/api_v2/00_list/10_group.feature", diff --git a/devops-service/tests/templates/api_v2/00_list/stack_preset.feature.erb b/devops-service/tests/templates/api_v2/00_list/stack_preset.feature.erb deleted file mode 100644 index f2c2311..0000000 --- a/devops-service/tests/templates/api_v2/00_list/stack_preset.feature.erb +++ /dev/null @@ -1,28 +0,0 @@ -@stack_preset @list -Feature: stack template preset list - - Scenario: Get list of all stack template presets - 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 - And response array should contains elements like: - """ - [ - { - "id": "test", - "template_body": "long body" - } - ] - """ - - Scenario: Get information about particular stack template preset - 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_body": "long body" - } - """