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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +3 -0
- data/Gemfile +9 -0
- data/LICENSE.md +21 -0
- data/README.md +184 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/circle.yml +20 -0
- data/elastic_beans.gemspec +31 -0
- data/exe/beans +198 -0
- data/lib/elastic_beans/application.rb +127 -0
- data/lib/elastic_beans/application_version.rb +202 -0
- data/lib/elastic_beans/aws/cloudformation_stack.rb +66 -0
- data/lib/elastic_beans/command/configure.rb +184 -0
- data/lib/elastic_beans/command/create.rb +150 -0
- data/lib/elastic_beans/command/deploy.rb +77 -0
- data/lib/elastic_beans/command/exec.rb +37 -0
- data/lib/elastic_beans/command/set_env.rb +77 -0
- data/lib/elastic_beans/command/talk.rb +74 -0
- data/lib/elastic_beans/command/version.rb +17 -0
- data/lib/elastic_beans/command.rb +12 -0
- data/lib/elastic_beans/configuration_template/base.rb +114 -0
- data/lib/elastic_beans/configuration_template/exec.rb +50 -0
- data/lib/elastic_beans/configuration_template/scheduler.rb +20 -0
- data/lib/elastic_beans/configuration_template/webserver.rb +49 -0
- data/lib/elastic_beans/configuration_template/worker.rb +27 -0
- data/lib/elastic_beans/configuration_template.rb +197 -0
- data/lib/elastic_beans/dns_entry.rb +127 -0
- data/lib/elastic_beans/environment/exec.rb +23 -0
- data/lib/elastic_beans/environment/scheduler.rb +23 -0
- data/lib/elastic_beans/environment/webserver.rb +23 -0
- data/lib/elastic_beans/environment/worker.rb +29 -0
- data/lib/elastic_beans/environment.rb +300 -0
- data/lib/elastic_beans/error/environments_not_ready.rb +15 -0
- data/lib/elastic_beans/error.rb +15 -0
- data/lib/elastic_beans/exec/ebextension.yml +10 -0
- data/lib/elastic_beans/exec/elastic_beans_exec.conf +15 -0
- data/lib/elastic_beans/exec/init.rb +50 -0
- data/lib/elastic_beans/exec/run_command.sh +13 -0
- data/lib/elastic_beans/exec/sqs_consumer.rb +75 -0
- data/lib/elastic_beans/network.rb +44 -0
- data/lib/elastic_beans/rack/exec.rb +63 -0
- data/lib/elastic_beans/scheduler/ebextension.yml +4 -0
- data/lib/elastic_beans/ui.rb +31 -0
- data/lib/elastic_beans/version.rb +3 -0
- data/lib/elastic_beans.rb +9 -0
- metadata +218 -0
@@ -0,0 +1,150 @@
|
|
1
|
+
require "timeout"
|
2
|
+
require "ruby-progressbar"
|
3
|
+
require "elastic_beans/dns_entry"
|
4
|
+
require "elastic_beans/error"
|
5
|
+
require "elastic_beans/environment/webserver"
|
6
|
+
|
7
|
+
module ElasticBeans
|
8
|
+
module Command
|
9
|
+
class Create
|
10
|
+
USAGE = "create -a APPLICATION [-t TYPE] [-q QUEUE] [-d PRETTY_DNS] ENVIRONMENT"
|
11
|
+
DESC = "Create a new environment in Elastic Beanstalk and attach it to relevant resources"
|
12
|
+
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.
|
15
|
+
|
16
|
+
Requires the Elastic Beanstalk application name.
|
17
|
+
Requires AWS credentials to be set in the environment, i.e. AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.
|
18
|
+
LONG_DESC
|
19
|
+
|
20
|
+
def initialize(
|
21
|
+
environment_name:,
|
22
|
+
dns: nil,
|
23
|
+
queue: nil,
|
24
|
+
tags:,
|
25
|
+
application:,
|
26
|
+
ui:,
|
27
|
+
elastic_beanstalk:,
|
28
|
+
route53:,
|
29
|
+
s3:
|
30
|
+
)
|
31
|
+
@environment_name = environment_name
|
32
|
+
@environment_type = environment_name
|
33
|
+
@dns = dns
|
34
|
+
if @environment_type == "worker"
|
35
|
+
@queue = queue || "default"
|
36
|
+
@environment_name = "#{@environment_name}-#{@queue}"
|
37
|
+
end
|
38
|
+
@tags = tags
|
39
|
+
@application = application
|
40
|
+
@ui = ui
|
41
|
+
@elastic_beanstalk = elastic_beanstalk
|
42
|
+
@route53 = route53
|
43
|
+
@s3 = s3
|
44
|
+
end
|
45
|
+
|
46
|
+
def run
|
47
|
+
ui.debug { "Creating application version from code at #{Dir.pwd}..." }
|
48
|
+
version = application.deployed_version || ElasticBeans::ApplicationVersion.create(
|
49
|
+
working_directory: Dir.pwd,
|
50
|
+
application: application,
|
51
|
+
elastic_beanstalk: elastic_beanstalk,
|
52
|
+
s3: s3,
|
53
|
+
)
|
54
|
+
environment = ElasticBeans::Environment.new_by_type(
|
55
|
+
environment_type,
|
56
|
+
suffix: environment_name,
|
57
|
+
queue: queue,
|
58
|
+
application: application,
|
59
|
+
elastic_beanstalk: elastic_beanstalk,
|
60
|
+
)
|
61
|
+
|
62
|
+
dns_thread = Thread.new do
|
63
|
+
if environment_type == "webserver" && dns_entry
|
64
|
+
ui.debug { "Updating DNS entry `#{dns_entry.name}'..." }
|
65
|
+
dns_entry.update(dns_value(environment))
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
ui.info("Creating environment `#{environment.name}'...")
|
70
|
+
progressbar = ProgressBar.create(title: "Creating", total: nil, output: ui.stdout)
|
71
|
+
environment_thread = Thread.new do
|
72
|
+
environment.create(
|
73
|
+
tags: tags,
|
74
|
+
version: version.version_label,
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
loop do
|
79
|
+
sleep 1
|
80
|
+
progressbar.increment
|
81
|
+
if !environment_thread.alive? && !dns_thread.alive?
|
82
|
+
progressbar.total = progressbar.progress
|
83
|
+
break
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
environment_thread.join
|
88
|
+
dns_thread.join
|
89
|
+
ui.info("Created!")
|
90
|
+
if environment_type == "webserver"
|
91
|
+
if dns_entry
|
92
|
+
host = dns_entry.name
|
93
|
+
else
|
94
|
+
host = environment.cname
|
95
|
+
end
|
96
|
+
ui.info("#{application.name} reachable at https://#{host}/")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
attr_reader(
|
103
|
+
:application,
|
104
|
+
:dns,
|
105
|
+
:environment_name,
|
106
|
+
:environment_type,
|
107
|
+
:queue,
|
108
|
+
:tags,
|
109
|
+
:elastic_beanstalk,
|
110
|
+
:route53,
|
111
|
+
:s3,
|
112
|
+
:ui,
|
113
|
+
)
|
114
|
+
|
115
|
+
def dns_entry
|
116
|
+
if dns.nil?
|
117
|
+
return nil
|
118
|
+
end
|
119
|
+
|
120
|
+
DnsEntry.new(dns, route53: route53)
|
121
|
+
end
|
122
|
+
|
123
|
+
def dns_value(environment)
|
124
|
+
Timeout.timeout(1200) do
|
125
|
+
loop do
|
126
|
+
sleep 1
|
127
|
+
begin
|
128
|
+
value = environment.cname
|
129
|
+
return value if value
|
130
|
+
rescue ElasticBeans::Environment::Webserver::MissingEnvironmentError
|
131
|
+
# keep trying
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
rescue Timeout::Error
|
136
|
+
raise UnhealthyEnvironmentError.new(environment_name: environment.name)
|
137
|
+
end
|
138
|
+
|
139
|
+
class UnhealthyEnvironmentError < ElasticBeans::Error
|
140
|
+
def initialize(environment_name:)
|
141
|
+
@environment_name = environment_name
|
142
|
+
end
|
143
|
+
|
144
|
+
def message
|
145
|
+
"Environment `#{@environment_name}' is still not available"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require "elastic_beans/error/environments_not_ready"
|
2
|
+
|
3
|
+
module ElasticBeans
|
4
|
+
module Command
|
5
|
+
class Deploy
|
6
|
+
USAGE = "deploy -a APPLICATION"
|
7
|
+
DESC = "Deploy the HEAD git commit to all environments in Elastic Beanstalk"
|
8
|
+
LONG_DESC = <<-LONG_DESC
|
9
|
+
Deploy the HEAD git commit to all environments in Elastic Beanstalk.
|
10
|
+
|
11
|
+
Requires the application name.
|
12
|
+
Requires AWS credentials to be set in the environment, i.e. AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.
|
13
|
+
LONG_DESC
|
14
|
+
|
15
|
+
def initialize(application:, elastic_beanstalk:, s3:, ui:)
|
16
|
+
@application = application
|
17
|
+
@elastic_beanstalk = elastic_beanstalk
|
18
|
+
@s3 = s3
|
19
|
+
@ui = ui
|
20
|
+
end
|
21
|
+
|
22
|
+
def run
|
23
|
+
environments = application.environments
|
24
|
+
unready_environments = environments.select { |environment| environment.status != "Ready" }
|
25
|
+
if unready_environments.any?
|
26
|
+
raise EnvironmentsNotReady.new(environments: unready_environments)
|
27
|
+
end
|
28
|
+
|
29
|
+
ui.debug { "Creating application version from code at #{Dir.pwd}..." }
|
30
|
+
progressbar = ProgressBar.create(title: "Deploying", total: nil, output: ui.stdout)
|
31
|
+
version = nil
|
32
|
+
version_thread = Thread.new do
|
33
|
+
version = ElasticBeans::ApplicationVersion.create(
|
34
|
+
working_directory: Dir.pwd,
|
35
|
+
application: application,
|
36
|
+
elastic_beanstalk: elastic_beanstalk,
|
37
|
+
s3: s3,
|
38
|
+
).version_label
|
39
|
+
end
|
40
|
+
|
41
|
+
loop do
|
42
|
+
sleep 1
|
43
|
+
progressbar.increment
|
44
|
+
if !version_thread.alive?
|
45
|
+
break
|
46
|
+
end
|
47
|
+
end
|
48
|
+
version_thread.join
|
49
|
+
|
50
|
+
progressbar.log("Deploying version #{version} to #{application.name}...")
|
51
|
+
deploy_threads = environments.map { |environment|
|
52
|
+
progressbar.log("Deploying version '#{version}' to environment `#{environment.name}'...")
|
53
|
+
thread = Thread.new do
|
54
|
+
environment.deploy_version(version)
|
55
|
+
end
|
56
|
+
progressbar.increment
|
57
|
+
thread
|
58
|
+
}
|
59
|
+
|
60
|
+
loop do
|
61
|
+
sleep 1
|
62
|
+
progressbar.increment
|
63
|
+
if deploy_threads.none?(&:alive?)
|
64
|
+
progressbar.total = progressbar.progress
|
65
|
+
break
|
66
|
+
end
|
67
|
+
end
|
68
|
+
deploy_threads.each(&:join)
|
69
|
+
ui.info("Deployed!")
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
attr_reader :application, :elastic_beanstalk, :s3, :ui
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "shellwords"
|
2
|
+
|
3
|
+
module ElasticBeans
|
4
|
+
module Command
|
5
|
+
class Exec
|
6
|
+
USAGE = "exec -a APPLICATION rake db:migrate"
|
7
|
+
DESC = "Run an arbitrary command in the context of your application"
|
8
|
+
LONG_DESC = <<-LONG_DESC
|
9
|
+
Run an arbitrary command in the context of your application.
|
10
|
+
The command is run in an "exec" environment, separate from your webserver or worker environments.
|
11
|
+
Upload gzipped output from the command to an HTTP endpoint.
|
12
|
+
|
13
|
+
Requires the Elastic Beanstalk application name.
|
14
|
+
Requires AWS credentials to be set in the environment, i.e. AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.
|
15
|
+
LONG_DESC
|
16
|
+
|
17
|
+
def initialize(application:, sqs:, ui:)
|
18
|
+
@application = application
|
19
|
+
@sqs = sqs
|
20
|
+
@ui = ui
|
21
|
+
end
|
22
|
+
|
23
|
+
def run(*command_parts)
|
24
|
+
ui.info("Running `#{command_parts.join(" ")}' on #{application.name}...")
|
25
|
+
application.enqueue_command(command(command_parts), sqs: sqs)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
attr_reader :application, :sqs, :ui
|
31
|
+
|
32
|
+
def command(command_parts)
|
33
|
+
command_parts.map { |word| Shellwords.escape(word) }.join(" ")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require "ruby-progressbar"
|
2
|
+
require "elastic_beans/error/environments_not_ready"
|
3
|
+
|
4
|
+
module ElasticBeans
|
5
|
+
module Command
|
6
|
+
class SetEnv
|
7
|
+
USAGE = "setenv -a APPLICATION KEY=value [KEY=value]..."
|
8
|
+
DESC = "Update environment variables in the Elastic Beanstalk application"
|
9
|
+
LONG_DESC = <<-LONG_DESC
|
10
|
+
Update environment variables in the Elastic Beanstalk application.
|
11
|
+
Updates all running environments and configuration templates resulting from `configure`.
|
12
|
+
|
13
|
+
Requires the application name.
|
14
|
+
Requires AWS credentials to be set in the environment, i.e. AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.
|
15
|
+
LONG_DESC
|
16
|
+
|
17
|
+
def initialize(application:, ui:)
|
18
|
+
@application = application
|
19
|
+
@ui = ui
|
20
|
+
end
|
21
|
+
|
22
|
+
def run(*env_pairs)
|
23
|
+
environments = application.environments
|
24
|
+
unready_environments = environments.select { |environment| environment.status != "Ready" }
|
25
|
+
if unready_environments.any?
|
26
|
+
raise EnvironmentsNotReady.new(environments: unready_environments)
|
27
|
+
end
|
28
|
+
|
29
|
+
env_vars = pairs_as_hash(env_pairs)
|
30
|
+
threads = []
|
31
|
+
|
32
|
+
progressbar = ProgressBar.create(title: "Updating", total: nil, output: ui.stdout)
|
33
|
+
|
34
|
+
progressbar.log("Updating configuration templates in #{application.name}...")
|
35
|
+
threads += application.configuration_templates.map { |config|
|
36
|
+
thread = Thread.new do
|
37
|
+
config.update_environment(env_vars)
|
38
|
+
end
|
39
|
+
progressbar.increment
|
40
|
+
thread
|
41
|
+
}
|
42
|
+
|
43
|
+
threads += environments.map { |environment|
|
44
|
+
progressbar.log("Updating `#{environment.name}'...")
|
45
|
+
thread = Thread.new do
|
46
|
+
environment.update_environment(env_vars)
|
47
|
+
end
|
48
|
+
progressbar.increment
|
49
|
+
thread
|
50
|
+
}
|
51
|
+
|
52
|
+
loop do
|
53
|
+
sleep 1
|
54
|
+
progressbar.increment
|
55
|
+
if threads.none?(&:alive?)
|
56
|
+
progressbar.total = progressbar.progress
|
57
|
+
break
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
threads.each(&:join)
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
attr_reader :application, :ui
|
67
|
+
|
68
|
+
def pairs_as_hash(pairs)
|
69
|
+
pairs.reduce({}) { |acc, pair|
|
70
|
+
key, value = pair.split('=', 2)
|
71
|
+
acc[key] = value
|
72
|
+
acc
|
73
|
+
}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module ElasticBeans
|
2
|
+
module Command
|
3
|
+
class Talk
|
4
|
+
BEANSTALK = <<-BEANSTALK
|
5
|
+
...........................,:~~:............................
|
6
|
+
........................:~~~~~++++=~........................
|
7
|
+
.....................,:~~~~~~~++++++~:......................
|
8
|
+
...................,~~~~~~~~~~++++++++++=~..................
|
9
|
+
...................,~~~~~~~~~~++++++++++++~:................
|
10
|
+
...................,~~~~~~~~~~+++++++++++++=:...............
|
11
|
+
...................,~~~~~~~~~~+++++++++++++=:...............
|
12
|
+
...................,~~~~~~~~~~+++++++++++++=:...............
|
13
|
+
...................,~~~~~~~~~~+++++++++++++=:......,::~~:...
|
14
|
+
...................,~~~~~~~~~~+++++++++++++=~::~~~~~~~=+++=:
|
15
|
+
...................,~~~~~~~~~~++++++=~~~~~~~~~~~~~~~~~=+++=~
|
16
|
+
...................,~~~~~~~~~~++++==~~~~~~~~~~~~~~~~~~=+++=~
|
17
|
+
...................,~~~~~~~~~~++++==~~~~~~~~~~~~~~~~~~=+++=~
|
18
|
+
...................,~~~~~~~~~~++++==~~~~~~~~~~~~~~~~~~=+++=~
|
19
|
+
...................,~~~~~~~~~~++++==~~~~~~~~~~~~~~~~~~=+++=~
|
20
|
+
...................,~~~~~~~~~~++++==~~~~~~~~~~~~~~~~~~=+++=~
|
21
|
+
...................,~~~~~~~~~~++++==~~~~~~~~~~~~~~~~~~=+++=~
|
22
|
+
...................,~~~~~~~~~~++++==~~~~~~~~~~~~~~~~~~=+++=~
|
23
|
+
...................,~~~~~~~~~~++++==~~~~~~~~~~~~~~~~~~=+++=~
|
24
|
+
...................,~~~~~~~~~~++++==~~~~~~~:::::::::::::::::
|
25
|
+
...................,~~~~~~~~~~++++==~::::::::,,,,,,.........
|
26
|
+
...................,~~~~~~~~~~+++++++++++++=:...............
|
27
|
+
...................,~~~~~~~~~~+++++++++++++=:...............
|
28
|
+
...................,~~~~~~~~~~+++++++++++++=:...............
|
29
|
+
...................,~~~~~~~~~~+++++++++++++=:...............
|
30
|
+
...................,~~~~~~~~~~+++++++++++++=:...............
|
31
|
+
...................,~~~~~~~~~~+++++++++++++=:...............
|
32
|
+
...............:~~~~~~~~~~~~~~+++++++++:....................
|
33
|
+
...............:~~~~~~~~~~~~~~+++++++++:....................
|
34
|
+
...............:~~~~~~~~~~~~~~+++++++++:....................
|
35
|
+
...............:~~~~~~~~~~~~~~+++++++++:....................
|
36
|
+
...............:~~~~~~~~~~~~~~+++++++++:....................
|
37
|
+
......,:~~=++????????+++~~~~~~+++++++++:....................
|
38
|
+
~==II??????????+++++++++~~~~~~+++++++++:....................
|
39
|
+
:~~~~=++++++++++++++++++~~~~~~+++++++++:....................
|
40
|
+
:~~~~=++++++++++++++++++~~~~~~+++++++++:....................
|
41
|
+
:~~~~=++++++++++++++++++~~~~~~+++++++++:....................
|
42
|
+
:~~~~=++++++++++++++++++~~~~~~+++++++++:....................
|
43
|
+
:~~~~=++++++++++++++++++~~~~~~+++++++++:....................
|
44
|
+
:~~~~=++++++++++++++++++~~~~~~+++++++++:....................
|
45
|
+
:~~~~=++++++++++++++++++~~~~~~+++++++++:....................
|
46
|
+
:~~~~=++++++++++++++++++~~~~~~+++++++++:....................
|
47
|
+
:~~~~=+++++++++++++++=~~~~~~~~+++++++++:....................
|
48
|
+
:~~~~=++++++=~~~~~~~~~~~~~~~~~+++++++++:....................
|
49
|
+
...:~=~~:......:~~~~~~~~~~~~~~+++++++++:....................
|
50
|
+
...............:~~~~~~~~~~~~~~+++++++++:....................
|
51
|
+
...............:~~~~~~~~~~~~~~+++++++++:....................
|
52
|
+
...............:~~~~~~~~~~~~~~+++++++++:....................
|
53
|
+
...............,:~~~~~~~~~~~~~+++++++++:....................
|
54
|
+
..................:~~~~~~~~~~~+++++++++:....................
|
55
|
+
.....................,:~~~~~~~++++++~:......................
|
56
|
+
........................:~~~~~++++=~........................
|
57
|
+
...........................,:~~:............................
|
58
|
+
............................................................
|
59
|
+
BEANSTALK
|
60
|
+
|
61
|
+
def initialize(ui:)
|
62
|
+
@ui = ui
|
63
|
+
end
|
64
|
+
|
65
|
+
def run
|
66
|
+
ui.info BEANSTALK
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
attr_reader :ui
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "elastic_beans/command/configure"
|
2
|
+
require "elastic_beans/command/create"
|
3
|
+
require "elastic_beans/command/deploy"
|
4
|
+
require "elastic_beans/command/exec"
|
5
|
+
require "elastic_beans/command/set_env"
|
6
|
+
require "elastic_beans/command/talk"
|
7
|
+
require "elastic_beans/command/version"
|
8
|
+
|
9
|
+
module ElasticBeans
|
10
|
+
module Command
|
11
|
+
end
|
12
|
+
end
|