elastic_beans 0.1.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.
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: []