elastic_beans 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +3 -0
  4. data/Gemfile +9 -0
  5. data/LICENSE.md +21 -0
  6. data/README.md +184 -0
  7. data/Rakefile +6 -0
  8. data/bin/console +14 -0
  9. data/bin/setup +8 -0
  10. data/circle.yml +20 -0
  11. data/elastic_beans.gemspec +31 -0
  12. data/exe/beans +198 -0
  13. data/lib/elastic_beans/application.rb +127 -0
  14. data/lib/elastic_beans/application_version.rb +202 -0
  15. data/lib/elastic_beans/aws/cloudformation_stack.rb +66 -0
  16. data/lib/elastic_beans/command/configure.rb +184 -0
  17. data/lib/elastic_beans/command/create.rb +150 -0
  18. data/lib/elastic_beans/command/deploy.rb +77 -0
  19. data/lib/elastic_beans/command/exec.rb +37 -0
  20. data/lib/elastic_beans/command/set_env.rb +77 -0
  21. data/lib/elastic_beans/command/talk.rb +74 -0
  22. data/lib/elastic_beans/command/version.rb +17 -0
  23. data/lib/elastic_beans/command.rb +12 -0
  24. data/lib/elastic_beans/configuration_template/base.rb +114 -0
  25. data/lib/elastic_beans/configuration_template/exec.rb +50 -0
  26. data/lib/elastic_beans/configuration_template/scheduler.rb +20 -0
  27. data/lib/elastic_beans/configuration_template/webserver.rb +49 -0
  28. data/lib/elastic_beans/configuration_template/worker.rb +27 -0
  29. data/lib/elastic_beans/configuration_template.rb +197 -0
  30. data/lib/elastic_beans/dns_entry.rb +127 -0
  31. data/lib/elastic_beans/environment/exec.rb +23 -0
  32. data/lib/elastic_beans/environment/scheduler.rb +23 -0
  33. data/lib/elastic_beans/environment/webserver.rb +23 -0
  34. data/lib/elastic_beans/environment/worker.rb +29 -0
  35. data/lib/elastic_beans/environment.rb +300 -0
  36. data/lib/elastic_beans/error/environments_not_ready.rb +15 -0
  37. data/lib/elastic_beans/error.rb +15 -0
  38. data/lib/elastic_beans/exec/ebextension.yml +10 -0
  39. data/lib/elastic_beans/exec/elastic_beans_exec.conf +15 -0
  40. data/lib/elastic_beans/exec/init.rb +50 -0
  41. data/lib/elastic_beans/exec/run_command.sh +13 -0
  42. data/lib/elastic_beans/exec/sqs_consumer.rb +75 -0
  43. data/lib/elastic_beans/network.rb +44 -0
  44. data/lib/elastic_beans/rack/exec.rb +63 -0
  45. data/lib/elastic_beans/scheduler/ebextension.yml +4 -0
  46. data/lib/elastic_beans/ui.rb +31 -0
  47. data/lib/elastic_beans/version.rb +3 -0
  48. data/lib/elastic_beans.rb +9 -0
  49. metadata +218 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 18b8fddb84235084c0ed2656617d432b4b22e6d4
