kamal 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/lib/kamal/cli/accessory.rb +3 -2
  3. data/lib/kamal/cli/app/boot.rb +67 -0
  4. data/lib/kamal/cli/app/prepare_assets.rb +24 -0
  5. data/lib/kamal/cli/app.rb +20 -61
  6. data/lib/kamal/cli/base.rb +21 -7
  7. data/lib/kamal/cli/env.rb +3 -3
  8. data/lib/kamal/cli/main.rb +1 -1
  9. data/lib/kamal/cli/templates/deploy.yml +1 -1
  10. data/lib/kamal/cli/templates/sample_hooks/docker-setup.sample +0 -0
  11. data/lib/kamal/cli/traefik.rb +15 -12
  12. data/lib/kamal/commander/specifics.rb +49 -0
  13. data/lib/kamal/commander.rb +9 -33
  14. data/lib/kamal/commands/accessory.rb +2 -2
  15. data/lib/kamal/commands/app/assets.rb +4 -4
  16. data/lib/kamal/commands/app/cord.rb +2 -2
  17. data/lib/kamal/commands/app/execution.rb +8 -6
  18. data/lib/kamal/commands/app/images.rb +1 -1
  19. data/lib/kamal/commands/app.rb +29 -8
  20. data/lib/kamal/commands/auditor.rb +1 -1
  21. data/lib/kamal/commands/base.rb +5 -1
  22. data/lib/kamal/commands/builder/base.rb +14 -4
  23. data/lib/kamal/commands/builder/multiarch.rb +9 -9
  24. data/lib/kamal/commands/builder/native/cached.rb +7 -6
  25. data/lib/kamal/commands/builder/native/remote.rb +9 -9
  26. data/lib/kamal/commands/builder/native.rb +8 -7
  27. data/lib/kamal/commands/healthcheck.rb +0 -1
  28. data/lib/kamal/commands/hook.rb +1 -1
  29. data/lib/kamal/commands/lock.rb +19 -9
  30. data/lib/kamal/commands/prune.rb +2 -2
  31. data/lib/kamal/commands/server.rb +1 -1
  32. data/lib/kamal/commands/traefik.rb +8 -14
  33. data/lib/kamal/configuration/accessory.rb +9 -19
  34. data/lib/kamal/configuration/boot.rb +1 -1
  35. data/lib/kamal/configuration/builder.rb +7 -3
  36. data/lib/kamal/configuration/env.rb +40 -0
  37. data/lib/kamal/configuration/role.rb +12 -42
  38. data/lib/kamal/configuration.rb +20 -8
  39. data/lib/kamal/env_file.rb +12 -15
  40. data/lib/kamal/utils.rb +7 -3
  41. data/lib/kamal/version.rb +1 -1
  42. data/lib/kamal.rb +1 -1
  43. metadata +6 -2
@@ -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
- docker :ps, "--quiet", *filter_args(statuses: ACTIVE_DOCKER_STATUSES), "--latest"
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
- list_versions("--latest", statuses: ACTIVE_DOCKER_STATUSES)
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
- %(while read line; do echo ${line##{role.container_prefix}-}; done) # Extract SHA from "service-role-dest-SHA"
68
+ extract_version_from_name
67
69
  end
68
70
 
69
71
 
70
72
  def make_env_directory
71
- make_directory role.host_env_directory
73
+ make_directory role.env.secrets_directory
72
74
  end
73
75
 
74
76
  def remove_env_file
75
- [ :rm, "-f", role.host_env_file_path ]
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 service_role_dest
89
- [ config.service, role, config.destination ].compact.join("-")
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
- "#{config.run_directory}/#{file}"
24
+ File.join(config.run_directory, file)
25
25
  end
26
26
 
27
27
  def audit_tags(**details)
@@ -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
- def push
11
- docker :buildx, :build,
12
- "--push",
13
- *build_options,
14
- build_context
15
- end
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
@@ -1,5 +1,4 @@
1
1
  class Kamal::Commands::Healthcheck < Kamal::Commands::Base
2
-
3
2
  def run
4
3
  primary = config.role(config.primary_role)
5
4
 
@@ -9,6 +9,6 @@ class Kamal::Commands::Hook < Kamal::Commands::Base
9
9
 
10
10
  private
11
11
  def hook_file(hook)
12
- "#{config.hooks_path}/#{hook}"
12
+ File.join(config.hooks_path, hook)
13
13
  end
14
14
  end
@@ -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
- "#{config.run_directory}/lock-#{config.service}"
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
- [lock_dir, :details].join("/")
58
+ File.join(lock_dir, "details")
49
59
  end
50
60
 
51
61
  def lock_details(message, version)
@@ -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
- end
46
+ end
@@ -1,5 +1,5 @@
1
1
  class Kamal::Commands::Server < Kamal::Commands::Base
2
2
  def ensure_run_directory
3
- [:mkdir, "-p", config.run_directory]
3
+ [ :mkdir, "-p", config.run_directory ]
4
4
  end
5
5
  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
- 'log.level' => 'DEBUG'
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 env_file
75
- Kamal::EnvFile.new(config.traefik.fetch("env", {}))
76
- end
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(host_env_directory)
81
+ make_directory(env.secrets_directory)
84
82
  end
85
83
 
86
84
  def remove_env_file
87
- [:rm, "-f", host_env_file_path]
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
- argumentize "--env-file", host_env_file_path
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
- specifics["env"] || {}
46
- end
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
- argumentize "--env-file", host_env_file_path
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
- (env["clear"] || env).each { |k, v| ENV[k] = v }
104
+ env.clear.each { |k, v| ENV[k] = v }
115
105
  yield
116
106
  ensure
117
- (env["clear"] || env).each { |k, v| ENV.delete(k) }
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 : "#{service_data_directory}/#{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
@@ -8,7 +8,7 @@ class Kamal::Configuration::Boot
8
8
  limit = @options["limit"]
9
9
 
10
10
  if limit.to_s.end_with?("%")
11
- [@host_count * limit.to_i / 100, 1].max
11
+ [ @host_count * limit.to_i / 100, 1 ].max
12
12
  else
13
13
  limit
14
14
  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
- if config.env && config.env["secret"]
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
- argumentize "--env-file", host_env_file_path
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
- if config.destination
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
- [ config.service, name, config.destination ].compact.join("-")
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["env"] || {}
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 merged_env_with_secrets
248
- merged_env.tap do |new_env|
249
- new_env["secret"] = Array(config.env["secret"]) + Array(specialized_env["secret"])
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:)