Merge branch 'devops_3_achuchkalov' of git.stu.neva.ru:cloudtechlab/devops-service into devops_3_achuchkalov

This commit is contained in:
Anton Chuchkalov 2015-07-17 12:25:11 +03:00
commit fa4b1089b6
39 changed files with 405 additions and 242 deletions

View File

@ -47,9 +47,9 @@ class HandlerFactory
when "stack_template" when "stack_template"
require "devops-client/handler/stack_template" require "devops-client/handler/stack_template"
StackTemplate StackTemplate
when "stack_template_preset" when "stack_preset"
require "devops-client/handler/stack_template_preset" require "devops-client/handler/stack_preset"
StackTemplatePreset StackPreset
when "stack" when "stack"
require "devops-client/handler/stack" require "devops-client/handler/stack"
Stack Stack

View File

@ -13,8 +13,8 @@ module Outputtable
@outputter ||= outputter_class.new(data_to_output, options, additional_output_options) @outputter ||= outputter_class.new(data_to_output, options, additional_output_options)
end end
def output def output(preferred_format=nil)
outputter.output outputter.output(preferred_format)
end end

View File

@ -13,7 +13,6 @@ class Stack < 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
@ -26,6 +25,12 @@ class Stack < Handler
create_handler create_handler
when :delete when :delete
delete_handler delete_handler
when :sync
sync_handler
output
when :resources
resources_handler
output('json')
end end
end end
@ -63,6 +68,30 @@ class Stack < Handler
@show = get "/stack/#{stack_id}" @show = get "/stack/#{stack_id}"
end end
def sync_handler
stack_id = @args[2]
r = inspect_parameters(@options_parser.sync_params, stack_id)
unless r.nil?
@options_parser.invalid_sync_command
abort(r)
end
@show = post "/stack/#{stack_id}/sync_details"
end
def resources_handler
stack_id, resource_id = @args[2], @args[3]
r = inspect_parameters(@options_parser.sync_params, stack_id)
unless r.nil?
@options_parser.invalid_sync_command
abort(r)
end
if resource_id
@list = get "/stack/#{stack_id}/resources/#{resource_id}"
else
@list = get "/stack/#{stack_id}/resources"
end
end
def delete_handler def delete_handler
stack_id = @args[2] stack_id = @args[2]
r = inspect_parameters(@options_parser.delete_params, stack_id) r = inspect_parameters(@options_parser.delete_params, stack_id)

View File

@ -1,15 +1,14 @@
require "devops-client/handler/handler" require "devops-client/handler/handler"
require "devops-client/options/stack_template_preset_options" require "devops-client/options/stack_preset_options"
require "devops-client/output/stack_template_preset" require "devops-client/output/stack_preset"
# require 'devops-client/helpers/select_available'
class StackTemplatePreset < Handler class StackPreset < Handler
output_with Output::StackTemplatePreset output_with Output::StackPreset
def initialize(host, def_options={}) def initialize(host, def_options={})
@host, @options = host, def_options @host, @options = host, def_options
@options_parser = StackTemplatePresetOptions.new(ARGV, def_options) @options_parser = StackPresetOptions.new(ARGV, def_options)
end end
def handle def handle
@ -21,8 +20,8 @@ class StackTemplatePreset < Handler
when :show when :show
show_handler show_handler
output output
when :build when :apply
build_handler apply_handler
end end
end end
@ -32,29 +31,31 @@ class StackTemplatePreset < Handler
@options_parser.invalid_show_command @options_parser.invalid_show_command
abort(wrong_params) abort(wrong_params)
end end
@show = get "/stack_template_presets/#{@args[2]}" @show = get "/stack_presets/#{@args[2]}"
end end
def list_handler def list_handler
@list = get('/stack_template_presets') @list = get('/stack_presets')
end end
def build_handler def apply_handler
wrong_params = inspect_parameters(@options_parser.build_params, @args[2]) wrong_params = inspect_parameters(@options_parser.apply_params, @args[2])
if wrong_params if wrong_params
@options_parser.invalid_build_command @options_parser.invalid_apply_command
abort(wrong_params) abort(wrong_params)
end end
params = {} params = {}
params[:id] = @args[2] params[:id] = @args[2]
params[:provider] = options[:provider] || resources_selector.select_available_provider params[:provider] = options[:provider] || resources_selector.select_available_provider
params[:stack] = options[:stack] || enter_parameter(I18n.t('handler.stack_template_preset.create.stack')) params[:stack] = options[:stack] || enter_parameter(I18n.t('handler.stack_preset.create.stack'))
params[:project] = options[:project] || resources_selector.select_available_project
params[:deploy_env] = options[:deploy_env] || enter_parameter(I18n.t('handler.stack.create.deploy_env'))
filepath = options[:parameters_file] || enter_parameter(I18n.t('handler.stack_template_preset.create.parameters_file')) filepath = options[:parameters_file] || enter_parameter(I18n.t('handler.stack_preset.create.parameters_file'))
params[:parameters] = JSON.parse(File.read(filepath)) params[:parameters] = JSON.parse(File.read(filepath))
result = post_body("/stack_template_presets/#{params[:id]}/build_stack_template", JSON.pretty_generate(params)) result = post_body("/stack_presets/#{params[:id]}/apply", JSON.pretty_generate(params))
end end
end end

