Merge branch 'bug_fix' of http://git.stu.neva.ru/cloudtechlab/devops-service into bug_fix
This commit is contained in:
commit
8ad16494e9
@ -47,9 +47,6 @@ class HandlerFactory
|
|||||||
when "stack_template"
|
when "stack_template"
|
||||||
require "devops-client/handler/stack_template"
|
require "devops-client/handler/stack_template"
|
||||||
StackTemplate
|
StackTemplate
|
||||||
when "stack_preset"
|
|
||||||
require "devops-client/handler/stack_preset"
|
|
||||||
StackPreset
|
|
||||||
when "stack"
|
when "stack"
|
||||||
require "devops-client/handler/stack"
|
require "devops-client/handler/stack"
|
||||||
Stack
|
Stack
|
||||||
|
|||||||
@ -15,7 +15,6 @@ class Image < Handler
|
|||||||
end
|
end
|
||||||
|
|
||||||
def handle
|
def handle
|
||||||
current_command = ARGV[1].to_sym
|
|
||||||
@options, @args = @options_parser.parse_options_for!(current_command)
|
@options, @args = @options_parser.parse_options_for!(current_command)
|
||||||
case current_command
|
case current_command
|
||||||
when :list
|
when :list
|
||||||
|
|||||||
@ -71,7 +71,7 @@ class Server < Handler
|
|||||||
:deploy_env => @args[3]
|
: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?
|
q[k] = self.options[k] unless self.options[k].nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1,62 +0,0 @@
|
|||||||
require "devops-client/handler/handler"
|
|
||||||
require "devops-client/options/stack_preset_options"
|
|
||||||
require "devops-client/output/stack_preset"
|
|
||||||
|
|
||||||
class StackPreset < Handler
|
|
||||||
|
|
||||||
output_with Output::StackPreset
|
|
||||||
|
|
||||||
def initialize(host, def_options={})
|
|
||||||
@host, @options = host, def_options
|
|
||||||
@options_parser = StackPresetOptions.new(ARGV, def_options)
|
|
||||||
end
|
|
||||||
|
|
||||||
def handle
|
|
||||||
@options, @args = @options_parser.parse_options_for!(current_command)
|
|
||||||
case current_command
|
|
||||||
when :list
|
|
||||||
list_handler
|
|
||||||
output
|
|
||||||
when :show
|
|
||||||
show_handler
|
|
||||||
output
|
|
||||||
when :apply
|
|
||||||
apply_handler
|
|
||||||
output
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def show_handler
|
|
||||||
wrong_params = inspect_parameters(@options_parser.show_params, @args[2])
|
|
||||||
if wrong_params
|
|
||||||
@options_parser.invalid_show_command
|
|
||||||
abort(wrong_params)
|
|
||||||
end
|
|
||||||
@show = get "/stack_presets/#{@args[2]}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def list_handler
|
|
||||||
@list = get('/stack_presets')
|
|
||||||
end
|
|
||||||
|
|
||||||
def apply_handler
|
|
||||||
wrong_params = inspect_parameters(@options_parser.apply_params, @args[2])
|
|
||||||
if wrong_params
|
|
||||||
@options_parser.invalid_apply_command
|
|
||||||
abort(wrong_params)
|
|
||||||
end
|
|
||||||
|
|
||||||
params = {}
|
|
||||||
params[:id] = @args[2]
|
|
||||||
params[:provider] = options[:provider] || resources_selector.select_available_provider
|
|
||||||
params[:stack] = options[:stack] || enter_parameter(I18n.t('handler.stack_preset.create.stack'))
|
|
||||||
params[:project] = options[:project] || resources_selector.select_available_project
|
|
||||||
params[:deploy_env] = options[:deploy_env] || enter_parameter(I18n.t('handler.stack.create.deploy_env'))
|
|
||||||
|
|
||||||
filepath = options[:parameters_file] || enter_parameter(I18n.t('handler.stack_preset.create.parameters_file'))
|
|
||||||
params[:parameters] = JSON.parse(File.read(filepath))
|
|
||||||
|
|
||||||
@list = post_body("/stack_presets/#{params[:id]}/apply", JSON.pretty_generate(params))
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
@ -14,7 +14,6 @@ class StackTemplate < Handler
|
|||||||
end
|
end
|
||||||
|
|
||||||
def handle
|
def handle
|
||||||
current_command = ARGV[1].to_sym
|
|
||||||
@options, @args = @options_parser.parse_options_for!(current_command)
|
@options, @args = @options_parser.parse_options_for!(current_command)
|
||||||
case current_command
|
case current_command
|
||||||
when :list
|
when :list
|
||||||
@ -27,6 +26,8 @@ class StackTemplate < Handler
|
|||||||
create_handler
|
create_handler
|
||||||
when :delete
|
when :delete
|
||||||
delete_handler
|
delete_handler
|
||||||
|
when :update_url
|
||||||
|
update_url_handler
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -76,6 +77,16 @@ class StackTemplate < Handler
|
|||||||
end
|
end
|
||||||
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)
|
def provider_stack_templates(provider)
|
||||||
if Providers.has_functionality?(provider, :stack_templates)
|
if Providers.has_functionality?(provider, :stack_templates)
|
||||||
@provider = true
|
@provider = true
|
||||||
|
|||||||
@ -14,7 +14,7 @@ class DeployOptions < CommonOptions
|
|||||||
options do |parser, options|
|
options do |parser, options|
|
||||||
parser.banner << self.banner
|
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(",")
|
options[:tags] = tags.split(",")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ module Options
|
|||||||
class DevopsOptionsParser
|
class DevopsOptionsParser
|
||||||
extend Forwardable
|
extend Forwardable
|
||||||
attr_reader :parsed_options
|
attr_reader :parsed_options
|
||||||
|
attr_accessor :resource_name, :command_name
|
||||||
|
|
||||||
# leave this duplication for a while
|
# leave this duplication for a while
|
||||||
TABLE_FORMAT = "table"
|
TABLE_FORMAT = "table"
|
||||||
@ -46,8 +47,9 @@ module Options
|
|||||||
# it is used to set options values without later quiz.
|
# it is used to set options values without later quiz.
|
||||||
# Arguments description:
|
# Arguments description:
|
||||||
# option_name - name of option;
|
# 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:
|
# 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:
|
# :type - could be one of following values:
|
||||||
# :required (default)
|
# :required (default)
|
||||||
# :optional
|
# :optional
|
||||||
@ -57,48 +59,59 @@ module Options
|
|||||||
# :option_key - key in result_options hash. Default - option_name.to_sym
|
# :option_key - key in result_options hash. Default - option_name.to_sym
|
||||||
# :variable - default - option_name.upcase
|
# :variable - default - option_name.upcase
|
||||||
# :description - default - I18n.t("options.descriptions.#{resource_name}.#{option_name}")
|
# :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
|
# :short - short option name
|
||||||
#
|
#
|
||||||
# EXAMPLES:
|
# EXAMPLES:
|
||||||
# 1)
|
# 1)
|
||||||
# parser.recognize_option_value(:provider, 'stack')
|
# parser.resource_name = :stack
|
||||||
# is equal to
|
# parser.recognize_option_value(:provider)
|
||||||
|
# is equal to
|
||||||
# opts.on("--provider provider", I18n.t("options.descriptions.stack.provider)) do |provider|
|
# opts.on("--provider provider", I18n.t("options.descriptions.stack.provider)) do |provider|
|
||||||
# options[:provider] = provider
|
# options[:provider] = provider
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
|
# Also, you could pass resource name in attributes without need to use attr_accessor:
|
||||||
|
# parser.recognize_option_value(:provider, resource_name: :stack)
|
||||||
|
#
|
||||||
# 2)
|
# 2)
|
||||||
# parser.recognize_option_value(:provider, 'stack', type: :optional, default: 'openstack')
|
# parser.recognize_option_value(:provider, type: :optional, default: 'openstack')
|
||||||
# is equal to
|
# is equal to
|
||||||
# options[:provider] = 'openstack'
|
# options[:provider] = 'openstack'
|
||||||
# opts.on("--provider [provider]", I18n.t("options.descriptions.stack.provider)) do |provider|
|
# opts.on("--provider [provider]", I18n.t("options.descriptions.stack.provider)) do |provider|
|
||||||
# options[:provider] = provider
|
# options[:provider] = provider
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# 3)
|
# 3)
|
||||||
# parser.recognize_option_value(:no_template, 'image', type: :switch, default: false, switch_value: true)
|
# parser.recognize_option_value(:no_template, type: :switch, default: false, switch_value: true)
|
||||||
# is equal to
|
# is equal to
|
||||||
# options[:no_template] = false
|
# options[:no_template] = false
|
||||||
# opts.on("--no_template", I18n.t("options.descriptions.image.no_template)) do
|
# opts.on("--no_template", I18n.t("options.descriptions.image.no_template)) do
|
||||||
# options[:no_template] = true
|
# options[:no_template] = true
|
||||||
# end
|
# end
|
||||||
#
|
#
|
||||||
# 4)
|
# 4)
|
||||||
# parser.recognize_option_value(:parameters, 'stack') do |parameters|
|
# parser.recognize_option_value(:parameters) do |parameters|
|
||||||
# options[:parameters] = JSON.parse(parameters)
|
# options[:parameters] = JSON.parse(parameters)
|
||||||
# end
|
# end
|
||||||
# is equal to
|
# is equal to
|
||||||
# opts.on("--parameters parameters", I18n.t("options.descriptions.stack.parameters)) do |parameters|
|
# opts.on("--parameters parameters", I18n.t("options.descriptions.stack.parameters)) do |parameters|
|
||||||
# options[:parameters] = JSON.parse(parameters)
|
# options[:parameters] = JSON.parse(parameters)
|
||||||
# end
|
# end
|
||||||
def recognize_option_value(option_name, resource_name, attrs={}, &block)
|
def recognize_option_value(option_name, attrs={}, &block)
|
||||||
recognizer = OptionValueRecognizer.new(option_name, resource_name, attrs)
|
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)
|
recognizer.recognize(@parser, @parsed_options, &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
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
|
def banner_usage
|
||||||
@parser.banner = "\n" + I18n.t("options.usage", :cmd => $0) + "\n\n" + I18n.t("options.commands") + ":\n"
|
@parser.banner = "\n" + I18n.t("options.usage", :cmd => $0) + "\n\n" + I18n.t("options.commands") + ":\n"
|
||||||
end
|
end
|
||||||
|
|||||||
@ -3,14 +3,16 @@
|
|||||||
# Description and examples of usage are in devops_option_parser.rb.
|
# Description and examples of usage are in devops_option_parser.rb.
|
||||||
class OptionValueRecognizer
|
class OptionValueRecognizer
|
||||||
|
|
||||||
def initialize(option_name, resource_name, attrs={})
|
attr_reader :option_name, :i18n_scope, :attrs
|
||||||
@option_name, @attrs = option_name, attrs
|
|
||||||
|
|
||||||
set_type(option_name, resource_name)
|
def initialize(option_name, i18n_scope, attrs={})
|
||||||
set_option_key(option_name, resource_name)
|
@option_name, @i18n_scope, @attrs = option_name, i18n_scope, attrs
|
||||||
set_description(option_name, resource_name)
|
|
||||||
set_variable(option_name, resource_name)
|
set_type
|
||||||
set_options_to_recognize(option_name, resource_name)
|
set_option_key
|
||||||
|
set_description
|
||||||
|
set_variable
|
||||||
|
set_options_to_recognize
|
||||||
end
|
end
|
||||||
|
|
||||||
def recognize(parser, parsed_options, &block)
|
def recognize(parser, parsed_options, &block)
|
||||||
@ -29,7 +31,9 @@ class OptionValueRecognizer
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_type(option_name, resource_name)
|
|
||||||
|
|
||||||
|
def set_type
|
||||||
@type = @attrs[:type] || :required
|
@type = @attrs[:type] || :required
|
||||||
raise "Illegal optional type: '#{@type}'" unless [:required, :optional, :switch].include?(@type)
|
raise "Illegal optional type: '#{@type}'" unless [:required, :optional, :switch].include?(@type)
|
||||||
if @type == :switch && !@attrs.keys.include?(:switch_value)
|
if @type == :switch && !@attrs.keys.include?(:switch_value)
|
||||||
@ -37,22 +41,15 @@ class OptionValueRecognizer
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_option_key(option_name, resource_name)
|
def set_option_key
|
||||||
@option_key = @attrs[:option_key] || option_name.to_sym
|
@option_key = @attrs[:option_key] || option_name.to_sym
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_description(option_name, resource_name)
|
def set_description
|
||||||
if @attrs[:description]
|
@description = @attrs[:description] || I18n.t(i18n_scope)
|
||||||
@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
|
end
|
||||||
|
|
||||||
def set_variable(option_name, resource_name)
|
def set_variable
|
||||||
variable = @attrs[:variable] || option_name.upcase
|
variable = @attrs[:variable] || option_name.upcase
|
||||||
|
|
||||||
@variable = case @type
|
@variable = case @type
|
||||||
@ -65,7 +62,7 @@ class OptionValueRecognizer
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def set_options_to_recognize(option_name, resource_name)
|
def set_options_to_recognize
|
||||||
full = "--#{@option_name}#{@variable}"
|
full = "--#{@option_name}#{@variable}"
|
||||||
@options_to_recognize = [full]
|
@options_to_recognize = [full]
|
||||||
@options_to_recognize.unshift(@attrs[:short]) if @attrs[:short]
|
@options_to_recognize.unshift(@attrs[:short]) if @attrs[:short]
|
||||||
|
|||||||
@ -17,12 +17,13 @@ class ImageOptions < CommonOptions
|
|||||||
def create_options
|
def create_options
|
||||||
self.options do |parser, options|
|
self.options do |parser, options|
|
||||||
parser.banner << self.create_banner
|
parser.banner << self.create_banner
|
||||||
|
parser.resource_name = :image
|
||||||
|
|
||||||
parser.recognize_option_value(:provider, 'image')
|
parser.recognize_option_value(:provider)
|
||||||
parser.recognize_option_value(:image_id, 'image')
|
parser.recognize_option_value(:image_id)
|
||||||
parser.recognize_option_value(:ssh_username, 'image')
|
parser.recognize_option_value(:ssh_username)
|
||||||
parser.recognize_option_value(:bootstrap_template, 'image')
|
parser.recognize_option_value(:bootstrap_template)
|
||||||
parser.recognize_option_value(:no_bootstrap_template, 'image', type: :switch, switch_value: true, default: false)
|
parser.recognize_option_value(:no_bootstrap_template, type: :switch, switch_value: true, default: false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -29,31 +29,32 @@ class ProjectOptions < CommonOptions
|
|||||||
def create_options
|
def create_options
|
||||||
self.options do |parser, options|
|
self.options do |parser, options|
|
||||||
parser.banner << self.create_banner
|
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(",")
|
options[:groups] = groups.split(",")
|
||||||
end
|
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)
|
abort("File '#{file}' does not exist") unless File.exist?(file)
|
||||||
options[:file] = file
|
options[:file] = file
|
||||||
end
|
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(",")
|
options[:subnets] = subnets.split(",")
|
||||||
end
|
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(","))
|
options[:users] = Set.new(users.split(","))
|
||||||
end
|
end
|
||||||
|
|
||||||
parser.recognize_option_value(:deploy_env, 'project', option_key: :identifier)
|
parser.recognize_option_value(:deploy_env, option_key: :identifier)
|
||||||
parser.recognize_option_value(:flavor, 'project')
|
parser.recognize_option_value(:flavor)
|
||||||
parser.recognize_option_value(:image, 'project')
|
parser.recognize_option_value(:image)
|
||||||
parser.recognize_option_value(:run_list, 'project')
|
parser.recognize_option_value(:run_list)
|
||||||
parser.recognize_option_value(:provider, 'project')
|
parser.recognize_option_value(:provider)
|
||||||
parser.recognize_option_value(:no_expires, 'project', type: :switch, switch_value: true, default: false)
|
parser.recognize_option_value(:no_expires, type: :switch, switch_value: true, default: false)
|
||||||
parser.recognize_option_value(:expires, 'project')
|
parser.recognize_option_value(:expires)
|
||||||
|
|
||||||
|
|
||||||
# TODO:
|
# TODO:
|
||||||
@ -72,7 +73,7 @@ class ProjectOptions < CommonOptions
|
|||||||
self.options do |parser, options|
|
self.options do |parser, options|
|
||||||
parser.banner << self.user_add_banner
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -80,7 +81,7 @@ class ProjectOptions < CommonOptions
|
|||||||
self.options do |parser, options|
|
self.options do |parser, options|
|
||||||
parser.banner << self.user_delete_banner
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -88,7 +89,7 @@ class ProjectOptions < CommonOptions
|
|||||||
options do |parser, options|
|
options do |parser, options|
|
||||||
parser.banner << self.deploy_banner
|
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(",")
|
options[:servers] = servers.split(",")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -96,7 +97,7 @@ class ProjectOptions < CommonOptions
|
|||||||
|
|
||||||
def delete_servers_options
|
def delete_servers_options
|
||||||
self.options do |parser, 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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ class ScriptOptions < CommonOptions
|
|||||||
options do |parser, options|
|
options do |parser, options|
|
||||||
parser.banner << self.delete_banner
|
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(",")
|
options[:params] = params.split(",")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -24,22 +24,21 @@ class ServerOptions < CommonOptions
|
|||||||
def delete_options
|
def delete_options
|
||||||
options do |parser, options|
|
options do |parser, options|
|
||||||
parser.banner << self.delete_banner
|
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,
|
type: :switch,
|
||||||
default: 'node',
|
default: 'node',
|
||||||
switch_value: 'instance',
|
switch_value: 'instance',
|
||||||
option_key: :key,
|
option_key: :key
|
||||||
i18n_scope: 'delete'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.recognize_option_value(:no_ask, 'server',
|
parser.recognize_option_value(:no_ask,
|
||||||
type: :switch,
|
type: :switch,
|
||||||
default: false,
|
default: false,
|
||||||
switch_value: true,
|
switch_value: true
|
||||||
i18n_scope: 'delete'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -47,12 +46,13 @@ class ServerOptions < CommonOptions
|
|||||||
options do |parser, options|
|
options do |parser, options|
|
||||||
parser.banner << self.delete_banner
|
parser.banner << self.delete_banner
|
||||||
|
|
||||||
parser.recognize_option_value(:instance, 'server',
|
parser.recognize_option_value(:instance,
|
||||||
|
resource_name: :server,
|
||||||
|
command_name: :pause,
|
||||||
type: :switch,
|
type: :switch,
|
||||||
default: 'node',
|
default: 'node',
|
||||||
switch_value: 'instance',
|
switch_value: 'instance',
|
||||||
option_key: :key,
|
option_key: :key
|
||||||
i18n_scope: 'pause'
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -61,12 +61,13 @@ class ServerOptions < CommonOptions
|
|||||||
options do |parser, options|
|
options do |parser, options|
|
||||||
parser.banner << self.delete_banner
|
parser.banner << self.delete_banner
|
||||||
|
|
||||||
parser.recognize_option_value(:instance, 'server',
|
parser.recognize_option_value(:instance,
|
||||||
|
resource_name: :server,
|
||||||
|
command_name: :unpause,
|
||||||
type: :switch,
|
type: :switch,
|
||||||
default: 'node',
|
default: 'node',
|
||||||
switch_value: 'instance',
|
switch_value: 'instance',
|
||||||
option_key: :key,
|
option_key: :key
|
||||||
i18n_scope: 'unpause'
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -75,12 +76,13 @@ class ServerOptions < CommonOptions
|
|||||||
options do |parser, options|
|
options do |parser, options|
|
||||||
parser.banner << self.delete_banner
|
parser.banner << self.delete_banner
|
||||||
|
|
||||||
parser.recognize_option_value(:instance, 'server',
|
parser.recognize_option_value(:instance,
|
||||||
|
resource_name: :server,
|
||||||
|
command_name: :reserve,
|
||||||
type: :switch,
|
type: :switch,
|
||||||
default: 'node',
|
default: 'node',
|
||||||
switch_value: 'instance',
|
switch_value: 'instance',
|
||||||
option_key: :key,
|
option_key: :key
|
||||||
i18n_scope: 'reserve'
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -89,12 +91,13 @@ class ServerOptions < CommonOptions
|
|||||||
options do |parser, options|
|
options do |parser, options|
|
||||||
parser.banner << self.delete_banner
|
parser.banner << self.delete_banner
|
||||||
|
|
||||||
parser.recognize_option_value(:instance, 'server',
|
parser.recognize_option_value(:instance,
|
||||||
|
resource_name: :server,
|
||||||
|
command_name: :unreserve,
|
||||||
type: :switch,
|
type: :switch,
|
||||||
default: 'node',
|
default: 'node',
|
||||||
switch_value: 'instance',
|
switch_value: 'instance',
|
||||||
option_key: :key,
|
option_key: :key
|
||||||
i18n_scope: 'unreserve'
|
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -102,26 +105,29 @@ class ServerOptions < CommonOptions
|
|||||||
def create_options
|
def create_options
|
||||||
options do |parser, options|
|
options do |parser, options|
|
||||||
parser.banner << self.create_banner
|
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,
|
type: :switch,
|
||||||
switch_value: true,
|
switch_value: true,
|
||||||
option_key: :without_bootstrap,
|
option_key: :without_bootstrap,
|
||||||
i18n_scope: 'create'
|
i18n_scope: 'create'
|
||||||
)
|
)
|
||||||
|
|
||||||
parser.recognize_option_value(:name, 'server', short: '-N', i18n_scope: 'create')
|
parser.recognize_option_value(:name, short: '-N')
|
||||||
parser.recognize_option_value(:force, 'server', short: '-f', i18n_scope: 'create')
|
parser.recognize_option_value(:force, short: '-f')
|
||||||
parser.recognize_option_value(:key, 'server', i18n_scope: 'create')
|
parser.recognize_option_value(:key)
|
||||||
|
|
||||||
parser.recognize_option_value(:groups, 'server',
|
parser.recognize_option_value(:groups,
|
||||||
short: '-G',
|
short: '-G',
|
||||||
variable: 'GROUP_1,GROUP_2...',
|
variable: 'GROUP_1,GROUP_2...'
|
||||||
i18n_scope: 'create'
|
|
||||||
) do |groups|
|
) do |groups|
|
||||||
options[:groups] = groups.split(",")
|
options[:groups] = groups.split(",")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
parser.recognize_option_value(:private_ip, 'server', short: '-N', i18n_scope: 'create')
|
||||||
|
|
||||||
# it was disabled somewhy
|
# it was disabled somewhy
|
||||||
# parser.on('--public-ip', "Associate public IP with server") do
|
# parser.on('--public-ip', "Associate public IP with server") do
|
||||||
# options[:public_ip] = true
|
# options[:public_ip] = true
|
||||||
@ -132,10 +138,12 @@ class ServerOptions < CommonOptions
|
|||||||
def bootstrap_options
|
def bootstrap_options
|
||||||
options do |parser, options|
|
options do |parser, options|
|
||||||
parser.banner << self.bootstrap_banner
|
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(:name, short: '-N')
|
||||||
parser.recognize_option_value(:bootstrap_template, 'server', i18n_scope: 'bootstrap')
|
parser.recognize_option_value(:bootstrap_template)
|
||||||
parser.recognize_option_value(:run_list, 'server', i18n_scope: 'bootstrap') do |list|
|
parser.recognize_option_value(:run_list) do |list|
|
||||||
options[:run_list] = list.split(",")
|
options[:run_list] = list.split(",")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -145,7 +153,7 @@ class ServerOptions < CommonOptions
|
|||||||
options do |parser, options|
|
options do |parser, options|
|
||||||
parser.banner << self.add_banner
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -21,16 +21,16 @@ class StackOptions < CommonOptions
|
|||||||
def create_options
|
def create_options
|
||||||
self.options do |parser, options|
|
self.options do |parser, options|
|
||||||
parser.banner << self.create_banner
|
parser.banner << self.create_banner
|
||||||
|
parser.resource_name = :stack
|
||||||
|
|
||||||
parser.recognize_option_value(:provider, 'stack')
|
parser.recognize_option_value(:provider)
|
||||||
parser.recognize_option_value(:id, 'stack')
|
parser.recognize_option_value(:id)
|
||||||
parser.recognize_option_value(:project, 'stack')
|
parser.recognize_option_value(:project)
|
||||||
parser.recognize_option_value(:deploy_env, 'stack')
|
parser.recognize_option_value(:deploy_env)
|
||||||
parser.recognize_option_value(:stack_template, 'stack')
|
parser.recognize_option_value(:stack_template)
|
||||||
parser.recognize_option_value(:parameters_file, 'stack')
|
parser.recognize_option_value(:parameters_file)
|
||||||
parser.recognize_option_value(:run_list, 'stack')
|
parser.recognize_option_value(:run_list)
|
||||||
parser.recognize_option_value(:without_bootstrap, 'stack', type: :switch, switch_value: true)
|
parser.recognize_option_value(:without_bootstrap, type: :switch, switch_value: true)
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1,37 +0,0 @@
|
|||||||
require "devops-client/options/common_options"
|
|
||||||
|
|
||||||
class StackPresetOptions < CommonOptions
|
|
||||||
|
|
||||||
commands :list, :show, :apply
|
|
||||||
|
|
||||||
def initialize args, def_options
|
|
||||||
super(args, def_options)
|
|
||||||
self.header = I18n.t("headers.stack_preset")
|
|
||||||
self.banner_header = "stack_preset"
|
|
||||||
self.list_params = ["[provider]", "[ec2|openstack]"]
|
|
||||||
self.show_params = ["STACK"]
|
|
||||||
self.apply_params = ["PRESET"]
|
|
||||||
end
|
|
||||||
|
|
||||||
def apply_options
|
|
||||||
self.options do |parser, options|
|
|
||||||
parser.banner << self.apply_banner
|
|
||||||
|
|
||||||
parser.recognize_option_value(:provider, 'stack_preset')
|
|
||||||
parser.recognize_option_value(:project, 'stack_preset')
|
|
||||||
parser.recognize_option_value(:deploy_env, 'stack_preset')
|
|
||||||
parser.recognize_option_value(:stack, 'stack_preset')
|
|
||||||
parser.recognize_option_value(:project, 'stack_preset')
|
|
||||||
parser.recognize_option_value(:deploy_env, 'stack_preset')
|
|
||||||
parser.recognize_option_value(:parameters_file, 'stack_preset')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
extend_options_method :list_options do |options|
|
|
||||||
if args[2]
|
|
||||||
options[:given_provider] = args[2]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
@ -2,7 +2,7 @@ require "devops-client/options/common_options"
|
|||||||
|
|
||||||
class StackTemplateOptions < CommonOptions
|
class StackTemplateOptions < CommonOptions
|
||||||
|
|
||||||
commands :create, :delete, :list, :show
|
commands :create, :delete, :list, :show, :update_url
|
||||||
|
|
||||||
def initialize args, def_options
|
def initialize args, def_options
|
||||||
super(args, def_options)
|
super(args, def_options)
|
||||||
@ -11,15 +11,17 @@ class StackTemplateOptions < CommonOptions
|
|||||||
self.list_params = ["[provider]", "[ec2|openstack]"]
|
self.list_params = ["[provider]", "[ec2|openstack]"]
|
||||||
self.show_params = ["STACK_TEMPLATE"]
|
self.show_params = ["STACK_TEMPLATE"]
|
||||||
self.delete_params = ["STACK_TEMPLATE"]
|
self.delete_params = ["STACK_TEMPLATE"]
|
||||||
|
self.update_url_params = ["STACK_TEMPLATE"]
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_options
|
def create_options
|
||||||
self.options do |parser, options|
|
self.options do |parser, options|
|
||||||
parser.banner << self.create_banner
|
parser.banner << self.create_banner
|
||||||
|
parser.resource_name = :stack_template
|
||||||
|
|
||||||
parser.recognize_option_value(:provider, 'stack_template', default: nil)
|
parser.recognize_option_value(:provider, default: nil)
|
||||||
parser.recognize_option_value(:id, 'stack_template')
|
parser.recognize_option_value(:id)
|
||||||
parser.recognize_option_value(:template_file, 'stack_template')
|
parser.recognize_option_value(:template_file)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -18,7 +18,7 @@ class UserOptions < CommonOptions
|
|||||||
self.options do |parser, options|
|
self.options do |parser, options|
|
||||||
parser.banner << self.create_banner
|
parser.banner << self.create_banner
|
||||||
|
|
||||||
parser.recognize_option_value(:new_password, 'user')
|
parser.recognize_option_value(:new_password, resource_name: :user)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1,45 +0,0 @@
|
|||||||
require "devops-client/output/base"
|
|
||||||
|
|
||||||
module Output
|
|
||||||
class StackPreset < Base
|
|
||||||
|
|
||||||
def table
|
|
||||||
if outputting_list?
|
|
||||||
title = I18n.t("output.title.stack_preset.list")
|
|
||||||
headers, rows = create_list
|
|
||||||
else
|
|
||||||
title = I18n.t("output.title.stack.show", id: @data["id"])
|
|
||||||
headers, rows = create_apply
|
|
||||||
end
|
|
||||||
create_table headers, rows, title, with_num?
|
|
||||||
end
|
|
||||||
|
|
||||||
def csv
|
|
||||||
if outputting_list?
|
|
||||||
headers, rows = create_list
|
|
||||||
else
|
|
||||||
headers, rows = create_show
|
|
||||||
end
|
|
||||||
create_csv headers, rows, with_num?
|
|
||||||
end
|
|
||||||
|
|
||||||
def json
|
|
||||||
JSON.pretty_generate(@data)
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def create_list
|
|
||||||
abort(I18n.t("output.not_found.stack_preset.list")) if @data.empty?
|
|
||||||
|
|
||||||
fields_to_output = %w(id)
|
|
||||||
|
|
||||||
headers_and_rows(@data, fields_to_output)
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_apply
|
|
||||||
headers_and_rows([@data], %w(id deploy_env stack_template cloud_stack_id stack_status))
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@ -43,7 +43,6 @@ en:
|
|||||||
user: "User"
|
user: "User"
|
||||||
stack: "Stack"
|
stack: "Stack"
|
||||||
stack_template: "Stack template"
|
stack_template: "Stack template"
|
||||||
stack_preset: "Stack template preset"
|
|
||||||
handler:
|
handler:
|
||||||
flavor:
|
flavor:
|
||||||
list:
|
list:
|
||||||
@ -119,10 +118,6 @@ en:
|
|||||||
question:
|
question:
|
||||||
create: "Are you sure to create stack?"
|
create: "Are you sure to create stack?"
|
||||||
delete: "Are you sure to delete stack '%{name}'?"
|
delete: "Are you sure to delete stack '%{name}'?"
|
||||||
stack_preset:
|
|
||||||
create:
|
|
||||||
parameters_file: "Path to file with JSON parameters: "
|
|
||||||
stack: 'Name of stack to create: '
|
|
||||||
message:
|
message:
|
||||||
choose_list_default: "Choose %{name} (comma separated), like 1,2,3 or empty for default value '%{default}': "
|
choose_list_default: "Choose %{name} (comma separated), like 1,2,3 or empty for default value '%{default}': "
|
||||||
choose_list: "Choose %{name} (comma separated), like 1,2,3: "
|
choose_list: "Choose %{name} (comma separated), like 1,2,3: "
|
||||||
@ -236,9 +231,6 @@ en:
|
|||||||
stack_template:
|
stack_template:
|
||||||
list: "Stack Templates"
|
list: "Stack Templates"
|
||||||
show: "Stack Template"
|
show: "Stack Template"
|
||||||
stack_preset:
|
|
||||||
list: "Stack Template Presets"
|
|
||||||
show: "Stack Template Preset"
|
|
||||||
stack:
|
stack:
|
||||||
list: "Stacks"
|
list: "Stacks"
|
||||||
show: "Stack"
|
show: "Stack"
|
||||||
@ -274,9 +266,6 @@ en:
|
|||||||
stack_template:
|
stack_template:
|
||||||
list: "No stack templates found"
|
list: "No stack templates found"
|
||||||
show: "There isn't such stack template"
|
show: "There isn't such stack template"
|
||||||
stack_preset:
|
|
||||||
list: "No stack template presets found"
|
|
||||||
show: "There isn't such stack template preset"
|
|
||||||
stack:
|
stack:
|
||||||
list: "No stacks found"
|
list: "No stacks found"
|
||||||
show: "There isn't such stack"
|
show: "There isn't such stack"
|
||||||
@ -360,11 +349,12 @@ en:
|
|||||||
unreserve:
|
unreserve:
|
||||||
instance: Unreserve server by instance id
|
instance: Unreserve server by instance id
|
||||||
create:
|
create:
|
||||||
without-bootstrap: 'Run server without bootsraping phase'
|
without_bootstrap: 'Run server without bootsraping phase'
|
||||||
name: Set node name
|
name: Set node name
|
||||||
groups: The security groups for this server
|
groups: The security groups for this server
|
||||||
force: Cancel rollback operation on error
|
force: Cancel rollback operation on error
|
||||||
key: User another key for server
|
key: User another key for server
|
||||||
|
private_ip: Private ip for this server
|
||||||
bootstrap:
|
bootstrap:
|
||||||
name: Set chef name
|
name: Set chef name
|
||||||
bootstrap_template: Bootstrap template
|
bootstrap_template: Bootstrap template
|
||||||
@ -377,14 +367,12 @@ en:
|
|||||||
deploy_env: Deploy env
|
deploy_env: Deploy env
|
||||||
project: Stack project
|
project: Stack project
|
||||||
stack_template: Stack template
|
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:
|
stack_template:
|
||||||
provider: Stack template provider
|
provider: Stack template provider
|
||||||
id: Stack template id
|
id: Stack template id
|
||||||
template_file: Stack template file
|
template_file: Stack template file
|
||||||
stack_preset:
|
|
||||||
parameters_file: Path to file with JSON parameters
|
|
||||||
stack: 'Name of stack to build: '
|
|
||||||
provider: Stack provider
|
|
||||||
user:
|
user:
|
||||||
new_password: New user password
|
new_password: New user password
|
||||||
|
|||||||
@ -36,8 +36,9 @@ guard :rspec, cmd: "rspec" do
|
|||||||
watch(rspec.spec_support) { rspec.spec_dir }
|
watch(rspec.spec_support) { rspec.spec_dir }
|
||||||
watch(rspec.spec_files)
|
watch(rspec.spec_files)
|
||||||
|
|
||||||
# Factories files
|
# Spec config files
|
||||||
watch(%r{spec/factories/.+\.rb}) { rspec.spec_dir }
|
watch(%r{spec/factories/.+\.rb}) { rspec.spec_dir }
|
||||||
|
watch(%r{spec/shared_contexts.+\.rb}) { rspec.spec_dir }
|
||||||
|
|
||||||
# Devops files
|
# Devops files
|
||||||
watch(%r{db/.+\.rb}) { rspec.spec_dir }
|
watch(%r{db/.+\.rb}) { rspec.spec_dir }
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
require "lib/executors/server_executor"
|
require "lib/executors/server_executor"
|
||||||
require 'db/mongo/models/stack/stack_factory'
|
require 'db/mongo/models/stack/stack_factory'
|
||||||
require "app/api2/parsers/stack"
|
require "app/api2/parsers/stack"
|
||||||
|
require 'workers/stack_bootstrap_worker'
|
||||||
require_relative "request_handler"
|
require_relative "request_handler"
|
||||||
|
|
||||||
module Devops
|
module Devops
|
||||||
|
|||||||
@ -1,43 +0,0 @@
|
|||||||
require 'json'
|
|
||||||
require 'lib/stack_presets/factory'
|
|
||||||
require 'workers/stack_bootstrap_worker'
|
|
||||||
require "app/api2/parsers/stack_preset"
|
|
||||||
require_relative "request_handler"
|
|
||||||
|
|
||||||
module Devops
|
|
||||||
module API2_0
|
|
||||||
module Handler
|
|
||||||
class StackPreset < RequestHandler
|
|
||||||
|
|
||||||
set_parser Devops::API2_0::Parser::StackPresetParser
|
|
||||||
|
|
||||||
def presets
|
|
||||||
Devops::StackPresetsFactory.list
|
|
||||||
end
|
|
||||||
|
|
||||||
def preset id
|
|
||||||
Devops::StackPresetsFactory.get(id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def apply id
|
|
||||||
body = parser.apply
|
|
||||||
preset = Devops::StackPresetsFactory.get(id)
|
|
||||||
stack = preset.create_stack_from_preset(body)
|
|
||||||
stack.owner = owner_from_request
|
|
||||||
Devops::Db.connector.stack_insert(stack)
|
|
||||||
|
|
||||||
file = JobStarter.start_job(:worker, :stack_bootstrap,
|
|
||||||
provider: stack.provider,
|
|
||||||
stack_id: stack.id,
|
|
||||||
request: @request
|
|
||||||
)
|
|
||||||
puts "Syncing report is located here: #{file}"
|
|
||||||
|
|
||||||
stack
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@ -39,6 +39,14 @@ module Devops
|
|||||||
end
|
end
|
||||||
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
|
private
|
||||||
|
|
||||||
# returns:
|
# returns:
|
||||||
|
|||||||
@ -1,16 +0,0 @@
|
|||||||
require_relative "request_parser"
|
|
||||||
|
|
||||||
module Devops
|
|
||||||
module API2_0
|
|
||||||
module Parser
|
|
||||||
class StackPresetParser < RequestParser
|
|
||||||
|
|
||||||
def apply
|
|
||||||
create_object_from_json_body
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@ -196,6 +196,7 @@ module Devops
|
|||||||
# "force": null, -> do not delete server on error
|
# "force": null, -> do not delete server on error
|
||||||
# "groups": [], -> specify special security groups, overrides value from project env
|
# "groups": [], -> specify special security groups, overrides value from project env
|
||||||
# "key": "ssh key" -> specify ssh key for server, 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
|
# * *Returns* : text stream
|
||||||
|
|||||||
@ -1,70 +0,0 @@
|
|||||||
module Devops
|
|
||||||
module API2_0
|
|
||||||
module Routes
|
|
||||||
module StackPresetRoutes
|
|
||||||
|
|
||||||
def self.registered(app)
|
|
||||||
# Get list of available stack_template_presets
|
|
||||||
#
|
|
||||||
# * *Request*
|
|
||||||
# - method : GET
|
|
||||||
# - headers :
|
|
||||||
# - Accept: application/json
|
|
||||||
#
|
|
||||||
# * *Returns* : array of hashes
|
|
||||||
# [ {id: 'preset id', template_preset_body: 'long body'} ]
|
|
||||||
#
|
|
||||||
app.get_with_headers "/stack_presets", :headers => [:accept] do
|
|
||||||
# check_privileges("stack_template_presets", "r")
|
|
||||||
json Devops::API2_0::Handler::StackPreset.new(request).presets.map(&:to_hash)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Get information about stack_template_preset
|
|
||||||
#
|
|
||||||
# * *Request*
|
|
||||||
# - method : GET
|
|
||||||
# - headers :
|
|
||||||
# - Accept: application/json
|
|
||||||
#
|
|
||||||
# * *Returns* : hash
|
|
||||||
# {id: 'preset id', template_preset_body: 'long body'}
|
|
||||||
#
|
|
||||||
app.get_with_headers "/stack_presets/:id", :headers => [:accept] do |id|
|
|
||||||
# check_privileges("stack_template_presets", "r")
|
|
||||||
json Devops::API2_0::Handler::StackPreset.new(request).preset(id).to_hash
|
|
||||||
end
|
|
||||||
|
|
||||||
# Build stack template from preset
|
|
||||||
#
|
|
||||||
# * *Request*
|
|
||||||
# - method : POST
|
|
||||||
# - headers :
|
|
||||||
# - Accept: application/json
|
|
||||||
# - params :
|
|
||||||
# - provider: string
|
|
||||||
# - stack_template_id: id of stack template to create
|
|
||||||
# - template_attrs: hash with template attributes
|
|
||||||
#
|
|
||||||
# TODO: not stack template, but stack itself
|
|
||||||
#
|
|
||||||
# * *Returns* : created stack template model
|
|
||||||
# {
|
|
||||||
# id: 'template id',
|
|
||||||
# provider: 'provider',
|
|
||||||
# template_body: 'long body'
|
|
||||||
# }
|
|
||||||
#
|
|
||||||
app.post_with_headers "/stack_presets/:id/apply", :headers => [:accept] do |id|
|
|
||||||
# check_privileges("stack_template_presets", "r")
|
|
||||||
check_privileges('stack_template', 'w')
|
|
||||||
stack = Devops::API2_0::Handler::StackPreset.new(request).apply(id)
|
|
||||||
create_response 'Created', stack.to_hash, 201
|
|
||||||
end
|
|
||||||
|
|
||||||
puts "Stack template presets routes initialized"
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@ -22,6 +22,11 @@ module Devops
|
|||||||
create_response 'Created', model.to_hash, 201
|
create_response 'Created', model.to_hash, 201
|
||||||
end
|
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 = {}
|
||||||
|
|
||||||
hash['GET'] = lambda {|stack_template_id|
|
hash['GET'] = lambda {|stack_template_id|
|
||||||
|
|||||||
@ -22,7 +22,6 @@ module Devops
|
|||||||
|
|
||||||
require_relative "api2/handlers/stack"
|
require_relative "api2/handlers/stack"
|
||||||
require_relative "api2/handlers/stack_template"
|
require_relative "api2/handlers/stack_template"
|
||||||
require_relative "api2/handlers/stack_preset"
|
|
||||||
|
|
||||||
require 'lib/stubber'
|
require 'lib/stubber'
|
||||||
end
|
end
|
||||||
@ -69,7 +68,6 @@ module Devops
|
|||||||
require_relative "api2/routes/bootstrap_templates"
|
require_relative "api2/routes/bootstrap_templates"
|
||||||
require_relative "api2/routes/stack"
|
require_relative "api2/routes/stack"
|
||||||
require_relative "api2/routes/stack_template"
|
require_relative "api2/routes/stack_template"
|
||||||
require_relative "api2/routes/stack_presets"
|
|
||||||
require_relative "api2/routes/statistic"
|
require_relative "api2/routes/statistic"
|
||||||
require_relative "api2/routes/report"
|
require_relative "api2/routes/report"
|
||||||
|
|
||||||
|
|||||||
@ -37,6 +37,7 @@ config[:aws_certificate] = "/path/to/.ssh/ec2.pem"
|
|||||||
config[:aws_availability_zone] = "aws_zone"
|
config[:aws_availability_zone] = "aws_zone"
|
||||||
config[:aws_proxy] = ""
|
config[:aws_proxy] = ""
|
||||||
config[:aws_no_proxy] = ""
|
config[:aws_no_proxy] = ""
|
||||||
|
config[:aws_stack_templates_bucket] = 'stacktemplates'
|
||||||
|
|
||||||
# static settings
|
# static settings
|
||||||
config[:static_ssh_key] = "ssh_key" # or nil
|
config[:static_ssh_key] = "ssh_key" # or nil
|
||||||
|
|||||||
@ -23,13 +23,13 @@ module Devops
|
|||||||
set_field_validators :id, [::Validators::FieldValidator::NotNil,
|
set_field_validators :id, [::Validators::FieldValidator::NotNil,
|
||||||
::Validators::FieldValidator::FieldType::String,
|
::Validators::FieldValidator::FieldType::String,
|
||||||
::Validators::FieldValidator::NotEmpty,
|
::Validators::FieldValidator::NotEmpty,
|
||||||
::Validators::FieldValidator::ImageName,
|
::Validators::FieldValidator::ImageId,
|
||||||
::Validators::Image::ImageInFilter]
|
::Validators::Image::ImageInFilter]
|
||||||
|
|
||||||
set_field_validators :remote_user, [::Validators::FieldValidator::NotNil,
|
set_field_validators :remote_user, [::Validators::FieldValidator::NotNil,
|
||||||
::Validators::FieldValidator::FieldType::String,
|
::Validators::FieldValidator::FieldType::String,
|
||||||
::Validators::FieldValidator::NotEmpty,
|
::Validators::FieldValidator::NotEmpty,
|
||||||
::Validators::FieldValidator::ImageName]
|
::Validators::FieldValidator::ImageUsername]
|
||||||
|
|
||||||
set_field_validators :name, [::Validators::FieldValidator::NotNil,
|
set_field_validators :name, [::Validators::FieldValidator::NotNil,
|
||||||
::Validators::FieldValidator::FieldType::String,
|
::Validators::FieldValidator::FieldType::String,
|
||||||
|
|||||||
@ -146,6 +146,7 @@ module Devops
|
|||||||
h
|
h
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# TODO: why symbols here?
|
||||||
def to_hash_list
|
def to_hash_list
|
||||||
{
|
{
|
||||||
name: self.id,
|
name: self.id,
|
||||||
@ -207,6 +208,7 @@ module Devops
|
|||||||
Project.new p
|
Project.new p
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# maybe it worth to move components functionality to devops-nibr?
|
||||||
#TODO: create validator
|
#TODO: create validator
|
||||||
def validate_components
|
def validate_components
|
||||||
raise InvalidRecord.new "Components is not a hash" unless self.components.is_a?(Hash)
|
raise InvalidRecord.new "Components is not a hash" unless self.components.is_a?(Hash)
|
||||||
|
|||||||
@ -17,6 +17,7 @@ module Devops
|
|||||||
|
|
||||||
def initialize a={}
|
def initialize a={}
|
||||||
super(a)
|
super(a)
|
||||||
|
self.provider = Provider::Openstack::PROVIDER
|
||||||
self.username = a["username"]
|
self.username = a["username"]
|
||||||
self.auth_url = a["auth_url"]
|
self.auth_url = a["auth_url"]
|
||||||
self.tenant = a["tenant"]
|
self.tenant = a["tenant"]
|
||||||
|
|||||||
@ -131,7 +131,11 @@ module Devops
|
|||||||
end
|
end
|
||||||
|
|
||||||
def template_body
|
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
|
end
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
|
|||||||
@ -20,34 +20,25 @@ module Devops
|
|||||||
raise 'Implement me'
|
raise 'Implement me'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update_template_url
|
||||||
|
self.template_url = generate_template_file_and_upload_to_storage(id, template_body)
|
||||||
|
end
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
|
|
||||||
def create(attrs)
|
def create(attrs)
|
||||||
template = attrs['template_body']
|
model = super(attrs)
|
||||||
attrs['template_url'] = generate_template_file_and_upload_to_storage(attrs['id'], template)
|
model.update_template_url
|
||||||
super(attrs)
|
model
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def generate_template_file_and_upload_to_storage(id, json)
|
def generate_template_file_and_upload_to_storage(id, json)
|
||||||
begin
|
uniq_filename = "#{id}-#{SecureRandom.hex}.template"
|
||||||
tempfile = Tempfile.new('foo')
|
provider_instance.store_stack_template(uniq_filename, json)['url']
|
||||||
tempfile.write(json)
|
|
||||||
tempfile.close
|
|
||||||
secure_filename = "#{id}-#{SecureRandom.hex}.template"
|
|
||||||
upload_file_to_storage(secure_filename, tempfile.path)
|
|
||||||
ensure
|
|
||||||
tempfile.unlink
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def upload_file_to_storage(filename, file_path)
|
|
||||||
"https://s3.amazonaws.com/#{filename}"
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -9,11 +9,12 @@ end
|
|||||||
|
|
||||||
require "db/validators/base"
|
require "db/validators/base"
|
||||||
[
|
[
|
||||||
'db/validators/helpers/*.rb',
|
'helpers/*.rb',
|
||||||
'db/validators/deploy_env/*.rb',
|
'deploy_env/*.rb',
|
||||||
'db/validators/key/*.rb',
|
'key/*.rb',
|
||||||
'db/validators/image/*.rb',
|
'image/*.rb',
|
||||||
'db/validators/field_validators/*.rb'
|
'field_validators/*.rb'
|
||||||
].each do |files_regexp|
|
].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
|
end
|
||||||
|
|||||||
@ -9,6 +9,7 @@ module Validators
|
|||||||
def validate!
|
def validate!
|
||||||
raise InvalidRecord.new(message) unless valid?
|
raise InvalidRecord.new(message) unless valid?
|
||||||
rescue StandardError => e
|
rescue StandardError => e
|
||||||
|
DevopsLogger.logger.error [e.message, e.backtrace].join("\n")
|
||||||
raise InvalidRecord.new("An error raised during validation with #{self.class}: #{e.class}: #{e.message}")
|
raise InvalidRecord.new("An error raised during validation with #{self.class}: #{e.class}: #{e.message}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
18
devops-service/db/validators/field_validators/image_id.rb
Normal file
18
devops-service/db/validators/field_validators/image_id.rb
Normal file
@ -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
|
||||||
@ -3,15 +3,14 @@ module Validators
|
|||||||
module FieldValidator
|
module FieldValidator
|
||||||
class ImageName < Base
|
class ImageName < Base
|
||||||
|
|
||||||
MAX_NAME_LEN = 100
|
MAX_LEN = 100
|
||||||
NAME_REGEX = /\A[\w\-\.]{1,#{MAX_NAME_LEN}}\z/
|
|
||||||
|
|
||||||
def valid?
|
def valid?
|
||||||
!NAME_REGEX.match(@value).nil?
|
@value.length <= MAX_LEN
|
||||||
end
|
end
|
||||||
|
|
||||||
def message
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -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
|
||||||
@ -1,11 +1,12 @@
|
|||||||
require_relative "base"
|
require_relative "base"
|
||||||
|
|
||||||
|
|
||||||
module Validators
|
module Validators
|
||||||
module FieldValidator
|
module FieldValidator
|
||||||
class ProviderAccount < Base
|
class ProviderAccount < Base
|
||||||
|
|
||||||
def valid?
|
def valid?
|
||||||
accounts = AccountsFactory.accounts(@model.provider)
|
accounts = ::Provider::AccountsFactory.accounts(@model.provider)
|
||||||
accounts.map{|a| a.account_name}.include?(@value)
|
accounts.map{|a| a.account_name}.include?(@value)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -82,7 +82,8 @@ module Devops
|
|||||||
"deploy_env" => @deploy_env.identifier,
|
"deploy_env" => @deploy_env.identifier,
|
||||||
"created_by" => options["created_by"],
|
"created_by" => options["created_by"],
|
||||||
"provider" => @deploy_env.provider,
|
"provider" => @deploy_env.provider,
|
||||||
"provider_account" => @deploy_env.provider_account
|
"provider_account" => @deploy_env.provider_account,
|
||||||
|
"private_ip" => options["private_ip"]
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1,76 +0,0 @@
|
|||||||
require 'lib/string_helper'
|
|
||||||
require 'db/mongo/models/stack_template/stack_template_factory'
|
|
||||||
|
|
||||||
module Devops
|
|
||||||
module StackPresets
|
|
||||||
class Base
|
|
||||||
|
|
||||||
def id
|
|
||||||
StringHelper.underscore_class(self.class)
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_hash
|
|
||||||
{id: id, template_body: template_body}
|
|
||||||
end
|
|
||||||
|
|
||||||
# attrs should include
|
|
||||||
# 'provider'
|
|
||||||
# 'stack'
|
|
||||||
# 'parameters'
|
|
||||||
# 'project'
|
|
||||||
# 'deploy_env'
|
|
||||||
def create_stack_from_preset(attrs)
|
|
||||||
provider = attrs.fetch('provider')
|
|
||||||
template_name = find_or_create_stack_template!(provider)
|
|
||||||
|
|
||||||
stack_attrs = attrs.merge(
|
|
||||||
'id' => attrs['stack'],
|
|
||||||
'stack_template' => template_name
|
|
||||||
)
|
|
||||||
|
|
||||||
Model::StackFactory.create(provider, stack_attrs)
|
|
||||||
end
|
|
||||||
|
|
||||||
def template_body
|
|
||||||
@template_body ||= File.read("lib/stack_presets/#{id}.#{template_file_extension}")
|
|
||||||
end
|
|
||||||
|
|
||||||
# some templates may be YAML files
|
|
||||||
def template_file_extension
|
|
||||||
:json
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def find_or_create_stack_template!(provider)
|
|
||||||
name = stack_template_name(provider)
|
|
||||||
begin
|
|
||||||
stack_template = Devops::Api2.settings.mongo.stack_template(name)
|
|
||||||
update_stack_template(stack_template) if stack_template.template_body != template_body
|
|
||||||
rescue RecordNotFound
|
|
||||||
create_stack_template(provider)
|
|
||||||
end
|
|
||||||
name
|
|
||||||
end
|
|
||||||
|
|
||||||
def stack_template_name(provider)
|
|
||||||
"#{id}_#{provider}_preset"
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_stack_template(provider)
|
|
||||||
stack_template = Model::StackTemplateFactory.create(provider, {
|
|
||||||
'id' => stack_template_name(provider),
|
|
||||||
'provider' => provider,
|
|
||||||
'template_body' => template_body
|
|
||||||
})
|
|
||||||
Devops::Api2.settings.mongo.stack_template_insert(stack_template)
|
|
||||||
end
|
|
||||||
|
|
||||||
def update_stack_template(stack_template)
|
|
||||||
stack_template.template_body = template_body
|
|
||||||
Devops::Api2.settings.mongo.stack_template_update(stack_template)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@ -1,23 +0,0 @@
|
|||||||
require_relative 'base'
|
|
||||||
require_relative 'postgres_cluster'
|
|
||||||
require_relative 'preset_not_found'
|
|
||||||
|
|
||||||
class Devops::StackPresetsFactory
|
|
||||||
|
|
||||||
# find all classes in Devops::StackPresets modules excluding Base and factory.
|
|
||||||
# This list can be extended in external gems via defining new classes in Devops::StackPresets module.
|
|
||||||
def self.list
|
|
||||||
@list ||= Devops::StackPresets.constants.select do |class_name|
|
|
||||||
class_name != :Base
|
|
||||||
end.map do |class_name|
|
|
||||||
Devops::StackPresets.const_get(class_name).new
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.get(id)
|
|
||||||
preset = list.detect { |preset| preset.id == id }
|
|
||||||
raise PresetNotFound, "Preset '#{preset}' not found" unless preset
|
|
||||||
preset
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
module Devops::StackPresets
|
|
||||||
class PostgresCluster < Base
|
|
||||||
def template_file_extension
|
|
||||||
:yml
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
heat_template_version: 2013-05-23
|
|
||||||
|
|
||||||
description: Simple template to deploy a single compute instance
|
|
||||||
|
|
||||||
parameters:
|
|
||||||
key_name:
|
|
||||||
type: string
|
|
||||||
label: Key Name
|
|
||||||
description: Name of key-pair to be used for compute instance
|
|
||||||
|
|
||||||
resources:
|
|
||||||
my_instance:
|
|
||||||
type: OS::Nova::Server
|
|
||||||
properties:
|
|
||||||
key_name: { get_param: key_name }
|
|
||||||
image: 5f4020a1-b6ab-47e4-a0ed-de4324a17c3a
|
|
||||||
flavor: m1.micro
|
|
||||||
networks:
|
|
||||||
- network: devops-net-1
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
class PresetNotFound < StandardError
|
|
||||||
|
|
||||||
end
|
|
||||||
@ -56,7 +56,7 @@ module Provider
|
|||||||
end
|
end
|
||||||
|
|
||||||
def groups filters={}
|
def groups filters={}
|
||||||
g = self.compute.describe_security_groups(filters)
|
g = self.compute.describe_security_groups(filters || {})
|
||||||
convert_groups(g.body["securityGroupInfo"])
|
convert_groups(g.body["securityGroupInfo"])
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -99,7 +99,8 @@ module Provider
|
|||||||
options = {
|
options = {
|
||||||
"InstanceType" => flavor,
|
"InstanceType" => flavor,
|
||||||
# "Placement.AvailabilityZone" => s.options[:availability_zone],
|
# "Placement.AvailabilityZone" => s.options[:availability_zone],
|
||||||
"KeyName" => self.ssh_key
|
"KeyName" => self.ssh_key,
|
||||||
|
"PrivateIpAddress" => s.private_ip
|
||||||
}
|
}
|
||||||
vpcId = nil
|
vpcId = nil
|
||||||
unless subnets.empty?
|
unless subnets.empty?
|
||||||
@ -222,7 +223,7 @@ module Provider
|
|||||||
out.flush
|
out.flush
|
||||||
response = cloud_formation.create_stack(stack.name,
|
response = cloud_formation.create_stack(stack.name,
|
||||||
{
|
{
|
||||||
'TemplateBody' => stack.template_body,
|
'TemplateURL' => stack.stack_template_model.template_url,
|
||||||
'Parameters' => stack.parameters || {},
|
'Parameters' => stack.parameters || {},
|
||||||
'Capabilities' => ['CAPABILITY_IAM'],
|
'Capabilities' => ['CAPABILITY_IAM'],
|
||||||
'Tags' => stack_tags(stack)
|
'Tags' => stack_tags(stack)
|
||||||
@ -320,6 +321,17 @@ module Provider
|
|||||||
def describe_vpcs
|
def describe_vpcs
|
||||||
self.compute.describe_vpcs.body["vpcSet"].select{|v| v["state"] == "available"}.map{|v| {"vpc_id" => v["vpcId"], "cidr" => v["cidrBlock"] } }
|
self.compute.describe_vpcs.body["vpcSet"].select{|v| v["state"] == "available"}.map{|v| {"vpc_id" => v["vpcId"], "cidr" => v["cidrBlock"] } }
|
||||||
end
|
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
|
private
|
||||||
|
|
||||||
def convert_groups list
|
def convert_groups list
|
||||||
@ -376,6 +388,16 @@ module Provider
|
|||||||
@orchestration ||= Fog::AWS::CloudFormation.new(connection_options)
|
@orchestration ||= Fog::AWS::CloudFormation.new(connection_options)
|
||||||
end
|
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)
|
def instance_name(instance)
|
||||||
return instance["tagSet"]["Name"] if instance["tagSet"]["Name"]
|
return instance["tagSet"]["Name"] if instance["tagSet"]["Name"]
|
||||||
if instance['tagSet']['aws:autoscaling:groupName']
|
if instance['tagSet']['aws:autoscaling:groupName']
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
require 'db/mongo/connectors/filter'
|
require 'db/mongo/connectors/filter'
|
||||||
require 'spec/connectors/tester_connector/filter'
|
require 'spec/connectors/tester_connector/filter'
|
||||||
require_relative 'shared_connectors_context'
|
|
||||||
|
|
||||||
RSpec.describe Connectors::Filter, type: :connector do
|
RSpec.describe Connectors::Filter, type: :connector do
|
||||||
set_tester_connector TesterConnector::Filter
|
set_tester_connector TesterConnector::Filter
|
||||||
include_context 'connectors'
|
|
||||||
let(:provider) {'ec2'}
|
let(:provider) {'ec2'}
|
||||||
|
|
||||||
describe '#available_images' do
|
describe '#available_images' do
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
require 'db/mongo/connectors/image'
|
require 'db/mongo/connectors/image'
|
||||||
require 'spec/connectors/tester_connector/image'
|
require 'spec/connectors/tester_connector/image'
|
||||||
require_relative 'shared_connectors_context'
|
|
||||||
|
|
||||||
RSpec.describe Connectors::Image, type: :connector do
|
RSpec.describe Connectors::Image, type: :connector do
|
||||||
set_tester_connector TesterConnector::Image
|
set_tester_connector TesterConnector::Image
|
||||||
include_context 'connectors'
|
|
||||||
let(:model_class) { Devops::Model::Image }
|
let(:model_class) { Devops::Model::Image }
|
||||||
|
|
||||||
include_examples 'mongo connector', {
|
include_examples 'mongo connector', {
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
require 'db/mongo/connectors/key'
|
require 'db/mongo/connectors/key'
|
||||||
require 'db/mongo/models/key'
|
require 'db/mongo/models/key'
|
||||||
require 'spec/connectors/tester_connector/key'
|
require 'spec/connectors/tester_connector/key'
|
||||||
require_relative 'shared_connectors_context'
|
|
||||||
|
|
||||||
RSpec.describe Connectors::Key, type: :connector do
|
RSpec.describe Connectors::Key, type: :connector do
|
||||||
set_tester_connector TesterConnector::Key
|
set_tester_connector TesterConnector::Key
|
||||||
include_context 'connectors'
|
|
||||||
let(:model_class) { Devops::Model::Key }
|
let(:model_class) { Devops::Model::Key }
|
||||||
|
|
||||||
include_examples 'mongo connector', model_name: :key, only: [:insert, :list]
|
include_examples 'mongo connector', model_name: :key, only: [:insert, :list]
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
require 'db/mongo/connectors/project'
|
require 'db/mongo/connectors/project'
|
||||||
require 'spec/connectors/tester_connector/project'
|
require 'spec/connectors/tester_connector/project'
|
||||||
require_relative 'shared_connectors_context'
|
|
||||||
|
|
||||||
RSpec.describe Connectors::Project, type: :connector do
|
RSpec.describe Connectors::Project, type: :connector do
|
||||||
set_tester_connector TesterConnector::Project
|
set_tester_connector TesterConnector::Project
|
||||||
include_context 'connectors'
|
|
||||||
let(:model_class) { Devops::Model::Project }
|
let(:model_class) { Devops::Model::Project }
|
||||||
|
|
||||||
include_examples 'mongo connector', {
|
include_examples 'mongo connector', {
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
require 'db/mongo/connectors/stack_template'
|
require 'db/mongo/connectors/stack_template'
|
||||||
require 'spec/connectors/tester_connector/stack_template'
|
require 'spec/connectors/tester_connector/stack_template'
|
||||||
require_relative 'shared_connectors_context'
|
|
||||||
|
|
||||||
RSpec.describe Connectors::StackTemplate, type: :connector do
|
RSpec.describe Connectors::StackTemplate, type: :connector do
|
||||||
set_tester_connector TesterConnector::StackTemplate
|
set_tester_connector TesterConnector::StackTemplate
|
||||||
include_context 'connectors'
|
|
||||||
let(:model_class) { Devops::Model::StackTemplateEc2 }
|
let(:model_class) { Devops::Model::StackTemplateEc2 }
|
||||||
|
|
||||||
include_examples 'mongo connector', {
|
include_examples 'mongo connector', {
|
||||||
|
|||||||
25
devops-service/spec/factories/provider_account.rb
Normal file
25
devops-service/spec/factories/provider_account.rb
Normal file
@ -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
|
||||||
@ -1,12 +1,14 @@
|
|||||||
require 'db/mongo/models/deploy_env/deploy_env_ec2'
|
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
|
RSpec.describe Devops::Model::DeployEnvEc2, type: :model do
|
||||||
let(:env) { build(:deploy_env_ec2) }
|
let(:env) { build(:deploy_env_ec2) }
|
||||||
include_context 'stubbed calls to connector in env validators'
|
|
||||||
|
|
||||||
it_behaves_like 'deploy env'
|
describe 'it inherits from cloud deploy_env', stubbed_env_validators: true, stubbed_logger: true do
|
||||||
it_behaves_like 'cloud deploy env'
|
it_behaves_like 'deploy env'
|
||||||
|
it_behaves_like 'cloud deploy env'
|
||||||
|
end
|
||||||
|
|
||||||
describe '#initialize' do
|
describe '#initialize' do
|
||||||
it 'keep only first subnet in given array' do
|
it 'keep only first subnet in given array' do
|
||||||
|
|||||||
@ -1,12 +1,14 @@
|
|||||||
require 'db/mongo/models/deploy_env/deploy_env_openstack'
|
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
|
RSpec.describe Devops::Model::DeployEnvOpenstack, type: :model do
|
||||||
let(:env) { build(:deploy_env_openstack) }
|
let(:env) { build(:deploy_env_openstack) }
|
||||||
include_context 'stubbed calls to connector in env validators'
|
|
||||||
|
|
||||||
it_behaves_like 'deploy env'
|
describe 'it inherits from cloud deploy_env', stubbed_env_validators: true, stubbed_logger: true do
|
||||||
it_behaves_like 'cloud deploy env'
|
it_behaves_like 'deploy env'
|
||||||
|
it_behaves_like 'cloud deploy env'
|
||||||
|
end
|
||||||
|
|
||||||
describe '.create' do
|
describe '.create' do
|
||||||
it 'returns instance of DeployEnvOpenstack' do
|
it 'returns instance of DeployEnvOpenstack' do
|
||||||
|
|||||||
@ -1,14 +1,19 @@
|
|||||||
require 'db/mongo/models/deploy_env/deploy_env_static'
|
require 'db/mongo/models/deploy_env/deploy_env_static'
|
||||||
|
require_relative 'shared_deploy_env_specs'
|
||||||
|
|
||||||
RSpec.describe Devops::Model::DeployEnvStatic, type: :model do
|
RSpec.describe Devops::Model::DeployEnvStatic, type: :model do
|
||||||
let(:env) { build(:deploy_env_static) }
|
let(:env) { build(:deploy_env_static) }
|
||||||
|
|
||||||
before do
|
|
||||||
allow(Provider::ProviderFactory).to receive(:providers).and_return(%w(static))
|
describe 'it inherits from deploy env', stubbed_logger: true do
|
||||||
allow_any_instance_of(Validators::Helpers::Users).to receive(:available_users).and_return(['root'])
|
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
|
end
|
||||||
|
|
||||||
it_behaves_like 'deploy env'
|
|
||||||
|
|
||||||
describe '.create' do
|
describe '.create' do
|
||||||
it 'returns instance of DeployEnvStatic' do
|
it 'returns instance of DeployEnvStatic' do
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
require 'core/devops-application'
|
|
||||||
require 'core/devops-db'
|
|
||||||
|
|
||||||
RSpec.shared_examples 'deploy env' do
|
RSpec.shared_examples 'deploy env' do
|
||||||
validated_model_name = described_class.name.demodulize.underscore
|
validated_model_name = described_class.name.demodulize.underscore
|
||||||
include SpecSupport
|
|
||||||
|
|
||||||
it 'is valid with correct attrs' do
|
it 'is valid with correct attrs' do
|
||||||
expect(env).to be_valid
|
expect(env).to be_valid
|
||||||
@ -81,11 +77,10 @@ RSpec.shared_examples 'deploy env' do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#update_field' do
|
describe '#update_field', stubbed_connector: true do
|
||||||
subject { env.update_field('project_name', 'run_list', ['role[asd]']) }
|
subject { env.update_field('project_name', 'run_list', ['role[asd]']) }
|
||||||
before do
|
before do
|
||||||
allow_message_expectations_on_nil
|
allow(stubbed_connector).to receive(:set_project_deploy_env_field)
|
||||||
allow(Devops::Db.connector).to receive(:set_project_deploy_env_field)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'validate it' do
|
it 'validate it' do
|
||||||
@ -98,12 +93,13 @@ RSpec.shared_examples 'deploy env' do
|
|||||||
end
|
end
|
||||||
|
|
||||||
it 'saves it' do
|
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
|
subject
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#create_role', stub_logger: true do
|
describe '#create_role', stubbed_logger: true do
|
||||||
subject { env.create_role('project_name') }
|
subject { env.create_role('project_name') }
|
||||||
before do
|
before do
|
||||||
allow(env).to receive_message_chain('knife_instance.role_name') { 'role_name' }
|
allow(env).to receive_message_chain('knife_instance.role_name') { 'role_name' }
|
||||||
@ -152,7 +148,7 @@ RSpec.shared_examples 'deploy env' do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#rename', stub_logger: true do
|
describe '#rename', stubbed_logger: true do
|
||||||
subject { env.rename('project_id', 'new_name') }
|
subject { env.rename('project_id', 'new_name') }
|
||||||
let(:old_role_name) {'project_id_name'}
|
let(:old_role_name) {'project_id_name'}
|
||||||
let(:new_role_name) {'project_id_new_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)
|
stub_const('Devops::Model::Project', project_class_double)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'raises InvalidRecord if env with such name already exists in project' do
|
it 'raises InvalidRecord if env with such name already exists in project', stubbed_connector: true do
|
||||||
allow(Devops::Db.connector).to receive_message_chain('project.deploy_env')
|
project = build(:project, with_deploy_env_identifiers: %w(new_name))
|
||||||
|
allow(stubbed_connector).to receive(:project) { project }
|
||||||
expect{subject}.to raise_error(InvalidRecord)
|
expect{subject}.to raise_error(InvalidRecord)
|
||||||
end
|
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
|
before do
|
||||||
allow(Devops::Db.connector).to receive_message_chain('project.deploy_env') {raise RecordNotFound}
|
allow(stubbed_connector).to receive(:project) { build(:project) }
|
||||||
allow(Devops::Db.connector).to receive(:set_project_deploy_env_field)
|
allow(stubbed_connector).to receive(:set_project_deploy_env_field)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'validates new identifier' do
|
it 'validates new identifier' do
|
||||||
@ -2,35 +2,44 @@ require 'db/mongo/models/image'
|
|||||||
|
|
||||||
RSpec.describe Devops::Model::Image, type: :model do
|
RSpec.describe Devops::Model::Image, type: :model do
|
||||||
let(:image) { build(:image) }
|
let(:image) { build(:image) }
|
||||||
let(:name_with_dash) { 'asd-asd' }
|
let(:string_with_dash) { 'asd-asd' }
|
||||||
let(:name_with_slash) { 'asd/asd' }
|
let(:string_with_slash) { 'asd/asd' }
|
||||||
|
let(:string_with_parenthesis) { 'centos 6.5 x86_64 (development instance)' }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
allow(Provider::ProviderFactory).to receive(:providers).and_return(%w(openstack ec2 static'))
|
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
|
end
|
||||||
|
|
||||||
it 'is valid with correct attrs' do
|
it 'is valid with correct attrs' do
|
||||||
expect(image).to be_valid
|
expect(image).to be_valid
|
||||||
end
|
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', :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', :remote_user, :not_nil, :non_empty_string, :field_validator
|
||||||
include_examples 'field type validation', :name, :not_nil, :non_empty_string, :field_validator
|
include_examples 'field type validation', :name, :not_nil, :non_empty_string, :field_validator
|
||||||
include_examples 'field type validation', :bootstrap_template, :maybe_nil, :non_empty_string, :only_word_symbols, :field_validator
|
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
|
it 'id should contain only letters, digits and dashes' do
|
||||||
expect(build(:image, id: name_with_dash)).to be_valid
|
expect(build(:image, id: string_with_dash)).to be_valid
|
||||||
expect(build(:image, id: name_with_slash)).not_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
|
end
|
||||||
|
|
||||||
it "id should be included in image filters" do
|
it "id should be included in image filters" do
|
||||||
expect(build(:image, id: 'wrong')).not_to be_valid
|
expect(build(:image, id: 'wrong')).not_to be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'name should contain only letters, digits and dashes' do
|
it 'name may contain everything' do
|
||||||
expect(build(:image, name: name_with_slash)).not_to be_valid
|
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
|
end
|
||||||
|
|
||||||
it 'bootstrap_template should be included in available bootstrap templates' do
|
it 'bootstrap_template should be included in available bootstrap templates' do
|
||||||
|
|||||||
@ -7,7 +7,7 @@ RSpec.describe Devops::Model::Key, type: :model do
|
|||||||
expect(key).to be_valid
|
expect(key).to be_valid
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'validations' do
|
describe 'validations', stubbed_logger: true do
|
||||||
it 'key file should exist in file system' do
|
it 'key file should exist in file system' do
|
||||||
expect(build(:key, path: './not_exist')).not_to be_valid
|
expect(build(:key, path: './not_exist')).not_to be_valid
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,11 +1,9 @@
|
|||||||
require 'db/mongo/models/project'
|
require 'db/mongo/models/project'
|
||||||
require_relative 'shared_models_context'
|
|
||||||
|
|
||||||
RSpec.describe Devops::Model::Project, type: :model do
|
RSpec.describe Devops::Model::Project, type: :model do
|
||||||
let(:project) { build(:project) }
|
let(:project) { build(:project) }
|
||||||
include_context 'stubbed calls to connector in env validators'
|
|
||||||
|
|
||||||
describe 'validation rules:' do
|
describe 'validation rules:', stubbed_env_validators: true, stubbed_logger: true do
|
||||||
include_examples 'field type validation', :id, :not_nil, :non_empty_string
|
include_examples 'field type validation', :id, :not_nil, :non_empty_string
|
||||||
include_examples 'field type validation', :deploy_envs, :not_nil, :non_empty_array
|
include_examples 'field type validation', :deploy_envs, :not_nil, :non_empty_array
|
||||||
include_examples 'field type validation', :description, :maybe_nil, :maybe_empty_string
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#add_deploy_env', stub_logger: true do
|
describe '#add_deploy_env', stubbed_logger: true do
|
||||||
let(:env) {build(:deploy_env_ec2)}
|
let(:env) {build(:deploy_env_ec2)}
|
||||||
subject { project.add_deploy_env(env) }
|
subject { project.add_deploy_env(env) }
|
||||||
before do
|
before do
|
||||||
@ -235,9 +233,9 @@ RSpec.describe Devops::Model::Project, type: :model do
|
|||||||
end
|
end
|
||||||
|
|
||||||
describe '#delete_deploy_env' do
|
describe '#delete_deploy_env' do
|
||||||
it 'removes env' do
|
it 'removes env', stubbed_connector: true do
|
||||||
allow(Devops::Db).to receive_message_chain('connector.remove_deploy_env_from_project')
|
allow(stubbed_connector).to receive(:remove_deploy_env_from_project)
|
||||||
expect(Devops::Db).to receive_message_chain('connector.remove_deploy_env_from_project').with(project.id, 'foo')
|
expect(stubbed_connector).to receive(:remove_deploy_env_from_project).with(project.id, 'foo')
|
||||||
project.delete_deploy_env('foo')
|
project.delete_deploy_env('foo')
|
||||||
expect(project.deploy_envs).to match_array []
|
expect(project.deploy_envs).to match_array []
|
||||||
end
|
end
|
||||||
@ -271,4 +269,93 @@ RSpec.describe Devops::Model::Project, type: :model do
|
|||||||
end
|
end
|
||||||
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
|
end
|
||||||
@ -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
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
# не пытайся выделить в shared_specs, фигня выйдет
|
||||||
|
RSpec.describe Devops::Model::OpenstackProviderAccount, type: :model do
|
||||||
|
let(:provider_account) { build(:openstack_provider_account) }
|
||||||
|
|
||||||
|
it "should not validate access_key_id", stubbed_logger: true do
|
||||||
|
pending "waiting for mongoid support to be finished"
|
||||||
|
fields = described_class.field_validators.values.flatten.flatten.map{|t| t[:field]}
|
||||||
|
expect(fields).not_to include(:access_key_id, :secret_access_key)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
@ -11,7 +11,7 @@ RSpec.describe Devops::Model::Server, type: :model do
|
|||||||
expect(server).to be_valid
|
expect(server).to be_valid
|
||||||
end
|
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', :id, :not_nil, :non_empty_string
|
||||||
include_examples 'field type validation', :provider, :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
|
include_examples 'field type validation', :remote_user, :not_nil, :non_empty_string
|
||||||
|
|||||||
@ -11,7 +11,7 @@ RSpec.describe Devops::Model::StackEc2, type: :model do
|
|||||||
expect(build(:stack_ec2)).to be_valid
|
expect(build(:stack_ec2)).to be_valid
|
||||||
end
|
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', :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', :project, :not_nil, :non_empty_string, :field_validator
|
||||||
include_examples 'field type validation', :deploy_env, :not_nil, :non_empty_string, :field_validator
|
include_examples 'field type validation', :deploy_env, :not_nil, :non_empty_string, :field_validator
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
require 'db/mongo/models/stack_template/stack_template_ec2'
|
require 'db/mongo/models/stack_template/stack_template_ec2'
|
||||||
|
require_relative 'shared_stack_template_specs'
|
||||||
|
|
||||||
RSpec.describe Devops::Model::StackTemplateEc2, type: :model do
|
RSpec.describe Devops::Model::StackTemplateEc2, type: :model do
|
||||||
let(:stack_template) { build(:stack_template_ec2) }
|
let(:stack_template) { build(:stack_template_ec2) }
|
||||||
@ -6,8 +7,20 @@ RSpec.describe Devops::Model::StackTemplateEc2, type: :model do
|
|||||||
before do
|
before do
|
||||||
allow(Provider::ProviderFactory).to receive(:providers).and_return(%w(ec2))
|
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.validate_stack_template') { true }
|
||||||
|
allow_any_instance_of(Devops::Model::StackTemplateEc2).to receive_message_chain('provider_instance.store_stack_template') { {'url' => nil} }
|
||||||
end
|
end
|
||||||
|
|
||||||
it_behaves_like 'stack template'
|
it_behaves_like 'stack template'
|
||||||
|
|
||||||
|
it 'uploads file to S3' do
|
||||||
|
expect_any_instance_of(Devops::Model::StackTemplateEc2).to receive_message_chain('provider_instance.store_stack_template')
|
||||||
|
params = {
|
||||||
|
'id' => 'foo',
|
||||||
|
'template_body' => '{}',
|
||||||
|
'owner' => 'root',
|
||||||
|
'provider' => 'ec2'
|
||||||
|
}
|
||||||
|
expect(described_class.create(params)).to be_an_instance_of(described_class)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -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
|
||||||
6
devops-service/spec/shared_contexts/stubbed_connector.rb
Normal file
6
devops-service/spec/shared_contexts/stubbed_connector.rb
Normal file
@ -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
|
||||||
@ -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
|
before do
|
||||||
allow(Provider::ProviderFactory).to receive(:providers).and_return(%w(ec2 openstack))
|
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'])
|
allow_any_instance_of(Validators::Helpers::Users).to receive(:available_users).and_return(['root'])
|
||||||
@ -11,11 +11,3 @@ RSpec.shared_context 'stubbed calls to connector in env validators' do
|
|||||||
allow_any_instance_of(Validators::FieldValidator::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
allow_any_instance_of(Validators::FieldValidator::Image).to receive(:available_images).and_return([{'id' => 'image'}])
|
||||||
end
|
end
|
||||||
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
|
|
||||||
7
devops-service/spec/shared_contexts/stubbed_logger.rb
Normal file
7
devops-service/spec/shared_contexts/stubbed_logger.rb
Normal file
@ -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
|
||||||
@ -2,9 +2,10 @@ def set_tester_connector(klass)
|
|||||||
define_method :tester_connector_class do
|
define_method :tester_connector_class do
|
||||||
klass
|
klass
|
||||||
end
|
end
|
||||||
|
include_context 'with tester connector'
|
||||||
end
|
end
|
||||||
|
|
||||||
RSpec.shared_context 'connectors' do
|
RSpec.shared_context 'with tester connector' do
|
||||||
before(:all) do
|
before(:all) do
|
||||||
@connector = described_class.new(SpecSupport.db)
|
@connector = described_class.new(SpecSupport.db)
|
||||||
@tester_connector = tester_connector_class.new
|
@tester_connector = tester_connector_class.new
|
||||||
@ -13,6 +13,7 @@ original_stdout = $stdout
|
|||||||
$stdout = File.open(File::NULL, "w")
|
$stdout = File.open(File::NULL, "w")
|
||||||
|
|
||||||
Dir[("./spec/support/**/*.rb")].each { |f| require f }
|
Dir[("./spec/support/**/*.rb")].each { |f| require f }
|
||||||
|
Dir[("./spec/shared_contexts/**/*.rb")].each { |f| require f }
|
||||||
|
|
||||||
# Factory girl configuration
|
# Factory girl configuration
|
||||||
FactoryGirl.define do
|
FactoryGirl.define do
|
||||||
|
|||||||
@ -5,7 +5,7 @@ module SpecSupport
|
|||||||
BLANK_FILE = File.join(ROOT, 'spec/support/blank_file')
|
BLANK_FILE = File.join(ROOT, 'spec/support/blank_file')
|
||||||
|
|
||||||
def self.db_params
|
def self.db_params
|
||||||
@db ||= begin
|
@db_params ||= begin
|
||||||
conf = config['mongo']
|
conf = config['mongo']
|
||||||
db_name = conf.fetch(:db)
|
db_name = conf.fetch(:db)
|
||||||
[db_name, conf[:host], conf[:port], conf[:user], conf[:password]]
|
[db_name, conf[:host], conf[:port], conf[:user], conf[:password]]
|
||||||
|
|||||||
@ -94,7 +94,6 @@ templates = {
|
|||||||
|
|
||||||
#list
|
#list
|
||||||
"templates/api_v2/00_list/flavor.feature.erb" => "features/api_v2/00_list/flavor.feature",
|
"templates/api_v2/00_list/flavor.feature.erb" => "features/api_v2/00_list/flavor.feature",
|
||||||
"templates/api_v2/00_list/stack_preset.feature.erb" => "features/api_v2/00_list/stack_preset.feature",
|
|
||||||
"templates/api_v2/00_list/00_network.feature.erb" => "features/api_v2/00_list/00_network.feature",
|
"templates/api_v2/00_list/00_network.feature.erb" => "features/api_v2/00_list/00_network.feature",
|
||||||
"templates/api_v2/00_list/10_user.feature.erb" => "features/api_v2/00_list/10_user.feature",
|
"templates/api_v2/00_list/10_user.feature.erb" => "features/api_v2/00_list/10_user.feature",
|
||||||
"templates/api_v2/00_list/10_group.feature.erb" => "features/api_v2/00_list/10_group.feature",
|
"templates/api_v2/00_list/10_group.feature.erb" => "features/api_v2/00_list/10_group.feature",
|
||||||
|
|||||||
@ -1,28 +0,0 @@
|
|||||||
@stack_preset @list
|
|
||||||
Feature: stack template preset list
|
|
||||||
|
|
||||||
Scenario: Get list of all stack template presets
|
|
||||||
When I send GET '/v2.0/stack_presets' query
|
|
||||||
Then response should be '200'
|
|
||||||
And the Content-Type header should include 'application/json'
|
|
||||||
And the JSON response should be an array
|
|
||||||
And response array should contains elements like:
|
|
||||||
"""
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"id": "test",
|
|
||||||
"template_body": "long body"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
"""
|
|
||||||
|
|
||||||
Scenario: Get information about particular stack template preset
|
|
||||||
When I send GET '/v2.0/stack_presets/postgres_cluster' query
|
|
||||||
Then response should be '200'
|
|
||||||
And the Content-Type header should include 'application/json'
|
|
||||||
And response should be JSON object like:
|
|
||||||
"""
|
|
||||||
{
|
|
||||||
"id": "postgres_cluster", "template_body": "long body"
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
Loading…
Reference in New Issue
Block a user