autostacker24 1.0.pre1420195669

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5504eb5540d79a296099f4b7e3e20e8956ffa7f6
4
+ data.tar.gz: 34aa0de0b82ea78c919503c70b44c19a242c97f9
5
+ SHA512:
6
+ metadata.gz: 3339d2f678fd379179aebc52882802061522c57cae23685490e7b70132e500c6a50f025fd284325a38eeb71121b4241525028aefcf971bc19078cc545b3df108
7
+ data.tar.gz: ea14bf541ef75c9e7b8459a3d8c6332d581f5c74578951e412e847a1d4004efa3fdc4496c42ab369c3fea889295eedd090c3fa3cb922b66f0caa47e3a0fdfbb4
@@ -0,0 +1,3 @@
1
+
2
+ require_relative 'autostacker24/service_stack.rb'
3
+ require_relative 'autostacker24/stacker.rb'
@@ -0,0 +1,43 @@
1
+ require 'json'
2
+ require_relative 'stacker.rb'
3
+
4
+ class ServiceStack
5
+
6
+ def initialize(name, version, sandbox = nil, global_stack_name = nil)
7
+ @name = name || fail('mandatory name is not specified')
8
+ @version = version || ENV['VERSION'] || fail('mandatory version is not specified')
9
+ @sandbox = sandbox || ENV['SANDBOX']
10
+ @stack_name = (sandbox ? "#{sandbox}-" : '') + name
11
+ @global_stack_name = global_stack_name || ENV['GLOBAL_STACK_NAME'] || 'global'
12
+ end
13
+
14
+ attr_reader :name, :sandbox, :version, :stack_name, :global_stack_name
15
+
16
+ def create_or_update(template, parameters)
17
+ inputs = JSON(template)['Parameters']
18
+ global_outputs.each{|k, v| parameters[k.to_sym] = v if inputs.has_key?(k.to_s)}
19
+ parameters[:Version] = version
20
+ Stacker.create_or_update_stack(stack_name, template, parameters)
21
+ end
22
+
23
+ def delete
24
+ Stacker.delete_stack(stack_name)
25
+ end
26
+
27
+ def outputs
28
+ @lazy_outputs ||= Stacker.get_stack_outputs(stack_name)
29
+ end
30
+
31
+ def global_outputs
32
+ @lazy_global_outputs ||= Stacker.get_stack_outputs(global_stack_name)
33
+ end
34
+
35
+ def estimate(template, parameters)
36
+ Stacker.estimate_template_cost(template, parameters)
37
+ end
38
+
39
+ end
40
+
41
+ if $0 ==__FILE__ # placeholder for interactive testing
42
+
43
+ end
@@ -0,0 +1,98 @@
1
+ require 'aws-sdk'
2
+
3
+ module Stacker
4
+
5
+ def self.create_or_update_stack(stack_name, template_body, parameters)
6
+ if find_stack(stack_name).nil?
7
+ create_stack(stack_name, template_body, parameters)
8
+ else
9
+ update_stack(stack_name, template_body, parameters)
10
+ end
11
+ end
12
+
13
+ def self.create_stack(stack_name, template_body, parameters)
14
+ cloud_formation.create_stack(stack_name: stack_name,
15
+ template_body: template_body,
16
+ on_failure: 'DELETE',
17
+ parameters: transform_parameters(parameters),
18
+ capabilities: ['CAPABILITY_IAM'])
19
+ wait_for_stack(stack_name, :create)
20
+ end
21
+
22
+ def self.update_stack(stack_name, template_body, parameters)
23
+ begin
24
+ cloud_formation.update_stack(stack_name: stack_name,
25
+ template_body: template_body,
26
+ parameters: transform_parameters(parameters),
27
+ capabilities: ['CAPABILITY_IAM'])
28
+ rescue Aws::CloudFormation::Errors::ValidationError => error
29
+ raise error unless error.message =~ /No updates are to be performed/i # may be flaky, do more research in API
30
+ find_stack(stack_name)
31
+ else
32
+ wait_for_stack(stack_name, :update)
33
+ end
34
+ end
35
+
36
+ def self.delete_stack(stack_name)
37
+ cloud_formation.delete_stack(stack_name: stack_name)
38
+ wait_for_stack(stack_name, :delete)
39
+ end
40
+
41
+ def self.wait_for_stack(stack_name, operation, timeout_in_minutes = 15)
42
+ stop_time = Time.now + timeout_in_minutes * 60
43
+ finished = /(CREATE_COMPLETE|UPDATE_COMPLETE|DELETE_COMPLETE|ROLLBACK_COMPLETE|ROLLBACK_FAILED|CREATE_FAILED|DELETE_FAILED)$/
44
+ while Time.now < stop_time
45
+ stack = find_stack(stack_name)
46
+ status = stack ? stack.stack_status : 'DELETE_COMPLETE'
47
+ expected_status = case operation
48
+ when :create then /CREATE_COMPLETE$/
49
+ when :update then /UPDATE_COMPLETE$/
50
+ when :delete then /DELETE_COMPLETE$/
51
+ end
52
+ return true if status =~ expected_status
53
+ fail "#{stack_name} failed, current status #{status}" if status =~ finished
54
+ puts "waiting for #{stack_name}, current status #{status}"
55
+ sleep(7)
56
+ end
57
+ fail "waiting for stack timeout after #{timeout_in_minutes} minutes"
58
+ end
59
+
60
+ def self.find_stack(stack_name)
61
+ cloud_formation.describe_stacks(stack_name: stack_name).stacks.first
62
+ rescue Aws::CloudFormation::Errors::ValidationError => error
63
+ raise error unless error.message =~ /does not exist/i # may be flaky, do more research in API
64
+ nil
65
+ end
66
+
67
+ def self.estimate_template_cost(template_body, parameters)
68
+ cloud_formation.estimate_template_cost(:template_body => template_body, :parameters => transform_parameters(parameters))
69
+ end
70
+
71
+ def self.get_stack_outputs(stack_name, hash = {})
72
+ stack = find_stack(stack_name)
73
+ fail "stack #{stack_name} not found" unless stack
74
+ transform_outputs(stack.outputs, hash).freeze
75
+ end
76
+
77
+ def self.transform_outputs(outputs, existing_outputs = {})
78
+ outputs.inject(existing_outputs) { |m, o| m.merge(o.output_key.to_sym => o.output_value) }
79
+ end
80
+
81
+ def self.transform_parameters(parameters)
82
+ parameters.inject([]) { |m, kv| m << {parameter_key: kv[0].to_s, parameter_value: kv[1].to_s} }
83
+ end
84
+
85
+ def self.get_stack_resources(stack_name)
86
+ resources = cloud_formation.describe_stack_resources(stack_name: stack_name).data.stack_resources
87
+ resources.inject({}){|map, resource| map.merge(resource.logical_resource_id => resource)}.freeze
88
+ end
89
+
90
+ def self.cloud_formation # lazy CloudFormation client
91
+ @lazy_cloud_formation ||= Aws::CloudFormation::Client.new(region: ENV['AWS_DEFAULT_REGION'] || 'eu-west-1')
92
+ end
93
+
94
+ end
95
+
96
+ if $0 ==__FILE__ # placeholder for interactive testing
97
+
98
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: autostacker24
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.pre1420195669
5
+ platform: ruby
6
+ authors:
7
+ - Johannes Mueller
8
+ - Christian Rodemeyer
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-01-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: aws-sdk
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ~>
19
+ - !ruby/object:Gem::Version
20
+ version: 2.0.pre
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ~>
26
+ - !ruby/object:Gem::Version
27
+ version: 2.0.pre
28
+ description: n/a
29
+ email:
30
+ - jmueller@autoscout24.com
31
+ - crodemeyer@autoscout24.com
32
+ executables: []
33
+ extensions: []
34
+ extra_rdoc_files: []
35
+ files:
36
+ - lib/autostacker24.rb
37
+ - lib/autostacker24/service_stack.rb
38
+ - lib/autostacker24/stacker.rb
39
+ homepage: https://github.com/AutoScout24/autostacker24
40
+ licenses:
41
+ - MIT
42
+ metadata: {}
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - '>'
55
+ - !ruby/object:Gem::Version
56
+ version: 1.3.1
57
+ requirements: []
58
+ rubyforge_project:
59
+ rubygems_version: 2.0.14
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Library for managing AWS CloudFormation stacks
63
+ test_files: []