View File

@ -2,7 +2,7 @@ require "devops-client/options/common_options"
class StackOptions < CommonOptions class StackOptions < CommonOptions
commands :create, :delete, :list, :show commands :create, :delete, :list, :show, :sync, :resources
def initialize args, def_options def initialize args, def_options
super(args, def_options) super(args, def_options)
@ -11,6 +11,8 @@ class StackOptions < CommonOptions
self.list_params = ["[provider]", "[ec2|openstack]"] self.list_params = ["[provider]", "[ec2|openstack]"]
self.show_params = ["STACK"] self.show_params = ["STACK"]
self.delete_params = ["STACK"] self.delete_params = ["STACK"]
self.sync_params = ["STACK"]
self.resources_params = ["STACK"]
end end
def create_options def create_options

View File

@ -0,0 +1,33 @@
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(:stack, 'stack_preset')
parser.recognize_option_value(:parameters_file, 'stack_preset')
end
end
extend_options_method :list_options do |options|
if args[2]
options[:given_provider] = args[2]
end
end
end

View File

@ -1,33 +0,0 @@
require "devops-client/options/common_options"
class StackTemplatePresetOptions < CommonOptions
commands :list, :show, :build
def initialize args, def_options
super(args, def_options)
self.header = I18n.t("headers.stack_template_preset")
self.banner_header = "stack_template_preset"
self.list_params = ["[provider]", "[ec2|openstack]"]
self.show_params = ["STACK"]
self.build_params = ["PRESET"]
end
def build_options
self.options do |parser, options|
parser.banner << self.build_banner
parser.recognize_option_value(:provider, 'stack_template_preset')
parser.recognize_option_value(:stack, 'stack_template_preset')
parser.recognize_option_value(:parameters_file, 'stack_template_preset')
end
end
extend_options_method :list_options do |options|
if args[2]
options[:given_provider] = args[2]
end
end
end

View File

@ -18,8 +18,9 @@ module Output
@data, @options, @additional_options = data_to_output, command_line_options, additional_options @data, @options, @additional_options = data_to_output, command_line_options, additional_options
end end
def output def output(format = nil)
case options[:format] format ||= options[:format]
case format
when CommonOptions::TABLE_FORMAT when CommonOptions::TABLE_FORMAT
table table
when CommonOptions::JSON_FORMAT when CommonOptions::JSON_FORMAT

View File

@ -10,6 +10,7 @@ module Output
title = I18n.t("output.title.stack.list") title = I18n.t("output.title.stack.list")
headers, rows = create_list headers, rows = create_list
else else
puts 'Details are not displayed in table view'
title = I18n.t("output.title.stack.show", id: @data["id"]) title = I18n.t("output.title.stack.show", id: @data["id"])
headers, rows = create_show headers, rows = create_show
end end
@ -30,14 +31,14 @@ module Output
def create_list def create_list
abort(I18n.t("output.not_found.stack.list")) if @data.empty? abort(I18n.t("output.not_found.stack.list")) if @data.empty?
fields_to_output = %w(id deploy_env stack_template) fields_to_output = %w(id deploy_env stack_template cloud_stack_id stack_status)
fields_to_output << 'provider' unless provider_given? fields_to_output << 'provider' unless provider_given?
headers_and_rows(@data, fields_to_output) headers_and_rows(@data, fields_to_output)
end end
def create_show def create_show
headers_and_rows([@data], %w(id deploy_env stack_template cloud_stack_id)) headers_and_rows([@data], %w(id deploy_env stack_template cloud_stack_id stack_status))
end end
end end

View File

