eb_deployer_updated 0.8.0

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.
Files changed (67) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/.travis.yml +14 -0
  6. data/CHANGELOG.md +127 -0
  7. data/Gemfile +10 -0
  8. data/LICENSE +22 -0
  9. data/README.md +136 -0
  10. data/Rakefile +12 -0
  11. data/TODOS.md +11 -0
  12. data/bin/eb_deploy +13 -0
  13. data/eb_deployer.gemspec +22 -0
  14. data/lib/eb_deployer/application.rb +96 -0
  15. data/lib/eb_deployer/aws_driver/beanstalk.rb +158 -0
  16. data/lib/eb_deployer/aws_driver/cloud_formation_driver.rb +53 -0
  17. data/lib/eb_deployer/aws_driver/s3_driver.rb +35 -0
  18. data/lib/eb_deployer/aws_driver.rb +8 -0
  19. data/lib/eb_deployer/cf_event_source.rb +26 -0
  20. data/lib/eb_deployer/cloud_formation_provisioner.rb +120 -0
  21. data/lib/eb_deployer/component.rb +45 -0
  22. data/lib/eb_deployer/config_loader.rb +64 -0
  23. data/lib/eb_deployer/default_component.rb +32 -0
  24. data/lib/eb_deployer/default_config.rb +20 -0
  25. data/lib/eb_deployer/default_config.yml +159 -0
  26. data/lib/eb_deployer/deployment_strategy/blue_green.rb +79 -0
  27. data/lib/eb_deployer/deployment_strategy/blue_only.rb +45 -0
  28. data/lib/eb_deployer/deployment_strategy/inplace_update.rb +16 -0
  29. data/lib/eb_deployer/deployment_strategy.rb +20 -0
  30. data/lib/eb_deployer/eb_environment.rb +204 -0
  31. data/lib/eb_deployer/eb_event_source.rb +35 -0
  32. data/lib/eb_deployer/environment.rb +60 -0
  33. data/lib/eb_deployer/event_poller.rb +51 -0
  34. data/lib/eb_deployer/package.rb +39 -0
  35. data/lib/eb_deployer/resource_stacks.rb +20 -0
  36. data/lib/eb_deployer/smoke_test.rb +23 -0
  37. data/lib/eb_deployer/tasks.rb +45 -0
  38. data/lib/eb_deployer/throttling_handling.rb +17 -0
  39. data/lib/eb_deployer/utils.rb +33 -0
  40. data/lib/eb_deployer/version.rb +3 -0
  41. data/lib/eb_deployer/version_cleaner.rb +30 -0
  42. data/lib/eb_deployer.rb +339 -0
  43. data/lib/generators/eb_deployer/install/install_generator.rb +82 -0
  44. data/lib/generators/eb_deployer/install/templates/eb_deployer.rake +1 -0
  45. data/lib/generators/eb_deployer/install/templates/eb_deployer.yml.erb +181 -0
  46. data/lib/generators/eb_deployer/install/templates/ebextensions/01_postgres_packages.config +5 -0
  47. data/lib/generators/eb_deployer/install/templates/postgres_rds.json +88 -0
  48. data/test/aws_driver_stubs.rb +350 -0
  49. data/test/beanstalk_test.rb +23 -0
  50. data/test/blue_green_deploy_test.rb +114 -0
  51. data/test/blue_only_deploy_test.rb +78 -0
  52. data/test/cf_event_poller_test.rb +32 -0
  53. data/test/cloud_formation_provisioner_test.rb +47 -0
  54. data/test/config_loader_test.rb +205 -0
  55. data/test/deploy_test.rb +42 -0
  56. data/test/eb_environment_test.rb +120 -0
  57. data/test/eb_event_poller_test.rb +32 -0
  58. data/test/inplace_update_deploy_test.rb +110 -0
  59. data/test/multi_components_deploy_test.rb +164 -0
  60. data/test/rails_generators_test.rb +67 -0
  61. data/test/resources_deploy_test.rb +191 -0
  62. data/test/smoke_test_test.rb +23 -0
  63. data/test/template_deploy_test.rb +13 -0
  64. data/test/test_helper.rb +68 -0
  65. data/test/tier_setting_deploy_test.rb +24 -0
  66. data/test/versions_deploy_test.rb +120 -0
  67. metadata +194 -0
