mrsk 0.9.1 → 0.10.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/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
|