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,356 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
describe "load config settings" do
|
3
|
+
|
4
|
+
before :each do
|
5
|
+
@config_file = File.expand_path("../../../tmp/test_config.yml", __FILE__)
|
6
|
+
@base_json = File.expand_path("../../../tmp/base.json", __FILE__)
|
7
|
+
@api_json = File.expand_path("../../../tmp/api.json", __FILE__)
|
8
|
+
@front_end_json = File.expand_path("../../../tmp/front-end.json", __FILE__)
|
9
|
+
@very_simple_json = File.expand_path("../../../tmp/very-simple.json", __FILE__)
|
10
|
+
@json_with_erb = File.expand_path("../../../tmp/json-with-erb.json", __FILE__)
|
11
|
+
|
12
|
+
base_json = <<-eos
|
13
|
+
{
|
14
|
+
"Parameters" : {},
|
15
|
+
"Outputs" : {
|
16
|
+
"vpc-id" : {},
|
17
|
+
"AutoScalingGroupName" : {},
|
18
|
+
"public-subnet-id" : {}
|
19
|
+
}
|
20
|
+
}
|
21
|
+
eos
|
22
|
+
|
23
|
+
json_with_erb = <<-eos
|
24
|
+
{
|
25
|
+
"Description": "<%= config[:inputs][:environment] %>"
|
26
|
+
}
|
27
|
+
eos
|
28
|
+
|
29
|
+
very_simple_json = <<-eos
|
30
|
+
{
|
31
|
+
"Parameters" : {},
|
32
|
+
"Outputs" : {
|
33
|
+
"vpc-id" : {},
|
34
|
+
"public-subnet-id" : {}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
eos
|
38
|
+
|
39
|
+
api_json = <<-eos
|
40
|
+
{
|
41
|
+
"Parameters" : {
|
42
|
+
"require-basic-auth" : { "Default" : "true" }
|
43
|
+
}
|
44
|
+
}
|
45
|
+
eos
|
46
|
+
|
47
|
+
front_end_json = <<-eos
|
48
|
+
{
|
49
|
+
"Parameters" : {
|
50
|
+
"require-basic-auth" : {},
|
51
|
+
"mail-server" : {}
|
52
|
+
},
|
53
|
+
"Outputs" : {
|
54
|
+
"AutoScalingGroupName" : {},
|
55
|
+
"elb-cname" : {}
|
56
|
+
}
|
57
|
+
}
|
58
|
+
eos
|
59
|
+
|
60
|
+
File.open(@api_json, 'w') {|f| f.write(api_json) }
|
61
|
+
File.open(@base_json, 'w') {|f| f.write(base_json) }
|
62
|
+
File.open(@front_end_json, 'w') {|f| f.write(front_end_json) }
|
63
|
+
File.open(@very_simple_json, 'w') {|f| f.write(very_simple_json) }
|
64
|
+
File.open(@json_with_erb, 'w') {|f| f.write(json_with_erb) }
|
65
|
+
|
66
|
+
|
67
|
+
yaml_string = <<-eos
|
68
|
+
application: myApp
|
69
|
+
components:
|
70
|
+
base:
|
71
|
+
deployment-strategy: create-or-update
|
72
|
+
inputs:
|
73
|
+
foobar: <%= environment %>.IsGreat
|
74
|
+
api:
|
75
|
+
deployment-strategy: auto-scaling-group-swap
|
76
|
+
depends-on:
|
77
|
+
- base
|
78
|
+
inputs:
|
79
|
+
require-basic-auth: true
|
80
|
+
timeout: 90
|
81
|
+
mail-server: http://api.abc.com
|
82
|
+
front-end:
|
83
|
+
deployment-strategy: cname-swap
|
84
|
+
depends-on:
|
85
|
+
- base
|
86
|
+
- api
|
87
|
+
inputs:
|
88
|
+
cname: front-end.myserver.com
|
89
|
+
settings:
|
90
|
+
keep-previous-stack: false
|
91
|
+
very-simple:
|
92
|
+
json-with-erb:
|
93
|
+
|
94
|
+
inputs:
|
95
|
+
require-basic-auth: false
|
96
|
+
timeout: 300
|
97
|
+
mail-server: http://abc.com
|
98
|
+
cname: myserver.com
|
99
|
+
|
100
|
+
|
101
|
+
environments:
|
102
|
+
dev:
|
103
|
+
inputs:
|
104
|
+
mail-server: http://dev.abc.com
|
105
|
+
timeout: 60
|
106
|
+
production:
|
107
|
+
inputs:
|
108
|
+
requires-basic-auth: true
|
109
|
+
mail-server: http://prod.abc.com
|
110
|
+
components:
|
111
|
+
front-end:
|
112
|
+
inputs:
|
113
|
+
cname: prod-front-end.myserver.com
|
114
|
+
eos
|
115
|
+
File.open(@config_file, 'w') {|f| f.write(yaml_string) }
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
before :each do
|
120
|
+
ENV['timeout'] = nil
|
121
|
+
ENV['cfdeploy_settings_timeout'] = nil
|
122
|
+
end
|
123
|
+
|
124
|
+
it "all the keys should be symbols in config" do
|
125
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file})
|
126
|
+
config[:components][:base][:'deployment-strategy'].should eq('create-or-update')
|
127
|
+
config['components'].should be_nil
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should copy application, environment, component to component settings" do
|
131
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file, :environment => 'uat'})
|
132
|
+
config[:components][:api][:settings][:application].should eq("myApp")
|
133
|
+
config[:components][:api][:settings][:component].should eq("api")
|
134
|
+
config[:components][:api][:settings][:environment].should eq("uat")
|
135
|
+
config[:components][:base][:settings][:application].should eq("myApp")
|
136
|
+
config[:components][:base][:settings][:component].should eq("base")
|
137
|
+
config[:components][:base][:settings][:environment].should eq("uat")
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should copy region to coponent settings" do
|
141
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file, :environment => 'uat', :region => 'us-west-1'})
|
142
|
+
config[:components][:api][:settings][:region].should eq("us-west-1")
|
143
|
+
config[:components][:base][:settings][:region].should eq("us-west-1")
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should copy application, environment, component to component inputs" do
|
147
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file, :environment => 'uat'})
|
148
|
+
config[:components][:api][:inputs][:application].should eq("myApp")
|
149
|
+
config[:components][:api][:inputs][:component].should eq("api")
|
150
|
+
config[:components][:api][:inputs][:environment].should eq("uat")
|
151
|
+
config[:components][:base][:inputs][:application].should eq("myApp")
|
152
|
+
config[:components][:base][:inputs][:component].should eq("base")
|
153
|
+
config[:components][:base][:inputs][:environment].should eq("uat")
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should copy region to coponent inputs" do
|
157
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file, :environment => 'uat', :region => 'us-west-1'})
|
158
|
+
config[:components][:api][:inputs][:region].should eq("us-west-1")
|
159
|
+
config[:components][:base][:inputs][:region].should eq("us-west-1")
|
160
|
+
end
|
161
|
+
|
162
|
+
it "config_dir option should be copied to component context" do
|
163
|
+
config_dir = File.dirname(@config_file)
|
164
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file, :environment => 'uat'})
|
165
|
+
config[:components][:api][:config_dir].should eq(config_dir)
|
166
|
+
config[:components][:base][:config_dir].should eq(config_dir)
|
167
|
+
config[:components][:'front-end'][:config_dir].should eq(config_dir)
|
168
|
+
end
|
169
|
+
|
170
|
+
it "component's settings should be merged to common settings" do
|
171
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file, :environment => 'uat'})
|
172
|
+
config[:components][:api][:inputs][:'timeout'].should eq(90)
|
173
|
+
config[:components][:api][:inputs][:'require-basic-auth'].should eq(true)
|
174
|
+
config[:components][:api][:inputs][:'mail-server'].should eq('http://api.abc.com')
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
it "environment's settings should be merged to component settings" do
|
179
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file, :environment => 'dev'})
|
180
|
+
config[:components][:api][:inputs][:'timeout'].should eq(60)
|
181
|
+
config[:components][:api][:inputs][:'require-basic-auth'].should eq(true)
|
182
|
+
config[:components][:api][:inputs][:'mail-server'].should eq('http://dev.abc.com')
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should merge environment's components to component settings" do
|
186
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file, :environment => 'production'})
|
187
|
+
config[:components][:'front-end'][:inputs][:'cname'].should eq('prod-front-end.myserver.com')
|
188
|
+
config[:components][:api][:inputs][:'cname'].should eq('myserver.com')
|
189
|
+
end
|
190
|
+
|
191
|
+
it "environment variables without prefix 'cfdeploy_settings_' should not be merged to components settings" do
|
192
|
+
ENV['timeout'] = "180"
|
193
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file, :environment => 'dev'})
|
194
|
+
config[:components][:api][:inputs][:'timeout'].should eq(60)
|
195
|
+
end
|
196
|
+
|
197
|
+
it "should merge environment variables should be merged to components settings" do
|
198
|
+
ENV['cfdeploy_inputs_timeout'] = "180"
|
199
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file, :environment => 'dev'})
|
200
|
+
config[:components][:api][:inputs][:'timeout'].should eq("180")
|
201
|
+
end
|
202
|
+
|
203
|
+
it "cli settings should be merged to components settings" do
|
204
|
+
ENV['cfdeploy_settings_timeout'] = "180"
|
205
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file, :environment => 'dev',:cli_overrides => {:settings => {:timeout => 45}}})
|
206
|
+
config[:components][:api][:settings][:'timeout'].should eq(45)
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should set cloudFormation parameter names into each component" do
|
210
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file})
|
211
|
+
config[:components][:base][:defined_parameters].should eq({})
|
212
|
+
config[:components][:api][:defined_parameters].should eq({:'require-basic-auth' => {:Default => "true"}})
|
213
|
+
config[:components][:'front-end'][:defined_parameters].should eq({:'require-basic-auth' => {}, :'mail-server' => {}})
|
214
|
+
end
|
215
|
+
|
216
|
+
it "should set cloudFormation output names into each component" do
|
217
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file})
|
218
|
+
config[:components][:base][:defined_outputs].should eq({:'vpc-id' => {}, :'AutoScalingGroupName'=>{}, :'public-subnet-id'=>{}})
|
219
|
+
config[:components][:api][:defined_outputs].should eq({})
|
220
|
+
config[:components][:'front-end'][:defined_outputs].should eq({:'AutoScalingGroupName'=>{}, :'elb-cname' => {}})
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should remove common settings in order not to confuse us" do
|
224
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file})
|
225
|
+
config[:settings].should be_nil
|
226
|
+
end
|
227
|
+
|
228
|
+
it "should set default elb-name-output for cname-swap strategy" do
|
229
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file})
|
230
|
+
config[:components][:'front-end'][:settings][:'elb-name-output'].should eq('ELBName')
|
231
|
+
end
|
232
|
+
|
233
|
+
it "should set default auto-scaling-group-name-output for cname-swap strategy" do
|
234
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file})
|
235
|
+
config[:components][:api][:settings][:'auto-scaling-group-name-output'].should eq([ CfDeployer::Defaults::AutoScalingGroupName ])
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should set auto-scaling-group-name-output to default if auto-scaling-group-name exists in output for create-or-update strategy" do
|
239
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file})
|
240
|
+
config[:components][:base][:settings][:'auto-scaling-group-name-output'].should eq([ CfDeployer::Defaults::AutoScalingGroupName ])
|
241
|
+
end
|
242
|
+
|
243
|
+
it "should not set auto-scaling-group-name-output to default if auto-scaling-group-name does not exists in output for create-or-update strategy" do
|
244
|
+
base_json = <<-eos
|
245
|
+
{
|
246
|
+
"Outputs" : {
|
247
|
+
}
|
248
|
+
}
|
249
|
+
eos
|
250
|
+
|
251
|
+
File.open(@base_json, 'w') {|f| f.write(base_json) }
|
252
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file})
|
253
|
+
config[:components][:'base'][:settings][:'auto-scaling-group-name-output'].should be_nil
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should set auto-scaling-group-name-output to default if auto-scaling-group-name exists in output for cname-swap strategy" do
|
257
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file})
|
258
|
+
config[:components][:'front-end'][:settings][:'auto-scaling-group-name-output'].should eq([ CfDeployer::Defaults::AutoScalingGroupName ])
|
259
|
+
end
|
260
|
+
|
261
|
+
it "should set raise-error-for-unused-inputs to default" do
|
262
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file})
|
263
|
+
config[:components][:'front-end'][:settings][:'raise-error-for-unused-inputs'].should eq(CfDeployer::Defaults::RaiseErrorForUnusedInputs)
|
264
|
+
end
|
265
|
+
|
266
|
+
it "should not set auto-scaling-group-name-output to default if auto-scaling-group-name does not exists in output for cname-swap strategy" do
|
267
|
+
front_end_json = <<-eos
|
268
|
+
{
|
269
|
+
"Outputs" : {
|
270
|
+
"elb-cname" : {}
|
271
|
+
}
|
272
|
+
}
|
273
|
+
eos
|
274
|
+
|
275
|
+
File.open(@front_end_json, 'w') {|f| f.write(front_end_json) }
|
276
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file})
|
277
|
+
config[:components][:'front-end'][:settings][:'auto-scaling-group-name-output'].should be_nil
|
278
|
+
end
|
279
|
+
|
280
|
+
it "should ERB the config file and provide the environment in the binding" do
|
281
|
+
config = CfDeployer::ConfigLoader.new.load(:'config-file' => @config_file, :environment => 'DrWho')
|
282
|
+
config[:components][:base][:inputs][:'foobar'].should eq('DrWho.IsGreat')
|
283
|
+
end
|
284
|
+
|
285
|
+
it "should ERB the component JSON and make the parsed template available" do
|
286
|
+
config = CfDeployer::ConfigLoader.new.load(:'config-file' => @config_file, :environment => 'DrWho')
|
287
|
+
CfDeployer::ConfigLoader.component_json('json-with-erb', config[:components][:'json-with-erb']).should include('DrWho')
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'should set default keep-previous-stack to true' do
|
291
|
+
config = CfDeployer::ConfigLoader.new.load(:'config-file' => @config_file)
|
292
|
+
config[:components][:api][:settings][:'keep-previous-stack'].should eq(CfDeployer::Defaults::KeepPreviousStack)
|
293
|
+
end
|
294
|
+
|
295
|
+
it 'should keep keep-previous-stack setting' do
|
296
|
+
config = CfDeployer::ConfigLoader.new.load(:'config-file' => @config_file)
|
297
|
+
config[:components][:'front-end'][:settings][:'keep-previous-stack'].should be_false
|
298
|
+
end
|
299
|
+
|
300
|
+
context 'targets' do
|
301
|
+
|
302
|
+
it 'should use all components as targets if no targets are specified' do
|
303
|
+
config = CfDeployer::ConfigLoader.new.load(:'config-file' => @config_file)
|
304
|
+
config[:targets].should eq(['base', 'api', 'front-end', 'very-simple', 'json-with-erb'])
|
305
|
+
end
|
306
|
+
|
307
|
+
it 'should keep targets if targets are specified' do
|
308
|
+
config = CfDeployer::ConfigLoader.new.load(:'config-file' => @config_file, :component => ['api', 'web'])
|
309
|
+
config[:targets].should eq(['api', 'web'])
|
310
|
+
end
|
311
|
+
|
312
|
+
end
|
313
|
+
|
314
|
+
context 'load CF template' do
|
315
|
+
it "should be able to load CF template even though inputs have referencing value not resolved" do
|
316
|
+
api_template = <<-eos
|
317
|
+
{
|
318
|
+
"Parameters" : {
|
319
|
+
"db" : "<%= config[:inputs][:db]%>",
|
320
|
+
"url" : "<%= config[:inputs][:url]%>"
|
321
|
+
},
|
322
|
+
"Outputs" : {}
|
323
|
+
}
|
324
|
+
eos
|
325
|
+
File.open(@api_json, 'w') {|f| f.write(api_template) }
|
326
|
+
|
327
|
+
base_template = <<-eos
|
328
|
+
{
|
329
|
+
"Outputs" : {
|
330
|
+
"elb-cname" : {}
|
331
|
+
}
|
332
|
+
}
|
333
|
+
eos
|
334
|
+
File.open(@base_json, 'w') {|f| f.write(base_template) }
|
335
|
+
|
336
|
+
config = <<-eos
|
337
|
+
application: myApp
|
338
|
+
components:
|
339
|
+
base:
|
340
|
+
api:
|
341
|
+
depends-on:
|
342
|
+
- base
|
343
|
+
inputs:
|
344
|
+
url: http://abc.com
|
345
|
+
db:
|
346
|
+
component: base
|
347
|
+
output-key: elb-cname
|
348
|
+
eos
|
349
|
+
File.open(@config_file, 'w') {|f| f.write(config) }
|
350
|
+
|
351
|
+
config = CfDeployer::ConfigLoader.new.load({:'config-file' => @config_file})
|
352
|
+
config[:components][:'api'][:defined_parameters].should eq({ db:'base::elb-cname', url:'http://abc.com'})
|
353
|
+
end
|
354
|
+
|
355
|
+
end
|
356
|
+
end
|