@ -1,11 +1,11 @@
require "devops-client/output/base" require "devops-client/output/base"
module Output module Output
class StackTemplatePreset < Base class StackPreset < Base
def table def table
if outputting_list? if outputting_list?
title = I18n.t("output.title.stack_template_preset.list") title = I18n.t("output.title.stack_preset.list")
headers, rows = create_list headers, rows = create_list
create_table headers, rows, title, with_num? create_table headers, rows, title, with_num?
else else
@ -29,7 +29,7 @@ module Output
private private
def create_list def create_list
abort(I18n.t("output.not_found.stack_template_preset.list")) if @data.empty? abort(I18n.t("output.not_found.stack_preset.list")) if @data.empty?
fields_to_output = %w(id) fields_to_output = %w(id)

View File

@ -43,7 +43,7 @@ en:
user: "User" user: "User"
stack: "Stack" stack: "Stack"
stack_template: "Stack template" stack_template: "Stack template"
stack_template_preset: "Stack template preset" stack_preset: "Stack template preset"
handler: handler:
flavor: flavor:
list: list:
@ -118,10 +118,10 @@ 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_template_preset: stack_preset:
create: create:
parameters_file: 'Path to file with JSON parameters: ' parameters_file: 'Path to file with JSON parameters: '
stack_template: 'Name of stack template to build: ' 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: "
@ -196,6 +196,7 @@ en:
template_preset_body: "Template preset body" template_preset_body: "Template preset body"
stack_template: "Stack Template" stack_template: "Stack Template"
cloud_stack_id: "Cloud Stack id" cloud_stack_id: "Cloud Stack id"
stack_status: Stack status
title: title:
flavor: flavor:
list: "Flavors" list: "Flavors"
@ -234,7 +235,7 @@ en:
stack_template: stack_template:
list: "Stack Templates" list: "Stack Templates"
show: "Stack Template" show: "Stack Template"
stack_template_preset: stack_preset:
list: "Stack Template Presets" list: "Stack Template Presets"
show: "Stack Template Preset" show: "Stack Template Preset"
stack: stack:
@ -271,7 +272,7 @@ 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_template_preset: stack_preset:
list: "No stack template presets found" list: "No stack template presets found"
show: "There isn't such stack template preset" show: "There isn't such stack template preset"
stack: stack:
@ -377,7 +378,7 @@ en:
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_template_preset: stack_preset:
parameters_file: Path to file with JSON parameters parameters_file: Path to file with JSON parameters
stack: 'Name of stack to build: ' stack: 'Name of stack to build: '
provider: Stack provider provider: Stack provider

View File

@ -21,7 +21,7 @@ module Devops
require "routes/v2.0/handlers/server" require "routes/v2.0/handlers/server"
require "routes/v2.0/handlers/stack" require "routes/v2.0/handlers/stack"
require "routes/v2.0/handlers/stack_template" require "routes/v2.0/handlers/stack_template"
require "routes/v2.0/stack_template_presets" require "routes/v2.0/stack_presets"
require "routes/v2.0/handlers/report" require "routes/v2.0/handlers/report"
require 'lib/stubber' require 'lib/stubber'
@ -39,7 +39,7 @@ module Devops
Devops::Api2.settings.mongo.create_root_user Devops::Api2.settings.mongo.create_root_user
::Provider::ProviderFactory.init(config) ::Provider::ProviderFactory.init(config)
Stubber.stub_providers! if config[:stub_classes] Stubber.stub_providers!(config[:stub_providers])
end end
def routes def routes
@ -60,7 +60,7 @@ module Devops
require "routes/v2.0/bootstrap_templates" require "routes/v2.0/bootstrap_templates"
require "routes/v2.0/stack" require "routes/v2.0/stack"
require "routes/v2.0/stack_template" require "routes/v2.0/stack_template"
require "routes/v2.0/handlers/stack_template_preset" require "routes/v2.0/handlers/stack_preset"
require "routes/v2.0/report" require "routes/v2.0/report"
routes = Devops::Version2_0::Routes.constants.collect{|s| Devops::Version2_0::Routes.const_get(s)}.select {|const| const.class == Module} routes = Devops::Version2_0::Routes.constants.collect{|s| Devops::Version2_0::Routes.const_get(s)}.select {|const| const.class == Module}

View File

@ -40,4 +40,7 @@ config[:static_ssh_key] = "ssh_key" # or nil
config[:static_certificate] = "/path/to/.ssh/static.pem" config[:static_certificate] = "/path/to/.ssh/static.pem"
config[:debug] = true config[:debug] = true
config[:stub_classes] = true
# set it to :all or [:ec2] to stub calls to selected providers
# or to false to disable stubbing
config[:stub_providers] = false