4
+ data.tar.gz: c49a0e1f3240697c150aab493b9373913dc25c61
5
+ SHA512:
6
+ metadata.gz: 480c7aeed8133114eafa17306f832a0a1e21487c9b0069424567283122b166fb3051eaee5f7d7b3829f62030fc91c2904af0bd65430087603884593dda108858
7
+ data.tar.gz: 35cc62acbf16cdbe0b26b2a600b9f84332bb6c5ac7e151053b56072aa40c4692f37245293285a0d671287ede3791f8cdce678ef53e662f9bae43693253371e5c
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in elastic_beans.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem "net-ssh-gateway"
8
+ gem "rails", "~> 5.0"
9
+ end
data/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 One Medical Group, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,184 @@
1
+ # Elastic Beans
2
+
3
+ Elastic Beans orchestrates an Elastic Beanstalk application for a Rails app.
4
+ It is a CLI that replaces the [Elastic Beanstalk CLI][eb], which looks great on the surface but is missing some key pieces.
5
+
6
+ * The VPC support in `eb create` is great, but it ends there. Connecting to instances inside a VPC requires manual SSH gateway setup.
7
+ * The CLI [supports multiple environments][eb-compose], but only in a rigid fashion that isn't usable when those environments share the same codebase.
8
+
9
+ [eb]: http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/eb-cli3.html
10
+ [eb-compose]: http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/ebcli-compose.html
11
+
12
+ ## Usage
13
+
14
+ Elastic Beans makes heavy use of the [AWS SDK][aws-sdk].
15
+ Configuration of AWS credentials and region should be completed before using this gem, according to [the SDK configuration instructions][configuration].
16
+ As the SDK documentation suggests, using environment variables is recommended.
17
+
18
+ [aws-sdk]: https://aws.amazon.com/sdk-for-ruby/
19
+ [configuration]: http://docs.aws.amazon.com/sdk-for-ruby/latest/DeveloperGuide/aws-ruby-sdk-getting-started.html#aws-ruby-sdk-configuration
20
+
21
+ # Pre-configure the application before creating environments
22
+ # Rails will not start without DATABASE_URL and SECRET_TOKEN_BASE
23
+ export DATABASE_URL=mysql2://... SECRET_KEY_BASE=abc123...
24
+ beans configure -n myapp-networking -a myapp -k KEYPAIR -s SSL_CERTIFICATE_ID [-i IMAGE_ID] [-t INSTANCE_TYPE] [-l LOGGING_HTTP_ENDPOINT]
25
+
26
+ # Create a webserver environment with a pretty DNS name at myapp.TLD (managed by Route53)
27
+ beans create -a myapp [-d myapp.TLD] [--tags=Environment:production Team:Unicorn] webserver
28
+
29
+ # Create a worker environment using an SQS queue created by the CloudFormation template
30
+ beans create -a myapp [-q QUEUE] worker
31
+
32
+ # Create an execution environment using an SQS queue created by the CloudFormation template
33
+ beans create -a myapp exec
34
+
35
+ # Create a periodic task scheduler using cron.yaml
36
+ beans create -a myapp scheduler
37
+
38
+ # Set environment variables across all environments
39
+ beans setenv -a myapp REDIS_URL=redis://...
40
+
41
+ # Deploy the HEAD git commit to all environments
42
+ # Creates an application version named after the git ref
43
+ beans deploy -a myapp
44
+
45
+ # Run one-off tasks
46
+ beans exec -a myapp rake db:migrate
47
+
48
+ # Update all existing environments and configuration
49
+ beans configure -n myapp-networking -a myapp [-k KEYPAIR] [-s SSL_CERTIFICATE_ID] [-i IMAGE_ID] [-t INSTANCE_TYPE]
50
+
51
+ ### API
52
+
53
+ app = ElasticBeans::Application.new(
54
+ name: "myapp",
55
+ cloudformation: Aws::CloudFormation::Client.new,
56
+ elastic_beanstalk: Aws::ElasticBeanstalk::Client.new,
57
+ )
58
+ app.exec_command("rake db:migrate", sqs: Aws::SQS::Client.new)
59
+
60
+ ### Periodic tasks
61
+
62
+ Elastic Beanstalk [supports periodic tasks][periodic] by sending a POST request to an endpoint of your application.
63
+ Elastic Beans includes a middleware that can convert specially-crafted paths into commands and enqueue them for execution.
64
+ The middleware only accepts localhost requests from `aws-sqsd`.
65
+
66
+ [periodic]: http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/using-features-managing-env-tiers.html#worker-periodictasks
67
+
68
+ In `config/initializers/elastic_beans.rb`, add the middleware into your stack, below forcing HTTPS (`aws-sqsd` does not use HTTPS):
69
+
70
+ require "elastic_beans/rack/exec"
71
+
72
+ if Rails.configuration.force_ssl
73
+ Rails.configuration.middleware.insert_before(
74
+ ActionDispatch::SSL,
75
+ ElasticBeans::Rack::Exec,
76
+ application: ElasticBeans::Application.new(
77
+ name: "myapp",
78
+ cloudformation: Aws::CloudFormation::Client.new,
79
+ elastic_beanstalk: Aws::ElasticBeanstalk::Client.new,
80
+ ),
81
+ sqs: Aws::SQS::Client.new,
82
+ logger: Rails.logger,
83
+ )
84
+ else
85
+ Rails.configuration.middleware.use(
86
+ ElasticBeans::Rack::Exec,
87
+ application: ElasticBeans::Application.new(
88
+ name: "myapp",
89
+ cloudformation: Aws::CloudFormation::Client.new,
90
+ elastic_beanstalk: Aws::ElasticBeanstalk::Client.new,
91
+ ),
92
+ sqs: Aws::SQS::Client.new,
93
+ logger: Rails.logger,
94
+ )
95
+ end
96
+
97
+ In `cron.yaml`, URL-encode the full command to be run and add it as another path segment to `/exec`:
98
+
99
+ - name: rake myapp:mytask[arg1,arg2]
100
+ url: "/exec/rake%20myapp%3Amytask%5Barg1%2Carg2%5D"
101
+
102
+ Then create a periodic scheduler environment using `cron.yaml`:
103
+
104
+ beans create -a myapp scheduler
105
+
106
+ This environment will enqueue the commands from `cron.yaml` for the `exec` environment to run.
107
+
108
+ ## Requirements
109
+
110
+ Elastic Beans assumes that you use CloudFormation to manage your infrastructure.
111
+ It requires two stacks for each application: a networking stack, and an application stack.
112
+ The settings for your application are discovered from the [outputs of these CloudFormation stacks][outputs].
113
+
114
+ [outputs]: http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/outputs-section-structure.html
115
+
116
+ The networking stack can be shared between many applications, but each application should have its own application stack.
117
+ For example, you might create separate "eb-development" and "eb-production" network stacks.
118
+ Then, create an Elastic Beanstalk application from a stack named "myapp."
119
+ Finally, you can set it up with beans:
120
+
121
+ $ beans configure -n eb-development -a myapp ...
122
+
123
+ ### Networking
124
+
125
+ Elastic Beans uses VPC networking and will run your application from a private subnet.
126
+ Networking settings are discovered from a CloudFormation stack that you must set up before running the `configure` command.
127
+ It must have the following outputs, which will be used for the corresponding settings:
128
+
129
+ * `ApplicationSecurityGroup` - [`aws:autoscaling:launchconfiguration/SecurityGroups`][launchconfiguration]
130
+ * Allow TCP connections from the `ELBSecurityGroup` on ports 80 and 443
131
+ * `ApplicationSubnet` - [`aws:ec2:vpc/Subnets`][vpc]
132
+ * `ELBSecurityGroup` - [`aws:elb:loadbalancer/SecurityGroups`][loadbalancer], [`aws:elb:loadbalancer/ManagedSecurityGroup`][loadbalancer]
133
+ * Allow TCP connections on ports 80 and 443 from `0.0.0.0/0`
134
+ * `ELBSubnet` - [`aws:ec2:vpc/ELBSubnets`][vpc]
135
+ * `SSHSecurityGroup` - [`aws:ec2:vpc/Subnets`][vpc]
136
+ * Allow TCP connections from your VPC on ports 80 and 443
137
+ * `VpcId` - [`aws:ec2:vpc/VPCId`][vpc]
138
+
139
+ [launchconfiguration]: http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options-general.html#command-options-general-autoscalinglaunchconfiguration
140
+ [loadbalancer]: http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options-general.html#command-options-general-elbloadbalancer
141
+ [vpc]: http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/command-options-general.html#command-options-general-ec2vpc
142
+
143
+ You must create [the default instance profile and service role for Elastic Beanstalk](http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/AWSHowTo.iam.html).
144
+ Elastic Beans will use the default names: `aws-elasticbeanstalk-ec2-role` and `aws-elasticbeanstalk-service-role`.
145
+
146
+ ### Application
147
+
148
+ Your Elastic Beanstalk application must already exist and also be created using CloudFormation.
149
+ Its details will be discovered from the following outputs:
150
+
151
+ * `ExecQueueUrl`
152
+ * `Worker[Name]QueueUrl`
153
+
154
+ Where a separate worker environment will be configured for each queue `[Name]` that appears.
155
+ The `Default` name must be present.
156
+
157
+ ### Code
158
+
159
+ Your application must use the [active-elastic-job gem](https://github.com/tawan/active-elastic-job) for background job processing.
160
+ Elastic Beans will set the `DISABLE_SQS_CONSUMER` environment variable appropriately in your environments.
161
+
162
+ ## Installation
163
+
164
+ Add this line to your application's Gemfile:
165
+
166
+ gem 'elastic_beans'
167
+
168
+ And then execute:
169
+
170
+ $ bundle
171
+
172
+ Or install it yourself as:
173
+
174
+ $ gem install elastic_beans
175
+
176
+ ## Development
177
+
178
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
179
+
180
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
181
+
182
+ ## Contributing
183
+
184
+ Bug reports and pull requests are welcome on GitHub at https://github.com/onemedical/elastic_beans.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "elastic_beans"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/circle.yml ADDED
@@ -0,0 +1,20 @@
1
+ ---
2
+ dependencies:
3
+ override:
4
+ - |
5
+ case $CIRCLE_NODE_INDEX in
6
+ 0)
7
+ rvm-exec 2.3.1 bash -c "bundle check --path=vendor/bundle_2.3 || bundle install --path=vendor/bundle_2.3 --jobs=4 --retry=3"
8
+ ;;
9
+ 1)
10
+ rvm-exec 2.2.5 bash -c "bundle check --path=vendor/bundle_2.2 || bundle install --path=vendor/bundle_2.2 --jobs=4 --retry=3"
11
+ ;;
12
+ esac
13
+ post:
14
+ - git config --global user.name "CircleCI"
15
+ - git config --global user.email "ops-ro@onemedical.com"
16
+
17
+ test:
18
+ override:
19
+ - case $CIRCLE_NODE_INDEX in 0) rvm-exec 2.3.1 bash -c "bundle check --path=vendor/bundle_2.3 && bundle exec rake" ;; 1) rvm-exec 2.2.5 bash -c "bundle check --path=vendor/bundle_2.2 && bundle exec rake" ;; esac:
20
+ parallel: true
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'elastic_beans/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "elastic_beans"
8
+ spec.version = ElasticBeans::VERSION
9
+ spec.authors = ["Adam Stegman"]
10
+ spec.email = ["astegman@onemedical.com"]
11
+
12
+ spec.summary = "Elastic Beanstalk environment orchestration for a Rails app"
13
+ spec.description = "a CLI that replaces the Elastic Beanstalk CLI, which looks great on the surface but is missing some key pieces."
14
+ spec.homepage = "https://github.com/onemedical/elastic_beans"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
+ spec.bindir = "exe"
18
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "aws-sdk", "~> 2.3"
22
+ spec.add_dependency "nesty", "~> 1.0"
23
+ spec.add_dependency "rails"
24
+ spec.add_dependency "ruby-progressbar", "~> 1.2"
25
+ spec.add_dependency "rubyzip", "~> 1.2"
26
+ spec.add_dependency "thor", "~> 0.19.0"
27
+
28
+ spec.add_development_dependency "bundler", "~> 1.12"
29
+ spec.add_development_dependency "rake", "~> 10.0"
30
+ spec.add_development_dependency "rspec", "~> 3.0"
31
+ end
data/exe/beans ADDED
@@ -0,0 +1,198 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "aws-sdk"
4
+ require "thor"
5
+ require "elastic_beans"
6
+ require "elastic_beans/error"
7
+ require "elastic_beans/command"
8
+ require "elastic_beans/ui"
9
+
10
+ class ElasticBeans::CLI < Thor
11
+ class_option :verbose, type: :boolean, aliases: %w(-v)
12
+
13
+ desc ElasticBeans::Command::Configure::USAGE, ElasticBeans::Command::Configure::DESC
14
+ 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 :image_id, aliases: %w(-i)
18
+ option :instance_type, aliases: %w(-t)
19
+ option :keypair, aliases: %w(-k)
20
+ option :logging_endpoint, aliases: %w(-l)
21
+ option :public_key, aliases: %w(-p)
22
+ option :ssl_certificate_id, aliases: %w(-s)
23
+ def configure
24
+ @verbose = options[:verbose]
25
+ ElasticBeans::Command::Configure.new(
26
+ image_id: options[:image_id],
27
+ instance_type: options[:instance_type],
28
+ keypair: options[:keypair],
29
+ logging_endpoint: options[:logging_endpoint],
30
+ public_key: options[:public_key],
31
+ ssl_certificate_id: options[:ssl_certificate_id],
32
+ application: application(name: options[:application]),
33
+ network: network(stack_name: options[:network]),
34
+ elastic_beanstalk: elastic_beanstalk_client,
35
+ iam: iam_client,
36
+ ui: ui,
37
+ ).run
38
+ rescue StandardError => e
39
+ error(e)
40
+ end
41
+
42
+ desc ElasticBeans::Command::Create::USAGE, ElasticBeans::Command::Create::DESC
43
+ 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: {}
48
+ def create(environment_name)
49
+ @verbose = options[:verbose]
50
+ ElasticBeans::Command::Create.new(
51
+ environment_name: environment_name,
52
+ dns: options[:dns],
53
+ queue: options[:queue],
54
+ tags: options[:tags],
55
+ application: application(name: options[:application]),
56
+ elastic_beanstalk: elastic_beanstalk_client,
57
+ route53: route53_client,
58
+ s3: s3_client,
59
+ ui: ui,
60
+ ).run
61
+ rescue StandardError => e
62
+ error(e)
63
+ end
64
+
65
+ desc ElasticBeans::Command::Deploy::USAGE, ElasticBeans::Command::Deploy::DESC
66
+ long_desc ElasticBeans::Command::Deploy::LONG_DESC
67
+ option :application, aliases: %w(-a), required: true
68
+ def deploy
69
+ @verbose = options[:verbose]
70
+ ElasticBeans::Command::Deploy.new(
71
+ application: application(
72
+ name: options[:application],
73
+ ),
74
+ elastic_beanstalk: elastic_beanstalk_client,
75
+ s3: s3_client,
76
+ ui: ui,
77
+ ).run
78
+ rescue StandardError => e
79
+ error(e)
80
+ end
81
+
82
+ desc ElasticBeans::Command::Exec::USAGE, ElasticBeans::Command::Exec::DESC
83
+ long_desc ElasticBeans::Command::Exec::LONG_DESC
84
+ option :application, aliases: %w(-a), required: true
85
+ def exec(*command_parts)
86
+ @verbose = options[:verbose]
87
+ ElasticBeans::Command::Exec.new(
88
+ application: application(
89
+ name: options[:application],
90
+ ),
91
+ sqs: sqs_client,
92
+ ui: ui,
93
+ ).run(*command_parts)
94
+ rescue StandardError => e
95
+ error(e)
96
+ end
97
+
98
+ desc ElasticBeans::Command::SetEnv::USAGE, ElasticBeans::Command::SetEnv::DESC
99
+ long_desc ElasticBeans::Command::SetEnv::LONG_DESC
100
+ option :application, aliases: %w(-a), required: true
101
+ def setenv(*env_pairs)
102
+ @verbose = options[:verbose]
103
+ ElasticBeans::Command::SetEnv.new(
104
+ application: application(
105
+ name: options[:application],
106
+ ),
107
+ ui: ui,
108
+ ).run(*env_pairs)
109
+ rescue StandardError => e
110
+ error(e)
111
+ end
112
+
113
+ desc "talk", ""
114
+ def talk
115
+ ElasticBeans::Command::Talk.new(ui: ui).run
116
+ end
117
+
118
+ map %w[--version] => :__print_version
119
+ desc "--version", "Print the version and exit"
120
+ def __print_version
121
+ ElasticBeans::Command::Version.new(ui: ui).run
122
+ end
123
+
124
+ private
125
+
126
+ def application(
127
+ name:,
128
+ cloudformation: cloudformation_client,
129
+ elastic_beanstalk: elastic_beanstalk_client
130
+ )
131
+ @application ||= ElasticBeans::Application.new(
132
+ name: name,
133
+ cloudformation: cloudformation,
134
+ elastic_beanstalk: elastic_beanstalk,
135
+ )
136
+ end
137
+
138
+ def cloudformation_client
139
+ ::Aws::CloudFormation::Client.new
140
+ end
141
+
142
+ def elastic_beanstalk_client
143
+ ::Aws::ElasticBeanstalk::Client.new
144
+ end
145
+
146
+ def error(e)
147
+ ui.debug { e.inspect }
148
+ ui.debug { e.backtrace }
149
+
150
+ case e
151
+ when ElasticBeans::Error
152
+ ui.error(e.message)
153
+ when ::Aws::Errors::MissingCredentialsError
154
+ ui.error("Missing AWS credentials, please set AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY and try again.")
155
+ else
156
+ raise e
157
+ end
158
+
159
+ exit 1
160
+ end
161
+
162
+ def iam_client
163
+ ::Aws::IAM::Client.new
164
+ end
165
+
166
+ def network(stack_name:, cloudformation: cloudformation_client)
167
+ @network ||= ElasticBeans::Network.new(
168
+ stack_name: stack_name,
169
+ cloudformation: cloudformation,
170
+ )
171
+ end
172
+
173
+ def route53_client
174
+ ::Aws::Route53::Client.new
175
+ end
176
+
177
+ def s3_client
178
+ ::Aws::S3::Client.new
179
+ end
180
+
181
+ def sqs_client
182
+ ::Aws::SQS::Client.new
183
+ end
184
+
185
+ def ui
186
+ ElasticBeans::UI.new(verbose: verbose?)
187
+ end
188
+
189
+ def verbose?
190
+ @verbose
191
+ end
192
+
193
+ def self.exit_on_failure?
194
+ true
195
+ end
196
+ end
197
+
198
+ ElasticBeans::CLI.start(ARGV)