mrsk 0.9.0 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +158 -13
- data/lib/mrsk/cli/accessory.rb +87 -64
- data/lib/mrsk/cli/app.rb +103 -65
- data/lib/mrsk/cli/base.rb +46 -9
- data/lib/mrsk/cli/build.rb +40 -30
- data/lib/mrsk/cli/lock.rb +37 -0
- data/lib/mrsk/cli/main.rb +91 -49
- data/lib/mrsk/cli/prune.rb +14 -8
- data/lib/mrsk/cli/server.rb +9 -7
- data/lib/mrsk/cli/templates/deploy.yml +2 -0
- data/lib/mrsk/cli/traefik.rb +37 -21
- data/lib/mrsk/commander.rb +40 -34
- data/lib/mrsk/commands/accessory.rb +9 -6
- data/lib/mrsk/commands/app.rb +39 -37
- data/lib/mrsk/commands/auditor.rb +20 -5
- data/lib/mrsk/commands/base.rb +6 -4
- data/lib/mrsk/commands/builder/base.rb +1 -0
- data/lib/mrsk/commands/builder/native.rb +2 -1
- data/lib/mrsk/commands/healthcheck.rb +5 -3
- data/lib/mrsk/commands/lock.rb +63 -0
- data/lib/mrsk/commands/traefik.rb +13 -7
- data/lib/mrsk/configuration/accessory.rb +53 -7
- data/lib/mrsk/configuration/role.rb +13 -4
- data/lib/mrsk/configuration.rb +59 -17
- data/lib/mrsk/utils.rb +18 -2
- data/lib/mrsk/version.rb +1 -1
- data/lib/mrsk.rb +1 -0
- metadata +47 -3
data/lib/mrsk/commands/app.rb
CHANGED
@@ -1,13 +1,21 @@
|
|
1
1
|
class Mrsk::Commands::App < Mrsk::Commands::Base
|
2
|
-
|
3
|
-
|
2
|
+
attr_reader :role
|
3
|
+
|
4
|
+
def initialize(config, role: nil)
|
5
|
+
super(config)
|
6
|
+
@role = role
|
7
|
+
end
|
8
|
+
|
9
|
+
def run
|
10
|
+
role = config.role(self.role)
|
4
11
|
|
5
12
|
docker :run,
|
6
13
|
"--detach",
|
7
14
|
"--restart unless-stopped",
|
8
|
-
"--
|
9
|
-
"
|
15
|
+
"--name", container_name,
|
16
|
+
"-e", "MRSK_CONTAINER_NAME=\"#{container_name}\"",
|
10
17
|
*role.env_args,
|
18
|
+
*config.logging_args,
|
11
19
|
*config.volume_args,
|
12
20
|
*role.label_args,
|
13
21
|
*role.option_args,
|
@@ -16,17 +24,17 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|
16
24
|
end
|
17
25
|
|
18
26
|
def start
|
19
|
-
docker :start,
|
27
|
+
docker :start, container_name
|
20
28
|
end
|
21
29
|
|
22
30
|
def stop(version: nil)
|
23
31
|
pipe \
|
24
32
|
version ? container_id_for_version(version) : current_container_id,
|
25
|
-
xargs(docker(:stop))
|
33
|
+
xargs(config.stop_wait_time ? docker(:stop, "-t", config.stop_wait_time) : docker(:stop))
|
26
34
|
end
|
27
35
|
|
28
36
|
def info
|
29
|
-
docker :ps, *
|
37
|
+
docker :ps, *filter_args
|
30
38
|
end
|
31
39
|
|
32
40
|
|
@@ -51,7 +59,7 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|
51
59
|
def execute_in_existing_container(*command, interactive: false)
|
52
60
|
docker :exec,
|
53
61
|
("-it" if interactive),
|
54
|
-
|
62
|
+
container_name,
|
55
63
|
*command
|
56
64
|
end
|
57
65
|
|
@@ -75,32 +83,23 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|
75
83
|
|
76
84
|
|
77
85
|
def current_container_id
|
78
|
-
docker :ps, "--quiet", *
|
86
|
+
docker :ps, "--quiet", *filter_args
|
87
|
+
end
|
88
|
+
|
89
|
+
def container_id_for_version(version)
|
90
|
+
container_id_for(container_name: container_name(version))
|
79
91
|
end
|
80
92
|
|
81
93
|
def current_running_version
|
82
94
|
# FIXME: Find more graceful way to extract the version from "app-version" than using sed and tail!
|
83
95
|
pipe \
|
84
|
-
docker(:ps,
|
96
|
+
docker(:ps, *filter_args, "--format", '"{{.Names}}"'),
|
85
97
|
%(sed 's/-/\\n/g'),
|
86
98
|
"tail -n 1"
|
87
99
|
end
|
88
100
|
|
89
|
-
def most_recent_version_from_available_images
|
90
|
-
pipe \
|
91
|
-
docker(:image, :ls, "--format", '"{{.Tag}}"', config.repository),
|
92
|
-
"head -n 1"
|
93
|
-
end
|
94
|
-
|
95
|
-
def all_versions_from_available_containers
|
96
|
-
pipe \
|
97
|
-
docker(:image, :ls, "--format", '"{{.Tag}}"', config.repository),
|
98
|
-
"head -n 1"
|
99
|
-
end
|
100
|
-
|
101
|
-
|
102
101
|
def list_containers
|
103
|
-
docker :container, :ls, "--all", *
|
102
|
+
docker :container, :ls, "--all", *filter_args
|
104
103
|
end
|
105
104
|
|
106
105
|
def list_container_names
|
@@ -109,12 +108,16 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|
109
108
|
|
110
109
|
def remove_container(version:)
|
111
110
|
pipe \
|
112
|
-
container_id_for(container_name:
|
111
|
+
container_id_for(container_name: container_name(version)),
|
113
112
|
xargs(docker(:container, :rm))
|
114
113
|
end
|
115
114
|
|
115
|
+
def rename_container(version:, new_version:)
|
116
|
+
docker :rename, container_name(version), container_name(new_version)
|
117
|
+
end
|
118
|
+
|
116
119
|
def remove_containers
|
117
|
-
docker :container, :prune, "--force", *
|
120
|
+
docker :container, :prune, "--force", *filter_args
|
118
121
|
end
|
119
122
|
|
120
123
|
def list_images
|
@@ -122,24 +125,23 @@ class Mrsk::Commands::App < Mrsk::Commands::Base
|
|
122
125
|
end
|
123
126
|
|
124
127
|
def remove_images
|
125
|
-
docker :image, :prune, "--all", "--force", *
|
128
|
+
docker :image, :prune, "--all", "--force", *filter_args
|
126
129
|
end
|
127
130
|
|
128
131
|
|
129
132
|
private
|
130
|
-
def
|
131
|
-
|
132
|
-
"#{config.service}-#{version}"
|
133
|
-
else
|
134
|
-
config.service_with_version
|
135
|
-
end
|
133
|
+
def container_name(version = nil)
|
134
|
+
[ config.service, role, config.destination, version || config.version ].compact.join("-")
|
136
135
|
end
|
137
136
|
|
138
|
-
def
|
139
|
-
|
137
|
+
def filter_args
|
138
|
+
argumentize "--filter", filters
|
140
139
|
end
|
141
140
|
|
142
|
-
def
|
143
|
-
[ "
|
141
|
+
def filters
|
142
|
+
[ "label=service=#{config.service}" ].tap do |filters|
|
143
|
+
filters << "label=destination=#{config.destination}" if config.destination
|
144
|
+
filters << "label=role=#{role}" if role
|
145
|
+
end
|
144
146
|
end
|
145
147
|
end
|
@@ -1,6 +1,13 @@
|
|
1
1
|
require "active_support/core_ext/time/conversions"
|
2
2
|
|
3
3
|
class Mrsk::Commands::Auditor < Mrsk::Commands::Base
|
4
|
+
attr_reader :role
|
5
|
+
|
6
|
+
def initialize(config, role: nil)
|
7
|
+
super(config)
|
8
|
+
@role = role
|
9
|
+
end
|
10
|
+
|
4
11
|
# Runs remotely
|
5
12
|
def record(line)
|
6
13
|
append \
|
@@ -21,22 +28,30 @@ class Mrsk::Commands::Auditor < Mrsk::Commands::Base
|
|
21
28
|
|
22
29
|
private
|
23
30
|
def audit_log_file
|
24
|
-
"mrsk
|
31
|
+
[ "mrsk", config.service, config.destination, "audit.log" ].compact.join("-")
|
25
32
|
end
|
26
33
|
|
27
34
|
def tagged_record_line(line)
|
28
|
-
|
35
|
+
tagged_line recorded_at_tag, performer_tag, role_tag, line
|
29
36
|
end
|
30
37
|
|
31
38
|
def tagged_broadcast_line(line)
|
32
|
-
|
39
|
+
tagged_line performer_tag, role_tag, line
|
33
40
|
end
|
34
41
|
|
35
|
-
def
|
36
|
-
"
|
42
|
+
def tagged_line(*tags_and_line)
|
43
|
+
"'#{tags_and_line.compact.join(" ")}'"
|
37
44
|
end
|
38
45
|
|
39
46
|
def recorded_at_tag
|
40
47
|
"[#{Time.now.to_fs(:db)}]"
|
41
48
|
end
|
49
|
+
|
50
|
+
def performer_tag
|
51
|
+
"[#{`whoami`.strip}]"
|
52
|
+
end
|
53
|
+
|
54
|
+
def role_tag
|
55
|
+
"[#{role}]" if role
|
56
|
+
end
|
42
57
|
end
|
data/lib/mrsk/commands/base.rb
CHANGED
@@ -1,8 +1,6 @@
|
|
1
1
|
module Mrsk::Commands
|
2
2
|
class Base
|
3
|
-
delegate :redact, to: Mrsk::Utils
|
4
|
-
|
5
|
-
MAX_LOG_SIZE = "10m"
|
3
|
+
delegate :redact, :argumentize, to: Mrsk::Utils
|
6
4
|
|
7
5
|
attr_accessor :config
|
8
6
|
|
@@ -18,7 +16,7 @@ module Mrsk::Commands
|
|
18
16
|
end
|
19
17
|
|
20
18
|
def container_id_for(container_name:)
|
21
|
-
docker :container, :ls, "--all", "--filter", "name
|
19
|
+
docker :container, :ls, "--all", "--filter", "name=^#{container_name}$", "--quiet"
|
22
20
|
end
|
23
21
|
|
24
22
|
private
|
@@ -41,6 +39,10 @@ module Mrsk::Commands
|
|
41
39
|
combine *commands, by: ">>"
|
42
40
|
end
|
43
41
|
|
42
|
+
def write(*commands)
|
43
|
+
combine *commands, by: ">"
|
44
|
+
end
|
45
|
+
|
44
46
|
def xargs(command)
|
45
47
|
[ :xargs, command ].flatten
|
46
48
|
end
|
@@ -10,7 +10,8 @@ class Mrsk::Commands::Builder::Native < Mrsk::Commands::Builder::Base
|
|
10
10
|
def push
|
11
11
|
combine \
|
12
12
|
docker(:build, *build_options, build_context),
|
13
|
-
docker(:push, config.absolute_image)
|
13
|
+
docker(:push, config.absolute_image),
|
14
|
+
docker(:push, config.latest_image)
|
14
15
|
end
|
15
16
|
|
16
17
|
def info
|
@@ -9,8 +9,10 @@ class Mrsk::Commands::Healthcheck < Mrsk::Commands::Base
|
|
9
9
|
"--name", container_name_with_version,
|
10
10
|
"--publish", "#{EXPOSED_PORT}:#{config.healthcheck["port"]}",
|
11
11
|
"--label", "service=#{container_name}",
|
12
|
+
"-e", "MRSK_CONTAINER_NAME=\"#{container_name}\"",
|
12
13
|
*web.env_args,
|
13
14
|
*config.volume_args,
|
15
|
+
*web.option_args,
|
14
16
|
config.absolute_image,
|
15
17
|
web.cmd
|
16
18
|
end
|
@@ -33,15 +35,15 @@ class Mrsk::Commands::Healthcheck < Mrsk::Commands::Base
|
|
33
35
|
|
34
36
|
private
|
35
37
|
def container_name
|
36
|
-
"healthcheck
|
38
|
+
[ "healthcheck", config.service, config.destination ].compact.join("-")
|
37
39
|
end
|
38
40
|
|
39
41
|
def container_name_with_version
|
40
|
-
"
|
42
|
+
"#{container_name}-#{config.version}"
|
41
43
|
end
|
42
44
|
|
43
45
|
def container_id
|
44
|
-
container_id_for(container_name:
|
46
|
+
container_id_for(container_name: container_name_with_version)
|
45
47
|
end
|
46
48
|
|
47
49
|
def health_url
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require "active_support/duration"
|
2
|
+
require "active_support/core_ext/numeric/time"
|
3
|
+
|
4
|
+
class Mrsk::Commands::Lock < Mrsk::Commands::Base
|
5
|
+
def acquire(message, version)
|
6
|
+
combine \
|
7
|
+
[:mkdir, lock_dir],
|
8
|
+
write_lock_details(message, version)
|
9
|
+
end
|
10
|
+
|
11
|
+
def release
|
12
|
+
combine \
|
13
|
+
[:rm, lock_details_file],
|
14
|
+
[:rm, "-r", lock_dir]
|
15
|
+
end
|
16
|
+
|
17
|
+
def status
|
18
|
+
combine \
|
19
|
+
stat_lock_dir,
|
20
|
+
read_lock_details
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def write_lock_details(message, version)
|
25
|
+
write \
|
26
|
+
[:echo, "\"#{Base64.encode64(lock_details(message, version))}\""],
|
27
|
+
lock_details_file
|
28
|
+
end
|
29
|
+
|
30
|
+
def read_lock_details
|
31
|
+
pipe \
|
32
|
+
[:cat, lock_details_file],
|
33
|
+
[:base64, "-d"]
|
34
|
+
end
|
35
|
+
|
36
|
+
def stat_lock_dir
|
37
|
+
write \
|
38
|
+
[:stat, lock_dir],
|
39
|
+
"/dev/null"
|
40
|
+
end
|
41
|
+
|
42
|
+
def lock_dir
|
43
|
+
:mrsk_lock
|
44
|
+
end
|
45
|
+
|
46
|
+
def lock_details_file
|
47
|
+
[lock_dir, :details].join("/")
|
48
|
+
end
|
49
|
+
|
50
|
+
def lock_details(message, version)
|
51
|
+
<<~DETAILS.strip
|
52
|
+
Locked by: #{locked_by} at #{Time.now.gmtime}
|
53
|
+
Version: #{version}
|
54
|
+
Message: #{message}
|
55
|
+
DETAILS
|
56
|
+
end
|
57
|
+
|
58
|
+
def locked_by
|
59
|
+
`git config user.name`.strip
|
60
|
+
rescue Errno::ENOENT
|
61
|
+
"Unknown"
|
62
|
+
end
|
63
|
+
end
|
@@ -1,16 +1,18 @@
|
|
1
1
|
class Mrsk::Commands::Traefik < Mrsk::Commands::Base
|
2
2
|
delegate :optionize, to: Mrsk::Utils
|
3
3
|
|
4
|
+
IMAGE = "traefik:v2.9.9"
|
4
5
|
CONTAINER_PORT = 80
|
5
6
|
|
6
7
|
def run
|
7
8
|
docker :run, "--name traefik",
|
8
9
|
"--detach",
|
9
10
|
"--restart", "unless-stopped",
|
10
|
-
"--log-opt", "max-size=#{MAX_LOG_SIZE}",
|
11
11
|
"--publish", port,
|
12
12
|
"--volume", "/var/run/docker.sock:/var/run/docker.sock",
|
13
|
-
|
13
|
+
*config.logging_args,
|
14
|
+
*docker_options_args,
|
15
|
+
IMAGE,
|
14
16
|
"--providers.docker",
|
15
17
|
"--log.level=DEBUG",
|
16
18
|
*cmd_option_args
|
@@ -25,7 +27,7 @@ class Mrsk::Commands::Traefik < Mrsk::Commands::Base
|
|
25
27
|
end
|
26
28
|
|
27
29
|
def info
|
28
|
-
docker :ps, "--filter", "name
|
30
|
+
docker :ps, "--filter", "name=^traefik$"
|
29
31
|
end
|
30
32
|
|
31
33
|
def logs(since: nil, lines: nil, grep: nil)
|
@@ -49,20 +51,24 @@ class Mrsk::Commands::Traefik < Mrsk::Commands::Base
|
|
49
51
|
docker :image, :prune, "--all", "--force", "--filter", "label=org.opencontainers.image.title=Traefik"
|
50
52
|
end
|
51
53
|
|
52
|
-
def port
|
54
|
+
def port
|
53
55
|
"#{host_port}:#{CONTAINER_PORT}"
|
54
56
|
end
|
55
57
|
|
56
58
|
private
|
59
|
+
def docker_options_args
|
60
|
+
optionize(config.traefik["options"] || {})
|
61
|
+
end
|
62
|
+
|
57
63
|
def cmd_option_args
|
58
|
-
if args = config.
|
59
|
-
optionize args
|
64
|
+
if args = config.traefik["args"]
|
65
|
+
optionize args, with: "="
|
60
66
|
else
|
61
67
|
[]
|
62
68
|
end
|
63
69
|
end
|
64
70
|
|
65
71
|
def host_port
|
66
|
-
config.
|
72
|
+
config.traefik["host_port"] || CONTAINER_PORT
|
67
73
|
end
|
68
74
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
class Mrsk::Configuration::Accessory
|
2
|
-
delegate :argumentize, :argumentize_env_with_secrets, to: Mrsk::Utils
|
2
|
+
delegate :argumentize, :argumentize_env_with_secrets, :optionize, to: Mrsk::Utils
|
3
3
|
|
4
4
|
attr_accessor :name, :specifics
|
5
5
|
|
@@ -15,18 +15,24 @@ class Mrsk::Configuration::Accessory
|
|
15
15
|
specifics["image"]
|
16
16
|
end
|
17
17
|
|
18
|
-
def
|
19
|
-
specifics["host"
|
18
|
+
def hosts
|
19
|
+
if (specifics.keys & ["host", "hosts", "roles"]).size != 1
|
20
|
+
raise ArgumentError, "Specify one of `host`, `hosts` or `roles` for accessory `#{name}`"
|
21
|
+
end
|
22
|
+
|
23
|
+
hosts_from_host || hosts_from_hosts || hosts_from_roles
|
20
24
|
end
|
21
25
|
|
22
26
|
def port
|
23
|
-
if specifics["port"]
|
24
|
-
|
25
|
-
else
|
26
|
-
"#{specifics["port"]}:#{specifics["port"]}"
|
27
|
+
if port = specifics["port"]&.to_s
|
28
|
+
port.include?(":") ? port : "#{port}:#{port}"
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
32
|
+
def publish_args
|
33
|
+
argumentize "--publish", port if port
|
34
|
+
end
|
35
|
+
|
30
36
|
def labels
|
31
37
|
default_labels.merge(specifics["labels"] || {})
|
32
38
|
end
|
@@ -65,6 +71,18 @@ class Mrsk::Configuration::Accessory
|
|
65
71
|
argumentize "--volume", volumes
|
66
72
|
end
|
67
73
|
|
74
|
+
def option_args
|
75
|
+
if args = specifics["options"]
|
76
|
+
optionize args
|
77
|
+
else
|
78
|
+
[]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def cmd
|
83
|
+
specifics["cmd"]
|
84
|
+
end
|
85
|
+
|
68
86
|
private
|
69
87
|
attr_accessor :config
|
70
88
|
|
@@ -120,4 +138,32 @@ class Mrsk::Configuration::Accessory
|
|
120
138
|
def service_data_directory
|
121
139
|
"$PWD/#{service_name}"
|
122
140
|
end
|
141
|
+
|
142
|
+
def hosts_from_host
|
143
|
+
if specifics.key?("host")
|
144
|
+
host = specifics["host"]
|
145
|
+
if host
|
146
|
+
[host]
|
147
|
+
else
|
148
|
+
raise ArgumentError, "Missing host for accessory `#{name}`"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def hosts_from_hosts
|
154
|
+
if specifics.key?("hosts")
|
155
|
+
hosts = specifics["hosts"]
|
156
|
+
if hosts.is_a?(Array)
|
157
|
+
hosts
|
158
|
+
else
|
159
|
+
raise ArgumentError, "Hosts should be an Array for accessory `#{name}`"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def hosts_from_roles
|
165
|
+
if specifics.key?("roles")
|
166
|
+
specifics["roles"].flat_map { |role| config.role(role).hosts }
|
167
|
+
end
|
168
|
+
end
|
123
169
|
end
|
@@ -7,6 +7,10 @@ class Mrsk::Configuration::Role
|
|
7
7
|
@name, @config = name.inquiry, config
|
8
8
|
end
|
9
9
|
|
10
|
+
def primary_host
|
11
|
+
hosts.first
|
12
|
+
end
|
13
|
+
|
10
14
|
def hosts
|
11
15
|
@hosts ||= extract_hosts_from_config
|
12
16
|
end
|
@@ -55,12 +59,16 @@ class Mrsk::Configuration::Role
|
|
55
59
|
config.servers
|
56
60
|
else
|
57
61
|
servers = config.servers[name]
|
58
|
-
servers.is_a?(Array) ? servers : servers["hosts"]
|
62
|
+
servers.is_a?(Array) ? servers : Array(servers["hosts"])
|
59
63
|
end
|
60
64
|
end
|
61
65
|
|
62
66
|
def default_labels
|
63
|
-
|
67
|
+
if config.destination
|
68
|
+
{ "service" => config.service, "role" => name, "destination" => config.destination }
|
69
|
+
else
|
70
|
+
{ "service" => config.service, "role" => name }
|
71
|
+
end
|
64
72
|
end
|
65
73
|
|
66
74
|
def traefik_labels
|
@@ -69,8 +77,9 @@ class Mrsk::Configuration::Role
|
|
69
77
|
"traefik.http.routers.#{config.service}.rule" => "PathPrefix(`/`)",
|
70
78
|
"traefik.http.services.#{config.service}.loadbalancer.healthcheck.path" => config.healthcheck["path"],
|
71
79
|
"traefik.http.services.#{config.service}.loadbalancer.healthcheck.interval" => "1s",
|
72
|
-
"traefik.http.middlewares.#{config.service}.retry.attempts" => "5",
|
73
|
-
"traefik.http.middlewares.#{config.service}.retry.initialinterval" => "500ms"
|
80
|
+
"traefik.http.middlewares.#{config.service}-retry.retry.attempts" => "5",
|
81
|
+
"traefik.http.middlewares.#{config.service}-retry.retry.initialinterval" => "500ms",
|
82
|
+
"traefik.http.routers.#{config.service}.middlewares" => "#{config.service}-retry@docker"
|
74
83
|
}
|
75
84
|
else
|
76
85
|
{}
|
data/lib/mrsk/configuration.rb
CHANGED
@@ -6,23 +6,24 @@ require "erb"
|
|
6
6
|
require "net/ssh/proxy/jump"
|
7
7
|
|
8
8
|
class Mrsk::Configuration
|
9
|
-
delegate :service, :image, :servers, :env, :labels, :registry, :builder, to: :raw_config, allow_nil: true
|
10
|
-
delegate :argumentize, :argumentize_env_with_secrets, to: Mrsk::Utils
|
9
|
+
delegate :service, :image, :servers, :env, :labels, :registry, :builder, :stop_wait_time, to: :raw_config, allow_nil: true
|
10
|
+
delegate :argumentize, :argumentize_env_with_secrets, :optionize, to: Mrsk::Utils
|
11
11
|
|
12
|
-
attr_accessor :
|
12
|
+
attr_accessor :destination
|
13
13
|
attr_accessor :raw_config
|
14
14
|
|
15
15
|
class << self
|
16
|
-
def create_from(
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
load_config_file destination_config_file(base_config_file, destination)
|
21
|
-
end
|
22
|
-
end, version: version)
|
16
|
+
def create_from(config_file:, destination: nil, version: nil)
|
17
|
+
raw_config = load_config_files(config_file, *destination_config_file(config_file, destination))
|
18
|
+
|
19
|
+
new raw_config, destination: destination, version: version
|
23
20
|
end
|
24
21
|
|
25
22
|
private
|
23
|
+
def load_config_files(*files)
|
24
|
+
files.inject({}) { |config, file| config.deep_merge! load_config_file(file) }
|
25
|
+
end
|
26
|
+
|
26
27
|
def load_config_file(file)
|
27
28
|
if file.exist?
|
28
29
|
YAML.load(ERB.new(IO.read(file)).result).symbolize_keys
|
@@ -32,18 +33,31 @@ class Mrsk::Configuration
|
|
32
33
|
end
|
33
34
|
|
34
35
|
def destination_config_file(base_config_file, destination)
|
35
|
-
|
36
|
-
dir.join basename.to_s.remove(".yml") + ".#{destination}.yml"
|
36
|
+
base_config_file.sub_ext(".#{destination}.yml") if destination
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
def initialize(raw_config, version:
|
40
|
+
def initialize(raw_config, destination: nil, version: nil, validate: true)
|
41
41
|
@raw_config = ActiveSupport::InheritableOptions.new(raw_config)
|
42
|
-
@
|
42
|
+
@destination = destination
|
43
|
+
@declared_version = version
|
43
44
|
valid? if validate
|
44
45
|
end
|
45
46
|
|
46
47
|
|
48
|
+
def version=(version)
|
49
|
+
@declared_version = version
|
50
|
+
end
|
51
|
+
|
52
|
+
def version
|
53
|
+
@declared_version.presence || ENV["VERSION"] || current_commit_hash
|
54
|
+
end
|
55
|
+
|
56
|
+
def abbreviated_version
|
57
|
+
Mrsk::Utils.abbreviate_version(version)
|
58
|
+
end
|
59
|
+
|
60
|
+
|
47
61
|
def roles
|
48
62
|
@roles ||= role_names.collect { |role_name| Role.new(role_name, config: self) }
|
49
63
|
end
|
@@ -62,15 +76,15 @@ class Mrsk::Configuration
|
|
62
76
|
|
63
77
|
|
64
78
|
def all_hosts
|
65
|
-
roles.flat_map(&:hosts)
|
79
|
+
roles.flat_map(&:hosts).uniq
|
66
80
|
end
|
67
81
|
|
68
82
|
def primary_web_host
|
69
|
-
role(:web).
|
83
|
+
role(:web).primary_host
|
70
84
|
end
|
71
85
|
|
72
86
|
def traefik_hosts
|
73
|
-
roles.select(&:running_traefik?).flat_map(&:hosts)
|
87
|
+
roles.select(&:running_traefik?).flat_map(&:hosts).uniq
|
74
88
|
end
|
75
89
|
|
76
90
|
|
@@ -107,6 +121,15 @@ class Mrsk::Configuration
|
|
107
121
|
end
|
108
122
|
end
|
109
123
|
|
124
|
+
def logging_args
|
125
|
+
if raw_config.logging.present?
|
126
|
+
optionize({ "log-driver" => raw_config.logging["driver"] }.compact) +
|
127
|
+
argumentize("--log-opt", raw_config.logging["options"])
|
128
|
+
else
|
129
|
+
argumentize("--log-opt", { "max-size" => "10m" })
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
110
133
|
|
111
134
|
def ssh_user
|
112
135
|
if raw_config.ssh.present?
|
@@ -159,10 +182,14 @@ class Mrsk::Configuration
|
|
159
182
|
ssh_options: ssh_options,
|
160
183
|
builder: raw_config.builder,
|
161
184
|
accessories: raw_config.accessories,
|
185
|
+
logging: logging_args,
|
162
186
|
healthcheck: healthcheck
|
163
187
|
}.compact
|
164
188
|
end
|
165
189
|
|
190
|
+
def traefik
|
191
|
+
raw_config.traefik || {}
|
192
|
+
end
|
166
193
|
|
167
194
|
private
|
168
195
|
# Will raise ArgumentError if any required config keys are missing
|
@@ -179,6 +206,12 @@ class Mrsk::Configuration
|
|
179
206
|
raise ArgumentError, "You must specify a password for the registry in config/deploy.yml (or set the ENV variable if that's used)"
|
180
207
|
end
|
181
208
|
|
209
|
+
roles.each do |role|
|
210
|
+
if role.hosts.empty?
|
211
|
+
raise ArgumentError, "No servers specified for the #{role.name} role"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
182
215
|
true
|
183
216
|
end
|
184
217
|
|
@@ -193,4 +226,13 @@ class Mrsk::Configuration
|
|
193
226
|
def role_names
|
194
227
|
raw_config.servers.is_a?(Array) ? [ "web" ] : raw_config.servers.keys.sort
|
195
228
|
end
|
229
|
+
|
230
|
+
def current_commit_hash
|
231
|
+
@current_commit_hash ||=
|
232
|
+
if system("git rev-parse")
|
233
|
+
`git rev-parse HEAD`.strip
|
234
|
+
else
|
235
|
+
raise "Can't use commit hash as version, no git repository found in #{Dir.pwd}"
|
236
|
+
end
|
237
|
+
end
|
196
238
|
end
|