View File

@ -4,9 +4,8 @@ module Connectors
module Helpers module Helpers
module UpdateCommand module UpdateCommand
# when included, this module adds method #update and alias for it. # this module adds methods #update and "#{resource_name}_update" (they are synonyms).
# Alias name depends on base class name. # We need second method name to forward methods from MongoConnector to resources connectors.
# We need this alias to forward methods from MongoConnector to resources connectors.
def self.included(base) def self.included(base)
resource_name = StringHelper.underscore_class(base) resource_name = StringHelper.underscore_class(base)

View File

@ -3,7 +3,8 @@ module Connectors
include Helpers::InsertCommand, include Helpers::InsertCommand,
Helpers::ShowCommand, Helpers::ShowCommand,
Helpers::ListCommand, Helpers::ListCommand,
Helpers::DeleteCommand Helpers::DeleteCommand,
Helpers::UpdateCommand
def initialize(db) def initialize(db)
self.collection = db.collection('stacks') self.collection = db.collection('stacks')

View File

@ -3,7 +3,8 @@ module Connectors
include Helpers::InsertCommand, include Helpers::InsertCommand,
Helpers::ShowCommand, Helpers::ShowCommand,
Helpers::ListCommand, Helpers::ListCommand,
Helpers::DeleteCommand Helpers::DeleteCommand,
Helpers::UpdateCommand
def initialize(db) def initialize(db)
self.collection = db.collection('stack_templates') self.collection = db.collection('stack_templates')

View File

@ -136,7 +136,7 @@ module Devops
def to_hash_without_id def to_hash_without_id
h = {} h = {}
h["deploy_envs"] = self.deploy_envs.map {|e| e.to_hash} unless self.deploy_envs.nil? h["deploy_envs"] = self.deploy_envs.map {|e| e.to_hash} unless self.deploy_envs.nil?
h["archived"] = self.archived h["archived"] = self.archived if self.archived
h["description"] = self.description h["description"] = self.description
if self.multi? if self.multi?
h["type"] = MULTI_TYPE h["type"] = MULTI_TYPE

View File

@ -2,26 +2,27 @@ module Devops
module Model module Model
class StackBase < MongoModel class StackBase < MongoModel
attr_accessor :id, :project, :deploy_env, :stack_template, :cloud_stack_id, :provider, :parameters, :template_body attr_accessor :id, :project, :deploy_env, :stack_template,
:cloud_stack_id, :provider, :parameters, :details
types id: {type: String, empty: false}, types id: {type: String, empty: false},
provider: {type: String, empty: false}, provider: {type: String, empty: false},
project: {type: String, empty: true}, project: {type: String},
deploy_env: {type: String, empty: true}, deploy_env: {type: String},
stack_template: {type: String, empty: true}, stack_template: {type: String, empty: false},
template_body: {type: String, empty: true} cloud_stack_id: {type: String, nil: true}
# cloud_stack_id: {type: String, empty: true} # details: {type: String, nil: true}
# TODO: add parameters Hash
def initialize attrs={} def initialize attrs={}
self.provider = self.class.provider
self.id = attrs['id'] self.id = attrs['id']
self.provider = attrs['provider']
self.project = attrs['project'] self.project = attrs['project']
self.deploy_env = attrs['deploy_env'] self.deploy_env = attrs['deploy_env']
self.stack_template = attrs['stack_template'] self.stack_template = attrs['stack_template']
self.template_body = attrs['template_body'] self.cloud_stack_id = attrs['cloud_stack_id']
# self.cloud_stack_id = attrs['cloud_stack_id']
self.parameters = attrs['parameters'] self.parameters = attrs['parameters']
self.details = attrs['details']
self self
end end
@ -32,40 +33,63 @@ module Devops
deploy_env: deploy_env, deploy_env: deploy_env,
stack_template: stack_template, stack_template: stack_template,
cloud_stack_id: cloud_stack_id, cloud_stack_id: cloud_stack_id,
parameters: parameters parameters: parameters,
details: details,
stack_status: stack_status
} }
end end
# attrs should include:
# - id (String)
# - provider (String)
# - deploy_env (String)
# - stack_template (String)
def self.create(attrs)
model = new(attrs)
model.create_stack_in_cloud!
model
end
def self.build_from_bson(attrs)
attrs['id'] = attrs["_id"]
self.new(attrs)
end
def create_stack_in_cloud! def create_stack_in_cloud!
raise 'override me' begin
self.cloud_stack_id = provider_class.create_stack(self)
rescue ProviderErrors::NameConflict
raise InvalidRecord.new "Duplicate key error: stack with name '#{id}' already exists in cloud"
end
end end
def delete_stack_in_cloud! def delete_stack_in_cloud!
raise 'override me' provider_class.delete_stack(self)
end
def sync_details!
self.details = provider_class.stack_details(self)
end
def resources
provider_class.stack_resources(self)
end
def resource(resource_id)
provider_class.stack_resource(self, resource_id)
end end
# if not set in constructor, assume stack was created via stack_template.
# It is need to support presets.
# TODO: refactore it.
def template_body def template_body
@template_body ||= Devops::Api2.settings.mongo.stack_template(stack_template).template_body Devops::Api2.settings.mongo.stack_template(stack_template).template_body
end
class << self
attr_accessor :provider
# attrs should include:
# - id (String)
# - deploy_env (String)
# - stack_template (String)
def create(attrs)
model = new(attrs)
model.create_stack_in_cloud!
model
end
def build_from_bson(attrs)
attrs['id'] = attrs["_id"]
self.new(attrs)
end
end
private
def provider_class
Provider::ProviderFactory.get(provider)
end end
end end

