kamal 1.4.0 → 1.5.1
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 +3 -2
- 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 +20 -61
- data/lib/kamal/cli/base.rb +21 -7
- data/lib/kamal/cli/env.rb +3 -3
- data/lib/kamal/cli/main.rb +1 -1
- data/lib/kamal/cli/templates/deploy.yml +1 -1
- data/lib/kamal/cli/templates/sample_hooks/docker-setup.sample +0 -0
- data/lib/kamal/cli/traefik.rb +15 -12
- 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 +4 -4
- data/lib/kamal/commands/app/cord.rb +2 -2
- data/lib/kamal/commands/app/execution.rb +8 -6
- data/lib/kamal/commands/app/images.rb +1 -1
- data/lib/kamal/commands/app.rb +29 -8
- data/lib/kamal/commands/app.rb.orig +127 -0
- data/lib/kamal/commands/auditor.rb +1 -1
- data/lib/kamal/commands/base.rb +6 -2
- data/lib/kamal/commands/builder/base.rb +14 -4
- data/lib/kamal/commands/builder/multiarch.rb +9 -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/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 +2 -2
- data/lib/kamal/commands/server.rb +1 -1
- data/lib/kamal/commands/traefik.rb +8 -14
- data/lib/kamal/configuration/accessory.rb +9 -19
- data/lib/kamal/configuration/boot.rb +1 -1
- data/lib/kamal/configuration/builder.rb +7 -3
- data/lib/kamal/configuration/env.rb +40 -0
- data/lib/kamal/configuration/role.rb +12 -42
- data/lib/kamal/configuration.rb +20 -8
- data/lib/kamal/env_file.rb +12 -15
- data/lib/kamal/utils.rb +8 -5
- data/lib/kamal/version.rb +1 -1
- data/lib/kamal.rb +1 -1
- metadata +7 -2
@@ -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
|
@@ -51,27 +51,11 @@ class Kamal::Configuration::Role
|
|
51
51
|
|
52
52
|
|
53
53
|
def env
|
54
|
-
|
55
|
-
merged_env_with_secrets
|
56
|
-
else
|
57
|
-
merged_env
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def env_file
|
62
|
-
Kamal::EnvFile.new(env)
|
63
|
-
end
|
64
|
-
|
65
|
-
def host_env_directory
|
66
|
-
File.join config.host_env_directory, "roles"
|
67
|
-
end
|
68
|
-
|
69
|
-
def host_env_file_path
|
70
|
-
File.join host_env_directory, "#{[config.service, name, config.destination].compact.join("-")}.env"
|
54
|
+
@env ||= base_env.merge(specialized_env)
|
71
55
|
end
|
72
56
|
|
73
57
|
def env_args
|
74
|
-
|
58
|
+
env.args
|
75
59
|
end
|
76
60
|
|
77
61
|
def asset_volume_args
|
@@ -123,13 +107,13 @@ class Kamal::Configuration::Role
|
|
123
107
|
end
|
124
108
|
|
125
109
|
def cord_host_directory
|
126
|
-
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("-")
|
127
111
|
end
|
128
112
|
|
129
113
|
def cord_volume
|
130
114
|
if (cord = health_check_options["cord"])
|
131
115
|
@cord_volume ||= Kamal::Configuration::Volume.new \
|
132
|
-
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("-")),
|
133
117
|
container_path: cord
|
134
118
|
end
|
135
119
|
end
|
@@ -192,11 +176,7 @@ class Kamal::Configuration::Role
|
|
192
176
|
end
|
193
177
|
|
194
178
|
def default_labels
|
195
|
-
|
196
|
-
{ "service" => config.service, "role" => name, "destination" => config.destination }
|
197
|
-
else
|
198
|
-
{ "service" => config.service, "role" => name }
|
199
|
-
end
|
179
|
+
{ "service" => config.service, "role" => name, "destination" => config.destination }
|
200
180
|
end
|
201
181
|
|
202
182
|
def traefik_labels
|
@@ -217,7 +197,7 @@ class Kamal::Configuration::Role
|
|
217
197
|
end
|
218
198
|
|
219
199
|
def traefik_service
|
220
|
-
|
200
|
+
container_prefix
|
221
201
|
end
|
222
202
|
|
223
203
|
def custom_labels
|
@@ -229,31 +209,21 @@ class Kamal::Configuration::Role
|
|
229
209
|
|
230
210
|
def specializations
|
231
211
|
if config.servers.is_a?(Array) || config.servers[name].is_a?(Array)
|
232
|
-
{
|
212
|
+
{}
|
233
213
|
else
|
234
214
|
config.servers[name].except("hosts")
|
235
215
|
end
|
236
216
|
end
|
237
217
|
|
238
218
|
def specialized_env
|
239
|
-
specializations
|
240
|
-
end
|
241
|
-
|
242
|
-
def merged_env
|
243
|
-
config.env&.merge(specialized_env) || {}
|
219
|
+
Kamal::Configuration::Env.from_config config: specializations.fetch("env", {})
|
244
220
|
end
|
245
221
|
|
246
222
|
# Secrets are stored in an array, which won't merge by default, so have to do it by hand.
|
247
|
-
def
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
# If there's no secret/clear split, everything is clear
|
252
|
-
clear_app_env = config.env["secret"] ? Array(config.env["clear"]) : Array(config.env["clear"] || config.env)
|
253
|
-
clear_role_env = specialized_env["secret"] ? Array(specialized_env["clear"]) : Array(specialized_env["clear"] || specialized_env)
|
254
|
-
|
255
|
-
new_env["clear"] = clear_app_env.to_h.merge(clear_role_env.to_h)
|
256
|
-
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")
|
257
227
|
end
|
258
228
|
|
259
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,7 +88,7 @@ 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
|
@@ -128,7 +128,11 @@ class Kamal::Configuration
|
|
128
128
|
end
|
129
129
|
|
130
130
|
def latest_image
|
131
|
-
"#{repository}
|
131
|
+
"#{repository}:#{latest_tag}"
|
132
|
+
end
|
133
|
+
|
134
|
+
def latest_tag
|
135
|
+
[ "latest", *destination ].join("-")
|
132
136
|
end
|
133
137
|
|
134
138
|
def service_with_version
|
@@ -216,12 +220,17 @@ class Kamal::Configuration
|
|
216
220
|
raw_config.hooks_path || ".kamal/hooks"
|
217
221
|
end
|
218
222
|
|
223
|
+
def asset_path
|
224
|
+
raw_config.asset_path
|
225
|
+
end
|
226
|
+
|
227
|
+
|
219
228
|
def host_env_directory
|
220
|
-
"
|
229
|
+
File.join(run_directory, "env")
|
221
230
|
end
|
222
231
|
|
223
|
-
def
|
224
|
-
raw_config.
|
232
|
+
def env
|
233
|
+
raw_config.env || {}
|
225
234
|
end
|
226
235
|
|
227
236
|
|
@@ -292,7 +301,7 @@ class Kamal::Configuration
|
|
292
301
|
end
|
293
302
|
|
294
303
|
def ensure_valid_service_name
|
295
|
-
raise ArgumentError, "Service name can only include alphanumeric characters, hyphens, and underscores" unless raw_config[:service] =~ /^[a-z0-9_-]+$/
|
304
|
+
raise ArgumentError, "Service name can only include alphanumeric characters, hyphens, and underscores" unless raw_config[:service] =~ /^[a-z0-9_-]+$/i
|
296
305
|
|
297
306
|
true
|
298
307
|
end
|
@@ -319,7 +328,10 @@ class Kamal::Configuration
|
|
319
328
|
def git_version
|
320
329
|
@git_version ||=
|
321
330
|
if Kamal::Git.used?
|
322
|
-
|
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
|
323
335
|
else
|
324
336
|
raise "Can't use commit hash as version, no git repository found in #{Dir.pwd}"
|
325
337
|
end
|
data/lib/kamal/env_file.rb
CHANGED
@@ -3,21 +3,11 @@ class Kamal::EnvFile
|
|
3
3
|
def initialize(env)
|
4
4
|
@env = env
|
5
5
|
end
|
6
|
-
|
6
|
+
|
7
7
|
def to_s
|
8
8
|
env_file = StringIO.new.tap do |contents|
|
9
|
-
|
10
|
-
|
11
|
-
contents << docker_env_file_line(key, ENV.fetch(key))
|
12
|
-
end
|
13
|
-
|
14
|
-
@env["clear"]&.each do |key, value|
|
15
|
-
contents << docker_env_file_line(key, value)
|
16
|
-
end
|
17
|
-
else
|
18
|
-
@env.fetch("clear", @env)&.each do |key, value|
|
19
|
-
contents << docker_env_file_line(key, value)
|
20
|
-
end
|
9
|
+
@env.each do |key, value|
|
10
|
+
contents << docker_env_file_line(key, value)
|
21
11
|
end
|
22
12
|
end.string
|
23
13
|
|
@@ -26,14 +16,21 @@ class Kamal::EnvFile
|
|
26
16
|
end
|
27
17
|
|
28
18
|
alias to_str to_s
|
29
|
-
|
19
|
+
|
30
20
|
private
|
31
21
|
def docker_env_file_line(key, value)
|
32
|
-
"#{key
|
22
|
+
"#{key}=#{escape_docker_env_file_value(value)}\n"
|
33
23
|
end
|
34
24
|
|
35
25
|
# Escape a value to make it safe to dump in a docker file.
|
36
26
|
def escape_docker_env_file_value(value)
|
27
|
+
# keep non-ascii(UTF-8) characters as it is
|
28
|
+
value.to_s.scan(/[\x00-\x7F]+|[^\x00-\x7F]+/).map do |part|
|
29
|
+
part.ascii_only? ? escape_docker_env_file_ascii_value(part) : part
|
30
|
+
end.join
|
31
|
+
end
|
32
|
+
|
33
|
+
def escape_docker_env_file_ascii_value(value)
|
37
34
|
# Doublequotes are treated literally in docker env files
|
38
35
|
# so remove leading and trailing ones and unescape any others
|
39
36
|
value.to_s.dump[1..-2].gsub(/\\"/, "\"")
|
data/lib/kamal/utils.rb
CHANGED
@@ -9,7 +9,7 @@ module Kamal::Utils
|
|
9
9
|
if value.present?
|
10
10
|
attr = "#{key}=#{escape_shell_value(value)}"
|
11
11
|
attr = self.sensitive(attr, redaction: "#{key}=[REDACTED]") if sensitive
|
12
|
-
[ argument, attr]
|
12
|
+
[ argument, attr ]
|
13
13
|
else
|
14
14
|
[ argument, key ]
|
15
15
|
end
|
@@ -29,7 +29,7 @@ module Kamal::Utils
|
|
29
29
|
|
30
30
|
# Flattens a one-to-many structure into an array of two-element arrays each containing a key-value pair
|
31
31
|
def flatten_args(args)
|
32
|
-
args.flat_map { |key, value| value.try(:map) { |entry| [key, entry] } || [ [ key, value ] ] }
|
32
|
+
args.flat_map { |key, value| value.try(:map) { |entry| [ key, entry ] } || [ [ key, value ] ] }
|
33
33
|
end
|
34
34
|
|
35
35
|
# Marks sensitive values for redaction in logs and human-visible output.
|
@@ -66,12 +66,15 @@ module Kamal::Utils
|
|
66
66
|
Array(filters).select do |filter|
|
67
67
|
matches += Array(items).select do |item|
|
68
68
|
# Only allow * for a wildcard
|
69
|
-
pattern = Regexp.escape(filter).gsub('\*', '.*')
|
70
69
|
# items are roles or hosts
|
71
|
-
|
70
|
+
File.fnmatch(filter, item.to_s, File::FNM_EXTGLOB)
|
72
71
|
end
|
73
72
|
end
|
74
73
|
|
75
|
-
matches
|
74
|
+
matches.uniq
|
75
|
+
end
|
76
|
+
|
77
|
+
def stable_sort!(elements, &block)
|
78
|
+
elements.sort_by!.with_index { |element, index| [ block.call(element), index ] }
|
76
79
|
end
|
77
80
|
end
|
data/lib/kamal/version.rb
CHANGED
data/lib/kamal.rb
CHANGED
@@ -5,6 +5,6 @@ require "active_support"
|
|
5
5
|
require "zeitwerk"
|
6
6
|
|
7
7
|
loader = Zeitwerk::Loader.for_gem
|
8
|
-
loader.ignore("
|
8
|
+
loader.ignore(File.join(__dir__, "kamal", "sshkit_with_ext.rb"))
|
9
9
|
loader.setup
|
10
10
|
loader.eager_load # We need all commands loaded.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kamal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-04-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -206,6 +206,8 @@ files:
|
|
206
206
|
- lib/kamal/cli.rb
|
207
207
|
- lib/kamal/cli/accessory.rb
|
208
208
|
- lib/kamal/cli/app.rb
|
209
|
+
- lib/kamal/cli/app/boot.rb
|
210
|
+
- lib/kamal/cli/app/prepare_assets.rb
|
209
211
|
- lib/kamal/cli/base.rb
|
210
212
|
- lib/kamal/cli/build.rb
|
211
213
|
- lib/kamal/cli/env.rb
|
@@ -227,9 +229,11 @@ files:
|
|
227
229
|
- lib/kamal/cli/templates/template.env
|
228
230
|
- lib/kamal/cli/traefik.rb
|
229
231
|
- lib/kamal/commander.rb
|
232
|
+
- lib/kamal/commander/specifics.rb
|
230
233
|
- lib/kamal/commands.rb
|
231
234
|
- lib/kamal/commands/accessory.rb
|
232
235
|
- lib/kamal/commands/app.rb
|
236
|
+
- lib/kamal/commands/app.rb.orig
|
233
237
|
- lib/kamal/commands/app/assets.rb
|
234
238
|
- lib/kamal/commands/app/containers.rb
|
235
239
|
- lib/kamal/commands/app/cord.rb
|
@@ -257,6 +261,7 @@ files:
|
|
257
261
|
- lib/kamal/configuration/accessory.rb
|
258
262
|
- lib/kamal/configuration/boot.rb
|
259
263
|
- lib/kamal/configuration/builder.rb
|
264
|
+
- lib/kamal/configuration/env.rb
|
260
265
|
- lib/kamal/configuration/role.rb
|
261
266
|
- lib/kamal/configuration/ssh.rb
|
262
267
|
- lib/kamal/configuration/sshkit.rb
|