kamal 0.16.1 → 1.0.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.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/kamal/cli/app.rb +38 -11
  4. data/lib/kamal/cli/base.rb +8 -0
  5. data/lib/kamal/cli/build.rb +18 -1
  6. data/lib/kamal/cli/env.rb +56 -0
  7. data/lib/kamal/cli/healthcheck/poller.rb +64 -0
  8. data/lib/kamal/cli/healthcheck.rb +2 -2
  9. data/lib/kamal/cli/lock.rb +12 -3
  10. data/lib/kamal/cli/main.rb +14 -3
  11. data/lib/kamal/cli/prune.rb +3 -2
  12. data/lib/kamal/cli/server.rb +2 -0
  13. data/lib/kamal/cli/templates/deploy.yml +12 -1
  14. data/lib/kamal/commander.rb +21 -8
  15. data/lib/kamal/commands/accessory.rb +8 -8
  16. data/lib/kamal/commands/app/assets.rb +51 -0
  17. data/lib/kamal/commands/app/containers.rb +23 -0
  18. data/lib/kamal/commands/app/cord.rb +22 -0
  19. data/lib/kamal/commands/app/execution.rb +27 -0
  20. data/lib/kamal/commands/app/images.rb +13 -0
  21. data/lib/kamal/commands/app/logging.rb +18 -0
  22. data/lib/kamal/commands/app.rb +17 -91
  23. data/lib/kamal/commands/auditor.rb +3 -1
  24. data/lib/kamal/commands/base.rb +12 -0
  25. data/lib/kamal/commands/builder/base.rb +6 -0
  26. data/lib/kamal/commands/builder.rb +1 -1
  27. data/lib/kamal/commands/healthcheck.rb +15 -12
  28. data/lib/kamal/commands/lock.rb +2 -2
  29. data/lib/kamal/commands/prune.rb +11 -3
  30. data/lib/kamal/commands/server.rb +5 -0
  31. data/lib/kamal/commands/traefik.rb +21 -7
  32. data/lib/kamal/configuration/accessory.rb +14 -2
  33. data/lib/kamal/configuration/role.rb +112 -19
  34. data/lib/kamal/configuration/ssh.rb +1 -1
  35. data/lib/kamal/configuration/volume.rb +22 -0
  36. data/lib/kamal/configuration.rb +79 -43
  37. data/lib/kamal/env_file.rb +41 -0
  38. data/lib/kamal/git.rb +19 -0
  39. data/lib/kamal/utils.rb +0 -39
  40. data/lib/kamal/version.rb +1 -1
  41. metadata +15 -4
  42. data/lib/kamal/utils/healthcheck_poller.rb +0 -39
@@ -0,0 +1,27 @@
1
+ module Kamal::Commands::App::Execution
2
+ def execute_in_existing_container(*command, interactive: false)
3
+ docker :exec,
4
+ ("-it" if interactive),
5
+ container_name,
6
+ *command
7
+ end
8
+
9
+ def execute_in_new_container(*command, interactive: false)
10
+ docker :run,
11
+ ("-it" if interactive),
12
+ "--rm",
13
+ *role_config&.env_args,
14
+ *config.volume_args,
15
+ *role_config&.option_args,
16
+ config.absolute_image,
17
+ *command
18
+ end
19
+
20
+ def execute_in_existing_container_over_ssh(*command, host:)
21
+ run_over_ssh execute_in_existing_container(*command, interactive: true), host: host
22
+ end
23
+
24
+ def execute_in_new_container_over_ssh(*command, host:)
25
+ run_over_ssh execute_in_new_container(*command, interactive: true), host: host
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ module Kamal::Commands::App::Images
2
+ def list_images
3
+ docker :image, :ls, config.repository
4
+ end
5
+
6
+ def remove_images
7
+ docker :image, :prune, "--all", "--force", *filter_args
8
+ end
9
+
10
+ def tag_current_image_as_latest
11
+ docker :tag, config.absolute_image, config.latest_image
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ module Kamal::Commands::App::Logging
2
+ def logs(since: nil, lines: nil, grep: nil)
3
+ pipe \
4
+ current_running_container_id,
5
+ "xargs docker logs#{" --since #{since}" if since}#{" --tail #{lines}" if lines} 2>&1",
6
+ ("grep '#{grep}'" if grep)
7
+ end
8
+
9
+ def follow_logs(host:, grep: nil)
10
+ run_over_ssh \
11
+ pipe(
12
+ current_running_container_id,
13
+ "xargs docker logs --timestamps --tail 10 --follow 2>&1",
14
+ (%(grep "#{grep}") if grep)
15
+ ),
16
+ host: host
17
+ end
18
+ end
@@ -1,34 +1,32 @@
1
1
  class Kamal::Commands::App < Kamal::Commands::Base