View File

@ -1,12 +1,7 @@
module Devops module Devops
module Model module Model
class StackEc2 < StackBase class StackEc2 < StackBase
self.provider = 'ec2'
def create_stack_in_cloud!
# create stack in AWS
self.cloud_stack_id = 'arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83'
end
end end
end end
end end

View File

@ -1,21 +1,11 @@
module Devops module Devops
module Model module Model
class StackOpenstack < StackBase class StackOpenstack < StackBase
self.provider = 'openstack'
def create_stack_in_cloud! def stack_status
begin details[:stack_status] if details
provider = Provider::ProviderFactory.get('openstack')
self.cloud_stack_id = provider.create_stack(self)
rescue ProviderErrors::NameConflict
raise InvalidRecord.new "Duplicate key error: stack with name '#{self.id}' already exists in cloud"
end
end end
def delete_stack_in_cloud!
provider = Provider::ProviderFactory.get('openstack')
provider.delete_stack(self)
end
end end
end end
end end

View File

@ -12,8 +12,8 @@ class MongoConnector
delegate( delegate(
[:images, :image, :image_insert, :image_delete, :image_update] => :images_connector, [:images, :image, :image_insert, :image_delete, :image_update] => :images_connector,
[:stack_templates, :stack_template, :stack_template_insert, :stack_template_delete] => :stack_templates_connector, [:stack_templates, :stack_template, :stack_template_insert, :stack_template_delete, :stack_template_update] => :stack_templates_connector,
[:stacks, :stack, :stack_insert, :stack_delete] => :stacks_connector, [:stacks, :stack, :stack_insert, :stack_delete, :stack_update] => :stacks_connector,
[:available_images, :add_available_images, :delete_available_images] => :filters_connector, [:available_images, :add_available_images, :delete_available_images] => :filters_connector,
[:project, :projects_all, :projects, :project_names_with_envs, [:project, :projects_all, :projects, :project_names_with_envs,
:projects_by_image, :projects_by_user, :project_insert, :project_update, :projects_by_image, :projects_by_user, :project_insert, :project_update,

View File

@ -0,0 +1,76 @@
require 'lib/string_helper'
require 'db/mongo/models/stack_template/stack_template_factory'
module Devops
module StackPresets
class Base
def id
StringHelper.underscore_class(self.class)
end
def to_hash
{id: id, template_body: template_body}
end
# attrs should include
# 'provider'
# 'stack'
# 'parameters'
# 'project'
# 'deploy_env'
def create_stack_from_preset(attrs)
provider = attrs.fetch('provider')
template_name = find_or_create_stack_template!(provider)
stack_attrs = attrs.merge(
'id' => attrs['stack'],
'stack_template' => template_name
)
Model::StackFactory.create(provider, stack_attrs)
end
def template_body
@template_body ||= File.read("lib/stack_presets/#{id}.#{template_file_extension}")
end
# some templates may be YAML files
def template_file_extension
:json
end
private
def find_or_create_stack_template!(provider)
name = stack_template_name(provider)
begin
stack_template = Devops::Api2.settings.mongo.stack_template(name)
update_stack_template(stack_template) if stack_template.template_body != template_body
rescue RecordNotFound
create_stack_template(provider)
end
name
end
def stack_template_name(provider)
"#{id}_#{provider}_preset"
end
def create_stack_template(provider)
stack_template = Model::StackTemplateFactory.create(provider, {
'id' => stack_template_name(provider),
'provider' => provider,
'template_body' => template_body
})
Devops::Api2.settings.mongo.stack_template_insert(stack_template)
end
def update_stack_template(stack_template)
stack_template.template_body = template_body
Devops::Api2.settings.mongo.stack_template_update(stack_template)
end
end
end
end

View File

@ -2,15 +2,15 @@ require_relative 'base'
require_relative 'postgres_cluster' require_relative 'postgres_cluster'
require_relative 'preset_not_found' require_relative 'preset_not_found'
class Devops::StackTemplatePresetsFactory class Devops::StackPresetsFactory
# find all classes in Devops::StackTemplatePresets modules excluding Base and factory. # 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::StackTemplatePresets module. # This list can be extended in external gems via defining new classes in Devops::StackPresets module.
def self.list def self.list
@list ||= Devops::StackTemplatePresets.constants.select do |class_name| @list ||= Devops::StackPresets.constants.select do |class_name|
class_name != :Base class_name != :Base
end.map do |class_name| end.map do |class_name|
Devops::StackTemplatePresets.const_get(class_name).new Devops::StackPresets.const_get(class_name).new
end end
end end

View File

@ -1,4 +1,4 @@
module Devops::StackTemplatePresets module Devops::StackPresets
class PostgresCluster < Base class PostgresCluster < Base
def template_file_extension def template_file_extension
:yml :yml

View File

@ -13,5 +13,7 @@ resources:
type: OS::Nova::Server type: OS::Nova::Server
properties: properties:
key_name: { get_param: key_name } key_name: { get_param: key_name }
image: 227f4be7-be1c-498d-ab88-54f8b5df249f image: 5f4020a1-b6ab-47e4-a0ed-de4324a17c3a
flavor: m1.small flavor: m1.micro
networks:
- network: devops-net-1

View File

@ -1,38 +0,0 @@
require 'lib/string_helper'
require 'db/mongo/models/stack_template/stack_template_factory'
module Devops
module StackTemplatePresets
class Base
def id
StringHelper.underscore_class(self.class)
end
def to_hash
{id: id, template_preset_body: template_preset_body}
end
def create_stack_from_preset(provider, stack_id, parameters)
stack_attrs = {
'id' => stack_id,
'provider' => provider,
'parameters' => parameters,
'template_body' => template_preset_body
}
Model::StackFactory.create(provider, stack_attrs)
end
def template_preset_body
file_name = File.join("lib/stack_template_presets/#{id}.#{template_file_extension}")
File.read(file_name)
end
# some templates may be YAML files
def template_file_extension
:json
end
end
end
end

View File

@ -1,5 +1,11 @@
module Stubber module Stubber
def self.stub_providers! def self.stub_providers!(providers)
Dir["tests/stubs/providers/*.rb"].each {|file| require file } return unless providers
providers = [:ec2, :openstack] if providers == :all
providers.each do |provider|
next unless [:ec2, :openstack].include?(provider)
require "tests/stubs/providers/#{provider}.rb"
end
end end
end end

View File

@ -193,11 +193,12 @@ module Provider
def create_stack(stack) def create_stack(stack)
begin begin
response = orchestration.create_stack(stack.id, { response = orchestration.create_stack(
stack_name: stack.id,
template: stack.template_body, template: stack.template_body,
tenant_id: connection_options[:openstack_tenant], tenant_id: connection_options[:openstack_tenant],
parameters: stack.parameters parameters: stack.parameters
}) )
response[:body]['stack']['id'] response[:body]['stack']['id']
rescue Excon::Errors::Conflict => e rescue Excon::Errors::Conflict => e
raise ProviderErrors::NameConflict raise ProviderErrors::NameConflict
@ -205,7 +206,19 @@ module Provider
end end
def delete_stack(stack) def delete_stack(stack)
orchestration.delete_stack(stack.id, stack.cloud_stack_id) fog_stack(stack).destroy
end
def stack_details(stack)
fog_stack(stack).details.attributes
end
def stack_resources(stack)
fog_stack(stack).resources
end
def stack_resource(stack, resource_id)
fog_stack(stack).resources.get(resource_id)
end end
private private
@ -233,5 +246,9 @@ module Provider
@connection ||= Fog::Orchestration.new(connection_options) @connection ||= Fog::Orchestration.new(connection_options)
end end
def fog_stack(stack)
orchestration.stacks.get(stack.id, stack.cloud_stack_id)
end
end end
end end

View File

@ -54,6 +54,34 @@ module Devops
} }
end end
def self.sync_details
lambda {
check_privileges("stack", "w")
stack = settings.mongo.stack(params[:stack_id])
stack.sync_details!
settings.mongo.stack_update(stack)
json stack.to_hash
}
end
def self.resources
lambda {
check_privileges("stack", "r")
stack = settings.mongo.stack(params[:stack_id])
json stack.resources
}
end
def self.resource
lambda {
check_privileges("stack", "r")
stack = settings.mongo.stack(params[:stack_id])
json stack.resource(params[:resource_id])
}
end
end end
end end
end end

View File

@ -0,0 +1,41 @@
require 'json'
require 'lib/stack_presets/factory'
module Devops
module Version2_0
module Handler
class StackPreset
def self.get_presets
lambda {
# check_privileges("stack_presets", "r")
json Devops::StackPresetsFactory.list.map(&:to_hash)
}
end
def self.get_preset
lambda {
# check_privileges("stack_presets", "r")
json Devops::StackPresetsFactory.get(params['id']).to_hash
}
end
def self.apply
lambda {
# check_privileges("stack_presets", "r")
check_privileges('stack_template', 'w')
attrs = create_object_from_json_body
preset = Devops::StackPresetsFactory.get(attrs.fetch('id'))
stack = preset.create_stack_from_preset(attrs)
settings.mongo.stack_insert(stack)
create_response 'Created', stack.to_hash, 201
}
end
end
end
end
end

View File

@ -28,8 +28,8 @@ module Devops
attrs = create_object_from_json_body attrs = create_object_from_json_body
template_model = Model::StackTemplateFactory.create(attrs['provider'], attrs) template_model = Model::StackTemplateFactory.create(attrs['provider'], attrs)
settings.mongo.stack_template_insert(template_model) settings.mongo.stack_template_insert(template_model)
create_response 'Created', template_model.to_hash, 201 create_response 'Created', template_model.to_hash, 201
} }
end end

