aws_beanstalk_tunkki 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/aws_beanstalk_tunkki +4 -0
- data/lib/aws_beanstalk_tunkki.rb +253 -0
- metadata +86 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f226c4c68ba5bd6380f70933d8c04b449a89fdd6e27ad53333e89758f6333682
|
4
|
+
data.tar.gz: 39848528ce0ce80fc0e14ab678573d2d7ede28bb34c0031061a04a769533d31c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f4229f11c843d1edffa590cb0f3d5e43b5d3304e952d9d2e2179466a396bd38d2e17f04a6b752e0beed12f0371f13adb2e8825f33250bfad0a1a80489dc19158
|
7
|
+
data.tar.gz: 810275c477f8ebe857f71cdd4d9865b11b147e7ee65c83bb36d952ab4ecef2afe8868855bea26a306832cbe521902e6528cf7f7b54cfd10be1ec456c30854604
|
@@ -0,0 +1,253 @@
|
|
1
|
+
require 'aws-sdk-elasticbeanstalk'
|
2
|
+
require 'aws-sdk-s3'
|
3
|
+
require 'optparse'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
class AWSBeanstalkTunkki
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
init_deploy_variables()
|
10
|
+
end
|
11
|
+
|
12
|
+
def run_deployment
|
13
|
+
application = get_bs_app()
|
14
|
+
if !check_bs_env()
|
15
|
+
create_bs_env(application.configuration_templates)
|
16
|
+
end
|
17
|
+
deploy_app(generate_version_label())
|
18
|
+
end
|
19
|
+
|
20
|
+
def init_deploy_variables
|
21
|
+
parse_command_line_options()
|
22
|
+
set_application_environment()
|
23
|
+
set_aws_clients()
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse_command_line_options
|
27
|
+
OptionParser.new do |opt|
|
28
|
+
opt.on('--app APP_NAME') { |app_name| @app = app_name }
|
29
|
+
opt.on('--branch BRANCH_NAME') { |branch_name| @branch = branch_name }
|
30
|
+
opt.on('--dir DIR') { |dir| @dir = dir }
|
31
|
+
opt.on('--region REGION') { |aws_region| @aws_region = aws_region }
|
32
|
+
opt.on('--local LOCAL') { |local| @local = local }
|
33
|
+
end.parse!
|
34
|
+
raise "Beanstalk application (--app) required!" if @app.nil?
|
35
|
+
raise "Git branch (--branch) required!" if @branch.nil?
|
36
|
+
raise "App dir location (--dir) required!" if @branch.nil?
|
37
|
+
raise "AWS Region missing (--region) required!" if @aws_region.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
def set_application_environment
|
41
|
+
case @branch
|
42
|
+
when /\Aprod/
|
43
|
+
set_application_environment_vars(environment: 'prod', env_simple: 'production')
|
44
|
+
when /\Ast/
|
45
|
+
set_application_environment_vars(environment: 'st', env_simple: 'staging')
|
46
|
+
when /\Adev/
|
47
|
+
set_application_environment_vars(environment: 'dev', env_simple: 'development')
|
48
|
+
when /\Aft/
|
49
|
+
set_application_environment_vars(environment: 'ft', env_simple: 'feature')
|
50
|
+
else
|
51
|
+
raise "Invalid deployment branch name detected! Branch name must start with prod, st, dev or ft"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def set_application_environment_vars(environment: 'dev', env_simple: '')
|
56
|
+
puts "Using branch '#{@branch}' as #{env_simple}"
|
57
|
+
@bs_env = @branch.gsub(/[\/:;.,+_<>#]/, '-')
|
58
|
+
@environment = environment
|
59
|
+
@bs_env_simple = env_simple
|
60
|
+
end
|
61
|
+
|
62
|
+
def set_aws_clients
|
63
|
+
if @local == "true"
|
64
|
+
# Deploy from local machine, requires AWS_PROFILE=default and aws-mfa based login before execution
|
65
|
+
credentials = Aws::SharedCredentials.new()
|
66
|
+
else
|
67
|
+
aws_access_key_id, aws_secret_access_key = *get_aws_keys()
|
68
|
+
raise "AWS keys are not defined!" if aws_access_key_id.nil? || aws_secret_access_key.nil?
|
69
|
+
credentials = Aws::Credentials.new(aws_access_key_id, aws_secret_access_key)
|
70
|
+
end
|
71
|
+
@elasticbeanstalk = Aws::ElasticBeanstalk::Client.new(region: @aws_region, credentials: credentials)
|
72
|
+
@s3 = Aws::S3::Client.new(region: @aws_region, credentials: credentials)
|
73
|
+
bucket = @s3.list_buckets.buckets.find { |b| /\Aelasticbeanstalk-#{@aws_region}/ =~ b.name }
|
74
|
+
raise "Could not resolve s3 bucket name." if bucket.nil?
|
75
|
+
@s3_bucket_name = bucket.name
|
76
|
+
end
|
77
|
+
|
78
|
+
def get_aws_keys
|
79
|
+
case @environment
|
80
|
+
when 'prod', 'st'
|
81
|
+
[ENV['AWS_ACCESS_KEY_ID_PROD'], ENV['AWS_SECRET_ACCESS_KEY_PROD']]
|
82
|
+
when 'dev', 'ft'
|
83
|
+
[ENV['AWS_ACCESS_KEY_ID_DEV'], ENV['AWS_SECRET_ACCESS_KEY_DEV']]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def get_bs_app
|
88
|
+
application_description = @elasticbeanstalk.describe_applications({application_names: [@app]})
|
89
|
+
raise "Application '#{@app}' not found." if application_description.applications.empty?
|
90
|
+
application_description.applications.first
|
91
|
+
end
|
92
|
+
|
93
|
+
def check_bs_env
|
94
|
+
env_name = "#{@app}-#{@bs_env}"
|
95
|
+
puts "Checking if Beanstalk environment '#{env_name}' in application '#{@app}' exists."
|
96
|
+
application_environments = @elasticbeanstalk.describe_environments({environment_names: [env_name]})
|
97
|
+
if is_environment_found?(application_environments.environments)
|
98
|
+
puts "Environment '#{env_name}' already exists in application '#{@app}'."
|
99
|
+
true
|
100
|
+
else
|
101
|
+
puts "Environment '#{env_name}' does not exist."
|
102
|
+
false
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def is_environment_found?(environments)
|
107
|
+
!environments.empty? && !environments.all? { |env| env.status == 'Terminated' }
|
108
|
+
end
|
109
|
+
|
110
|
+
def create_bs_env(configuration_templates)
|
111
|
+
puts "Searching for Beanstalk configuration template.."
|
112
|
+
|
113
|
+
app_bs_env_simple = "#{@app}-#{@bs_env_simple}"
|
114
|
+
app_default = "#{@app}-default"
|
115
|
+
app_bs_env = "#{@app}-#{@bs_env}"
|
116
|
+
|
117
|
+
conf_template = find_configuration_template(configuration_templates)
|
118
|
+
puts "Using '#{conf_template}' configuration template."
|
119
|
+
puts "Launching new environment '#{@app}-#{@bs_env}' to application '#{@app}'."
|
120
|
+
|
121
|
+
begin
|
122
|
+
@elasticbeanstalk.create_environment(
|
123
|
+
{
|
124
|
+
application_name: @app,
|
125
|
+
environment_name: app_bs_env,
|
126
|
+
cname_prefix: app_bs_env,
|
127
|
+
template_name: conf_template,
|
128
|
+
})
|
129
|
+
if (poll_for_environment_changes(app_bs_env) { |env| env.status != 'Launching' })
|
130
|
+
puts "Created environment '#{app_bs_env}'!"
|
131
|
+
else
|
132
|
+
raise "Timeout when creating environment."
|
133
|
+
end
|
134
|
+
rescue => e
|
135
|
+
raise "Environment launch failed, unable to proceed. Error: #{e}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def find_configuration_template(configuration_templates)
|
140
|
+
configuration_templates.find do |tpl|
|
141
|
+
/(?<conf_app_stub>[\w-]+)-(?<conf_env_stub>\w+)-\w+\z/ =~ tpl
|
142
|
+
conf_app_stub && conf_env_stub && @app.match(conf_app_stub) && @bs_env_simple.match(conf_env_stub)
|
143
|
+
end or raise "No configuration templates found, can't create environment."
|
144
|
+
end
|
145
|
+
|
146
|
+
def poll_for_environment_changes(env_name)
|
147
|
+
print "Making changes to environment #{env_name}"
|
148
|
+
ten_minutes = 60 * 10
|
149
|
+
ten_minutes.times do |i|
|
150
|
+
if (yield(@elasticbeanstalk.describe_environments({environment_names: [env_name]}).environments.first))
|
151
|
+
print "\n"
|
152
|
+
return true
|
153
|
+
else
|
154
|
+
print '.'
|
155
|
+
sleep(1)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
false
|
159
|
+
end
|
160
|
+
|
161
|
+
def create_app_version
|
162
|
+
version_label = generate_version_label()
|
163
|
+
response = @elasticbeanstalk.create_application_version(
|
164
|
+
{
|
165
|
+
application_name: @app,
|
166
|
+
version_label: version_label,
|
167
|
+
})
|
168
|
+
version_label
|
169
|
+
rescue => e
|
170
|
+
raise "Application version launch failed. Error: #{e}"
|
171
|
+
end
|
172
|
+
|
173
|
+
def deploy_app(version_label)
|
174
|
+
puts "Deploying application to Beanstalk environment."
|
175
|
+
s3_upload_details = upload_version_to_s3(version_label)
|
176
|
+
create_app_version(version_label, s3_upload_details)
|
177
|
+
update_environment(version_label)
|
178
|
+
end
|
179
|
+
|
180
|
+
def upload_version_to_s3(version_label)
|
181
|
+
zip_name = make_zip_file(version_label)
|
182
|
+
zip_name_with_path = "#{@app}/#{zip_name}"
|
183
|
+
print "Uploading '#{zip_name}' to S3 bucket (#{@s3_bucket_name})... "
|
184
|
+
begin
|
185
|
+
File.open(zip_name) do |zip_file|
|
186
|
+
@s3.put_object(bucket: @s3_bucket_name, body: zip_file, key: zip_name_with_path)
|
187
|
+
end
|
188
|
+
print "Done!\n"
|
189
|
+
{bucket: @s3_bucket_name, file: zip_name_with_path}
|
190
|
+
rescue => e
|
191
|
+
raise "Upload to S3 bucket (#{@s3_bucket_name}) failed. Error: #{e}"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def make_zip_file(version_label)
|
196
|
+
print 'Zipping application files ... '
|
197
|
+
zip_name = "#{version_label}.zip"
|
198
|
+
`cd #{@dir}; zip #{zip_name} -r ./ -x *.git* *.log*`
|
199
|
+
raise "Creating ZIP failed!" if $?.exitstatus != 0
|
200
|
+
FileUtils.mv("#{@dir}/#{zip_name}", './')
|
201
|
+
print "Done!\n"
|
202
|
+
zip_name
|
203
|
+
end
|
204
|
+
|
205
|
+
def create_app_version(version_label, s3_upload_details)
|
206
|
+
if @app.length > 199
|
207
|
+
raise "Error! Beanstalk environment name max length is 200 characters! Length: #{@app.length} characters"
|
208
|
+
end
|
209
|
+
@elasticbeanstalk.create_application_version(
|
210
|
+
{
|
211
|
+
application_name: @app,
|
212
|
+
version_label: version_label,
|
213
|
+
source_bundle: {
|
214
|
+
s3_bucket: s3_upload_details[:bucket],
|
215
|
+
s3_key: s3_upload_details[:file],
|
216
|
+
},
|
217
|
+
auto_create_application: true,
|
218
|
+
process: true,
|
219
|
+
})
|
220
|
+
puts "Created application version '#{version_label}'"
|
221
|
+
rescue => e
|
222
|
+
raise "Creating application version '#{version_label}' failed. Error: #{e}"
|
223
|
+
end
|
224
|
+
|
225
|
+
def update_environment(version_label)
|
226
|
+
sleep(5) # Environment is in an invalid state for this operation. Must be Ready. (RuntimeError)
|
227
|
+
@elasticbeanstalk.update_environment(
|
228
|
+
{
|
229
|
+
environment_name: "#{@app}-#{@bs_env}",
|
230
|
+
version_label: version_label,
|
231
|
+
option_settings: [
|
232
|
+
{
|
233
|
+
namespace: "aws:elasticbeanstalk:command",
|
234
|
+
option_name: "Timeout",
|
235
|
+
value: "1800",
|
236
|
+
}
|
237
|
+
]
|
238
|
+
})
|
239
|
+
if (poll_for_environment_changes("#{@app}-#{@bs_env}") { |env| env.status != 'Updating' })
|
240
|
+
puts "Updated '#{@app}-#{@bs_env}' environment successfully."
|
241
|
+
else
|
242
|
+
raise "Timeout of 10 minutes reached when updating environment."
|
243
|
+
end
|
244
|
+
rescue => e
|
245
|
+
raise "Updating environment failed. Error: #{e}"
|
246
|
+
end
|
247
|
+
|
248
|
+
def generate_version_label
|
249
|
+
time = Time.now
|
250
|
+
"#{@app}-#{@bs_env_simple}-#{time.strftime('%Y-%m-%d-%H%M%S')}"
|
251
|
+
end
|
252
|
+
|
253
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: aws_beanstalk_tunkki
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Valtteri Pajunen
|
8
|
+
- Janne Saraste
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2019-12-12 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: aws-sdk-elasticbeanstalk
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.26'
|
21
|
+
- - "~>"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: '1.26'
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
requirements:
|
28
|
+
- - ">="
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '1.26'
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.26'
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: aws-sdk-s3
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.59'
|
41
|
+
- - "~>"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '1.59'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - ">="
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '1.59'
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '1.59'
|
54
|
+
description: Tool for deploying your app to AWS ElasticBeanstalk.
|
55
|
+
email: IL.Tekniikka@iltalehti.fi
|
56
|
+
executables:
|
57
|
+
- aws_beanstalk_tunkki
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files: []
|
60
|
+
files:
|
61
|
+
- bin/aws_beanstalk_tunkki
|
62
|
+
- lib/aws_beanstalk_tunkki.rb
|
63
|
+
homepage: https://github.com/almamedia/aws-beanstalk-tunkki
|
64
|
+
licenses:
|
65
|
+
- MIT
|
66
|
+
metadata: {}
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options: []
|
69
|
+
require_paths:
|
70
|
+
- lib
|
71
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '0'
|
81
|
+
requirements: []
|
82
|
+
rubygems_version: 3.0.3
|
83
|
+
signing_key:
|
84
|
+
specification_version: 4
|
85
|
+
summary: AWS Beanstalk Tunkki
|
86
|
+
test_files: []
|