2
+ include Assets, Containers, Cord, Execution, Images, Logging
3
+
2
4
  ACTIVE_DOCKER_STATUSES = [ :running, :restarting ]
3
5
 
4
- attr_reader :role
6
+ attr_reader :role, :role_config
5
7
 
6
8
  def initialize(config, role: nil)
7
9
  super(config)
8
10
  @role = role
9
- end
10
-
11
- def start_or_run(hostname: nil)
12
- combine start, run(hostname: hostname), by: "||"
11
+ @role_config = config.role(self.role)
13
12
  end
14
13
 
15
14
  def run(hostname: nil)
16
- role = config.role(self.role)
17
-
18
15
  docker :run,
19
16
  "--detach",
20
17
  "--restart unless-stopped",
21
18
  "--name", container_name,
22
19
  *(["--hostname", hostname] if hostname),
23
20
  "-e", "KAMAL_CONTAINER_NAME=\"#{container_name}\"",
24
- *role.env_args,
25
- *role.health_check_args,
21
+ *role_config.env_args,
22
+ *role_config.health_check_args,
26
23
  *config.logging_args,
27
24
  *config.volume_args,
28
- *role.label_args,
29
- *role.option_args,
25
+ *role_config.asset_volume_args,
26
+ *role_config.label_args,
27
+ *role_config.option_args,
30
28
  config.absolute_image,
31
- role.cmd
29
+ role_config.cmd
32
30
  end
33
31
 
34
32
  def start
@@ -50,53 +48,6 @@ class Kamal::Commands::App < Kamal::Commands::Base
50
48
  end
51
49
 
52
50
 
53
- def logs(since: nil, lines: nil, grep: nil)
54
- pipe \
55
- current_running_container_id,
56
- "xargs docker logs#{" --since #{since}" if since}#{" --tail #{lines}" if lines} 2>&1",
57
- ("grep '#{grep}'" if grep)
58
- end
59
-
60
- def follow_logs(host:, grep: nil)
61
- run_over_ssh \
62
- pipe(
63
- current_running_container_id,
64
- "xargs docker logs --timestamps --tail 10 --follow 2>&1",
65
- (%(grep "#{grep}") if grep)
66
- ),
67
- host: host
68
- end
69
-
70
-
71
- def execute_in_existing_container(*command, interactive: false)
72
- docker :exec,
73
- ("-it" if interactive),
74
- container_name,
75
- *command
76
- end
77
-
78
- def execute_in_new_container(*command, interactive: false)
79
- role = config.role(self.role)
80
-
81
- docker :run,
82
- ("-it" if interactive),
83
- "--rm",
84
- *config.env_args,
85
- *config.volume_args,
86
- *role&.option_args,
87
- config.absolute_image,
88
- *command
89
- end
90
-
91
- def execute_in_existing_container_over_ssh(*command, host:)
92
- run_over_ssh execute_in_existing_container(*command, interactive: true), host: host
93
- end
94
-
95
- def execute_in_new_container_over_ssh(*command, host:)
96
- run_over_ssh execute_in_new_container(*command, interactive: true), host: host
97
- end
98
-
99
-
100
51
  def current_running_container_id
101
52
  docker :ps, "--quiet", *filter_args(statuses: ACTIVE_DOCKER_STATUSES), "--latest"
102
53
  end
@@ -112,47 +63,22 @@ class Kamal::Commands::App < Kamal::Commands::Base
112
63
  def list_versions(*docker_args, statuses: nil)
113
64
  pipe \
114
65
  docker(:ps, *filter_args(statuses: statuses), *docker_args, "--format", '"{{.Names}}"'),
