stackup 0.0.1
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/Gemfile +11 -0
- data/Gemfile.lock +48 -0
- data/README.md +40 -0
- data/Rakefile +10 -0
- data/lib/stackup.rb +3 -0
- data/lib/stackup/monitor.rb +29 -0
- data/lib/stackup/stack.rb +48 -0
- data/pkg/stackup-0.0.1.gem +0 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/stackup/monitor_spec.rb +21 -0
- data/spec/stackup/stack_spec.rb +54 -0
- data/stackup.gemspec +22 -0
- metadata +86 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 198c45027f791cb13d1ba1de4643fda60a97a18d
|
4
|
+
data.tar.gz: 7aab71076441135004a10109bda7a452ec15d75d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ff9a5468160fd18e6b4f80697457e76c653e5d5a755b776cd2873ee230e91148c9cd02dc9d402457e6c7ce468d8e016e6f0377b9512399c74394cf0e1d24cae2
|
7
|
+
data.tar.gz: 4d13507cc1022c2073b6feb0c13eea683b8983e2468489d470b5b5c40f9fea394340fe733d592283c9d852ebce45d6d8e1c87469b64c710aa321bca607ba7b4f
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
stackup (0.0.1)
|
5
|
+
aws-sdk (~> 2.0)
|
6
|
+
clamp (~> 1.0)
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
aws-sdk (2.1.20)
|
12
|
+
aws-sdk-resources (= 2.1.20)
|
13
|
+
aws-sdk-core (2.1.20)
|
14
|
+
jmespath (~> 1.0)
|
15
|
+
aws-sdk-resources (2.1.20)
|
16
|
+
aws-sdk-core (= 2.1.20)
|
17
|
+
byebug (6.0.2)
|
18
|
+
clamp (1.0.0)
|
19
|
+
diff-lcs (1.2.5)
|
20
|
+
jmespath (1.0.2)
|
21
|
+
multi_json (~> 1.0)
|
22
|
+
multi_json (1.11.2)
|
23
|
+
rake (10.4.2)
|
24
|
+
rspec (3.3.0)
|
25
|
+
rspec-core (~> 3.3.0)
|
26
|
+
rspec-expectations (~> 3.3.0)
|
27
|
+
rspec-mocks (~> 3.3.0)
|
28
|
+
rspec-core (3.3.2)
|
29
|
+
rspec-support (~> 3.3.0)
|
30
|
+
rspec-expectations (3.3.1)
|
31
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
32
|
+
rspec-support (~> 3.3.0)
|
33
|
+
rspec-mocks (3.3.2)
|
34
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
35
|
+
rspec-support (~> 3.3.0)
|
36
|
+
rspec-support (3.3.0)
|
37
|
+
|
38
|
+
PLATFORMS
|
39
|
+
ruby
|
40
|
+
|
41
|
+
DEPENDENCIES
|
42
|
+
byebug
|
43
|
+
rake (~> 10.0)
|
44
|
+
rspec (~> 3.3)
|
45
|
+
stackup!
|
46
|
+
|
47
|
+
BUNDLED WITH
|
48
|
+
1.10.6
|
data/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# stackup
|
2
|
+
|
3
|
+
Stackup attempts to simplify AWS Cloudformation stack creation process in
|
4
|
+
ruby projects by providing executable to perform common operations such
|
5
|
+
as apply(create/update), delete, recreate on stack along with validations on
|
6
|
+
templates. Task executions which enforce a stack change will wait until
|
7
|
+
ROLLBACK/COMPLETE or DELETE is signalled on the stack (useful in continuous
|
8
|
+
deployment environments to wait until deployment is successful).
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
$ gem install stackup
|
13
|
+
|
14
|
+
## Usage
|
15
|
+
|
16
|
+
The entry-point is the "stackup" command.
|
17
|
+
|
18
|
+
The "stack" subcommand lists stacks:
|
19
|
+
|
20
|
+
$ stackup stacks
|
21
|
+
|
22
|
+
Most other commands operate in the context of a named stack:
|
23
|
+
|
24
|
+
$ stackup stack STACK-NAME ...
|
25
|
+
|
26
|
+
To create or update a stack, based on a template, use "apply":
|
27
|
+
|
28
|
+
$ stackup stack myapp-test apply
|
29
|
+
|
30
|
+
This will:
|
31
|
+
|
32
|
+
* update (or create) the named CloudFormation stack, using the specified template
|
33
|
+
* monitor events until the stack update is complete
|
34
|
+
* print any stack "outputs"
|
35
|
+
|
36
|
+
Other stack subcommands include:
|
37
|
+
|
38
|
+
$ stackup stack myapp-test outputs
|
39
|
+
$ stackup stack myapp-test resources
|
40
|
+
$ stackup stack myapp-test delete
|
data/Rakefile
ADDED
data/lib/stackup.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Stackup
|
2
|
+
class Monitor
|
3
|
+
attr_accessor :stack, :events
|
4
|
+
def initialize(stack)
|
5
|
+
@stack = stack
|
6
|
+
@events = Set.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def new_events
|
10
|
+
stack.events.take_while do |event|
|
11
|
+
!seen?(event)
|
12
|
+
end.reverse
|
13
|
+
rescue ::Aws::CloudFormation::Errors::ValidationError => e
|
14
|
+
[]
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def seen?(event)
|
19
|
+
event_id = event.event_id
|
20
|
+
if events.include?(event_id)
|
21
|
+
true
|
22
|
+
else
|
23
|
+
events.add(event_id)
|
24
|
+
false
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module Stackup
|
4
|
+
class Stack
|
5
|
+
attr_reader :stack, :name, :cf, :template, :monitor
|
6
|
+
SUCESS_STATES = ["CREATE_COMPLETE", "UPDATE_COMPLETE"]
|
7
|
+
FAILURE_STATES = ["CREATE_FAILED", "DELETE_FAILED", "UPDATE_ROLLBACK_FAILED", "ROLLBACK_FAILED", "ROLLBACK_COMPLETE","ROLLBACK_FAILED","UPDATE_ROLLBACK_COMPLETE","UPDATE_ROLLBACK_FAILED"]
|
8
|
+
END_STATES = SUCESS_STATES + FAILURE_STATES
|
9
|
+
|
10
|
+
def initialize(name, template)
|
11
|
+
@cf = Aws::CloudFormation::Client.new
|
12
|
+
@stack = Aws::CloudFormation::Stack.new(name: name, client: cf)
|
13
|
+
@monitor = Stackup::Monitor.new(@stack)
|
14
|
+
@template = template
|
15
|
+
@name = name
|
16
|
+
end
|
17
|
+
|
18
|
+
def create
|
19
|
+
response = cf.create_stack({
|
20
|
+
stack_name: name,
|
21
|
+
template_body: template,
|
22
|
+
disable_rollback: true
|
23
|
+
})
|
24
|
+
!response[:stack_id].nil?
|
25
|
+
stack.wait_until(max_attempts: 1000, delay: 10) { |resource| display_events ; END_STATES.include?(resource.stack_status) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def display_events
|
29
|
+
monitor.new_events.each do |e|
|
30
|
+
ts = e.timestamp.localtime.strftime("%H:%M:%S")
|
31
|
+
fields = [e.logical_resource_id, e.resource_status, e.resource_status_reason]
|
32
|
+
puts("[#{ts}] #{fields.compact.join(' - ')}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def deployed?
|
37
|
+
!stack.stack_status.nil?
|
38
|
+
rescue Aws::CloudFormation::Errors::ValidationError => e
|
39
|
+
false
|
40
|
+
end
|
41
|
+
|
42
|
+
def valid?
|
43
|
+
response = cf.validate_template(template)
|
44
|
+
response[:code].nil?
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
Binary file
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Stackup::Monitor do
|
4
|
+
let(:stack) { Stackup::Stack.new('name', 'template') }
|
5
|
+
let(:monitor) { Stackup::Monitor.new(stack) }
|
6
|
+
let(:event) { double(Aws::CloudFormation::Event.new(id: '1')) }
|
7
|
+
let(:events) { [ event ] }
|
8
|
+
|
9
|
+
it 'should add the event if it is non-existent' do
|
10
|
+
allow(event).to receive(:event_id).and_return('1')
|
11
|
+
allow(stack).to receive(:events).and_return(events)
|
12
|
+
expect(monitor.new_events.size).to eq(1)
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should skip the event if it has been shown' do
|
16
|
+
allow(event).to receive(:event_id).and_return('1')
|
17
|
+
allow(stack).to receive(:events).and_return(events)
|
18
|
+
expect(monitor.new_events.size).to eq(1)
|
19
|
+
expect(monitor.new_events.size).to eq(0)
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Stackup::Stack do
|
4
|
+
let(:stack) { Stackup::Stack.new('stack_name', double(String)) }
|
5
|
+
let(:cf_stack) { double(Aws::CloudFormation::Stack) }
|
6
|
+
let(:cf) {double(Aws::CloudFormation::Client)}
|
7
|
+
|
8
|
+
before do
|
9
|
+
allow(Aws::CloudFormation::Client).to receive(:new).and_return(cf)
|
10
|
+
allow(Aws::CloudFormation::Stack).to receive(:new).and_return(cf_stack)
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'create' do
|
14
|
+
let(:response) {Seahorse::Client::Http::Response.new}
|
15
|
+
it 'should create stack if all is well' do
|
16
|
+
allow(response).to receive(:[]).with(:stack_id).and_return('1')
|
17
|
+
allow(cf).to receive(:create_stack).and_return(response)
|
18
|
+
allow(cf_stack).to receive(:wait_until).and_return(true)
|
19
|
+
expect(stack.create).to be true
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should return nil if stack was not created' do
|
23
|
+
allow(response).to receive(:[]).with(:stack_id).and_return(nil)
|
24
|
+
allow(cf).to receive(:create_stack).and_return(response)
|
25
|
+
allow(cf_stack).to receive(:wait_until).and_return(false)
|
26
|
+
expect(stack.create).to be false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'validate' do
|
31
|
+
it 'should be valid if cf validate say so' do
|
32
|
+
allow(cf).to receive(:validate_template).and_return({})
|
33
|
+
expect(stack.valid?).to be true
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should be invalid if cf validate say so' do
|
37
|
+
allow(cf).to receive(:validate_template).and_return({code: '404'})
|
38
|
+
expect(stack.valid?).to be false
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'deployed' do
|
44
|
+
it 'should be true if it is already deployed' do
|
45
|
+
allow(cf_stack).to receive(:stack_status).and_return('CREATE_COMPLETE')
|
46
|
+
expect(stack.deployed?).to be true
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should be false if it is not deployed' do
|
50
|
+
allow(cf_stack).to receive(:stack_status).and_raise(Aws::CloudFormation::Errors::ValidationError.new('1', '2'))
|
51
|
+
expect(stack.deployed?).to be false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/stackup.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
|
7
|
+
spec.name = "stackup"
|
8
|
+
spec.version = '0.0.1'
|
9
|
+
spec.authors = ["Arvind Kunday", "Mike Williams"]
|
10
|
+
spec.email = ["arvind.kunday@rea-group.com", "mike.williams@rea-group.com"]
|
11
|
+
spec.summary = "Tools for deployment to AWS"
|
12
|
+
spec.homepage = "https://github.com/realestate-com-au/stackup"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = Dir["**/*"].reject { |f| File.directory?(f) }
|
16
|
+
spec.executables = spec.files.grep(/^bin/) { |f| File.basename(f) }
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
|
19
|
+
spec.add_dependency "aws-sdk", "~> 2.0"
|
20
|
+
spec.add_dependency "clamp", "~> 1.0"
|
21
|
+
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: stackup
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Arvind Kunday
|
8
|
+
- Mike Williams
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-09-15 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'
|
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'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: clamp
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - "~>"
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '1.0'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "~>"
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '1.0'
|
42
|
+
description:
|
43
|
+
email:
|
44
|
+
- arvind.kunday@rea-group.com
|
45
|
+
- mike.williams@rea-group.com
|
46
|
+
executables: []
|
47
|
+
extensions: []
|
48
|
+
extra_rdoc_files: []
|
49
|
+
files:
|
50
|
+
- Gemfile
|
51
|
+
- Gemfile.lock
|
52
|
+
- README.md
|
53
|
+
- Rakefile
|
54
|
+
- lib/stackup.rb
|
55
|
+
- lib/stackup/monitor.rb
|
56
|
+
- lib/stackup/stack.rb
|
57
|
+
- pkg/stackup-0.0.1.gem
|
58
|
+
- spec/spec_helper.rb
|
59
|
+
- spec/stackup/monitor_spec.rb
|
60
|
+
- spec/stackup/stack_spec.rb
|
61
|
+
- stackup.gemspec
|
62
|
+
homepage: https://github.com/realestate-com-au/stackup
|
63
|
+
licenses:
|
64
|
+
- MIT
|
65
|
+
metadata: {}
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0'
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
requirements: []
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 2.4.5.1
|
83
|
+
signing_key:
|
84
|
+
specification_version: 4
|
85
|
+
summary: Tools for deployment to AWS
|
86
|
+
test_files: []
|