man_eb_deployer 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/release.yml +31 -0
- data/.github/workflows/test.yml +16 -0
- data/.gitignore +12 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +143 -0
- data/Gemfile +10 -0
- data/LICENSE +22 -0
- data/README.md +138 -0
- data/Rakefile +12 -0
- data/TODOS.md +11 -0
- data/bin/eb_deploy +13 -0
- data/eb_deployer.gemspec +22 -0
- data/lib/eb_deployer/application.rb +96 -0
- data/lib/eb_deployer/aws_driver/beanstalk.rb +158 -0
- data/lib/eb_deployer/aws_driver/cloud_formation_driver.rb +53 -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/cf_event_source.rb +26 -0
- data/lib/eb_deployer/cloud_formation_provisioner.rb +120 -0
- data/lib/eb_deployer/component.rb +45 -0
- data/lib/eb_deployer/config_loader.rb +64 -0
- data/lib/eb_deployer/default_component.rb +32 -0
- data/lib/eb_deployer/default_config.rb +20 -0
- data/lib/eb_deployer/default_config.yml +159 -0
- data/lib/eb_deployer/deployment_strategy/blue_green.rb +79 -0
- data/lib/eb_deployer/deployment_strategy/blue_only.rb +45 -0
- data/lib/eb_deployer/deployment_strategy/inplace_update.rb +16 -0
- data/lib/eb_deployer/deployment_strategy.rb +20 -0
- data/lib/eb_deployer/eb_environment.rb +204 -0
- data/lib/eb_deployer/eb_event_source.rb +35 -0
- data/lib/eb_deployer/environment.rb +60 -0
- data/lib/eb_deployer/event_poller.rb +51 -0
- data/lib/eb_deployer/package.rb +39 -0
- data/lib/eb_deployer/resource_stacks.rb +20 -0
- data/lib/eb_deployer/smoke_test.rb +23 -0
- data/lib/eb_deployer/tasks.rb +45 -0
- data/lib/eb_deployer/throttling_handling.rb +17 -0
- data/lib/eb_deployer/utils.rb +33 -0
- data/lib/eb_deployer/version.rb +3 -0
- data/lib/eb_deployer/version_cleaner.rb +30 -0
- data/lib/eb_deployer.rb +339 -0
- data/lib/generators/eb_deployer/install/install_generator.rb +82 -0
- data/lib/generators/eb_deployer/install/templates/eb_deployer.rake +1 -0
- data/lib/generators/eb_deployer/install/templates/eb_deployer.yml.erb +181 -0
- data/lib/generators/eb_deployer/install/templates/ebextensions/01_postgres_packages.config +5 -0
- data/lib/generators/eb_deployer/install/templates/postgres_rds.json +88 -0
- data/test/aws_driver_stubs.rb +350 -0
- data/test/beanstalk_test.rb +23 -0
- data/test/blue_green_deploy_test.rb +114 -0
- data/test/blue_only_deploy_test.rb +78 -0
- data/test/cf_event_poller_test.rb +32 -0
- data/test/cloud_formation_provisioner_test.rb +47 -0
- data/test/config_loader_test.rb +205 -0
- data/test/deploy_test.rb +42 -0
- data/test/eb_environment_test.rb +120 -0
- data/test/eb_event_poller_test.rb +32 -0
- data/test/inplace_update_deploy_test.rb +110 -0
- data/test/multi_components_deploy_test.rb +164 -0
- data/test/rails_generators_test.rb +67 -0
- data/test/resources_deploy_test.rb +191 -0
- data/test/smoke_test_test.rb +23 -0
- data/test/template_deploy_test.rb +13 -0
- data/test/test_helper.rb +68 -0
- data/test/tier_setting_deploy_test.rb +24 -0
- data/test/versions_deploy_test.rb +120 -0
- metadata +176 -0
@@ -0,0 +1,158 @@
|
|
1
|
+
module EbDeployer
|
2
|
+
module AWSDriver
|
3
|
+
class Beanstalk
|
4
|
+
include Utils
|
5
|
+
attr_reader :client
|
6
|
+
|
7
|
+
def initialize(client=Aws::ElasticBeanstalk::Client.new)
|
8
|
+
@client = client
|
9
|
+
end
|
10
|
+
|
11
|
+
def create_application(app)
|
12
|
+
@client.create_application(:application_name => app)
|
13
|
+
end
|
14
|
+
|
15
|
+
def delete_application(app)
|
16
|
+
@client.delete_application(:application_name => app)
|
17
|
+
end
|
18
|
+
|
19
|
+
def application_exists?(app)
|
20
|
+
@client.describe_applications(:application_names => [app])[:applications].any?
|
21
|
+
end
|
22
|
+
|
23
|
+
def update_environment_settings(app, env, settings)
|
24
|
+
env_id = convert_env_name_to_id(app, [env]).first
|
25
|
+
@client.update_environment(:environment_id => env_id, :option_settings => settings)
|
26
|
+
end
|
27
|
+
|
28
|
+
def update_environment(app_name, env_name, version, tier, settings, template_name)
|
29
|
+
env_id = convert_env_name_to_id(app_name, [env_name]).first
|
30
|
+
request = reject_nil({
|
31
|
+
:environment_id => env_id,
|
32
|
+
:version_label => version,
|
33
|
+
:option_settings => settings,
|
34
|
+
:tier => environment_tier(tier),
|
35
|
+
:template_name => template_name
|
36
|
+
})
|
37
|
+
@client.update_environment(request)
|
38
|
+
end
|
39
|
+
|
40
|
+
def environment_exists?(app_name, env_name)
|
41
|
+
alive_envs(app_name, [env_name]).any?
|
42
|
+
end
|
43
|
+
|
44
|
+
def environment_names_for_application(app_name)
|
45
|
+
alive_envs(app_name).collect { |env| env[:environment_name] }
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_environment(app_name, env_name, stack_name, cname_prefix, version, tier, tags, settings, template_name)
|
49
|
+
request = reject_nil({
|
50
|
+
:application_name => app_name,
|
51
|
+
:environment_name => env_name,
|
52
|
+
:solution_stack_name => stack_name,
|
53
|
+
:version_label => version,
|
54
|
+
:option_settings => settings,
|
55
|
+
:tier => environment_tier(tier),
|
56
|
+
:cname_prefix => cname_prefix,
|
57
|
+
:tags => tags,
|
58
|
+
:template_name => template_name
|
59
|
+
})
|
60
|
+
@client.create_environment(request)
|
61
|
+
end
|
62
|
+
|
63
|
+
def delete_environment(app_name, env_name)
|
64
|
+
@client.terminate_environment(:environment_name => env_name)
|
65
|
+
end
|
66
|
+
|
67
|
+
def delete_application_version(app_name, version, delete_source_bundle)
|
68
|
+
request = {
|
69
|
+
:application_name => app_name,
|
70
|
+
:version_label => version,
|
71
|
+
:delete_source_bundle => delete_source_bundle
|
72
|
+
}
|
73
|
+
@client.delete_application_version(request)
|
74
|
+
end
|
75
|
+
|
76
|
+
def create_application_version(app_name, version_label, source_bundle)
|
77
|
+
@client.create_application_version(:application_name => app_name,
|
78
|
+
:source_bundle => source_bundle,
|
79
|
+
:version_label => version_label)
|
80
|
+
end
|
81
|
+
|
82
|
+
def application_version_labels(app_name)
|
83
|
+
application_versions(app_name).map { |apv| apv[:version_label] }
|
84
|
+
end
|
85
|
+
|
86
|
+
def application_versions(app_name)
|
87
|
+
request = { :application_name => app_name }
|
88
|
+
@client.describe_application_versions(request)[:application_versions]
|
89
|
+
end
|
90
|
+
|
91
|
+
def fetch_events(app_name, env_name, params, &block)
|
92
|
+
response = @client.describe_events(params.merge(:application_name => app_name,
|
93
|
+
:environment_name => env_name))
|
94
|
+
return [response[:events], response[:next_token]]
|
95
|
+
end
|
96
|
+
|
97
|
+
def environment_cname_prefix(app_name, env_name)
|
98
|
+
cname = environment_cname(app_name, env_name)
|
99
|
+
if cname =~ /^([^\.]+)(?:\.(?:[a-z0-9\-]+))?\.elasticbeanstalk\.com/i
|
100
|
+
$1
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def environment_cname(app_name, env_name)
|
105
|
+
get_environment_attribute(app_name, env_name, :cname)
|
106
|
+
end
|
107
|
+
|
108
|
+
def environment_health_state(app_name, env_name)
|
109
|
+
get_environment_attribute(app_name, env_name, :health)
|
110
|
+
end
|
111
|
+
|
112
|
+
def environment_status(app_name, env_name)
|
113
|
+
get_environment_attribute(app_name, env_name, :status)
|
114
|
+
end
|
115
|
+
|
116
|
+
def environment_verion_label(app_name, env_name)
|
117
|
+
get_environment_attribute(app_name, env_name, :version_label)
|
118
|
+
end
|
119
|
+
|
120
|
+
def environment_swap_cname(app_name, env1, env2)
|
121
|
+
env1_id, env2_id = convert_env_name_to_id(app_name, [env1, env2])
|
122
|
+
@client.swap_environment_cnames(:source_environment_id => env1_id,
|
123
|
+
:destination_environment_id => env2_id)
|
124
|
+
end
|
125
|
+
|
126
|
+
def list_solution_stack_names
|
127
|
+
@client.list_available_solution_stacks[:solution_stacks]
|
128
|
+
end
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
TIERS = [
|
133
|
+
{:name=>"Worker", :type=>"SQS/HTTP"},
|
134
|
+
{:name=>"WebServer", :type=>"Standard"}
|
135
|
+
]
|
136
|
+
|
137
|
+
def get_environment_attribute(app_name, env_name, attribute)
|
138
|
+
env = alive_envs(app_name, [env_name]).first
|
139
|
+
env && env[attribute]
|
140
|
+
end
|
141
|
+
|
142
|
+
def environment_tier(name)
|
143
|
+
TIERS.find {|t| t[:name].downcase == name.downcase} || raise("No tier found with name #{name.inspect}")
|
144
|
+
end
|
145
|
+
|
146
|
+
def convert_env_name_to_id(app_name, env_names)
|
147
|
+
envs = alive_envs(app_name, env_names)
|
148
|
+
envs.map { |env| env[:environment_id] }
|
149
|
+
end
|
150
|
+
|
151
|
+
def alive_envs(app_name, env_names=[])
|
152
|
+
envs = @client.describe_environments(:application_name => app_name, :environment_names => env_names)[:environments]
|
153
|
+
|
154
|
+
envs.select {|e| e[:status] != 'Terminated' }
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module EbDeployer
|
2
|
+
module AWSDriver
|
3
|
+
class CloudFormationDriver
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@client = Aws::CloudFormation::Client.new
|
7
|
+
end
|
8
|
+
|
9
|
+
def stack_exists?(name)
|
10
|
+
describe_stack(name)
|
11
|
+
true
|
12
|
+
rescue Aws::CloudFormation::Errors::ValidationError
|
13
|
+
false
|
14
|
+
end
|
15
|
+
|
16
|
+
def create_stack(name, template, opts)
|
17
|
+
@client.create_stack(opts.merge(:stack_name => name,
|
18
|
+
:template_body => template,
|
19
|
+
:parameters => convert_parameters(opts[:parameters])))
|
20
|
+
end
|
21
|
+
|
22
|
+
def update_stack(name, template, opts)
|
23
|
+
@client.update_stack(opts.merge(:stack_name => name,
|
24
|
+
:template_body => template,
|
25
|
+
:parameters => convert_parameters(opts[:parameters])))
|
26
|
+
end
|
27
|
+
|
28
|
+
def query_output(name, key)
|
29
|
+
output = describe_stack(name)[:outputs].find { |o| o[:output_key] == key }
|
30
|
+
output && output[:output_value]
|
31
|
+
end
|
32
|
+
|
33
|
+
def fetch_events(name, options={})
|
34
|
+
response = @client.describe_stack_events(options.merge(:stack_name => name))
|
35
|
+
return response.stack_events, response.next_token
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def describe_stack(name)
|
41
|
+
@client.describe_stacks(:stack_name => name)[:stacks].first
|
42
|
+
end
|
43
|
+
|
44
|
+
def log(msg)
|
45
|
+
puts "[#{Time.now.utc}][cloud_formation_driver] #{msg}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def convert_parameters(params)
|
49
|
+
params.map { |k, v| {:parameter_key => k, :parameter_value => v}}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module EbDeployer
|
2
|
+
module AWSDriver
|
3
|
+
class S3Driver
|
4
|
+
def create_bucket(bucket_name)
|
5
|
+
s3.create_bucket(:bucket => bucket_name)
|
6
|
+
end
|
7
|
+
|
8
|
+
def bucket_exists?(bucket_name)
|
9
|
+
s3.bucket(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
|
+
o.upload_file(file)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
def s3
|
23
|
+
Aws::S3::Resource.new(client: Aws::S3::Client.new)
|
24
|
+
end
|
25
|
+
|
26
|
+
def obj(bucket_name, obj_name)
|
27
|
+
s3.bucket(bucket_name).object(obj_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
def buckets
|
31
|
+
s3.buckets
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module EbDeployer
|
2
|
+
class CfEventSource
|
3
|
+
def initialize(stack_name, cf_driver)
|
4
|
+
@stack_name = stack_name
|
5
|
+
@cf_driver = cf_driver
|
6
|
+
end
|
7
|
+
|
8
|
+
def get_anchor
|
9
|
+
events, _ = @cf_driver.fetch_events(@stack_name)
|
10
|
+
events.first
|
11
|
+
end
|
12
|
+
|
13
|
+
def fetch_events(from_anchor, &block)
|
14
|
+
events, next_token = @cf_driver.fetch_events(@stack_name)
|
15
|
+
should_continue = yield(events)
|
16
|
+
fetch_next(next_token, &block) if next_token && should_continue
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
def fetch_next(next_token, &block)
|
21
|
+
events, next_token = @cf_driver.fetch_events(@stack_name, :next_token => next_token)
|
22
|
+
should_continue = yield(events)
|
23
|
+
fetch_next(next_token, &block) if next_token && should_continue
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module EbDeployer
|
2
|
+
class ResourceNotInReadyState < StandardError
|
3
|
+
end
|
4
|
+
|
5
|
+
class CloudFormationProvisioner
|
6
|
+
SUCCESS_STATS = ["CREATE_COMPLETE", "UPDATE_COMPLETE"]
|
7
|
+
FAILED_STATS = ["CREATE_FAILED", "UPDATE_FAILED", "UPDATE_ROLLBACK_COMPLETE"]
|
8
|
+
|
9
|
+
def initialize(stack_name, cf_driver)
|
10
|
+
@stack_name = stack_name
|
11
|
+
@cf_driver = cf_driver
|
12
|
+
@poller = EventPoller.new(CfEventSource.new(@stack_name, @cf_driver))
|
13
|
+
end
|
14
|
+
|
15
|
+
def provision(resources, tags)
|
16
|
+
resources = symbolize_keys(resources)
|
17
|
+
template = File.read(resources[:template])
|
18
|
+
capabilities = resources[:capabilities] || []
|
19
|
+
params = resources[:inputs] || resources[:parameters] || {}
|
20
|
+
policy = File.read(resources[:policy]) if resources[:policy]
|
21
|
+
override_policy = resources[:override_policy] || false
|
22
|
+
anchor = nil
|
23
|
+
begin
|
24
|
+
if stack_exists?
|
25
|
+
anchor = @poller.get_anchor
|
26
|
+
update_stack(template, params, capabilities, policy, override_policy, tags)
|
27
|
+
else
|
28
|
+
create_stack(template, params, capabilities, policy, tags)
|
29
|
+
end
|
30
|
+
rescue Aws::CloudFormation::Errors::ValidationError => e
|
31
|
+
if e.message =~ /No updates are to be performed/
|
32
|
+
log(e.message)
|
33
|
+
return
|
34
|
+
else
|
35
|
+
raise
|
36
|
+
end
|
37
|
+
end
|
38
|
+
wait_for_stack_op_terminate(anchor)
|
39
|
+
log("Resource stack provisioned successfully")
|
40
|
+
end
|
41
|
+
|
42
|
+
def transform_outputs(resources)
|
43
|
+
resources = symbolize_keys(resources)
|
44
|
+
outputs = resources[:outputs] || {}
|
45
|
+
transforms = resources[:transforms] || {}
|
46
|
+
transform_output_to_settings(convert_to_transforms(outputs).merge(transforms))
|
47
|
+
end
|
48
|
+
|
49
|
+
def output(key)
|
50
|
+
@cf_driver.query_output(@stack_name, key)
|
51
|
+
rescue Aws::CloudFormation::Errors::ValidationError
|
52
|
+
raise ResourceNotInReadyState.new("Resource stack not in ready state yet, perhaps you should provision it first?")
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
#todo: remove duplication
|
58
|
+
def symbolize_keys(hash)
|
59
|
+
hash.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
def convert_to_transforms(outputs)
|
64
|
+
outputs.inject({}) do |memo, (key, value)|
|
65
|
+
memo[key] = lambda { |output_value| value.merge('value' => output_value) }
|
66
|
+
memo
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def update_stack(template, params, capabilities, policy, override_policy, tags)
|
71
|
+
opts = {:capabilities => capabilities, :parameters => params, :tags => tags}
|
72
|
+
if (policy)
|
73
|
+
opts[:stack_policy_during_update_body] = policy if override_policy
|
74
|
+
log("Using temporary stack policy to apply resource stack updates") if override_policy
|
75
|
+
opts[:stack_policy_body] = policy unless override_policy
|
76
|
+
log("Applying new stack policy to existing resource stack") unless override_policy
|
77
|
+
end
|
78
|
+
@cf_driver.update_stack(@stack_name, template, opts)
|
79
|
+
end
|
80
|
+
|
81
|
+
def stack_exists?
|
82
|
+
@cf_driver.stack_exists?(@stack_name)
|
83
|
+
end
|
84
|
+
|
85
|
+
def create_stack(template, params, capabilities, policy, tags)
|
86
|
+
opts = {:disable_rollback => true, :capabilities => capabilities, :parameters => params, :tags => tags}
|
87
|
+
opts[:stack_policy_body] = policy if policy
|
88
|
+
log("Applying stack policy to new resource stack") if policy
|
89
|
+
@cf_driver.create_stack(@stack_name, template, opts)
|
90
|
+
end
|
91
|
+
|
92
|
+
def transform_output_to_settings(transforms)
|
93
|
+
(transforms || []).inject([]) do |settings, pair|
|
94
|
+
key, transform = pair
|
95
|
+
settings << transform.call(output(key))
|
96
|
+
settings
|
97
|
+
end.flatten
|
98
|
+
end
|
99
|
+
|
100
|
+
def wait_for_stack_op_terminate(anchor)
|
101
|
+
@poller.poll(anchor) do |event|
|
102
|
+
log_event(event)
|
103
|
+
if FAILED_STATS.include?(event.resource_status)
|
104
|
+
raise "Resource stack update failed!"
|
105
|
+
end
|
106
|
+
|
107
|
+
break if event.logical_resource_id == @stack_name && SUCCESS_STATS.include?(event.resource_status)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def log_event(event)
|
112
|
+
puts "[#{event.timestamp}][cloud_formation_provisioner] #{event.resource_type}(#{event.logical_resource_id}) #{event.resource_status} \"#{event.resource_status_reason}\""
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
def log(msg)
|
117
|
+
puts "[#{Time.now.utc}][cloud_formation_provisioner] #{msg}"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module EbDeployer
|
2
|
+
class Component
|
3
|
+
attr_reader :name
|
4
|
+
|
5
|
+
def initialize(name, env, options, eb_driver)
|
6
|
+
@name = name
|
7
|
+
@env = env
|
8
|
+
@eb_driver = eb_driver
|
9
|
+
@options = options.dup
|
10
|
+
@component_eb_settings = @options.delete(:option_settings) || []
|
11
|
+
@component_inactive_settings = @options.delete(:inactive_settings) || []
|
12
|
+
strategy_name = @options[:strategy] || @env.strategy_name
|
13
|
+
@strategy = DeploymentStrategy.create(self, strategy_name)
|
14
|
+
end
|
15
|
+
|
16
|
+
def cname_prefix
|
17
|
+
@options[:cname_prefix] || default_cname_prefix
|
18
|
+
end
|
19
|
+
|
20
|
+
def deploy(version_label, eb_settings, inactive_settings=[])
|
21
|
+
@strategy.test_compatibility(create_options)
|
22
|
+
@strategy.deploy(version_label,
|
23
|
+
eb_settings + @component_eb_settings,
|
24
|
+
inactive_settings + @component_inactive_settings)
|
25
|
+
end
|
26
|
+
|
27
|
+
def new_eb_env(suffix=nil, cname_prefix_overriding=nil)
|
28
|
+
EbEnvironment.new(@env.app_name,
|
29
|
+
[@env.name, @name, suffix].compact.join('-'),
|
30
|
+
@eb_driver,
|
31
|
+
create_options.merge(:cname_prefix => cname_prefix_overriding || cname_prefix))
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def create_options
|
38
|
+
@env.creation_opts.merge(@options)
|
39
|
+
end
|
40
|
+
|
41
|
+
def default_cname_prefix
|
42
|
+
[@env.app_name, @env.name, @name].join('-')
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'digest'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module EbDeployer
|
6
|
+
class ConfigLoader
|
7
|
+
include Utils
|
8
|
+
|
9
|
+
class EvalBinding
|
10
|
+
attr_reader :environment, :package_digest
|
11
|
+
def initialize(package_digest, env)
|
12
|
+
@package_digest = package_digest
|
13
|
+
@environment = env
|
14
|
+
end
|
15
|
+
|
16
|
+
def random_hash
|
17
|
+
SecureRandom.hex[0..9]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def load(options)
|
22
|
+
options = options.dup
|
23
|
+
package_digest = package_digest(options[:package])
|
24
|
+
config_file = options.delete(:config_file)
|
25
|
+
|
26
|
+
env = options[:environment]
|
27
|
+
config_settings = load_config_settings(config_file, package_digest, env)
|
28
|
+
|
29
|
+
app_name = config_settings[:application]
|
30
|
+
|
31
|
+
common_settings = symbolize_keys(config_settings[:common])
|
32
|
+
common_settings[:version_label] ||= package_digest
|
33
|
+
|
34
|
+
envs = config_settings[:environments]
|
35
|
+
raise "Environment #{env} is not defined in #{config_file}" unless envs.has_key?(env)
|
36
|
+
env_settings = symbolize_keys(envs[env] || {})
|
37
|
+
env_option_settings = env_settings.delete(:option_settings) || []
|
38
|
+
|
39
|
+
ret = options.merge(common_settings).merge(env_settings)
|
40
|
+
ret[:application] = app_name
|
41
|
+
ret[:option_settings] ||= []
|
42
|
+
ret[:option_settings] += env_option_settings
|
43
|
+
ret
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def load_config_settings(config_file, package_digest, env)
|
49
|
+
yaml = ERB.new(File.read(config_file)).
|
50
|
+
result(eval_binding(package_digest, env))
|
51
|
+
symbolize_keys(YAML.load(yaml))
|
52
|
+
end
|
53
|
+
|
54
|
+
def eval_binding(package_digest, env)
|
55
|
+
EvalBinding.new(package_digest, env).instance_eval { binding }
|
56
|
+
end
|
57
|
+
|
58
|
+
def package_digest(package)
|
59
|
+
return nil unless package
|
60
|
+
return package unless File.exist?(package)
|
61
|
+
Digest::MD5.file(package).hexdigest
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module EbDeployer
|
2
|
+
class DefaultComponent
|
3
|
+
def initialize(env, creation_opts, strategy_name, eb_driver)
|
4
|
+
@env = env
|
5
|
+
@eb_driver = eb_driver
|
6
|
+
@creation_opts = creation_opts
|
7
|
+
@strategy = DeploymentStrategy.create(self, strategy_name)
|
8
|
+
end
|
9
|
+
|
10
|
+
def cname_prefix
|
11
|
+
@creation_opts[:cname_prefix] || default_cname_prefix
|
12
|
+
end
|
13
|
+
|
14
|
+
def deploy(version_label, eb_settings, inactive_settings=[])
|
15
|
+
@strategy.test_compatibility(@creation_opts)
|
16
|
+
@strategy.deploy(version_label, eb_settings, inactive_settings)
|
17
|
+
end
|
18
|
+
|
19
|
+
def new_eb_env(suffix=nil, cname_prefix_overriding=nil)
|
20
|
+
EbEnvironment.new(@env.app_name,
|
21
|
+
[@env.name, suffix].compact.join('-'),
|
22
|
+
@eb_driver,
|
23
|
+
@creation_opts.merge(:cname_prefix => cname_prefix_overriding || cname_prefix))
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def default_cname_prefix
|
29
|
+
[@env.app_name, @env.name].join('-')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module EbDeployer
|
2
|
+
class DefaultConfig
|
3
|
+
attr_reader :app_name
|
4
|
+
|
5
|
+
def initialize(app_name)
|
6
|
+
@app_name = app_name.gsub('_', '-')
|
7
|
+
end
|
8
|
+
|
9
|
+
def write_to(path)
|
10
|
+
FileUtils.mkdir_p(File.dirname(path))
|
11
|
+
File.open(path, 'w') { |f| f << ERB.new(File.read(config_template)).result(binding) }
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def config_template
|
17
|
+
File.expand_path("../default_config.yml", __FILE__)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|