View File

@ -1,43 +0,0 @@
require 'json'
require 'lib/stack_template_presets/factory'
module Devops
module Version2_0
module Handler
class StackTemplatePreset
def self.get_presets
lambda {
# check_privileges("stack_template_presets", "r")
json Devops::StackTemplatePresetsFactory.list.map(&:to_hash)
}
end
def self.get_preset
lambda {
# check_privileges("stack_template_presets", "r")
json Devops::StackTemplatePresetsFactory.get(params['id']).to_hash
}
end
def self.build_stack_template
lambda {
# check_privileges("stack_template_presets", "r")
check_privileges('stack_template', 'w')
attrs = create_object_from_json_body
provider, stack_id, parameters = attrs.fetch('provider'), attrs.fetch('stack'), attrs.fetch('parameters')
preset = Devops::StackTemplatePresetsFactory.get(attrs.fetch('id'))
stack = preset.create_stack_from_preset(provider, stack_id, parameters)
create_response 'Created', stack.to_hash, 201
}
end
end
end
end
end

View File

@ -14,6 +14,12 @@ module Devops
app.post_with_headers "/stack", :headers => [:accept], &Devops::Version2_0::Handler::Stack.create_stack app.post_with_headers "/stack", :headers => [:accept], &Devops::Version2_0::Handler::Stack.create_stack
app.post_with_headers "/stack/:stack_id/sync_details", :headers => [:accept], &Devops::Version2_0::Handler::Stack.sync_details
app.get_with_headers "/stack/:stack_id/resources", :headers => [:accept], &Devops::Version2_0::Handler::Stack.resources
app.get_with_headers "/stack/:stack_id/resources/:resource_id", :headers => [:accept], &Devops::Version2_0::Handler::Stack.resource
hash = {} hash = {}
hash['GET'] = Devops::Version2_0::Handler::Stack.get_stack hash['GET'] = Devops::Version2_0::Handler::Stack.get_stack

