From 57f5bf0f2e3e1b8a643f8e42aed5feca951032b5 Mon Sep 17 00:00:00 2001 From: Anton Chuchkalov Date: Fri, 18 Dec 2015 18:35:12 +0400 Subject: [PATCH 01/11] Unbootstrap: delete node from chef server only if /etc/chef directory was successfully moved --- devops-service/lib/executors/server_executor.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/devops-service/lib/executors/server_executor.rb b/devops-service/lib/executors/server_executor.rb index 7ff7fdc..a8bda22 100644 --- a/devops-service/lib/executors/server_executor.rb +++ b/devops-service/lib/executors/server_executor.rb @@ -213,7 +213,10 @@ module Devops DevopsLogger.logger.info msg r else - @out << "Can not bootstrap node '#{@server.id}', error code: #{r}" + @out << "Can not bootstrap node '#{@server.id}', error code: #{r}\n" + if r == 256 + @out << "Maybe old chef client configuration still exists?\n" + end @out.flush result_code(:server_bootstrap_fail) end @@ -309,7 +312,7 @@ module Devops k = Devops::Db.connector.key(@server.key) cert_path = k.path i = 0 - res = delete_from_chef_server(@server.chef_node_name) + res = {} begin new_name = "/etc/chef.backup_#{Time.now.strftime("%d-%m-%Y_%H.%M.%S")}" # r = `ssh -i #{cert_path} -q #{@server.remote_user}@#{@server.private_ip} rm -Rf /etc/chef` @@ -329,7 +332,9 @@ module Devops retry unless i == 5 return {error: e.message} end - res + + deleting_chef_node_and_chef_client_result = delete_from_chef_server(@server.chef_node_name) + res.merge!(deleting_chef_node_and_chef_client_result) end def deploy_server_with_tags tags, deploy_info From fe2b99b80f0fcf20af8a5d4272bc67435e204150 Mon Sep 17 00:00:00 2001 From: Anton Chuchkalov Date: Mon, 21 Dec 2015 14:04:39 +0400 Subject: [PATCH 02/11] Revert "Unbootstrap: delete node from chef server only if /etc/chef directory was successfully moved" This reverts commit 57f5bf0f2e3e1b8a643f8e42aed5feca951032b5. --- devops-service/lib/executors/server_executor.rb | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/devops-service/lib/executors/server_executor.rb b/devops-service/lib/executors/server_executor.rb index a8bda22..7ff7fdc 100644 --- a/devops-service/lib/executors/server_executor.rb +++ b/devops-service/lib/executors/server_executor.rb @@ -213,10 +213,7 @@ module Devops DevopsLogger.logger.info msg r else - @out << "Can not bootstrap node '#{@server.id}', error code: #{r}\n" - if r == 256 - @out << "Maybe old chef client configuration still exists?\n" - end + @out << "Can not bootstrap node '#{@server.id}', error code: #{r}" @out.flush result_code(:server_bootstrap_fail) end @@ -312,7 +309,7 @@ module Devops k = Devops::Db.connector.key(@server.key) cert_path = k.path i = 0 - res = {} + res = delete_from_chef_server(@server.chef_node_name) begin new_name = "/etc/chef.backup_#{Time.now.strftime("%d-%m-%Y_%H.%M.%S")}" # r = `ssh -i #{cert_path} -q #{@server.remote_user}@#{@server.private_ip} rm -Rf /etc/chef` @@ -332,9 +329,7 @@ module Devops retry unless i == 5 return {error: e.message} end - - deleting_chef_node_and_chef_client_result = delete_from_chef_server(@server.chef_node_name) - res.merge!(deleting_chef_node_and_chef_client_result) + res end def deploy_server_with_tags tags, deploy_info From 756d7b8d1c36904647b6bb22d32d4c5dcd6feba8 Mon Sep 17 00:00:00 2001 From: Anton Chuchkalov Date: Tue, 12 Jan 2016 12:01:07 +0300 Subject: [PATCH 03/11] permit all symbols in image name --- devops-service/db/mongo/models/image.rb | 4 ++-- .../validators/field_validators/image_id.rb | 18 +++++++++++++++ .../validators/field_validators/image_name.rb | 7 +++--- .../field_validators/image_username.rb | 18 +++++++++++++++ devops-service/spec/models/image_spec.rb | 23 +++++++++++++------ 5 files changed, 57 insertions(+), 13 deletions(-) create mode 100644 devops-service/db/validators/field_validators/image_id.rb create mode 100644 devops-service/db/validators/field_validators/image_username.rb 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/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/spec/models/image_spec.rb b/devops-service/spec/models/image_spec.rb index 769e04a..a90912d 100644 --- a/devops-service/spec/models/image_spec.rb +++ b/devops-service/spec/models/image_spec.rb @@ -2,12 +2,13 @@ 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 @@ -21,16 +22,24 @@ RSpec.describe Devops::Model::Image, type: :model do 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 From 8b0b1f9e11d27953e827b4f6da7f7ea337a0d07c Mon Sep 17 00:00:00 2001 From: Anton Chuchkalov Date: Wed, 13 Jan 2016 14:02:32 +0300 Subject: [PATCH 04/11] add possibility to manually set private ip to created instances --- devops-client/lib/devops-client/handler/server.rb | 2 +- devops-client/lib/devops-client/options/server_options.rb | 2 ++ devops-client/locales/en.yml | 3 ++- devops-service/lib/executors/server_executor.rb | 3 ++- devops-service/providers/ec2.rb | 3 ++- 5 files changed, 9 insertions(+), 4 deletions(-) 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/options/server_options.rb b/devops-client/lib/devops-client/options/server_options.rb index 71461d0..3d72fed 100644 --- a/devops-client/lib/devops-client/options/server_options.rb +++ b/devops-client/lib/devops-client/options/server_options.rb @@ -122,6 +122,8 @@ class ServerOptions < CommonOptions 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 diff --git a/devops-client/locales/en.yml b/devops-client/locales/en.yml index 58f1d9f..75bd050 100644 --- a/devops-client/locales/en.yml +++ b/devops-client/locales/en.yml @@ -360,11 +360,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 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/providers/ec2.rb b/devops-service/providers/ec2.rb index dbb5d6b..2260b3d 100644 --- a/devops-service/providers/ec2.rb +++ b/devops-service/providers/ec2.rb @@ -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? From 0dbd75631d8449f8d5265c3ef6701ebd6421c691 Mon Sep 17 00:00:00 2001 From: Anton Chuchkalov Date: Wed, 13 Jan 2016 15:02:55 +0300 Subject: [PATCH 05/11] add private_ip parameter to docs --- devops-service/app/api2/routes/server.rb | 1 + 1 file changed, 1 insertion(+) 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 From f083acef32c917d9d5860f15bfff9f3f38ca54a4 Mon Sep 17 00:00:00 2001 From: Anton Chuchkalov Date: Wed, 13 Jan 2016 22:13:39 +0300 Subject: [PATCH 06/11] client refactoring: make params recognizing less verbose --- .../devops-client/options/deploy_options.rb | 2 +- .../options/helpers/devops_options_parser.rb | 37 +++++++---- .../helpers/option_value_recognizer.rb | 37 +++++------ .../devops-client/options/image_options.rb | 11 ++-- .../devops-client/options/project_options.rb | 31 ++++----- .../devops-client/options/script_options.rb | 2 +- .../devops-client/options/server_options.rb | 66 ++++++++++--------- .../devops-client/options/stack_options.rb | 18 ++--- .../options/stack_preset_options.rb | 15 +++-- .../options/stack_template_options.rb | 7 +- .../lib/devops-client/options/user_options.rb | 2 +- devops-client/locales/en.yml | 6 +- 12 files changed, 128 insertions(+), 106 deletions(-) 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..ab07d2d 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,22 +105,23 @@ 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 @@ -132,10 +136,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 +151,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 index 5aa4d62..d91a754 100644 --- a/devops-client/lib/devops-client/options/stack_preset_options.rb +++ b/devops-client/lib/devops-client/options/stack_preset_options.rb @@ -16,14 +16,15 @@ class StackPresetOptions < CommonOptions def apply_options self.options do |parser, options| parser.banner << self.apply_banner + parser.resource_name = :stack_preset - 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') + parser.recognize_option_value(:provider) + parser.recognize_option_value(:project) + parser.recognize_option_value(:deploy_env) + parser.recognize_option_value(:stack) + parser.recognize_option_value(:project) + parser.recognize_option_value(:deploy_env) + parser.recognize_option_value(:parameters_file) 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..37d5533 100644 --- a/devops-client/lib/devops-client/options/stack_template_options.rb +++ b/devops-client/lib/devops-client/options/stack_template_options.rb @@ -16,10 +16,11 @@ class StackTemplateOptions < CommonOptions 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/locales/en.yml b/devops-client/locales/en.yml index 58f1d9f..06e7dfe 100644 --- a/devops-client/locales/en.yml +++ b/devops-client/locales/en.yml @@ -360,7 +360,7 @@ 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 @@ -377,7 +377,9 @@ 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 From 0fe1218731efdbb30c42930ef1d0ecafa945d0e3 Mon Sep 17 00:00:00 2001 From: Tim Lianov Date: Thu, 21 Jan 2016 12:10:36 -0500 Subject: [PATCH 07/11] Revert "Merge branch 'qa' into release" This reverts commit 49ba7a8b0d927b0bd3bbbe113dd5d0412b92cd57, reversing changes made to eb753df4c96bf3593e85d437ccf85e5a776e923d. --- .../lib/devops-client/handler/server.rb | 2 +- .../devops-client/handler/stack_template.rb | 13 +-- .../devops-client/options/deploy_options.rb | 2 +- .../options/helpers/devops_options_parser.rb | 37 +++---- .../helpers/option_value_recognizer.rb | 37 ++++--- .../devops-client/options/image_options.rb | 11 +- .../devops-client/options/project_options.rb | 31 +++--- .../devops-client/options/script_options.rb | 2 +- .../devops-client/options/server_options.rb | 68 ++++++------ .../devops-client/options/stack_options.rb | 18 ++-- .../options/stack_preset_options.rb | 15 ++- .../options/stack_template_options.rb | 10 +- .../lib/devops-client/options/user_options.rb | 2 +- devops-client/locales/en.yml | 7 +- devops-service/Guardfile | 3 +- .../app/api2/handlers/stack_template.rb | 8 -- devops-service/app/api2/routes/server.rb | 1 - .../app/api2/routes/stack_template.rb | 5 - devops-service/config.rb | 3 +- devops-service/db/mongo/models/image.rb | 4 +- devops-service/db/mongo/models/project.rb | 2 - .../openstack_provider_account.rb | 1 - .../db/mongo/models/stack/stack_base.rb | 6 +- .../stack_template/stack_template_ec2.rb | 35 +++--- devops-service/db/validators/all.rb | 13 ++- .../validators/field_validators/image_id.rb | 18 ---- .../validators/field_validators/image_name.rb | 7 +- .../field_validators/image_username.rb | 18 ---- .../lib/executors/server_executor.rb | 3 +- devops-service/providers/ec2.rb | 26 +---- .../spec/connectors/filter_connector_spec.rb | 2 + .../spec/connectors/image_connector_spec.rb | 2 + .../spec/connectors/key_connector_spec.rb | 2 + .../spec/connectors/project_connector_spec.rb | 2 + .../shared_connectors_context.rb} | 3 +- .../stack_template_connector_spec.rb | 2 + .../spec/factories/provider_account.rb | 25 ----- .../models/deploy_env/deploy_env_ec2_spec.rb | 10 +- .../deploy_env/deploy_env_openstack_spec.rb | 10 +- .../deploy_env/deploy_env_static_spec.rb | 13 +-- devops-service/spec/models/image_spec.rb | 23 ++-- devops-service/spec/models/project_spec.rb | 101 ++---------------- .../ec2_provider_account_spec.rb | 70 ------------ .../openstack_provider_account_spec.rb | 12 --- .../shared_models_context.rb} | 12 ++- .../stack_template/stack_template_ec2_spec.rb | 3 +- .../auto_require_shared_specs.rb | 7 -- .../spec/shared_contexts/stubbed_connector.rb | 6 -- .../spec/shared_contexts/stubbed_logger.rb | 7 -- devops-service/spec/spec_helper.rb | 1 - .../shared_cloud_deploy_env_specs.rb | 0 .../shared_connectors_specs.rb | 0 .../shared_deploy_env_specs.rb | 27 ++--- .../shared_stack_template_specs.rb | 0 .../shared_validation_specs.rb | 0 devops-service/spec/support/spec_support.rb | 2 +- 56 files changed, 213 insertions(+), 537 deletions(-) delete mode 100644 devops-service/db/validators/field_validators/image_id.rb delete mode 100644 devops-service/db/validators/field_validators/image_username.rb rename devops-service/spec/{shared_contexts/with_tester_connector.rb => connectors/shared_connectors_context.rb} (85%) delete mode 100644 devops-service/spec/factories/provider_account.rb delete mode 100644 devops-service/spec/models/provider_account/ec2_provider_account_spec.rb delete mode 100644 devops-service/spec/models/provider_account/openstack_provider_account_spec.rb rename devops-service/spec/{shared_contexts/stubbed_env_validators.rb => models/shared_models_context.rb} (79%) delete mode 100644 devops-service/spec/shared_contexts/auto_require_shared_specs.rb delete mode 100644 devops-service/spec/shared_contexts/stubbed_connector.rb delete mode 100644 devops-service/spec/shared_contexts/stubbed_logger.rb rename devops-service/spec/{models/deploy_env => support}/shared_cloud_deploy_env_specs.rb (100%) rename devops-service/spec/{connectors => support}/shared_connectors_specs.rb (100%) rename devops-service/spec/{models/deploy_env => support}/shared_deploy_env_specs.rb (89%) rename devops-service/spec/{models/stack_template => support}/shared_stack_template_specs.rb (100%) rename devops-service/spec/{models => support}/shared_validation_specs.rb (100%) diff --git a/devops-client/lib/devops-client/handler/server.rb b/devops-client/lib/devops-client/handler/server.rb index 1d85e02..9febf16 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, :private_ip].each do |k| + [:key, :without_bootstrap, :name, :groups, :force].each do |k| q[k] = self.options[k] unless self.options[k].nil? end diff --git a/devops-client/lib/devops-client/handler/stack_template.rb b/devops-client/lib/devops-client/handler/stack_template.rb index d1754c4..c305e18 100644 --- a/devops-client/lib/devops-client/handler/stack_template.rb +++ b/devops-client/lib/devops-client/handler/stack_template.rb @@ -14,6 +14,7 @@ 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 @@ -26,8 +27,6 @@ class StackTemplate < Handler create_handler when :delete delete_handler - when :update_url - update_url_handler end end @@ -77,16 +76,6 @@ 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 abb657d..a23443d 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, resource_name: :deploy, variable_name: 'TAG1,TAG2...') do |tags| + parser.recognize_option_value(:tag, '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 e0bd6ef..c3fc63e 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,7 +7,6 @@ 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" @@ -47,9 +46,8 @@ 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 @@ -59,59 +57,48 @@ 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.resource_name = :stack - # parser.recognize_option_value(:provider) - # is equal to + # parser.recognize_option_value(:provider, 'stack') + # 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, type: :optional, default: 'openstack') - # is equal to + # parser.recognize_option_value(:provider, 'stack', 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, type: :switch, default: false, switch_value: true) - # is equal to + # parser.recognize_option_value(:no_template, 'image', 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) do |parameters| + # parser.recognize_option_value(:parameters, 'stack') 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, attrs={}, &block) - scope = i18n_scope(attrs.delete(:resource_name), attrs.delete(:command_name), option_name) - recognizer = OptionValueRecognizer.new(option_name, scope, attrs) + def recognize_option_value(option_name, resource_name, attrs={}, &block) + recognizer = OptionValueRecognizer.new(option_name, resource_name, 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 e4ea362..6c1735a 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,16 +3,14 @@ # Description and examples of usage are in devops_option_parser.rb. class OptionValueRecognizer - attr_reader :option_name, :i18n_scope, :attrs + def initialize(option_name, resource_name, attrs={}) + @option_name, @attrs = option_name, attrs - 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 + 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) end def recognize(parser, parsed_options, &block) @@ -31,9 +29,7 @@ class OptionValueRecognizer private - - - def set_type + def set_type(option_name, resource_name) @type = @attrs[:type] || :required raise "Illegal optional type: '#{@type}'" unless [:required, :optional, :switch].include?(@type) if @type == :switch && !@attrs.keys.include?(:switch_value) @@ -41,15 +37,22 @@ class OptionValueRecognizer end end - def set_option_key + def set_option_key(option_name, resource_name) @option_key = @attrs[:option_key] || option_name.to_sym end - def set_description - @description = @attrs[:description] || I18n.t(i18n_scope) + 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 end - def set_variable + def set_variable(option_name, resource_name) variable = @attrs[:variable] || option_name.upcase @variable = case @type @@ -62,7 +65,7 @@ class OptionValueRecognizer end end - def set_options_to_recognize + def set_options_to_recognize(option_name, resource_name) 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 587488b..df737ad 100644 --- a/devops-client/lib/devops-client/options/image_options.rb +++ b/devops-client/lib/devops-client/options/image_options.rb @@ -17,13 +17,12 @@ 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) - 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) + 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) 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 64727e0..3bbd72e 100644 --- a/devops-client/lib/devops-client/options/project_options.rb +++ b/devops-client/lib/devops-client/options/project_options.rb @@ -29,32 +29,31 @@ 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, variable: 'GROUP_1,GROUP_2...') do |groups| + parser.recognize_option_value(:groups, 'project', variable: 'GROUP_1,GROUP_2...') do |groups| options[:groups] = groups.split(",") end - parser.recognize_option_value(:file) do |file| + parser.recognize_option_value(:file, 'project') do |file| abort("File '#{file}' does not exist") unless File.exist?(file) options[:file] = file end - parser.recognize_option_value(:subnets, variable: 'SUBNET_1,SUBNET_2...') do |subnets| + parser.recognize_option_value(:subnets, 'project', variable: 'SUBNET_1,SUBNET_2...') do |subnets| options[:subnets] = subnets.split(",") end - parser.recognize_option_value(:users, variable: 'USER_1,USER_2...') do |users| + parser.recognize_option_value(:users, 'project', variable: 'USER_1,USER_2...') do |users| options[:users] = Set.new(users.split(",")) end - 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) + 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') # TODO: @@ -73,7 +72,7 @@ class ProjectOptions < CommonOptions self.options do |parser, options| parser.banner << self.user_add_banner - parser.recognize_option_value(:deploy_env, resource_name: :project, command_name: 'user_add') + parser.recognize_option_value(:deploy_env, 'project', i18n_scope: 'user_add') end end @@ -81,7 +80,7 @@ class ProjectOptions < CommonOptions self.options do |parser, options| parser.banner << self.user_delete_banner - parser.recognize_option_value(:deploy_env, resource_name: :project, command_name: 'user_delete') + parser.recognize_option_value(:deploy_env, 'project', i18n_scope: 'user_delete') end end @@ -89,7 +88,7 @@ class ProjectOptions < CommonOptions options do |parser, options| parser.banner << self.deploy_banner - parser.recognize_option_value(:servers, resource_name: :project, command_name: 'deploy') do |servers| + parser.recognize_option_value(:servers, 'project', i18n_scope: 'deploy') do |servers| options[:servers] = servers.split(",") end end @@ -97,7 +96,7 @@ class ProjectOptions < CommonOptions def delete_servers_options self.options do |parser, options| - parser.recognize_option_value(:dry_run, resource_name: :project, type: :switch, default: false, switch_value: true, command_name: 'delete_servers') + parser.recognize_option_value(:dry_run, 'project', type: :switch, default: false, switch_value: true, i18n_scope: '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 42ffe54..caab4a0 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, resource_name: :script) do |params| + parser.recognize_option_value(:params, '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 7a44bc0..71461d0 100644 --- a/devops-client/lib/devops-client/options/server_options.rb +++ b/devops-client/lib/devops-client/options/server_options.rb @@ -24,21 +24,22 @@ 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, + parser.recognize_option_value(:instance, 'server', type: :switch, default: 'node', switch_value: 'instance', - option_key: :key + option_key: :key, + i18n_scope: 'delete' ) - parser.recognize_option_value(:no_ask, + parser.recognize_option_value(:no_ask, 'server', type: :switch, default: false, - switch_value: true + switch_value: true, + i18n_scope: 'delete' ) + end end @@ -46,13 +47,12 @@ class ServerOptions < CommonOptions options do |parser, options| parser.banner << self.delete_banner - parser.recognize_option_value(:instance, - resource_name: :server, - command_name: :pause, + parser.recognize_option_value(:instance, 'server', type: :switch, default: 'node', switch_value: 'instance', - option_key: :key + option_key: :key, + i18n_scope: 'pause' ) end end @@ -61,13 +61,12 @@ class ServerOptions < CommonOptions options do |parser, options| parser.banner << self.delete_banner - parser.recognize_option_value(:instance, - resource_name: :server, - command_name: :unpause, + parser.recognize_option_value(:instance, 'server', type: :switch, default: 'node', switch_value: 'instance', - option_key: :key + option_key: :key, + i18n_scope: 'unpause' ) end end @@ -76,13 +75,12 @@ class ServerOptions < CommonOptions options do |parser, options| parser.banner << self.delete_banner - parser.recognize_option_value(:instance, - resource_name: :server, - command_name: :reserve, + parser.recognize_option_value(:instance, 'server', type: :switch, default: 'node', switch_value: 'instance', - option_key: :key + option_key: :key, + i18n_scope: 'reserve' ) end end @@ -91,13 +89,12 @@ class ServerOptions < CommonOptions options do |parser, options| parser.banner << self.delete_banner - parser.recognize_option_value(:instance, - resource_name: :server, - command_name: :unreserve, + parser.recognize_option_value(:instance, 'server', type: :switch, default: 'node', switch_value: 'instance', - option_key: :key + option_key: :key, + i18n_scope: 'unreserve' ) end end @@ -105,29 +102,26 @@ 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', + parser.recognize_option_value('without_bootstrap', 'server', type: :switch, switch_value: true, option_key: :without_bootstrap, 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(: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(:groups, + parser.recognize_option_value(:groups, 'server', short: '-G', - variable: 'GROUP_1,GROUP_2...' + variable: 'GROUP_1,GROUP_2...', + i18n_scope: 'create' ) 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 @@ -138,12 +132,10 @@ 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, short: '-N') - parser.recognize_option_value(:bootstrap_template) - parser.recognize_option_value(:run_list) do |list| + 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| options[:run_list] = list.split(",") end end @@ -153,7 +145,7 @@ class ServerOptions < CommonOptions options do |parser, options| parser.banner << self.add_banner - parser.recognize_option_value('public-ip', resource_name: :server, command_name: :add, option_key: :public_ip) + parser.recognize_option_value('public-ip', 'server', i18n_scope: '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 325e629..c33c25a 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) - 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) + 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) + end end diff --git a/devops-client/lib/devops-client/options/stack_preset_options.rb b/devops-client/lib/devops-client/options/stack_preset_options.rb index d91a754..5aa4d62 100644 --- a/devops-client/lib/devops-client/options/stack_preset_options.rb +++ b/devops-client/lib/devops-client/options/stack_preset_options.rb @@ -16,15 +16,14 @@ class StackPresetOptions < CommonOptions def apply_options self.options do |parser, options| parser.banner << self.apply_banner - parser.resource_name = :stack_preset - parser.recognize_option_value(:provider) - parser.recognize_option_value(:project) - parser.recognize_option_value(:deploy_env) - parser.recognize_option_value(:stack) - parser.recognize_option_value(:project) - parser.recognize_option_value(:deploy_env) - parser.recognize_option_value(:parameters_file) + 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 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 3da56a9..67f8498 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, :update_url + commands :create, :delete, :list, :show def initialize args, def_options super(args, def_options) @@ -11,17 +11,15 @@ 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, default: nil) - parser.recognize_option_value(:id) - parser.recognize_option_value(:template_file) + parser.recognize_option_value(:provider, 'stack_template', default: nil) + parser.recognize_option_value(:id, 'stack_template') + parser.recognize_option_value(:template_file, 'stack_template') 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 f6da6e0..e224431 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, resource_name: :user) + parser.recognize_option_value(:new_password, 'user') end end diff --git a/devops-client/locales/en.yml b/devops-client/locales/en.yml index 8a579c9..58f1d9f 100644 --- a/devops-client/locales/en.yml +++ b/devops-client/locales/en.yml @@ -360,12 +360,11 @@ 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 @@ -378,9 +377,7 @@ en: deploy_env: Deploy env project: Stack project stack_template: Stack template - parameters_file: File with parameters JSON - run_list: Stack run list - without_bootstrap: Skip bootsraping phase on created instances + parameters: Parameters hash as single quoted JSON string stack_template: provider: Stack template provider id: Stack template id diff --git a/devops-service/Guardfile b/devops-service/Guardfile index 13d5834..9248c74 100644 --- a/devops-service/Guardfile +++ b/devops-service/Guardfile @@ -36,9 +36,8 @@ guard :rspec, cmd: "rspec" do watch(rspec.spec_support) { rspec.spec_dir } watch(rspec.spec_files) - # Spec config files + # Factories 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_template.rb b/devops-service/app/api2/handlers/stack_template.rb index ecb28a2..49718a9 100644 --- a/devops-service/app/api2/handlers/stack_template.rb +++ b/devops-service/app/api2/handlers/stack_template.rb @@ -39,14 +39,6 @@ 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/routes/server.rb b/devops-service/app/api2/routes/server.rb index 69bd54e..b00d983 100644 --- a/devops-service/app/api2/routes/server.rb +++ b/devops-service/app/api2/routes/server.rb @@ -196,7 +196,6 @@ 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_template.rb b/devops-service/app/api2/routes/stack_template.rb index 1b18fd9..d825191 100644 --- a/devops-service/app/api2/routes/stack_template.rb +++ b/devops-service/app/api2/routes/stack_template.rb @@ -22,11 +22,6 @@ 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/config.rb b/devops-service/config.rb index 1751eb7..5bc27b3 100644 --- a/devops-service/config.rb +++ b/devops-service/config.rb @@ -37,7 +37,6 @@ 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 @@ -47,4 +46,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 \ No newline at end of file +config[:stub_providers] = false diff --git a/devops-service/db/mongo/models/image.rb b/devops-service/db/mongo/models/image.rb index 0263562..dace22e 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::ImageId, + ::Validators::FieldValidator::ImageName, ::Validators::Image::ImageInFilter] set_field_validators :remote_user, [::Validators::FieldValidator::NotNil, ::Validators::FieldValidator::FieldType::String, ::Validators::FieldValidator::NotEmpty, - ::Validators::FieldValidator::ImageUsername] + ::Validators::FieldValidator::ImageName] 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 c4edc04..a4a4a23 100644 --- a/devops-service/db/mongo/models/project.rb +++ b/devops-service/db/mongo/models/project.rb @@ -146,7 +146,6 @@ module Devops h end - # TODO: why symbols here? def to_hash_list { name: self.id, @@ -208,7 +207,6 @@ 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 ef723ac..9aa6ca2 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,7 +17,6 @@ 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 e631bf6..cf118e5 100644 --- a/devops-service/db/mongo/models/stack/stack_base.rb +++ b/devops-service/db/mongo/models/stack/stack_base.rb @@ -131,11 +131,7 @@ module Devops end def template_body - stack_template_model.template_body - end - - def stack_template_model - Devops::Db.connector.stack_template(stack_template) + Devops::Db.connector.stack_template(stack_template).template_body 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 20b3d03..89f7a0d 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,25 +20,34 @@ 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) - model = super(attrs) - model.update_template_url - model - end - end - private + def create(attrs) + template = attrs['template_body'] + attrs['template_url'] = generate_template_file_and_upload_to_storage(attrs['id'], template) + super(attrs) + end + + private def generate_template_file_and_upload_to_storage(id, json) - uniq_filename = "#{id}-#{SecureRandom.hex}.template" - provider_instance.store_stack_template(uniq_filename, json)['url'] + 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 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 c40f2f2..e64b6d0 100644 --- a/devops-service/db/validators/all.rb +++ b/devops-service/db/validators/all.rb @@ -9,12 +9,11 @@ end require "db/validators/base" [ - 'helpers/*.rb', - 'deploy_env/*.rb', - 'key/*.rb', - 'image/*.rb', - 'field_validators/*.rb' + 'db/validators/helpers/*.rb', + 'db/validators/deploy_env/*.rb', + 'db/validators/key/*.rb', + 'db/validators/image/*.rb', + 'db/validators/field_validators/*.rb' ].each do |files_regexp| - current_dir = File.dirname(__FILE__) - Dir[File.join(current_dir, files_regexp)].each {|file| require file } + Dir[File.join(Devops::Application.root, files_regexp)].each {|file| require file } end diff --git a/devops-service/db/validators/field_validators/image_id.rb b/devops-service/db/validators/field_validators/image_id.rb deleted file mode 100644 index 926a2f6..0000000 --- a/devops-service/db/validators/field_validators/image_id.rb +++ /dev/null @@ -1,18 +0,0 @@ -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 c108246..e886a53 100644 --- a/devops-service/db/validators/field_validators/image_name.rb +++ b/devops-service/db/validators/field_validators/image_name.rb @@ -3,14 +3,15 @@ module Validators module FieldValidator class ImageName < Base - MAX_LEN = 100 + MAX_NAME_LEN = 100 + NAME_REGEX = /\A[\w\-\.]{1,#{MAX_NAME_LEN}}\z/ def valid? - @value.length <= MAX_LEN + !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}" + "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 diff --git a/devops-service/db/validators/field_validators/image_username.rb b/devops-service/db/validators/field_validators/image_username.rb deleted file mode 100644 index 334011d..0000000 --- a/devops-service/db/validators/field_validators/image_username.rb +++ /dev/null @@ -1,18 +0,0 @@ -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/lib/executors/server_executor.rb b/devops-service/lib/executors/server_executor.rb index 88ac412..0518211 100644 --- a/devops-service/lib/executors/server_executor.rb +++ b/devops-service/lib/executors/server_executor.rb @@ -82,8 +82,7 @@ module Devops "deploy_env" => @deploy_env.identifier, "created_by" => options["created_by"], "provider" => @deploy_env.provider, - "provider_account" => @deploy_env.provider_account, - "private_ip" => options["private_ip"] + "provider_account" => @deploy_env.provider_account }) end diff --git a/devops-service/providers/ec2.rb b/devops-service/providers/ec2.rb index be008f4..609186b 100644 --- a/devops-service/providers/ec2.rb +++ b/devops-service/providers/ec2.rb @@ -99,8 +99,7 @@ module Provider options = { "InstanceType" => flavor, # "Placement.AvailabilityZone" => s.options[:availability_zone], - "KeyName" => self.ssh_key, - "PrivateIpAddress" => s.private_ip + "KeyName" => self.ssh_key } vpcId = nil unless subnets.empty? @@ -223,7 +222,7 @@ module Provider out.flush response = cloud_formation.create_stack(stack.name, { - 'TemplateURL' => stack.stack_template_model.template_url, + 'TemplateBody' => stack.template_body, 'Parameters' => stack.parameters || {}, 'Capabilities' => ['CAPABILITY_IAM'], 'Tags' => stack_tags(stack) @@ -321,17 +320,6 @@ 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 @@ -388,16 +376,6 @@ 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 6eb808d..2850835 100644 --- a/devops-service/spec/connectors/filter_connector_spec.rb +++ b/devops-service/spec/connectors/filter_connector_spec.rb @@ -1,8 +1,10 @@ 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 31653f5..585d728 100644 --- a/devops-service/spec/connectors/image_connector_spec.rb +++ b/devops-service/spec/connectors/image_connector_spec.rb @@ -1,8 +1,10 @@ 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 ae64bf1..9be46ee 100644 --- a/devops-service/spec/connectors/key_connector_spec.rb +++ b/devops-service/spec/connectors/key_connector_spec.rb @@ -1,9 +1,11 @@ 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 b286a24..2b86bd8 100644 --- a/devops-service/spec/connectors/project_connector_spec.rb +++ b/devops-service/spec/connectors/project_connector_spec.rb @@ -1,8 +1,10 @@ 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/shared_contexts/with_tester_connector.rb b/devops-service/spec/connectors/shared_connectors_context.rb similarity index 85% rename from devops-service/spec/shared_contexts/with_tester_connector.rb rename to devops-service/spec/connectors/shared_connectors_context.rb index 8bb586e..3c0fedb 100644 --- a/devops-service/spec/shared_contexts/with_tester_connector.rb +++ b/devops-service/spec/connectors/shared_connectors_context.rb @@ -2,10 +2,9 @@ def set_tester_connector(klass) define_method :tester_connector_class do klass end - include_context 'with tester connector' end -RSpec.shared_context 'with tester connector' do +RSpec.shared_context 'connectors' do before(:all) do @connector = described_class.new(SpecSupport.db) @tester_connector = tester_connector_class.new diff --git a/devops-service/spec/connectors/stack_template_connector_spec.rb b/devops-service/spec/connectors/stack_template_connector_spec.rb index b0bc860..edb9fe7 100644 --- a/devops-service/spec/connectors/stack_template_connector_spec.rb +++ b/devops-service/spec/connectors/stack_template_connector_spec.rb @@ -1,8 +1,10 @@ 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 deleted file mode 100644 index f239513..0000000 --- a/devops-service/spec/factories/provider_account.rb +++ /dev/null @@ -1,25 +0,0 @@ -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 8bbf1d0..2d3b2d8 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,14 +1,12 @@ require 'db/mongo/models/deploy_env/deploy_env_ec2' -require_relative 'shared_deploy_env_specs' -require_relative 'shared_cloud_deploy_env_specs' +require_relative '../shared_models_context' RSpec.describe Devops::Model::DeployEnvEc2, type: :model do let(:env) { build(:deploy_env_ec2) } + include_context 'stubbed calls to connector in env validators' - describe 'it inherits from cloud deploy_env', stubbed_env_validators: true do - it_behaves_like 'deploy env' - it_behaves_like 'cloud deploy env' - end + it_behaves_like 'deploy env' + it_behaves_like 'cloud deploy env' 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 e1a54de..08783b6 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,14 +1,12 @@ require 'db/mongo/models/deploy_env/deploy_env_openstack' -require_relative 'shared_deploy_env_specs' -require_relative 'shared_cloud_deploy_env_specs' +require_relative '../shared_models_context' RSpec.describe Devops::Model::DeployEnvOpenstack, type: :model do let(:env) { build(:deploy_env_openstack) } + include_context 'stubbed calls to connector in env validators' - describe 'it inherits from cloud deploy_env', stubbed_env_validators: true do - it_behaves_like 'deploy env' - it_behaves_like 'cloud deploy env' - end + it_behaves_like 'deploy env' + it_behaves_like 'cloud deploy env' 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 45ad446..2f1d584 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,19 +1,14 @@ 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) } - - 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' + 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' describe '.create' do it 'returns instance of DeployEnvStatic' do diff --git a/devops-service/spec/models/image_spec.rb b/devops-service/spec/models/image_spec.rb index a90912d..769e04a 100644 --- a/devops-service/spec/models/image_spec.rb +++ b/devops-service/spec/models/image_spec.rb @@ -2,13 +2,12 @@ require 'db/mongo/models/image' RSpec.describe Devops::Model::Image, type: :model do let(:image) { build(:image) } - let(:string_with_dash) { 'asd-asd' } - let(:string_with_slash) { 'asd/asd' } - let(:string_with_parenthesis) { 'centos 6.5 x86_64 (development instance)' } + let(:name_with_dash) { 'asd-asd' } + let(:name_with_slash) { 'asd/asd' } 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' => string_with_dash}, {'id' => string_with_slash}]) + allow_any_instance_of(Validators::Image::ImageInFilter).to receive(:available_images).and_return([{'id' => 'test_image'}, {'id' => name_with_dash}, {'id' => name_with_slash}]) end it 'is valid with correct attrs' do @@ -22,24 +21,16 @@ RSpec.describe Devops::Model::Image, type: :model do 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: 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 + expect(build(:image, id: name_with_dash)).to be_valid + expect(build(:image, id: name_with_slash)).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 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 + it 'name should contain only letters, digits and dashes' do + expect(build(:image, name: name_with_slash)).not_to be_valid end it 'bootstrap_template should be included in available bootstrap templates' do diff --git a/devops-service/spec/models/project_spec.rb b/devops-service/spec/models/project_spec.rb index dd892b1..bed0128 100644 --- a/devops-service/spec/models/project_spec.rb +++ b/devops-service/spec/models/project_spec.rb @@ -1,9 +1,11 @@ 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:', stubbed_env_validators: true do + describe 'validation rules:' 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 @@ -88,7 +90,7 @@ RSpec.describe Devops::Model::Project, type: :model do end end - describe '#add_deploy_env', stubbed_logger: true do + describe '#add_deploy_env', stub_logger: true do let(:env) {build(:deploy_env_ec2)} subject { project.add_deploy_env(env) } before do @@ -233,9 +235,9 @@ RSpec.describe Devops::Model::Project, type: :model do end describe '#delete_deploy_env' do - 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') + 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') project.delete_deploy_env('foo') expect(project.deploy_envs).to match_array [] end @@ -269,93 +271,4 @@ 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 deleted file mode 100644 index 8145ea0..0000000 --- a/devops-service/spec/models/provider_account/ec2_provider_account_spec.rb +++ /dev/null @@ -1,70 +0,0 @@ -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 deleted file mode 100644 index e601778..0000000 --- a/devops-service/spec/models/provider_account/openstack_provider_account_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -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" do - 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/shared_contexts/stubbed_env_validators.rb b/devops-service/spec/models/shared_models_context.rb similarity index 79% rename from devops-service/spec/shared_contexts/stubbed_env_validators.rb rename to devops-service/spec/models/shared_models_context.rb index 69f081c..fe5e754 100644 --- a/devops-service/spec/shared_contexts/stubbed_env_validators.rb +++ b/devops-service/spec/models/shared_models_context.rb @@ -1,4 +1,4 @@ -RSpec.shared_context 'stubbed calls to connector in env validators', stubbed_env_validators: true do +RSpec.shared_context 'stubbed calls to connector in env validators' 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,4 +10,12 @@ RSpec.shared_context 'stubbed calls to connector in env validators', stubbed_env 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 \ No newline at end of file +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 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 6e63c48..1cb48af 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,5 +1,4 @@ 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) } @@ -7,8 +6,8 @@ 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_file') { {'url' => nil} } end it_behaves_like 'stack template' + 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 deleted file mode 100644 index eeabd9a..0000000 --- a/devops-service/spec/shared_contexts/auto_require_shared_specs.rb +++ /dev/null @@ -1,7 +0,0 @@ -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 deleted file mode 100644 index 7d6dabb..0000000 --- a/devops-service/spec/shared_contexts/stubbed_connector.rb +++ /dev/null @@ -1,6 +0,0 @@ -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/shared_contexts/stubbed_logger.rb b/devops-service/spec/shared_contexts/stubbed_logger.rb deleted file mode 100644 index f2d79e9..0000000 --- a/devops-service/spec/shared_contexts/stubbed_logger.rb +++ /dev/null @@ -1,7 +0,0 @@ -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/spec_helper.rb b/devops-service/spec/spec_helper.rb index 9f2500f..ac74d92 100644 --- a/devops-service/spec/spec_helper.rb +++ b/devops-service/spec/spec_helper.rb @@ -13,7 +13,6 @@ 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/models/deploy_env/shared_cloud_deploy_env_specs.rb b/devops-service/spec/support/shared_cloud_deploy_env_specs.rb similarity index 100% rename from devops-service/spec/models/deploy_env/shared_cloud_deploy_env_specs.rb rename to devops-service/spec/support/shared_cloud_deploy_env_specs.rb diff --git a/devops-service/spec/connectors/shared_connectors_specs.rb b/devops-service/spec/support/shared_connectors_specs.rb similarity index 100% rename from devops-service/spec/connectors/shared_connectors_specs.rb rename to devops-service/spec/support/shared_connectors_specs.rb diff --git a/devops-service/spec/models/deploy_env/shared_deploy_env_specs.rb b/devops-service/spec/support/shared_deploy_env_specs.rb similarity index 89% rename from devops-service/spec/models/deploy_env/shared_deploy_env_specs.rb rename to devops-service/spec/support/shared_deploy_env_specs.rb index 538f838..a23b1b6 100644 --- a/devops-service/spec/models/deploy_env/shared_deploy_env_specs.rb +++ b/devops-service/spec/support/shared_deploy_env_specs.rb @@ -1,5 +1,9 @@ +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 @@ -77,10 +81,11 @@ RSpec.shared_examples 'deploy env' do end end - describe '#update_field', stubbed_connector: true do + describe '#update_field' do subject { env.update_field('project_name', 'run_list', ['role[asd]']) } before do - allow(stubbed_connector).to receive(:set_project_deploy_env_field) + allow_message_expectations_on_nil + allow(Devops::Db.connector).to receive(:set_project_deploy_env_field) end it 'validate it' do @@ -93,13 +98,12 @@ RSpec.shared_examples 'deploy env' do end it 'saves it' do - expected_args = ['project_name', env.identifier, {'run_list' => ['role[asd]']}] - expect(stubbed_connector).to receive(:set_project_deploy_env_field).with(*expected_args) + expect(Devops::Db.connector).to receive(:set_project_deploy_env_field).with('project_name', env.identifier, {'run_list' => ['role[asd]']}) subject end end - describe '#create_role', stubbed_logger: true do + describe '#create_role', stub_logger: true do subject { env.create_role('project_name') } before do allow(env).to receive_message_chain('knife_instance.role_name') { 'role_name' } @@ -148,7 +152,7 @@ RSpec.shared_examples 'deploy env' do end end - describe '#rename', stubbed_logger: true do + describe '#rename', stub_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'} @@ -170,16 +174,15 @@ 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', stubbed_connector: true do - project = build(:project, with_deploy_env_identifiers: %w(new_name)) - allow(stubbed_connector).to receive(:project) { project } + it 'raises InvalidRecord if env with such name already exists in project' do + allow(Devops::Db.connector).to receive_message_chain('project.deploy_env') expect{subject}.to raise_error(InvalidRecord) end - context 'when there is no env with such name already', stubbed_connector: true do + context 'when there is no env with such name already' do before do - allow(stubbed_connector).to receive(:project) { build(:project) } - allow(stubbed_connector).to receive(:set_project_deploy_env_field) + allow(Devops::Db.connector).to receive_message_chain('project.deploy_env') {raise RecordNotFound} + allow(Devops::Db.connector).to receive(:set_project_deploy_env_field) end it 'validates new identifier' do diff --git a/devops-service/spec/models/stack_template/shared_stack_template_specs.rb b/devops-service/spec/support/shared_stack_template_specs.rb similarity index 100% rename from devops-service/spec/models/stack_template/shared_stack_template_specs.rb rename to devops-service/spec/support/shared_stack_template_specs.rb diff --git a/devops-service/spec/models/shared_validation_specs.rb b/devops-service/spec/support/shared_validation_specs.rb similarity index 100% rename from devops-service/spec/models/shared_validation_specs.rb rename to devops-service/spec/support/shared_validation_specs.rb diff --git a/devops-service/spec/support/spec_support.rb b/devops-service/spec/support/spec_support.rb index ab47bc6..14a684a 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_params ||= begin + @db ||= begin conf = config['mongo'] db_name = conf.fetch(:db) [db_name, conf[:host], conf[:port], conf[:user], conf[:password]] From 5ab7f100288ff13a370ffc24ae794ccfe093407b Mon Sep 17 00:00:00 2001 From: Anton Chuchkalov Date: Wed, 27 Jan 2016 11:29:49 +0300 Subject: [PATCH 08/11] change puts to logger in validators#base --- devops-service/db/validators/base.rb | 2 +- devops-service/spec/models/deploy_env/deploy_env_ec2_spec.rb | 2 +- .../spec/models/deploy_env/deploy_env_openstack_spec.rb | 2 +- devops-service/spec/models/image_spec.rb | 2 +- devops-service/spec/models/key_spec.rb | 2 +- devops-service/spec/models/project_spec.rb | 2 +- .../models/provider_account/openstack_provider_account_spec.rb | 2 +- devops-service/spec/models/server_spec.rb | 2 +- devops-service/spec/models/stack/stack_ec2_spec.rb | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/devops-service/db/validators/base.rb b/devops-service/db/validators/base.rb index 0cb68f9..677e9f2 100644 --- a/devops-service/db/validators/base.rb +++ b/devops-service/db/validators/base.rb @@ -9,7 +9,7 @@ module Validators def validate! raise InvalidRecord.new(message) unless valid? rescue StandardError => e - puts [e.message, e.backtrace].join("\n") + 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/spec/models/deploy_env/deploy_env_ec2_spec.rb b/devops-service/spec/models/deploy_env/deploy_env_ec2_spec.rb index 8bbf1d0..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 @@ -5,7 +5,7 @@ require_relative 'shared_cloud_deploy_env_specs' RSpec.describe Devops::Model::DeployEnvEc2, type: :model do let(:env) { build(:deploy_env_ec2) } - describe 'it inherits from cloud deploy_env', stubbed_env_validators: true do + 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 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 e1a54de..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 @@ -5,7 +5,7 @@ require_relative 'shared_cloud_deploy_env_specs' RSpec.describe Devops::Model::DeployEnvOpenstack, type: :model do let(:env) { build(:deploy_env_openstack) } - describe 'it inherits from cloud deploy_env', stubbed_env_validators: true do + 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 diff --git a/devops-service/spec/models/image_spec.rb b/devops-service/spec/models/image_spec.rb index a90912d..39e630d 100644 --- a/devops-service/spec/models/image_spec.rb +++ b/devops-service/spec/models/image_spec.rb @@ -15,7 +15,7 @@ RSpec.describe Devops::Model::Image, type: :model 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 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 dd892b1..6457ebb 100644 --- a/devops-service/spec/models/project_spec.rb +++ b/devops-service/spec/models/project_spec.rb @@ -3,7 +3,7 @@ require 'db/mongo/models/project' RSpec.describe Devops::Model::Project, type: :model do let(:project) { build(:project) } - describe 'validation rules:', stubbed_env_validators: true 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 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 index e601778..537d36d 100644 --- a/devops-service/spec/models/provider_account/openstack_provider_account_spec.rb +++ b/devops-service/spec/models/provider_account/openstack_provider_account_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' RSpec.describe Devops::Model::OpenstackProviderAccount, type: :model do let(:provider_account) { build(:openstack_provider_account) } - it "should not validate access_key_id" do + it "should not validate access_key_id", stubbed_logger: true do fields = described_class.field_validators.values.flatten.flatten.map{|t| t[:field]} expect(fields).not_to include(:access_key_id, :secret_access_key) end 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/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 From 50ff44ef8cf32b134816898b1b9dcb71cb1d0149 Mon Sep 17 00:00:00 2001 From: Anton Chuchkalov Date: Wed, 27 Jan 2016 11:31:01 +0300 Subject: [PATCH 09/11] make failing spec penging --- .../models/provider_account/openstack_provider_account_spec.rb | 1 + 1 file changed, 1 insertion(+) 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 index 537d36d..4e31025 100644 --- a/devops-service/spec/models/provider_account/openstack_provider_account_spec.rb +++ b/devops-service/spec/models/provider_account/openstack_provider_account_spec.rb @@ -5,6 +5,7 @@ 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 From c4fbbff70a1d952c252b20a4c34ae78c91b19979 Mon Sep 17 00:00:00 2001 From: Anton Chuchkalov Date: Wed, 27 Jan 2016 11:51:54 +0300 Subject: [PATCH 10/11] fix requiring StackBootstrapWorker error --- devops-service/app/api2/handlers/stack.rb | 1 + 1 file changed, 1 insertion(+) 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 From 5d47856f650c3a3f17b6b97a5ba575d3c6324936 Mon Sep 17 00:00:00 2001 From: Anton Chuchkalov Date: Wed, 27 Jan 2016 16:44:59 +0400 Subject: [PATCH 11/11] Revert "Revert "Merge branch 'qa' into release"" This reverts commit 0fe1218731efdbb30c42930ef1d0ecafa945d0e3. --- .../lib/devops-client/handler/server.rb | 2 +- .../devops-client/handler/stack_template.rb | 13 ++- .../devops-client/options/deploy_options.rb | 2 +- .../options/helpers/devops_options_parser.rb | 37 ++++--- .../helpers/option_value_recognizer.rb | 37 +++---- .../devops-client/options/image_options.rb | 11 +- .../devops-client/options/project_options.rb | 31 +++--- .../devops-client/options/script_options.rb | 2 +- .../devops-client/options/server_options.rb | 68 ++++++------ .../devops-client/options/stack_options.rb | 18 ++-- .../options/stack_preset_options.rb | 15 +-- .../options/stack_template_options.rb | 10 +- .../lib/devops-client/options/user_options.rb | 2 +- devops-client/locales/en.yml | 7 +- devops-service/Guardfile | 3 +- .../app/api2/handlers/stack_template.rb | 8 ++ devops-service/app/api2/routes/server.rb | 1 + .../app/api2/routes/stack_template.rb | 5 + devops-service/config.rb | 3 +- devops-service/db/mongo/models/image.rb | 4 +- devops-service/db/mongo/models/project.rb | 2 + .../openstack_provider_account.rb | 1 + .../db/mongo/models/stack/stack_base.rb | 6 +- .../stack_template/stack_template_ec2.rb | 31 ++---- devops-service/db/validators/all.rb | 13 +-- .../validators/field_validators/image_id.rb | 18 ++++ .../validators/field_validators/image_name.rb | 7 +- .../field_validators/image_username.rb | 18 ++++ .../lib/executors/server_executor.rb | 3 +- devops-service/providers/ec2.rb | 26 ++++- .../spec/connectors/filter_connector_spec.rb | 2 - .../spec/connectors/image_connector_spec.rb | 2 - .../spec/connectors/key_connector_spec.rb | 2 - .../spec/connectors/project_connector_spec.rb | 2 - .../shared_connectors_specs.rb | 0 .../stack_template_connector_spec.rb | 2 - .../spec/factories/provider_account.rb | 25 +++++ .../models/deploy_env/deploy_env_ec2_spec.rb | 10 +- .../deploy_env/deploy_env_openstack_spec.rb | 10 +- .../deploy_env/deploy_env_static_spec.rb | 13 ++- .../shared_cloud_deploy_env_specs.rb | 0 .../deploy_env}/shared_deploy_env_specs.rb | 27 +++-- devops-service/spec/models/image_spec.rb | 23 ++-- devops-service/spec/models/project_spec.rb | 101 ++++++++++++++++-- .../ec2_provider_account_spec.rb | 70 ++++++++++++ .../openstack_provider_account_spec.rb | 12 +++ .../shared_validation_specs.rb | 0 .../shared_stack_template_specs.rb | 0 .../stack_template/stack_template_ec2_spec.rb | 3 +- .../auto_require_shared_specs.rb | 7 ++ .../spec/shared_contexts/stubbed_connector.rb | 6 ++ .../stubbed_env_validators.rb} | 12 +-- .../spec/shared_contexts/stubbed_logger.rb | 7 ++ .../with_tester_connector.rb} | 3 +- devops-service/spec/spec_helper.rb | 1 + devops-service/spec/support/spec_support.rb | 2 +- 56 files changed, 535 insertions(+), 211 deletions(-) create mode 100644 devops-service/db/validators/field_validators/image_id.rb create mode 100644 devops-service/db/validators/field_validators/image_username.rb rename devops-service/spec/{support => connectors}/shared_connectors_specs.rb (100%) create mode 100644 devops-service/spec/factories/provider_account.rb rename devops-service/spec/{support => models/deploy_env}/shared_cloud_deploy_env_specs.rb (100%) rename devops-service/spec/{support => models/deploy_env}/shared_deploy_env_specs.rb (89%) create mode 100644 devops-service/spec/models/provider_account/ec2_provider_account_spec.rb create mode 100644 devops-service/spec/models/provider_account/openstack_provider_account_spec.rb rename devops-service/spec/{support => models}/shared_validation_specs.rb (100%) rename devops-service/spec/{support => models/stack_template}/shared_stack_template_specs.rb (100%) create mode 100644 devops-service/spec/shared_contexts/auto_require_shared_specs.rb create mode 100644 devops-service/spec/shared_contexts/stubbed_connector.rb rename devops-service/spec/{models/shared_models_context.rb => shared_contexts/stubbed_env_validators.rb} (79%) create mode 100644 devops-service/spec/shared_contexts/stubbed_logger.rb rename devops-service/spec/{connectors/shared_connectors_context.rb => shared_contexts/with_tester_connector.rb} (85%) 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_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 index 5aa4d62..d91a754 100644 --- a/devops-client/lib/devops-client/options/stack_preset_options.rb +++ b/devops-client/lib/devops-client/options/stack_preset_options.rb @@ -16,14 +16,15 @@ class StackPresetOptions < CommonOptions def apply_options self.options do |parser, options| parser.banner << self.apply_banner + parser.resource_name = :stack_preset - 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') + parser.recognize_option_value(:provider) + parser.recognize_option_value(:project) + parser.recognize_option_value(:deploy_env) + parser.recognize_option_value(:stack) + parser.recognize_option_value(:project) + parser.recognize_option_value(:deploy_env) + parser.recognize_option_value(:parameters_file) 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/locales/en.yml b/devops-client/locales/en.yml index 58f1d9f..8a579c9 100644 --- a/devops-client/locales/en.yml +++ b/devops-client/locales/en.yml @@ -360,11 +360,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,7 +378,9 @@ 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 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_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/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_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/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/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/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/providers/ec2.rb b/devops-service/providers/ec2.rb index 609186b..be008f4 100644 --- a/devops-service/providers/ec2.rb +++ b/devops-service/providers/ec2.rb @@ -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..8bbf1d0 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 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..e1a54de 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 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..a90912d 100644 --- a/devops-service/spec/models/image_spec.rb +++ b/devops-service/spec/models/image_spec.rb @@ -2,12 +2,13 @@ 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 @@ -21,16 +22,24 @@ RSpec.describe Devops::Model::Image, type: :model do 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/project_spec.rb b/devops-service/spec/models/project_spec.rb index bed0128..dd892b1 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 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..e601778 --- /dev/null +++ b/devops-service/spec/models/provider_account/openstack_provider_account_spec.rb @@ -0,0 +1,12 @@ +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" do + 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/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/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..6e63c48 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,8 @@ 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_file') { {'url' => nil} } end it_behaves_like 'stack template' - 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]]