elastic_beans 0.2.0 → 0.3.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.
- checksums.yaml +4 -4
- data/README.md +91 -16
- data/exe/beans +26 -20
- data/lib/elastic_beans/application.rb +33 -1
- data/lib/elastic_beans/application_version.rb +18 -3
- data/lib/elastic_beans/aws/cloudformation_stack.rb +2 -0
- data/lib/elastic_beans/command/configure.rb +12 -18
- data/lib/elastic_beans/command/create.rb +8 -4
- data/lib/elastic_beans/command/deploy.rb +3 -3
- data/lib/elastic_beans/command/exec.rb +4 -3
- data/lib/elastic_beans/command/scale.rb +2 -2
- data/lib/elastic_beans/command/set_env.rb +4 -3
- data/lib/elastic_beans/command/talk.rb +1 -0
- data/lib/elastic_beans/command/version.rb +1 -0
- data/lib/elastic_beans/command.rb +2 -0
- data/lib/elastic_beans/configuration_template/base.rb +12 -2
- data/lib/elastic_beans/configuration_template/exec.rb +6 -0
- data/lib/elastic_beans/configuration_template/scheduler.rb +4 -0
- data/lib/elastic_beans/configuration_template/webserver.rb +11 -4
- data/lib/elastic_beans/configuration_template/worker.rb +6 -0
- data/lib/elastic_beans/configuration_template.rb +32 -11
- data/lib/elastic_beans/dns_entry.rb +2 -0
- data/lib/elastic_beans/env_vars.rb +6 -0
- data/lib/elastic_beans/environment/exec.rb +13 -4
- data/lib/elastic_beans/environment/scheduler.rb +13 -4
- data/lib/elastic_beans/environment/webserver.rb +13 -4
- data/lib/elastic_beans/environment/worker.rb +15 -4
- data/lib/elastic_beans/environment.rb +74 -18
- data/lib/elastic_beans/error/environments_not_ready.rb +2 -0
- data/lib/elastic_beans/error.rb +1 -0
- data/lib/elastic_beans/exec/init.rb +2 -0
- data/lib/elastic_beans/exec/sqs_consumer.rb +2 -0
- data/lib/elastic_beans/network.rb +1 -0
- data/lib/elastic_beans/rack/exec.rb +5 -0
- data/lib/elastic_beans/ui.rb +2 -0
- data/lib/elastic_beans/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2b231170798c366604081d7d0800c0c332a386d6
|
4
|
+
data.tar.gz: 661c9aca9b2ae4fdc6402cd02c5b3d37c4f62d76
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71da843ae45cfac1cf6fa2061df76383849d16cdb359c1ff7145975c25042ca8985d7501b2e57d09d2968d4b8b0246cf40f89ef73d98b6a165b4cb15ae17f8fa
|
7
|
+
data.tar.gz: 928d9e71798950eb693d0a9ad4a9ac720ca48e56de71b8cf074d0fd409e2c957119d2dd83fcc6dd8b757ef122e08bda185ff25fad6dacddedcf5db7d327bbfb0
|
data/README.md
CHANGED
@@ -19,9 +19,10 @@ As the SDK documentation suggests, using environment variables is recommended.
|
|
19
19
|
[configuration]: http://docs.aws.amazon.com/sdk-for-ruby/latest/DeveloperGuide/aws-ruby-sdk-getting-started.html#aws-ruby-sdk-configuration
|
20
20
|
|
21
21
|
# Pre-configure the application before creating environments
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
beans configure -n myapp-networking -a myapp \
|
23
|
+
-b SECRET_KEY_BASE -d DATABASE_URL -k KEYPAIR \
|
24
|
+
-p INTERNAL_PUBLIC_KEY -s SSL_CERTIFICATE_ARN \
|
25
|
+
[-i IMAGE_ID] [-t INSTANCE_TYPE] [-l LOGGING_HTTP_ENDPOINT]
|
25
26
|
|
26
27
|
# Create a webserver environment with a pretty DNS name at myapp.TLD (managed by Route53)
|
27
28
|
beans create -a myapp [-d myapp.TLD] [--tags=Environment:production Team:Unicorn] webserver
|
@@ -41,25 +42,27 @@ As the SDK documentation suggests, using environment variables is recommended.
|
|
41
42
|
# Set environment variables across all environments
|
42
43
|
beans setenv -a myapp REDIS_URL=redis://...
|
43
44
|
|
44
|
-
#
|
45
|
-
#
|
45
|
+
# Create an application version for the HEAD git commit in the working directory.
|
46
|
+
# Then deploy that version to each running environment.
|
46
47
|
beans deploy -a myapp
|
47
48
|
|
48
|
-
# Run one-off tasks
|
49
|
+
# Run one-off tasks and upload logs to the LOGGING_HTTP_ENDPOINT from `configure`
|
49
50
|
beans exec -a myapp rake db:migrate
|
50
51
|
|
51
52
|
# Update all existing environments and configuration
|
52
|
-
beans configure -n myapp-networking -a myapp
|
53
|
+
beans configure -n myapp-networking -a myapp \
|
54
|
+
[-b SECRET_KEY_BASE] [-d DATABASE_URL] [-k KEYPAIR] \
|
55
|
+
[-p INTERNAL_PUBLIC_KEY] [-s SSL_CERTIFICATE_ARN] \
|
56
|
+
[-i IMAGE_ID] [-t INSTANCE_TYPE] [-l LOGGING_HTTP_ENDPOINT]
|
53
57
|
|
54
58
|
### API
|
55
59
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
app.exec_command("rake db:migrate", sqs: Aws::SQS::Client.new)
|
60
|
+
Elastic Beans exposes the classes it uses to manage Elastic Beanstalk so you can call them from your own code.
|
61
|
+
[Check out the API documentation][api].
|
62
|
+
|
63
|
+
[api]: http://www.rubydoc.info/gems/elastic_beans
|
64
|
+
|
65
|
+
AWS SDK clients must be passed into Elastic Beans constructors.
|
63
66
|
|
64
67
|
### Periodic tasks
|
65
68
|
|
@@ -81,6 +84,7 @@ In `config/initializers/elastic_beans.rb`, add the middleware into your stack, b
|
|
81
84
|
name: "myapp",
|
82
85
|
cloudformation: Aws::CloudFormation::Client.new,
|
83
86
|
elastic_beanstalk: Aws::ElasticBeanstalk::Client.new,
|
87
|
+
s3: Aws::S3::Client.new,
|
84
88
|
),
|
85
89
|
sqs: Aws::SQS::Client.new,
|
86
90
|
logger: Rails.logger,
|
@@ -92,6 +96,7 @@ In `config/initializers/elastic_beans.rb`, add the middleware into your stack, b
|
|
92
96
|
name: "myapp",
|
93
97
|
cloudformation: Aws::CloudFormation::Client.new,
|
94
98
|
elastic_beanstalk: Aws::ElasticBeanstalk::Client.new,
|
99
|
+
s3: Aws::S3::Client.new,
|
95
100
|
),
|
96
101
|
sqs: Aws::SQS::Client.new,
|
97
102
|
logger: Rails.logger,
|
@@ -135,6 +140,12 @@ This way they can be computationally expensive without affecting application per
|
|
135
140
|
Additionally, they are not limited to the visibility timeout of an application background job queue.
|
136
141
|
Logs are persisted to an HTTPS endpoint upon command completion.
|
137
142
|
|
143
|
+
### Persistent configuration
|
144
|
+
|
145
|
+
Elastic Beans stores your configuration in configuration templates.
|
146
|
+
This means that you can terminate and create an environment and it will remember its setup from before.
|
147
|
+
In addition, changes to the configuration will affect existing and future environments.
|
148
|
+
|
138
149
|
### Shared code between environments
|
139
150
|
|
140
151
|
A Rails app supports multiple contexts with the same codebase.
|
@@ -155,7 +166,7 @@ The settings for your application are discovered from the [outputs of these Clou
|
|
155
166
|
|
156
167
|
The networking stack can be shared between many applications, but each application should have its own application stack.
|
157
168
|
For example, you might create separate "eb-development" and "eb-production" network stacks.
|
158
|
-
Then, create an Elastic Beanstalk application from a stack named "myapp."
|
169
|
+
Then, create an Elastic Beanstalk application named "myapp" from a stack named "myapp."
|
159
170
|
Finally, you can set it up with beans:
|
160
171
|
|
161
172
|
$ beans configure -n eb-development -a myapp ...
|
@@ -186,19 +197,83 @@ Elastic Beans will use the default names: `aws-elasticbeanstalk-ec2-role` and `a
|
|
186
197
|
### Application
|
187
198
|
|
188
199
|
Your Elastic Beanstalk application must already exist and also be created using CloudFormation.
|
200
|
+
The Elastic Beanstalk application name and CloudFormation stack name must be identical.
|
189
201
|
Its details will be discovered from the following outputs:
|
190
202
|
|
191
203
|
* `ExecQueueUrl`
|
192
204
|
* `Worker[Name]QueueUrl`
|
193
205
|
|
194
206
|
Where a separate worker environment will be configured for each queue `[Name]` that appears.
|
195
|
-
|
207
|
+
A default worker queue, i.e. `WorkerDefaultQueueUrl`, must exist.
|
196
208
|
|
197
209
|
### Code
|
198
210
|
|
199
211
|
Your application must use the [active-elastic-job gem](https://github.com/tawan/active-elastic-job) for background job processing.
|
200
212
|
Elastic Beans will set the `DISABLE_SQS_CONSUMER` environment variable appropriately in your environments.
|
201
213
|
|
214
|
+
### Known issues and limitations of the pre-release
|
215
|
+
|
216
|
+
Elastic Beans still has some rough edges that need to be worked out.
|
217
|
+
|
218
|
+
#### Authentication with AWS uses environment variables
|
219
|
+
|
220
|
+
Use the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables to authenticate with the AWS SDK.
|
221
|
+
|
222
|
+
#### Changes to the configuration in the AWS console are not persistent
|
223
|
+
|
224
|
+
Changing configuration in the AWS console will work fine, but if the setting is also saved in a configuration template it will be overwritten the next time you run `beans configure`.
|
225
|
+
|
226
|
+
#### Creating multiple environments simultaneously causes sample application to be deployed
|
227
|
+
|
228
|
+
Due to a bug in the version-finding code, creating multiple environments simultaneously can cause a sample application to be deployed to one of them (an empty version label).
|
229
|
+
|
230
|
+
#### End-to-end encryption requires some custom setup
|
231
|
+
|
232
|
+
Currently (pre-1.0), you must set up HTTPS yourself in nginx using an ebextension.
|
233
|
+
Use whatever certificate you like to do so, even a self-signed certificate is fine.
|
234
|
+
Use the public key from this certificate as the `--public-key` option to `beans configure`.
|
235
|
+
|
236
|
+
#### Environment variables are mostly hidden
|
237
|
+
|
238
|
+
`beans setenv` sets environment variables in S3, but there's no way to *get* them.
|
239
|
+
|
240
|
+
#### Environment variables are not access-controlled
|
241
|
+
|
242
|
+
Environment variables are stored in plain-text in S3.
|
243
|
+
Anyone with access to the Elastic Beanstalk bucket (for instance, the Elastic Beanstalk instance profile) can read the environment variables.
|
244
|
+
|
245
|
+
#### Rate limiting
|
246
|
+
|
247
|
+
Running several beans tasks concurrently can cause Elastic Beanstalk rate-limiting on the AWS account.
|
248
|
+
|
249
|
+
#### SIGINT causes a stack trace
|
250
|
+
|
251
|
+
Sorry `¯\_(ツ)_/¯`
|
252
|
+
|
253
|
+
#### Solution stack is hard-coded
|
254
|
+
|
255
|
+
If you do not use a custom image, the solution stack will start as a hard-coded value.
|
256
|
+
It will also be up to you to update it.
|
257
|
+
|
258
|
+
#### Uses default Elastic Beanstalk IAM settings and S3 bucket
|
259
|
+
|
260
|
+
Elastic Beans looks for [the default Elastic Beanstalk IAM instance profile and service role][iam].
|
261
|
+
As the linked document explains, the easiest way to create them is to create a sample application in the AWS console.
|
262
|
+
|
263
|
+
Creating the sample application should also create the default Elastic Beanstalk S3 bucket, which has a name of the form `elasticbeanstalk-REGION-ACCOUNT_ID`.
|
264
|
+
Elastic Beans will use this bucket to store application versions and environment variables.
|
265
|
+
|
266
|
+
[iam]: http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/concepts-roles.html
|
267
|
+
|
268
|
+
#### Worker environment health check requires some custom setup
|
269
|
+
|
270
|
+
Elastic Beanstalk worker environments (aws-sqsd) must use a non-SSL health check.
|
271
|
+
Your Rails application must implement this as a middleware (or lower in the stack) before Rails enforces SSL.
|
272
|
+
|
273
|
+
#### Worker environment visibility timeout is hard-coded
|
274
|
+
|
275
|
+
1800 seconds is the longest it can be.
|
276
|
+
|
202
277
|
## Installation
|
203
278
|
|
204
279
|
Add this line to your application's Gemfile:
|
data/exe/beans
CHANGED
@@ -8,27 +8,33 @@ require "elastic_beans/command"
|
|
8
8
|
require "elastic_beans/ui"
|
9
9
|
|
10
10
|
class ElasticBeans::CLI < Thor
|
11
|
+
APPLICATION_DESC = "The name of the Elastic Beanstalk application and CloudFormation stack that contains application settings"
|
12
|
+
|
11
13
|
class_option :verbose, type: :boolean, aliases: %w(-v)
|
12
14
|
|
13
15
|
desc ElasticBeans::Command::Configure::USAGE, ElasticBeans::Command::Configure::DESC
|
14
16
|
long_desc ElasticBeans::Command::Configure::LONG_DESC
|
15
|
-
option :application, aliases: %w(-a), required: true
|
16
|
-
option :network, aliases: %w(-n), required: true
|
17
|
-
option :
|
18
|
-
option :
|
19
|
-
option :
|
20
|
-
option :
|
21
|
-
option :
|
22
|
-
option :
|
17
|
+
option :application, aliases: %w(-a), required: true, desc: APPLICATION_DESC
|
18
|
+
option :network, aliases: %w(-n), required: true, desc: "The name of the CloudFormation stack that contains networking settings"
|
19
|
+
option :database_url, aliases: %w(-d), desc: "The DATABASE_URL for the Rails application"
|
20
|
+
option :image_id, aliases: %w(-i), desc: "A custom AMI to use instead of the default Ruby Elastic Beanstalk AMI"
|
21
|
+
option :instance_type, aliases: %w(-t), desc: "A default instance type to use for all environments instead of c4.large"
|
22
|
+
option :keypair, aliases: %w(-k), desc: "Required on first run. The EC2 keypair to use for Elastic Beanstalk instances"
|
23
|
+
option :logging_endpoint, aliases: %w(-l), desc: "An HTTP endpoint that can receive logs from one-off commands"
|
24
|
+
option :public_key, aliases: %w(-p), desc: "For end-to-end encryption. The public key of the SSL certificate the ELB will verify to communicate with your Rails app"
|
25
|
+
option :secret_key_base, aliases: %w(-b), desc: "The SECRET_KEY_BASE for the Rails application"
|
26
|
+
option :ssl_certificate_arn, aliases: %w(-s), desc: "The ARN of the SSL server certificate stored in IAM to attach to the ELB"
|
23
27
|
def configure
|
24
28
|
@verbose = options[:verbose]
|
25
29
|
ElasticBeans::Command::Configure.new(
|
30
|
+
database_url: options[:database_url],
|
26
31
|
image_id: options[:image_id],
|
27
32
|
instance_type: options[:instance_type],
|
28
33
|
keypair: options[:keypair],
|
29
34
|
logging_endpoint: options[:logging_endpoint],
|
30
35
|
public_key: options[:public_key],
|
31
|
-
|
36
|
+
secret_key_base: options[:secret_key_base],
|
37
|
+
ssl_certificate_arn: options[:ssl_certificate_arn],
|
32
38
|
application: application(name: options[:application]),
|
33
39
|
network: network(stack_name: options[:network]),
|
34
40
|
elastic_beanstalk: elastic_beanstalk_client,
|
@@ -41,10 +47,10 @@ class ElasticBeans::CLI < Thor
|
|
41
47
|
|
42
48
|
desc ElasticBeans::Command::Create::USAGE, ElasticBeans::Command::Create::DESC
|
43
49
|
long_desc ElasticBeans::Command::Create::LONG_DESC
|
44
|
-
option :application, aliases: %w(-a), required: true
|
45
|
-
option :dns, aliases: %w(-d)
|
46
|
-
option :queue, aliases: %w(-q)
|
47
|
-
option :tags, type: :hash, default: {}
|
50
|
+
option :application, aliases: %w(-a), required: true, desc: APPLICATION_DESC
|
51
|
+
option :dns, aliases: %w(-d), desc: "A Route53 DNS entry to create or update for a new webserver environment"
|
52
|
+
option :queue, aliases: %w(-q), desc: "The name of the queue a new worker environment should listen to, e.g. `default`"
|
53
|
+
option :tags, type: :hash, default: {}, desc: "EC2 tags to apply to the new environment as a Hash, e.g. `--tags=Environment:development Team:mine`"
|
48
54
|
def create(environment_type)
|
49
55
|
@verbose = options[:verbose]
|
50
56
|
ElasticBeans::Command::Create.new(
|
@@ -64,7 +70,7 @@ class ElasticBeans::CLI < Thor
|
|
64
70
|
|
65
71
|
desc ElasticBeans::Command::Deploy::USAGE, ElasticBeans::Command::Deploy::DESC
|
66
72
|
long_desc ElasticBeans::Command::Deploy::LONG_DESC
|
67
|
-
option :application, aliases: %w(-a), required: true
|
73
|
+
option :application, aliases: %w(-a), required: true, desc: APPLICATION_DESC
|
68
74
|
def deploy
|
69
75
|
@verbose = options[:verbose]
|
70
76
|
ElasticBeans::Command::Deploy.new(
|
@@ -81,7 +87,7 @@ class ElasticBeans::CLI < Thor
|
|
81
87
|
|
82
88
|
desc ElasticBeans::Command::Exec::USAGE, ElasticBeans::Command::Exec::DESC
|
83
89
|
long_desc ElasticBeans::Command::Exec::LONG_DESC
|
84
|
-
option :application, aliases: %w(-a), required: true
|
90
|
+
option :application, aliases: %w(-a), required: true, desc: APPLICATION_DESC
|
85
91
|
def exec(*command_parts)
|
86
92
|
@verbose = options[:verbose]
|
87
93
|
ElasticBeans::Command::Exec.new(
|
@@ -97,10 +103,10 @@ class ElasticBeans::CLI < Thor
|
|
97
103
|
|
98
104
|
desc ElasticBeans::Command::Scale::USAGE, ElasticBeans::Command::Scale::DESC
|
99
105
|
long_desc ElasticBeans::Command::Scale::LONG_DESC
|
100
|
-
option :application, aliases: %w(-a), required: true
|
101
|
-
option :minimum, aliases: %w(-i --min), required: true
|
102
|
-
option :maximum, aliases: %w(-m --max), required: true
|
103
|
-
option :queue, aliases: %w(-q)
|
106
|
+
option :application, aliases: %w(-a), required: true, desc: APPLICATION_DESC
|
107
|
+
option :minimum, aliases: %w(-i --min), required: true, desc: "The minimum number of healthy instances to keep"
|
108
|
+
option :maximum, aliases: %w(-m --max), required: true, desc: "The maximum number of healthy instances to keep"
|
109
|
+
option :queue, aliases: %w(-q), desc: "The name of the queue to identify the worker environment to scale, e.g. `default`"
|
104
110
|
def scale(environment_type)
|
105
111
|
@verbose = options[:verbose]
|
106
112
|
ElasticBeans::Command::Scale.new(
|
@@ -119,7 +125,7 @@ class ElasticBeans::CLI < Thor
|
|
119
125
|
|
120
126
|
desc ElasticBeans::Command::SetEnv::USAGE, ElasticBeans::Command::SetEnv::DESC
|
121
127
|
long_desc ElasticBeans::Command::SetEnv::LONG_DESC
|
122
|
-
option :application, aliases: %w(-a), required: true
|
128
|
+
option :application, aliases: %w(-a), required: true, desc: APPLICATION_DESC
|
123
129
|
def setenv(*env_pairs)
|
124
130
|
@verbose = options[:verbose]
|
125
131
|
ElasticBeans::Command::SetEnv.new(
|
@@ -4,6 +4,9 @@ require "elastic_beans/aws/cloudformation_stack"
|
|
4
4
|
require "elastic_beans/error"
|
5
5
|
|
6
6
|
module ElasticBeans
|
7
|
+
# An Elastic Beanstalk application which should exist.
|
8
|
+
#
|
9
|
+
# If the application does not exist, an error will be raised when attempting to access it.
|
7
10
|
class Application
|
8
11
|
attr_reader :name
|
9
12
|
|
@@ -14,6 +17,10 @@ module ElasticBeans
|
|
14
17
|
@stack = ElasticBeans::Aws::CloudformationStack.new(name, cloudformation: cloudformation)
|
15
18
|
end
|
16
19
|
|
20
|
+
# Returns an ElasticBeans::ApplicationVersion reflecting the deployed version of the application from the
|
21
|
+
# latest-updated environment.
|
22
|
+
#
|
23
|
+
# Ignores terminated or terminating environments.
|
17
24
|
def deployed_version
|
18
25
|
response = elastic_beanstalk.describe_environments(application_name: name)
|
19
26
|
live_environments = response.environments.select { |environment| environment.status !~ /Terminat/ }
|
@@ -26,6 +33,9 @@ module ElasticBeans
|
|
26
33
|
retry
|
27
34
|
end
|
28
35
|
|
36
|
+
# Returns an ElasticBeans::ConfigurationTemplate for each saved configuration of the Elastic Beanstalk application.
|
37
|
+
#
|
38
|
+
# See ElasticBeans::ConfigurationTemplate::new_from_existing for details on determining appropriate types.
|
29
39
|
def configuration_templates
|
30
40
|
response = elastic_beanstalk.describe_applications(application_names: [name])
|
31
41
|
application = response.applications[0]
|
@@ -46,6 +56,7 @@ module ElasticBeans
|
|
46
56
|
retry
|
47
57
|
end
|
48
58
|
|
59
|
+
# Returns the ElasticBeans::EnvVars for this application.
|
49
60
|
def env_vars
|
50
61
|
unless exists?
|
51
62
|
raise MissingApplicationError
|
@@ -54,6 +65,9 @@ module ElasticBeans
|
|
54
65
|
EnvVars.new(application: self, s3: s3)
|
55
66
|
end
|
56
67
|
|
68
|
+
# Returns an ElasticBeans::Environment for each un-terminated environment in the Elastic Beanstalk application.
|
69
|
+
#
|
70
|
+
# See ElasticBeans::Environment::new_from_existing for details on determining appropriate types.
|
57
71
|
def environments
|
58
72
|
response = elastic_beanstalk.describe_environments(application_name: name)
|
59
73
|
live_environments = response.environments.select { |environment| environment.status !~ /Terminat/ }
|
@@ -69,6 +83,10 @@ module ElasticBeans
|
|
69
83
|
retry
|
70
84
|
end
|
71
85
|
|
86
|
+
# Returns the name of the S3 bucket in which to store artifacts for this application.
|
87
|
+
# Looks for the default Elastic Beanstalk bucket, which is of the form +elasticbeanstalk-REGION-ACCOUNT_ID+.
|
88
|
+
#
|
89
|
+
# Raises an error if the bucket cannot be found.
|
72
90
|
def bucket_name
|
73
91
|
return @bucket_name if @bucket_name
|
74
92
|
bucket = s3.list_buckets.buckets.find { |bucket| bucket.name.start_with?("elasticbeanstalk-") }
|
@@ -78,6 +96,10 @@ module ElasticBeans
|
|
78
96
|
@bucket_name = bucket.name
|
79
97
|
end
|
80
98
|
|
99
|
+
# Enqueues a one-off command to be run on the application's +exec+ environment.
|
100
|
+
# Does not wait for action to be taken, but returns immediately after enqueuing the command.
|
101
|
+
#
|
102
|
+
# Raises an error if the exec environment cannot be found.
|
81
103
|
def enqueue_command(command, sqs:)
|
82
104
|
if environments.none? { |environment| environment.is_a?(Environment::Exec) }
|
83
105
|
raise MissingExecEnvironmentError
|
@@ -93,6 +115,7 @@ module ElasticBeans
|
|
93
115
|
stack.stack_output("ExecQueueUrl")
|
94
116
|
end
|
95
117
|
|
118
|
+
# Returns an ElasticBeans::ApplicationVersion for each version of the Elastic Beanstalk application.
|
96
119
|
def versions
|
97
120
|
response = elastic_beanstalk.describe_application_versions(application_name: name)
|
98
121
|
response.application_versions.map { |version| ElasticBeans::ApplicationVersion.new(version.version_label) }
|
@@ -101,12 +124,15 @@ module ElasticBeans
|
|
101
124
|
retry
|
102
125
|
end
|
103
126
|
|
127
|
+
# Returns the +Worker{QUEUE}QueueUrl+ from the application CloudFormation stack.
|
104
128
|
def worker_queue_url(queue)
|
105
129
|
queue_attribute = queue.to_s.downcase
|
106
130
|
queue_attribute[0] = queue_attribute[0].upcase
|
107
131
|
stack.stack_output("Worker#{queue_attribute}QueueUrl")
|
108
132
|
end
|
109
133
|
|
134
|
+
# Returns the name of each queue discovered in the application CloudFormation stack.
|
135
|
+
# Looks for outputs of the form +Worker{QUEUE}QueueUrl+.
|
110
136
|
def worker_queues
|
111
137
|
stack.stack_outputs.each_with_object([]) do |(output_key, _), acc|
|
112
138
|
match = /\AWorker(?<queue>\w+)QueueUrl\z/.match(output_key)
|
@@ -133,12 +159,16 @@ module ElasticBeans
|
|
133
159
|
retry
|
134
160
|
end
|
135
161
|
|
162
|
+
# :nodoc: all
|
163
|
+
# @!visibility private
|
136
164
|
class MissingApplicationError < ElasticBeans::Error
|
137
165
|
def message
|
138
166
|
"Application `#{@application_name}' does not exist. Please create the Elastic Beanstalk application using a CloudFormation stack."
|
139
167
|
end
|
140
168
|
end
|
141
169
|
|
170
|
+
# :nodoc: all
|
171
|
+
# @!visibility private
|
142
172
|
class MissingBucketError < ElasticBeans::Error
|
143
173
|
def message
|
144
174
|
"Cannot find the Elastic Beanstalk S3 bucket." \
|
@@ -146,12 +176,14 @@ module ElasticBeans
|
|
146
176
|
end
|
147
177
|
end
|
148
178
|
|
179
|
+
# :nodoc: all
|
180
|
+
# @!visibility private
|
149
181
|
class MissingExecEnvironmentError < ElasticBeans::Error
|
150
182
|
def message
|
151
183
|
<<-MESSAGE
|
152
184
|
A one-off command cannot be executed because the "exec" environment does not exist. Please create it:
|
153
185
|
|
154
|
-
#{
|
186
|
+
#{command_as_string "-a APPLICATION exec"}
|
155
187
|
MESSAGE
|
156
188
|
end
|
157
189
|
end
|
@@ -9,11 +9,18 @@ module ElasticBeans
|
|
9
9
|
class ApplicationVersion
|
10
10
|
attr_reader :version_label
|
11
11
|
|
12
|
+
# Create a representation of an existing application version in Elastic Beanstalk.
|
12
13
|
def initialize(version_label)
|
13
14
|
@version_label = version_label
|
14
15
|
end
|
15
16
|
|
16
17
|
class << self
|
18
|
+
# Create a new Elastic Beanstalk application version from the HEAD git commit of the given +working_directory+.
|
19
|
+
# Returns immediately if the application version already exists in Elastic Beanstalk.
|
20
|
+
#
|
21
|
+
# Injects helper code from this library to enable the functionality described in the README.
|
22
|
+
#
|
23
|
+
# Raises an error if the application version cannot be processed by Elastic Beanstalk.
|
17
24
|
def create(working_directory:, application:, elastic_beanstalk:, s3:)
|
18
25
|
version_label = fetch_version_label(working_directory)
|
19
26
|
if application.versions.any? { |version| version.version_label == version_label }
|
@@ -21,7 +28,7 @@ module ElasticBeans
|
|
21
28
|
end
|
22
29
|
|
23
30
|
archive_path = File.join(working_directory, ".elasticbeanstalk", "#{version_label}.zip")
|
24
|
-
create_archive(sha: version_label, path: archive_path)
|
31
|
+
create_archive(working_directory: working_directory, sha: version_label, path: archive_path)
|
25
32
|
create_application_version(
|
26
33
|
path: archive_path,
|
27
34
|
version_label: version_label,
|
@@ -68,9 +75,11 @@ module ElasticBeans
|
|
68
75
|
raise FailedApplicationVersion.new(version_label: version_label, status: status)
|
69
76
|
end
|
70
77
|
|
71
|
-
def create_archive(sha:, path:)
|
78
|
+
def create_archive(working_directory:, sha:, path:)
|
72
79
|
FileUtils.mkdir_p(File.dirname(path))
|
73
|
-
|
80
|
+
Dir.chdir(working_directory) do
|
81
|
+
system("git archive --format=zip -o #{path} #{sha}")
|
82
|
+
end
|
74
83
|
unless $?.success?
|
75
84
|
raise FailedArchiveError.new(sha: sha, path: path)
|
76
85
|
end
|
@@ -157,6 +166,8 @@ module ElasticBeans
|
|
157
166
|
|
158
167
|
private
|
159
168
|
|
169
|
+
# :nodoc: all
|
170
|
+
# @!visibility private
|
160
171
|
class FailedApplicationVersion < ElasticBeans::Error
|
161
172
|
include Nesty::NestedError
|
162
173
|
|
@@ -174,6 +185,8 @@ module ElasticBeans
|
|
174
185
|
end
|
175
186
|
end
|
176
187
|
|
188
|
+
# :nodoc: all
|
189
|
+
# @!visibility private
|
177
190
|
class FailedArchiveError < ElasticBeans::Error
|
178
191
|
def initialize(sha:, path:)
|
179
192
|
@sha = sha
|
@@ -185,6 +198,8 @@ module ElasticBeans
|
|
185
198
|
end
|
186
199
|
end
|
187
200
|
|
201
|
+
# :nodoc: all
|
202
|
+
# @!visibility private
|
188
203
|
class InvalidVersionWorkingDirectoryError < ElasticBeans::Error
|
189
204
|
def initialize(wd:)
|
190
205
|
@wd = wd
|
@@ -3,41 +3,41 @@ require "elastic_beans/error/environments_not_ready"
|
|
3
3
|
|
4
4
|
module ElasticBeans
|
5
5
|
module Command
|
6
|
+
# :nodoc: all
|
6
7
|
class Configure
|
7
|
-
USAGE = "configure
|
8
|
+
USAGE = "configure"
|
8
9
|
DESC = "Configure the given Elastic Beanstalk application"
|
9
10
|
LONG_DESC = <<-LONG_DESC
|
10
11
|
Configure the given Elastic Beanstalk application.
|
11
12
|
Creates and updates configuration templates for each possible environment type.
|
12
13
|
Updates running environments with the new configuration.
|
13
14
|
|
14
|
-
Requires the networking CloudFormation stack and application name.
|
15
15
|
Requires AWS credentials to be set in the environment, i.e. AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.
|
16
|
-
Some environment variables that Rails always requires must be set:
|
17
|
-
|
18
|
-
* DATABASE_URL
|
19
|
-
* SECRET_KEY_BASE
|
20
16
|
LONG_DESC
|
21
17
|
|
22
18
|
def initialize(
|
19
|
+
database_url:,
|
23
20
|
image_id:,
|
24
21
|
instance_type:,
|
25
22
|
keypair:,
|
26
23
|
logging_endpoint:,
|
27
24
|
public_key:,
|
28
|
-
|
25
|
+
secret_key_base:,
|
26
|
+
ssl_certificate_arn:,
|
29
27
|
application:,
|
30
28
|
network:,
|
31
29
|
elastic_beanstalk:,
|
32
30
|
iam:,
|
33
31
|
ui:
|
34
32
|
)
|
33
|
+
@database_url = database_url
|
35
34
|
@image_id = image_id
|
36
35
|
@instance_type = instance_type
|
37
36
|
@keypair = keypair
|
38
37
|
@logging_endpoint = logging_endpoint
|
39
38
|
@public_key = public_key
|
40
|
-
@
|
39
|
+
@secret_key_base = secret_key_base
|
40
|
+
@ssl_certificate_arn = ssl_certificate_arn
|
41
41
|
@application = application
|
42
42
|
@network = network
|
43
43
|
@elastic_beanstalk = elastic_beanstalk
|
@@ -83,7 +83,7 @@ Some environment variables that Rails always requires must be set:
|
|
83
83
|
keypair: keypair,
|
84
84
|
iam: iam,
|
85
85
|
public_key: public_key,
|
86
|
-
|
86
|
+
ssl_certificate_arn: ssl_certificate_arn,
|
87
87
|
)
|
88
88
|
progressbar.increment
|
89
89
|
progressbar.log("Updating exec configuration template...")
|
@@ -161,25 +161,19 @@ Some environment variables that Rails always requires must be set:
|
|
161
161
|
|
162
162
|
attr_reader(
|
163
163
|
:application,
|
164
|
+
:database_url,
|
164
165
|
:image_id,
|
165
166
|
:instance_type,
|
166
167
|
:keypair,
|
167
168
|
:logging_endpoint,
|
168
169
|
:network,
|
169
170
|
:public_key,
|
170
|
-
:
|
171
|
+
:secret_key_base,
|
172
|
+
:ssl_certificate_arn,
|
171
173
|
:elastic_beanstalk,
|
172
174
|
:iam,
|
173
175
|
:ui,
|
174
176
|
)
|
175
|
-
|
176
|
-
def database_url
|
177
|
-
ENV['DATABASE_URL']
|
178
|
-
end
|
179
|
-
|
180
|
-
def secret_key_base
|
181
|
-
ENV['SECRET_KEY_BASE']
|
182
|
-
end
|
183
177
|
end
|
184
178
|
end
|
185
179
|
end
|
@@ -6,14 +6,17 @@ require "elastic_beans/environment/webserver"
|
|
6
6
|
|
7
7
|
module ElasticBeans
|
8
8
|
module Command
|
9
|
+
# :nodoc: all
|
9
10
|
class Create
|
10
|
-
USAGE = "create
|
11
|
+
USAGE = "create ENVIRONMENT_TYPE"
|
11
12
|
DESC = "Create a new environment in Elastic Beanstalk and attach it to relevant resources"
|
12
13
|
LONG_DESC = <<-LONG_DESC
|
13
|
-
Create a new environment in Elastic Beanstalk and attach it to relevant resources
|
14
|
-
The environment type must be one of the recognized types: webserver, worker, or scheduled.
|
14
|
+
Create a new environment in Elastic Beanstalk and attach it to relevant resources.
|
15
|
+
The environment type must be one of the recognized types: webserver, worker, exec, or scheduled.
|
16
|
+
|
17
|
+
A new environment will use the same deployed version as all other environments.
|
18
|
+
If this is the first environment, a new version will be created from the HEAD git commit of the working directory.
|
15
19
|
|
16
|
-
Requires the Elastic Beanstalk application name.
|
17
20
|
Requires AWS credentials to be set in the environment, i.e. AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.
|
18
21
|
LONG_DESC
|
19
22
|
|
@@ -133,6 +136,7 @@ Requires AWS credentials to be set in the environment, i.e. AWS_ACCESS_KEY_ID an
|
|
133
136
|
raise UnhealthyEnvironmentError.new(environment_name: environment.name)
|
134
137
|
end
|
135
138
|
|
139
|
+
# :nodoc: all
|
136
140
|
class UnhealthyEnvironmentError < ElasticBeans::Error
|
137
141
|
def initialize(environment_name:)
|
138
142
|
@environment_name = environment_name
|
@@ -3,13 +3,13 @@ require "elastic_beans/error/environments_not_ready"
|
|
3
3
|
|
4
4
|
module ElasticBeans
|
5
5
|
module Command
|
6
|
+
# :nodoc: all
|
6
7
|
class Deploy
|
7
|
-
USAGE = "deploy
|
8
|
+
USAGE = "deploy"
|
8
9
|
DESC = "Deploy the HEAD git commit to all environments in Elastic Beanstalk"
|
9
10
|
LONG_DESC = <<-LONG_DESC
|
10
|
-
Deploy the HEAD git commit to all environments in Elastic Beanstalk.
|
11
|
+
Deploy the HEAD git commit of the working directory to all environments in Elastic Beanstalk.
|
11
12
|
|
12
|
-
Requires the application name.
|
13
13
|
Requires AWS credentials to be set in the environment, i.e. AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.
|
14
14
|
LONG_DESC
|
15
15
|
|
@@ -2,15 +2,16 @@ require "shellwords"
|
|
2
2
|
|
3
3
|
module ElasticBeans
|
4
4
|
module Command
|
5
|
+
# :nodoc: all
|
5
6
|
class Exec
|
6
|
-
USAGE = "exec
|
7
|
+
USAGE = "exec COMMAND STRING"
|
7
8
|
DESC = "Run an arbitrary command in the context of your application"
|
8
9
|
LONG_DESC = <<-LONG_DESC
|
9
10
|
Run an arbitrary command in the context of your application.
|
10
11
|
The command is run in an "exec" environment, separate from your webserver or worker environments.
|
11
|
-
|
12
|
+
You must create the exec environment prior to this command being run: `beans create exec -a APPLICATION`.
|
13
|
+
Upload output from the command to an HTTP endpoint.
|
12
14
|
|
13
|
-
Requires the Elastic Beanstalk application name.
|
14
15
|
Requires AWS credentials to be set in the environment, i.e. AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.
|
15
16
|
LONG_DESC
|
16
17
|
|
@@ -3,13 +3,13 @@ require "elastic_beans/error/environments_not_ready"
|
|
3
3
|
|
4
4
|
module ElasticBeans
|
5
5
|
module Command
|
6
|
+
# :nodoc: all
|
6
7
|
class Scale
|
7
|
-
USAGE = "scale
|
8
|
+
USAGE = "scale ENVIRONMENT_TYPE"
|
8
9
|
DESC = "Change the autoscaling minimum and maximum for the given environment"
|
9
10
|
LONG_DESC = <<-LONG_DESC
|
10
11
|
Change the autoscaling minimum and maximum for the given environment.
|
11
12
|
|
12
|
-
Requires the application name.
|
13
13
|
Requires AWS credentials to be set in the environment, i.e. AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.
|
14
14
|
LONG_DESC
|
15
15
|
|