dash 3.1.5 → 3.2.1
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 +26 -6
- data/bin/dash +2 -2
- data/lib/{kamal → dash}/cli/accessory.rb +24 -24
- data/lib/dash/cli/alias/command.rb +10 -0
- data/lib/{kamal → dash}/cli/app/assets.rb +2 -2
- data/lib/{kamal → dash}/cli/app/boot.rb +15 -15
- data/lib/{kamal → dash}/cli/app/error_pages.rb +6 -6
- data/lib/{kamal → dash}/cli/app/rollout_boot.rb +6 -6
- data/lib/{kamal → dash}/cli/app/ssl_certificates.rb +3 -3
- data/lib/{kamal → dash}/cli/app.rb +87 -87
- data/lib/{kamal → dash}/cli/base.rb +73 -49
- data/lib/dash/cli/build/clone.rb +59 -0
- data/lib/{kamal → dash}/cli/build/port_forwarding.rb +1 -1
- data/lib/{kamal → dash}/cli/build.rb +45 -45
- data/lib/{kamal → dash}/cli/doctor/config_checks.rb +3 -3
- data/lib/{kamal → dash}/cli/doctor/endpoint_checks.rb +25 -7
- data/lib/{kamal → dash}/cli/doctor/host_checks.rb +23 -23
- data/lib/{kamal → dash}/cli/doctor.rb +9 -9
- data/lib/{kamal → dash}/cli/healthcheck/barrier.rb +2 -2
- data/lib/{kamal → dash}/cli/healthcheck/drift_error.rb +2 -2
- data/lib/dash/cli/healthcheck/error.rb +2 -0
- data/lib/{kamal → dash}/cli/healthcheck/poller.rb +7 -7
- data/lib/{kamal → dash}/cli/lock.rb +1 -1
- data/lib/dash/cli/main/migrate.rb +77 -0
- data/lib/{kamal → dash}/cli/main.rb +87 -76
- data/lib/{kamal → dash}/cli/proxy/drift.rb +4 -4
- data/lib/{kamal → dash}/cli/proxy/loadbalancer_claim.rb +6 -6
- data/lib/{kamal → dash}/cli/proxy/loadbalancer_reboot.rb +23 -23
- data/lib/{kamal → dash}/cli/proxy/reboot.rb +15 -15
- data/lib/{kamal → dash}/cli/proxy.rb +172 -160
- data/lib/{kamal → dash}/cli/prune.rb +10 -10
- data/lib/{kamal → dash}/cli/registry.rb +13 -13
- data/lib/{kamal → dash}/cli/secrets.rb +3 -3
- data/lib/{kamal → dash}/cli/server.rb +15 -15
- data/lib/{kamal → dash}/cli/templates/deploy.yml +6 -6
- data/lib/dash/cli/templates/sample_hooks/docker-setup.sample +3 -0
- data/lib/dash/cli/templates/sample_hooks/post-app-boot.sample +3 -0
- data/lib/dash/cli/templates/sample_hooks/post-app-stop.sample +9 -0
- data/lib/dash/cli/templates/sample_hooks/post-deploy.sample +14 -0
- data/lib/dash/cli/templates/sample_hooks/post-proxy-deploy.sample +3 -0
- data/lib/dash/cli/templates/sample_hooks/post-proxy-reboot.sample +3 -0
- data/lib/dash/cli/templates/sample_hooks/pre-app-boot.sample +3 -0
- data/lib/{kamal → dash}/cli/templates/sample_hooks/pre-app-stop.sample +2 -2
- data/lib/{kamal → dash}/cli/templates/sample_hooks/pre-build.sample +8 -8
- data/lib/{kamal → dash}/cli/templates/sample_hooks/pre-connect.sample +8 -8
- data/lib/{kamal → dash}/cli/templates/sample_hooks/pre-deploy.sample +9 -9
- data/lib/dash/cli/templates/sample_hooks/pre-proxy-deploy.sample +3 -0
- data/lib/dash/cli/templates/sample_hooks/pre-proxy-reboot.sample +3 -0
- data/lib/dash/cli/templates/secrets +22 -0
- data/lib/{kamal → dash}/cli.rb +2 -2
- data/lib/{kamal → dash}/commander/specifics.rb +2 -2
- data/lib/{kamal → dash}/commander.rb +31 -23
- data/lib/{kamal → dash}/commands/accessory/proxy.rb +1 -1
- data/lib/{kamal → dash}/commands/accessory.rb +2 -2
- data/lib/{kamal → dash}/commands/app/assets.rb +1 -1
- data/lib/{kamal → dash}/commands/app/containers.rb +1 -1
- data/lib/{kamal → dash}/commands/app/error_pages.rb +2 -2
- data/lib/{kamal → dash}/commands/app/execution.rb +1 -1
- data/lib/{kamal → dash}/commands/app/images.rb +1 -1
- data/lib/{kamal → dash}/commands/app/logging.rb +1 -1
- data/lib/{kamal → dash}/commands/app/proxy.rb +1 -1
- data/lib/{kamal → dash}/commands/app.rb +1 -1
- data/lib/{kamal → dash}/commands/auditor.rb +3 -7
- data/lib/{kamal → dash}/commands/base.rb +39 -3
- data/lib/{kamal → dash}/commands/builder/base.rb +2 -2
- data/lib/{kamal → dash}/commands/builder/clone.rb +3 -3
- data/lib/{kamal → dash}/commands/builder/cloud.rb +1 -1
- data/lib/{kamal → dash}/commands/builder/hybrid.rb +1 -1
- data/lib/{kamal → dash}/commands/builder/local.rb +1 -1
- data/lib/{kamal → dash}/commands/builder/pack.rb +1 -1
- data/lib/{kamal → dash}/commands/builder/remote.rb +1 -1
- data/lib/{kamal → dash}/commands/builder.rb +7 -7
- data/lib/{kamal → dash}/commands/docker.rb +1 -1
- data/lib/{kamal → dash}/commands/hook.rb +1 -1
- data/lib/{kamal → dash}/commands/loadbalancer.rb +9 -8
- data/lib/{kamal → dash}/commands/lock.rb +2 -2
- data/lib/{kamal → dash}/commands/proxy/cert_transfer.rb +3 -3
- data/lib/{kamal → dash}/commands/proxy.rb +20 -10
- data/lib/{kamal → dash}/commands/prune.rb +1 -1
- data/lib/dash/commands/registry.rb +44 -0
- data/lib/{kamal → dash}/commands/server.rb +1 -5
- data/lib/dash/commands.rb +2 -0
- data/lib/{kamal → dash}/configuration/accessory.rb +11 -11
- data/lib/{kamal → dash}/configuration/alias.rb +3 -3
- data/lib/{kamal → dash}/configuration/boot.rb +2 -2
- data/lib/{kamal → dash}/configuration/builder.rb +7 -7
- data/lib/{kamal → dash}/configuration/docs/accessory.yml +6 -6
- data/lib/{kamal → dash}/configuration/docs/alias.yml +2 -2
- data/lib/{kamal → dash}/configuration/docs/boot.yml +1 -1
- data/lib/{kamal → dash}/configuration/docs/builder.yml +3 -3
- data/lib/{kamal → dash}/configuration/docs/configuration.yml +25 -18
- data/lib/{kamal → dash}/configuration/docs/env.yml +17 -17
- data/lib/{kamal → dash}/configuration/docs/proxy.yml +53 -30
- data/lib/{kamal → dash}/configuration/docs/registry.yml +6 -6
- data/lib/{kamal → dash}/configuration/docs/role.yml +1 -1
- data/lib/{kamal → dash}/configuration/docs/servers.yml +2 -2
- data/lib/{kamal → dash}/configuration/env/tag.rb +2 -2
- data/lib/{kamal → dash}/configuration/env.rb +5 -5
- data/lib/{kamal → dash}/configuration/loadbalancer.rb +3 -3
- data/lib/{kamal → dash}/configuration/logging.rb +3 -3
- data/lib/{kamal → dash}/configuration/output.rb +4 -4
- data/lib/{kamal → dash}/configuration/proxy/acme.rb +4 -3
- data/lib/{kamal → dash}/configuration/proxy/boot.rb +10 -8
- data/lib/{kamal → dash}/configuration/proxy/run.rb +14 -14
- data/lib/{kamal → dash}/configuration/proxy.rb +16 -16
- data/lib/{kamal → dash}/configuration/registry.rb +3 -3
- data/lib/{kamal → dash}/configuration/role/healthcheck.rb +3 -3
- data/lib/{kamal → dash}/configuration/role.rb +13 -13
- data/lib/{kamal → dash}/configuration/servers.rb +4 -4
- data/lib/{kamal → dash}/configuration/ssh.rb +3 -3
- data/lib/{kamal → dash}/configuration/sshkit.rb +2 -2
- data/lib/{kamal → dash}/configuration/validation.rb +2 -2
- data/lib/{kamal → dash}/configuration/validator/accessory.rb +1 -1
- data/lib/{kamal → dash}/configuration/validator/alias.rb +2 -2
- data/lib/{kamal → dash}/configuration/validator/builder.rb +1 -1
- data/lib/dash/configuration/validator/configuration.rb +6 -0
- data/lib/{kamal → dash}/configuration/validator/env.rb +2 -2
- data/lib/{kamal → dash}/configuration/validator/proxy.rb +8 -8
- data/lib/{kamal → dash}/configuration/validator/registry.rb +1 -1
- data/lib/{kamal → dash}/configuration/validator/role.rb +1 -1
- data/lib/{kamal → dash}/configuration/validator/servers.rb +1 -1
- data/lib/{kamal → dash}/configuration/validator.rb +4 -4
- data/lib/{kamal → dash}/configuration/volume.rb +2 -2
- data/lib/{kamal → dash}/configuration.rb +40 -30
- data/lib/{kamal → dash}/docker.rb +1 -1
- data/lib/{kamal → dash}/env_file.rb +1 -1
- data/lib/{kamal → dash}/git.rb +1 -1
- data/lib/{kamal → dash}/otel_shipper.rb +3 -3
- data/lib/{kamal → dash}/output/base_logger.rb +1 -1
- data/lib/{kamal → dash}/output/file_logger.rb +1 -1
- data/lib/{kamal → dash}/output/formatter.rb +1 -1
- data/lib/{kamal → dash}/output/otel_logger.rb +3 -3
- data/lib/dash/project_directory.rb +28 -0
- data/lib/{kamal → dash}/secrets/adapters/aws_secrets_manager.rb +1 -1
- data/lib/{kamal → dash}/secrets/adapters/base.rb +2 -2
- data/lib/{kamal → dash}/secrets/adapters/bitwarden.rb +1 -1
- data/lib/{kamal → dash}/secrets/adapters/bitwarden_secrets_manager.rb +1 -1
- data/lib/{kamal → dash}/secrets/adapters/doppler.rb +1 -1
- data/lib/{kamal → dash}/secrets/adapters/enpass.rb +3 -3
- data/lib/{kamal → dash}/secrets/adapters/gcp_secret_manager.rb +1 -1
- data/lib/{kamal → dash}/secrets/adapters/last_pass.rb +1 -1
- data/lib/{kamal → dash}/secrets/adapters/one_password.rb +2 -2
- data/lib/{kamal → dash}/secrets/adapters/passbolt.rb +1 -1
- data/lib/{kamal → dash}/secrets/adapters/test.rb +1 -1
- data/lib/{kamal → dash}/secrets/adapters.rb +2 -2
- data/lib/{kamal → dash}/secrets/dotenv/inline_command_substitution.rb +5 -3
- data/lib/{kamal → dash}/secrets.rb +6 -6
- data/lib/{kamal → dash}/tags.rb +8 -3
- data/lib/{kamal → dash}/utils/sensitive.rb +1 -1
- data/lib/{kamal → dash}/utils.rb +15 -5
- data/lib/dash/version.rb +3 -0
- data/lib/{kamal.rb → dash.rb} +5 -5
- metadata +171 -216
- data/bin/kamal +0 -18
- data/lib/kamal/cli/alias/command.rb +0 -10
- data/lib/kamal/cli/build/clone.rb +0 -59
- data/lib/kamal/cli/healthcheck/error.rb +0 -2
- data/lib/kamal/cli/templates/sample_hooks/docker-setup.sample +0 -3
- data/lib/kamal/cli/templates/sample_hooks/post-app-boot.sample +0 -3
- data/lib/kamal/cli/templates/sample_hooks/post-app-stop.sample +0 -9
- data/lib/kamal/cli/templates/sample_hooks/post-deploy.sample +0 -14
- data/lib/kamal/cli/templates/sample_hooks/post-proxy-deploy.sample +0 -3
- data/lib/kamal/cli/templates/sample_hooks/post-proxy-reboot.sample +0 -3
- data/lib/kamal/cli/templates/sample_hooks/pre-app-boot.sample +0 -3
- data/lib/kamal/cli/templates/sample_hooks/pre-proxy-deploy.sample +0 -3
- data/lib/kamal/cli/templates/sample_hooks/pre-proxy-reboot.sample +0 -3
- data/lib/kamal/cli/templates/secrets +0 -22
- data/lib/kamal/commands/registry.rb +0 -38
- data/lib/kamal/commands.rb +0 -2
- data/lib/kamal/configuration/validator/configuration.rb +0 -6
- data/lib/kamal/version.rb +0 -3
- /data/lib/{kamal → dash}/configuration/docs/logging.yml +0 -0
- /data/lib/{kamal → dash}/configuration/docs/output.yml +0 -0
- /data/lib/{kamal → dash}/configuration/docs/ssh.yml +0 -0
- /data/lib/{kamal → dash}/configuration/docs/sshkit.yml +0 -0
- /data/lib/{kamal → dash}/sshkit_with_ext.rb +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class
|
|
1
|
+
class Dash::Configuration::Validator
|
|
2
2
|
attr_reader :config, :example, :context
|
|
3
3
|
|
|
4
4
|
def initialize(config, example:, context:)
|
|
@@ -91,7 +91,7 @@ class Kamal::Configuration::Validator
|
|
|
91
91
|
else
|
|
92
92
|
validate_type! value, type
|
|
93
93
|
end
|
|
94
|
-
rescue
|
|
94
|
+
rescue Dash::ConfigurationError
|
|
95
95
|
type_error(Array, type)
|
|
96
96
|
end
|
|
97
97
|
|
|
@@ -187,7 +187,7 @@ class Kamal::Configuration::Validator
|
|
|
187
187
|
end
|
|
188
188
|
|
|
189
189
|
def error(message)
|
|
190
|
-
raise
|
|
190
|
+
raise Dash::ConfigurationError, "#{error_context}#{message}"
|
|
191
191
|
end
|
|
192
192
|
|
|
193
193
|
def type_error(*expected_types)
|
|
@@ -245,7 +245,7 @@ class Kamal::Configuration::Validator
|
|
|
245
245
|
validate_health_option_expansion!(options)
|
|
246
246
|
end
|
|
247
247
|
|
|
248
|
-
#
|
|
248
|
+
# Dash::Utils::DOLLAR_SIGN_WITHOUT_SHELL_EXPANSION_REGEX escapes a bare `$` but exempts
|
|
249
249
|
# `${...}`, leaving it for the deploy host's shell to expand at docker run time. Role env
|
|
250
250
|
# never reaches that shell, so `${SOME_ENV}` in a health command silently becomes empty and
|
|
251
251
|
# the container sits `starting` until deploy_timeout. Reject it where it is most likely written.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
class
|
|
1
|
+
class Dash::Configuration::Volume
|
|
2
2
|
attr_reader :host_path, :container_path, :options
|
|
3
|
-
delegate :argumentize, to:
|
|
3
|
+
delegate :argumentize, to: Dash::Utils
|
|
4
4
|
|
|
5
5
|
def initialize(host_path:, container_path:, options: nil)
|
|
6
6
|
@host_path = host_path
|
|
@@ -5,11 +5,15 @@ require "active_support/core_ext/hash/keys"
|
|
|
5
5
|
require "erb"
|
|
6
6
|
require "net/ssh/proxy/jump"
|
|
7
7
|
|
|
8
|
-
class
|
|
8
|
+
class Dash::Configuration
|
|
9
9
|
HOOKS_OUTPUT_LEVELS = [ :quiet, :verbose ].freeze
|
|
10
10
|
|
|
11
|
+
# The pre-3b name of #run_directory. Referenced only by the one-shot host
|
|
12
|
+
# migration in Dash::Commands::Base; nothing reads paths under it.
|
|
13
|
+
LEGACY_RUN_DIRECTORY = ".kamal"
|
|
14
|
+
|
|
11
15
|
delegate :service, :labels, :hooks_path, to: :raw_config, allow_nil: true
|
|
12
|
-
delegate :argumentize, :optionize, to:
|
|
16
|
+
delegate :argumentize, :optionize, to: Dash::Utils
|
|
13
17
|
|
|
14
18
|
attr_reader :destination, :raw_config, :secrets
|
|
15
19
|
attr_reader :accessories, :aliases, :boot, :builder, :env, :logging, :output, :proxy, :proxy_boot, :servers, :ssh, :sshkit, :registry
|
|
@@ -18,7 +22,7 @@ class Kamal::Configuration
|
|
|
18
22
|
|
|
19
23
|
class << self
|
|
20
24
|
def create_from(config_file:, destination: nil, version: nil)
|
|
21
|
-
ENV["KAMAL_DESTINATION"] = destination
|
|
25
|
+
ENV["DASH_DESTINATION"] = ENV["KAMAL_DESTINATION"] = destination
|
|
22
26
|
|
|
23
27
|
raw_config = load_raw_config(config_file: config_file, destination: destination)
|
|
24
28
|
|
|
@@ -56,9 +60,9 @@ class Kamal::Configuration
|
|
|
56
60
|
@destination = destination
|
|
57
61
|
@declared_version = version
|
|
58
62
|
|
|
59
|
-
validate! raw_config, example: validation_yml.symbolize_keys, context: "", with:
|
|
63
|
+
validate! raw_config, example: validation_yml.symbolize_keys, context: "", with: Dash::Configuration::Validator::Configuration
|
|
60
64
|
|
|
61
|
-
@secrets =
|
|
65
|
+
@secrets = Dash::Secrets.new(destination: destination, secrets_path: secrets_path)
|
|
62
66
|
|
|
63
67
|
# Eager load config to validate it, these are first as they have dependencies later on
|
|
64
68
|
@servers = Servers.new(config: self)
|
|
@@ -292,8 +296,14 @@ class Kamal::Configuration
|
|
|
292
296
|
raw_config.stop_timeout
|
|
293
297
|
end
|
|
294
298
|
|
|
299
|
+
# Where dash keeps its per-host state - app env and assets, the proxy's
|
|
300
|
+
# options/image/run_command files and apps-config bind mount, loadbalancer
|
|
301
|
+
# service claims, deploy locks and the audit log - under the SSH user's home.
|
|
302
|
+
# Renamed from `.kamal` in stage 3b of the server artifact rename
|
|
303
|
+
# (zoolutions/dash#118); hosts still on the old name are migrated in place by
|
|
304
|
+
# Dash::Commands::Base#ensure_run_directory.
|
|
295
305
|
def run_directory
|
|
296
|
-
".
|
|
306
|
+
".dash"
|
|
297
307
|
end
|
|
298
308
|
|
|
299
309
|
def apps_directory
|
|
@@ -313,11 +323,11 @@ class Kamal::Configuration
|
|
|
313
323
|
end
|
|
314
324
|
|
|
315
325
|
def hooks_path
|
|
316
|
-
raw_config.hooks_path || "
|
|
326
|
+
raw_config.hooks_path || Dash::ProjectDirectory.join("hooks")
|
|
317
327
|
end
|
|
318
328
|
|
|
319
329
|
def secrets_path
|
|
320
|
-
raw_config.secrets_path || "
|
|
330
|
+
raw_config.secrets_path || Dash::ProjectDirectory.join("secrets")
|
|
321
331
|
end
|
|
322
332
|
|
|
323
333
|
def asset_path
|
|
@@ -379,26 +389,26 @@ class Kamal::Configuration
|
|
|
379
389
|
|
|
380
390
|
def ensure_required_keys_present
|
|
381
391
|
%i[ service registry ].each do |key|
|
|
382
|
-
raise
|
|
392
|
+
raise Dash::ConfigurationError, "Missing required configuration for #{key}" unless raw_config[key].present?
|
|
383
393
|
end
|
|
384
394
|
|
|
385
|
-
raise
|
|
395
|
+
raise Dash::ConfigurationError, "Missing required configuration for image" if image.blank?
|
|
386
396
|
|
|
387
397
|
if raw_config.servers.nil?
|
|
388
|
-
raise
|
|
398
|
+
raise Dash::ConfigurationError, "No servers or accessories specified" unless raw_config.accessories.present?
|
|
389
399
|
else
|
|
390
400
|
unless role(primary_role_name).present?
|
|
391
|
-
raise
|
|
401
|
+
raise Dash::ConfigurationError, "The primary_role #{primary_role_name} isn't defined"
|
|
392
402
|
end
|
|
393
403
|
|
|
394
404
|
if primary_role.hosts.empty?
|
|
395
|
-
raise
|
|
405
|
+
raise Dash::ConfigurationError, "No servers specified for the #{primary_role.name} primary_role"
|
|
396
406
|
end
|
|
397
407
|
|
|
398
408
|
unless allow_empty_roles?
|
|
399
409
|
roles.each do |role|
|
|
400
410
|
if role.hosts.empty?
|
|
401
|
-
raise
|
|
411
|
+
raise Dash::ConfigurationError, "No servers specified for the #{role.name} role. You can ignore this with allow_empty_roles: true"
|
|
402
412
|
end
|
|
403
413
|
end
|
|
404
414
|
end
|
|
@@ -408,21 +418,21 @@ class Kamal::Configuration
|
|
|
408
418
|
end
|
|
409
419
|
|
|
410
420
|
def ensure_valid_service_name
|
|
411
|
-
raise
|
|
421
|
+
raise Dash::ConfigurationError, "Service name can only include alphanumeric characters, hyphens, and underscores" unless raw_config[:service] =~ /^[a-z0-9_-]+$/i
|
|
412
422
|
|
|
413
423
|
true
|
|
414
424
|
end
|
|
415
425
|
|
|
416
426
|
def ensure_valid_kamal_version
|
|
417
|
-
if minimum_version && Gem::Version.new(minimum_version) > Gem::Version.new(
|
|
418
|
-
raise
|
|
427
|
+
if minimum_version && Gem::Version.new(minimum_version) > Gem::Version.new(Dash::VERSION)
|
|
428
|
+
raise Dash::ConfigurationError, "Current version is #{Dash::VERSION}, minimum required is #{minimum_version}"
|
|
419
429
|
end
|
|
420
430
|
|
|
421
431
|
true
|
|
422
432
|
end
|
|
423
433
|
|
|
424
434
|
def ensure_retain_containers_valid
|
|
425
|
-
raise
|
|
435
|
+
raise Dash::ConfigurationError, "Must retain at least 1 container" if retain_containers < 1
|
|
426
436
|
|
|
427
437
|
true
|
|
428
438
|
end
|
|
@@ -431,7 +441,7 @@ class Kamal::Configuration
|
|
|
431
441
|
hooks = %w[ pre-traefik-reboot post-traefik-reboot ].select { |hook_file| File.exist?(File.join(hooks_path, hook_file)) }
|
|
432
442
|
|
|
433
443
|
if hooks.any?
|
|
434
|
-
raise
|
|
444
|
+
raise Dash::ConfigurationError, "Found #{hooks.join(", ")}, these should be renamed to (pre|post)-proxy-reboot"
|
|
435
445
|
end
|
|
436
446
|
|
|
437
447
|
true
|
|
@@ -451,7 +461,7 @@ class Kamal::Configuration
|
|
|
451
461
|
return true if offenders.empty?
|
|
452
462
|
|
|
453
463
|
warn "Non-proxied role(s) #{offenders.map(&:name).join(", ")} have no healthcheck. " \
|
|
454
|
-
"Without one,
|
|
464
|
+
"Without one, dash accepts the container as ready #{readiness_delay}s after it merely starts " \
|
|
455
465
|
"and then stops the previous container — traffic can be dropped. Add a `healthcheck:` block, " \
|
|
456
466
|
"or opt out explicitly with `healthcheck: false`. This warning will become an error in a future release."
|
|
457
467
|
|
|
@@ -492,7 +502,7 @@ class Kamal::Configuration
|
|
|
492
502
|
|
|
493
503
|
return true if offenders.empty?
|
|
494
504
|
|
|
495
|
-
raise
|
|
505
|
+
raise Dash::ConfigurationError, "Role(s) #{offenders.map(&:name).join(", ")}: " \
|
|
496
506
|
"proxy/sleep requires proxy/run/docker_socket - kamal-proxy can only stop and start containers " \
|
|
497
507
|
"through the container runtime socket, and it is not mounted into the proxy without it"
|
|
498
508
|
end
|
|
@@ -577,7 +587,7 @@ class Kamal::Configuration
|
|
|
577
587
|
paced = roles.select(&:boot)
|
|
578
588
|
return true if paced.empty? || boot.parallel_roles != false
|
|
579
589
|
|
|
580
|
-
raise
|
|
590
|
+
raise Dash::ConfigurationError, "servers/#{paced.first.name}/boot cannot be combined with boot/parallel_roles: false, " \
|
|
581
591
|
"which boots each host's roles in turn and so cannot pace one role's hosts. Remove one of them"
|
|
582
592
|
end
|
|
583
593
|
|
|
@@ -602,7 +612,7 @@ class Kamal::Configuration
|
|
|
602
612
|
hosts = roles.select(&:ssl?).flat_map { |role| role.proxy.hosts }
|
|
603
613
|
duplicates = hosts.tally.filter_map { |host, count| host if count > 1 }
|
|
604
614
|
|
|
605
|
-
raise
|
|
615
|
+
raise Dash::ConfigurationError, "Different roles can't share the same host for SSL: #{duplicates.join(", ")}" if duplicates.any?
|
|
606
616
|
|
|
607
617
|
true
|
|
608
618
|
end
|
|
@@ -610,7 +620,7 @@ class Kamal::Configuration
|
|
|
610
620
|
def ensure_local_registry_remote_builder_has_ssh_url
|
|
611
621
|
if registry.local? && builder.remote?
|
|
612
622
|
unless URI(builder.remote).scheme == "ssh"
|
|
613
|
-
raise
|
|
623
|
+
raise Dash::ConfigurationError, "Local registry with remote builder requires an SSH URL (e.g., ssh://user@host)"
|
|
614
624
|
end
|
|
615
625
|
end
|
|
616
626
|
|
|
@@ -621,7 +631,7 @@ class Kamal::Configuration
|
|
|
621
631
|
all_hosts.each do |host|
|
|
622
632
|
run_configs = proxy_runs(host)
|
|
623
633
|
if run_configs.uniq.size > 1
|
|
624
|
-
raise
|
|
634
|
+
raise Dash::ConfigurationError, "Conflicting proxy run configurations for host #{host}"
|
|
625
635
|
end
|
|
626
636
|
end
|
|
627
637
|
end
|
|
@@ -634,7 +644,7 @@ class Kamal::Configuration
|
|
|
634
644
|
# accessories-only configuration has nothing to run it on.
|
|
635
645
|
def ensure_valid_loadbalancer
|
|
636
646
|
if proxy.loadbalancer == true && primary_role.nil?
|
|
637
|
-
raise
|
|
647
|
+
raise Dash::ConfigurationError, "proxy/loadbalancer: can't be enabled without servers"
|
|
638
648
|
end
|
|
639
649
|
|
|
640
650
|
true
|
|
@@ -656,16 +666,16 @@ class Kamal::Configuration
|
|
|
656
666
|
def validate_hooks_output_level!(level, hook = nil)
|
|
657
667
|
return if HOOKS_OUTPUT_LEVELS.include?(level)
|
|
658
668
|
context = hook ? " for hook '#{hook}'" : ""
|
|
659
|
-
raise
|
|
669
|
+
raise Dash::ConfigurationError, "Invalid hooks_output '#{level}'#{context}, must be one of: #{HOOKS_OUTPUT_LEVELS.join(', ')}"
|
|
660
670
|
end
|
|
661
671
|
|
|
662
672
|
def git_version
|
|
663
673
|
@git_version ||=
|
|
664
|
-
if
|
|
665
|
-
if
|
|
674
|
+
if Dash::Git.used?
|
|
675
|
+
if Dash::Git.uncommitted_changes.present? && !builder.git_clone?
|
|
666
676
|
uncommitted_suffix = "_uncommitted_#{SecureRandom.hex(8)}"
|
|
667
677
|
end
|
|
668
|
-
[
|
|
678
|
+
[ Dash::Git.revision, uncommitted_suffix ].compact.join
|
|
669
679
|
else
|
|
670
680
|
raise "Can't use commit hash as version, no git repository found in #{Dir.pwd}"
|
|
671
681
|
end
|
data/lib/{kamal → dash}/git.rb
RENAMED
|
@@ -4,7 +4,7 @@ require "json"
|
|
|
4
4
|
require "securerandom"
|
|
5
5
|
require "uri"
|
|
6
6
|
|
|
7
|
-
class
|
|
7
|
+
class Dash::OtelShipper
|
|
8
8
|
BATCH_SIZE = 100
|
|
9
9
|
FLUSH_INTERVAL = 5.seconds
|
|
10
10
|
|
|
@@ -38,7 +38,7 @@ class Kamal::OtelShipper
|
|
|
38
38
|
@run_id = SecureRandom.uuid
|
|
39
39
|
@resource_attributes = [
|
|
40
40
|
{ key: "service.name", value: { stringValue: "kamal" } },
|
|
41
|
-
{ key: "service.version", value: { stringValue:
|
|
41
|
+
{ key: "service.version", value: { stringValue: Dash::VERSION } },
|
|
42
42
|
{ key: "kamal.run_id", value: { stringValue: @run_id } },
|
|
43
43
|
*tags.tags.map do |key, value|
|
|
44
44
|
otel_key = OTEL_ATTRIBUTE_KEYS.fetch(key, "kamal.#{key}")
|
|
@@ -156,7 +156,7 @@ class Kamal::OtelShipper
|
|
|
156
156
|
payload = {
|
|
157
157
|
resourceLogs: [ {
|
|
158
158
|
resource: { attributes: @resource_attributes },
|
|
159
|
-
scopeLogs: [ { scope: { name: "kamal", version:
|
|
159
|
+
scopeLogs: [ { scope: { name: "kamal", version: Dash::VERSION }, logRecords: records } ]
|
|
160
160
|
} ]
|
|
161
161
|
}
|
|
162
162
|
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
class
|
|
1
|
+
class Dash::Output::OtelLogger < Dash::Output::BaseLogger
|
|
2
2
|
def self.build(settings:, config:)
|
|
3
3
|
raise ArgumentError, "OTel endpoint is required" unless settings["endpoint"]
|
|
4
4
|
new(
|
|
5
5
|
endpoint: settings["endpoint"],
|
|
6
|
-
tags:
|
|
6
|
+
tags: Dash::Tags.from_config(config).except(:service_version, :recorded_at),
|
|
7
7
|
service: config.service
|
|
8
8
|
)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def initialize(endpoint:, tags:, service: nil)
|
|
12
12
|
@endpoint = endpoint
|
|
13
|
-
@shipper =
|
|
13
|
+
@shipper = Dash::OtelShipper.new(endpoint: endpoint, tags: tags)
|
|
14
14
|
@service = service
|
|
15
15
|
super()
|
|
16
16
|
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Where a project keeps its dash-owned files - secrets and hooks - in the
|
|
2
|
+
# operator's own repository. Renamed from `.kamal` in stage 3a of the server
|
|
3
|
+
# artifact rename (zoolutions/dash#118); `.kamal` stays readable until 5.0 so an
|
|
4
|
+
# upgrade doesn't turn every existing project into a missing-secret error.
|
|
5
|
+
#
|
|
6
|
+
# Deliberately not memoized: `dash migrate` moves the directory inside a single
|
|
7
|
+
# process, and a cached answer would be stale for the rest of that invocation.
|
|
8
|
+
class Dash::ProjectDirectory
|
|
9
|
+
CURRENT = ".dash"
|
|
10
|
+
LEGACY = ".kamal"
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
def path
|
|
14
|
+
legacy? ? LEGACY : CURRENT
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# The predicate tests the directory rather than a specific file: a project
|
|
18
|
+
# holding only `secrets-common` or `secrets.<destination>` must still
|
|
19
|
+
# resolve, and Dash::Secrets synthesizes those names from the base path.
|
|
20
|
+
def legacy?
|
|
21
|
+
!Dir.exist?(CURRENT) && Dir.exist?(LEGACY)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def join(*parts)
|
|
25
|
+
File.join(path, *parts)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
class
|
|
2
|
-
delegate :optionize, to:
|
|
1
|
+
class Dash::Secrets::Adapters::Base
|
|
2
|
+
delegate :optionize, to: Dash::Utils
|
|
3
3
|
|
|
4
4
|
def fetch(secrets, account: nil, from: nil)
|
|
5
5
|
raise RuntimeError, "Missing required option '--account'" if requires_account? && account.blank?
|
|
@@ -4,11 +4,11 @@
|
|
|
4
4
|
# Usage
|
|
5
5
|
#
|
|
6
6
|
# Fetch all password from FooBar item
|
|
7
|
-
# `
|
|
7
|
+
# `dash secrets fetch --adapter enpass --from /Users/YOUR_USERNAME/Library/Containers/in.sinew.Enpass-Desktop/Data/Documents/Vaults/primary FooBar`
|
|
8
8
|
#
|
|
9
9
|
# Fetch only DB_PASSWORD from FooBar item
|
|
10
|
-
# `
|
|
11
|
-
class
|
|
10
|
+
# `dash secrets fetch --adapter enpass --from /Users/YOUR_USERNAME/Library/Containers/in.sinew.Enpass-Desktop/Data/Documents/Vaults/primary FooBar/DB_PASSWORD`
|
|
11
|
+
class Dash::Secrets::Adapters::Enpass < Dash::Secrets::Adapters::Base
|
|
12
12
|
def requires_account?
|
|
13
13
|
false
|
|
14
14
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class
|
|
1
|
+
class Dash::Secrets::Adapters::GcpSecretManager < Dash::Secrets::Adapters::Base
|
|
2
2
|
private
|
|
3
3
|
def login(account)
|
|
4
4
|
# Since only the account option is passed from the cli, we'll use it for both account and service account
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
require "active_support/core_ext/string/inflections"
|
|
2
|
-
module
|
|
2
|
+
module Dash::Secrets::Adapters
|
|
3
3
|
def self.lookup(name)
|
|
4
4
|
name = "one_password" if name.downcase == "1password"
|
|
5
5
|
name = "last_pass" if name.downcase == "lastpass"
|
|
@@ -9,7 +9,7 @@ module Kamal::Secrets::Adapters
|
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def self.adapter_class(name)
|
|
12
|
-
Object.const_get("
|
|
12
|
+
Object.const_get("Dash::Secrets::Adapters::#{name.camelize}").new
|
|
13
13
|
rescue NameError => e
|
|
14
14
|
raise RuntimeError, "Unknown secrets adapter: #{name}"
|
|
15
15
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class
|
|
1
|
+
class Dash::Secrets::Dotenv::InlineCommandSubstitution
|
|
2
2
|
# Unlike dotenv, this regex does not match escaped
|
|
3
3
|
# parentheses when looking for command substitutions.
|
|
4
4
|
INTERPOLATED_SHELL_COMMAND = /
|
|
@@ -29,7 +29,9 @@ class Kamal::Secrets::Dotenv::InlineCommandSubstitution
|
|
|
29
29
|
$LAST_MATCH_INFO[0][1..]
|
|
30
30
|
else
|
|
31
31
|
command = ::Dotenv::Substitutions::Variable.call(command, env)
|
|
32
|
-
|
|
32
|
+
# Accept the legacy `kamal secrets` spelling too — secrets files
|
|
33
|
+
# written before the dash rename still use it.
|
|
34
|
+
if command =~ /\A\s*(dash|kamal)\s*secrets\s+/
|
|
33
35
|
# Inline the command
|
|
34
36
|
inline_secrets_command(command)
|
|
35
37
|
else
|
|
@@ -41,7 +43,7 @@ class Kamal::Secrets::Dotenv::InlineCommandSubstitution
|
|
|
41
43
|
end
|
|
42
44
|
|
|
43
45
|
def inline_secrets_command(command)
|
|
44
|
-
|
|
46
|
+
Dash::Cli::Main.start(command.shellsplit[1..] + [ "--inline" ]).chomp
|
|
45
47
|
end
|
|
46
48
|
end
|
|
47
49
|
end
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
require "dotenv"
|
|
2
2
|
|
|
3
|
-
class
|
|
4
|
-
|
|
3
|
+
class Dash::Secrets
|
|
4
|
+
Dash::Secrets::Dotenv::InlineCommandSubstitution.install!
|
|
5
5
|
|
|
6
|
-
def initialize(destination: nil, secrets_path:
|
|
6
|
+
def initialize(destination: nil, secrets_path: nil)
|
|
7
7
|
@destination = destination
|
|
8
|
-
@secrets_path = secrets_path
|
|
8
|
+
@secrets_path = secrets_path || Dash::ProjectDirectory.join("secrets")
|
|
9
9
|
@mutex = Mutex.new
|
|
10
10
|
end
|
|
11
11
|
|
|
@@ -13,9 +13,9 @@ class Kamal::Secrets
|
|
|
13
13
|
synchronized_fetch(key)
|
|
14
14
|
rescue KeyError
|
|
15
15
|
if secrets_files.present?
|
|
16
|
-
raise
|
|
16
|
+
raise Dash::ConfigurationError, "Secret '#{key}' not found in #{secrets_files.join(", ")}"
|
|
17
17
|
else
|
|
18
|
-
raise
|
|
18
|
+
raise Dash::ConfigurationError, "Secret '#{key}' not found, no secret files (#{secrets_filenames.join(", ")}) provided"
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
|
data/lib/{kamal → dash}/tags.rb
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require "time"
|
|
2
2
|
|
|
3
|
-
class
|
|
3
|
+
class Dash::Tags
|
|
4
4
|
attr_reader :config, :tags
|
|
5
5
|
|
|
6
6
|
class << self
|
|
@@ -10,7 +10,7 @@ class Kamal::Tags
|
|
|
10
10
|
|
|
11
11
|
def default_tags(config)
|
|
12
12
|
{ recorded_at: Time.now.utc.iso8601,
|
|
13
|
-
performer:
|
|
13
|
+
performer: Dash::Git.email.presence || `whoami`.chomp,
|
|
14
14
|
destination: config.destination,
|
|
15
15
|
version: config.version,
|
|
16
16
|
service_version: service_version(config),
|
|
@@ -26,8 +26,13 @@ class Kamal::Tags
|
|
|
26
26
|
@tags = tags.compact
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
+
# Both prefixes carry the same value: hooks are operator-written and apps read
|
|
30
|
+
# these at runtime, so the old names stay until 5.0 (zoolutions/dash#118).
|
|
29
31
|
def env
|
|
30
|
-
tags.
|
|
32
|
+
tags.each_with_object({}) do |(detail, value), env|
|
|
33
|
+
env["DASH_#{detail.upcase}"] = value
|
|
34
|
+
env["KAMAL_#{detail.upcase}"] = value
|
|
35
|
+
end
|
|
31
36
|
end
|
|
32
37
|
|
|
33
38
|
def to_s
|