elastic_beans 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|