cf_deployer 1.2.8
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/.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:
|