orchestration 0.3.17 → 0.4.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 +4 -4
- data/.gitignore +4 -0
- data/LICENSE +7 -0
- data/MANIFEST +76 -0
- data/Makefile +3 -3
- data/README.md +162 -137
- data/Rakefile +2 -2
- data/config/locales/en.yml +3 -1
- data/lib/orchestration/docker_compose/app_service.rb +84 -13
- data/lib/orchestration/docker_compose/compose_configuration.rb +69 -0
- data/lib/orchestration/docker_compose/database_service.rb +15 -13
- data/lib/orchestration/docker_compose/install_generator.rb +3 -2
- data/lib/orchestration/docker_compose/mongo_service.rb +5 -5
- data/lib/orchestration/docker_compose/rabbitmq_service.rb +2 -3
- data/lib/orchestration/docker_compose.rb +1 -0
- data/lib/orchestration/environment.rb +19 -6
- data/lib/orchestration/errors.rb +1 -1
- data/lib/orchestration/file_helpers.rb +27 -4
- data/lib/orchestration/install_generator.rb +85 -20
- data/lib/orchestration/services/app/configuration.rb +9 -5
- data/lib/orchestration/services/app/healthcheck.rb +1 -22
- data/lib/orchestration/services/database/adapters/mysql2.rb +13 -2
- data/lib/orchestration/services/database/adapters/postgresql.rb +0 -1
- data/lib/orchestration/services/database/configuration.rb +68 -75
- data/lib/orchestration/services/database/healthcheck.rb +10 -1
- data/lib/orchestration/services/listener/configuration.rb +1 -1
- data/lib/orchestration/services/listener/healthcheck.rb +2 -2
- data/lib/orchestration/services/{configuration_base.rb → mixins/configuration_base.rb} +15 -13
- data/lib/orchestration/services/{healthcheck_base.rb → mixins/healthcheck_base.rb} +3 -2
- data/lib/orchestration/services/mixins/http_healthcheck.rb +38 -0
- data/lib/orchestration/services/mongo/configuration.rb +37 -63
- data/lib/orchestration/services/mongo/healthcheck.rb +3 -32
- data/lib/orchestration/services/rabbitmq/configuration.rb +11 -22
- data/lib/orchestration/services/rabbitmq/healthcheck.rb +2 -2
- data/lib/orchestration/services.rb +3 -2
- data/lib/orchestration/templates/Dockerfile.erb +8 -4
- data/lib/orchestration/templates/database.yml.erb +32 -0
- data/lib/orchestration/templates/deploy.mk.erb +2 -2
- data/lib/orchestration/templates/entrypoint.sh.erb +13 -4
- data/lib/orchestration/templates/env.erb +10 -2
- data/lib/orchestration/templates/healthcheck.rb.erb +56 -0
- data/lib/orchestration/templates/makefile_macros.mk.erb +108 -0
- data/lib/orchestration/templates/mongoid.yml.erb +18 -0
- data/lib/orchestration/templates/orchestration.mk.erb +242 -120
- data/lib/orchestration/templates/puma.rb.erb +19 -0
- data/lib/orchestration/templates/rabbitmq.yml.erb +12 -0
- data/lib/orchestration/templates/unicorn.rb.erb +5 -5
- data/lib/orchestration/terminal.rb +13 -15
- data/lib/orchestration/version.rb +1 -1
- data/lib/orchestration.rb +20 -2
- data/lib/tasks/orchestration.rake +3 -1
- data/orchestration.gemspec +3 -5
- metadata +23 -13
@@ -8,41 +8,112 @@ module Orchestration
|
|
8
8
|
@config = config
|
9
9
|
end
|
10
10
|
|
11
|
+
class << self
|
12
|
+
def command
|
13
|
+
server = env.web_server
|
14
|
+
%w[bundle exec] + case env.web_server
|
15
|
+
when 'puma'
|
16
|
+
%w[puma -C config/puma.rb]
|
17
|
+
when 'unicorn'
|
18
|
+
%w[unicorn -c config/unicorn.rb]
|
19
|
+
else
|
20
|
+
unsupported_web_server(server)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def entrypoint
|
25
|
+
["/app/#{orchestration}/entrypoint.sh"]
|
26
|
+
end
|
27
|
+
|
28
|
+
def healthcheck
|
29
|
+
{
|
30
|
+
'test' => ['ruby', "/app/#{orchestration}/healthcheck.rb"],
|
31
|
+
# Defaults according to
|
32
|
+
# https://docs.docker.com/engine/reference/builder/#healthcheck
|
33
|
+
# Except start_period which cannot be set to 0s
|
34
|
+
'interval' => '30s',
|
35
|
+
'timeout' => '30s',
|
36
|
+
'start_period' => '5s',
|
37
|
+
'retries' => 3
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def orchestration
|
44
|
+
env.orchestration_dir_name
|
45
|
+
end
|
46
|
+
|
47
|
+
def env
|
48
|
+
@env ||= Environment.new
|
49
|
+
end
|
50
|
+
|
51
|
+
def unsupported_web_server(server)
|
52
|
+
raise ArgumentError,
|
53
|
+
I18n.t(
|
54
|
+
'orchestration.rake.app.unspported_web_server',
|
55
|
+
server: server,
|
56
|
+
expected: %w[puma unicorn]
|
57
|
+
)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
11
61
|
def definition
|
12
62
|
{
|
13
63
|
'image' => image,
|
14
64
|
'environment' => environment,
|
15
|
-
'ports' => ports
|
65
|
+
'ports' => ports,
|
66
|
+
'deploy' => deploy,
|
67
|
+
'logging' => logging
|
16
68
|
}
|
17
69
|
end
|
18
70
|
|
19
71
|
private
|
20
72
|
|
21
73
|
def image
|
22
|
-
'${DOCKER_ORGANIZATION}/${DOCKER_REPOSITORY}'
|
74
|
+
'${DOCKER_ORGANIZATION}/${DOCKER_REPOSITORY}:${DOCKER_TAG}'
|
75
|
+
end
|
76
|
+
|
77
|
+
def deploy
|
78
|
+
{
|
79
|
+
'mode' => 'replicated',
|
80
|
+
'replicas' => '${REPLICAS}'
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
def logging
|
85
|
+
{
|
86
|
+
'driver' => 'json-file',
|
87
|
+
'options' => {
|
88
|
+
'max-size' => '10m',
|
89
|
+
'max-file' => '5'
|
90
|
+
}
|
91
|
+
}
|
23
92
|
end
|
24
93
|
|
25
94
|
def environment
|
26
95
|
{
|
27
96
|
'RAILS_LOG_TO_STDOUT' => '1',
|
28
97
|
'RAILS_SERVE_STATIC_FILES' => '1',
|
29
|
-
'
|
30
|
-
'
|
31
|
-
|
32
|
-
}.merge(inherited_environment)
|
98
|
+
'WEB_PRELOAD_APP' => '1',
|
99
|
+
'WEB_HEALTHCHECK_PATH' => '/'
|
100
|
+
}.merge(Hash[inherited_environment.map { |key| [key, nil] }])
|
33
101
|
end
|
34
102
|
|
35
103
|
def inherited_environment
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
104
|
+
%w[
|
105
|
+
DATABASE_URL
|
106
|
+
HOST_UID
|
107
|
+
RAILS_ENV
|
108
|
+
SECRET_KEY_BASE
|
109
|
+
WEB_CONCURRENCY
|
110
|
+
WEB_TIMEOUT
|
111
|
+
WEB_WORKER_PROCESSES
|
112
|
+
]
|
42
113
|
end
|
43
114
|
|
44
115
|
def ports
|
45
|
-
['${
|
116
|
+
['${CONTAINER_PORT:?CONTAINER_PORT must be provided}:8080']
|
46
117
|
end
|
47
118
|
end
|
48
119
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orchestration
|
4
|
+
module DockerCompose
|
5
|
+
class ComposeConfiguration
|
6
|
+
def initialize(env)
|
7
|
+
@env = env
|
8
|
+
end
|
9
|
+
|
10
|
+
def services
|
11
|
+
config['services']
|
12
|
+
end
|
13
|
+
|
14
|
+
def database_adapter_name
|
15
|
+
return nil unless defined?(ActiveRecord)
|
16
|
+
return 'postgresql' if defined?(::PG)
|
17
|
+
return 'mysql2' if defined?(::Mysql2)
|
18
|
+
return 'sqlite3' if defined?(::SQLite3)
|
19
|
+
|
20
|
+
nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def database_adapter
|
24
|
+
return nil unless defined?(ActiveRecord)
|
25
|
+
|
26
|
+
base = Orchestration::Services::Database::Adapters
|
27
|
+
return base::Postgresql.new if defined?(::PG)
|
28
|
+
return base::Mysql2.new if defined?(::Mysql2)
|
29
|
+
return base::Sqlite3.new if defined?(::SQLite3)
|
30
|
+
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def local_port(name, remote_port = nil)
|
35
|
+
return nil if ports(name).empty?
|
36
|
+
return ports(name).first[:local].to_i if remote_port.nil?
|
37
|
+
|
38
|
+
ports(name).find { |mapping| mapping[:remote] == remote_port }
|
39
|
+
.fetch(:local)
|
40
|
+
.to_i
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def config
|
46
|
+
@config ||= @env.docker_compose_config
|
47
|
+
end
|
48
|
+
|
49
|
+
def ports(name)
|
50
|
+
services
|
51
|
+
.fetch(name.to_s)
|
52
|
+
.fetch('ports', [])
|
53
|
+
.map do |mapping|
|
54
|
+
next short_format_ports(mapping) if mapping.is_a?(String)
|
55
|
+
|
56
|
+
{
|
57
|
+
local: mapping.fetch('published'),
|
58
|
+
remote: mapping.fetch('target')
|
59
|
+
}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def short_format_ports(mapping)
|
64
|
+
local, _, remote = mapping.partition(':')
|
65
|
+
{ local: local, remote: remote }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -3,41 +3,43 @@
|
|
3
3
|
module Orchestration
|
4
4
|
module DockerCompose
|
5
5
|
class DatabaseService
|
6
|
-
# We dictate which port all database services will run on in their
|
7
|
-
# container to simplify port mapping.
|
8
|
-
PORT = 3354
|
9
|
-
|
10
6
|
def initialize(config, environment)
|
11
7
|
@environment = environment
|
12
8
|
@config = config
|
13
9
|
end
|
14
10
|
|
15
11
|
def definition
|
16
|
-
return nil
|
17
|
-
return nil if
|
12
|
+
return nil unless @config.enabled?
|
13
|
+
return nil if adapter.name == 'sqlite3'
|
18
14
|
|
19
15
|
{
|
20
|
-
'image' =>
|
21
|
-
'environment' =>
|
16
|
+
'image' => adapter.image,
|
17
|
+
'environment' => adapter.environment
|
22
18
|
}.merge(ports).merge(volumes)
|
23
19
|
end
|
24
20
|
|
25
21
|
private
|
26
22
|
|
27
|
-
def
|
28
|
-
@
|
23
|
+
def adapter
|
24
|
+
name = ComposeConfiguration.new(@environment).database_adapter_name
|
25
|
+
base = 'Orchestration::Services::Database::Adapters'
|
26
|
+
Object.const_get("#{base}::#{name.capitalize}").new
|
27
|
+
end
|
28
|
+
|
29
|
+
def remote_port
|
30
|
+
adapter.default_port
|
29
31
|
end
|
30
32
|
|
31
33
|
def ports
|
32
34
|
return {} unless %i[development test].include?(@environment)
|
33
35
|
|
34
|
-
{ 'ports' => ["#{
|
36
|
+
{ 'ports' => ["#{Orchestration.random_local_port}:#{remote_port}"] }
|
35
37
|
end
|
36
38
|
|
37
39
|
def volumes
|
38
|
-
return {}
|
40
|
+
return {} if @environment == :test
|
39
41
|
|
40
|
-
{ 'volumes' => ["#{
|
42
|
+
{ 'volumes' => ["#{@config.env.database_volume}:#{adapter.data_dir}"] }
|
41
43
|
end
|
42
44
|
end
|
43
45
|
end
|
@@ -56,7 +56,8 @@ module Orchestration
|
|
56
56
|
def structure(environment = nil)
|
57
57
|
{
|
58
58
|
'version' => compose_config(environment).version,
|
59
|
-
'services' => services(environment)
|
59
|
+
'services' => services(environment),
|
60
|
+
'volumes' => volumes(environment)
|
60
61
|
}
|
61
62
|
end
|
62
63
|
|
@@ -107,7 +108,7 @@ module Orchestration
|
|
107
108
|
end
|
108
109
|
|
109
110
|
def service_enabled?(service_name)
|
110
|
-
return false
|
111
|
+
return false unless configuration(service_name).enabled?
|
111
112
|
|
112
113
|
true
|
113
114
|
end
|
@@ -11,7 +11,7 @@ module Orchestration
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def definition
|
14
|
-
return nil
|
14
|
+
return nil unless @config.enabled?
|
15
15
|
|
16
16
|
{ 'image' => 'library/mongo' }.merge(ports).merge(volumes)
|
17
17
|
end
|
@@ -30,16 +30,16 @@ module Orchestration
|
|
30
30
|
{ 'volumes' => ["#{@config.env.mongo_volume}:/data/db"] }
|
31
31
|
end
|
32
32
|
|
33
|
-
def local_port
|
34
|
-
@config.port.nil? ? remote_port : @config.port
|
35
|
-
end
|
36
|
-
|
37
33
|
def client
|
38
34
|
Services::Mong::Configuration::CONFIG_KEYS.each do |key|
|
39
35
|
return @config.settings.fetch(key) if @config.settings.key?(key)
|
40
36
|
end
|
41
37
|
end
|
42
38
|
|
39
|
+
def local_port
|
40
|
+
Orchestration.random_local_port
|
41
|
+
end
|
42
|
+
|
43
43
|
def remote_port
|
44
44
|
Orchestration::Services::Mongo::PORT
|
45
45
|
end
|
@@ -9,7 +9,7 @@ module Orchestration
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def definition
|
12
|
-
return nil
|
12
|
+
return nil unless @config.enabled?
|
13
13
|
|
14
14
|
{ 'image' => 'library/rabbitmq' }.merge(ports)
|
15
15
|
end
|
@@ -17,10 +17,9 @@ module Orchestration
|
|
17
17
|
def ports
|
18
18
|
return {} unless %i[development test].include?(@environment)
|
19
19
|
|
20
|
-
host_port = @config.settings.fetch('port', 5672)
|
21
20
|
container_port = Orchestration::Services::RabbitMQ::PORT
|
22
21
|
|
23
|
-
{ 'ports' => ["#{
|
22
|
+
{ 'ports' => ["#{Orchestration.random_local_port}:#{container_port}"] }
|
24
23
|
end
|
25
24
|
end
|
26
25
|
end
|
@@ -7,6 +7,7 @@ end
|
|
7
7
|
|
8
8
|
require 'orchestration/docker_compose/install_generator'
|
9
9
|
require 'orchestration/docker_compose/configuration'
|
10
|
+
require 'orchestration/docker_compose/compose_configuration'
|
10
11
|
|
11
12
|
require 'orchestration/docker_compose/app_service'
|
12
13
|
require 'orchestration/docker_compose/database_service'
|
@@ -12,10 +12,19 @@ module Orchestration
|
|
12
12
|
ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
|
13
13
|
end
|
14
14
|
|
15
|
+
def web_server
|
16
|
+
# Used at installation time only
|
17
|
+
ENV.fetch('server', 'puma')
|
18
|
+
end
|
19
|
+
|
15
20
|
def database_url
|
16
21
|
ENV['DATABASE_URL']
|
17
22
|
end
|
18
23
|
|
24
|
+
def mongo_url
|
25
|
+
ENV['MONGO_URL']
|
26
|
+
end
|
27
|
+
|
19
28
|
def mongoid_configuration_path
|
20
29
|
root.join('config', 'mongoid.yml')
|
21
30
|
end
|
@@ -61,6 +70,14 @@ module Orchestration
|
|
61
70
|
Rails.application.class.parent.name.underscore
|
62
71
|
end
|
63
72
|
|
73
|
+
def rabbitmq_url
|
74
|
+
ENV.fetch('RABBITMQ_URL', nil)
|
75
|
+
end
|
76
|
+
|
77
|
+
def app_port
|
78
|
+
ENV.fetch('CONTAINER_PORT', ENV.fetch('WEB_PORT', '3000')).to_i
|
79
|
+
end
|
80
|
+
|
64
81
|
def app_name
|
65
82
|
settings.get('docker.repository')
|
66
83
|
end
|
@@ -83,16 +100,12 @@ module Orchestration
|
|
83
100
|
'orchestration'
|
84
101
|
end
|
85
102
|
|
86
|
-
def public_volume
|
87
|
-
"#{app_name}_public"
|
88
|
-
end
|
89
|
-
|
90
103
|
def database_volume
|
91
|
-
|
104
|
+
'database'
|
92
105
|
end
|
93
106
|
|
94
107
|
def mongo_volume
|
95
|
-
|
108
|
+
'mongo'
|
96
109
|
end
|
97
110
|
end
|
98
111
|
end
|
data/lib/orchestration/errors.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module Orchestration
|
4
4
|
class OrchestrationError < StandardError; end
|
5
5
|
|
6
|
-
class
|
6
|
+
class HTTPConnectionError < OrchestrationError; end
|
7
7
|
class DatabaseConfigurationError < OrchestrationError; end
|
8
8
|
class MongoConfigurationError < OrchestrationError; end
|
9
9
|
|
@@ -30,7 +30,8 @@ module Orchestration
|
|
30
30
|
path.relative_path_from(@env.root).to_s
|
31
31
|
end
|
32
32
|
|
33
|
-
def simple_copy(template_name, dest, options = {})
|
33
|
+
def simple_copy(template_name, dest = nil, options = {})
|
34
|
+
dest ||= @env.orchestration_root.join(template_name)
|
34
35
|
update_file(
|
35
36
|
dest,
|
36
37
|
template(template_name, env: @env),
|
@@ -42,8 +43,10 @@ module Orchestration
|
|
42
43
|
relpath = relative_path(path)
|
43
44
|
overwrite = options.fetch(:overwrite, true)
|
44
45
|
present = File.exist?(path)
|
45
|
-
return @terminal.write(:skip, relpath) if present && !overwrite
|
46
|
+
return @terminal.write(:skip, relpath) if present && !overwrite && !force?
|
46
47
|
|
48
|
+
previous_content = File.read(path) if present
|
49
|
+
backup(path, previous_content) if options.fetch(:backup, false)
|
47
50
|
write_file(path, content)
|
48
51
|
@terminal.write(:create, relative_path(path))
|
49
52
|
end
|
@@ -52,14 +55,29 @@ module Orchestration
|
|
52
55
|
present = File.exist?(path)
|
53
56
|
return create_file(path, content) unless present
|
54
57
|
|
55
|
-
overwrite = options.fetch(:overwrite, true)
|
56
58
|
previous_content = File.read(path) if present
|
57
|
-
if present
|
59
|
+
if skip?(present, content, previous_content, options)
|
58
60
|
return @terminal.write(:skip, relative_path(path))
|
59
61
|
end
|
60
62
|
|
61
63
|
File.write(path, content)
|
62
64
|
@terminal.write(:update, relative_path(path))
|
65
|
+
|
66
|
+
backup(path, previous_content) if options.fetch(:backup, false)
|
67
|
+
end
|
68
|
+
|
69
|
+
def skip?(present, content, previous_content, options)
|
70
|
+
overwrite = options.fetch(:overwrite, true)
|
71
|
+
return false unless present
|
72
|
+
return true unless overwrite || force?
|
73
|
+
|
74
|
+
previous_content == content
|
75
|
+
end
|
76
|
+
|
77
|
+
def backup(path, previous_content)
|
78
|
+
backup_path = Pathname.new("#{path}.bak")
|
79
|
+
File.write(backup_path, previous_content)
|
80
|
+
@terminal.write(:backup, relative_path(backup_path))
|
63
81
|
end
|
64
82
|
|
65
83
|
def append_file(path, content, echo: true)
|
@@ -105,5 +123,10 @@ module Orchestration
|
|
105
123
|
FileUtils.mkdir_p(File.dirname(path))
|
106
124
|
File.write(path, content)
|
107
125
|
end
|
126
|
+
|
127
|
+
def force?
|
128
|
+
# Rake task was invoked with `force=yes`
|
129
|
+
ENV['force'] == 'yes'
|
130
|
+
end
|
108
131
|
end
|
109
132
|
end
|
@@ -4,6 +4,7 @@ require 'thor'
|
|
4
4
|
require 'tempfile'
|
5
5
|
|
6
6
|
module Orchestration
|
7
|
+
# rubocop:disable Metrics/ClassLength
|
7
8
|
class InstallGenerator < Thor::Group
|
8
9
|
include FileHelpers
|
9
10
|
|
@@ -20,7 +21,7 @@ module Orchestration
|
|
20
21
|
@terminal.ask_setting('docker.organization')
|
21
22
|
@terminal.ask_setting('docker.repository', @env.default_app_name)
|
22
23
|
relpath = relative_path(path)
|
23
|
-
return @terminal.write(:create, relpath) unless @settings.exist?
|
24
|
+
return @terminal.write(:create, relpath) unless @settings.exist? || force?
|
24
25
|
return @terminal.write(:update, relpath) if @settings.dirty?
|
25
26
|
|
26
27
|
@terminal.write(:skip, relpath)
|
@@ -39,10 +40,9 @@ module Orchestration
|
|
39
40
|
end
|
40
41
|
|
41
42
|
def dockerfile
|
42
|
-
content = template('Dockerfile', ruby_version: RUBY_VERSION)
|
43
43
|
create_file(
|
44
44
|
orchestration_dir.join('Dockerfile'),
|
45
|
-
|
45
|
+
dockerfile_content,
|
46
46
|
overwrite: false
|
47
47
|
)
|
48
48
|
end
|
@@ -64,14 +64,55 @@ module Orchestration
|
|
64
64
|
ensure_lines_in_file(path, entries)
|
65
65
|
end
|
66
66
|
|
67
|
+
def docker_compose
|
68
|
+
@docker_compose.docker_compose_yml
|
69
|
+
@docker_compose.docker_compose_test_yml
|
70
|
+
@docker_compose.docker_compose_development_yml
|
71
|
+
@docker_compose.docker_compose_local_yml
|
72
|
+
@docker_compose.docker_compose_production_yml
|
73
|
+
@docker_compose.docker_compose_override_yml
|
74
|
+
end
|
75
|
+
|
76
|
+
def puma
|
77
|
+
return nil unless @env.web_server == 'puma'
|
78
|
+
|
79
|
+
content = template('puma.rb')
|
80
|
+
path = @env.root.join('config', 'puma.rb')
|
81
|
+
create_file(path, content, backup: true)
|
82
|
+
end
|
83
|
+
|
67
84
|
def unicorn
|
85
|
+
return nil unless @env.web_server == 'unicorn'
|
86
|
+
|
68
87
|
content = template('unicorn.rb')
|
69
88
|
path = @env.root.join('config', 'unicorn.rb')
|
70
|
-
create_file(path, content,
|
89
|
+
create_file(path, content, backup: true)
|
90
|
+
end
|
91
|
+
|
92
|
+
def database_yml
|
93
|
+
return unless defined?(ActiveRecord)
|
94
|
+
|
95
|
+
service_config('database.yml', Services::Database::Configuration)
|
96
|
+
end
|
97
|
+
|
98
|
+
def mongoid_yml
|
99
|
+
return unless defined?(Mongoid)
|
100
|
+
|
101
|
+
service_config('mongoid.yml', Services::Mongo::Configuration)
|
102
|
+
end
|
103
|
+
|
104
|
+
def rabbitmq_yml
|
105
|
+
return unless defined?(Bunny)
|
106
|
+
|
107
|
+
service_config('rabbitmq.yml', Services::RabbitMQ::Configuration)
|
108
|
+
end
|
109
|
+
|
110
|
+
def healthcheck
|
111
|
+
simple_copy('healthcheck.rb')
|
71
112
|
end
|
72
113
|
|
73
114
|
def yaml_bash
|
74
|
-
simple_copy('yaml.bash'
|
115
|
+
simple_copy('yaml.bash')
|
75
116
|
end
|
76
117
|
|
77
118
|
def env
|
@@ -79,16 +120,7 @@ module Orchestration
|
|
79
120
|
end
|
80
121
|
|
81
122
|
def deploy_mk
|
82
|
-
simple_copy('deploy.mk'
|
83
|
-
end
|
84
|
-
|
85
|
-
def docker_compose
|
86
|
-
@docker_compose.docker_compose_yml
|
87
|
-
@docker_compose.docker_compose_test_yml
|
88
|
-
@docker_compose.docker_compose_development_yml
|
89
|
-
@docker_compose.docker_compose_local_yml
|
90
|
-
@docker_compose.docker_compose_production_yml
|
91
|
-
@docker_compose.docker_compose_override_yml
|
123
|
+
simple_copy('deploy.mk')
|
92
124
|
end
|
93
125
|
|
94
126
|
private
|
@@ -98,15 +130,48 @@ module Orchestration
|
|
98
130
|
end
|
99
131
|
|
100
132
|
def makefile_environment
|
101
|
-
|
133
|
+
macros = template('makefile_macros.mk', env: @env)
|
134
|
+
|
135
|
+
{ env: @env, services: enabled_services, macros: macros }
|
102
136
|
end
|
103
137
|
|
104
|
-
def
|
138
|
+
def enabled_services
|
105
139
|
%i[test development production].map do |environment|
|
106
|
-
@docker_compose.enabled_services(environment)
|
107
|
-
"wait-#{service}"
|
108
|
-
end
|
140
|
+
@docker_compose.enabled_services(environment)
|
109
141
|
end.flatten.uniq
|
110
142
|
end
|
143
|
+
|
144
|
+
def service_config(filename, config_class)
|
145
|
+
content = service_config_content(filename, config_class)
|
146
|
+
path = @env.root.join('config', filename)
|
147
|
+
if path.exist?
|
148
|
+
update_file(path, content, backup: true)
|
149
|
+
else
|
150
|
+
create_file(path, content)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def service_config_content(filename, config_class)
|
155
|
+
template(
|
156
|
+
filename,
|
157
|
+
config: config_class.new(@env),
|
158
|
+
compose: proc do |env|
|
159
|
+
DockerCompose::ComposeConfiguration.new(
|
160
|
+
Environment.new(environment: env)
|
161
|
+
)
|
162
|
+
end
|
163
|
+
)
|
164
|
+
end
|
165
|
+
|
166
|
+
def dockerfile_content
|
167
|
+
template(
|
168
|
+
'Dockerfile',
|
169
|
+
ruby_version: RUBY_VERSION,
|
170
|
+
command: DockerCompose::AppService.command,
|
171
|
+
entrypoint: DockerCompose::AppService.entrypoint,
|
172
|
+
healthcheck: DockerCompose::AppService.healthcheck
|
173
|
+
)
|
174
|
+
end
|
111
175
|
end
|
176
|
+
# rubocop:enable Metrics/ClassLength
|
112
177
|
end
|
@@ -8,6 +8,10 @@ module Orchestration
|
|
8
8
|
|
9
9
|
self.service_name = 'app'
|
10
10
|
|
11
|
+
def enabled?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
11
15
|
def initialize(env, service_name = nil)
|
12
16
|
super
|
13
17
|
@settings = {}
|
@@ -22,7 +26,7 @@ module Orchestration
|
|
22
26
|
end
|
23
27
|
|
24
28
|
def friendly_config
|
25
|
-
"[#{app_name}] #{host}:#{
|
29
|
+
"[#{app_name}] #{host}:#{port}"
|
26
30
|
end
|
27
31
|
|
28
32
|
def database_settings
|
@@ -40,14 +44,14 @@ module Orchestration
|
|
40
44
|
private
|
41
45
|
|
42
46
|
def build_database_url(settings)
|
43
|
-
|
47
|
+
adapter = settings.fetch('adapter')
|
44
48
|
database = settings.fetch('database')
|
45
49
|
username = settings.fetch('username')
|
46
50
|
password = settings.fetch('password')
|
47
|
-
port =
|
48
|
-
host = Database::Configuration.service_name
|
51
|
+
port = settings.fetch('port')
|
52
|
+
host = settings['host'] || Database::Configuration.service_name
|
49
53
|
|
50
|
-
"#{
|
54
|
+
"#{adapter}://#{username}:#{password}@#{host}:#{port}/#{database}"
|
51
55
|
end
|
52
56
|
end
|
53
57
|
end
|
@@ -5,28 +5,7 @@ module Orchestration
|
|
5
5
|
module App
|
6
6
|
class Healthcheck
|
7
7
|
include HealthcheckBase
|
8
|
-
|
9
|
-
def connect
|
10
|
-
response = Net::HTTP.get_response(
|
11
|
-
URI("http://localhost:#{@configuration.local_port}")
|
12
|
-
)
|
13
|
-
connection_error(response.code) if connection_error?(response.code)
|
14
|
-
end
|
15
|
-
|
16
|
-
def connection_errors
|
17
|
-
[Errno::ECONNREFUSED, AppConnectionError]
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def connection_error(code)
|
23
|
-
raise AppConnectionError,
|
24
|
-
I18n.t('orchestration.app.connection_error', code: code)
|
25
|
-
end
|
26
|
-
|
27
|
-
def connection_error?(code)
|
28
|
-
%w[502 503 500].include?(code)
|
29
|
-
end
|
8
|
+
include HTTPHealthcheck
|
30
9
|
end
|
31
10
|
end
|
32
11
|
end
|