115
- %(while read line; do echo ${line##{service_role_dest}-}; done) # Extract SHA from "service-role-dest-SHA"
116
- end
117
-
118
- def list_containers
119
- docker :container, :ls, "--all", *filter_args
120
- end
121
-
122
- def list_container_names
123
- [ *list_containers, "--format", "'{{ .Names }}'" ]
66
+ %(while read line; do echo ${line##{role_config.container_prefix}-}; done) # Extract SHA from "service-role-dest-SHA"
124
67
  end
125
68
 
126
- def remove_container(version:)
127
- pipe \
128
- container_id_for(container_name: container_name(version)),
129
- xargs(docker(:container, :rm))
130
- end
131
-
132
- def rename_container(version:, new_version:)
133
- docker :rename, container_name(version), container_name(new_version)
134
- end
135
-
136
- def remove_containers
137
- docker :container, :prune, "--force", *filter_args
138
- end
139
-
140
- def list_images
141
- docker :image, :ls, config.repository
142
- end
143
69
 
144
- def remove_images
145
- docker :image, :prune, "--all", "--force", *filter_args
70
+ def make_env_directory
71
+ make_directory role_config.host_env_directory
146
72
  end
147
73
 
148
- def tag_current_as_latest
149
- docker :tag, config.absolute_image, config.latest_image
74
+ def remove_env_file
75
+ [ :rm, "-f", role_config.host_env_file_path ]
150
76
  end
151
77
 
152
78
 
153
79
  private
154
80
  def container_name(version = nil)
155
- [ config.service, role, config.destination, version || config.version ].compact.join("-")
81
+ [ role_config.container_prefix, version || config.version ].compact.join("-")
156
82
  end
157
83
 
158
84
  def filter_args(statuses: nil)
@@ -160,7 +86,7 @@ class Kamal::Commands::App < Kamal::Commands::Base
160
86
  end
161
87
 
162
88
  def service_role_dest
163
- [config.service, role, config.destination].compact.join("-")
89
+ [ config.service, role, config.destination ].compact.join("-")
164
90
  end
165
91
 
166
92
  def filters(statuses: nil)
@@ -19,7 +19,9 @@ class Kamal::Commands::Auditor < Kamal::Commands::Base
19
19
 
20
20
  private
21
21
  def audit_log_file
22
- [ "kamal", config.service, config.destination, "audit.log" ].compact.join("-")
22
+ file = [ config.service, config.destination, "audit.log" ].compact.join("-")
23
+
24
+ "#{config.run_directory}/#{file}"
23
25
  end
24
26
 
25
27
  def audit_tags(**details)
@@ -26,6 +26,18 @@ module Kamal::Commands
26
26
  docker :container, :ls, *("--all" unless only_running), "--filter", "name=^#{container_name}$", "--quiet"
27
27
  end
28
28
 
29
+ def make_directory_for(remote_file)
30
+ make_directory Pathname.new(remote_file).dirname.to_s
31
+ end
32
+
33
+ def make_directory(path)
34
+ [ :mkdir, "-p", path ]
35
+ end
36
+
37
+ def remove_directory(path)
38
+ [ :rm, "-r", path ]
39
+ end
40
+
29
41
  private
30
42
  def combine(*commands, by: "&&")
31
43
  commands
@@ -21,6 +21,12 @@ class Kamal::Commands::Builder::Base < Kamal::Commands::Base
21
21
  config.builder.context
22
22
  end
23
23
 
24
+ def validate_image
25
+ pipe \
26
+ docker(:inspect, "-f", "'{{ .Config.Labels.service }}'", config.absolute_image),
27
+ [:grep, "-x", config.service, "||", "(echo \"Image #{config.absolute_image} is missing the `service` label\" && exit 1)"]
28
+ end
29
+
24
30
 
25
31
  private
26
32
  def build_tags
@@ -1,7 +1,7 @@
1
1
  require "active_support/core_ext/string/filters"
2
2
 
3
3
  class Kamal::Commands::Builder < Kamal::Commands::Base
4
- delegate :create, :remove, :push, :clean, :pull, :info, to: :target
4
+ delegate :create, :remove, :push, :clean, :pull, :info, :validate_image, to: :target
5
5
 
6
6
  def name
7
7
  target.class.to_s.remove("Kamal::Commands::Builder::").underscore.inquiry
@@ -1,5 +1,4 @@
1
1
  class Kamal::Commands::Healthcheck < Kamal::Commands::Base
2
- EXPOSED_PORT = 3999
3
2
 
4
3
  def run
5
4
  web = config.role(:web)
@@ -7,11 +6,11 @@ class Kamal::Commands::Healthcheck < Kamal::Commands::Base
7
6
  docker :run,
8
7
  "--detach",
9
8
  "--name", container_name_with_version,
10
- "--publish", "#{EXPOSED_PORT}:#{config.healthcheck["port"]}",
11
- "--label", "service=#{container_name}",
12
- "-e", "KAMAL_CONTAINER_NAME=\"#{container_name}\"",
9
+ "--publish", "#{exposed_port}:#{config.healthcheck["port"]}",
10
+ "--label", "service=#{config.healthcheck_service}",
11
+ "-e", "KAMAL_CONTAINER_NAME=\"#{config.healthcheck_service}\"",
13
12
  *web.env_args,
14
- *web.health_check_args,
13
+ *web.health_check_args(cord: false),
15
14
  *config.volume_args,
16
15
  *web.option_args,
17
16
  config.absolute_image,
@@ -27,7 +26,7 @@ class Kamal::Commands::Healthcheck < Kamal::Commands::Base
27
26
  end
28
27
 
29
28
  def logs
30
- pipe container_id, xargs(docker(:logs, "--tail", 50, "2>&1"))
29
+ pipe container_id, xargs(docker(:logs, "--tail", log_lines, "2>&1"))
31
30
  end
32
31
 
33
32
  def stop
@@ -39,12 +38,8 @@ class Kamal::Commands::Healthcheck < Kamal::Commands::Base
39
38
  end
40
39
 
41
40
  private
42
- def container_name
43
- [ "healthcheck", config.service, config.destination ].compact.join("-")
44
- end
45
-
46
41
  def container_name_with_version
47
- "#{container_name}-#{config.version}"
42
+ "#{config.healthcheck_service}-#{config.version}"
48
43
  end
49
44
 
50
45
  def container_id
@@ -52,6 +47,14 @@ class Kamal::Commands::Healthcheck < Kamal::Commands::Base
52
47
  end
53
48
 
54
49
  def health_url
55
- "http://localhost:#{EXPOSED_PORT}#{config.healthcheck["path"]}"
50
+ "http://localhost:#{exposed_port}#{config.healthcheck["path"]}"
51
+ end
52
+
53
+ def exposed_port
54
+ config.healthcheck["exposed_port"]
55
+ end
56
+
57
+ def log_lines
58
+ config.healthcheck["log_lines"]
56
59
  end
57
60
  end
@@ -40,7 +40,7 @@ class Kamal::Commands::Lock < Kamal::Commands::Base
40
40
  end
41
41
 
42
42
  def lock_dir
43
- "kamal_lock-#{config.service}"
43
+ "#{config.run_directory}/lock-#{config.service}"
44
44
  end
45
45
 
46
46
  def lock_details_file
@@ -56,7 +56,7 @@ class Kamal::Commands::Lock < Kamal::Commands::Base
56
56
  end
57
57
 
58
58
  def locked_by
59
- `git config user.name`.strip
59
+ Kamal::Git.user_name
60
60
  rescue Errno::ENOENT
61
61
  "Unknown"
62
62
  end
@@ -3,7 +3,7 @@ require "active_support/core_ext/numeric/time"
3
3
 
4
4
  class Kamal::Commands::Prune < Kamal::Commands::Base
5
5
  def dangling_images
6
- docker :image, :prune, "--force", "--filter", "label=service=#{config.service}", "--filter", "dangling=true"
6
+ docker :image, :prune, "--force", "--filter", "label=service=#{config.service}"
7
7
  end
8
8
 
9
9
  def tagged_images
@@ -13,13 +13,17 @@ 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 containers(keep_last: 5)
16
+ def app_containers(keep_last: 5)
17
17
  pipe \
18
18
  docker(:ps, "-q", "-a", *service_filter, *stopped_containers_filters),
19
19
  "tail -n +#{keep_last + 1}",
20
20
  "while read container_id; do docker rm $container_id; done"
21
21
  end
22
22
 
23
+ def healthcheck_containers
24
+ docker :container, :prune, "--force", *healthcheck_service_filter
25
+ end
26
+
23
27
  private
24
28
  def stopped_containers_filters
25
29
  [ "created", "exited", "dead" ].flat_map { |status| ["--filter", "status=#{status}"] }
@@ -35,4 +39,8 @@ class Kamal::Commands::Prune < Kamal::Commands::Base
35
39
  def service_filter
36
40
  [ "--filter", "label=service=#{config.service}" ]
37
41
  end
38
- end
42
+
43
+ def healthcheck_service_filter
44
+ [ "--filter", "label=service=#{config.healthcheck_service}" ]
45
+ end
46
+ end
@@ -0,0 +1,5 @@
1
+ class Kamal::Commands::Server < Kamal::Commands::Base
2
+ def ensure_run_directory
3
+ [:mkdir, "-p", config.run_directory]
4
+ end
5
+ end
@@ -1,5 +1,5 @@
1
1
  class Kamal::Commands::Traefik < Kamal::Commands::Base
2
- delegate :argumentize, :argumentize_env_with_secrets, :optionize, to: Kamal::Utils
2
+ delegate :argumentize, :optionize, to: Kamal::Utils
3
3
 
4
4
  DEFAULT_IMAGE = "traefik:v2.9"
5
5
  CONTAINER_PORT = 80
@@ -63,6 +63,22 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
63
63
  "#{host_port}:#{CONTAINER_PORT}"
64
64
  end
65
65
 
66
+ def env_file
67
+ Kamal::EnvFile.new(config.traefik.fetch("env", {}))
68
+ end
69
+
70
+ def host_env_file_path
71
+ File.join host_env_directory, "traefik.env"
72
+ end
73
+
74
+ def make_env_directory
75
+ make_directory(host_env_directory)
76
+ end
77
+
78
+ def remove_env_file
79
+ [:rm, "-f", host_env_file_path]
80
+ end
81
+
66
82
  private
67
83
  def publish_args
68
84
  argumentize "--publish", port unless config.traefik["publish"] == false
@@ -73,13 +89,11 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
73
89
  end
74
90
 
75
91
  def env_args
76
- env_config = config.traefik["env"] || {}
92
+ argumentize "--env-file", host_env_file_path
93
+ end
77
94
 
78
- if env_config.present?
79
- argumentize_env_with_secrets(env_config)
80
- else
81
- []
82
- end
95
+ def host_env_directory
96
+ File.join config.host_env_directory, "traefik"
83
97
  end
84
98
 
85
99
  def labels
@@ -1,5 +1,5 @@
1
1
  class Kamal::Configuration::Accessory
2
- delegate :argumentize, :argumentize_env_with_secrets, :optionize, to: Kamal::Utils
2
+ delegate :argumentize, :optionize, to: Kamal::Utils
3
3
 
4
4
  attr_accessor :name, :specifics
5
5
 
@@ -45,8 +45,20 @@ class Kamal::Configuration::Accessory
45
45
  specifics["env"] || {}
46
46
  end
47
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"
58
+ end
59
+
48
60
  def env_args
49
- argumentize_env_with_secrets env
61
+ argumentize "--env-file", host_env_file_path
50
62
  end
51
63
 
52
64
  def files
@@ -1,5 +1,6 @@
1
1
  class Kamal::Configuration::Role
2
- delegate :argumentize, :argumentize_env_with_secrets, :optionize, to: Kamal::Utils
2
+ CORD_FILE = "cord"
3
+ delegate :argumentize, :optionize, to: Kamal::Utils
3
4
 
4
5
  attr_accessor :name
5
6
 
@@ -15,6 +16,18 @@ class Kamal::Configuration::Role
15
16
  @hosts ||= extract_hosts_from_config
16
17
  end
17
18
 
19
+ def cmd
20
+ specializations["cmd"]
21
+ end
22
+
23
+ def option_args
24
+ if args = specializations["options"]
25
+ optionize args
26
+ else
27
+ []
28
+ end
29
+ end
30
+
18
31
  def labels
19
32
  default_labels.merge(traefik_labels).merge(custom_labels)
20
33
  end
@@ -23,6 +36,7 @@ class Kamal::Configuration::Role
23
36
  argumentize "--label", labels
24
37
  end
25
38
 
39
+
26
40
  def env
27
41
  if config.env && config.env["secret"]
28
42
  merged_env_with_secrets
@@ -31,46 +45,117 @@ class Kamal::Configuration::Role
31
45
  end
32
46
  end
33
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, "roles"
54
+ end
55
+
56
+ def host_env_file_path
57
+ File.join host_env_directory, "#{[config.service, name, config.destination].compact.join("-")}.env"
58
+ end
59
+
34
60
  def env_args
35
- argumentize_env_with_secrets env
61
+ argumentize "--env-file", host_env_file_path
62
+ end
63
+
64
+ def asset_volume_args
65
+ asset_volume&.docker_args
36
66
  end
37
67
 
38
- def health_check_args
68
+
69
+ def health_check_args(cord: true)
39
70
  if health_check_cmd.present?
40
- optionize({ "health-cmd" => health_check_cmd, "health-interval" => health_check_interval })
71
+ if cord && uses_cord?
72
+ optionize({ "health-cmd" => health_check_cmd_with_cord, "health-interval" => health_check_interval })
73
+ .concat(cord_volume.docker_args)
74
+ else
75
+ optionize({ "health-cmd" => health_check_cmd, "health-interval" => health_check_interval })
76
+ end
41
77
  else
42
78
  []
43
79
  end
44
80
  end
45
81
 
46
82
  def health_check_cmd
47
- options = specializations["healthcheck"] || {}
48
- options = config.healthcheck.merge(options) if running_traefik?
83
+ health_check_options["cmd"] || http_health_check(port: health_check_options["port"], path: health_check_options["path"])
84
+ end
49
85
 
50
- options["cmd"] || http_health_check(port: options["port"], path: options["path"])
86
+ def health_check_cmd_with_cord
87
+ "(#{health_check_cmd}) && (stat #{cord_container_file} > /dev/null || exit 1)"
51
88
  end
52
89
 
53
90
  def health_check_interval
54
- options = specializations["healthcheck"] || {}
55
- options = config.healthcheck.merge(options) if running_traefik?
91
+ health_check_options["interval"] || "1s"
92
+ end
93
+
56
94
 
57
- options["interval"] || "1s"
95
+ def running_traefik?
96
+ name.web? || specializations["traefik"]
58
97
  end
59
98
 
60
- def cmd
61
- specializations["cmd"]
99
+
100
+ def uses_cord?
101
+ running_traefik? && cord_volume && health_check_cmd.present?
62
102
  end
63
103
 
64
- def option_args
65
- if args = specializations["options"]
66
- optionize args
67
- else
68
- []
104
+ def cord_host_directory
105
+ File.join config.run_directory_as_docker_volume, "cords", [container_prefix, config.run_id].join("-")
106
+ end
107
+
108
+ def cord_volume
109
+ if (cord = health_check_options["cord"])
110
+ @cord_volume ||= Kamal::Configuration::Volume.new \
111
+ host_path: File.join(config.run_directory, "cords", [container_prefix, config.run_id].join("-")),
112
+ container_path: cord
69
113
  end
70
114
  end
71
115
 
72
- def running_traefik?
73
- name.web? || specializations["traefik"]
116
+ def cord_host_file
117
+ File.join cord_volume.host_path, CORD_FILE
118
+ end
119
+
120
+ def cord_container_directory
121
+ health_check_options.fetch("cord", nil)
122
+ end
123
+
124
+ def cord_container_file
125
+ File.join cord_volume.container_path, CORD_FILE
126
+ end
127
+
128
+
129
+ def container_name(version = nil)
130
+ [ container_prefix, version || config.version ].compact.join("-")
131
+ end
132
+
133
+ def container_prefix
134
+ [ config.service, name, config.destination ].compact.join("-")
135
+ end
136
+
137
+
138
+ def asset_path
139
+ specializations["asset_path"] || config.asset_path
140
+ end
141
+
142
+ def assets?
143
+ asset_path.present? && running_traefik?
144
+ end
145
+
146
+ def asset_volume(version = nil)
147
+ if assets?
148
+ Kamal::Configuration::Volume.new \
149
+ host_path: asset_volume_path(version), container_path: asset_path
150
+ end
151
+ end
152
+
153
+ def asset_extracted_path(version = nil)
154
+ File.join config.run_directory, "assets", "extracted", container_name(version)
155
+ end
156
+
157
+ def asset_volume_path(version = nil)
158
+ File.join config.run_directory, "assets", "volumes", container_name(version)
74
159
  end
75
160
 
76
161
  private
@@ -152,4 +237,12 @@ class Kamal::Configuration::Role
152
237
  def http_health_check(port:, path:)
153
238
  "curl -f #{URI.join("http://localhost:#{port}", path)} || exit 1" if path.present? || port.present?
154
239
  end
240
+
241
+ def health_check_options
242
+ @health_check_options ||= begin
243
+ options = specializations["healthcheck"] || {}
244
+ options = config.healthcheck.merge(options) if running_traefik?
245
+ options
246
+ end
247
+ end
155
248
  end
@@ -18,7 +18,7 @@ class Kamal::Configuration::Ssh
18
18
  end
19
19
 
20
20
  def options
21
- { user: user, proxy: proxy, auth_methods: [ "publickey" ], logger: logger, keepalive: true, keepalive_interval: 30 }.compact
21
+ { user: user, proxy: proxy, logger: logger, keepalive: true, keepalive_interval: 30 }.compact
22
22
  end
23
23
 
24
24
  def to_h