View File

@ -1,10 +1,10 @@
module Devops module Devops
module Version2_0 module Version2_0
module Routes module Routes
module StackTemplatePresetRoutes module StackPresetRoutes
def self.registered(app) def self.registered(app)
# Get list of available stack_template_presets # Get list of available stack_presets
# #
# * *Request* # * *Request*
# - method : GET # - method : GET
@ -14,10 +14,10 @@ module Devops
# * *Returns* : array of hashes # * *Returns* : array of hashes
# [ {id: 'preset id', template_preset_body: 'long body'} ] # [ {id: 'preset id', template_preset_body: 'long body'} ]
# #
app.get_with_headers "/stack_template_presets", :headers => [:accept], &Devops::Version2_0::Handler::StackTemplatePreset.get_presets app.get_with_headers "/stack_presets", :headers => [:accept], &Devops::Version2_0::Handler::StackPreset.get_presets
# Get information about stack_template_preset # Get information about stack_preset
# #
# * *Request* # * *Request*
# - method : GET # - method : GET
@ -27,7 +27,7 @@ module Devops
# * *Returns* : hash # * *Returns* : hash
# {id: 'preset id', template_preset_body: 'long body'} # {id: 'preset id', template_preset_body: 'long body'}
# #
app.get_with_headers "/stack_template_presets/:id", :headers => [:accept], &Devops::Version2_0::Handler::StackTemplatePreset.get_preset app.get_with_headers "/stack_presets/:id", :headers => [:accept], &Devops::Version2_0::Handler::StackPreset.get_preset
# Build stack template from preset # Build stack template from preset
@ -38,7 +38,7 @@ module Devops
# - Accept: application/json # - Accept: application/json
# - params : # - params :
# - provider: string # - provider: string
# - stack_template_id: id of stack template to create # - stack_id: id of stack template to create
# - template_attrs: hash with template attributes # - template_attrs: hash with template attributes
# #
# TODO: not stack template, but stack itself # TODO: not stack template, but stack itself
@ -50,7 +50,7 @@ module Devops
# template_body: 'long body' # template_body: 'long body'
# } # }
# #
app.post_with_headers "/stack_template_presets/:id/build_stack_template", :headers => [:accept], &Devops::Version2_0::Handler::StackTemplatePreset.build_stack_template app.post_with_headers "/stack_presets/:id/apply", :headers => [:accept], &Devops::Version2_0::Handler::StackPreset.apply
puts "Stack template presets routes initialized" puts "Stack template presets routes initialized"
end end

