kamal 0.16.1 → 1.1.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/README.md +1 -1
- data/lib/kamal/cli/app.rb +44 -13
- data/lib/kamal/cli/base.rb +15 -2
- data/lib/kamal/cli/build.rb +18 -1
- data/lib/kamal/cli/env.rb +56 -0
- data/lib/kamal/cli/healthcheck/poller.rb +64 -0
- data/lib/kamal/cli/healthcheck.rb +2 -2
- data/lib/kamal/cli/lock.rb +12 -3
- data/lib/kamal/cli/main.rb +18 -4
- data/lib/kamal/cli/prune.rb +3 -2
- data/lib/kamal/cli/server.rb +2 -0
- data/lib/kamal/cli/templates/deploy.yml +12 -1
- data/lib/kamal/commander.rb +21 -8
- data/lib/kamal/commands/accessory.rb +8 -8
- data/lib/kamal/commands/app/assets.rb +51 -0
- data/lib/kamal/commands/app/containers.rb +23 -0
- data/lib/kamal/commands/app/cord.rb +22 -0
- data/lib/kamal/commands/app/execution.rb +27 -0
- data/lib/kamal/commands/app/images.rb +13 -0
- data/lib/kamal/commands/app/logging.rb +18 -0
- data/lib/kamal/commands/app.rb +18 -91
- data/lib/kamal/commands/auditor.rb +3 -1
- data/lib/kamal/commands/base.rb +12 -0
- data/lib/kamal/commands/builder/base.rb +6 -0
- data/lib/kamal/commands/builder.rb +1 -1
- data/lib/kamal/commands/docker.rb +1 -1
- data/lib/kamal/commands/healthcheck.rb +15 -12
- data/lib/kamal/commands/lock.rb +2 -2
- data/lib/kamal/commands/prune.rb +11 -3
- data/lib/kamal/commands/server.rb +5 -0
- data/lib/kamal/commands/traefik.rb +21 -7
- data/lib/kamal/configuration/accessory.rb +14 -2
- data/lib/kamal/configuration/role.rb +112 -19
- data/lib/kamal/configuration/ssh.rb +1 -1
- data/lib/kamal/configuration/volume.rb +22 -0
- data/lib/kamal/configuration.rb +73 -44
- data/lib/kamal/env_file.rb +41 -0
- data/lib/kamal/git.rb +19 -0
- data/lib/kamal/utils/sensitive.rb +1 -0
- data/lib/kamal/utils.rb +0 -39
- data/lib/kamal/version.rb +1 -1
- metadata +15 -4
- data/lib/kamal/utils/healthcheck_poller.rb +0 -39
@@ -1,5 +1,6 @@
|
|
1
1
|
class Kamal::Configuration::Role
|
2
|
-
|
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
|
-
|
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
|
-
|
68
|
+
|
69
|
+
def health_check_args(cord: true)
|
39
70
|
if health_check_cmd.present?
|
40
|
-
|
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
|
-
|
48
|
-
|
83
|
+
health_check_options["cmd"] || http_health_check(port: health_check_options["port"], path: health_check_options["path"])
|
84
|
+
end
|
49
85
|
|
50
|
-
|
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
|
-
|
55
|
-
|
91
|
+
health_check_options["interval"] || "1s"
|
92
|
+
end
|
93
|
+
|
56
94
|
|
57
|
-
|
95
|
+
def running_traefik?
|
96
|
+
name.web? || specializations["traefik"]
|
58
97
|
end
|
59
98
|
|
60
|
-
|
61
|
-
|
99
|
+
|
100
|
+
def uses_cord?
|
101
|
+
running_traefik? && cord_volume && health_check_cmd.present?
|
62
102
|
end
|
63
103
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
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
|
73
|
-
|
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,
|
21
|
+
{ user: user, proxy: proxy, logger: logger, keepalive: true, keepalive_interval: 30 }.compact
|
22
22
|
end
|
23
23
|
|
24
24
|
def to_h
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Kamal::Configuration::Volume
|
2
|
+
attr_reader :host_path, :container_path
|
3
|
+
delegate :argumentize, to: Kamal::Utils
|
4
|
+
|
5
|
+
def initialize(host_path:, container_path:)
|
6
|
+
@host_path = host_path
|
7
|
+
@container_path = container_path
|
8
|
+
end
|
9
|
+
|
10
|
+
def docker_args
|
11
|
+
argumentize "--volume", "#{host_path_for_docker_volume}:#{container_path}"
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
def host_path_for_docker_volume
|
16
|
+
if Pathname.new(host_path).absolute?
|
17
|
+
host_path
|
18
|
+
else
|
19
|
+
File.join "$(pwd)", host_path
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/kamal/configuration.rb
CHANGED
@@ -7,10 +7,9 @@ require "net/ssh/proxy/jump"
|
|
7
7
|
|
8
8
|
class Kamal::Configuration
|
9
9
|
delegate :service, :image, :servers, :env, :labels, :registry, :stop_wait_time, :hooks_path, to: :raw_config, allow_nil: true
|
10
|
-
delegate :argumentize, :
|
10
|
+
delegate :argumentize, :optionize, to: Kamal::Utils
|
11
11
|
|
12
|
-
|
13
|
-
attr_accessor :raw_config
|
12
|
+
attr_reader :destination, :raw_config
|
14
13
|
|
15
14
|
class << self
|
16
15
|
def create_from(config_file:, destination: nil, version: nil)
|
@@ -54,7 +53,18 @@ class Kamal::Configuration
|
|
54
53
|
end
|
55
54
|
|
56
55
|
def abbreviated_version
|
57
|
-
|
56
|
+
if version
|
57
|
+
# Don't abbreviate <sha>_uncommitted_<etc>
|
58
|
+
if version.include?("_")
|
59
|
+
version
|
60
|
+
else
|
61
|
+
version[0...7]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def minimum_version
|
67
|
+
raw_config.minimum_version
|
58
68
|
end
|
59
69
|
|
60
70
|
|
@@ -87,10 +97,6 @@ class Kamal::Configuration
|
|
87
97
|
roles.select(&:running_traefik?).flat_map(&:hosts).uniq
|
88
98
|
end
|
89
99
|
|
90
|
-
def boot
|
91
|
-
Kamal::Configuration::Boot.new(config: self)
|
92
|
-
end
|
93
|
-
|
94
100
|
|
95
101
|
def repository
|
96
102
|
[ raw_config.registry["server"], image ].compact.join("/")
|
@@ -108,15 +114,11 @@ class Kamal::Configuration
|
|
108
114
|
"#{service}-#{version}"
|
109
115
|
end
|
110
116
|
|
111
|
-
|
112
|
-
|
113
|
-
if raw_config.env.present?
|
114
|
-
argumentize_env_with_secrets(raw_config.env)
|
115
|
-
else
|
116
|
-
[]
|
117
|
-
end
|
117
|
+
def require_destination?
|
118
|
+
raw_config.require_destination
|
118
119
|
end
|
119
120
|
|
121
|
+
|
120
122
|
def volume_args
|
121
123
|
if raw_config.volumes.present?
|
122
124
|
argumentize "--volume", raw_config.volumes
|
@@ -135,6 +137,18 @@ class Kamal::Configuration
|
|
135
137
|
end
|
136
138
|
|
137
139
|
|
140
|
+
def boot
|
141
|
+
Kamal::Configuration::Boot.new(config: self)
|
142
|
+
end
|
143
|
+
|
144
|
+
def builder
|
145
|
+
Kamal::Configuration::Builder.new(config: self)
|
146
|
+
end
|
147
|
+
|
148
|
+
def traefik
|
149
|
+
raw_config.traefik || {}
|
150
|
+
end
|
151
|
+
|
138
152
|
def ssh
|
139
153
|
Kamal::Configuration::Ssh.new(config: self)
|
140
154
|
end
|
@@ -145,21 +159,50 @@ class Kamal::Configuration
|
|
145
159
|
|
146
160
|
|
147
161
|
def healthcheck
|
148
|
-
{ "path" => "/up", "port" => 3000, "max_attempts" => 7 }.merge(raw_config.healthcheck || {})
|
162
|
+
{ "path" => "/up", "port" => 3000, "max_attempts" => 7, "exposed_port" => 3999, "cord" => "/tmp/kamal-cord", "log_lines" => 50 }.merge(raw_config.healthcheck || {})
|
163
|
+
end
|
164
|
+
|
165
|
+
def healthcheck_service
|
166
|
+
[ "healthcheck", service, destination ].compact.join("-")
|
149
167
|
end
|
150
168
|
|
151
169
|
def readiness_delay
|
152
170
|
raw_config.readiness_delay || 7
|
153
171
|
end
|
154
172
|
|
155
|
-
def
|
156
|
-
|
173
|
+
def run_id
|
174
|
+
@run_id ||= SecureRandom.hex(16)
|
157
175
|
end
|
158
176
|
|
159
|
-
|
160
|
-
|
177
|
+
|
178
|
+
def run_directory
|
179
|
+
raw_config.run_directory || ".kamal"
|
180
|
+
end
|
181
|
+
|
182
|
+
def run_directory_as_docker_volume
|
183
|
+
if Pathname.new(run_directory).absolute?
|
184
|
+
run_directory
|
185
|
+
else
|
186
|
+
File.join "$(pwd)", run_directory
|
187
|
+
end
|
161
188
|
end
|
162
189
|
|
190
|
+
def hooks_path
|
191
|
+
raw_config.hooks_path || ".kamal/hooks"
|
192
|
+
end
|
193
|
+
|
194
|
+
def host_env_directory
|
195
|
+
"#{run_directory}/env"
|
196
|
+
end
|
197
|
+
|
198
|
+
def asset_path
|
199
|
+
raw_config.asset_path
|
200
|
+
end
|
201
|
+
|
202
|
+
|
203
|
+
def valid?
|
204
|
+
ensure_destination_if_required && ensure_required_keys_present && ensure_valid_kamal_version
|
205
|
+
end
|
163
206
|
|
164
207
|
def to_h
|
165
208
|
{
|
@@ -170,7 +213,6 @@ class Kamal::Configuration
|
|
170
213
|
repository: repository,
|
171
214
|
absolute_image: absolute_image,
|
172
215
|
service_with_version: service_with_version,
|
173
|
-
env_args: env_args,
|
174
216
|
volume_args: volume_args,
|
175
217
|
ssh_options: ssh.to_h,
|
176
218
|
sshkit: sshkit.to_h,
|
@@ -181,28 +223,17 @@ class Kamal::Configuration
|
|
181
223
|
}.compact
|
182
224
|
end
|
183
225
|
|
184
|
-
def traefik
|
185
|
-
raw_config.traefik || {}
|
186
|
-
end
|
187
|
-
|
188
|
-
def hooks_path
|
189
|
-
raw_config.hooks_path || ".kamal/hooks"
|
190
|
-
end
|
191
|
-
|
192
|
-
def builder
|
193
|
-
Kamal::Configuration::Builder.new(config: self)
|
194
|
-
end
|
195
|
-
|
196
|
-
# Will raise KeyError if any secret ENVs are missing
|
197
|
-
def ensure_env_available
|
198
|
-
env_args
|
199
|
-
roles.each(&:env_args)
|
200
|
-
|
201
|
-
true
|
202
|
-
end
|
203
226
|
|
204
227
|
private
|
205
228
|
# Will raise ArgumentError if any required config keys are missing
|
229
|
+
def ensure_destination_if_required
|
230
|
+
if require_destination? && destination.nil?
|
231
|
+
raise ArgumentError, "You must specify a destination"
|
232
|
+
end
|
233
|
+
|
234
|
+
true
|
235
|
+
end
|
236
|
+
|
206
237
|
def ensure_required_keys_present
|
207
238
|
%i[ service image registry servers ].each do |key|
|
208
239
|
raise ArgumentError, "Missing required configuration for #{key}" unless raw_config[key].present?
|
@@ -240,10 +271,8 @@ class Kamal::Configuration
|
|
240
271
|
|
241
272
|
def git_version
|
242
273
|
@git_version ||=
|
243
|
-
if
|
244
|
-
|
245
|
-
|
246
|
-
"#{`git rev-parse HEAD`.strip}#{uncommitted_suffix}"
|
274
|
+
if Kamal::Git.used?
|
275
|
+
[ Kamal::Git.revision, Kamal::Git.uncommitted_changes.present? ? "_uncommitted_#{SecureRandom.hex(8)}" : "" ].join
|
247
276
|
else
|
248
277
|
raise "Can't use commit hash as version, no git repository found in #{Dir.pwd}"
|
249
278
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# Encode an env hash as a string where secret values have been looked up and all values escaped for Docker.
|
2
|
+
class Kamal::EnvFile
|
3
|
+
def initialize(env)
|
4
|
+
@env = env
|
5
|
+
end
|
6
|
+
|
7
|
+
def to_s
|
8
|
+
env_file = StringIO.new.tap do |contents|
|
9
|
+
if (secrets = @env["secret"]).present?
|
10
|
+
@env.fetch("secret", @env)&.each do |key|
|
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
|
21
|
+
end
|
22
|
+
end.string
|
23
|
+
|
24
|
+
# Ensure the file has some contents to avoid the SSHKIT empty file warning
|
25
|
+
env_file.presence || "\n"
|
26
|
+
end
|
27
|
+
|
28
|
+
alias to_str to_s
|
29
|
+
|
30
|
+
private
|
31
|
+
def docker_env_file_line(key, value)
|
32
|
+
"#{key.to_s}=#{escape_docker_env_file_value(value)}\n"
|
33
|
+
end
|
34
|
+
|
35
|
+
# Escape a value to make it safe to dump in a docker file.
|
36
|
+
def escape_docker_env_file_value(value)
|
37
|
+
# Doublequotes are treated literally in docker env files
|
38
|
+
# so remove leading and trailing ones and unescape any others
|
39
|
+
value.to_s.dump[1..-2].gsub(/\\"/, "\"")
|
40
|
+
end
|
41
|
+
end
|
data/lib/kamal/git.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Kamal::Git
|
2
|
+
extend self
|
3
|
+
|
4
|
+
def used?
|
5
|
+
system("git rev-parse")
|
6
|
+
end
|
7
|
+
|
8
|
+
def user_name
|
9
|
+
`git config user.name`.strip
|
10
|
+
end
|
11
|
+
|
12
|
+
def revision
|
13
|
+
`git rev-parse HEAD`.strip
|
14
|
+
end
|
15
|
+
|
16
|
+
def uncommitted_changes
|
17
|
+
`git status --porcelain`.strip
|
18
|
+
end
|
19
|
+
end
|
data/lib/kamal/utils.rb
CHANGED
@@ -16,16 +16,6 @@ module Kamal::Utils
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
# Return a list of shell arguments using the same named argument against the passed attributes,
|
20
|
-
# but redacts and expands secrets.
|
21
|
-
def argumentize_env_with_secrets(env)
|
22
|
-
if (secrets = env["secret"]).present?
|
23
|
-
argumentize("-e", secrets.to_h { |key| [ key, ENV.fetch(key) ] }, sensitive: true) + argumentize("-e", env["clear"])
|
24
|
-
else
|
25
|
-
argumentize "-e", env.fetch("clear", env)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
19
|
# Returns a list of shell-dashed option arguments. If the value is true, it's treated like a value-less option.
|
30
20
|
def optionize(args, with: nil)
|
31
21
|
options = if with
|
@@ -62,39 +52,10 @@ module Kamal::Utils
|
|
62
52
|
end
|
63
53
|
end
|
64
54
|
|
65
|
-
def unredacted(value)
|
66
|
-
case
|
67
|
-
when value.respond_to?(:unredacted)
|
68
|
-
value.unredacted
|
69
|
-
when value.respond_to?(:transform_values)
|
70
|
-
value.transform_values { |value| unredacted value }
|
71
|
-
when value.respond_to?(:map)
|
72
|
-
value.map { |element| unredacted element }
|
73
|
-
else
|
74
|
-
value
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
55
|
# Escape a value to make it safe for shell use.
|
79
56
|
def escape_shell_value(value)
|
80
57
|
value.to_s.dump
|
81
58
|
.gsub(/`/, '\\\\`')
|
82
59
|
.gsub(DOLLAR_SIGN_WITHOUT_SHELL_EXPANSION_REGEX, '\$')
|
83
60
|
end
|
84
|
-
|
85
|
-
# Abbreviate a git revhash for concise display
|
86
|
-
def abbreviate_version(version)
|
87
|
-
if version
|
88
|
-
# Don't abbreviate <sha>_uncommitted_<etc>
|
89
|
-
if version.include?("_")
|
90
|
-
version
|
91
|
-
else
|
92
|
-
version[0...7]
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def uncommitted_changes
|
98
|
-
`git status --porcelain`.strip
|
99
|
-
end
|
100
61
|
end
|
data/lib/kamal/version.rb
CHANGED
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:
|
4
|
+
version: 1.1.0
|
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: 2023-
|
11
|
+
date: 2023-11-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -194,7 +194,9 @@ files:
|
|
194
194
|
- lib/kamal/cli/app.rb
|
195
195
|
- lib/kamal/cli/base.rb
|
196
196
|
- lib/kamal/cli/build.rb
|
197
|
+
- lib/kamal/cli/env.rb
|
197
198
|
- lib/kamal/cli/healthcheck.rb
|
199
|
+
- lib/kamal/cli/healthcheck/poller.rb
|
198
200
|
- lib/kamal/cli/lock.rb
|
199
201
|
- lib/kamal/cli/main.rb
|
200
202
|
- lib/kamal/cli/prune.rb
|
@@ -211,6 +213,12 @@ files:
|
|
211
213
|
- lib/kamal/commands.rb
|
212
214
|
- lib/kamal/commands/accessory.rb
|
213
215
|
- lib/kamal/commands/app.rb
|
216
|
+
- lib/kamal/commands/app/assets.rb
|
217
|
+
- lib/kamal/commands/app/containers.rb
|
218
|
+
- lib/kamal/commands/app/cord.rb
|
219
|
+
- lib/kamal/commands/app/execution.rb
|
220
|
+
- lib/kamal/commands/app/images.rb
|
221
|
+
- lib/kamal/commands/app/logging.rb
|
214
222
|
- lib/kamal/commands/auditor.rb
|
215
223
|
- lib/kamal/commands/base.rb
|
216
224
|
- lib/kamal/commands/builder.rb
|
@@ -226,6 +234,7 @@ files:
|
|
226
234
|
- lib/kamal/commands/lock.rb
|
227
235
|
- lib/kamal/commands/prune.rb
|
228
236
|
- lib/kamal/commands/registry.rb
|
237
|
+
- lib/kamal/commands/server.rb
|
229
238
|
- lib/kamal/commands/traefik.rb
|
230
239
|
- lib/kamal/configuration.rb
|
231
240
|
- lib/kamal/configuration/accessory.rb
|
@@ -234,10 +243,12 @@ files:
|
|
234
243
|
- lib/kamal/configuration/role.rb
|
235
244
|
- lib/kamal/configuration/ssh.rb
|
236
245
|
- lib/kamal/configuration/sshkit.rb
|
246
|
+
- lib/kamal/configuration/volume.rb
|
247
|
+
- lib/kamal/env_file.rb
|
248
|
+
- lib/kamal/git.rb
|
237
249
|
- lib/kamal/sshkit_with_ext.rb
|
238
250
|
- lib/kamal/tags.rb
|
239
251
|
- lib/kamal/utils.rb
|
240
|
-
- lib/kamal/utils/healthcheck_poller.rb
|
241
252
|
- lib/kamal/utils/sensitive.rb
|
242
253
|
- lib/kamal/version.rb
|
243
254
|
homepage: https://github.com/basecamp/kamal
|
@@ -259,7 +270,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
259
270
|
- !ruby/object:Gem::Version
|
260
271
|
version: '0'
|
261
272
|
requirements: []
|
262
|
-
rubygems_version: 3.4.
|
273
|
+
rubygems_version: 3.4.21
|
263
274
|
signing_key:
|
264
275
|
specification_version: 4
|
265
276
|
summary: Deploy web apps in containers to servers running Docker with zero downtime.
|
@@ -1,39 +0,0 @@
|
|
1
|
-
class Kamal::Utils::HealthcheckPoller
|
2
|
-
TRAEFIK_HEALTHY_DELAY = 2
|
3
|
-
|
4
|
-
class HealthcheckError < StandardError; end
|
5
|
-
|
6
|
-
class << self
|
7
|
-
def wait_for_healthy(pause_after_ready: false, &block)
|
8
|
-
attempt = 1
|
9
|
-
max_attempts = KAMAL.config.healthcheck["max_attempts"]
|
10
|
-
|
11
|
-
begin
|
12
|
-
case status = block.call
|
13
|
-
when "healthy"
|
14
|
-
sleep TRAEFIK_HEALTHY_DELAY if pause_after_ready
|
15
|
-
when "running" # No health check configured
|
16
|
-
sleep KAMAL.config.readiness_delay if pause_after_ready
|
17
|
-
else
|
18
|
-
raise HealthcheckError, "container not ready (#{status})"
|
19
|
-
end
|
20
|
-
rescue HealthcheckError => e
|
21
|
-
if attempt <= max_attempts
|
22
|
-
info "#{e.message}, retrying in #{attempt}s (attempt #{attempt}/#{max_attempts})..."
|
23
|
-
sleep attempt
|
24
|
-
attempt += 1
|
25
|
-
retry
|
26
|
-
else
|
27
|
-
raise
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
info "Container is healthy!"
|
32
|
-
end
|
33
|
-
|
34
|
-
private
|
35
|
-
def info(message)
|
36
|
-
SSHKit.config.output.info(message)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|