kamal 1.5.2 → 1.7.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/lib/kamal/cli/accessory.rb +30 -24
- data/lib/kamal/cli/app/boot.rb +70 -18
- data/lib/kamal/cli/app/prepare_assets.rb +1 -1
- data/lib/kamal/cli/app.rb +60 -47
- data/lib/kamal/cli/base.rb +26 -28
- data/lib/kamal/cli/build/clone.rb +61 -0
- data/lib/kamal/cli/build.rb +64 -53
- data/lib/kamal/cli/env.rb +5 -5
- data/lib/kamal/cli/healthcheck/barrier.rb +31 -0
- data/lib/kamal/cli/healthcheck/error.rb +2 -0
- data/lib/kamal/cli/healthcheck/poller.rb +6 -7
- data/lib/kamal/cli/main.rb +49 -44
- data/lib/kamal/cli/prune.rb +3 -3
- data/lib/kamal/cli/registry.rb +9 -10
- data/lib/kamal/cli/server.rb +39 -15
- data/lib/kamal/cli/templates/sample_hooks/docker-setup.sample +1 -1
- data/lib/kamal/cli/traefik.rb +13 -11
- data/lib/kamal/cli.rb +1 -1
- data/lib/kamal/commander.rb +6 -6
- data/lib/kamal/commands/accessory.rb +4 -4
- data/lib/kamal/commands/app/containers.rb +8 -0
- data/lib/kamal/commands/app/execution.rb +3 -3
- data/lib/kamal/commands/app/logging.rb +5 -5
- data/lib/kamal/commands/app.rb +6 -5
- data/lib/kamal/commands/base.rb +2 -3
- data/lib/kamal/commands/builder/base.rb +19 -12
- data/lib/kamal/commands/builder/clone.rb +28 -0
- data/lib/kamal/commands/builder/multiarch/remote.rb +10 -0
- data/lib/kamal/commands/builder/multiarch.rb +13 -9
- data/lib/kamal/commands/builder/native/cached.rb +14 -6
- data/lib/kamal/commands/builder/native/remote.rb +17 -9
- data/lib/kamal/commands/builder/native.rb +6 -7
- data/lib/kamal/commands/builder.rb +19 -11
- data/lib/kamal/commands/registry.rb +4 -13
- data/lib/kamal/commands/traefik.rb +8 -47
- data/lib/kamal/configuration/accessory.rb +30 -41
- data/lib/kamal/configuration/boot.rb +9 -4
- data/lib/kamal/configuration/builder.rb +61 -30
- data/lib/kamal/configuration/docs/accessory.yml +90 -0
- data/lib/kamal/configuration/docs/boot.yml +19 -0
- data/lib/kamal/configuration/docs/builder.yml +107 -0
- data/lib/kamal/configuration/docs/configuration.yml +157 -0
- data/lib/kamal/configuration/docs/env.yml +72 -0
- data/lib/kamal/configuration/docs/healthcheck.yml +59 -0
- data/lib/kamal/configuration/docs/logging.yml +21 -0
- data/lib/kamal/configuration/docs/registry.yml +49 -0
- data/lib/kamal/configuration/docs/role.yml +52 -0
- data/lib/kamal/configuration/docs/servers.yml +27 -0
- data/lib/kamal/configuration/docs/ssh.yml +46 -0
- data/lib/kamal/configuration/docs/sshkit.yml +23 -0
- data/lib/kamal/configuration/docs/traefik.yml +62 -0
- data/lib/kamal/configuration/env/tag.rb +12 -0
- data/lib/kamal/configuration/env.rb +10 -14
- data/lib/kamal/configuration/healthcheck.rb +63 -0
- data/lib/kamal/configuration/logging.rb +33 -0
- data/lib/kamal/configuration/registry.rb +31 -0
- data/lib/kamal/configuration/role.rb +72 -61
- data/lib/kamal/configuration/servers.rb +18 -0
- data/lib/kamal/configuration/ssh.rb +11 -8
- data/lib/kamal/configuration/sshkit.rb +9 -7
- data/lib/kamal/configuration/traefik.rb +60 -0
- data/lib/kamal/configuration/validation.rb +27 -0
- data/lib/kamal/configuration/validator/accessory.rb +9 -0
- data/lib/kamal/configuration/validator/builder.rb +9 -0
- data/lib/kamal/configuration/validator/env.rb +54 -0
- data/lib/kamal/configuration/validator/registry.rb +25 -0
- data/lib/kamal/configuration/validator/role.rb +11 -0
- data/lib/kamal/configuration/validator/servers.rb +7 -0
- data/lib/kamal/configuration/validator.rb +140 -0
- data/lib/kamal/configuration.rb +50 -63
- data/lib/kamal/git.rb +4 -0
- data/lib/kamal/sshkit_with_ext.rb +36 -0
- data/lib/kamal/version.rb +1 -1
- data/lib/kamal.rb +2 -0
- metadata +64 -9
- data/lib/kamal/cli/healthcheck.rb +0 -21
- data/lib/kamal/commands/healthcheck.rb +0 -59
@@ -0,0 +1,140 @@
|
|
1
|
+
class Kamal::Configuration::Validator
|
2
|
+
attr_reader :config, :example, :context
|
3
|
+
|
4
|
+
def initialize(config, example:, context:)
|
5
|
+
@config = config
|
6
|
+
@example = example
|
7
|
+
@context = context
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate!
|
11
|
+
validate_against_example! config, example
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
def validate_against_example!(validation_config, example)
|
16
|
+
validate_type! validation_config, Hash
|
17
|
+
|
18
|
+
if (unknown_keys = validation_config.keys - example.keys).any?
|
19
|
+
unknown_keys_error unknown_keys
|
20
|
+
end
|
21
|
+
|
22
|
+
validation_config.each do |key, value|
|
23
|
+
with_context(key) do
|
24
|
+
example_value = example[key]
|
25
|
+
|
26
|
+
if example_value == "..."
|
27
|
+
validate_type! value, *(Array if key == :servers), Hash
|
28
|
+
elsif key == "hosts"
|
29
|
+
validate_servers! value
|
30
|
+
elsif example_value.is_a?(Array)
|
31
|
+
validate_array_of! value, example_value.first.class
|
32
|
+
elsif example_value.is_a?(Hash)
|
33
|
+
case key.to_s
|
34
|
+
when "options"
|
35
|
+
validate_type! value, Hash
|
36
|
+
when "args", "labels"
|
37
|
+
validate_hash_of! value, example_value.first[1].class
|
38
|
+
else
|
39
|
+
validate_against_example! value, example_value
|
40
|
+
end
|
41
|
+
else
|
42
|
+
validate_type! value, example_value.class
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
def valid_type?(value, type)
|
50
|
+
value.is_a?(type) ||
|
51
|
+
(type == String && stringish?(value)) ||
|
52
|
+
(boolean?(type) && boolean?(value.class))
|
53
|
+
end
|
54
|
+
|
55
|
+
def type_description(type)
|
56
|
+
if type == Integer || type == Array
|
57
|
+
"an #{type.name.downcase}"
|
58
|
+
elsif type == TrueClass || type == FalseClass
|
59
|
+
"a boolean"
|
60
|
+
else
|
61
|
+
"a #{type.name.downcase}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def boolean?(type)
|
66
|
+
type == TrueClass || type == FalseClass
|
67
|
+
end
|
68
|
+
|
69
|
+
def stringish?(value)
|
70
|
+
value.is_a?(String) || value.is_a?(Symbol) || value.is_a?(Numeric) || value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
71
|
+
end
|
72
|
+
|
73
|
+
def validate_array_of!(array, type)
|
74
|
+
validate_type! array, Array
|
75
|
+
|
76
|
+
array.each_with_index do |value, index|
|
77
|
+
with_context(index) do
|
78
|
+
validate_type! value, type
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def validate_hash_of!(hash, type)
|
84
|
+
validate_type! hash, Hash
|
85
|
+
|
86
|
+
hash.each do |key, value|
|
87
|
+
with_context(key) do
|
88
|
+
validate_type! value, type
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def validate_servers!(servers)
|
94
|
+
validate_type! servers, Array
|
95
|
+
|
96
|
+
servers.each_with_index do |server, index|
|
97
|
+
with_context(index) do
|
98
|
+
validate_type! server, String, Hash
|
99
|
+
|
100
|
+
if server.is_a?(Hash)
|
101
|
+
error "multiple hosts found" unless server.size == 1
|
102
|
+
host, tags = server.first
|
103
|
+
|
104
|
+
with_context(host) do
|
105
|
+
validate_type! tags, String, Array
|
106
|
+
validate_array_of! tags, String if tags.is_a?(Array)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def validate_type!(value, *types)
|
114
|
+
type_error(*types) unless types.any? { |type| valid_type?(value, type) }
|
115
|
+
end
|
116
|
+
|
117
|
+
def error(message)
|
118
|
+
raise Kamal::ConfigurationError, "#{error_context}#{message}"
|
119
|
+
end
|
120
|
+
|
121
|
+
def type_error(*expected_types)
|
122
|
+
error "should be #{expected_types.map { |type| type_description(type) }.join(" or ")}"
|
123
|
+
end
|
124
|
+
|
125
|
+
def unknown_keys_error(unknown_keys)
|
126
|
+
error "unknown #{"key".pluralize(unknown_keys.count)}: #{unknown_keys.join(", ")}"
|
127
|
+
end
|
128
|
+
|
129
|
+
def error_context
|
130
|
+
"#{context}: " if context.present?
|
131
|
+
end
|
132
|
+
|
133
|
+
def with_context(context)
|
134
|
+
old_context = @context
|
135
|
+
@context = [ @context, context ].select(&:present?).join("/")
|
136
|
+
yield
|
137
|
+
ensure
|
138
|
+
@context = old_context
|
139
|
+
end
|
140
|
+
end
|
data/lib/kamal/configuration.rb
CHANGED
@@ -1,15 +1,19 @@
|
|
1
1
|
require "active_support/ordered_options"
|
2
2
|
require "active_support/core_ext/string/inquiry"
|
3
3
|
require "active_support/core_ext/module/delegation"
|
4
|
+
require "active_support/core_ext/hash/keys"
|
4
5
|
require "pathname"
|
5
6
|
require "erb"
|
6
7
|
require "net/ssh/proxy/jump"
|
7
8
|
|
8
9
|
class Kamal::Configuration
|
9
|
-
delegate :service, :image, :
|
10
|
+
delegate :service, :image, :labels, :stop_wait_time, :hooks_path, to: :raw_config, allow_nil: true
|
10
11
|
delegate :argumentize, :optionize, to: Kamal::Utils
|
11
12
|
|
12
13
|
attr_reader :destination, :raw_config
|
14
|
+
attr_reader :accessories, :boot, :builder, :env, :healthcheck, :logging, :traefik, :servers, :ssh, :sshkit, :registry
|
15
|
+
|
16
|
+
include Validation
|
13
17
|
|
14
18
|
class << self
|
15
19
|
def create_from(config_file:, destination: nil, version: nil)
|
@@ -42,7 +46,29 @@ class Kamal::Configuration
|
|
42
46
|
@raw_config = ActiveSupport::InheritableOptions.new(raw_config)
|
43
47
|
@destination = destination
|
44
48
|
@declared_version = version
|
45
|
-
|
49
|
+
|
50
|
+
validate! raw_config, example: validation_yml.symbolize_keys, context: ""
|
51
|
+
|
52
|
+
# Eager load config to validate it, these are first as they have dependencies later on
|
53
|
+
@servers = Servers.new(config: self)
|
54
|
+
@registry = Registry.new(config: self)
|
55
|
+
|
56
|
+
@accessories = @raw_config.accessories&.keys&.collect { |name| Accessory.new(name, config: self) } || []
|
57
|
+
@boot = Boot.new(config: self)
|
58
|
+
@builder = Builder.new(config: self)
|
59
|
+
@env = Env.new(config: @raw_config.env || {})
|
60
|
+
|
61
|
+
@healthcheck = Healthcheck.new(healthcheck_config: @raw_config.healthcheck)
|
62
|
+
@logging = Logging.new(logging_config: @raw_config.logging)
|
63
|
+
@traefik = Traefik.new(config: self)
|
64
|
+
@ssh = Ssh.new(config: self)
|
65
|
+
@sshkit = Sshkit.new(config: self)
|
66
|
+
|
67
|
+
ensure_destination_if_required
|
68
|
+
ensure_required_keys_present
|
69
|
+
ensure_valid_kamal_version
|
70
|
+
ensure_retain_containers_valid
|
71
|
+
ensure_valid_service_name
|
46
72
|
end
|
47
73
|
|
48
74
|
|
@@ -71,17 +97,13 @@ class Kamal::Configuration
|
|
71
97
|
|
72
98
|
|
73
99
|
def roles
|
74
|
-
|
100
|
+
servers.roles
|
75
101
|
end
|
76
102
|
|
77
103
|
def role(name)
|
78
104
|
roles.detect { |r| r.name == name.to_s }
|
79
105
|
end
|
80
106
|
|
81
|
-
def accessories
|
82
|
-
@accessories ||= raw_config.accessories&.keys&.collect { |name| Kamal::Configuration::Accessory.new(name, config: self) } || []
|
83
|
-
end
|
84
|
-
|
85
107
|
def accessory(name)
|
86
108
|
accessories.detect { |a| a.name == name.to_s }
|
87
109
|
end
|
@@ -120,7 +142,7 @@ class Kamal::Configuration
|
|
120
142
|
end
|
121
143
|
|
122
144
|
def repository
|
123
|
-
[
|
145
|
+
[ registry.server, image ].compact.join("/")
|
124
146
|
end
|
125
147
|
|
126
148
|
def absolute_image
|
@@ -157,39 +179,9 @@ class Kamal::Configuration
|
|
157
179
|
end
|
158
180
|
|
159
181
|
def logging_args
|
160
|
-
|
161
|
-
optionize({ "log-driver" => logging["driver"] }.compact) +
|
162
|
-
argumentize("--log-opt", logging["options"])
|
163
|
-
else
|
164
|
-
argumentize("--log-opt", { "max-size" => "10m" })
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
|
169
|
-
def boot
|
170
|
-
Kamal::Configuration::Boot.new(config: self)
|
182
|
+
logging.args
|
171
183
|
end
|
172
184
|
|
173
|
-
def builder
|
174
|
-
Kamal::Configuration::Builder.new(config: self)
|
175
|
-
end
|
176
|
-
|
177
|
-
def traefik
|
178
|
-
raw_config.traefik || {}
|
179
|
-
end
|
180
|
-
|
181
|
-
def ssh
|
182
|
-
Kamal::Configuration::Ssh.new(config: self)
|
183
|
-
end
|
184
|
-
|
185
|
-
def sshkit
|
186
|
-
Kamal::Configuration::Sshkit.new(config: self)
|
187
|
-
end
|
188
|
-
|
189
|
-
|
190
|
-
def healthcheck
|
191
|
-
{ "path" => "/up", "port" => 3000, "max_attempts" => 7, "exposed_port" => 3999, "cord" => "/tmp/kamal-cord", "log_lines" => 50 }.merge(raw_config.healthcheck || {})
|
192
|
-
end
|
193
185
|
|
194
186
|
def healthcheck_service
|
195
187
|
[ "healthcheck", service, destination ].compact.join("-")
|
@@ -229,15 +221,19 @@ class Kamal::Configuration
|
|
229
221
|
File.join(run_directory, "env")
|
230
222
|
end
|
231
223
|
|
232
|
-
def
|
233
|
-
raw_config.env
|
224
|
+
def env_tags
|
225
|
+
@env_tags ||= if (tags = raw_config.env["tags"])
|
226
|
+
tags.collect { |name, config| Env::Tag.new(name, config: config) }
|
227
|
+
else
|
228
|
+
[]
|
229
|
+
end
|
234
230
|
end
|
235
231
|
|
236
|
-
|
237
|
-
|
238
|
-
ensure_destination_if_required && ensure_required_keys_present && ensure_valid_kamal_version && ensure_retain_containers_valid && ensure_valid_service_name
|
232
|
+
def env_tag(name)
|
233
|
+
env_tags.detect { |t| t.name == name.to_s }
|
239
234
|
end
|
240
235
|
|
236
|
+
|
241
237
|
def to_h
|
242
238
|
{
|
243
239
|
roles: role_names,
|
@@ -253,11 +249,10 @@ class Kamal::Configuration
|
|
253
249
|
builder: builder.to_h,
|
254
250
|
accessories: raw_config.accessories,
|
255
251
|
logging: logging_args,
|
256
|
-
healthcheck: healthcheck
|
252
|
+
healthcheck: healthcheck.to_h
|
257
253
|
}.compact
|
258
254
|
end
|
259
255
|
|
260
|
-
|
261
256
|
private
|
262
257
|
# Will raise ArgumentError if any required config keys are missing
|
263
258
|
def ensure_destination_if_required
|
@@ -270,29 +265,21 @@ class Kamal::Configuration
|
|
270
265
|
|
271
266
|
def ensure_required_keys_present
|
272
267
|
%i[ service image registry servers ].each do |key|
|
273
|
-
raise
|
274
|
-
end
|
275
|
-
|
276
|
-
if raw_config.registry["username"].blank?
|
277
|
-
raise ArgumentError, "You must specify a username for the registry in config/deploy.yml"
|
278
|
-
end
|
279
|
-
|
280
|
-
if raw_config.registry["password"].blank?
|
281
|
-
raise ArgumentError, "You must specify a password for the registry in config/deploy.yml (or set the ENV variable if that's used)"
|
268
|
+
raise Kamal::ConfigurationError, "Missing required configuration for #{key}" unless raw_config[key].present?
|
282
269
|
end
|
283
270
|
|
284
|
-
unless
|
285
|
-
raise
|
271
|
+
unless role(primary_role_name).present?
|
272
|
+
raise Kamal::ConfigurationError, "The primary_role #{primary_role_name} isn't defined"
|
286
273
|
end
|
287
274
|
|
288
275
|
if primary_role.hosts.empty?
|
289
|
-
raise
|
276
|
+
raise Kamal::ConfigurationError, "No servers specified for the #{primary_role.name} primary_role"
|
290
277
|
end
|
291
278
|
|
292
279
|
unless allow_empty_roles?
|
293
280
|
roles.each do |role|
|
294
281
|
if role.hosts.empty?
|
295
|
-
raise
|
282
|
+
raise Kamal::ConfigurationError, "No servers specified for the #{role.name} role. You can ignore this with allow_empty_roles: true"
|
296
283
|
end
|
297
284
|
end
|
298
285
|
end
|
@@ -301,21 +288,21 @@ class Kamal::Configuration
|
|
301
288
|
end
|
302
289
|
|
303
290
|
def ensure_valid_service_name
|
304
|
-
raise
|
291
|
+
raise Kamal::ConfigurationError, "Service name can only include alphanumeric characters, hyphens, and underscores" unless raw_config[:service] =~ /^[a-z0-9_-]+$/i
|
305
292
|
|
306
293
|
true
|
307
294
|
end
|
308
295
|
|
309
296
|
def ensure_valid_kamal_version
|
310
297
|
if minimum_version && Gem::Version.new(minimum_version) > Gem::Version.new(Kamal::VERSION)
|
311
|
-
raise
|
298
|
+
raise Kamal::ConfigurationError, "Current version is #{Kamal::VERSION}, minimum required is #{minimum_version}"
|
312
299
|
end
|
313
300
|
|
314
301
|
true
|
315
302
|
end
|
316
303
|
|
317
304
|
def ensure_retain_containers_valid
|
318
|
-
raise
|
305
|
+
raise Kamal::ConfigurationError, "Must retain at least 1 container" if retain_containers < 1
|
319
306
|
|
320
307
|
true
|
321
308
|
end
|
@@ -328,7 +315,7 @@ class Kamal::Configuration
|
|
328
315
|
def git_version
|
329
316
|
@git_version ||=
|
330
317
|
if Kamal::Git.used?
|
331
|
-
if Kamal::Git.uncommitted_changes.present? && !builder.
|
318
|
+
if Kamal::Git.uncommitted_changes.present? && !builder.git_clone?
|
332
319
|
uncommitted_suffix = "_uncommitted_#{SecureRandom.hex(8)}"
|
333
320
|
end
|
334
321
|
[ Kamal::Git.revision, uncommitted_suffix ].compact.join
|
data/lib/kamal/git.rb
CHANGED
@@ -103,3 +103,39 @@ class SSHKit::Backend::Netssh
|
|
103
103
|
|
104
104
|
prepend LimitConcurrentStartsInstance
|
105
105
|
end
|
106
|
+
|
107
|
+
class SSHKit::Runner::Parallel
|
108
|
+
# SSHKit joins the threads in sequence and fails on the first error it encounters, which means that we wait threads
|
109
|
+
# before the first failure to complete but not for ones after.
|
110
|
+
#
|
111
|
+
# We'll patch it to wait for them all to complete, and to record all the threads that errored so we can see when a
|
112
|
+
# problem occurs on multiple hosts.
|
113
|
+
module CompleteAll
|
114
|
+
def execute
|
115
|
+
threads = hosts.map do |host|
|
116
|
+
Thread.new(host) do |h|
|
117
|
+
backend(h, &block).run
|
118
|
+
rescue ::StandardError => e
|
119
|
+
e2 = SSHKit::Runner::ExecuteError.new e
|
120
|
+
raise e2, "Exception while executing #{host.user ? "as #{host.user}@" : "on host "}#{host}: #{e.message}"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
exceptions = []
|
125
|
+
threads.each do |t|
|
126
|
+
begin
|
127
|
+
t.join
|
128
|
+
rescue SSHKit::Runner::ExecuteError => e
|
129
|
+
exceptions << e
|
130
|
+
end
|
131
|
+
end
|
132
|
+
if exceptions.one?
|
133
|
+
raise exceptions.first
|
134
|
+
elsif exceptions.many?
|
135
|
+
raise exceptions.first, [ "Exceptions on #{exceptions.count} hosts:", exceptions.map(&:message) ].join("\n")
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
prepend CompleteAll
|
141
|
+
end
|
data/lib/kamal/version.rb
CHANGED
data/lib/kamal.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: 1.
|
4
|
+
version: 1.7.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: 2024-
|
11
|
+
date: 2024-06-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -28,16 +28,22 @@ dependencies:
|
|
28
28
|
name: sshkit
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.22.2
|
34
|
+
- - "<"
|
32
35
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
36
|
+
version: '2.0'
|
34
37
|
type: :runtime
|
35
38
|
prerelease: false
|
36
39
|
version_requirements: !ruby/object:Gem::Requirement
|
37
40
|
requirements:
|
38
|
-
- - "
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.22.2
|
44
|
+
- - "<"
|
39
45
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
46
|
+
version: '2.0'
|
41
47
|
- !ruby/object:Gem::Dependency
|
42
48
|
name: net-ssh
|
43
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +114,26 @@ dependencies:
|
|
108
114
|
- - "~>"
|
109
115
|
- !ruby/object:Gem::Version
|
110
116
|
version: '1.2'
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: x25519
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - "~>"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '1.0'
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: 1.0.10
|
127
|
+
type: :runtime
|
128
|
+
prerelease: false
|
129
|
+
version_requirements: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - "~>"
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '1.0'
|
134
|
+
- - ">="
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: 1.0.10
|
111
137
|
- !ruby/object:Gem::Dependency
|
112
138
|
name: bcrypt_pbkdf
|
113
139
|
requirement: !ruby/object:Gem::Requirement
|
@@ -210,8 +236,10 @@ files:
|
|
210
236
|
- lib/kamal/cli/app/prepare_assets.rb
|
211
237
|
- lib/kamal/cli/base.rb
|
212
238
|
- lib/kamal/cli/build.rb
|
239
|
+
- lib/kamal/cli/build/clone.rb
|
213
240
|
- lib/kamal/cli/env.rb
|
214
|
-
- lib/kamal/cli/healthcheck.rb
|
241
|
+
- lib/kamal/cli/healthcheck/barrier.rb
|
242
|
+
- lib/kamal/cli/healthcheck/error.rb
|
215
243
|
- lib/kamal/cli/healthcheck/poller.rb
|
216
244
|
- lib/kamal/cli/lock.rb
|
217
245
|
- lib/kamal/cli/main.rb
|
@@ -243,13 +271,13 @@ files:
|
|
243
271
|
- lib/kamal/commands/base.rb
|
244
272
|
- lib/kamal/commands/builder.rb
|
245
273
|
- lib/kamal/commands/builder/base.rb
|
274
|
+
- lib/kamal/commands/builder/clone.rb
|
246
275
|
- lib/kamal/commands/builder/multiarch.rb
|
247
276
|
- lib/kamal/commands/builder/multiarch/remote.rb
|
248
277
|
- lib/kamal/commands/builder/native.rb
|
249
278
|
- lib/kamal/commands/builder/native/cached.rb
|
250
279
|
- lib/kamal/commands/builder/native/remote.rb
|
251
280
|
- lib/kamal/commands/docker.rb
|
252
|
-
- lib/kamal/commands/healthcheck.rb
|
253
281
|
- lib/kamal/commands/hook.rb
|
254
282
|
- lib/kamal/commands/lock.rb
|
255
283
|
- lib/kamal/commands/prune.rb
|
@@ -260,10 +288,37 @@ files:
|
|
260
288
|
- lib/kamal/configuration/accessory.rb
|
261
289
|
- lib/kamal/configuration/boot.rb
|
262
290
|
- lib/kamal/configuration/builder.rb
|
291
|
+
- lib/kamal/configuration/docs/accessory.yml
|
292
|
+
- lib/kamal/configuration/docs/boot.yml
|
293
|
+
- lib/kamal/configuration/docs/builder.yml
|
294
|
+
- lib/kamal/configuration/docs/configuration.yml
|
295
|
+
- lib/kamal/configuration/docs/env.yml
|
296
|
+
- lib/kamal/configuration/docs/healthcheck.yml
|
297
|
+
- lib/kamal/configuration/docs/logging.yml
|
298
|
+
- lib/kamal/configuration/docs/registry.yml
|
299
|
+
- lib/kamal/configuration/docs/role.yml
|
300
|
+
- lib/kamal/configuration/docs/servers.yml
|
301
|
+
- lib/kamal/configuration/docs/ssh.yml
|
302
|
+
- lib/kamal/configuration/docs/sshkit.yml
|
303
|
+
- lib/kamal/configuration/docs/traefik.yml
|
263
304
|
- lib/kamal/configuration/env.rb
|
305
|
+
- lib/kamal/configuration/env/tag.rb
|
306
|
+
- lib/kamal/configuration/healthcheck.rb
|
307
|
+
- lib/kamal/configuration/logging.rb
|
308
|
+
- lib/kamal/configuration/registry.rb
|
264
309
|
- lib/kamal/configuration/role.rb
|
310
|
+
- lib/kamal/configuration/servers.rb
|
265
311
|
- lib/kamal/configuration/ssh.rb
|
266
312
|
- lib/kamal/configuration/sshkit.rb
|
313
|
+
- lib/kamal/configuration/traefik.rb
|
314
|
+
- lib/kamal/configuration/validation.rb
|
315
|
+
- lib/kamal/configuration/validator.rb
|
316
|
+
- lib/kamal/configuration/validator/accessory.rb
|
317
|
+
- lib/kamal/configuration/validator/builder.rb
|
318
|
+
- lib/kamal/configuration/validator/env.rb
|
319
|
+
- lib/kamal/configuration/validator/registry.rb
|
320
|
+
- lib/kamal/configuration/validator/role.rb
|
321
|
+
- lib/kamal/configuration/validator/servers.rb
|
267
322
|
- lib/kamal/configuration/volume.rb
|
268
323
|
- lib/kamal/env_file.rb
|
269
324
|
- lib/kamal/git.rb
|
@@ -291,7 +346,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
291
346
|
- !ruby/object:Gem::Version
|
292
347
|
version: '0'
|
293
348
|
requirements: []
|
294
|
-
rubygems_version: 3.5.
|
349
|
+
rubygems_version: 3.5.11
|
295
350
|
signing_key:
|
296
351
|
specification_version: 4
|
297
352
|
summary: Deploy web apps in containers to servers running Docker with zero downtime.
|
@@ -1,21 +0,0 @@
|
|
1
|
-
class Kamal::Cli::Healthcheck < Kamal::Cli::Base
|
2
|
-
default_command :perform
|
3
|
-
|
4
|
-
desc "perform", "Health check current app version"
|
5
|
-
def perform
|
6
|
-
raise "The primary host is not configured to run Traefik" unless KAMAL.config.role(KAMAL.config.primary_role).running_traefik?
|
7
|
-
on(KAMAL.primary_host) do
|
8
|
-
begin
|
9
|
-
execute *KAMAL.healthcheck.run
|
10
|
-
Poller.wait_for_healthy { capture_with_info(*KAMAL.healthcheck.status) }
|
11
|
-
rescue Poller::HealthcheckError => e
|
12
|
-
error capture_with_info(*KAMAL.healthcheck.logs)
|
13
|
-
error capture_with_pretty_json(*KAMAL.healthcheck.container_health_log)
|
14
|
-
raise
|
15
|
-
ensure
|
16
|
-
execute *KAMAL.healthcheck.stop, raise_on_non_zero_exit: false
|
17
|
-
execute *KAMAL.healthcheck.remove, raise_on_non_zero_exit: false
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,59 +0,0 @@
|
|
1
|
-
class Kamal::Commands::Healthcheck < Kamal::Commands::Base
|
2
|
-
def run
|
3
|
-
primary = config.role(config.primary_role)
|
4
|
-
|
5
|
-
docker :run,
|
6
|
-
"--detach",
|
7
|
-
"--name", container_name_with_version,
|
8
|
-
"--publish", "#{exposed_port}:#{config.healthcheck["port"]}",
|
9
|
-
"--label", "service=#{config.healthcheck_service}",
|
10
|
-
"-e", "KAMAL_CONTAINER_NAME=\"#{config.healthcheck_service}\"",
|
11
|
-
*primary.env_args,
|
12
|
-
*primary.health_check_args(cord: false),
|
13
|
-
*config.volume_args,
|
14
|
-
*primary.option_args,
|
15
|
-
config.absolute_image,
|
16
|
-
primary.cmd
|
17
|
-
end
|
18
|
-
|
19
|
-
def status
|
20
|
-
pipe container_id, xargs(docker(:inspect, "--format", DOCKER_HEALTH_STATUS_FORMAT))
|
21
|
-
end
|
22
|
-
|
23
|
-
def container_health_log
|
24
|
-
pipe container_id, xargs(docker(:inspect, "--format", DOCKER_HEALTH_LOG_FORMAT))
|
25
|
-
end
|
26
|
-
|
27
|
-
def logs
|
28
|
-
pipe container_id, xargs(docker(:logs, "--tail", log_lines, "2>&1"))
|
29
|
-
end
|
30
|
-
|
31
|
-
def stop
|
32
|
-
pipe container_id, xargs(docker(:stop))
|
33
|
-
end
|
34
|
-
|
35
|
-
def remove
|
36
|
-
pipe container_id, xargs(docker(:container, :rm))
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
def container_name_with_version
|
41
|
-
"#{config.healthcheck_service}-#{config.version}"
|
42
|
-
end
|
43
|
-
|
44
|
-
def container_id
|
45
|
-
container_id_for(container_name: container_name_with_version)
|
46
|
-
end
|
47
|
-
|
48
|
-
def health_url
|
49
|
-
"http://localhost:#{exposed_port}#{config.healthcheck["path"]}"
|
50
|
-
end
|
51
|
-
|
52
|
-
def exposed_port
|
53
|
-
config.healthcheck["exposed_port"]
|
54
|
-
end
|
55
|
-
|
56
|
-
def log_lines
|
57
|
-
config.healthcheck["log_lines"]
|
58
|
-
end
|
59
|
-
end
|