eb_deployer 0.3.6 → 0.3.7
Sign up to get free protection for your applications and to get access to all the features.
- data/.ruby-version +1 -1
- data/.travis.yml +10 -0
- data/Gemfile +1 -1
- data/README.md +1 -1
- data/lib/eb_deployer/application.rb +7 -1
- data/lib/eb_deployer/aws_driver/beanstalk.rb +127 -0
- data/lib/eb_deployer/aws_driver/cloud_formation_driver.rb +49 -0
- data/lib/eb_deployer/aws_driver/s3_driver.rb +35 -0
- data/lib/eb_deployer/aws_driver.rb +8 -0
- data/lib/eb_deployer/config_loader.rb +0 -1
- data/lib/eb_deployer/deployment_strategy/blue_green.rb +40 -0
- data/lib/eb_deployer/deployment_strategy/inplace_update.rb +13 -0
- data/lib/eb_deployer/deployment_strategy.rb +6 -61
- data/lib/eb_deployer/eb_environment.rb +111 -0
- data/lib/eb_deployer/environment.rb +21 -87
- data/lib/eb_deployer/resource_stacks.rb +19 -0
- data/lib/eb_deployer/version.rb +1 -1
- data/lib/eb_deployer.rb +35 -41
- data/test/config_loader_test.rb +0 -13
- data/test/deploy_test.rb +11 -0
- data/test/{environment_test.rb → eb_environment_test.rb} +8 -8
- data/test/test_helper.rb +1 -1
- metadata +20 -8
- data/lib/eb_deployer/beanstalk.rb +0 -126
- data/lib/eb_deployer/cloud_formation_driver.rb +0 -48
- data/lib/eb_deployer/s3_driver.rb +0 -33
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.9.3-
|
1
|
+
1.9.3-p484
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# EbDeployer
|
1
|
+
# EbDeployer [![Build Status](https://travis-ci.org/ThoughtWorksStudios/eb_deployer.png?branch=master)](https://travis-ci.org/ThoughtWorksStudios/eb_deployer)
|
2
2
|
|
3
3
|
Low friction deployments should be a breeze. Elastic Beanstalk provides a great foundation for performing Blue-Green deployments, and EbDeployer add a missing link to automate the whole flow out of box.
|
4
4
|
|
@@ -1,5 +1,7 @@
|
|
1
1
|
module EbDeployer
|
2
2
|
class Application
|
3
|
+
attr_reader :name
|
4
|
+
|
3
5
|
def initialize(name, eb_driver, s3_driver, bucket = nil)
|
4
6
|
@name = name
|
5
7
|
@eb_driver = eb_driver
|
@@ -34,7 +36,7 @@ module EbDeployer
|
|
34
36
|
|
35
37
|
def delete(env_name=nil)
|
36
38
|
if @eb_driver.application_exists?(@name)
|
37
|
-
env_name =
|
39
|
+
env_name = EbEnvironment.unique_ebenv_name(@name, env_name) unless env_name.nil?
|
38
40
|
available_envs = @eb_driver.environment_names_for_application(@name)
|
39
41
|
|
40
42
|
unless env_name.nil? || available_envs.include?(env_name)
|
@@ -75,6 +77,10 @@ module EbDeployer
|
|
75
77
|
end
|
76
78
|
end
|
77
79
|
|
80
|
+
def clean_versions(version_prefix, retentions)
|
81
|
+
VersionCleaner.new(self, retentions).clean(version_prefix)
|
82
|
+
end
|
83
|
+
|
78
84
|
private
|
79
85
|
|
80
86
|
def create_application_if_not_exists
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module EbDeployer
|
2
|
+
module AWSDriver
|
3
|
+
class Beanstalk
|
4
|
+
attr_reader :client
|
5
|
+
|
6
|
+
def initialize(client=AWS::ElasticBeanstalk.new.client)
|
7
|
+
@client = client
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_application(app)
|
11
|
+
@client.create_application(:application_name => app)
|
12
|
+
end
|
13
|
+
|
14
|
+
def delete_application(app)
|
15
|
+
@client.delete_application(:application_name => app)
|
16
|
+
end
|
17
|
+
|
18
|
+
def application_exists?(app)
|
19
|
+
@client.describe_applications(:application_names => [app])[:applications].any?
|
20
|
+
end
|
21
|
+
|
22
|
+
def update_environment(app_name, env_name, version, tier, settings)
|
23
|
+
env_id = convert_env_name_to_id(app_name, [env_name]).first
|
24
|
+
request = {
|
25
|
+
:environment_id => env_id,
|
26
|
+
:version_label => version,
|
27
|
+
:option_settings => settings,
|
28
|
+
:tier => tier
|
29
|
+
}
|
30
|
+
|
31
|
+
@client.update_environment(request)
|
32
|
+
end
|
33
|
+
|
34
|
+
def environment_exists?(app_name, env_name)
|
35
|
+
alive_envs(app_name, [env_name]).any?
|
36
|
+
end
|
37
|
+
|
38
|
+
def environment_names_for_application(app_name)
|
39
|
+
alive_envs(app_name).collect { |env| env[:environment_name] }
|
40
|
+
end
|
41
|
+
|
42
|
+
def create_environment(app_name, env_name, stack_name, cname_prefix, version, tier, settings)
|
43
|
+
request = {
|
44
|
+
:application_name => app_name,
|
45
|
+
:environment_name => env_name,
|
46
|
+
:solution_stack_name => stack_name,
|
47
|
+
:version_label => version,
|
48
|
+
:option_settings => settings,
|
49
|
+
:tier => tier,
|
50
|
+
:cname_prefix => cname_prefix
|
51
|
+
}
|
52
|
+
|
53
|
+
@client.create_environment(request)
|
54
|
+
end
|
55
|
+
|
56
|
+
def delete_environment(app_name, env_name)
|
57
|
+
@client.terminate_environment(:environment_name => env_name)
|
58
|
+
end
|
59
|
+
|
60
|
+
def delete_application_version(app_name, version, delete_source_bundle)
|
61
|
+
request = {
|
62
|
+
:application_name => app_name,
|
63
|
+
:version_label => version,
|
64
|
+
:delete_source_bundle => delete_source_bundle
|
65
|
+
}
|
66
|
+
@client.delete_application_version(request)
|
67
|
+
end
|
68
|
+
|
69
|
+
def create_application_version(app_name, version_label, source_bundle)
|
70
|
+
@client.create_application_version(:application_name => app_name,
|
71
|
+
:source_bundle => source_bundle,
|
72
|
+
:version_label => version_label)
|
73
|
+
end
|
74
|
+
|
75
|
+
def application_version_labels(app_name)
|
76
|
+
application_versions(app_name).map { |apv| apv[:version_label] }
|
77
|
+
end
|
78
|
+
|
79
|
+
def application_versions(app_name)
|
80
|
+
request = { :application_name => app_name }
|
81
|
+
@client.describe_application_versions(request)[:application_versions]
|
82
|
+
end
|
83
|
+
|
84
|
+
def fetch_events(app_name, env_name, params, &block)
|
85
|
+
response = @client.describe_events(params.merge(:application_name => app_name,
|
86
|
+
:environment_name => env_name))
|
87
|
+
return [response[:events], response[:next_token]]
|
88
|
+
end
|
89
|
+
|
90
|
+
def environment_cname_prefix(app_name, env_name)
|
91
|
+
cname = environment_cname(app_name, env_name)
|
92
|
+
if cname =~ /^(.+)\.elasticbeanstalk\.com/
|
93
|
+
$1
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def environment_cname(app_name, env_name)
|
98
|
+
env = alive_envs(app_name, [env_name]).first
|
99
|
+
env && env[:cname]
|
100
|
+
end
|
101
|
+
|
102
|
+
def environment_health_state(app_name, env_name)
|
103
|
+
env = alive_envs(app_name, [env_name]).first
|
104
|
+
env && env[:health]
|
105
|
+
end
|
106
|
+
|
107
|
+
def environment_swap_cname(app_name, env1, env2)
|
108
|
+
env1_id, env2_id = convert_env_name_to_id(app_name, [env1, env2])
|
109
|
+
@client.swap_environment_cnam_es(:source_environment_id => env1_id,
|
110
|
+
:destination_environment_id => env2_id)
|
111
|
+
end
|
112
|
+
|
113
|
+
private
|
114
|
+
|
115
|
+
def convert_env_name_to_id(app_name, env_names)
|
116
|
+
envs = alive_envs(app_name, env_names)
|
117
|
+
envs.map { |env| env[:environment_id] }
|
118
|
+
end
|
119
|
+
|
120
|
+
def alive_envs(app_name, env_names=[])
|
121
|
+
envs = @client.describe_environments(:application_name => app_name, :environment_names => env_names)[:environments]
|
122
|
+
|
123
|
+
envs.select {|e| e[:status] != 'Terminated' }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module EbDeployer
|
2
|
+
module AWSDriver
|
3
|
+
class CloudFormationDriver
|
4
|
+
|
5
|
+
def stack_exists?(name)
|
6
|
+
stack(name).exists?
|
7
|
+
end
|
8
|
+
|
9
|
+
def create_stack(name, template, opts)
|
10
|
+
cloud_formation.stacks.create(name, template, opts)
|
11
|
+
end
|
12
|
+
|
13
|
+
def update_stack(name, template, opts)
|
14
|
+
begin
|
15
|
+
stack(name).update(opts.merge(:template => template))
|
16
|
+
rescue AWS::CloudFormation::Errors::ValidationError => e
|
17
|
+
if e.message =~ /No updates are to be performed/
|
18
|
+
log(e.message)
|
19
|
+
else
|
20
|
+
raise
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def stack_status(name)
|
26
|
+
stack(name).status.downcase.to_sym
|
27
|
+
end
|
28
|
+
|
29
|
+
def query_output(name, key)
|
30
|
+
output = stack(name).outputs.find { |o| o.key == key }
|
31
|
+
output && output.value
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def cloud_formation
|
37
|
+
AWS::CloudFormation.new
|
38
|
+
end
|
39
|
+
|
40
|
+
def stack(name)
|
41
|
+
cloud_formation.stacks[name]
|
42
|
+
end
|
43
|
+
|
44
|
+
def log(msg)
|
45
|
+
puts "[#{Time.now.utc}][cloud_formation_driver] #{msg}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module EbDeployer
|
2
|
+
module AWSDriver
|
3
|
+
class S3Driver
|
4
|
+
def create_bucket(bucket_name)
|
5
|
+
buckets.create(bucket_name)
|
6
|
+
end
|
7
|
+
|
8
|
+
def bucket_exists?(bucket_name)
|
9
|
+
buckets[bucket_name].exists?
|
10
|
+
end
|
11
|
+
|
12
|
+
def object_length(bucket_name, obj_name)
|
13
|
+
obj(bucket_name, obj_name).content_length rescue nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def upload_file(bucket_name, obj_name, file)
|
17
|
+
o = obj(bucket_name, obj_name)
|
18
|
+
File.open(file) { |f| o.write(f) }
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def s3
|
23
|
+
AWS::S3.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def obj(bucket_name, obj_name)
|
27
|
+
buckets[bucket_name].objects[obj_name]
|
28
|
+
end
|
29
|
+
|
30
|
+
def buckets
|
31
|
+
s3.buckets
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module EbDeployer
|
2
|
+
module DeploymentStrategy
|
3
|
+
class BlueGreen
|
4
|
+
def initialize(env)
|
5
|
+
@env = env
|
6
|
+
end
|
7
|
+
|
8
|
+
def deploy(version_label, env_settings)
|
9
|
+
if !envs.any?(&method(:active_env?))
|
10
|
+
env('a', @env.cname_prefix).
|
11
|
+
deploy(version_label, env_settings)
|
12
|
+
return
|
13
|
+
end
|
14
|
+
|
15
|
+
active_env = envs.detect(&method(:active_env?))
|
16
|
+
inactive_env = envs.reject(&method(:active_env?)).first
|
17
|
+
|
18
|
+
inactive_env.deploy(version_label, env_settings)
|
19
|
+
active_env.swap_cname_with(inactive_env)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def active_env?(env)
|
24
|
+
env.cname_prefix == @env.cname_prefix
|
25
|
+
end
|
26
|
+
|
27
|
+
def envs
|
28
|
+
[env('a'), env('b')]
|
29
|
+
end
|
30
|
+
|
31
|
+
def env(suffix, cname_prefix=nil)
|
32
|
+
@env.new_eb_env(suffix, cname_prefix || inactive_cname_prefix)
|
33
|
+
end
|
34
|
+
|
35
|
+
def inactive_cname_prefix
|
36
|
+
"#{@env.cname_prefix}-inactive"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,72 +1,17 @@
|
|
1
|
+
require 'eb_deployer/deployment_strategy/inplace_update'
|
2
|
+
require 'eb_deployer/deployment_strategy/blue_green'
|
3
|
+
|
1
4
|
module EbDeployer
|
2
5
|
module DeploymentStrategy
|
3
|
-
|
4
|
-
def initialize(app, env_name, eb_driver, env_creation_opts)
|
5
|
-
@app = app
|
6
|
-
@env_name = env_name
|
7
|
-
@eb_driver = eb_driver
|
8
|
-
@env_creation_opts = env_creation_opts
|
9
|
-
end
|
10
|
-
|
11
|
-
def deploy(version_label, env_settings)
|
12
|
-
Environment.new(@app, @env_name, @eb_driver, @env_creation_opts).
|
13
|
-
deploy(version_label, env_settings)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
class BlueGreen
|
18
|
-
def initialize(app, env_name, eb_driver, env_creation_opts)
|
19
|
-
@app = app
|
20
|
-
@env_name = env_name
|
21
|
-
@eb_driver = eb_driver
|
22
|
-
@env_creation_opts = env_creation_opts
|
23
|
-
@major_cname_prefix = env_creation_opts[:cname_prefix]
|
24
|
-
end
|
25
|
-
|
26
|
-
def deploy(version_label, env_settings)
|
27
|
-
if !envs.any?(&method(:active_env?))
|
28
|
-
env('a', @major_cname_prefix).
|
29
|
-
deploy(version_label, env_settings)
|
30
|
-
return
|
31
|
-
end
|
32
|
-
|
33
|
-
active_env = envs.detect(&method(:active_env?))
|
34
|
-
inactive_env = envs.reject(&method(:active_env?)).first
|
35
|
-
|
36
|
-
inactive_env.deploy(version_label, env_settings)
|
37
|
-
active_env.swap_cname_with(inactive_env)
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
def active_env?(env)
|
42
|
-
env.cname_prefix == @major_cname_prefix
|
43
|
-
end
|
44
|
-
|
45
|
-
def envs
|
46
|
-
[env('a'), env('b')]
|
47
|
-
end
|
48
|
-
|
49
|
-
def env(suffix, cname_prefix=nil)
|
50
|
-
Environment.new(@app, @env_name + '-' + suffix,
|
51
|
-
@eb_driver,
|
52
|
-
@env_creation_opts.merge({:cname_prefix => cname_prefix || inactive_cname_prefix}))
|
53
|
-
end
|
54
|
-
|
55
|
-
def inactive_cname_prefix
|
56
|
-
"#{@app}-#{@env_name}-inactive"
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def self.create(strategy_name, app, env_name, eb_driver, env_creation_opts={})
|
6
|
+
def self.create(env, strategy_name)
|
61
7
|
case strategy_name.to_s
|
62
8
|
when 'inplace_update', 'inplace-update'
|
63
|
-
InplaceUpdate.new(
|
9
|
+
InplaceUpdate.new(env)
|
64
10
|
when 'blue_green', 'blue-green'
|
65
|
-
BlueGreen.new(
|
11
|
+
BlueGreen.new(env)
|
66
12
|
else
|
67
13
|
raise 'strategy_name: ' + strategy_name.to_s + ' not supported'
|
68
14
|
end
|
69
|
-
|
70
15
|
end
|
71
16
|
end
|
72
17
|
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module EbDeployer
|
2
|
+
class EbEnvironment
|
3
|
+
attr_reader :app, :name
|
4
|
+
attr_writer :event_poller
|
5
|
+
|
6
|
+
def self.unique_ebenv_name(app_name, env_name)
|
7
|
+
raise "Environment name #{env_name} is too long, it must be under 15 chars" if env_name.size > 15
|
8
|
+
digest = Digest::SHA1.hexdigest(app_name + '-' + env_name)[0..6]
|
9
|
+
"#{env_name}-#{digest}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(app, env_name, eb_driver, creation_opts={})
|
13
|
+
@app = app
|
14
|
+
@name = self.class.unique_ebenv_name(app, env_name)
|
15
|
+
@bs = eb_driver
|
16
|
+
@creation_opts = creation_opts
|
17
|
+
end
|
18
|
+
|
19
|
+
def deploy(version_label, settings={})
|
20
|
+
terminate if @creation_opts[:phoenix_mode]
|
21
|
+
create_or_update_env(version_label, settings)
|
22
|
+
smoke_test
|
23
|
+
wait_for_env_become_healthy
|
24
|
+
end
|
25
|
+
|
26
|
+
def cname_prefix
|
27
|
+
@bs.environment_cname_prefix(@app, @name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def ==(another)
|
31
|
+
self.app == another.app && self.name == another.name
|
32
|
+
end
|
33
|
+
|
34
|
+
def swap_cname_with(another)
|
35
|
+
log("Swap CNAME with env #{another.name}")
|
36
|
+
@bs.environment_swap_cname(self.app, self.name, another.name)
|
37
|
+
end
|
38
|
+
|
39
|
+
def log(msg)
|
40
|
+
puts "[#{Time.now.utc}][environment:#{@name}] #{msg}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def terminate
|
44
|
+
if @bs.environment_exists?(@app, @name)
|
45
|
+
with_polling_events(/terminateEnvironment completed successfully/i) do
|
46
|
+
@bs.delete_environment(@app, @name)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def create_or_update_env(version_label, settings)
|
55
|
+
if @bs.environment_exists?(@app, @name)
|
56
|
+
with_polling_events(/Environment update completed successfully/i) do
|
57
|
+
@bs.update_environment(@app, @name, version_label, @creation_opts[:tier], settings)
|
58
|
+
end
|
59
|
+
else
|
60
|
+
with_polling_events(/Successfully launched environment/i) do
|
61
|
+
@bs.create_environment(@app, @name, @creation_opts[:solution_stack], @creation_opts[:cname_prefix], version_label, @creation_opts[:tier], settings)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def smoke_test
|
67
|
+
host_name = @bs.environment_cname(@app, @name)
|
68
|
+
SmokeTest.new(@creation_opts[:smoke_test]).run(host_name, self)
|
69
|
+
end
|
70
|
+
|
71
|
+
def with_polling_events(terminate_pattern, &block)
|
72
|
+
event_start_time = Time.now
|
73
|
+
yield
|
74
|
+
event_poller.poll(event_start_time) do |event|
|
75
|
+
if event[:message] =~ /Failed to deploy application/
|
76
|
+
raise event[:message]
|
77
|
+
end
|
78
|
+
|
79
|
+
if event[:message] =~ /Command failed on instance/
|
80
|
+
raise "Elasticbeanstalk instance provision failed (maybe a problem with your .ebextension files). The original message: #{event[:message]}"
|
81
|
+
end
|
82
|
+
|
83
|
+
log_event(event)
|
84
|
+
break if event[:message] =~ terminate_pattern
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def wait_for_env_become_healthy
|
89
|
+
Timeout.timeout(600) do
|
90
|
+
current_health_status = @bs.environment_health_state(@app, @name)
|
91
|
+
|
92
|
+
while current_health_status != 'Green'
|
93
|
+
log("health status: #{current_health_status}")
|
94
|
+
sleep 15
|
95
|
+
current_health_status = @bs.environment_health_state(@app, @name)
|
96
|
+
end
|
97
|
+
|
98
|
+
log("health status: #{current_health_status}")
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def event_poller
|
103
|
+
@event_poller || EventPoller.new(@app, @name, @bs)
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
def log_event(event)
|
108
|
+
puts "[#{event[:event_date]}][environment:#{@name}] #{event[:message]}"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -1,111 +1,45 @@
|
|
1
1
|
module EbDeployer
|
2
2
|
class Environment
|
3
|
-
attr_reader :app, :name
|
4
|
-
attr_writer :event_poller
|
5
3
|
|
6
|
-
def
|
7
|
-
raise "Environment name #{env_name} is too long, it must be under 15 chars" if env_name.size > 15
|
8
|
-
digest = Digest::SHA1.hexdigest(app_name + '-' + env_name)[0..6]
|
9
|
-
"#{env_name}-#{digest}"
|
10
|
-
end
|
11
|
-
|
12
|
-
def initialize(app, env_name, eb_driver, creation_opts={})
|
4
|
+
def initialize(app, name, resource_stacks, settings, creation_opts, bs_driver)
|
13
5
|
@app = app
|
14
|
-
@name =
|
15
|
-
@
|
6
|
+
@name = name
|
7
|
+
@resource_stacks = resource_stacks
|
8
|
+
@settings = settings
|
16
9
|
@creation_opts = creation_opts
|
17
|
-
|
18
|
-
|
19
|
-
def deploy(version_label, settings={})
|
20
|
-
terminate if @creation_opts[:phoenix_mode]
|
21
|
-
create_or_update_env(version_label, settings)
|
22
|
-
smoke_test
|
23
|
-
wait_for_env_become_healthy
|
10
|
+
@bs_driver = bs_driver
|
24
11
|
end
|
25
12
|
|
26
13
|
def cname_prefix
|
27
|
-
@
|
28
|
-
end
|
29
|
-
|
30
|
-
def ==(another)
|
31
|
-
self.app == another.app && self.name == another.name
|
32
|
-
end
|
33
|
-
|
34
|
-
def swap_cname_with(another)
|
35
|
-
log("Swap CNAME with env #{another.name}")
|
36
|
-
@bs.environment_swap_cname(self.app, self.name, another.name)
|
14
|
+
@creation_opts[:cname_prefix] || default_cname_prefix
|
37
15
|
end
|
38
16
|
|
39
|
-
def
|
40
|
-
|
17
|
+
def deploy(version_label, strategy_name)
|
18
|
+
strategy = create_strategy(strategy_name)
|
19
|
+
strategy.deploy(version_label,
|
20
|
+
@settings + @resource_stacks.provision(resource_stack_name))
|
41
21
|
end
|
42
22
|
|
43
|
-
def
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
23
|
+
def new_eb_env(suffix=nil, cname_prefix_overriding=nil)
|
24
|
+
EbEnvironment.new(@app.name,
|
25
|
+
[@name, suffix].compact.join('-'),
|
26
|
+
@bs_driver,
|
27
|
+
@creation_opts.merge(:cname_prefix => cname_prefix_overriding || cname_prefix))
|
49
28
|
end
|
50
29
|
|
51
|
-
|
52
30
|
private
|
53
31
|
|
54
|
-
def
|
55
|
-
|
56
|
-
with_polling_events(/Environment update completed successfully/i) do
|
57
|
-
@bs.update_environment(@app, @name, version_label, @creation_opts[:tier], settings)
|
58
|
-
end
|
59
|
-
else
|
60
|
-
with_polling_events(/Successfully launched environment/i) do
|
61
|
-
@bs.create_environment(@app, @name, @creation_opts[:solution_stack], @creation_opts[:cname_prefix], version_label, @creation_opts[:tier], settings)
|
62
|
-
end
|
63
|
-
end
|
32
|
+
def default_cname_prefix
|
33
|
+
[@app.name, @name].join('-')
|
64
34
|
end
|
65
35
|
|
66
|
-
def smoke_test
|
67
|
-
host_name = @bs.environment_cname(@app, @name)
|
68
|
-
SmokeTest.new(@creation_opts[:smoke_test]).run(host_name, self)
|
69
|
-
end
|
70
36
|
|
71
|
-
def
|
72
|
-
|
73
|
-
yield
|
74
|
-
event_poller.poll(event_start_time) do |event|
|
75
|
-
if event[:message] =~ /Failed to deploy application/
|
76
|
-
raise event[:message]
|
77
|
-
end
|
78
|
-
|
79
|
-
if event[:message] =~ /Command failed on instance/
|
80
|
-
raise "Elasticbeanstalk instance provision failed (maybe a problem with your .ebextension files). The original message: #{event[:message]}"
|
81
|
-
end
|
82
|
-
|
83
|
-
log_event(event)
|
84
|
-
break if event[:message] =~ terminate_pattern
|
85
|
-
end
|
37
|
+
def create_strategy(strategy_name)
|
38
|
+
DeploymentStrategy.create(self, strategy_name)
|
86
39
|
end
|
87
40
|
|
88
|
-
def
|
89
|
-
|
90
|
-
current_health_status = @bs.environment_health_state(@app, @name)
|
91
|
-
|
92
|
-
while current_health_status != 'Green'
|
93
|
-
log("health status: #{current_health_status}")
|
94
|
-
sleep 15
|
95
|
-
current_health_status = @bs.environment_health_state(@app, @name)
|
96
|
-
end
|
97
|
-
|
98
|
-
log("health status: #{current_health_status}")
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def event_poller
|
103
|
-
@event_poller || EventPoller.new(@app, @name, @bs)
|
104
|
-
end
|
105
|
-
|
106
|
-
|
107
|
-
def log_event(event)
|
108
|
-
puts "[#{event[:event_date]}][environment:#{@name}] #{event[:message]}"
|
41
|
+
def resource_stack_name
|
42
|
+
"#{@app.name}-#{@name}"
|
109
43
|
end
|
110
44
|
end
|
111
45
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module EbDeployer
|
2
|
+
class ResourceStacks
|
3
|
+
def initialize(resources, cf_driver, skip_provision=false)
|
4
|
+
@resources = resources
|
5
|
+
@cf_driver = cf_driver
|
6
|
+
@skip_provision = skip_provision
|
7
|
+
end
|
8
|
+
|
9
|
+
def provision(stack_name)
|
10
|
+
provisioner = CloudFormationProvisioner.new(stack_name, @cf_driver)
|
11
|
+
if @resources
|
12
|
+
provisioner.provision(@resources) unless @skip_provision
|
13
|
+
provisioner.transform_outputs(@resources)
|
14
|
+
else
|
15
|
+
[]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/eb_deployer/version.rb
CHANGED
data/lib/eb_deployer.rb
CHANGED
@@ -1,17 +1,3 @@
|
|
1
|
-
require "eb_deployer/version"
|
2
|
-
require "eb_deployer/deployment_strategy"
|
3
|
-
require "eb_deployer/beanstalk"
|
4
|
-
require "eb_deployer/cloud_formation_provisioner"
|
5
|
-
require 'eb_deployer/application'
|
6
|
-
require "eb_deployer/environment"
|
7
|
-
require "eb_deployer/event_poller"
|
8
|
-
require "eb_deployer/package"
|
9
|
-
require 'eb_deployer/s3_driver'
|
10
|
-
require 'eb_deployer/cloud_formation_driver'
|
11
|
-
require 'eb_deployer/config_loader'
|
12
|
-
require 'eb_deployer/default_config'
|
13
|
-
require 'eb_deployer/smoke_test'
|
14
|
-
require 'eb_deployer/version_cleaner'
|
15
1
|
require 'digest'
|
16
2
|
require 'set'
|
17
3
|
require 'time'
|
@@ -22,6 +8,21 @@ require 'optparse'
|
|
22
8
|
require 'erb'
|
23
9
|
require 'fileutils'
|
24
10
|
|
11
|
+
require 'eb_deployer/version'
|
12
|
+
require 'eb_deployer/aws_driver'
|
13
|
+
require 'eb_deployer/deployment_strategy'
|
14
|
+
require 'eb_deployer/cloud_formation_provisioner'
|
15
|
+
require 'eb_deployer/application'
|
16
|
+
require 'eb_deployer/resource_stacks'
|
17
|
+
require 'eb_deployer/eb_environment'
|
18
|
+
require 'eb_deployer/environment'
|
19
|
+
require 'eb_deployer/event_poller'
|
20
|
+
require 'eb_deployer/package'
|
21
|
+
require 'eb_deployer/config_loader'
|
22
|
+
require 'eb_deployer/default_config'
|
23
|
+
require 'eb_deployer/smoke_test'
|
24
|
+
require 'eb_deployer/version_cleaner'
|
25
|
+
|
25
26
|
module EbDeployer
|
26
27
|
|
27
28
|
TIERS = [
|
@@ -48,7 +49,7 @@ module EbDeployer
|
|
48
49
|
end
|
49
50
|
app = opts[:application]
|
50
51
|
env_name = opts[:environment]
|
51
|
-
cf = opts[:cf_driver] || CloudFormationDriver.new
|
52
|
+
cf = opts[:cf_driver] || AWSDriver::CloudFormationDriver.new
|
52
53
|
provisioner = CloudFormationProvisioner.new("#{app}-#{env_name}", cf)
|
53
54
|
provisioner.output(key)
|
54
55
|
end
|
@@ -177,9 +178,9 @@ module EbDeployer
|
|
177
178
|
AWS.config(:region => region)
|
178
179
|
end
|
179
180
|
|
180
|
-
bs = opts[:bs_driver] || Beanstalk.new
|
181
|
-
s3 = opts[:s3_driver] || S3Driver.new
|
182
|
-
cf = opts[:cf_driver] || CloudFormationDriver.new
|
181
|
+
bs = opts[:bs_driver] || AWSDriver::Beanstalk.new
|
182
|
+
s3 = opts[:s3_driver] || AWSDriver::S3Driver.new
|
183
|
+
cf = opts[:cf_driver] || AWSDriver::CloudFormationDriver.new
|
183
184
|
stack_name = opts[:solution_stack_name] || "64bit Amazon Linux 2013.09 running Tomcat 7 Java 7"
|
184
185
|
app = opts[:application]
|
185
186
|
env_name = opts[:environment]
|
@@ -188,7 +189,7 @@ module EbDeployer
|
|
188
189
|
cname = opts[:cname]
|
189
190
|
env_settings = opts[:option_settings] || opts[:settings] || []
|
190
191
|
strategy_name = opts[:strategy] || :blue_green
|
191
|
-
cname_prefix = opts[:cname_prefix]
|
192
|
+
cname_prefix = opts[:cname_prefix]
|
192
193
|
smoke_test = opts[:smoke_test] || Proc.new {}
|
193
194
|
phoenix_mode = opts[:phoenix_mode]
|
194
195
|
bucket = opts[:package_bucket] || app
|
@@ -196,30 +197,24 @@ module EbDeployer
|
|
196
197
|
keep_latest = opts[:keep_latest].to_i || 0
|
197
198
|
app_tier = self.environment_tier(opts[:tier] || 'WebServer')
|
198
199
|
|
200
|
+
resource_stacks = ResourceStacks.new(opts[:resources], cf, skip_resource)
|
199
201
|
application = Application.new(app, bs, s3, bucket)
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
cleaner = VersionCleaner.new(application, keep_latest)
|
214
|
-
|
215
|
-
if resources = opts[:resources]
|
216
|
-
cf.provision(resources) unless skip_resource
|
217
|
-
env_settings += cf.transform_outputs(resources)
|
218
|
-
end
|
202
|
+
environment = Environment.new(application,
|
203
|
+
env_name,
|
204
|
+
resource_stacks,
|
205
|
+
env_settings,
|
206
|
+
{
|
207
|
+
:solution_stack => stack_name,
|
208
|
+
:cname_prefix => cname_prefix,
|
209
|
+
:smoke_test => smoke_test,
|
210
|
+
:phoenix_mode => phoenix_mode,
|
211
|
+
:tier => app_tier
|
212
|
+
},
|
213
|
+
bs)
|
219
214
|
|
220
215
|
application.create_version(version_label, opts[:package])
|
221
|
-
|
222
|
-
|
216
|
+
environment.deploy(version_label, strategy_name)
|
217
|
+
application.clean_versions(version_prefix, keep_latest)
|
223
218
|
end
|
224
219
|
|
225
220
|
def self.destroy(opts)
|
@@ -313,7 +308,6 @@ module EbDeployer
|
|
313
308
|
puts "YAML package file format:"
|
314
309
|
puts "s3_bucket: <bucket_name>"
|
315
310
|
puts "s3_key: <object_path>"
|
316
|
-
exit(0)
|
317
311
|
end
|
318
312
|
end
|
319
313
|
end
|
data/test/config_loader_test.rb
CHANGED
@@ -25,19 +25,6 @@ YAML
|
|
25
25
|
assert_equal(nil, config[:common])
|
26
26
|
end
|
27
27
|
|
28
|
-
def test_use_package_as_version_label_when_using_s3_obj_as_package
|
29
|
-
config = @loader.load(generate_input(<<-YAML, :package => 'bucket:obj'))
|
30
|
-
application: myapp
|
31
|
-
common:
|
32
|
-
strategy: inplace-update
|
33
|
-
environments:
|
34
|
-
dev:
|
35
|
-
YAML
|
36
|
-
assert_equal('myapp', config[:application])
|
37
|
-
assert_equal('bucket:obj', config[:package])
|
38
|
-
assert_equal('bucket:obj', config[:version_label])
|
39
|
-
end
|
40
|
-
|
41
28
|
def test_common_settings_get_merge_into_the_config
|
42
29
|
config = @loader.load(generate_input(<<-YAML))
|
43
30
|
application: myapp
|
data/test/deploy_test.rb
CHANGED
@@ -432,6 +432,17 @@ class DeployTest < MiniTest::Unit::TestCase
|
|
432
432
|
assert_equal({'s3_bucket' => 'test-bucket', 's3_key' => 'test-mingle.war'}, last_version[:source_bundle])
|
433
433
|
end
|
434
434
|
|
435
|
+
=begin
|
436
|
+
def test_deploy_with_components
|
437
|
+
deploy(:application => 'simple',
|
438
|
+
:environment => 'production',
|
439
|
+
:components => [{ :name => 'web' }])
|
440
|
+
|
441
|
+
assert !@eb_driver.environment_exists?('simple', eb_envname('simple', 'production'))
|
442
|
+
|
443
|
+
end
|
444
|
+
=end
|
445
|
+
|
435
446
|
private
|
436
447
|
|
437
448
|
def temp_file(content)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class
|
3
|
+
class EbEnvironmentTest < MiniTest::Unit::TestCase
|
4
4
|
class PollerStub
|
5
5
|
class Deadloop < StandardError; end
|
6
6
|
|
@@ -25,13 +25,13 @@ class EnvironmentTest < MiniTest::Unit::TestCase
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def test_deploy_should_create_corresponding_eb_env
|
28
|
-
env = EbDeployer::
|
28
|
+
env = EbDeployer::EbEnvironment.new("myapp", "production", @eb_driver)
|
29
29
|
env.deploy("version1")
|
30
30
|
assert @eb_driver.environment_exists?('myapp', eb_envname('myapp', 'production'))
|
31
31
|
end
|
32
32
|
|
33
33
|
def test_deploy_again_should_update_environment
|
34
|
-
env = EbDeployer::
|
34
|
+
env = EbDeployer::EbEnvironment.new("myapp", "production", @eb_driver)
|
35
35
|
env.deploy("version1")
|
36
36
|
env.deploy("version2")
|
37
37
|
assert @eb_driver.environment_exists?('myapp', eb_envname('myapp', 'production'))
|
@@ -39,14 +39,14 @@ class EnvironmentTest < MiniTest::Unit::TestCase
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def test_option_setttings_get_set_on_eb_env
|
42
|
-
env = EbDeployer::
|
42
|
+
env = EbDeployer::EbEnvironment.new("myapp", "production", @eb_driver)
|
43
43
|
env.deploy("version1", {s1: 'v1'})
|
44
44
|
assert_equal({s1: 'v1' }, @eb_driver.environment_settings('myapp', eb_envname('myapp', 'production')))
|
45
45
|
end
|
46
46
|
|
47
47
|
def test_should_run_smoke_test_after_deploy
|
48
48
|
smoked_host = nil
|
49
|
-
env = EbDeployer::
|
49
|
+
env = EbDeployer::EbEnvironment.new("myapp", "production", @eb_driver, :smoke_test => Proc.new { |host| smoked_host = host })
|
50
50
|
env.deploy("version1")
|
51
51
|
|
52
52
|
assert !smoked_host.nil?
|
@@ -54,13 +54,13 @@ class EnvironmentTest < MiniTest::Unit::TestCase
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def test_should_raise_runtime_error_when_deploy_failed
|
57
|
-
env = EbDeployer::
|
57
|
+
env = EbDeployer::EbEnvironment.new("myapp", "production", @eb_driver)
|
58
58
|
env.event_poller = PollerStub.new(["start deploying", "Failed to deploy application"])
|
59
59
|
assert_raises(RuntimeError) { env.deploy("version 1") }
|
60
60
|
end
|
61
61
|
|
62
62
|
def test_should_raise_runtime_error_when_eb_extension_execution_failed
|
63
|
-
env = EbDeployer::
|
63
|
+
env = EbDeployer::EbEnvironment.new("myapp", "production", @eb_driver)
|
64
64
|
|
65
65
|
env.event_poller = PollerStub.new(["start deploying",
|
66
66
|
"create environment",
|
@@ -72,7 +72,7 @@ class EnvironmentTest < MiniTest::Unit::TestCase
|
|
72
72
|
|
73
73
|
|
74
74
|
def test_terminate_should_delete_environment
|
75
|
-
env = EbDeployer::
|
75
|
+
env = EbDeployer::EbEnvironment.new("myapp", "production", @eb_driver)
|
76
76
|
env.deploy("version1")
|
77
77
|
env.terminate
|
78
78
|
assert !@eb_driver.environment_exists?('myapp', eb_envname('myapp', 'production'))
|
data/test/test_helper.rb
CHANGED
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.3.
|
4
|
+
version: 0.3.7
|
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-03-
|
13
|
+
date: 2014-03-26 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: aws-sdk
|
@@ -40,6 +40,7 @@ files:
|
|
40
40
|
- .gitignore
|
41
41
|
- .ruby-gemset
|
42
42
|
- .ruby-version
|
43
|
+
- .travis.yml
|
43
44
|
- Gemfile
|
44
45
|
- LICENSE
|
45
46
|
- README.md
|
@@ -48,17 +49,22 @@ files:
|
|
48
49
|
- eb_deployer.gemspec
|
49
50
|
- lib/eb_deployer.rb
|
50
51
|
- lib/eb_deployer/application.rb
|
51
|
-
- lib/eb_deployer/
|
52
|
-
- lib/eb_deployer/
|
52
|
+
- lib/eb_deployer/aws_driver.rb
|
53
|
+
- lib/eb_deployer/aws_driver/beanstalk.rb
|
54
|
+
- lib/eb_deployer/aws_driver/cloud_formation_driver.rb
|
55
|
+
- lib/eb_deployer/aws_driver/s3_driver.rb
|
53
56
|
- lib/eb_deployer/cloud_formation_provisioner.rb
|
54
57
|
- lib/eb_deployer/config_loader.rb
|
55
58
|
- lib/eb_deployer/default_config.rb
|
56
59
|
- lib/eb_deployer/default_config.yml
|
57
60
|
- lib/eb_deployer/deployment_strategy.rb
|
61
|
+
- lib/eb_deployer/deployment_strategy/blue_green.rb
|
62
|
+
- lib/eb_deployer/deployment_strategy/inplace_update.rb
|
63
|
+
- lib/eb_deployer/eb_environment.rb
|
58
64
|
- lib/eb_deployer/environment.rb
|
59
65
|
- lib/eb_deployer/event_poller.rb
|
60
66
|
- lib/eb_deployer/package.rb
|
61
|
-
- lib/eb_deployer/
|
67
|
+
- lib/eb_deployer/resource_stacks.rb
|
62
68
|
- lib/eb_deployer/smoke_test.rb
|
63
69
|
- lib/eb_deployer/version.rb
|
64
70
|
- lib/eb_deployer/version_cleaner.rb
|
@@ -66,7 +72,7 @@ files:
|
|
66
72
|
- test/cloud_formation_provisioner_test.rb
|
67
73
|
- test/config_loader_test.rb
|
68
74
|
- test/deploy_test.rb
|
69
|
-
- test/
|
75
|
+
- test/eb_environment_test.rb
|
70
76
|
- test/smoke_test_test.rb
|
71
77
|
- test/test_helper.rb
|
72
78
|
homepage: https://github.com/ThoughtWorksStudios/eb_deployer
|
@@ -82,15 +88,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
82
88
|
- - ! '>='
|
83
89
|
- !ruby/object:Gem::Version
|
84
90
|
version: '0'
|
91
|
+
segments:
|
92
|
+
- 0
|
93
|
+
hash: 1041206842017006108
|
85
94
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
86
95
|
none: false
|
87
96
|
requirements:
|
88
97
|
- - ! '>='
|
89
98
|
- !ruby/object:Gem::Version
|
90
99
|
version: '0'
|
100
|
+
segments:
|
101
|
+
- 0
|
102
|
+
hash: 1041206842017006108
|
91
103
|
requirements: []
|
92
104
|
rubyforge_project:
|
93
|
-
rubygems_version: 1.8.
|
105
|
+
rubygems_version: 1.8.29
|
94
106
|
signing_key:
|
95
107
|
specification_version: 3
|
96
108
|
summary: Low friction deployments should be a breeze. Elastic Beanstalk provides a
|
@@ -101,7 +113,7 @@ test_files:
|
|
101
113
|
- test/cloud_formation_provisioner_test.rb
|
102
114
|
- test/config_loader_test.rb
|
103
115
|
- test/deploy_test.rb
|
104
|
-
- test/
|
116
|
+
- test/eb_environment_test.rb
|
105
117
|
- test/smoke_test_test.rb
|
106
118
|
- test/test_helper.rb
|
107
119
|
has_rdoc:
|
@@ -1,126 +0,0 @@
|
|
1
|
-
module EbDeployer
|
2
|
-
class Beanstalk
|
3
|
-
attr_reader :client
|
4
|
-
|
5
|
-
def initialize(client=AWS::ElasticBeanstalk.new.client)
|
6
|
-
@client = client
|
7
|
-
end
|
8
|
-
|
9
|
-
def create_application(app)
|
10
|
-
@client.create_application(:application_name => app)
|
11
|
-
end
|
12
|
-
|
13
|
-
def delete_application(app)
|
14
|
-
@client.delete_application(:application_name => app)
|
15
|
-
end
|
16
|
-
|
17
|
-
def application_exists?(app)
|
18
|
-
@client.describe_applications(:application_names => [app])[:applications].any?
|
19
|
-
end
|
20
|
-
|
21
|
-
def update_environment(app_name, env_name, version, tier, settings)
|
22
|
-
env_id = convert_env_name_to_id(app_name, [env_name]).first
|
23
|
-
request = {
|
24
|
-
:environment_id => env_id,
|
25
|
-
:version_label => version,
|
26
|
-
:option_settings => settings,
|
27
|
-
:tier => tier
|
28
|
-
}
|
29
|
-
|
30
|
-
@client.update_environment(request)
|
31
|
-
end
|
32
|
-
|
33
|
-
def environment_exists?(app_name, env_name)
|
34
|
-
alive_envs(app_name, [env_name]).any?
|
35
|
-
end
|
36
|
-
|
37
|
-
def environment_names_for_application(app_name)
|
38
|
-
alive_envs(app_name).collect { |env| env[:environment_name] }
|
39
|
-
end
|
40
|
-
|
41
|
-
def create_environment(app_name, env_name, stack_name, cname_prefix, version, tier, settings)
|
42
|
-
request = {
|
43
|
-
:application_name => app_name,
|
44
|
-
:environment_name => env_name,
|
45
|
-
:solution_stack_name => stack_name,
|
46
|
-
:version_label => version,
|
47
|
-
:option_settings => settings,
|
48
|
-
:tier => tier,
|
49
|
-
:cname_prefix => cname_prefix
|
50
|
-
}
|
51
|
-
|
52
|
-
@client.create_environment(request)
|
53
|
-
end
|
54
|
-
|
55
|
-
def delete_environment(app_name, env_name)
|
56
|
-
@client.terminate_environment(:environment_name => env_name)
|
57
|
-
end
|
58
|
-
|
59
|
-
def delete_application_version(app_name, version, delete_source_bundle)
|
60
|
-
request = {
|
61
|
-
:application_name => app_name,
|
62
|
-
:version_label => version,
|
63
|
-
:delete_source_bundle => delete_source_bundle
|
64
|
-
}
|
65
|
-
@client.delete_application_version(request)
|
66
|
-
end
|
67
|
-
|
68
|
-
def create_application_version(app_name, version_label, source_bundle)
|
69
|
-
@client.create_application_version(:application_name => app_name,
|
70
|
-
:source_bundle => source_bundle,
|
71
|
-
:version_label => version_label)
|
72
|
-
end
|
73
|
-
|
74
|
-
def application_version_labels(app_name)
|
75
|
-
application_versions(app_name).map { |apv| apv[:version_label] }
|
76
|
-
end
|
77
|
-
|
78
|
-
def application_versions(app_name)
|
79
|
-
request = { :application_name => app_name }
|
80
|
-
@client.describe_application_versions(request)[:application_versions]
|
81
|
-
end
|
82
|
-
|
83
|
-
def fetch_events(app_name, env_name, params, &block)
|
84
|
-
response = @client.describe_events(params.merge(:application_name => app_name,
|
85
|
-
:environment_name => env_name))
|
86
|
-
return [response[:events], response[:next_token]]
|
87
|
-
end
|
88
|
-
|
89
|
-
def environment_cname_prefix(app_name, env_name)
|
90
|
-
cname = environment_cname(app_name, env_name)
|
91
|
-
if cname =~ /^(.+)\.elasticbeanstalk\.com/
|
92
|
-
$1
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def environment_cname(app_name, env_name)
|
97
|
-
env = alive_envs(app_name, [env_name]).first
|
98
|
-
env && env[:cname]
|
99
|
-
end
|
100
|
-
|
101
|
-
def environment_health_state(app_name, env_name)
|
102
|
-
env = alive_envs(app_name, [env_name]).first
|
103
|
-
env && env[:health]
|
104
|
-
end
|
105
|
-
|
106
|
-
def environment_swap_cname(app_name, env1, env2)
|
107
|
-
env1_id, env2_id = convert_env_name_to_id(app_name, [env1, env2])
|
108
|
-
@client.swap_environment_cnam_es(:source_environment_id => env1_id,
|
109
|
-
:destination_environment_id => env2_id)
|
110
|
-
end
|
111
|
-
|
112
|
-
private
|
113
|
-
|
114
|
-
def convert_env_name_to_id(app_name, env_names)
|
115
|
-
envs = alive_envs(app_name, env_names)
|
116
|
-
envs.map { |env| env[:environment_id] }
|
117
|
-
end
|
118
|
-
|
119
|
-
def alive_envs(app_name, env_names=[])
|
120
|
-
envs = @client.describe_environments(:application_name => app_name, :environment_names => env_names)[:environments]
|
121
|
-
|
122
|
-
envs.select {|e| e[:status] != 'Terminated' }
|
123
|
-
end
|
124
|
-
|
125
|
-
end
|
126
|
-
end
|
@@ -1,48 +0,0 @@
|
|
1
|
-
module EbDeployer
|
2
|
-
class CloudFormationDriver
|
3
|
-
|
4
|
-
def stack_exists?(name)
|
5
|
-
stack(name).exists?
|
6
|
-
end
|
7
|
-
|
8
|
-
def create_stack(name, template, opts)
|
9
|
-
cloud_formation.stacks.create(name, template, opts)
|
10
|
-
end
|
11
|
-
|
12
|
-
def update_stack(name, template, opts)
|
13
|
-
begin
|
14
|
-
stack(name).update(opts.merge(:template => template))
|
15
|
-
rescue AWS::CloudFormation::Errors::ValidationError => e
|
16
|
-
if e.message =~ /No updates are to be performed/
|
17
|
-
log(e.message)
|
18
|
-
else
|
19
|
-
raise
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def stack_status(name)
|
25
|
-
stack(name).status.downcase.to_sym
|
26
|
-
end
|
27
|
-
|
28
|
-
def query_output(name, key)
|
29
|
-
output = stack(name).outputs.find { |o| o.key == key }
|
30
|
-
output && output.value
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def cloud_formation
|
36
|
-
AWS::CloudFormation.new
|
37
|
-
end
|
38
|
-
|
39
|
-
def stack(name)
|
40
|
-
cloud_formation.stacks[name]
|
41
|
-
end
|
42
|
-
|
43
|
-
def log(msg)
|
44
|
-
puts "[#{Time.now.utc}][cloud_formation_driver] #{msg}"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
module EbDeployer
|
2
|
-
class S3Driver
|
3
|
-
def create_bucket(bucket_name)
|
4
|
-
buckets.create(bucket_name)
|
5
|
-
end
|
6
|
-
|
7
|
-
def bucket_exists?(bucket_name)
|
8
|
-
buckets[bucket_name].exists?
|
9
|
-
end
|
10
|
-
|
11
|
-
def object_length(bucket_name, obj_name)
|
12
|
-
obj(bucket_name, obj_name).content_length rescue nil
|
13
|
-
end
|
14
|
-
|
15
|
-
def upload_file(bucket_name, obj_name, file)
|
16
|
-
o = obj(bucket_name, obj_name)
|
17
|
-
File.open(file) { |f| o.write(f) }
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
def s3
|
22
|
-
AWS::S3.new
|
23
|
-
end
|
24
|
-
|
25
|
-
def obj(bucket_name, obj_name)
|
26
|
-
buckets[bucket_name].objects[obj_name]
|
27
|
-
end
|
28
|
-
|
29
|
-
def buckets
|
30
|
-
s3.buckets
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|