eb_deployer 0.4.2 → 0.4.3
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.
- data/CHANGELOG.md +4 -0
- data/lib/eb_deployer.rb +1 -0
- data/lib/eb_deployer/config_loader.rb +1 -4
- data/lib/eb_deployer/environment.rb +2 -4
- data/lib/eb_deployer/event_poller.rb +12 -5
- data/lib/eb_deployer/utils.rb +28 -0
- data/lib/eb_deployer/version.rb +1 -1
- data/test/blue_green_deploy_test.rb +20 -64
- data/test/deploy_test.rb +1 -1
- data/test/inplace_update_deploy_test.rb +18 -0
- data/test/test_helper.rb +48 -0
- metadata +5 -4
data/CHANGELOG.md
CHANGED
data/lib/eb_deployer.rb
CHANGED
@@ -3,6 +3,7 @@ require 'digest'
|
|
3
3
|
|
4
4
|
module EbDeployer
|
5
5
|
class ConfigLoader
|
6
|
+
include Utils
|
6
7
|
|
7
8
|
class EvalBinding
|
8
9
|
def initialize(package_digest)
|
@@ -44,10 +45,6 @@ module EbDeployer
|
|
44
45
|
|
45
46
|
private
|
46
47
|
|
47
|
-
def symbolize_keys(hash)
|
48
|
-
hash.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
49
|
-
end
|
50
|
-
|
51
48
|
def load_config_settings(config_file, package_digest)
|
52
49
|
yaml = ERB.new(File.read(config_file)).result(eval_binding(package_digest))
|
53
50
|
symbolize_keys(YAML.load(yaml))
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module EbDeployer
|
2
2
|
class Environment
|
3
|
+
include Utils
|
4
|
+
|
3
5
|
attr_writer :resource_stacks, :settings, :creation_opts, :components, :component_under_deploy, :strategy_name
|
4
6
|
attr_reader :name
|
5
7
|
|
@@ -53,10 +55,6 @@ module EbDeployer
|
|
53
55
|
@components.detect { |c| c.name == name }
|
54
56
|
end
|
55
57
|
|
56
|
-
def symbolize_keys(hash)
|
57
|
-
hash.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
58
|
-
end
|
59
|
-
|
60
58
|
def resource_stack_name
|
61
59
|
"#{app_name}-#{@name}"
|
62
60
|
end
|
@@ -1,7 +1,9 @@
|
|
1
1
|
module EbDeployer
|
2
2
|
class EventPoller
|
3
|
-
|
4
|
-
|
3
|
+
include Utils
|
4
|
+
|
5
|
+
def initialize(app, env, eb_driver)
|
6
|
+
@app, @env, @eb_driver = app, env, eb_driver
|
5
7
|
end
|
6
8
|
|
7
9
|
def poll(start_time = Time.now, &block)
|
@@ -16,7 +18,6 @@ module EbDeployer
|
|
16
18
|
end
|
17
19
|
end
|
18
20
|
|
19
|
-
|
20
21
|
private
|
21
22
|
|
22
23
|
def digest(event)
|
@@ -28,15 +29,21 @@ module EbDeployer
|
|
28
29
|
end
|
29
30
|
|
30
31
|
def fetch_events(start_time, &block)
|
31
|
-
events, next_token =
|
32
|
+
events, next_token = fetch_events_from_eb(:start_time => start_time.iso8601)
|
32
33
|
yield(events)
|
33
34
|
fetch_next(next_token, &block) if next_token
|
34
35
|
end
|
35
36
|
|
36
37
|
def fetch_next(next_token, &block)
|
37
|
-
events, next_token =
|
38
|
+
events, next_token = fetch_events_from_eb(:next_token => next_token)
|
38
39
|
yield(events)
|
39
40
|
fetch_next(next_token, &block) if next_token
|
40
41
|
end
|
42
|
+
|
43
|
+
def fetch_events_from_eb(options)
|
44
|
+
backoff(AWS::ElasticBeanstalk::Errors::Throttling) do
|
45
|
+
@eb_driver.fetch_events(@app, @env, options)
|
46
|
+
end
|
47
|
+
end
|
41
48
|
end
|
42
49
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module EbDeployer
|
2
|
+
module Utils
|
3
|
+
BACKOFF_INITIAL_SLEEP = 1
|
4
|
+
|
5
|
+
# A util deal with throttling exceptions
|
6
|
+
# example:
|
7
|
+
# backoff(AWS::EC2::Errors::RequestLimitExceeded) do
|
8
|
+
# ...
|
9
|
+
# end
|
10
|
+
def backoff(error_class, retry_limit=9, &block)
|
11
|
+
next_sleep = BACKOFF_INITIAL_SLEEP
|
12
|
+
begin
|
13
|
+
yield
|
14
|
+
rescue error_class
|
15
|
+
raise if retry_limit == 0
|
16
|
+
sleep(next_sleep)
|
17
|
+
next_sleep *= 2
|
18
|
+
retry_limit -= 1
|
19
|
+
retry
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# convert top level key in a hash to symbol
|
24
|
+
def symbolize_keys(hash)
|
25
|
+
hash.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/eb_deployer/version.rb
CHANGED
@@ -2,55 +2,27 @@ require 'deploy_test'
|
|
2
2
|
|
3
3
|
class BlueGreenDeployTest < DeployTest
|
4
4
|
def test_blue_green_deployment_strategy_should_create_blue_env_on_first_deployment
|
5
|
-
|
6
|
-
:environment => "production",
|
7
|
-
:strategy => 'blue-green',
|
8
|
-
:version_label => 42)
|
9
|
-
|
5
|
+
do_deploy(42)
|
10
6
|
assert @eb.environment_exists?('simple', t('production-a', 'simple'))
|
11
7
|
assert_equal 'simple-production', @eb.environment_cname_prefix('simple', t('production-a', 'simple'))
|
12
8
|
end
|
13
9
|
|
14
10
|
|
15
11
|
def test_blue_green_deployment_should_create_green_env_if_blue_exists
|
16
|
-
|
17
|
-
|
18
|
-
:strategy => 'blue-green',
|
19
|
-
:version_label => 42)
|
20
|
-
|
21
|
-
deploy(:application => 'simple',
|
22
|
-
:environment => "production",
|
23
|
-
:strategy => 'blue-green',
|
24
|
-
:version_label => 43)
|
25
|
-
|
12
|
+
do_deploy(42)
|
13
|
+
do_deploy(43)
|
26
14
|
assert @eb.environment_exists?('simple', t('production-a', 'simple'))
|
27
15
|
assert @eb.environment_exists?('simple', t('production-b', 'simple'))
|
28
16
|
end
|
29
17
|
|
30
18
|
|
31
19
|
def test_blue_green_deployment_should_swap_cname_to_make_active_most_recent_updated_env
|
32
|
-
|
33
|
-
|
34
|
-
:strategy => 'blue-green',
|
35
|
-
:version_label => 42)
|
36
|
-
|
37
|
-
deploy(:application => 'simple',
|
38
|
-
:environment => "production",
|
39
|
-
:strategy => 'blue-green',
|
40
|
-
:version_label => 43)
|
41
|
-
|
20
|
+
do_deploy(42)
|
21
|
+
do_deploy(43)
|
42
22
|
assert_match(/simple-production-inactive/, @eb.environment_cname_prefix('simple', t('production-a', 'simple')))
|
43
|
-
|
44
23
|
assert_equal 'simple-production', @eb.environment_cname_prefix('simple', t('production-b', 'simple'))
|
45
|
-
|
46
|
-
|
47
|
-
deploy(:application => 'simple',
|
48
|
-
:environment => "production",
|
49
|
-
:strategy => 'blue-green',
|
50
|
-
:version_label => 44)
|
51
|
-
|
24
|
+
do_deploy(44)
|
52
25
|
assert_match(/simple-production-inactive/, @eb.environment_cname_prefix('simple', t('production-b', 'simple')))
|
53
|
-
|
54
26
|
assert_equal 'simple-production', @eb.environment_cname_prefix('simple', t('production-a', 'simple'))
|
55
27
|
end
|
56
28
|
|
@@ -59,11 +31,7 @@ class BlueGreenDeployTest < DeployTest
|
|
59
31
|
smoked_host = []
|
60
32
|
smoke_test = lambda { |host| smoked_host << host }
|
61
33
|
[42, 43, 44].each do |version_label|
|
62
|
-
|
63
|
-
:environment => "production",
|
64
|
-
:strategy => 'blue-green',
|
65
|
-
:smoke_test => smoke_test,
|
66
|
-
:version_label => version_label)
|
34
|
+
do_deploy(version_label, :smoke_test => smoke_test)
|
67
35
|
end
|
68
36
|
|
69
37
|
assert_equal ['simple-production.elasticbeanstalk.com',
|
@@ -73,42 +41,22 @@ class BlueGreenDeployTest < DeployTest
|
|
73
41
|
|
74
42
|
|
75
43
|
def test_blue_green_deployment_should_delete_and_recreate_inactive_env_if_phoenix_mode_is_enabled
|
76
|
-
|
77
|
-
|
78
|
-
:strategy => 'blue-green',
|
79
|
-
:version_label => 42,
|
80
|
-
:phoenix_mode => true)
|
81
|
-
|
82
|
-
deploy(:application => 'simple',
|
83
|
-
:environment => "production",
|
84
|
-
:strategy => 'blue-green',
|
85
|
-
:version_label => 43,
|
86
|
-
:phoenix_mode => true)
|
87
|
-
|
44
|
+
do_deploy(42, :phoenix_mode => true)
|
45
|
+
do_deploy(43, :phoenix_mode => true)
|
88
46
|
assert_equal [], @eb.environments_been_deleted('simple')
|
89
47
|
|
90
48
|
inactive_env = t('production-a', 'simple')
|
91
49
|
assert_match(/inactive/, @eb.environment_cname_prefix('simple', inactive_env))
|
92
50
|
|
93
|
-
|
94
|
-
deploy(:application => 'simple',
|
95
|
-
:environment => "production",
|
96
|
-
:strategy => 'blue-green',
|
97
|
-
:version_label => 44,
|
98
|
-
:phoenix_mode => true)
|
99
|
-
|
51
|
+
do_deploy(44, :phoenix_mode => true)
|
100
52
|
assert_equal [inactive_env], @eb.environments_been_deleted('simple')
|
101
53
|
|
102
54
|
assert_equal 'simple-production', @eb.environment_cname_prefix('simple', inactive_env)
|
103
55
|
end
|
104
56
|
|
105
57
|
def test_destroy_should_clean_up_env
|
106
|
-
|
107
|
-
|
108
|
-
:environment => "production",
|
109
|
-
:strategy => 'blue-green',
|
110
|
-
:version_label => 44,
|
111
|
-
:phoenix_mode => true)
|
58
|
+
[42, 44].each do |version|
|
59
|
+
do_deploy(version)
|
112
60
|
end
|
113
61
|
|
114
62
|
destroy(:application => 'simple', :environment => 'production')
|
@@ -117,5 +65,13 @@ class BlueGreenDeployTest < DeployTest
|
|
117
65
|
end
|
118
66
|
|
119
67
|
|
68
|
+
private
|
69
|
+
|
70
|
+
def do_deploy(version_label, options={})
|
71
|
+
deploy( {:application => 'simple',
|
72
|
+
:environment => "production",
|
73
|
+
:strategy => 'blue-green',
|
74
|
+
}.merge(options).merge(:version_label => version_label))
|
75
|
+
end
|
120
76
|
|
121
77
|
end
|
data/test/deploy_test.rb
CHANGED
@@ -79,4 +79,22 @@ class InplaceUpdateDeployTest < DeployTest
|
|
79
79
|
assert !@eb.environment_exists?('simple', t('production', 'simple'))
|
80
80
|
end
|
81
81
|
|
82
|
+
def test_deploy_should_raise_error_when_constantly_hitting_throttling_error
|
83
|
+
throttling_error = AWS::ElasticBeanstalk::Errors::Throttling.new("bang!")
|
84
|
+
@eb.set_error(:fetch_events, throttling_error)
|
85
|
+
assert_raises(AWS::ElasticBeanstalk::Errors::Throttling) do
|
86
|
+
deploy(:application => 'simple', :environment => "production")
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_deploy_should_retry_on_temporary_throttling_error
|
91
|
+
throttling_error = AWS::ElasticBeanstalk::Errors::Throttling.new("bang!")
|
92
|
+
error_seq = [throttling_error] * 5
|
93
|
+
@eb.set_error_generator(:fetch_events) do
|
94
|
+
error_seq.pop
|
95
|
+
end
|
96
|
+
deploy(:application => 'simple', :environment => "production")
|
97
|
+
assert @eb.environment_exists?('simple', t('production', 'simple'))
|
98
|
+
end
|
99
|
+
|
82
100
|
end
|
data/test/test_helper.rb
CHANGED
@@ -6,6 +6,54 @@ require 'aws_driver_stubs'
|
|
6
6
|
require 'minitest/autorun'
|
7
7
|
require 'minitest/pride'
|
8
8
|
|
9
|
+
def silence_warnings(&block)
|
10
|
+
old_verbose, $VERBOSE = $VERBOSE, nil
|
11
|
+
yield
|
12
|
+
ensure
|
13
|
+
$VERBOSE = old_verbose
|
14
|
+
end
|
15
|
+
|
16
|
+
silence_warnings { EbDeployer::Utils::BACKOFF_INITIAL_SLEEP = 0 }
|
17
|
+
|
18
|
+
class ErrorRaisingWrapper < SimpleDelegator
|
19
|
+
def initialize(stub)
|
20
|
+
@errors = {}
|
21
|
+
super(stub)
|
22
|
+
end
|
23
|
+
|
24
|
+
def set_error(method, error)
|
25
|
+
set_error_generator(method) do
|
26
|
+
error
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def set_error_generator(method, &error_gen)
|
31
|
+
define_delegate_method(method)
|
32
|
+
@errors[method] = Proc.new(&error_gen)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
def define_delegate_method(method)
|
37
|
+
method = method.to_s
|
38
|
+
original_method_name = "__#{method}_without_error"
|
39
|
+
raise "method #{method} not defined" unless self.respond_to?(method)
|
40
|
+
return if self.respond_to?(original_method_name)
|
41
|
+
|
42
|
+
self.instance_eval <<-CODE
|
43
|
+
def #{original_method_name}(*args, &block)
|
44
|
+
self.__get_obj__.send(:#{method}, *args, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def #{method}(*args, &block)
|
48
|
+
if error_gen = @errors[:fetch_events]
|
49
|
+
error = error_gen.call
|
50
|
+
raise error if error
|
51
|
+
end
|
52
|
+
super
|
53
|
+
end
|
54
|
+
CODE
|
55
|
+
end
|
56
|
+
end
|
9
57
|
|
10
58
|
class MiniTest::Unit::TestCase
|
11
59
|
def sample_file(file_name, content='s' * 100)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: eb_deployer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2014-04-
|
13
|
+
date: 2014-04-02 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: aws-sdk
|
@@ -69,6 +69,7 @@ files:
|
|
69
69
|
- lib/eb_deployer/package.rb
|
70
70
|
- lib/eb_deployer/resource_stacks.rb
|
71
71
|
- lib/eb_deployer/smoke_test.rb
|
72
|
+
- lib/eb_deployer/utils.rb
|
72
73
|
- lib/eb_deployer/version.rb
|
73
74
|
- lib/eb_deployer/version_cleaner.rb
|
74
75
|
- test/aws_driver_stubs.rb
|
@@ -99,7 +100,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
99
100
|
version: '0'
|
100
101
|
segments:
|
101
102
|
- 0
|
102
|
-
hash:
|
103
|
+
hash: 567704794056721741
|
103
104
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
104
105
|
none: false
|
105
106
|
requirements:
|
@@ -108,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
108
109
|
version: '0'
|
109
110
|
segments:
|
110
111
|
- 0
|
111
|
-
hash:
|
112
|
+
hash: 567704794056721741
|
112
113
|
requirements: []
|
113
114
|
rubyforge_project:
|
114
115
|
rubygems_version: 1.8.29
|