kamal 1.4.0 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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/auditor.rb +1 -1
- data/lib/kamal/commands/base.rb +5 -1
- 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 +7 -3
- data/lib/kamal/version.rb +1 -1
- data/lib/kamal.rb +1 -1
- metadata +6 -2
data/lib/kamal/commands/app.rb
CHANGED
@@ -15,7 +15,7 @@ class Kamal::Commands::App < Kamal::Commands::Base
|
|
15
15
|
"--detach",
|
16
16
|
"--restart unless-stopped",
|
17
17
|
"--name", container_name,
|
18
|
-
*(["--hostname", hostname] if hostname),
|
18
|
+
*([ "--hostname", hostname ] if hostname),
|
19
19
|
"-e", "KAMAL_CONTAINER_NAME=\"#{container_name}\"",
|
20
20
|
"-e", "KAMAL_VERSION=\"#{config.version}\"",
|
21
21
|
*role.env_args,
|
@@ -49,7 +49,7 @@ class Kamal::Commands::App < Kamal::Commands::Base
|
|
49
49
|
|
50
50
|
|
51
51
|
def current_running_container_id
|
52
|
-
|
52
|
+
current_running_container(format: "--quiet")
|
53
53
|
end
|
54
54
|
|
55
55
|
def container_id_for_version(version, only_running: false)
|
@@ -57,22 +57,24 @@ class Kamal::Commands::App < Kamal::Commands::Base
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def current_running_version
|
60
|
-
|
60
|
+
pipe \
|
61
|
+
current_running_container(format: "--format '{{.Names}}'"),
|
62
|
+
extract_version_from_name
|
61
63
|
end
|
62
64
|
|
63
65
|
def list_versions(*docker_args, statuses: nil)
|
64
66
|
pipe \
|
65
67
|
docker(:ps, *filter_args(statuses: statuses), *docker_args, "--format", '"{{.Names}}"'),
|
66
|
-
|
68
|
+
extract_version_from_name
|
67
69
|
end
|
68
70
|
|
69
71
|
|
70
72
|
def make_env_directory
|
71
|
-
make_directory role.
|
73
|
+
make_directory role.env.secrets_directory
|
72
74
|
end
|
73
75
|
|
74
76
|
def remove_env_file
|
75
|
-
[ :rm, "-f", role.
|
77
|
+
[ :rm, "-f", role.env.secrets_file ]
|
76
78
|
end
|
77
79
|
|
78
80
|
|
@@ -81,12 +83,31 @@ class Kamal::Commands::App < Kamal::Commands::Base
|
|
81
83
|
[ role.container_prefix, version || config.version ].compact.join("-")
|
82
84
|
end
|
83
85
|
|
86
|
+
def latest_image_id
|
87
|
+
docker :image, :ls, *argumentize("--filter", "reference=#{config.latest_image}"), "--format", "'{{.ID}}'"
|
88
|
+
end
|
89
|
+
|
90
|
+
def current_running_container(format:)
|
91
|
+
pipe \
|
92
|
+
shell(chain(latest_image_container(format: format), latest_container(format: format))),
|
93
|
+
[ :head, "-1" ]
|
94
|
+
end
|
95
|
+
|
96
|
+
def latest_image_container(format:)
|
97
|
+
latest_container format: format, filters: [ "ancestor=$(#{latest_image_id.join(" ")})" ]
|
98
|
+
end
|
99
|
+
|
100
|
+
def latest_container(format:, filters: nil)
|
101
|
+
docker :ps, "--latest", *format, *filter_args(statuses: ACTIVE_DOCKER_STATUSES), argumentize("--filter", filters)
|
102
|
+
end
|
103
|
+
|
84
104
|
def filter_args(statuses: nil)
|
85
105
|
argumentize "--filter", filters(statuses: statuses)
|
86
106
|
end
|
87
107
|
|
88
|
-
def
|
89
|
-
|
108
|
+
def extract_version_from_name
|
109
|
+
# Extract SHA from "service-role-dest-SHA"
|
110
|
+
%(while read line; do echo ${line##{role.container_prefix}-}; done)
|
90
111
|
end
|
91
112
|
|
92
113
|
def filters(statuses: nil)
|
@@ -21,7 +21,7 @@ class Kamal::Commands::Auditor < Kamal::Commands::Base
|
|
21
21
|
def audit_log_file
|
22
22
|
file = [ config.service, config.destination, "audit.log" ].compact.join("-")
|
23
23
|
|
24
|
-
|
24
|
+
File.join(config.run_directory, file)
|
25
25
|
end
|
26
26
|
|
27
27
|
def audit_tags(**details)
|
data/lib/kamal/commands/base.rb
CHANGED
@@ -71,13 +71,17 @@ module Kamal::Commands
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def shell(command)
|
74
|
-
[ :sh, "-c", "'#{command.flatten.join(" ").gsub("'", "'
|
74
|
+
[ :sh, "-c", "'#{command.flatten.join(" ").gsub("'", "'\\\\''")}'" ]
|
75
75
|
end
|
76
76
|
|
77
77
|
def docker(*args)
|
78
78
|
args.compact.unshift :docker
|
79
79
|
end
|
80
80
|
|
81
|
+
def git(*args)
|
82
|
+
args.compact.unshift :git
|
83
|
+
end
|
84
|
+
|
81
85
|
def tags(**details)
|
82
86
|
Kamal::Tags.from_config(config, **details)
|
83
87
|
end
|
@@ -3,7 +3,7 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
|
3
3
|
class BuilderError < StandardError; end
|
4
4
|
|
5
5
|
delegate :argumentize, to: Kamal::Utils
|
6
|
-
delegate :args, :secrets, :dockerfile, :local_arch, :local_host, :remote_arch, :remote_host, :cache_from, :cache_to, :ssh, to: :builder_config
|
6
|
+
delegate :args, :secrets, :dockerfile, :local_arch, :local_host, :remote_arch, :remote_host, :cache_from, :cache_to, :ssh, :git_archive?, to: :builder_config
|
7
7
|
|
8
8
|
def clean
|
9
9
|
docker :image, :rm, "--force", config.absolute_image
|
@@ -13,6 +13,16 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
|
13
13
|
docker :pull, config.absolute_image
|
14
14
|
end
|
15
15
|
|
16
|
+
def push
|
17
|
+
if git_archive?
|
18
|
+
pipe \
|
19
|
+
git(:archive, "--format=tar", :HEAD),
|
20
|
+
build_and_push
|
21
|
+
else
|
22
|
+
build_and_push
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
16
26
|
def build_options
|
17
27
|
[ *build_tags, *build_cache, *build_labels, *build_args, *build_secrets, *build_dockerfile, *build_ssh ]
|
18
28
|
end
|
@@ -25,7 +35,7 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
|
25
35
|
pipe \
|
26
36
|
docker(:inspect, "-f", "'{{ .Config.Labels.service }}'", config.absolute_image),
|
27
37
|
any(
|
28
|
-
[:grep, "-x", config.service],
|
38
|
+
[ :grep, "-x", config.service ],
|
29
39
|
"(echo \"Image #{config.absolute_image} is missing the 'service' label\" && exit 1)"
|
30
40
|
)
|
31
41
|
end
|
@@ -38,8 +48,8 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
|
|
38
48
|
|
39
49
|
def build_cache
|
40
50
|
if cache_to && cache_from
|
41
|
-
["--cache-to", cache_to,
|
42
|
-
"--cache-from", cache_from]
|
51
|
+
[ "--cache-to", cache_to,
|
52
|
+
"--cache-from", cache_from ]
|
43
53
|
end
|
44
54
|
end
|
45
55
|
|
@@ -7,15 +7,6 @@ class Kamal::Commands::Builder::Multiarch < Kamal::Commands::Builder::Base
|
|
7
7
|
docker :buildx, :rm, builder_name
|
8
8
|
end
|
9
9
|
|
10
|
-
def push
|
11
|
-
docker :buildx, :build,
|
12
|
-
"--push",
|
13
|
-
"--platform", platform_names,
|
14
|
-
"--builder", builder_name,
|
15
|
-
*build_options,
|
16
|
-
build_context
|
17
|
-
end
|
18
|
-
|
19
10
|
def info
|
20
11
|
combine \
|
21
12
|
docker(:context, :ls),
|
@@ -34,4 +25,13 @@ class Kamal::Commands::Builder::Multiarch < Kamal::Commands::Builder::Base
|
|
34
25
|
"linux/amd64,linux/arm64"
|
35
26
|
end
|
36
27
|
end
|
28
|
+
|
29
|
+
def build_and_push
|
30
|
+
docker :buildx, :build,
|
31
|
+
"--push",
|
32
|
+
"--platform", platform_names,
|
33
|
+
"--builder", builder_name,
|
34
|
+
*build_options,
|
35
|
+
build_context
|
36
|
+
end
|
37
37
|
end
|
@@ -7,10 +7,11 @@ class Kamal::Commands::Builder::Native::Cached < Kamal::Commands::Builder::Nativ
|
|
7
7
|
docker :buildx, :rm, builder_name
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
10
|
+
private
|
11
|
+
def build_and_push
|
12
|
+
docker :buildx, :build,
|
13
|
+
"--push",
|
14
|
+
*build_options,
|
15
|
+
build_context
|
16
|
+
end
|
16
17
|
end
|
@@ -11,15 +11,6 @@ class Kamal::Commands::Builder::Native::Remote < Kamal::Commands::Builder::Nativ
|
|
11
11
|
remove_buildx
|
12
12
|
end
|
13
13
|
|
14
|
-
def push
|
15
|
-
docker :buildx, :build,
|
16
|
-
"--push",
|
17
|
-
"--platform", platform,
|
18
|
-
"--builder", builder_name,
|
19
|
-
*build_options,
|
20
|
-
build_context
|
21
|
-
end
|
22
|
-
|
23
14
|
def info
|
24
15
|
chain \
|
25
16
|
docker(:context, :ls),
|
@@ -56,4 +47,13 @@ class Kamal::Commands::Builder::Native::Remote < Kamal::Commands::Builder::Nativ
|
|
56
47
|
def remove_buildx
|
57
48
|
docker :buildx, :rm, builder_name
|
58
49
|
end
|
50
|
+
|
51
|
+
def build_and_push
|
52
|
+
docker :buildx, :build,
|
53
|
+
"--push",
|
54
|
+
"--platform", platform,
|
55
|
+
"--builder", builder_name,
|
56
|
+
*build_options,
|
57
|
+
build_context
|
58
|
+
end
|
59
59
|
end
|
@@ -7,14 +7,15 @@ class Kamal::Commands::Builder::Native < Kamal::Commands::Builder::Base
|
|
7
7
|
# No-op on native without cache
|
8
8
|
end
|
9
9
|
|
10
|
-
def push
|
11
|
-
combine \
|
12
|
-
docker(:build, *build_options, build_context),
|
13
|
-
docker(:push, config.absolute_image),
|
14
|
-
docker(:push, config.latest_image)
|
15
|
-
end
|
16
|
-
|
17
10
|
def info
|
18
11
|
# No-op on native
|
19
12
|
end
|
13
|
+
|
14
|
+
private
|
15
|
+
def build_and_push
|
16
|
+
combine \
|
17
|
+
docker(:build, *build_options, build_context),
|
18
|
+
docker(:push, config.absolute_image),
|
19
|
+
docker(:push, config.latest_image)
|
20
|
+
end
|
20
21
|
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
@@ -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
|
@@ -4,7 +4,7 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
|
|
4
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
|
@@ -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
|
@@ -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
|
@@ -85,10 +85,14 @@ class Kamal::Configuration::Builder
|
|
85
85
|
@options["ssh"]
|
86
86
|
end
|
87
87
|
|
88
|
+
def git_archive?
|
89
|
+
Kamal::Git.used? && @options["context"].nil?
|
90
|
+
end
|
91
|
+
|
88
92
|
private
|
89
93
|
def valid?
|
90
94
|
if @options["cache"] && @options["cache"]["type"]
|
91
|
-
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"])
|
92
96
|
end
|
93
97
|
end
|
94
98
|
|
@@ -109,7 +113,7 @@ class Kamal::Configuration::Builder
|
|
109
113
|
end
|
110
114
|
|
111
115
|
def cache_to_config_for_gha
|
112
|
-
[ "type=gha", @options["cache"]&.fetch("options", nil)].compact.join(",")
|
116
|
+
[ "type=gha", @options["cache"]&.fetch("options", nil) ].compact.join(",")
|
113
117
|
end
|
114
118
|
|
115
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
|
@@ -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:)
|