diff --git a/devops-client/lib/devops-client/handler/stack_template.rb b/devops-client/lib/devops-client/handler/stack_template.rb index c305e18..d1754c4 100644 --- a/devops-client/lib/devops-client/handler/stack_template.rb +++ b/devops-client/lib/devops-client/handler/stack_template.rb @@ -14,7 +14,6 @@ class StackTemplate < Handler end def handle - current_command = ARGV[1].to_sym @options, @args = @options_parser.parse_options_for!(current_command) case current_command when :list @@ -27,6 +26,8 @@ class StackTemplate < Handler create_handler when :delete delete_handler + when :update_url + update_url_handler end end @@ -76,6 +77,16 @@ class StackTemplate < Handler end end + def update_url_handler + r = inspect_parameters @options_parser.update_url_params, @args[2] + unless r.nil? + @options_parser.invalid_update_url_command + abort(r) + end + stack_template = post "/stack_template/#{@args[2]}/update_template_url" + puts stack_template['template_url'] + end + def provider_stack_templates(provider) if Providers.has_functionality?(provider, :stack_templates) @provider = true diff --git a/devops-client/lib/devops-client/options/stack_template_options.rb b/devops-client/lib/devops-client/options/stack_template_options.rb index 67f8498..74b9d9e 100644 --- a/devops-client/lib/devops-client/options/stack_template_options.rb +++ b/devops-client/lib/devops-client/options/stack_template_options.rb @@ -2,7 +2,7 @@ require "devops-client/options/common_options" class StackTemplateOptions < CommonOptions - commands :create, :delete, :list, :show + commands :create, :delete, :list, :show, :update_url def initialize args, def_options super(args, def_options) @@ -11,6 +11,7 @@ class StackTemplateOptions < CommonOptions self.list_params = ["[provider]", "[ec2|openstack]"] self.show_params = ["STACK_TEMPLATE"] self.delete_params = ["STACK_TEMPLATE"] + self.update_url_params = ["STACK_TEMPLATE"] end def create_options diff --git a/devops-service/app/api2/handlers/stack_template.rb b/devops-service/app/api2/handlers/stack_template.rb index 49718a9..ecb28a2 100644 --- a/devops-service/app/api2/handlers/stack_template.rb +++ b/devops-service/app/api2/handlers/stack_template.rb @@ -39,6 +39,14 @@ module Devops end end + # temp solution to update url on existing stacks + def update_template_url(id) + template = Devops::Db.connector.stack_template(id) + template.update_template_url + Devops::Db.connector.stack_template_update(template) + template + end + private # returns: diff --git a/devops-service/app/api2/routes/stack_template.rb b/devops-service/app/api2/routes/stack_template.rb index d825191..1b18fd9 100644 --- a/devops-service/app/api2/routes/stack_template.rb +++ b/devops-service/app/api2/routes/stack_template.rb @@ -22,6 +22,11 @@ module Devops create_response 'Created', model.to_hash, 201 end + app.post_with_headers "/stack_template/:id/update_template_url", :headers => [:accept] do |template_id| + check_privileges('stack_template', 'w') + json Devops::API2_0::Handler::StackTemplate.new(request).update_template_url(template_id).to_hash + end + hash = {} hash['GET'] = lambda {|stack_template_id| diff --git a/devops-service/config.rb b/devops-service/config.rb index 5bc27b3..1751eb7 100644 --- a/devops-service/config.rb +++ b/devops-service/config.rb @@ -37,6 +37,7 @@ config[:aws_certificate] = "/path/to/.ssh/ec2.pem" config[:aws_availability_zone] = "aws_zone" config[:aws_proxy] = "" config[:aws_no_proxy] = "" +config[:aws_stack_templates_bucket] = 'stacktemplates' # static settings config[:static_ssh_key] = "ssh_key" # or nil @@ -46,4 +47,4 @@ config[:debug] = true # set it to :all or [:ec2] to stub calls to selected providers # or to false to disable stubbing -config[:stub_providers] = false +config[:stub_providers] = false \ No newline at end of file diff --git a/devops-service/db/mongo/models/stack/stack_base.rb b/devops-service/db/mongo/models/stack/stack_base.rb index cf118e5..e631bf6 100644 --- a/devops-service/db/mongo/models/stack/stack_base.rb +++ b/devops-service/db/mongo/models/stack/stack_base.rb @@ -131,7 +131,11 @@ module Devops end def template_body - Devops::Db.connector.stack_template(stack_template).template_body + stack_template_model.template_body + end + + def stack_template_model + Devops::Db.connector.stack_template(stack_template) end class << self diff --git a/devops-service/db/mongo/models/stack_template/stack_template_ec2.rb b/devops-service/db/mongo/models/stack_template/stack_template_ec2.rb index 7a2636e..4cd52f3 100644 --- a/devops-service/db/mongo/models/stack_template/stack_template_ec2.rb +++ b/devops-service/db/mongo/models/stack_template/stack_template_ec2.rb @@ -16,34 +16,25 @@ module Devops super.merge(template_url: template_url) end + def update_template_url + self.template_url = generate_template_file_and_upload_to_storage(id, template_body) + end + class << self - def create(attrs) - template = attrs['template_body'] - attrs['template_url'] = generate_template_file_and_upload_to_storage(attrs['id'], template) - super(attrs) + model = super(attrs) + model.update_template_url + model end + end - private + private def generate_template_file_and_upload_to_storage(id, json) - begin - tempfile = Tempfile.new('foo') - tempfile.write(json) - tempfile.close - secure_filename = "#{id}-#{SecureRandom.hex}.template" - upload_file_to_storage(secure_filename, tempfile.path) - ensure - tempfile.unlink - end + uniq_filename = "#{id}-#{SecureRandom.hex}.template" + provider_instance.store_stack_template(uniq_filename, json)['url'] end - def upload_file_to_storage(filename, file_path) - "https://s3.amazonaws.com/#{filename}" - end - - end - end end end diff --git a/devops-service/providers/ec2.rb b/devops-service/providers/ec2.rb index 609186b..84860a6 100644 --- a/devops-service/providers/ec2.rb +++ b/devops-service/providers/ec2.rb @@ -222,7 +222,7 @@ module Provider out.flush response = cloud_formation.create_stack(stack.name, { - 'TemplateBody' => stack.template_body, + 'TemplateURL' => stack.stack_template_model.template_url, 'Parameters' => stack.parameters || {}, 'Capabilities' => ['CAPABILITY_IAM'], 'Tags' => stack_tags(stack) @@ -320,6 +320,17 @@ module Provider def describe_vpcs self.compute.describe_vpcs.body["vpcSet"].select{|v| v["state"] == "available"}.map{|v| {"vpc_id" => v["vpcId"], "cidr" => v["cidrBlock"] } } end + + def store_stack_template(filename, json) + store_file(stack_templates_bucket, filename, json) + end + + def store_file(bucket, filename, body) + { + 'url' => bucket.files.create(key: filename, body: body, public: true).public_url + } + end + private def convert_groups list @@ -376,6 +387,16 @@ module Provider @orchestration ||= Fog::AWS::CloudFormation.new(connection_options) end + def storage + @storage ||= Fog::Storage.new(connection_options) + end + + def stack_templates_bucket + bucket_name = DevopsConfig.config[:aws_stack_templates_bucket] || 'stacktemplatesnibrdev' + bucket = storage.directories.get(bucket_name) + bucket ||= storage.directories.create(key: bucket_name) + end + def instance_name(instance) return instance["tagSet"]["Name"] if instance["tagSet"]["Name"] if instance['tagSet']['aws:autoscaling:groupName'] diff --git a/devops-service/spec/models/stack_template/stack_template_ec2_spec.rb b/devops-service/spec/models/stack_template/stack_template_ec2_spec.rb index 02c4d03..3386445 100644 --- a/devops-service/spec/models/stack_template/stack_template_ec2_spec.rb +++ b/devops-service/spec/models/stack_template/stack_template_ec2_spec.rb @@ -7,7 +7,20 @@ RSpec.describe Devops::Model::StackTemplateEc2, type: :model do before do allow(Provider::ProviderFactory).to receive(:providers).and_return(%w(ec2)) allow_any_instance_of(Devops::Model::StackTemplateEc2).to receive_message_chain('provider_instance.validate_stack_template') { true } + allow_any_instance_of(Devops::Model::StackTemplateEc2).to receive_message_chain('provider_instance.store_stack_template') { {'url' => nil} } end it_behaves_like 'stack template' + + it 'uploads file to S3' do + expect_any_instance_of(Devops::Model::StackTemplateEc2).to receive_message_chain('provider_instance.store_stack_template') + params = { + 'id' => 'foo', + 'template_body' => '{}', + 'owner' => 'root', + 'provider' => 'ec2' + } + expect(described_class.create(params)).to be_an_instance_of(described_class) + end + end \ No newline at end of file