cf_deployer 1.2.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +29 -0
- data/ChangeLog.md +16 -0
- data/DETAILS.md +268 -0
- data/FAQ.md +61 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +51 -0
- data/LICENSE +22 -0
- data/QUICKSTART.md +96 -0
- data/README.md +36 -0
- data/Rakefile +32 -0
- data/bin/cf_deploy +10 -0
- data/cf_deployer.gemspec +23 -0
- data/lib/cf_deployer/application.rb +74 -0
- data/lib/cf_deployer/application_error.rb +4 -0
- data/lib/cf_deployer/aws_constants.rb +3 -0
- data/lib/cf_deployer/cli.rb +111 -0
- data/lib/cf_deployer/component.rb +103 -0
- data/lib/cf_deployer/config_loader.rb +189 -0
- data/lib/cf_deployer/config_validation.rb +138 -0
- data/lib/cf_deployer/defaults.rb +10 -0
- data/lib/cf_deployer/deployment_strategy/auto_scaling_group_swap.rb +102 -0
- data/lib/cf_deployer/deployment_strategy/base.rb +88 -0
- data/lib/cf_deployer/deployment_strategy/blue_green.rb +70 -0
- data/lib/cf_deployer/deployment_strategy/cname_swap.rb +108 -0
- data/lib/cf_deployer/deployment_strategy/create_or_update.rb +57 -0
- data/lib/cf_deployer/driver/auto_scaling_group.rb +86 -0
- data/lib/cf_deployer/driver/cloud_formation_driver.rb +85 -0
- data/lib/cf_deployer/driver/dry_run.rb +27 -0
- data/lib/cf_deployer/driver/elb_driver.rb +17 -0
- data/lib/cf_deployer/driver/instance.rb +29 -0
- data/lib/cf_deployer/driver/route53_driver.rb +79 -0
- data/lib/cf_deployer/driver/verisign_driver.rb +21 -0
- data/lib/cf_deployer/hook.rb +32 -0
- data/lib/cf_deployer/logger.rb +34 -0
- data/lib/cf_deployer/stack.rb +154 -0
- data/lib/cf_deployer/status_presenter.rb +195 -0
- data/lib/cf_deployer/version.rb +3 -0
- data/lib/cf_deployer.rb +97 -0
- data/spec/fakes/instance.rb +32 -0
- data/spec/fakes/route53_client.rb +23 -0
- data/spec/fakes/stack.rb +65 -0
- data/spec/functional/deploy_spec.rb +73 -0
- data/spec/functional/kill_inactive_spec.rb +57 -0
- data/spec/functional_spec_helper.rb +3 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/unit/application_spec.rb +191 -0
- data/spec/unit/component_spec.rb +142 -0
- data/spec/unit/config_loader_spec.rb +356 -0
- data/spec/unit/config_validation_spec.rb +480 -0
- data/spec/unit/deployment_strategy/auto_scaling_group_swap_spec.rb +435 -0
- data/spec/unit/deployment_strategy/base_spec.rb +44 -0
- data/spec/unit/deployment_strategy/cname_swap_spec.rb +294 -0
- data/spec/unit/deployment_strategy/create_or_update_spec.rb +113 -0
- data/spec/unit/deployment_strategy/deployment_strategy_spec.rb +29 -0
- data/spec/unit/driver/auto_scaling_group_spec.rb +127 -0
- data/spec/unit/driver/cloud_formation_spec.rb +32 -0
- data/spec/unit/driver/elb_spec.rb +11 -0
- data/spec/unit/driver/instance_spec.rb +30 -0
- data/spec/unit/driver/route53_spec.rb +85 -0
- data/spec/unit/driver/verisign_spec.rb +18 -0
- data/spec/unit/hook_spec.rb +64 -0
- data/spec/unit/stack_spec.rb +150 -0
- data/spec/unit/status_presenter_spec.rb +108 -0
- metadata +197 -0
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CfDeployer::Driver::Route53 do
|
4
|
+
subject { CfDeployer::Driver::Route53.new }
|
5
|
+
|
6
|
+
describe ".find_alias_target" do
|
7
|
+
it "should raise an error when the target zone cannot be found" do
|
8
|
+
route53 = double('route53')
|
9
|
+
allow(AWS::Route53).to receive(:new) { route53 }
|
10
|
+
|
11
|
+
allow(route53).to receive(:hosted_zones) { [] }
|
12
|
+
|
13
|
+
expect { subject.find_alias_target('abc.com', 'foo') }.to raise_error('Target zone not found!')
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should get empty alias target when the target host cannot be found" do
|
17
|
+
zone = double('zone')
|
18
|
+
allow(zone).to receive(:name) { 'target.com.' }
|
19
|
+
allow(zone).to receive(:resource_record_sets) { [] }
|
20
|
+
|
21
|
+
route53 = double('route53')
|
22
|
+
allow(AWS::Route53).to receive(:new) { route53 }
|
23
|
+
allow(route53).to receive(:hosted_zones) { [zone] }
|
24
|
+
|
25
|
+
subject.find_alias_target('target.com', 'foo').should be_nil
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should get alias target" do
|
29
|
+
host = double('host', :name => 'foo.target.com.', :alias_target => { :dns_name => 'abc.com.'})
|
30
|
+
zone = double('zone', :name => 'target.com.', :resource_record_sets => [host])
|
31
|
+
route53 = double('route53', :hosted_zones => [zone])
|
32
|
+
allow(AWS::Route53).to receive(:new) { route53 }
|
33
|
+
|
34
|
+
subject.find_alias_target('Target.com', 'Foo.target.com').should eq('abc.com')
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should get a nil alias target when the record exists but has no alias target" do
|
38
|
+
host = double('host', :name => 'foo.target.com.', :alias_target => nil)
|
39
|
+
zone = double('zone', :name => 'target.com.', :resource_record_sets => [host])
|
40
|
+
route53 = double('route53', :hosted_zones => [zone])
|
41
|
+
allow(AWS::Route53).to receive(:new) { route53 }
|
42
|
+
|
43
|
+
subject.find_alias_target('target.com', 'foo.target.com').should be_nil
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should get alias target when zone and host name having trailing dot" do
|
47
|
+
host = double('host', :name => 'foo.target.com.', :alias_target => { :dns_name => 'abc.com.'})
|
48
|
+
zone = double('zone', :name => 'target.com.', :resource_record_sets => [host])
|
49
|
+
route53 = double('route53', :hosted_zones => [zone])
|
50
|
+
allow(AWS::Route53).to receive(:new) { route53 }
|
51
|
+
|
52
|
+
subject.find_alias_target('target.com.', 'foo.target.com.').should eq('abc.com')
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
describe ".set_alias_target" do
|
58
|
+
it "should raise an error when the target-zone cannot be found" do
|
59
|
+
route53 = double('route53')
|
60
|
+
allow(AWS::Route53).to receive(:new) { route53 }
|
61
|
+
|
62
|
+
allow(route53).to receive(:hosted_zones) { [] }
|
63
|
+
|
64
|
+
expect { subject.set_alias_target('abc.com', 'foo', 'abc', 'def') }.to raise_error('Target zone not found!')
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should attempt multiple times" do
|
68
|
+
failing_route53 = Fakes::AWSRoute53.new(times_to_fail: 5, hosted_zones: [double(name: 'abc.com.', path: '')])
|
69
|
+
route53_driver = CfDeployer::Driver::Route53.new(failing_route53)
|
70
|
+
|
71
|
+
allow(route53_driver).to receive(:sleep)
|
72
|
+
route53_driver.set_alias_target('abc.com', 'foo', 'abc', 'def')
|
73
|
+
|
74
|
+
expect(failing_route53.client.fail_counter).to eq(6)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should raise an exception when failing more than 20 times" do
|
78
|
+
failing_route53 = Fakes::AWSRoute53.new(times_to_fail: 21, hosted_zones: [double(name: 'abc.com.', path: '')])
|
79
|
+
route53_driver = CfDeployer::Driver::Route53.new(failing_route53)
|
80
|
+
|
81
|
+
allow(route53_driver).to receive(:sleep)
|
82
|
+
expect { route53_driver.set_alias_target('abc.com', 'foo', 'abc', 'def') }.to raise_error('Failed to update Route53 alias target record!')
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CfDeployer::Driver::Verisign do
|
4
|
+
subject { CfDeployer::Driver::Verisign.new }
|
5
|
+
|
6
|
+
describe ".find_alias_target" do
|
7
|
+
it "should raise an error because it's not implemented yet" do
|
8
|
+
expect { subject.find_alias_target('abc.com', 'foo') }.to raise_error('Not Implemented')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe ".set_alias_target" do
|
13
|
+
it "should raise an error because it's not implemented yet" do
|
14
|
+
expect { subject.set_alias_target('abc.com', 'foo', 'abc', 'def') }.to raise_error('Not Implemented')
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CfDeployer::Hook do
|
4
|
+
before :all do
|
5
|
+
@file = File.expand_path("../../../tmp/test_code.rb", __FILE__)
|
6
|
+
end
|
7
|
+
it 'should eval string as hook' do
|
8
|
+
$result = nil
|
9
|
+
context = { app: 'myApp'}
|
10
|
+
CfDeployer::Hook.new('MyHook', "$result = context[:app]").run(context)
|
11
|
+
expect($result).to eq('myApp')
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'should log the hook name ' do
|
15
|
+
context = { app: 'myApp'}
|
16
|
+
expect(CfDeployer::Log).to receive(:info).with(/My Hook/)
|
17
|
+
CfDeployer::Hook.new('My Hook', "$result = context[:app]").run(context)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should duplicate context in hook' do
|
21
|
+
$result = nil
|
22
|
+
context = { app: 'myApp'}
|
23
|
+
CfDeployer::Hook.new('MyHook', "context[:app] = 'app2'").run(context)
|
24
|
+
expect(context[:app]).to eq('myApp')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should timeout when executing hook in a string takes too long time' do
|
28
|
+
$result = nil
|
29
|
+
stub_const("CfDeployer::Defaults::Timeout", 10/1000.0)
|
30
|
+
context = { app: 'myApp'}
|
31
|
+
expect{CfDeployer::Hook.new('MyHook', "sleep 40/1000.0").run(context)}.to raise_error(Timeout::Error)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should timeout when executing hook in a string takes too longer time than given timeout' do
|
35
|
+
$result = nil
|
36
|
+
context = { app: 'myApp'}
|
37
|
+
expect{CfDeployer::Hook.new('MyHook', {code: "sleep 40/1000.0", timeout: 20/1000.0}).run(context)}.to raise_error(Timeout::Error)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should excute code in a file' do
|
41
|
+
code = <<-eos
|
42
|
+
$result = context[:app]
|
43
|
+
eos
|
44
|
+
File.open(@file, 'w') {|f| f.write(code) }
|
45
|
+
$result = nil
|
46
|
+
config_dir = File.expand_path('../../samples', __FILE__)
|
47
|
+
context = { app: 'myApp', config_dir: config_dir}
|
48
|
+
CfDeployer::Hook.new('MyHook', {file: '../../tmp/test_code.rb'}).run(context)
|
49
|
+
expect($result).to eq('myApp')
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should timeout when excuting code in a file takes too long time' do
|
53
|
+
file = File.expand_path("../../tmp/test_code.rb", __FILE__)
|
54
|
+
code = <<-eos
|
55
|
+
sleep 40/1000.0
|
56
|
+
$result = context[:app]
|
57
|
+
eos
|
58
|
+
File.open(@file, 'w') {|f| f.write(code) }
|
59
|
+
$result = nil
|
60
|
+
config_dir = File.expand_path('../../samples', __FILE__)
|
61
|
+
context = { app: 'myApp', config_dir: config_dir}
|
62
|
+
expect{CfDeployer::Hook.new('MyHook', {file: '../../tmp/test_code.rb', timeout: 20/1000.0}).run(context)}.to raise_error(Timeout::Error)
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CfDeployer::Stack do
|
4
|
+
before do
|
5
|
+
@cf_driver = double CfDeployer::Driver::CloudFormation
|
6
|
+
@stack = CfDeployer::Stack.new('test', 'web', {:cf_driver => @cf_driver})
|
7
|
+
end
|
8
|
+
|
9
|
+
context '#deploy' do
|
10
|
+
it 'should call CfDeployer::ConfigLoader.component_json to get the JSON for the stack' do
|
11
|
+
config = { :inputs => { :foo => 'foo' },
|
12
|
+
:defined_parameters => { :bar => 'bar' },
|
13
|
+
:cf_driver => @cf_driver }
|
14
|
+
CfDeployer::ConfigLoader.should_receive(:component_json).with('web', config)
|
15
|
+
allow(@cf_driver).to receive(:stack_exists?) { false }
|
16
|
+
allow(@cf_driver).to receive(:stack_status) { :create_complete }
|
17
|
+
stack = CfDeployer::Stack.new('test','web', config)
|
18
|
+
allow(stack).to receive(:create_stack)
|
19
|
+
stack.deploy
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context '#parameters' do
|
24
|
+
it "should get parameters" do
|
25
|
+
parameters = double('parameters')
|
26
|
+
allow(@cf_driver).to receive(:parameters){ parameters }
|
27
|
+
allow(@cf_driver).to receive(:stack_status) { :create_complete }
|
28
|
+
expect(@stack.parameters).to eq(parameters)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should get empty hash if stack is not ready" do
|
32
|
+
allow(@cf_driver).to receive(:stack_status) { :create_inprogress }
|
33
|
+
expect(@stack.parameters).to eq({})
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context '#outputs' do
|
38
|
+
it "should get outputs" do
|
39
|
+
outputs = double('outputs')
|
40
|
+
allow(@cf_driver).to receive(:outputs){ outputs }
|
41
|
+
allow(@cf_driver).to receive(:stack_status) { :create_complete }
|
42
|
+
expect(@stack.outputs).to eq(outputs)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should get empty hash if stack is not ready" do
|
46
|
+
outputs = double('outputs')
|
47
|
+
allow(@cf_driver).to receive(:stack_status) { :create_inprogress }
|
48
|
+
expect(@stack.outputs).to eq({})
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context "#ready?" do
|
53
|
+
|
54
|
+
CfDeployer::Stack::READY_STATS.each do |status|
|
55
|
+
it "should be ready when in #{status} status" do
|
56
|
+
allow(@cf_driver).to receive(:stack_status) { status }
|
57
|
+
expect(@stack).to be_ready
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should not be ready when not in a ready status" do
|
62
|
+
allow(@cf_driver).to receive(:stack_status) { :my_fake_status }
|
63
|
+
expect(@stack).not_to be_ready
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should get error if output is empty" do
|
67
|
+
expect(@cf_driver).to receive(:query_output).with('mykey'){ nil }
|
68
|
+
expect{@stack.output('mykey')}.to raise_error("'mykey' is empty from stack test output")
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should get output value" do
|
72
|
+
expect(@cf_driver).to receive(:query_output).with('mykey'){ 'myvalue'}
|
73
|
+
@stack.output('mykey').should eq('myvalue')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '#delete' do
|
78
|
+
it 'should delete the stack' do
|
79
|
+
allow(@stack).to receive(:exists?).and_return(true, false)
|
80
|
+
expect(@cf_driver).to receive(:delete_stack)
|
81
|
+
@stack.delete
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'should not delete the stack if it does not exist' do
|
85
|
+
allow(@stack).to receive(:exists?) { false }
|
86
|
+
expect(@cf_driver).not_to receive(:delete_stack)
|
87
|
+
@stack.delete
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'should be fine to get not exist error after deletion' do
|
91
|
+
allow(@stack).to receive(:exists?).and_return(true, true)
|
92
|
+
allow(@stack).to receive(:stack_status).and_raise(AWS::CloudFormation::Errors::ValidationError.new('the stack does not exist'))
|
93
|
+
expect(@cf_driver).to receive(:delete_stack)
|
94
|
+
expect {@stack.delete}.not_to raise_error
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should raise an error if a validation error is thrown not about stack does not exist' do
|
98
|
+
allow(@stack).to receive(:exists?).and_return(true, true)
|
99
|
+
allow(@stack).to receive(:stack_status).and_raise(AWS::CloudFormation::Errors::ValidationError.new('I am an error'))
|
100
|
+
expect(@cf_driver).to receive(:delete_stack)
|
101
|
+
expect {@stack.delete}.to raise_error
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe '#status' do
|
106
|
+
it "should be :ready if the stack is ready" do
|
107
|
+
allow(@stack).to receive(:exists?) { true }
|
108
|
+
allow(@stack).to receive(:ready?) { true }
|
109
|
+
expect(@stack.status).to eq(:ready)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should be :exists if it exists but is not ready' do
|
113
|
+
allow(@stack).to receive(:exists?) { true }
|
114
|
+
allow(@stack).to receive(:ready?) { false }
|
115
|
+
expect(@stack.status).to eq(:exists)
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'should be :does_not_exist if it does not exist' do
|
119
|
+
allow(@stack).to receive(:exists?) { false }
|
120
|
+
expect(@stack.status).to eq(:does_not_exist)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe '#resource_statuses' do
|
125
|
+
it 'should get resource_statuses from the CF driver' do
|
126
|
+
rs = { :something => :some_status }
|
127
|
+
expect(@cf_driver).to receive(:resource_statuses) { rs }
|
128
|
+
expect(@stack.resource_statuses[:something]).to eq(:some_status)
|
129
|
+
end
|
130
|
+
|
131
|
+
it 'should add instance status info for instances in ASGs' do
|
132
|
+
asg = double CfDeployer::Driver::AutoScalingGroup
|
133
|
+
rs = { 'AWS::AutoScaling::AutoScalingGroup' => { 'ASG123' => :some_status } }
|
134
|
+
expect(@cf_driver).to receive(:resource_statuses) { rs }
|
135
|
+
expect(asg).to receive(:instance_statuses) { { 'i-abcd1234' => { :status => :some_status } } }
|
136
|
+
expect(CfDeployer::Driver::AutoScalingGroup).to receive(:new).with('ASG123') { asg }
|
137
|
+
expect(@stack.resource_statuses[:asg_instances]['ASG123']['i-abcd1234'][:status]).to eq(:some_status)
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'should add instance status info for instances NOT in ASGs' do
|
141
|
+
instance = double CfDeployer::Driver::Instance
|
142
|
+
rs = { 'AWS::EC2::Instance' => { 'i-abcd1234' => :some_status } }
|
143
|
+
expect(@cf_driver).to receive(:resource_statuses) { rs }
|
144
|
+
expect(CfDeployer::Driver::Instance).to receive(:new).with('i-abcd1234') { instance }
|
145
|
+
expect(instance).to receive(:status) { { :status => :some_status } }
|
146
|
+
expect(@stack.resource_statuses[:instances]['i-abcd1234'][:status]).to eq(:some_status)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "status_presenter" do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@presenter = CfDeployer::StatusPresenter.new({}, 'all')
|
7
|
+
end
|
8
|
+
|
9
|
+
context "#filter_for_verbosity" do
|
10
|
+
it "should filter out all resources if the verbosity is 'stacks'" do
|
11
|
+
info = {
|
12
|
+
:web => {
|
13
|
+
:stack1 => {
|
14
|
+
:status => :ready,
|
15
|
+
:resources => { :some_resource_type => [ :resource_1, :resource_2 ] }
|
16
|
+
}
|
17
|
+
}
|
18
|
+
}
|
19
|
+
|
20
|
+
stacks_presenter = CfDeployer::StatusPresenter.new({}, 'stacks')
|
21
|
+
filtered_info = stacks_presenter.send :filter_for_verbosity, info
|
22
|
+
|
23
|
+
expect(filtered_info[:resources]).to eq(nil)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should only keep :instances and :asg_instances when verbosity is 'instances'" do
|
27
|
+
info = {
|
28
|
+
:web => {
|
29
|
+
:stack1 => {
|
30
|
+
:status => :ready,
|
31
|
+
:resources => {
|
32
|
+
:instances => [ :instance_1 ],
|
33
|
+
:asg_instances => [ :asg_instance_1 ],
|
34
|
+
:some_other_resource => [ :other_resource ]
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
instances__presenter = CfDeployer::StatusPresenter.new({}, 'instances')
|
41
|
+
filtered_info = instances__presenter.send :filter_for_verbosity, info
|
42
|
+
|
43
|
+
expect(filtered_info[:web][:stack1][:resources][:instances]).to eq(info[:web][:stack1][:resources][:instances])
|
44
|
+
expect(filtered_info[:web][:stack1][:resources][:asg_instances]).to eq(info[:web][:stack1][:resources][:asg_instances])
|
45
|
+
expect(filtered_info[:web][:stack1][:resources][:some_other_resource]).to eq(nil)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context "#tableize" do
|
50
|
+
before do
|
51
|
+
@table_data = [
|
52
|
+
[ 'r1c1',
|
53
|
+
'r2c1',
|
54
|
+
'r3c1'
|
55
|
+
],
|
56
|
+
[ 'r1c2',
|
57
|
+
'r2c2'
|
58
|
+
]
|
59
|
+
]
|
60
|
+
|
61
|
+
@table_output = @presenter.send :tableize, @table_data
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should have one more row than the max of each column's number of rows" do
|
65
|
+
expect(@table_output.size).to eq(4)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should have a table seperator as the last row" do
|
69
|
+
expect(@table_output.last).to eq(@presenter.send :table_seperator)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should draw a column seperator and pad the left column" do
|
73
|
+
expected_pad = ' ' * (CfDeployer::StatusPresenter::UNPADDED_TABLE_CELL_WIDTH - CfDeployer::StatusPresenter::PAD.size)
|
74
|
+
expected_row = @table_data[0][0] + expected_pad + '|' + @table_data[1][0]
|
75
|
+
expect(@table_output.first).to eq(expected_row)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "#middle_truncate_ljust" do
|
80
|
+
it "should replace the middle of a long string with an elipsis" do
|
81
|
+
long_str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
82
|
+
truncated_str = @presenter.send :middle_truncate_ljust, long_str, 40
|
83
|
+
expect(truncated_str).to eq('abcdefghijklmnopq...GHIJKLMNOPQRSTUVWXYZ')
|
84
|
+
expect(truncated_str.size).to eq(40)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context "#visible_length" do
|
89
|
+
it "should return the length of the string without ANSI color code characters" do
|
90
|
+
colored_string = "a \e[31mcolored\e[0m string"
|
91
|
+
expect(@presenter.send(:visible_length, colored_string)).to eq(16)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
context "#invisible_length" do
|
96
|
+
it "should return the length of the ANSI color code characters" do
|
97
|
+
colored_string = "a \e[31mcolored\e[0m string"
|
98
|
+
expect(@presenter.send(:invisible_length, colored_string)).to eq(9)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context "#centered" do
|
103
|
+
it "should rjust a string to the center of the table" do
|
104
|
+
expect(@presenter.send(:centered, 'Some String')).to eq(' Some String')
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
metadata
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cf_deployer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.2.8
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jame Brechtel
|
8
|
+
- Peter Zhao
|
9
|
+
- Patrick McFadden
|
10
|
+
- Rob Sweet
|
11
|
+
autorequire:
|
12
|
+
bindir: bin
|
13
|
+
cert_chain: []
|
14
|
+
date: 2014-06-25 00:00:00.000000000 Z
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: aws-sdk
|
18
|
+
requirement: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: log4r
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - '>='
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '0'
|
37
|
+
type: :runtime
|
38
|
+
prerelease: false
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
- !ruby/object:Gem::Dependency
|
45
|
+
name: thor
|
46
|
+
requirement: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - '>='
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '0'
|
51
|
+
type: :runtime
|
52
|
+
prerelease: false
|
53
|
+
version_requirements: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - '>='
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: '0'
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: rainbow
|
60
|
+
requirement: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
type: :runtime
|
66
|
+
prerelease: false
|
67
|
+
version_requirements: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - '>='
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
description: For automatic blue green deployment flow on CloudFormation.
|
73
|
+
email:
|
74
|
+
- jbrechtel@gmail.com
|
75
|
+
- peter.qs.zhao@gmail.com
|
76
|
+
- pemcfadden@gmail.com
|
77
|
+
- rob@ldg.net
|
78
|
+
executables:
|
79
|
+
- cf_deploy
|
80
|
+
extensions: []
|
81
|
+
extra_rdoc_files: []
|
82
|
+
files:
|
83
|
+
- .gitignore
|
84
|
+
- ChangeLog.md
|
85
|
+
- DETAILS.md
|
86
|
+
- FAQ.md
|
87
|
+
- Gemfile
|
88
|
+
- Gemfile.lock
|
89
|
+
- LICENSE
|
90
|
+
- QUICKSTART.md
|
91
|
+
- README.md
|
92
|
+
- Rakefile
|
93
|
+
- bin/cf_deploy
|
94
|
+
- cf_deployer.gemspec
|
95
|
+
- lib/cf_deployer.rb
|
96
|
+
- lib/cf_deployer/application.rb
|
97
|
+
- lib/cf_deployer/application_error.rb
|
98
|
+
- lib/cf_deployer/aws_constants.rb
|
99
|
+
- lib/cf_deployer/cli.rb
|
100
|
+
- lib/cf_deployer/component.rb
|
101
|
+
- lib/cf_deployer/config_loader.rb
|
102
|
+
- lib/cf_deployer/config_validation.rb
|
103
|
+
- lib/cf_deployer/defaults.rb
|
104
|
+
- lib/cf_deployer/deployment_strategy/auto_scaling_group_swap.rb
|
105
|
+
- lib/cf_deployer/deployment_strategy/base.rb
|
106
|
+
- lib/cf_deployer/deployment_strategy/blue_green.rb
|
107
|
+
- lib/cf_deployer/deployment_strategy/cname_swap.rb
|
108
|
+
- lib/cf_deployer/deployment_strategy/create_or_update.rb
|
109
|
+
- lib/cf_deployer/driver/auto_scaling_group.rb
|
110
|
+
- lib/cf_deployer/driver/cloud_formation_driver.rb
|
111
|
+
- lib/cf_deployer/driver/dry_run.rb
|
112
|
+
- lib/cf_deployer/driver/elb_driver.rb
|
113
|
+
- lib/cf_deployer/driver/instance.rb
|
114
|
+
- lib/cf_deployer/driver/route53_driver.rb
|
115
|
+
- lib/cf_deployer/driver/verisign_driver.rb
|
116
|
+
- lib/cf_deployer/hook.rb
|
117
|
+
- lib/cf_deployer/logger.rb
|
118
|
+
- lib/cf_deployer/stack.rb
|
119
|
+
- lib/cf_deployer/status_presenter.rb
|
120
|
+
- lib/cf_deployer/version.rb
|
121
|
+
- spec/fakes/instance.rb
|
122
|
+
- spec/fakes/route53_client.rb
|
123
|
+
- spec/fakes/stack.rb
|
124
|
+
- spec/functional/deploy_spec.rb
|
125
|
+
- spec/functional/kill_inactive_spec.rb
|
126
|
+
- spec/functional_spec_helper.rb
|
127
|
+
- spec/spec_helper.rb
|
128
|
+
- spec/unit/application_spec.rb
|
129
|
+
- spec/unit/component_spec.rb
|
130
|
+
- spec/unit/config_loader_spec.rb
|
131
|
+
- spec/unit/config_validation_spec.rb
|
132
|
+
- spec/unit/deployment_strategy/auto_scaling_group_swap_spec.rb
|
133
|
+
- spec/unit/deployment_strategy/base_spec.rb
|
134
|
+
- spec/unit/deployment_strategy/cname_swap_spec.rb
|
135
|
+
- spec/unit/deployment_strategy/create_or_update_spec.rb
|
136
|
+
- spec/unit/deployment_strategy/deployment_strategy_spec.rb
|
137
|
+
- spec/unit/driver/auto_scaling_group_spec.rb
|
138
|
+
- spec/unit/driver/cloud_formation_spec.rb
|
139
|
+
- spec/unit/driver/elb_spec.rb
|
140
|
+
- spec/unit/driver/instance_spec.rb
|
141
|
+
- spec/unit/driver/route53_spec.rb
|
142
|
+
- spec/unit/driver/verisign_spec.rb
|
143
|
+
- spec/unit/hook_spec.rb
|
144
|
+
- spec/unit/stack_spec.rb
|
145
|
+
- spec/unit/status_presenter_spec.rb
|
146
|
+
homepage: http://github.com/manheim/cf_deployer
|
147
|
+
licenses:
|
148
|
+
- MIT
|
149
|
+
metadata: {}
|
150
|
+
post_install_message:
|
151
|
+
rdoc_options: []
|
152
|
+
require_paths:
|
153
|
+
- lib
|
154
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
155
|
+
requirements:
|
156
|
+
- - '>='
|
157
|
+
- !ruby/object:Gem::Version
|
158
|
+
version: '0'
|
159
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
160
|
+
requirements:
|
161
|
+
- - '>='
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '0'
|
164
|
+
requirements: []
|
165
|
+
rubyforge_project:
|
166
|
+
rubygems_version: 2.0.3
|
167
|
+
signing_key:
|
168
|
+
specification_version: 4
|
169
|
+
summary: Support multiple components deployment using CloudFormation templates with
|
170
|
+
multiple blue green strategies.
|
171
|
+
test_files:
|
172
|
+
- spec/fakes/instance.rb
|
173
|
+
- spec/fakes/route53_client.rb
|
174
|
+
- spec/fakes/stack.rb
|
175
|
+
- spec/functional/deploy_spec.rb
|
176
|
+
- spec/functional/kill_inactive_spec.rb
|
177
|
+
- spec/functional_spec_helper.rb
|
178
|
+
- spec/spec_helper.rb
|
179
|
+
- spec/unit/application_spec.rb
|
180
|
+
- spec/unit/component_spec.rb
|
181
|
+
- spec/unit/config_loader_spec.rb
|
182
|
+
- spec/unit/config_validation_spec.rb
|
183
|
+
- spec/unit/deployment_strategy/auto_scaling_group_swap_spec.rb
|
184
|
+
- spec/unit/deployment_strategy/base_spec.rb
|
185
|
+
- spec/unit/deployment_strategy/cname_swap_spec.rb
|
186
|
+
- spec/unit/deployment_strategy/create_or_update_spec.rb
|
187
|
+
- spec/unit/deployment_strategy/deployment_strategy_spec.rb
|
188
|
+
- spec/unit/driver/auto_scaling_group_spec.rb
|
189
|
+
- spec/unit/driver/cloud_formation_spec.rb
|
190
|
+
- spec/unit/driver/elb_spec.rb
|
191
|
+
- spec/unit/driver/instance_spec.rb
|
192
|
+
- spec/unit/driver/route53_spec.rb
|
193
|
+
- spec/unit/driver/verisign_spec.rb
|
194
|
+
- spec/unit/hook_spec.rb
|
195
|
+
- spec/unit/stack_spec.rb
|
196
|
+
- spec/unit/status_presenter_spec.rb
|
197
|
+
has_rdoc:
|