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 +7 -0
- data/lib/autostacker24.rb +3 -0
- data/lib/autostacker24/service_stack.rb +43 -0
- data/lib/autostacker24/stacker.rb +98 -0
- metadata +63 -0
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,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: []
|