orchestration 0.5.11 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +34 -30
- data/config/locales/en.yml +11 -15
- data/lib/orchestration.rb +4 -0
- data/lib/orchestration/docker_compose/app_service.rb +8 -1
- data/lib/orchestration/docker_compose/configuration.rb +1 -1
- data/lib/orchestration/docker_compose/database_service.rb +1 -1
- data/lib/orchestration/docker_compose/install_generator.rb +4 -4
- data/lib/orchestration/docker_compose/rabbitmq_service.rb +4 -2
- data/lib/orchestration/environment.rb +1 -1
- data/lib/orchestration/errors.rb +2 -0
- data/lib/orchestration/install_generator.rb +2 -29
- data/lib/orchestration/make.rb +4 -0
- data/lib/orchestration/make/orchestration.mk +503 -0
- data/lib/orchestration/service_check.rb +24 -38
- data/lib/orchestration/services/database/adapters.rb +1 -0
- data/lib/orchestration/services/database/adapters/adapter_base.rb +21 -0
- data/lib/orchestration/services/database/adapters/mysql2.rb +4 -2
- data/lib/orchestration/services/database/adapters/postgresql.rb +2 -0
- data/lib/orchestration/services/database/adapters/sqlite3.rb +2 -0
- data/lib/orchestration/services/database/configuration.rb +17 -19
- data/lib/orchestration/services/mixins/configuration_base.rb +1 -1
- data/lib/orchestration/services/rabbitmq.rb +1 -0
- data/lib/orchestration/templates/Dockerfile.erb +5 -7
- data/lib/orchestration/templates/application.mk.erb +23 -7
- data/lib/orchestration/templates/rabbitmq.yml.erb +5 -2
- data/lib/orchestration/terminal.rb +4 -3
- data/lib/orchestration/version.rb +1 -1
- data/lib/tasks/orchestration.rake +23 -6
- data/orchestration.gemspec +6 -3
- metadata +64 -21
- data/lib/orchestration/templates/makefile_macros.mk.erb +0 -112
- data/lib/orchestration/templates/orchestration.mk.erb +0 -393
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
module Orchestration
|
4
4
|
class ServiceCheck
|
5
|
-
ATTEMPT_LIMIT = ENV.fetch('ORCHESTRATION_RETRY_LIMIT', '
|
6
|
-
RETRY_INTERVAL = ENV.fetch('ORCHESTRATION_RETRY_INTERVAL', '
|
5
|
+
ATTEMPT_LIMIT = ENV.fetch('ORCHESTRATION_RETRY_LIMIT', '15').to_i
|
6
|
+
RETRY_INTERVAL = ENV.fetch('ORCHESTRATION_RETRY_INTERVAL', '15').to_i
|
7
7
|
|
8
8
|
def initialize(service, terminal, options = {})
|
9
9
|
@service = service
|
@@ -31,36 +31,36 @@ module Orchestration
|
|
31
31
|
@service.connect
|
32
32
|
true
|
33
33
|
rescue *@service.connection_errors => e
|
34
|
-
|
35
|
-
sleep @retry_interval
|
34
|
+
wait_failure(e)
|
36
35
|
retry unless @attempts == @attempt_limit
|
37
36
|
echo_error(e)
|
38
37
|
echo_failure
|
39
38
|
false
|
40
39
|
end
|
41
40
|
|
42
|
-
def
|
43
|
-
@
|
41
|
+
def wait_failure(error)
|
42
|
+
@attempts += 1
|
43
|
+
@last_error = error
|
44
|
+
sleep @retry_interval
|
44
45
|
end
|
45
46
|
|
46
|
-
def
|
47
|
-
@
|
47
|
+
def last_error
|
48
|
+
return nil if @last_error.nil?
|
49
|
+
|
50
|
+
last_error_message
|
48
51
|
end
|
49
52
|
|
50
|
-
def
|
51
|
-
|
52
|
-
"orchestration.#{@service_name}.waiting",
|
53
|
-
config: friendly_config,
|
54
|
-
default: default_waiting
|
55
|
-
)
|
53
|
+
def last_error_message
|
54
|
+
"(#{@last_error&.cause&.class&.name || @last_error&.class&.name})"
|
56
55
|
end
|
57
56
|
|
58
|
-
def
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
57
|
+
def echo_start
|
58
|
+
@terminal.write(@service_name.to_sym, '', :status)
|
59
|
+
@terminal.write(:config, friendly_config)
|
60
|
+
end
|
61
|
+
|
62
|
+
def echo_waiting
|
63
|
+
@terminal.write(:waiting, last_error)
|
64
64
|
end
|
65
65
|
|
66
66
|
def echo_ready
|
@@ -68,30 +68,16 @@ module Orchestration
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def service_ready
|
71
|
-
I18n.t(
|
72
|
-
"orchestration.#{@service_name}.ready",
|
73
|
-
config: friendly_config,
|
74
|
-
default: default_ready
|
75
|
-
)
|
76
|
-
end
|
77
|
-
|
78
|
-
def default_ready
|
79
|
-
I18n.t(
|
80
|
-
'orchestration.custom_service.ready',
|
81
|
-
config: friendly_config,
|
82
|
-
service: @service_name
|
83
|
-
)
|
71
|
+
I18n.t('orchestration.service.ready', service: @service_name)
|
84
72
|
end
|
85
73
|
|
86
74
|
def echo_failure
|
87
|
-
@terminal.write(
|
88
|
-
:failure,
|
89
|
-
I18n.t('orchestration.attempt_limit', limit: @attempt_limit)
|
90
|
-
)
|
75
|
+
@terminal.write(:failure, I18n.t('orchestration.attempt_limit', limit: @attempt_limit))
|
91
76
|
end
|
92
77
|
|
93
78
|
def echo_error(error)
|
94
|
-
|
79
|
+
cause = error.cause.nil? ? error : error.cause
|
80
|
+
@terminal.write(:error, "[#{cause.class.name}] #{cause.message}")
|
95
81
|
end
|
96
82
|
|
97
83
|
def friendly_config
|
@@ -9,6 +9,7 @@ module Orchestration
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
+
require 'orchestration/services/database/adapters/adapter_base'
|
12
13
|
require 'orchestration/services/database/adapters/mysql2'
|
13
14
|
require 'orchestration/services/database/adapters/postgresql'
|
14
15
|
require 'orchestration/services/database/adapters/sqlite3'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orchestration
|
4
|
+
module Services
|
5
|
+
module Database
|
6
|
+
module Adapters
|
7
|
+
module AdapterBase
|
8
|
+
attr_reader :config
|
9
|
+
|
10
|
+
def initialize(config = nil)
|
11
|
+
@config = config
|
12
|
+
end
|
13
|
+
|
14
|
+
def console_command
|
15
|
+
I18n.t("orchestration.dbconsole.#{name}") % config.settings.transform_keys(&:to_sym)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -5,12 +5,14 @@ module Orchestration
|
|
5
5
|
module Database
|
6
6
|
module Adapters
|
7
7
|
class Mysql2
|
8
|
+
include AdapterBase
|
9
|
+
|
8
10
|
def name
|
9
11
|
'mysql2'
|
10
12
|
end
|
11
13
|
|
12
14
|
def image
|
13
|
-
return
|
15
|
+
return mysql57 if gem_version < Gem::Version.new('0.4')
|
14
16
|
|
15
17
|
'library/mysql'
|
16
18
|
end
|
@@ -43,7 +45,7 @@ module Orchestration
|
|
43
45
|
|
44
46
|
private
|
45
47
|
|
46
|
-
def
|
48
|
+
def mysql57
|
47
49
|
'library/mysql:5.7'
|
48
50
|
end
|
49
51
|
|
@@ -15,7 +15,7 @@ module Orchestration
|
|
15
15
|
def friendly_config
|
16
16
|
return "[#{adapter.name}]" if sqlite?
|
17
17
|
|
18
|
-
"[#{adapter.name}] #{host}:#{port}"
|
18
|
+
"[#{adapter.name}] #{adapter.name}://#{username}:#{password}@#{host}:#{port}/#{database}"
|
19
19
|
end
|
20
20
|
|
21
21
|
def settings(healthcheck: false)
|
@@ -33,6 +33,10 @@ module Orchestration
|
|
33
33
|
sqlite? || super
|
34
34
|
end
|
35
35
|
|
36
|
+
def console_command
|
37
|
+
adapter.console_command
|
38
|
+
end
|
39
|
+
|
36
40
|
def adapter
|
37
41
|
url_adapter = url_config['adapter']
|
38
42
|
file_adapter = file_config['adapter']
|
@@ -82,37 +86,31 @@ module Orchestration
|
|
82
86
|
end
|
83
87
|
|
84
88
|
def host
|
85
|
-
|
89
|
+
chained_config('host') || super
|
86
90
|
end
|
87
91
|
|
88
92
|
def port
|
89
93
|
return nil if sqlite?
|
90
94
|
|
91
|
-
|
95
|
+
chained_config('port') || super
|
92
96
|
end
|
93
97
|
|
94
98
|
def username
|
95
|
-
(
|
96
|
-
url_config['username'] ||
|
97
|
-
file_config['username'] ||
|
98
|
-
(adapter && adapter.credentials['username'])
|
99
|
-
)
|
99
|
+
chained_config('username') || (adapter && adapter.credentials['username'])
|
100
100
|
end
|
101
101
|
|
102
102
|
def password
|
103
|
-
(
|
104
|
-
url_config['password'] ||
|
105
|
-
file_config['password'] ||
|
106
|
-
(adapter && adapter.credentials['password'])
|
107
|
-
)
|
103
|
+
chained_config('password') || (adapter && adapter.credentials['password'])
|
108
104
|
end
|
109
105
|
|
110
106
|
def database
|
111
|
-
(
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
107
|
+
chained_config('database') || (adapter && adapter.credentials['database'])
|
108
|
+
end
|
109
|
+
|
110
|
+
def chained_config(key)
|
111
|
+
return url_config[key] || file_config[key] if @env.environment == 'test'
|
112
|
+
|
113
|
+
file_config[key] || url_config[key]
|
116
114
|
end
|
117
115
|
|
118
116
|
def adapter_by_name(name)
|
@@ -121,7 +119,7 @@ module Orchestration
|
|
121
119
|
'mysql' => adapters::Mysql2,
|
122
120
|
'postgresql' => adapters::Postgresql,
|
123
121
|
'sqlite3' => adapters::Sqlite3
|
124
|
-
}.fetch(name).new
|
122
|
+
}.fetch(name).new(self)
|
125
123
|
rescue KeyError
|
126
124
|
Orchestration.error('database.unknown_adapter', adapter: name.inspect)
|
127
125
|
raise
|
@@ -53,7 +53,7 @@ module Orchestration
|
|
53
53
|
local, remote = parse_port(service).map(&:to_i)
|
54
54
|
return remote if @env.environment == 'test' && @options[:sidecar]
|
55
55
|
|
56
|
-
(@env.environment == '
|
56
|
+
(@env.environment == 'deployment' ? remote : local)
|
57
57
|
end
|
58
58
|
|
59
59
|
def service
|
@@ -2,7 +2,7 @@ FROM ruby:<%= ruby_version %>
|
|
2
2
|
ARG BUNDLE_BITBUCKET__ORG
|
3
3
|
ARG BUNDLE_GITHUB__COM
|
4
4
|
ARG GIT_COMMIT
|
5
|
-
RUN curl -sL https://deb.nodesource.com/
|
5
|
+
RUN curl -sL https://deb.nodesource.com/setup_14.x | bash - \
|
6
6
|
&& apt-get update \
|
7
7
|
&& DEBIAN_FRONTEND=noninteractive apt-get install -y \
|
8
8
|
nodejs \
|
@@ -13,17 +13,15 @@ RUN curl -sL https://deb.nodesource.com/setup_10.x | bash - \
|
|
13
13
|
&& mkdir /app<%if defined?(Webpacker) %> \
|
14
14
|
&& curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash \
|
15
15
|
&& . /root/.bashrc \
|
16
|
-
&& nvm install
|
16
|
+
&& nvm install 14.16.0 \
|
17
17
|
&& npm config set user 0 \
|
18
18
|
&& npm config set unsafe-perm true \
|
19
19
|
&& npm install -g yarn<% end %>
|
20
20
|
WORKDIR /app
|
21
21
|
COPY .build/Gemfile .build/Gemfile.lock ./
|
22
|
-
RUN bundle
|
23
|
-
|
24
|
-
|
25
|
-
RUN . /root/.bashrc ; yarn install
|
26
|
-
<% end %>
|
22
|
+
RUN bundle config set deployment 'true' \
|
23
|
+
&& bundle config set without 'development test' \
|
24
|
+
&& bundle install
|
27
25
|
ADD .build/context.tar .
|
28
26
|
<% if defined?(Webpacker) %>RUN . /root/.bashrc ; NODE_ENV=production RAILS_ENV=production yarn install && NODE_ENV=production RAILS_ENV=production SECRET_KEY_BASE=abc123 bundle exec rake assets:precompile<% elsif Rake::Task.tasks.map(&:name).include?('assets:precompile') %>RUN NODE_ENV=production RAILS_ENV=production SECRET_KEY_BASE=abc123 bundle exec rake assets:precompile<% end %>
|
29
27
|
RUN echo "${GIT_COMMIT}" > /app/GIT_COMMIT
|
@@ -1,20 +1,36 @@
|
|
1
|
+
include $(shell bundle exec ruby -e 'require "orchestration/make"')
|
2
|
+
|
1
3
|
#
|
2
4
|
# Example test command
|
3
5
|
#
|
4
|
-
#
|
6
|
+
# Define your test tasks here. The default command runs RSpec and Rubocop but
|
7
|
+
# you can feel free to add any other tasks you like.
|
5
8
|
#
|
6
|
-
#
|
7
|
-
# waits for them to be ready, and runs DB migrations.
|
9
|
+
# Set up your test dependencies and run tests by calling: `make setup test`
|
8
10
|
#
|
9
|
-
#
|
11
|
+
# Subsequent test runs can skip the setup step and simply run: `make test`
|
10
12
|
#
|
11
13
|
.PHONY: test
|
12
|
-
test:
|
14
|
+
test:
|
13
15
|
bundle exec rspec
|
14
16
|
bundle exec rubocop
|
15
17
|
|
16
|
-
#
|
17
|
-
.
|
18
|
+
#
|
19
|
+
# Define any custom setup that needs to take place before running tests.
|
20
|
+
# If the command exists, it will be called immediately after the `setup`
|
21
|
+
# command (which starts containers and sets up the database).
|
22
|
+
#
|
23
|
+
# This command can be deleted if it is not needed.
|
24
|
+
#
|
25
|
+
.PHONY: post-setup
|
26
|
+
post-setup:
|
27
|
+
@# Setup tasks that are not already provided by Orchestration go here.
|
28
|
+
|
29
|
+
#
|
30
|
+
# Launch all dependencies needed for a development environment and set up the
|
31
|
+
# development database.
|
32
|
+
#
|
33
|
+
.PHONY: setup
|
18
34
|
develop:
|
19
35
|
bundle install
|
20
36
|
@$(MAKE) start env=test
|
@@ -1,12 +1,15 @@
|
|
1
1
|
<% if compose.call('development').services.key?('rabbitmq') %>
|
2
2
|
development:
|
3
|
-
url: <%= "#{'<' + '%' + '='} ENV.fetch('RABBITMQ_URL', 'amqp://127.0.0.1:#{compose.call('development').local_port('rabbitmq')}') #{'%' + '>'}" %>
|
3
|
+
url: <%= "#{'<' + '%' + '='} ENV.fetch('RABBITMQ_URL', 'amqp://127.0.0.1:#{compose.call('development').local_port('rabbitmq', 5672)}') #{'%' + '>'}" %>
|
4
|
+
management_url: <%= "#{'<' + '%' + '='} ENV.fetch('RABBITMQ_MANAGEMENT_URL', 'http://guest:guest@127.0.0.1:#{compose.call('development').local_port('rabbitmq', 15672)}') #{'%' + '>'}" %>
|
4
5
|
<% end %>
|
5
6
|
|
6
7
|
<% if compose.call('test').services.key?('rabbitmq') %>
|
7
8
|
test:
|
8
|
-
url: <%= "#{'<' + '%' + '='} ENV.fetch('RABBITMQ_URL', 'amqp://127.0.0.1:#{compose.call('test').local_port('rabbitmq')}') #{'%' + '>'}" %>
|
9
|
+
url: <%= "#{'<' + '%' + '='} ENV.fetch('RABBITMQ_URL', 'amqp://127.0.0.1:#{compose.call('test').local_port('rabbitmq', 5672)}') #{'%' + '>'}" %>
|
10
|
+
management_url: <%= "#{'<' + '%' + '='} ENV.fetch('RABBITMQ_MANAGEMENT_URL', 'http://guest:guest@127.0.0.1:#{compose.call('test').local_port('rabbitmq', 15672)}') #{'%' + '>'}" %>
|
9
11
|
<% end %>
|
10
12
|
|
11
13
|
production:
|
12
14
|
url: <%%= ENV['RABBITMQ_URL'] %>
|
15
|
+
url: <%%= ENV['RABBITMQ_MANAGEMENT_URL'] %>
|
@@ -4,7 +4,6 @@ module Orchestration
|
|
4
4
|
COLOR_MAP = {
|
5
5
|
failure: %i[red bright],
|
6
6
|
error: %i[red],
|
7
|
-
waiting: %i[yellow],
|
8
7
|
ready: %i[green],
|
9
8
|
create: %i[green],
|
10
9
|
update: %i[yellow],
|
@@ -12,7 +11,9 @@ module Orchestration
|
|
12
11
|
status: %i[blue],
|
13
12
|
setup: %i[blue],
|
14
13
|
input: %i[red],
|
15
|
-
skip: %i[yellow bright]
|
14
|
+
skip: %i[yellow bright],
|
15
|
+
waiting: %i[yellow],
|
16
|
+
config: %i[cyan]
|
16
17
|
}.freeze
|
17
18
|
|
18
19
|
class Terminal
|
@@ -20,7 +21,7 @@ module Orchestration
|
|
20
21
|
@settings = settings
|
21
22
|
end
|
22
23
|
|
23
|
-
def write(desc, message, color_name = nil, newline: true)
|
24
|
+
def write(desc, message = nil, color_name = nil, newline: true)
|
24
25
|
output = newline ? "#{message}\n" : message.to_s
|
25
26
|
$stdout.print colorize(desc, output, color_name)
|
26
27
|
$stdout.flush
|
@@ -8,11 +8,9 @@ namespace :orchestration do
|
|
8
8
|
Orchestration::InstallGenerator.start
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
Orchestration::InstallGenerator.new.orchestration_makefile
|
15
|
-
end
|
11
|
+
desc I18n.t('orchestration.makefile')
|
12
|
+
task :makefile do
|
13
|
+
Orchestration.makefile
|
16
14
|
end
|
17
15
|
|
18
16
|
desc I18n.t('orchestration.rake.config')
|
@@ -21,6 +19,26 @@ namespace :orchestration do
|
|
21
19
|
puts "#{config['docker']['organization']} #{config['docker']['repository']}"
|
22
20
|
end
|
23
21
|
|
22
|
+
namespace :db do
|
23
|
+
desc I18n.t('orchestration.rake.db.url')
|
24
|
+
task :url do
|
25
|
+
config = Rails.application.config_for(:database)
|
26
|
+
|
27
|
+
if config[:adapter] == 'sqlite3'
|
28
|
+
puts "sqlite3:#{config[:database]}"
|
29
|
+
else
|
30
|
+
puts DatabaseUrl.to_active_record_url(config)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
desc I18n.t('orchestration.rake.db.console')
|
35
|
+
task :console do
|
36
|
+
env = Orchestration::Environment.new
|
37
|
+
options = ENV['db'] ? { config_path: "config/database.#{ENV['db']}.yml" } : {}
|
38
|
+
sh Orchestration::Services::Database::Configuration.new(env, nil, options).console_command
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
24
42
|
desc I18n.t('orchestration.rake.healthcheck')
|
25
43
|
task :healthcheck do
|
26
44
|
Orchestration::DockerHealthcheck.execute
|
@@ -28,7 +46,6 @@ namespace :orchestration do
|
|
28
46
|
|
29
47
|
desc I18n.t('orchestration.rake.wait')
|
30
48
|
task :wait do
|
31
|
-
Orchestration::InstallGenerator.new.verify_makefile(skip: false)
|
32
49
|
env = Orchestration::Environment.new
|
33
50
|
services = Orchestration::Services
|
34
51
|
env.docker_compose_config['services'].each do |name, _service|
|