kamal 1.3.1 → 1.5.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/lib/kamal/cli/accessory.rb +38 -29
- data/lib/kamal/cli/app/boot.rb +67 -0
- data/lib/kamal/cli/app/prepare_assets.rb +24 -0
- data/lib/kamal/cli/app.rb +25 -67
- data/lib/kamal/cli/base.rb +23 -8
- data/lib/kamal/cli/env.rb +3 -5
- data/lib/kamal/cli/main.rb +7 -4
- data/lib/kamal/cli/prune.rb +6 -2
- data/lib/kamal/cli/server.rb +3 -1
- data/lib/kamal/cli/templates/deploy.yml +5 -1
- data/lib/kamal/cli/templates/sample_hooks/docker-setup.sample +7 -0
- data/lib/kamal/cli/traefik.rb +16 -13
- data/lib/kamal/commander/specifics.rb +49 -0
- data/lib/kamal/commander.rb +9 -33
- data/lib/kamal/commands/accessory.rb +2 -2
- data/lib/kamal/commands/app/assets.rb +12 -12
- data/lib/kamal/commands/app/cord.rb +4 -4
- data/lib/kamal/commands/app/execution.rb +10 -8
- data/lib/kamal/commands/app/images.rb +1 -1
- data/lib/kamal/commands/app/logging.rb +2 -2
- data/lib/kamal/commands/app.rb +38 -18
- data/lib/kamal/commands/auditor.rb +1 -1
- data/lib/kamal/commands/base.rb +12 -0
- data/lib/kamal/commands/builder/base.rb +22 -5
- data/lib/kamal/commands/builder/multiarch.rb +17 -9
- data/lib/kamal/commands/builder/native/cached.rb +7 -6
- data/lib/kamal/commands/builder/native/remote.rb +9 -9
- data/lib/kamal/commands/builder/native.rb +8 -7
- data/lib/kamal/commands/docker.rb +10 -1
- data/lib/kamal/commands/healthcheck.rb +0 -1
- data/lib/kamal/commands/hook.rb +1 -1
- data/lib/kamal/commands/lock.rb +19 -9
- data/lib/kamal/commands/prune.rb +4 -4
- data/lib/kamal/commands/registry.rb +4 -1
- data/lib/kamal/commands/server.rb +1 -1
- data/lib/kamal/commands/traefik.rb +10 -16
- data/lib/kamal/configuration/accessory.rb +10 -20
- data/lib/kamal/configuration/boot.rb +1 -1
- data/lib/kamal/configuration/builder.rb +11 -3
- data/lib/kamal/configuration/env.rb +40 -0
- data/lib/kamal/configuration/role.rb +23 -40
- data/lib/kamal/configuration.rb +53 -21
- data/lib/kamal/env_file.rb +12 -15
- data/lib/kamal/sshkit_with_ext.rb +1 -0
- data/lib/kamal/utils.rb +7 -3
- data/lib/kamal/version.rb +1 -1
- data/lib/kamal.rb +1 -1
- metadata +8 -3
@@ -1,7 +1,7 @@
|
|
1
1
|
class Kamal::Commands::Docker < Kamal::Commands::Base
|
2
2
|
# Install Docker using the https://github.com/docker/docker-install convenience script.
|
3
3
|
def install
|
4
|
-
pipe
|
4
|
+
pipe get_docker, :sh
|
5
5
|
end
|
6
6
|
|
7
7
|
# Checks the Docker client version. Fails if Docker is not installed.
|
@@ -18,4 +18,13 @@ class Kamal::Commands::Docker < Kamal::Commands::Base
|
|
18
18
|
def superuser?
|
19
19
|
[ '[ "${EUID:-$(id -u)}" -eq 0 ] || command -v sudo >/dev/null || command -v su >/dev/null' ]
|
20
20
|
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def get_docker
|
24
|
+
shell \
|
25
|
+
any \
|
26
|
+
[ :curl, "-fsSL", "https://get.docker.com" ],
|
27
|
+
[ :wget, "-O -", "https://get.docker.com" ],
|
28
|
+
[ :echo, "\"exit 1\"" ]
|
29
|
+
end
|
21
30
|
end
|
data/lib/kamal/commands/hook.rb
CHANGED
data/lib/kamal/commands/lock.rb
CHANGED
@@ -5,14 +5,14 @@ require "base64"
|
|
5
5
|
class Kamal::Commands::Lock < Kamal::Commands::Base
|
6
6
|
def acquire(message, version)
|
7
7
|
combine \
|
8
|
-
[:mkdir, lock_dir],
|
8
|
+
[ :mkdir, lock_dir ],
|
9
9
|
write_lock_details(message, version)
|
10
10
|
end
|
11
11
|
|
12
12
|
def release
|
13
13
|
combine \
|
14
|
-
[:rm, lock_details_file],
|
15
|
-
[:rm, "-r", lock_dir]
|
14
|
+
[ :rm, lock_details_file ],
|
15
|
+
[ :rm, "-r", lock_dir ]
|
16
16
|
end
|
17
17
|
|
18
18
|
def status
|
@@ -21,31 +21,41 @@ class Kamal::Commands::Lock < Kamal::Commands::Base
|
|
21
21
|
read_lock_details
|
22
22
|
end
|
23
23
|
|
24
|
+
def ensure_locks_directory
|
25
|
+
[ :mkdir, "-p", locks_dir ]
|
26
|
+
end
|
27
|
+
|
24
28
|
private
|
25
29
|
def write_lock_details(message, version)
|
26
30
|
write \
|
27
|
-
[:echo, "\"#{Base64.encode64(lock_details(message, version))}\""],
|
31
|
+
[ :echo, "\"#{Base64.encode64(lock_details(message, version))}\"" ],
|
28
32
|
lock_details_file
|
29
33
|
end
|
30
34
|
|
31
35
|
def read_lock_details
|
32
36
|
pipe \
|
33
|
-
[:cat, lock_details_file],
|
34
|
-
[:base64, "-d"]
|
37
|
+
[ :cat, lock_details_file ],
|
38
|
+
[ :base64, "-d" ]
|
35
39
|
end
|
36
40
|
|
37
41
|
def stat_lock_dir
|
38
42
|
write \
|
39
|
-
[:stat, lock_dir],
|
43
|
+
[ :stat, lock_dir ],
|
40
44
|
"/dev/null"
|
41
45
|
end
|
42
46
|
|
47
|
+
def locks_dir
|
48
|
+
File.join(config.run_directory, "locks")
|
49
|
+
end
|
50
|
+
|
43
51
|
def lock_dir
|
44
|
-
|
52
|
+
dir_name = [ config.service, config.destination ].compact.join("-")
|
53
|
+
|
54
|
+
File.join(locks_dir, dir_name)
|
45
55
|
end
|
46
56
|
|
47
57
|
def lock_details_file
|
48
|
-
|
58
|
+
File.join(lock_dir, "details")
|
49
59
|
end
|
50
60
|
|
51
61
|
def lock_details(message, version)
|
data/lib/kamal/commands/prune.rb
CHANGED
@@ -13,10 +13,10 @@ class Kamal::Commands::Prune < Kamal::Commands::Base
|
|
13
13
|
"while read image tag; do docker rmi $tag; done"
|
14
14
|
end
|
15
15
|
|
16
|
-
def app_containers(
|
16
|
+
def app_containers(retain:)
|
17
17
|
pipe \
|
18
18
|
docker(:ps, "-q", "-a", *service_filter, *stopped_containers_filters),
|
19
|
-
"tail -n +#{
|
19
|
+
"tail -n +#{retain + 1}",
|
20
20
|
"while read container_id; do docker rm $container_id; done"
|
21
21
|
end
|
22
22
|
|
@@ -26,7 +26,7 @@ class Kamal::Commands::Prune < Kamal::Commands::Base
|
|
26
26
|
|
27
27
|
private
|
28
28
|
def stopped_containers_filters
|
29
|
-
[ "created", "exited", "dead" ].flat_map { |status| ["--filter", "status=#{status}"] }
|
29
|
+
[ "created", "exited", "dead" ].flat_map { |status| [ "--filter", "status=#{status}" ] }
|
30
30
|
end
|
31
31
|
|
32
32
|
def active_image_list
|
@@ -43,4 +43,4 @@ class Kamal::Commands::Prune < Kamal::Commands::Base
|
|
43
43
|
def healthcheck_service_filter
|
44
44
|
[ "--filter", "label=service=#{config.healthcheck_service}" ]
|
45
45
|
end
|
46
|
-
|
46
|
+
end
|
@@ -2,7 +2,10 @@ class Kamal::Commands::Registry < Kamal::Commands::Base
|
|
2
2
|
delegate :registry, to: :config
|
3
3
|
|
4
4
|
def login
|
5
|
-
docker :login,
|
5
|
+
docker :login,
|
6
|
+
registry["server"],
|
7
|
+
"-u", sensitive(Kamal::Utils.escape_shell_value(lookup("username"))),
|
8
|
+
"-p", sensitive(Kamal::Utils.escape_shell_value(lookup("password")))
|
6
9
|
end
|
7
10
|
|
8
11
|
def logout
|
@@ -1,10 +1,10 @@
|
|
1
1
|
class Kamal::Commands::Traefik < Kamal::Commands::Base
|
2
2
|
delegate :argumentize, :optionize, to: Kamal::Utils
|
3
3
|
|
4
|
-
DEFAULT_IMAGE = "traefik:v2.
|
4
|
+
DEFAULT_IMAGE = "traefik:v2.10"
|
5
5
|
CONTAINER_PORT = 80
|
6
6
|
DEFAULT_ARGS = {
|
7
|
-
|
7
|
+
"log.level" => "DEBUG"
|
8
8
|
}
|
9
9
|
DEFAULT_LABELS = {
|
10
10
|
# These ensure we serve a 502 rather than a 404 if no containers are available
|
@@ -39,7 +39,7 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def start_or_run
|
42
|
-
|
42
|
+
any start, run
|
43
43
|
end
|
44
44
|
|
45
45
|
def info
|
@@ -71,20 +71,18 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
|
|
71
71
|
"#{host_port}:#{CONTAINER_PORT}"
|
72
72
|
end
|
73
73
|
|
74
|
-
def
|
75
|
-
Kamal::
|
76
|
-
|
77
|
-
|
78
|
-
def host_env_file_path
|
79
|
-
File.join host_env_directory, "traefik.env"
|
74
|
+
def env
|
75
|
+
Kamal::Configuration::Env.from_config \
|
76
|
+
config: config.traefik.fetch("env", {}),
|
77
|
+
secrets_file: File.join(config.host_env_directory, "traefik", "traefik.env")
|
80
78
|
end
|
81
79
|
|
82
80
|
def make_env_directory
|
83
|
-
make_directory(
|
81
|
+
make_directory(env.secrets_directory)
|
84
82
|
end
|
85
83
|
|
86
84
|
def remove_env_file
|
87
|
-
[:rm, "-f",
|
85
|
+
[ :rm, "-f", env.secrets_file ]
|
88
86
|
end
|
89
87
|
|
90
88
|
private
|
@@ -97,11 +95,7 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
|
|
97
95
|
end
|
98
96
|
|
99
97
|
def env_args
|
100
|
-
|
101
|
-
end
|
102
|
-
|
103
|
-
def host_env_directory
|
104
|
-
File.join config.host_env_directory, "traefik"
|
98
|
+
env.args
|
105
99
|
end
|
106
100
|
|
107
101
|
def labels
|
@@ -8,7 +8,7 @@ class Kamal::Configuration::Accessory
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def service_name
|
11
|
-
"#{config.service}-#{name}"
|
11
|
+
specifics["service"] || "#{config.service}-#{name}"
|
12
12
|
end
|
13
13
|
|
14
14
|
def image
|
@@ -16,7 +16,7 @@ class Kamal::Configuration::Accessory
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def hosts
|
19
|
-
if (specifics.keys & ["host", "hosts", "roles"]).size != 1
|
19
|
+
if (specifics.keys & [ "host", "hosts", "roles" ]).size != 1
|
20
20
|
raise ArgumentError, "Specify one of `host`, `hosts` or `roles` for accessory `#{name}`"
|
21
21
|
end
|
22
22
|
|
@@ -42,23 +42,13 @@ class Kamal::Configuration::Accessory
|
|
42
42
|
end
|
43
43
|
|
44
44
|
def env
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
def env_file
|
49
|
-
Kamal::EnvFile.new(env)
|
50
|
-
end
|
51
|
-
|
52
|
-
def host_env_directory
|
53
|
-
File.join config.host_env_directory, "accessories"
|
54
|
-
end
|
55
|
-
|
56
|
-
def host_env_file_path
|
57
|
-
File.join host_env_directory, "#{service_name}.env"
|
45
|
+
Kamal::Configuration::Env.from_config \
|
46
|
+
config: specifics.fetch("env", {}),
|
47
|
+
secrets_file: File.join(config.host_env_directory, "accessories", "#{service_name}.env")
|
58
48
|
end
|
59
49
|
|
60
50
|
def env_args
|
61
|
-
|
51
|
+
env.args
|
62
52
|
end
|
63
53
|
|
64
54
|
def files
|
@@ -111,10 +101,10 @@ class Kamal::Configuration::Accessory
|
|
111
101
|
end
|
112
102
|
|
113
103
|
def with_clear_env_loaded
|
114
|
-
|
104
|
+
env.clear.each { |k, v| ENV[k] = v }
|
115
105
|
yield
|
116
106
|
ensure
|
117
|
-
|
107
|
+
env.clear.each { |k, v| ENV.delete(k) }
|
118
108
|
end
|
119
109
|
|
120
110
|
def read_dynamic_file(local_file)
|
@@ -144,7 +134,7 @@ class Kamal::Configuration::Accessory
|
|
144
134
|
end
|
145
135
|
|
146
136
|
def expand_host_path(host_path)
|
147
|
-
absolute_path?(host_path) ? host_path :
|
137
|
+
absolute_path?(host_path) ? host_path : File.join(service_data_directory, host_path)
|
148
138
|
end
|
149
139
|
|
150
140
|
def absolute_path?(path)
|
@@ -159,7 +149,7 @@ class Kamal::Configuration::Accessory
|
|
159
149
|
if specifics.key?("host")
|
160
150
|
host = specifics["host"]
|
161
151
|
if host
|
162
|
-
[host]
|
152
|
+
[ host ]
|
163
153
|
else
|
164
154
|
raise ArgumentError, "Missing host for accessory `#{name}`"
|
165
155
|
end
|
@@ -40,7 +40,7 @@ class Kamal::Configuration::Builder
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def context
|
43
|
-
@options["context"] || "."
|
43
|
+
@options["context"] || (git_archive? ? "-" : ".")
|
44
44
|
end
|
45
45
|
|
46
46
|
def local_arch
|
@@ -81,10 +81,18 @@ class Kamal::Configuration::Builder
|
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
84
|
+
def ssh
|
85
|
+
@options["ssh"]
|
86
|
+
end
|
87
|
+
|
88
|
+
def git_archive?
|
89
|
+
Kamal::Git.used? && @options["context"].nil?
|
90
|
+
end
|
91
|
+
|
84
92
|
private
|
85
93
|
def valid?
|
86
94
|
if @options["cache"] && @options["cache"]["type"]
|
87
|
-
raise ArgumentError, "Invalid cache type: #{@options["cache"]["type"]}" unless ["gha", "registry"].include?(@options["cache"]["type"])
|
95
|
+
raise ArgumentError, "Invalid cache type: #{@options["cache"]["type"]}" unless [ "gha", "registry" ].include?(@options["cache"]["type"])
|
88
96
|
end
|
89
97
|
end
|
90
98
|
|
@@ -105,7 +113,7 @@ class Kamal::Configuration::Builder
|
|
105
113
|
end
|
106
114
|
|
107
115
|
def cache_to_config_for_gha
|
108
|
-
[ "type=gha", @options["cache"]&.fetch("options", nil)].compact.join(",")
|
116
|
+
[ "type=gha", @options["cache"]&.fetch("options", nil) ].compact.join(",")
|
109
117
|
end
|
110
118
|
|
111
119
|
def cache_to_config_for_registry
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Kamal::Configuration::Env
|
2
|
+
attr_reader :secrets_keys, :clear, :secrets_file
|
3
|
+
delegate :argumentize, to: Kamal::Utils
|
4
|
+
|
5
|
+
def self.from_config(config:, secrets_file: nil)
|
6
|
+
secrets_keys = config.fetch("secret", [])
|
7
|
+
clear = config.fetch("clear", config.key?("secret") ? {} : config)
|
8
|
+
|
9
|
+
new clear: clear, secrets_keys: secrets_keys, secrets_file: secrets_file
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(clear:, secrets_keys:, secrets_file:)
|
13
|
+
@clear = clear
|
14
|
+
@secrets_keys = secrets_keys
|
15
|
+
@secrets_file = secrets_file
|
16
|
+
end
|
17
|
+
|
18
|
+
def args
|
19
|
+
[ "--env-file", secrets_file, *argumentize("--env", clear) ]
|
20
|
+
end
|
21
|
+
|
22
|
+
def secrets_io
|
23
|
+
StringIO.new(Kamal::EnvFile.new(secrets).to_s)
|
24
|
+
end
|
25
|
+
|
26
|
+
def secrets
|
27
|
+
@secrets ||= secrets_keys.to_h { |key| [ key, ENV.fetch(key) ] }
|
28
|
+
end
|
29
|
+
|
30
|
+
def secrets_directory
|
31
|
+
File.dirname(secrets_file)
|
32
|
+
end
|
33
|
+
|
34
|
+
def merge(other)
|
35
|
+
self.class.new \
|
36
|
+
clear: @clear.merge(other.clear),
|
37
|
+
secrets_keys: @secrets_keys | other.secrets_keys,
|
38
|
+
secrets_file: secrets_file
|
39
|
+
end
|
40
|
+
end
|
@@ -3,9 +3,10 @@ class Kamal::Configuration::Role
|
|
3
3
|
delegate :argumentize, :optionize, to: Kamal::Utils
|
4
4
|
|
5
5
|
attr_accessor :name
|
6
|
+
alias to_s name
|
6
7
|
|
7
8
|
def initialize(name, config:)
|
8
|
-
|
9
|
+
@name, @config = name.inquiry, config
|
9
10
|
end
|
10
11
|
|
11
12
|
def primary_host
|
@@ -36,29 +37,25 @@ class Kamal::Configuration::Role
|
|
36
37
|
argumentize "--label", labels
|
37
38
|
end
|
38
39
|
|
40
|
+
def logging_args
|
41
|
+
args = config.logging || {}
|
42
|
+
args.deep_merge!(specializations["logging"]) if specializations["logging"].present?
|
39
43
|
|
40
|
-
|
41
|
-
|
42
|
-
|
44
|
+
if args.any?
|
45
|
+
optionize({ "log-driver" => args["driver"] }.compact) +
|
46
|
+
argumentize("--log-opt", args["options"])
|
43
47
|
else
|
44
|
-
|
48
|
+
config.logging_args
|
45
49
|
end
|
46
50
|
end
|
47
51
|
|
48
|
-
def env_file
|
49
|
-
Kamal::EnvFile.new(env)
|
50
|
-
end
|
51
|
-
|
52
|
-
def host_env_directory
|
53
|
-
File.join config.host_env_directory, "roles"
|
54
|
-
end
|
55
52
|
|
56
|
-
def
|
57
|
-
|
53
|
+
def env
|
54
|
+
@env ||= base_env.merge(specialized_env)
|
58
55
|
end
|
59
56
|
|
60
57
|
def env_args
|
61
|
-
|
58
|
+
env.args
|
62
59
|
end
|
63
60
|
|
64
61
|
def asset_volume_args
|
@@ -101,7 +98,7 @@ class Kamal::Configuration::Role
|
|
101
98
|
end
|
102
99
|
|
103
100
|
def primary?
|
104
|
-
@config.primary_role
|
101
|
+
self == @config.primary_role
|
105
102
|
end
|
106
103
|
|
107
104
|
|
@@ -110,13 +107,13 @@ class Kamal::Configuration::Role
|
|
110
107
|
end
|
111
108
|
|
112
109
|
def cord_host_directory
|
113
|
-
File.join config.run_directory_as_docker_volume, "cords", [container_prefix, config.run_id].join("-")
|
110
|
+
File.join config.run_directory_as_docker_volume, "cords", [ container_prefix, config.run_id ].join("-")
|
114
111
|
end
|
115
112
|
|
116
113
|
def cord_volume
|
117
114
|
if (cord = health_check_options["cord"])
|
118
115
|
@cord_volume ||= Kamal::Configuration::Volume.new \
|
119
|
-
host_path: File.join(config.run_directory, "cords", [container_prefix, config.run_id].join("-")),
|
116
|
+
host_path: File.join(config.run_directory, "cords", [ container_prefix, config.run_id ].join("-")),
|
120
117
|
container_path: cord
|
121
118
|
end
|
122
119
|
end
|
@@ -179,11 +176,7 @@ class Kamal::Configuration::Role
|
|
179
176
|
end
|
180
177
|
|
181
178
|
def default_labels
|
182
|
-
|
183
|
-
{ "service" => config.service, "role" => name, "destination" => config.destination }
|
184
|
-
else
|
185
|
-
{ "service" => config.service, "role" => name }
|
186
|
-
end
|
179
|
+
{ "service" => config.service, "role" => name, "destination" => config.destination }
|
187
180
|
end
|
188
181
|
|
189
182
|
def traefik_labels
|
@@ -204,7 +197,7 @@ class Kamal::Configuration::Role
|
|
204
197
|
end
|
205
198
|
|
206
199
|
def traefik_service
|
207
|
-
|
200
|
+
container_prefix
|
208
201
|
end
|
209
202
|
|
210
203
|
def custom_labels
|
@@ -216,31 +209,21 @@ class Kamal::Configuration::Role
|
|
216
209
|
|
217
210
|
def specializations
|
218
211
|
if config.servers.is_a?(Array) || config.servers[name].is_a?(Array)
|
219
|
-
{
|
212
|
+
{}
|
220
213
|
else
|
221
214
|
config.servers[name].except("hosts")
|
222
215
|
end
|
223
216
|
end
|
224
217
|
|
225
218
|
def specialized_env
|
226
|
-
specializations
|
227
|
-
end
|
228
|
-
|
229
|
-
def merged_env
|
230
|
-
config.env&.merge(specialized_env) || {}
|
219
|
+
Kamal::Configuration::Env.from_config config: specializations.fetch("env", {})
|
231
220
|
end
|
232
221
|
|
233
222
|
# Secrets are stored in an array, which won't merge by default, so have to do it by hand.
|
234
|
-
def
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
# If there's no secret/clear split, everything is clear
|
239
|
-
clear_app_env = config.env["secret"] ? Array(config.env["clear"]) : Array(config.env["clear"] || config.env)
|
240
|
-
clear_role_env = specialized_env["secret"] ? Array(specialized_env["clear"]) : Array(specialized_env["clear"] || specialized_env)
|
241
|
-
|
242
|
-
new_env["clear"] = clear_app_env.to_h.merge(clear_role_env.to_h)
|
243
|
-
end
|
223
|
+
def base_env
|
224
|
+
Kamal::Configuration::Env.from_config \
|
225
|
+
config: config.env,
|
226
|
+
secrets_file: File.join(config.host_env_directory, "roles", "#{container_prefix}.env")
|
244
227
|
end
|
245
228
|
|
246
229
|
def http_health_check(port:, path:)
|
data/lib/kamal/configuration.rb
CHANGED
@@ -6,7 +6,7 @@ require "erb"
|
|
6
6
|
require "net/ssh/proxy/jump"
|
7
7
|
|
8
8
|
class Kamal::Configuration
|
9
|
-
delegate :service, :image, :servers, :
|
9
|
+
delegate :service, :image, :servers, :labels, :registry, :stop_wait_time, :hooks_path, :logging, to: :raw_config, allow_nil: true
|
10
10
|
delegate :argumentize, :optionize, to: Kamal::Utils
|
11
11
|
|
12
12
|
attr_reader :destination, :raw_config
|
@@ -88,11 +88,23 @@ class Kamal::Configuration
|
|
88
88
|
|
89
89
|
|
90
90
|
def all_hosts
|
91
|
-
roles.flat_map(&:hosts).uniq
|
91
|
+
(roles + accessories).flat_map(&:hosts).uniq
|
92
92
|
end
|
93
93
|
|
94
94
|
def primary_host
|
95
|
-
|
95
|
+
primary_role&.primary_host
|
96
|
+
end
|
97
|
+
|
98
|
+
def primary_role_name
|
99
|
+
raw_config.primary_role || "web"
|
100
|
+
end
|
101
|
+
|
102
|
+
def primary_role
|
103
|
+
role(primary_role_name)
|
104
|
+
end
|
105
|
+
|
106
|
+
def allow_empty_roles?
|
107
|
+
raw_config.allow_empty_roles
|
96
108
|
end
|
97
109
|
|
98
110
|
def traefik_roles
|
@@ -116,7 +128,11 @@ class Kamal::Configuration
|
|
116
128
|
end
|
117
129
|
|
118
130
|
def latest_image
|
119
|
-
"#{repository}
|
131
|
+
"#{repository}:#{latest_tag}"
|
132
|
+
end
|
133
|
+
|
134
|
+
def latest_tag
|
135
|
+
[ "latest", *destination ].join("-")
|
120
136
|
end
|
121
137
|
|
122
138
|
def service_with_version
|
@@ -127,6 +143,10 @@ class Kamal::Configuration
|
|
127
143
|
raw_config.require_destination
|
128
144
|
end
|
129
145
|
|
146
|
+
def retain_containers
|
147
|
+
raw_config.retain_containers || 5
|
148
|
+
end
|
149
|
+
|
130
150
|
|
131
151
|
def volume_args
|
132
152
|
if raw_config.volumes.present?
|
@@ -137,9 +157,9 @@ class Kamal::Configuration
|
|
137
157
|
end
|
138
158
|
|
139
159
|
def logging_args
|
140
|
-
if
|
141
|
-
optionize({ "log-driver" =>
|
142
|
-
argumentize("--log-opt",
|
160
|
+
if logging.present?
|
161
|
+
optionize({ "log-driver" => logging["driver"] }.compact) +
|
162
|
+
argumentize("--log-opt", logging["options"])
|
143
163
|
else
|
144
164
|
argumentize("--log-opt", { "max-size" => "10m" })
|
145
165
|
end
|
@@ -200,25 +220,22 @@ class Kamal::Configuration
|
|
200
220
|
raw_config.hooks_path || ".kamal/hooks"
|
201
221
|
end
|
202
222
|
|
203
|
-
def host_env_directory
|
204
|
-
"#{run_directory}/env"
|
205
|
-
end
|
206
|
-
|
207
223
|
def asset_path
|
208
224
|
raw_config.asset_path
|
209
225
|
end
|
210
226
|
|
211
|
-
|
212
|
-
|
227
|
+
|
228
|
+
def host_env_directory
|
229
|
+
File.join(run_directory, "env")
|
213
230
|
end
|
214
231
|
|
215
|
-
def
|
216
|
-
raw_config.
|
232
|
+
def env
|
233
|
+
raw_config.env || {}
|
217
234
|
end
|
218
235
|
|
219
236
|
|
220
237
|
def valid?
|
221
|
-
ensure_destination_if_required && ensure_required_keys_present && ensure_valid_kamal_version
|
238
|
+
ensure_destination_if_required && ensure_required_keys_present && ensure_valid_kamal_version && ensure_retain_containers_valid && ensure_valid_service_name
|
222
239
|
end
|
223
240
|
|
224
241
|
def to_h
|
@@ -264,12 +281,12 @@ class Kamal::Configuration
|
|
264
281
|
raise ArgumentError, "You must specify a password for the registry in config/deploy.yml (or set the ENV variable if that's used)"
|
265
282
|
end
|
266
283
|
|
267
|
-
unless role_names.include?(
|
268
|
-
raise ArgumentError, "The primary_role #{
|
284
|
+
unless role_names.include?(primary_role_name)
|
285
|
+
raise ArgumentError, "The primary_role #{primary_role_name} isn't defined"
|
269
286
|
end
|
270
287
|
|
271
|
-
if
|
272
|
-
raise ArgumentError, "No servers specified for the #{primary_role} primary_role"
|
288
|
+
if primary_role.hosts.empty?
|
289
|
+
raise ArgumentError, "No servers specified for the #{primary_role.name} primary_role"
|
273
290
|
end
|
274
291
|
|
275
292
|
unless allow_empty_roles?
|
@@ -283,6 +300,12 @@ class Kamal::Configuration
|
|
283
300
|
true
|
284
301
|
end
|
285
302
|
|
303
|
+
def ensure_valid_service_name
|
304
|
+
raise ArgumentError, "Service name can only include alphanumeric characters, hyphens, and underscores" unless raw_config[:service] =~ /^[a-z0-9_-]+$/i
|
305
|
+
|
306
|
+
true
|
307
|
+
end
|
308
|
+
|
286
309
|
def ensure_valid_kamal_version
|
287
310
|
if minimum_version && Gem::Version.new(minimum_version) > Gem::Version.new(Kamal::VERSION)
|
288
311
|
raise ArgumentError, "Current version is #{Kamal::VERSION}, minimum required is #{minimum_version}"
|
@@ -291,6 +314,12 @@ class Kamal::Configuration
|
|
291
314
|
true
|
292
315
|
end
|
293
316
|
|
317
|
+
def ensure_retain_containers_valid
|
318
|
+
raise ArgumentError, "Must retain at least 1 container" if retain_containers < 1
|
319
|
+
|
320
|
+
true
|
321
|
+
end
|
322
|
+
|
294
323
|
|
295
324
|
def role_names
|
296
325
|
raw_config.servers.is_a?(Array) ? [ "web" ] : raw_config.servers.keys.sort
|
@@ -299,7 +328,10 @@ class Kamal::Configuration
|
|
299
328
|
def git_version
|
300
329
|
@git_version ||=
|
301
330
|
if Kamal::Git.used?
|
302
|
-
|
331
|
+
if Kamal::Git.uncommitted_changes.present? && !builder.git_archive?
|
332
|
+
uncommitted_suffix = "_uncommitted_#{SecureRandom.hex(8)}"
|
333
|
+
end
|
334
|
+
[ Kamal::Git.revision, uncommitted_suffix ].compact.join
|
303
335
|
else
|
304
336
|
raise "Can't use commit hash as version, no git repository found in #{Dir.pwd}"
|
305
337
|
end
|