View File

@ -77,7 +77,7 @@ 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_template_preset.feature.erb" => "features/api_v2/00_list/stack_template_preset.feature", "templates/api_v2/00_list/stack_preset.feature.erb" => "features/api_v2/00_list/stack_preset.feature",
"templates/api_v2/00_list/10_user.feature.erb" => "features/api_v2/00_list/10_user.feature", "templates/api_v2/00_list/10_user.feature.erb" => "features/api_v2/00_list/10_user.feature",
#create #create

View File

@ -62,4 +62,12 @@ class Provider::Ec2
] ]
end end
def create_stack(stack)
'arn:aws:cloudformation:us-east-1:123456789:stack/MyStack/aaf549a0-a413-11df-adb3-5081b3858e83'
end
def delete_stack(stack)
true
end
end end

View File

@ -71,4 +71,16 @@ class Provider::Openstack
true true
end end
def stack_details(stack)
{stack_status: 'stubbed'}
end
def stack_resources(stack)
[{'stubbed' => 'stubbed'}]
end
def stack_resource(stack, resource_id)
{'stubbed' => 'stubbed'}
end
end end

View File

@ -1,8 +1,8 @@
@stack_template_preset @stack_preset
Feature: stack template preset list Feature: stack template preset list
Scenario: Get list of all stack template presets Scenario: Get list of all stack template presets
When I send GET '/v2.0/stack_template_presets' query When I send GET '/v2.0/stack_presets' query
Then response should be '200' Then response should be '200'
And the Content-Type header should include 'application/json' And the Content-Type header should include 'application/json'
And the JSON response should be an array And the JSON response should be an array
@ -11,18 +11,18 @@ Feature: stack template preset list
[ [
{ {
"id": "test", "id": "test",
"template_preset_body": "long body" "template_body": "long body"
} }
] ]
""" """
Scenario: Get information about particular stack template preset Scenario: Get information about particular stack template preset
When I send GET '/v2.0/stack_template_presets/postgres_cluster' query When I send GET '/v2.0/stack_presets/postgres_cluster' query
Then response should be '200' Then response should be '200'
And the Content-Type header should include 'application/json' And the Content-Type header should include 'application/json'
And response should be JSON object like: And response should be JSON object like:
""" """
{ {
"id": "postgres_cluster", "template_preset_body": "long body" "id": "postgres_cluster", "template_body": "long body"
} }
""" """