@@ -0,0 +1,88 @@
1
+ {
2
+ "Outputs": {
3
+ "RDSHost": {
4
+ "Description": "Database endpoint address",
5
+ "Value": { "Fn::GetAtt": ["RDSDatabase", "Endpoint.Address"] }
6
+ },
7
+ "RDSPort": {
8
+ "Description": "Database endpoint port",
9
+ "Value": { "Fn::GetAtt": ["RDSDatabase", "Endpoint.Port"] }
10
+ },
11
+ "RDSPassSecurityGroup": {
12
+ "Description": "Security group assign to ec2 instance that need access to rds instance",
13
+ "Value": {
14
+ "Ref": "RDSPassSecurityGroup"
15
+ }
16
+ }
17
+ },
18
+
19
+ "Parameters": {
20
+ "DBUser": {
21
+ "NoEcho": "false",
22
+ "Description": "The name of master user for the client DB Instance.",
23
+ "Type": "String",
24
+ "ConstraintDescription": "must begin with a letter and contain only alphanumeric characters"
25
+ },
26
+
27
+ "DBName": {
28
+ "NoEcho": "false",
29
+ "Description": "The DB Name of the RDS instance",
30
+ "Type": "String",
31
+ "ConstraintDescription": "must contain only alphanumeric characters"
32
+ },
33
+
34
+ "DBPassword": {
35
+ "NoEcho": "true",
36
+ "Description": "The master password for the DB instance.",
37
+ "Type": "String",
38
+ "ConstraintDescription": "must contain only alphanumeric characters"
39
+ }
40
+ },
41
+
42
+ "Resources": {
43
+ "RDSDBSecurityGroup": {
44
+ "Type": "AWS::RDS::DBSecurityGroup",
45
+ "Properties": {
46
+ "GroupDescription": "Enable database access to Beanstalk application",
47
+ "DBSecurityGroupIngress": {
48
+ "EC2SecurityGroupName": {
49
+ "Ref": "RDSPassSecurityGroup"
50
+ }
51
+ }
52
+ }
53
+ },
54
+
55
+ "RDSDatabase": {
56
+ "Type": "AWS::RDS::DBInstance",
57
+ "DeletionPolicy": "Delete",
58
+ "Properties": {
59
+ "MasterUsername": {
60
+ "Ref": "DBUser"
61
+ },
62
+ "DBSecurityGroups": [
63
+ {
64
+ "Ref": "RDSDBSecurityGroup"
65
+ }
66
+ ],
67
+ "DBInstanceClass": "db.m1.small",
68
+ "AllocatedStorage": "5",
69
+ "MultiAZ": "false",
70
+ "EngineVersion": "9.3.3",
71
+ "DBName": {
72
+ "Ref": "DBName"
73
+ },
74
+ "MasterUserPassword": {
75
+ "Ref": "DBPassword"
76
+ },
77
+ "Engine": "postgres"
78
+ }
79
+ },
80
+
81
+ "RDSPassSecurityGroup": {
82
+ "Type": "AWS::EC2::SecurityGroup",
83
+ "Properties": {
84
+ "GroupDescription": "SecurityGroup access RDS database."
85
+ }
86
+ }
87
+ }
88
+ }
@@ -0,0 +1,350 @@
1
+ class EBStub
2
+ attr_reader :envs, :events
3
+ def initialize
4
+ @apps = []
5
+ @envs = {}
6
+ @versions = {}
7
+ @envs_been_deleted = {}
8
+ @versions_deleted = {}
9
+ @event_fetched_times = 0
10
+ @envs_health_states = {}
11
+ @events = nil
12
+ end
13
+
14
+ def create_application(app)
15
+ raise 'already exists' if application_exists?(app)
16
+ @apps << app
17
+ end
18
+
19
+ def delete_application(app)
20
+ raise "there are environments running for this app" unless environment_names_for_application(app).empty?
21
+ @apps.delete(app)
22
+ end
23
+
24
+ def application_exists?(app)
25
+ @apps.include?(app)
26
+ end
27
+
28
+ def create_environment(app, env, solution_stack, cname_prefix, version, tier, tags, settings, template_name)
29
+ raise 'cname prefix is not avaible' if @envs.values.detect { |value| value[:cname_prefix] == cname_prefix }
30
+ raise "env name #{env} is longer than 23 chars" if env.size > 23
31
+ raise "app not exists" unless application_exists?(app)
32
+ @envs[env_key(app, env)] = {
33
+ :name => env,
34
+ :application => app,
35
+ :solution_stack => solution_stack,
36
+ :version => version,
37
+ :cname_prefix => cname_prefix,
38
+ :tier => tier,
39
+ :tags => tags,
40
+ :settings => settings,
41
+ :template_name => template_name }
42
+ set_env_ready(app, env, false)
43
+ end
44
+
45
+ def delete_environment(app, env)
46
+ @envs.delete(env_key(app, env))
47
+ @envs_been_deleted[app] ||= []
48
+ @envs_been_deleted[app] << env
49
+ end
50
+
51
+ def update_environment_settings(app, env, settings)
52
+ raise "not in ready state, consider waiting for previous action finish by pulling envents" unless env_ready?(app, env)
53
+ @envs[env_key(app, env)].merge!(:settings => settings)
54
+ end
55
+
56
+
57
+ def update_environment(app, env, version, tier, settings, template_name)
58
+ raise "not in ready state, consider waiting for previous action finish by pulling envents" unless env_ready?(app, env)
59
+ @envs[env_key(app, env)].merge!(:version => version, :settings => settings, :tier => tier, :template_name => template_name)
60
+ set_env_ready(app, env, false)
61
+ end
62
+
63
+ def environment_exists?(app_name, env_name)
64
+ @envs.has_key?(env_key(app_name, env_name))
65
+ end
66
+
67
+ def create_application_version(app_name, version_label, source_bundle)
68
+ @versions[app_name] ||= []
69
+ @versions[app_name] << {
70
+ :version_label => version_label,
71
+ :source_bundle => source_bundle,
72
+ :date_created => Time.now,
73
+ :date_updated => Time.now
74
+ }
75
+ end
76
+
77
+ def delete_application_version(app_name, version, delete_source_bundle)
78
+ @versions_deleted[app_name] ||= []
79
+ @versions_deleted[app_name] << version
80
+ @versions[app_name].delete_if { |apv| apv[:version_label] == version }
81
+ end
82
+
83
+ def application_versions(app_name)
84
+ @versions[app_name]
85
+ end
86
+
87
+ def application_version_labels(app_name)
88
+ if @versions[app_name]
89
+ @versions[app_name].map { |appv| appv[:version_label]}
90
+ else
91
+ []
92
+ end
93
+ end
94
+
95
+ # simulating elasticbeanstalk events api behavior
96
+ # use set_events and append_events to set fake events
97
+ def fetch_events(app_name, env_name, options={})
98
+ @event_fetched_times += 1
99
+ set_env_ready(app_name, env_name, true) # assume env become ready after it spit out all the events
100
+
101
+ unless @events # unrestricted mode for testing if no explicit events set
102
+ return [generate_event_from_messages(['Successfully deployed new configuration to environment',
103
+ 'terminateEnvironment completed successfully',
104
+ 'Successfully launched environment',
105
+ 'Completed swapping CNAMEs for environments'
106
+ ], Time.now + @event_fetched_times), nil]
107
+ end
108
+
109
+ events = @events[env_key(app_name, env_name)][@event_fetched_times - 1]
110
+
111
+ if options.has_key?(:start_time)
112
+ start_time = Time.parse(options[:start_time])
113
+ events = events.select { |e| e[:event_date] >= start_time }
114
+ end
115
+
116
+ if limit = options[:max_records]
117
+ events = events[0..limit]
118
+ end
119
+
120
+ [events, nil]
121
+ end
122
+
123
+ # add fake events for each times of fetch events call
124
+ # message passed in should be old to new order
125
+ # e.g. given set_events("myapp", "test", ['a'], ['b', 'c'])
126
+ # then
127
+ # fetch_events('myapp', 'test') # => [{message: 'a'}] for first time
128
+ # fetch_events('myapp', 'test') # => [{message: 'c'}, {message: 'b'}, {message: 'a'}] for the second time call
129
+ def set_events(app_name, env_name, *messages)
130
+ events_seq = []
131
+ messages.each do |messages_for_call_seq|
132
+ if old_events = events_seq.last
133
+ last_event_date = old_events.first && old_events.first[:event_date]
134
+ events_seq << (generate_event_from_messages(messages_for_call_seq, last_event_date) + old_events)
135
+ else
136
+ events_seq << generate_event_from_messages(messages_for_call_seq)
137
+ end
138
+ end
139
+ @events ||= {}
140
+ @events[env_key(app_name, env_name)] = events_seq
141
+ end
142
+
143
+ def environment_cname_prefix(app_name, env_name)
144
+ return unless @envs[env_key(app_name, env_name)]
145
+ @envs[env_key(app_name, env_name)][:cname_prefix]
146
+ end
147
+
148
+ def environment_cname(app_name, env_name)
149
+ return unless @envs[env_key(app_name, env_name)]
150
+ if cname_prefix = environment_cname_prefix(app_name, env_name)
151
+ cname_prefix + ".us-west-1.elasticbeanstalk.com"
152
+ end
153
+ end
154
+
155
+
156
+ def environment_swap_cname(app_name, env1_name, env2_name)
157
+ raise "#{env1_name} not in ready state, consider to wait for previous action finsish by pulling events" unless env_ready?(app_name, env1_name)
158
+
159
+ env1, env2 = @envs[env_key(app_name, env1_name)], @envs[env_key(app_name, env2_name)]
160
+ temp = env1[:cname_prefix]
161
+ env1[:cname_prefix] = env2[:cname_prefix]
162
+ env2[:cname_prefix] = temp
163
+ set_env_ready(app_name, env1_name, false)
164
+ set_env_ready(app_name, env2_name, false)
165
+ end
166
+
167
+ def environment_status(app_name, env_name)
168
+ 'ready'
169
+ end
170
+
171
+ def environment_health_state(app_name, env_name)
172
+ @envs_health_states.fetch(app_name+env_name, 'Green')
173
+ end
174
+
175
+ def environment_verion_label(app_name, env_name)
176
+ @envs[env_key(app_name, env_name)][:version]
177
+ end
178
+
179
+ def list_solution_stack_names
180
+ ["64bit Amazon Linux 2014.09 v1.1.0 running Tomcat 7 Java 7"]
181
+ end
182
+
183
+ #test only
184
+
185
+ def mark_env_health_state_as(app_name, env_name, state)
186
+ @envs_health_states[app_name+env_name] = state
187
+ end
188
+
189
+ def mark_all_envs_ready
190
+ @envs.values.each { |env| set_env_ready(env[:application], env[:name], true) }
191
+ end
192
+
193
+ def set_solution_stacks(names)
194
+ @solution_stacks = names
195
+ end
196
+
197
+ def environment_tier(app_name, env_name)
198
+ @envs[env_key(app_name, env_name)][:tier]
199
+ end
200
+
201
+ def environment_tags(app_name, env_name)
202
+ @envs[env_key(app_name, env_name)][:tags]
203
+ end
204
+
205
+ def environment_settings(app_name, env_name)
206
+ @envs[env_key(app_name, env_name)][:settings]
207
+ end
208
+
209
+ def environment_names_for_application(app)
210
+ @envs.inject([]) do |memo, pair|
211
+ _, env = pair
212
+ memo << env[:name] if env[:application] == app
213
+ memo
214
+ end
215
+ end
216
+
217
+ def environments_been_deleted(app)
218
+ @envs_been_deleted[app] || []
219
+ end
220
+
221
+ def versions_deleted(app_name)
222
+ @versions_deleted[app_name]
223
+ end
224
+
225
+ def template_name(app_name, env_name)
226
+ @envs[env_key(app_name, env_name)][:template_name]
227
+ end
228
+
229
+ private
230
+
231
+ def set_env_ready(app, env, ready)
232
+ if record = @envs[env_key(app, env)]
233
+ record[:ready] = ready
234
+ end
235
+ end
236
+
237
+ def env_ready?(app, env)
238
+ @envs[env_key(app, env)][:ready]
239
+ end
240
+
241
+ def generate_event_from_messages(messages, start_time=Time.now)
242
+ start_time ||= Time.now
243
+ events = messages.map do |m|
244
+ { :message => m }
245
+ end
246
+
247
+ events.each_with_index do |e, i|
248
+ e[:event_date] = start_time + (i + 1)
249
+ end
250
+
251
+ events.reverse
252
+ end
253
+
254
+ def env_key(app, name)
255
+ [app, name].join("-")
256
+ end
257
+
258
+ end
259
+
260
+ class S3Stub
261
+ def initialize
262
+ @buckets = {}
263
+ end
264
+
265
+ def create_bucket(bucket_name)
266
+ @buckets[bucket_name] = {}
267
+ end
268
+
269
+ def bucket_exists?(bucket_name)
270
+ @buckets.has_key?(bucket_name)
271
+ end
272
+
273
+ def objects(bucket_name)
274
+ @buckets[bucket_name]
275
+ end
276
+
277
+ def object_length(bucket_name, obj_name)
278
+ @buckets[bucket_name][obj_name] && File.size(@buckets[bucket_name][obj_name])
279
+ end
280
+
281
+ def upload_file(bucket_name, obj_name, file)
282
+ @buckets[bucket_name][obj_name] = file
283
+ end
284
+
285
+ end
286
+
287
+ class CFStub
288
+ def initialize
289
+ @stacks = {}
290
+ @events = {}
291
+ @event_fetch_counter = 0;
292
+ end
293
+
294
+ def create_stack(name, template, opts)
295
+ @stacks[name] = {:template => template, :opts => opts }
296
+ end
297
+
298
+ def update_stack(name, template, opts)
299
+ @stacks[name] = @stacks[name].merge(:template => template, :opts => opts)
300
+ end
301
+
302
+ def stack_status(name)
303
+ @stacks[name] && :update_complete
304
+ end
305
+
306
+ def stack_exists?(name)
307
+ @stacks.has_key?(name)
308
+ end
309
+
310
+ def query_output(name, key)
311
+ raise Aws::CloudFormation::Errors::ValidationError.new(nil, nil) unless stack_exists?(name)
312
+ "value of #{key}"
313
+ end
314
+
315
+ def stack_config(name)
316
+ @stacks[name][:opts]
317
+ end
318
+
319
+ def set_events(name, *messages)
320
+ events_seq = []
321
+ messages.each do |messages_for_call_seq|
322
+ if old_events = events_seq.last
323
+ events_seq << generate_event_from_messages(name, messages_for_call_seq) + old_events
324
+ else
325
+ events_seq << generate_event_from_messages(name, messages_for_call_seq)
326
+ end
327
+ end
328
+ @events[name] = events_seq
329
+ end
330
+
331
+ def fetch_events(name, opts={})
332
+ @event_fetch_counter += 1
333
+ if es = @events[name]
334
+ return es[@event_fetch_counter - 1], nil
335
+ else
336
+ return generate_event_from_messages(name, ["UPDATE_COMPLETE"]), nil
337
+ end
338
+ end
339
+
340
+ private
341
+
342
+ def generate_event_from_messages(stack, messages)
343
+ messages.map do |message|
344
+ OpenStruct.new(timestamp: Time.now,
345
+ resource_type: 'AWS::CloudFormation::Stack',
346
+ logical_resource_id: stack,
347
+ resource_status: message)
348
+ end.reverse
349
+ end
350
+ end
@@ -0,0 +1,23 @@
1
+ require 'test_helper'
2
+
3
+ class BeanstalkTest < Test::Unit::TestCase
4
+
5
+ class StubbedCnameResponder
6
+ def initialize(stubbed_response)
7
+ @stubbed_response = stubbed_response
8
+ end
9
+
10
+ def describe_environments(options)
11
+ {:environments => [@stubbed_response.merge(:status => "online")]}
12
+ end
13
+ end
14
+
15
+ def test_cname_prefix_will_parse_both_legacy_and_regionalized_domains
16
+ legacy_domain = "mingle-saas.elasticbeanstalk.com"
17
+ regionalized_domain = "mingle-saas.us-west-1.elasticbeanstalk.com"
18
+
19
+ assert_equal "mingle-saas", EbDeployer::AWSDriver::Beanstalk.new(StubbedCnameResponder.new(:cname => legacy_domain)).environment_cname_prefix("mingle", "saas")
20
+ assert_equal "mingle-saas", EbDeployer::AWSDriver::Beanstalk.new(StubbedCnameResponder.new(:cname => regionalized_domain)).environment_cname_prefix("mingle", "saas")
21
+ end
22
+
23
+ end
@@ -0,0 +1,114 @@
1
+ require 'deploy_test'
2
+
3
+ class BlueGreenDeployTest < DeployTest
4
+ def test_blue_green_deployment_strategy_should_create_blue_env_on_first_deployment
5
+ do_deploy(42)
6
+ assert @eb.environment_exists?('simple', t('production-a', 'simple'))
7
+ assert_equal 'simple-production', @eb.environment_cname_prefix('simple', t('production-a', 'simple'))
8
+ end
9
+
10
+
11
+ def test_blue_green_deployment_should_create_green_env_if_blue_exists
12
+ do_deploy(42)
13
+ do_deploy(43)
14
+ assert @eb.environment_exists?('simple', t('production-a', 'simple'))
15
+ assert @eb.environment_exists?('simple', t('production-b', 'simple'))
16
+ end
17
+
18
+
19
+ def test_blue_green_deployment_should_swap_cname_to_make_active_most_recent_updated_env
20
+ do_deploy(42)
21
+ do_deploy(43)
22
+ assert_match(/simple-production-inactive/, @eb.environment_cname_prefix('simple', t('production-a', 'simple')))
23
+ assert_equal 'simple-production', @eb.environment_cname_prefix('simple', t('production-b', 'simple'))
24
+ do_deploy(44)
25
+ assert_match(/simple-production-inactive/, @eb.environment_cname_prefix('simple', t('production-b', 'simple')))
26
+ assert_equal 'simple-production', @eb.environment_cname_prefix('simple', t('production-a', 'simple'))
27
+ end
28
+
29
+
30
+ def test_blue_green_deploy_should_run_smoke_test_before_cname_switch
31
+ smoked_host = []
32
+ smoke_test = lambda { |host| smoked_host << host }
33
+ [42, 43, 44].each do |version_label|
34
+ do_deploy(version_label, :smoke_test => smoke_test)
35
+ end
36
+
37
+ assert_equal ['simple-production.us-west-1.elasticbeanstalk.com',
38
+ 'simple-production-inactive.us-west-1.elasticbeanstalk.com',
39
+ 'simple-production-inactive.us-west-1.elasticbeanstalk.com'], smoked_host
40
+ end
41
+
42
+ def test_blue_green_deploy_should_blue_green_terminate_inactive_env_if_blue_green_terminate_inactive_is_enabled
43
+ do_deploy(42, :blue_green_terminate_inactive => true, :blue_green_terminate_inactive_wait => 1, :blue_green_terminate_inactive_sleep => 1)
44
+ do_deploy(43, :blue_green_terminate_inactive => true, :blue_green_terminate_inactive_wait => 0, :blue_green_terminate_inactive_sleep => 0)
45
+
46
+ inactive_env = t('production-a', 'simple')
47
+ assert_equal [inactive_env], @eb.environments_been_deleted('simple')
48
+ end
49
+
50
+ def test_blue_green_deployment_should_delete_and_recreate_inactive_env_if_phoenix_mode_is_enabled
51
+ do_deploy(42, :phoenix_mode => true)
52
+ do_deploy(43, :phoenix_mode => true)
53
+ assert_equal [], @eb.environments_been_deleted('simple')
54
+
55
+ inactive_env = t('production-a', 'simple')
56
+ assert_match(/inactive/, @eb.environment_cname_prefix('simple', inactive_env))
57
+
58
+ do_deploy(44, :phoenix_mode => true)
59
+ assert_equal [inactive_env], @eb.environments_been_deleted('simple')
60
+
61
+ assert_equal 'simple-production', @eb.environment_cname_prefix('simple', inactive_env)
62
+ end
63
+
64
+ def test_destroy_should_clean_up_env
65
+ [42, 44].each do |version|
66
+ do_deploy(version)
67
+ end
68
+
69
+ destroy(:application => 'simple', :environment => 'production')
70
+ assert !@eb.environment_exists?('simple', t('production-a', 'simple'))
71
+ assert !@eb.environment_exists?('simple', t('production-b', 'simple'))
72
+ end
73
+
74
+ def test_can_have_inactive_settings_which_will_be_applied_to_inactive_env
75
+ settings = {:option_settings =>
76
+ [{:namespace => 'aws:autoscaling:launchconfiguration',
77
+ :option_name => 'MinSize',
78
+ :value => 10}],
79
+ :inactive_settings =>
80
+ [{:namespace => 'aws:autoscaling:launchconfiguration',
81
+ :option_name => 'MinSize',
82
+ :value => 1}]}
83
+
84
+ do_deploy(42, settings)
85
+ assert_equal 10, @eb.environment_settings('simple', t('production-a', 'simple')).last[:value]
86
+ assert_equal '42', @eb.environment_verion_label('simple', t('production-a', 'simple'))
87
+
88
+ do_deploy(43, settings)
89
+ assert_equal 1, @eb.environment_settings('simple', t('production-a', 'simple')).last[:value]
90
+ assert_equal '42', @eb.environment_verion_label('simple', t('production-a', 'simple'))
91
+
92
+ assert_equal 10, @eb.environment_settings('simple', t('production-b', 'simple')).last[:value]
93
+ assert_equal '43', @eb.environment_verion_label('simple', t('production-b', 'simple'))
94
+
95
+
96
+ do_deploy(44, settings)
97
+ assert_equal 10, @eb.environment_settings('simple', t('production-a', 'simple')).last[:value]
98
+ assert_equal '44', @eb.environment_verion_label('simple', t('production-a', 'simple'))
99
+
100
+ assert_equal 1, @eb.environment_settings('simple', t('production-b', 'simple')).last[:value]
101
+ assert_equal '43', @eb.environment_verion_label('simple', t('production-b', 'simple'))
102
+
103
+ end
104
+
105
+ private
106
+
107
+ def do_deploy(version_label, options={})
108
+ deploy( {:application => 'simple',
109
+ :environment => "production",
110
+ :strategy => 'blue-green',
111
+ }.merge(options).merge(:version_label => version_label))
112
+ end
113
+
114
+ end
@@ -0,0 +1,78 @@
1
+ require 'deploy_test'
2
+
3
+ class BlueOnlyDeployTest < DeployTest
4
+ def test_blue_only_deployment_strategy_should_create_blue_env_on_first_deployment
5
+ do_deploy(42)
6
+ assert @eb.environment_exists?('simple', t('production-a', 'simple'))
7
+ assert_equal 'simple-production', @eb.environment_cname_prefix('simple', t('production-a', 'simple'))
8
+ end
9
+
10
+
11
+ def test_blue_only_deployment_should_create_green_env_if_blue_exists
12
+ do_deploy(42)
13
+ do_deploy(43)
14
+ assert @eb.environment_exists?('simple', t('production-a', 'simple'))
15
+ assert @eb.environment_exists?('simple', t('production-b', 'simple'))
16
+ end
17
+
18
+
19
+ def test_blue_only_deployment_should_not_swap_cname_to_make_active_most_recent_updated_env
20
+ do_deploy(42)
21
+ assert_equal 'simple-production', @eb.environment_cname_prefix('simple', t('production-a', 'simple'))
22
+ assert_nil(@eb.environment_cname_prefix('simple', t('production-b', 'simple')))
23
+ do_deploy(43)
24
+ assert_equal 'simple-production', @eb.environment_cname_prefix('simple', t('production-a', 'simple'))
25
+ assert_match(/simple-production-inactive/, @eb.environment_cname_prefix('simple', t('production-b', 'simple')))
26
+ do_deploy(44)
27
+ assert_equal 'simple-production', @eb.environment_cname_prefix('simple', t('production-a', 'simple'))
28
+ assert_match(/simple-production-inactive/, @eb.environment_cname_prefix('simple', t('production-b', 'simple')))
29
+ end
30
+
31
+
32
+ def test_blue_only_deploy_should_run_smoke_test_before_cname_switch
33
+ smoked_host = []
34
+ smoke_test = lambda { |host| smoked_host << host }
35
+ [42, 43, 44].each do |version_label|
36
+ do_deploy(version_label, :smoke_test => smoke_test)
37
+ end
38
+
39
+ assert_equal ['simple-production.us-west-1.elasticbeanstalk.com',
40
+ 'simple-production-inactive.us-west-1.elasticbeanstalk.com',
41
+ 'simple-production-inactive.us-west-1.elasticbeanstalk.com'], smoked_host
42
+ end
43
+
44
+
45
+ def test_blue_only_deployment_should_delete_and_recreate_inactive_env_if_phoenix_mode_is_enabled
46
+ do_deploy(42, :phoenix_mode => true)
47
+ do_deploy(43, :phoenix_mode => true)
48
+ assert_equal [], @eb.environments_been_deleted('simple')
49
+
50
+ inactive_env = t('production-b', 'simple')
51
+ assert_match(/inactive/, @eb.environment_cname_prefix('simple', inactive_env))
52
+
53
+ do_deploy(44, :phoenix_mode => true)
54
+ assert_equal [inactive_env], @eb.environments_been_deleted('simple')
55
+
56
+ assert_match(/inactive/, @eb.environment_cname_prefix('simple', inactive_env))
57
+ end
58
+
59
+ def test_destroy_should_clean_up_env
60
+ [42, 44].each do |version|
61
+ do_deploy(version)
62
+ end
63
+
64
+ destroy(:application => 'simple', :environment => 'production')
65
+ assert !@eb.environment_exists?('simple', t('production-a', 'simple'))
66
+ assert !@eb.environment_exists?('simple', t('production-b', 'simple'))
67
+ end
68
+
69
+ private
70
+
71
+ def do_deploy(version_label, options={})
72
+ deploy( {:application => 'simple',
73
+ :environment => "production",
74
+ :strategy => 'blue-only',
75
+ }.merge(options).merge(:version_label => version_label))
76
+ end
77
+
78
+ end
@@ -0,0 +1,32 @@
1
+ require 'test_helper'
2
+
3
+ class CfEventPollerTest < Test::Unit::TestCase
4
+ def setup
5
+ @cf = CFStub.new
6
+ @poller = EbDeployer::EventPoller.new(EbDeployer::CfEventSource.new("mystack", @cf))
7
+ end
8
+
9
+ def test_run_handle_block_through_all_events_when_there_is_no_from_anchor
10
+ messages_handled = []
11
+ @cf.set_events('mystack', ['a', 'b', nil])
12
+ @poller.poll(nil) do |event|
13
+ break if event.resource_status.nil?
14
+ messages_handled << event.resource_status
15
+ end
16
+
17
+ assert_equal ['a', 'b'], messages_handled
18
+ end
19
+
20
+
21
+ def test_can_poll_all_events_after_an_anchor
22
+ @cf.set_events('mystack', ['a', 'b'], ['c', 'd', nil])
23
+ anchor = @poller.get_anchor
24
+ messages_handled = []
25
+ @poller.poll(anchor) do |event|
26
+ break if event.resource_status.nil?
27
+ messages_handled << event.resource_status
28
+ end
29
+
30
+ assert_equal ['c', 'd'], messages_handled
31
+ end
32
+ end