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
@@ -0,0 +1,15 @@
1
+ require "elastic_beans/error"
2
+
3
+ class EnvironmentsNotReady < ElasticBeans::Error
4
+ def initialize(environments:)
5
+ @environments = environments
6
+ end
7
+
8
+ def message
9
+ msg = "Some environments are not healthy."
10
+ @environments.each do |environment|
11
+ msg << "\n * #{environment.name} is `#{environment.status}'"
12
+ end
13
+ msg
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ require "shellwords"
2
+
3
+ module ElasticBeans
4
+ class Error < StandardError
5
+ protected
6
+
7
+ def command_as_string(args = nil)
8
+ unless args
9
+ args = $*.map { |arg| Shellwords.escape(arg) }.join(" ")
10
+ end
11
+
12
+ "beans #{args}"
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ container_commands:
2
+ 00_copy_files:
3
+ command: "mkdir -p /opt/elastic_beans && cp -vR /var/app/ondeck/.elastic_beans/exec /opt/elastic_beans/"
4
+ 01_permissions:
5
+ command: "chmod 755 /opt/elastic_beans/exec/run_command.sh"
6
+ 09_upstart:
7
+ command: "cp -v /opt/elastic_beans/exec/elastic_beans_exec.conf /etc/init/"
8
+ 10_start_elastic_beans_exec:
9
+ command: stop elastic_beans_exec; start elastic_beans_exec
10
+ test: "/opt/elasticbeanstalk/bin/get-config meta -k sqsdconfig --output YAML | grep -q '^environment_name: .*-exec$'"
@@ -0,0 +1,15 @@
1
+ description "Elastic Beans SQS consumer for running arbitrary commands"
2
+ author "One Medical Group"
3
+
4
+ respawn
5
+ respawn limit 15 5
6
+
7
+ script
8
+ EB_SUPPORT_DIR="`/opt/elasticbeanstalk/bin/get-config container -k support_dir`"
9
+ source $EB_SUPPORT_DIR/envvars
10
+
11
+ # execute using Elastic Beanstalk's built-in Ruby with aws-sdk pre-installed
12
+ export PATH="/opt/elasticbeanstalk/lib/ruby/bin:$PATH"
13
+ export GEM_PATH="/opt/elasticbeanstalk/lib/ruby/lib/ruby/2.2.0"
14
+ exec ruby /opt/elastic_beans/exec/init.rb start
15
+ end script
@@ -0,0 +1,50 @@
1
+ require "aws-sdk"
2
+ require "fileutils"
3
+ require "net/http"
4
+ require "uri"
5
+
6
+ class Init
7
+ LOGFILE = "/var/log/elastic_beans_exec.log"
8
+ PIDFILE = "/var/run/elastic_beans_exec.pid"
9
+ AZ_PATTERN = /\A(?<region>.+-\d+)\w+\z/
10
+ AZ_URI = URI("http://169.254.169.254/latest/meta-data/placement/availability-zone")
11
+
12
+ def self.run(command)
13
+ init = new
14
+ unless init.respond_to?(command)
15
+ abort "Usage: $0 {start}"
16
+ end
17
+ init.send(command)
18
+ end
19
+
20
+ def start
21
+ logging_endpoint = ENV['ELASTIC_BEANS_EXEC_LOGGING_ENDPOINT']
22
+ queue_url = ENV['ELASTIC_BEANS_EXEC_QUEUE_URL']
23
+ if queue_url.nil?
24
+ raise "ELASTIC_BEANS_EXEC_QUEUE_URL not set; please re-run `beans configure`."
25
+ end
26
+ sqs_client = ::Aws::SQS::Client.new(region: region)
27
+ require File.expand_path("../sqs_consumer", __FILE__)
28
+ consumer = SQSConsumer.new(
29
+ logfile: LOGFILE,
30
+ logging_endpoint: logging_endpoint,
31
+ queue_url: queue_url,
32
+ sqs: sqs_client,
33
+ )
34
+ consumer.run
35
+ end
36
+
37
+ private
38
+
39
+ def region
40
+ return @region if @region
41
+ az = Net::HTTP.get(AZ_URI)
42
+ az_match = AZ_PATTERN.match(az)
43
+ if az_match.nil?
44
+ raise "Could not find region in availability zone `#{az}'"
45
+ end
46
+ @region = az_match[:region]
47
+ end
48
+ end
49
+
50
+ Init.run(ARGV[0])
@@ -0,0 +1,13 @@
1
+ #!/bin/sh
2
+
3
+ # execute in the context of the application
4
+ EB_APP_DIR="`/opt/elasticbeanstalk/bin/get-config container -k app_deploy_dir`"
5
+ cd "$EB_APP_DIR"
6
+
7
+ # load app environment
8
+ EB_SCRIPT_DIR="`/opt/elasticbeanstalk/bin/get-config container -k script_dir`"
9
+ EB_SUPPORT_DIR="`/opt/elasticbeanstalk/bin/get-config container -k support_dir`"
10
+ . $EB_SUPPORT_DIR/envvars
11
+ . $EB_SCRIPT_DIR/use-app-ruby.sh
12
+
13
+ exec "$@"
@@ -0,0 +1,75 @@
1
+ require "json"
2
+ require "net/http"
3
+ require "uri"
4
+
5
+ class SQSConsumer
6
+ def initialize(logfile:, queue_url:, sqs:, logging_endpoint: nil)
7
+ @logfile = logfile
8
+ @queue_url = queue_url
9
+ @sqs = sqs
10
+ @logging_uri = URI(logging_endpoint) if logging_endpoint
11
+ @command_script = File.expand_path('../run_command.sh', __FILE__)
12
+ end
13
+
14
+ def run
15
+ trap("TERM", &method(:stop))
16
+ loop do
17
+ sleep 1
18
+ response = sqs.receive_message(
19
+ queue_url: queue_url,
20
+ max_number_of_messages: 1,
21
+ )
22
+ message = response.messages[0]
23
+ if message
24
+ command = JSON.parse(message.body)
25
+
26
+ @command_pid = Process.spawn("#{command_script} #{command['command']}", out: logfile, err: logfile)
27
+ sqs.delete_message(
28
+ queue_url: queue_url,
29
+ receipt_handle: message.receipt_handle,
30
+ )
31
+ upload_log("Executing command `#{command['command']}' on host #{`hostname`.chomp} pid #{command_pid}...")
32
+ _, status = Process.wait2(command_pid)
33
+ File.open(logfile, "a") do |file|
34
+ file.puts "Command `#{command['command']}' exited on host #{`hostname`.chomp}: #{status}"
35
+ end
36
+
37
+ @command_pid = nil
38
+ upload_logfile
39
+ end
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ attr_reader :command_pid, :command_script, :logfile, :logging_uri, :queue_url, :sqs
46
+
47
+ def stop(signal = nil)
48
+ signal ||= "TERM"
49
+ Process.kill(signal, command_pid) if command_pid
50
+ exit
51
+ rescue Errno::ESRCH
52
+ end
53
+
54
+ def upload_log(logs)
55
+ if logging_uri
56
+ Net::HTTP.start(logging_uri.host, logging_uri.port, use_ssl: true) do |http|
57
+ request = Net::HTTP::Post.new(logging_uri)
58
+ request.body = logs
59
+ request.content_type = "text/plain"
60
+ http.request(request)
61
+ end
62
+ end
63
+ end
64
+
65
+ def upload_logfile
66
+ if logging_uri
67
+ Net::HTTP.start(logging_uri.host, logging_uri.port, use_ssl: true) do |http|
68
+ request = Net::HTTP::Post.new(logging_uri, "Transfer-Encoding" => "chunked")
69
+ request.body_stream = File.open(logfile, "rb")
70
+ request.content_type = "text/plain"
71
+ http.request(request)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,44 @@
1
+ require "elastic_beans/aws/cloudformation_stack"
2
+
3
+ module ElasticBeans
4
+ class Network
5
+ APPLICATION_SECURITY_GROUP_KEY = "ApplicationSecurityGroup"
6
+ APPLICATION_SUBNET_KEY = "ApplicationSubnet"
7
+ ELB_SECURITY_GROUP_KEY = "ELBSecurityGroup"
8
+ ELB_SUBNET_KEY = "ELBSubnet"
9
+ SSH_SECURITY_GROUP_KEY = "SSHSecurityGroup"
10
+ VPC_KEY = "VpcId"
11
+
12
+ def initialize(stack_name:, cloudformation:)
13
+ @stack = ElasticBeans::Aws::CloudformationStack.new(stack_name, cloudformation: cloudformation)
14
+ end
15
+
16
+ def application_security_groups
17
+ [stack.stack_output(APPLICATION_SECURITY_GROUP_KEY)]
18
+ end
19
+
20
+ def application_subnets
21
+ [stack.stack_output(APPLICATION_SUBNET_KEY)]
22
+ end
23
+
24
+ def elb_security_groups
25
+ [stack.stack_output(ELB_SECURITY_GROUP_KEY)]
26
+ end
27
+
28
+ def elb_subnets
29
+ [stack.stack_output(ELB_SUBNET_KEY)]
30
+ end
31
+
32
+ def ssh_security_group
33
+ stack.stack_output(SSH_SECURITY_GROUP_KEY)
34
+ end
35
+
36
+ def vpc
37
+ stack.stack_output(VPC_KEY)
38
+ end
39
+
40
+ private
41
+
42
+ attr_reader :stack
43
+ end
44
+ end
@@ -0,0 +1,63 @@
1
+ require "logger"
2
+ require "uri"
3
+ require "action_dispatch"
4
+
5
+ module ElasticBeans
6
+ module Rack
7
+ class Exec
8
+ FAILURE = ['500', {'Content-type' => 'text/plain'}, [""]]
9
+ SUCCESS = ['200', {'Content-type' => 'text/plain'}, [""]]
10
+ USER_AGENT_PREFIX = 'aws-sqsd'.freeze
11
+
12
+ def initialize(app, args={})
13
+ @app = app
14
+ @application = args.fetch(:application)
15
+ @sqs = args.fetch(:sqs)
16
+ @logger = args[:logger] || Logger.new("/dev/null")
17
+ end
18
+
19
+ def call(env)
20
+ request = ActionDispatch::Request.new(env)
21
+ if enabled? && cron_request?(request)
22
+ command = command_from_request(request)
23
+ logger.info("[elastic_beans] Executing command: `#{command}'")
24
+ begin
25
+ application.enqueue_command(command, sqs: sqs)
26
+ rescue => e
27
+ logger.info("[elastic_beans] Enqueue failed: #{e.class.name}: #{e.message}\n#{e.backtrace.join("; ")}")
28
+ return FAILURE
29
+ end
30
+
31
+ return SUCCESS
32
+ end
33
+
34
+ logger.debug { "[elastic_beans] skipped exec request: #{request.path}" }
35
+ app.call(env)
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :app, :application, :logger, :sqs
41
+
42
+ def aws_sqsd?(request)
43
+ current_user_agent = request.headers['User-Agent'.freeze]
44
+ (current_user_agent.present? &&
45
+ current_user_agent.size >= USER_AGENT_PREFIX.size &&
46
+ current_user_agent[0..(USER_AGENT_PREFIX.size - 1)] == USER_AGENT_PREFIX)
47
+ end
48
+
49
+ def command_from_request(request)
50
+ URI.unescape(request.path.sub(%r{\A/exec/}, ''))
51
+ end
52
+
53
+ def cron_request?(request)
54
+ request.local? && aws_sqsd?(request) && request.method == 'POST' && request.path.start_with?('/exec/')
55
+ end
56
+
57
+ def enabled?
58
+ worker_disabled = ENV['DISABLE_SQS_CONSUMER'] || 'false'
59
+ worker_disabled == 'false'
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,4 @@
1
+ container_commands:
2
+ remove_scheduler_file:
3
+ command: "rm -f /var/app/ondeck/cron.yaml"
4
+ test: "/opt/elasticbeanstalk/bin/get-config meta -k sqsdconfig --output YAML | grep '^environment_name: ' | grep -qv '^environment_name: .*-scheduler$'"
@@ -0,0 +1,31 @@
1
+ module ElasticBeans
2
+ class UI
3
+ attr_reader :stdout, :stderr
4
+
5
+ def initialize(verbose: false, stdout: $stdout, stderr: $stderr)
6
+ @stdout = stdout
7
+ @stderr = stderr
8
+ @verbose = verbose
9
+ end
10
+
11
+ def debug
12
+ if verbose?
13
+ stdout.puts yield
14
+ end
15
+ end
16
+
17
+ def error(message)
18
+ stderr.puts message
19
+ end
20
+
21
+ def info(message)
22
+ stdout.puts message
23
+ end
24
+
25
+ private
26
+
27
+ def verbose?
28
+ !!@verbose
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ module ElasticBeans
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,9 @@
1
+ module ElasticBeans
2
+ end
3
+
4
+ require "elastic_beans/application"
5
+ require "elastic_beans/application_version"
6
+ require "elastic_beans/configuration_template"
7
+ require "elastic_beans/environment"
8
+ require "elastic_beans/network"
9
+ require "elastic_beans/version"
metadata ADDED
@@ -0,0 +1,218 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: elastic_beans
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Adam Stegman
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-11-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: aws-sdk
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: nesty
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rails
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: ruby-progressbar
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.2'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.2'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubyzip
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.2'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: thor
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.19.0
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.19.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: bundler
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '1.12'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '1.12'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rake
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '10.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '10.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '3.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '3.0'
139
+ description: a CLI that replaces the Elastic Beanstalk CLI, which looks great on the
140
+ surface but is missing some key pieces.
141
+ email:
142
+ - astegman@onemedical.com
143
+ executables:
144
+ - beans
145
+ extensions: []
146
+ extra_rdoc_files: []
147
+ files:
148
+ - ".gitignore"
149
+ - ".rspec"
150
+ - Gemfile
151
+ - LICENSE.md
152
+ - README.md
153
+ - Rakefile
154
+ - bin/console
155
+ - bin/setup
156
+ - circle.yml
157
+ - elastic_beans.gemspec
158
+ - exe/beans
159
+ - lib/elastic_beans.rb
160
+ - lib/elastic_beans/application.rb
161
+ - lib/elastic_beans/application_version.rb
162
+ - lib/elastic_beans/aws/cloudformation_stack.rb
163
+ - lib/elastic_beans/command.rb
164
+ - lib/elastic_beans/command/configure.rb
165
+ - lib/elastic_beans/command/create.rb
166
+ - lib/elastic_beans/command/deploy.rb
167
+ - lib/elastic_beans/command/exec.rb
168
+ - lib/elastic_beans/command/set_env.rb
169
+ - lib/elastic_beans/command/talk.rb
170
+ - lib/elastic_beans/command/version.rb
171
+ - lib/elastic_beans/configuration_template.rb
172
+ - lib/elastic_beans/configuration_template/base.rb
173
+ - lib/elastic_beans/configuration_template/exec.rb
174
+ - lib/elastic_beans/configuration_template/scheduler.rb
175
+ - lib/elastic_beans/configuration_template/webserver.rb
176
+ - lib/elastic_beans/configuration_template/worker.rb
177
+ - lib/elastic_beans/dns_entry.rb
178
+ - lib/elastic_beans/environment.rb
179
+ - lib/elastic_beans/environment/exec.rb
180
+ - lib/elastic_beans/environment/scheduler.rb
181
+ - lib/elastic_beans/environment/webserver.rb
182
+ - lib/elastic_beans/environment/worker.rb
183
+ - lib/elastic_beans/error.rb
184
+ - lib/elastic_beans/error/environments_not_ready.rb
185
+ - lib/elastic_beans/exec/ebextension.yml
186
+ - lib/elastic_beans/exec/elastic_beans_exec.conf
187
+ - lib/elastic_beans/exec/init.rb
188
+ - lib/elastic_beans/exec/run_command.sh
189
+ - lib/elastic_beans/exec/sqs_consumer.rb
190
+ - lib/elastic_beans/network.rb
191
+ - lib/elastic_beans/rack/exec.rb
192
+ - lib/elastic_beans/scheduler/ebextension.yml
193
+ - lib/elastic_beans/ui.rb
194
+ - lib/elastic_beans/version.rb
195
+ homepage: https://github.com/onemedical/elastic_beans
196
+ licenses: []
197
+ metadata: {}
198
+ post_install_message:
199
+ rdoc_options: []
200
+ require_paths:
201
+ - lib
202
+ required_ruby_version: !ruby/object:Gem::Requirement
203
+ requirements:
204
+ - - ">="
205
+ - !ruby/object:Gem::Version
206
+ version: '0'
207
+ required_rubygems_version: !ruby/object:Gem::Requirement
208
+ requirements:
209
+ - - ">="
210
+ - !ruby/object:Gem::Version
211
+ version: '0'
212
+ requirements: []
213
+ rubyforge_project:
214
+ rubygems_version: 2.5.1
215
+ signing_key:
216
+ specification_version: 4
217
+ summary: Elastic Beanstalk environment orchestration for a Rails app
218
+ test_files: []