dash 3.2.0 → 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 +1 -1
- 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 +86 -86
- data/lib/{kamal → dash}/cli/base.rb +71 -47
- 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 +18 -18
- 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 +77 -66
- data/lib/{kamal → dash}/cli/proxy/drift.rb +3 -3
- data/lib/{kamal → dash}/cli/proxy/loadbalancer_claim.rb +3 -3
- data/lib/{kamal → dash}/cli/proxy/loadbalancer_reboot.rb +22 -22
- data/lib/{kamal → dash}/cli/proxy/reboot.rb +15 -15
- data/lib/{kamal → dash}/cli/proxy.rb +166 -154
- data/lib/{kamal → dash}/cli/prune.rb +10 -10
- data/lib/{kamal → dash}/cli/registry.rb +11 -11
- data/lib/{kamal → dash}/cli/secrets.rb +3 -3
- data/lib/{kamal → dash}/cli/server.rb +14 -14
- data/lib/{kamal → dash}/cli/templates/deploy.yml +4 -4
- 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/{kamal → dash}/cli/templates/secrets +6 -6
- 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 +2 -2
- 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/builder.yml +3 -3
- data/lib/{kamal → dash}/configuration/docs/configuration.yml +12 -5
- data/lib/{kamal → dash}/configuration/docs/env.yml +10 -10
- data/lib/{kamal → dash}/configuration/docs/proxy.yml +31 -8
- data/lib/{kamal → dash}/configuration/docs/registry.yml +5 -5
- 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 +7 -7
- data/lib/{kamal → dash}/configuration/proxy/run.rb +11 -11
- data/lib/{kamal → dash}/configuration/proxy.rb +15 -15
- 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 +12 -12
- data/lib/{kamal → dash}/configuration/servers.rb +4 -4
- data/lib/{kamal → dash}/configuration/ssh.rb +2 -2
- 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 +39 -29
- 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 +1 -1
- 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 +2 -2
- 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} +4 -4
- metadata +156 -154
- 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/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/accessory.yml +0 -0
- /data/lib/{kamal → dash}/configuration/docs/alias.yml +0 -0
- /data/lib/{kamal → dash}/configuration/docs/boot.yml +0 -0
- /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/role.yml +0 -0
- /data/lib/{kamal → dash}/configuration/docs/servers.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,7 +1,7 @@
|
|
|
1
|
-
class
|
|
2
|
-
include
|
|
1
|
+
class Dash::Configuration::Role
|
|
2
|
+
include Dash::Configuration::Validation
|
|
3
3
|
|
|
4
|
-
delegate :argumentize, :optionize, to:
|
|
4
|
+
delegate :argumentize, :optionize, to: Dash::Utils
|
|
5
5
|
|
|
6
6
|
attr_reader :name, :config, :specialized_env, :specialized_logging, :specialized_proxy, :healthcheck
|
|
7
7
|
|
|
@@ -13,20 +13,20 @@ class Kamal::Configuration::Role
|
|
|
13
13
|
role_config,
|
|
14
14
|
example: validation_yml["servers"]["workers"],
|
|
15
15
|
context: "servers/#{name}",
|
|
16
|
-
with:
|
|
16
|
+
with: Dash::Configuration::Validator::Role
|
|
17
17
|
|
|
18
|
-
@specialized_env =
|
|
18
|
+
@specialized_env = Dash::Configuration::Env.new \
|
|
19
19
|
config: specializations.fetch("env", {}),
|
|
20
20
|
secrets: config.secrets,
|
|
21
21
|
context: "servers/#{name}/env"
|
|
22
22
|
|
|
23
|
-
@specialized_logging =
|
|
23
|
+
@specialized_logging = Dash::Configuration::Logging.new \
|
|
24
24
|
logging_config: specializations.fetch("logging", {}),
|
|
25
25
|
context: "servers/#{name}/logging"
|
|
26
26
|
|
|
27
27
|
# `healthcheck: false` is an opt-out, not a healthcheck — it leaves @healthcheck nil.
|
|
28
28
|
if healthcheck_config = specializations["healthcheck"]
|
|
29
|
-
@healthcheck =
|
|
29
|
+
@healthcheck = Dash::Configuration::Role::Healthcheck.new \
|
|
30
30
|
healthcheck_config: healthcheck_config,
|
|
31
31
|
context: "servers/#{name}/healthcheck"
|
|
32
32
|
end
|
|
@@ -94,13 +94,13 @@ class Kamal::Configuration::Role
|
|
|
94
94
|
# `boot.wait` a second time inside every group.
|
|
95
95
|
#
|
|
96
96
|
# Built on first read rather than in the initializer — Servers.new constructs every Role
|
|
97
|
-
# before
|
|
97
|
+
# before Dash::Configuration#initialize has finished assigning its own collaborators.
|
|
98
98
|
def boot
|
|
99
99
|
return @boot if defined?(@boot)
|
|
100
100
|
|
|
101
101
|
@boot =
|
|
102
102
|
if (boot_config = specializations["boot"])
|
|
103
|
-
|
|
103
|
+
Dash::Configuration::Boot.new \
|
|
104
104
|
config: config, boot_config: boot_config, context: "servers/#{name}/boot"
|
|
105
105
|
end
|
|
106
106
|
end
|
|
@@ -235,7 +235,7 @@ class Kamal::Configuration::Role
|
|
|
235
235
|
|
|
236
236
|
def asset_volume(version = config.version)
|
|
237
237
|
if assets?
|
|
238
|
-
|
|
238
|
+
Dash::Configuration::Volume.new \
|
|
239
239
|
host_path: asset_volume_directory(version), container_path: asset_path, options: asset_path_options
|
|
240
240
|
end
|
|
241
241
|
end
|
|
@@ -255,7 +255,7 @@ class Kamal::Configuration::Role
|
|
|
255
255
|
def ensure_one_host_for_ssl
|
|
256
256
|
# Skip SSL validation when a loadbalancer is present or custom certificates are provided
|
|
257
257
|
if running_proxy? && proxy.ssl? && hosts.size > 1 && !proxy.loadbalancer.present? && !proxy.custom_ssl_certificate?
|
|
258
|
-
raise
|
|
258
|
+
raise Dash::ConfigurationError, "SSL is only supported on a single server unless you provide custom certificates or configure a loadbalancer, found #{hosts.size} servers for role #{name}"
|
|
259
259
|
end
|
|
260
260
|
end
|
|
261
261
|
|
|
@@ -274,7 +274,7 @@ class Kamal::Configuration::Role
|
|
|
274
274
|
if running_proxy?
|
|
275
275
|
proxy_config = proxy_specializations == true || proxy_specializations.nil? ? {} : proxy_specializations
|
|
276
276
|
|
|
277
|
-
@specialized_proxy =
|
|
277
|
+
@specialized_proxy = Dash::Configuration::Proxy.new \
|
|
278
278
|
config: config,
|
|
279
279
|
proxy_config: proxy_config,
|
|
280
280
|
secrets: config.secrets,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
class
|
|
2
|
-
include
|
|
1
|
+
class Dash::Configuration::Servers
|
|
2
|
+
include Dash::Configuration::Validation
|
|
3
3
|
|
|
4
4
|
attr_reader :config, :servers_config, :roles
|
|
5
5
|
|
|
6
6
|
def initialize(config:)
|
|
7
7
|
@config = config
|
|
8
8
|
@servers_config = config.raw_config.servers
|
|
9
|
-
validate! servers_config, with:
|
|
9
|
+
validate! servers_config, with: Dash::Configuration::Validator::Servers
|
|
10
10
|
|
|
11
|
-
@roles = role_names.map { |role_name|
|
|
11
|
+
@roles = role_names.map { |role_name| Dash::Configuration::Role.new role_name, config: config }
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
private
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
require "yaml"
|
|
2
2
|
require "active_support/inflector"
|
|
3
3
|
|
|
4
|
-
module
|
|
4
|
+
module Dash::Configuration::Validation
|
|
5
5
|
extend ActiveSupport::Concern
|
|
6
6
|
|
|
7
7
|
class_methods do
|
|
@@ -14,7 +14,7 @@ module Kamal::Configuration::Validation
|
|
|
14
14
|
end
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
def validate!(config, example: nil, context: nil, with:
|
|
17
|
+
def validate!(config, example: nil, context: nil, with: Dash::Configuration::Validator)
|
|
18
18
|
context ||= self.class.validation_config_key
|
|
19
19
|
example ||= validation_yml[self.class.validation_config_key]
|
|
20
20
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class
|
|
1
|
+
class Dash::Configuration::Validator::Alias < Dash::Configuration::Validator
|
|
2
2
|
def validate!
|
|
3
3
|
super
|
|
4
4
|
|
|
@@ -8,7 +8,7 @@ class Kamal::Configuration::Validator::Alias < Kamal::Configuration::Validator
|
|
|
8
8
|
error "Invalid alias name: '#{name}'. Must only contain lowercase letters, alphanumeric, hyphens and underscores."
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
if
|
|
11
|
+
if Dash::Cli::Main.commands.include?(name)
|
|
12
12
|
error "Alias '#{name}' conflicts with a built-in command."
|
|
13
13
|
end
|
|
14
14
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class
|
|
1
|
+
class Dash::Configuration::Validator::Env < Dash::Configuration::Validator
|
|
2
2
|
SPECIAL_KEYS = [ "clear", "secret", "tags" ]
|
|
3
3
|
|
|
4
4
|
def validate!
|
|
@@ -39,7 +39,7 @@ class Kamal::Configuration::Validator::Env < Kamal::Configuration::Validator
|
|
|
39
39
|
with_context(tag) do
|
|
40
40
|
validate_type! value, Hash
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
Dash::Configuration::Validator::Env.new(
|
|
43
43
|
value,
|
|
44
44
|
example: example["tags"].values[1],
|
|
45
45
|
context: context
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class
|
|
1
|
+
class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
|
|
2
2
|
def validate!
|
|
3
3
|
unless config.nil?
|
|
4
4
|
super
|
|
@@ -149,7 +149,7 @@ class Kamal::Configuration::Validator::Proxy < Kamal::Configuration::Validator
|
|
|
149
149
|
validate_dns_provider_zones! provider
|
|
150
150
|
elsif provider.present? && !supported_dns_provider?(provider)
|
|
151
151
|
error "unsupported dns_provider '#{provider}'. " \
|
|
152
|
-
"Supported providers: #{
|
|
152
|
+
"Supported providers: #{Dash::Configuration::Proxy::Acme::DNS_PROVIDERS.join(", ")}"
|
|
153
153
|
end
|
|
154
154
|
end
|
|
155
155
|
end
|
|
@@ -175,13 +175,13 @@ class Kamal::Configuration::Validator::Proxy < Kamal::Configuration::Validator
|
|
|
175
175
|
|
|
176
176
|
unless zone_provider.is_a?(String) && supported_dns_provider?(zone_provider)
|
|
177
177
|
error "unsupported dns_provider '#{zone_provider}' for '#{zone}'. " \
|
|
178
|
-
"Supported providers: #{
|
|
178
|
+
"Supported providers: #{Dash::Configuration::Proxy::Acme::DNS_PROVIDERS.join(", ")}"
|
|
179
179
|
end
|
|
180
180
|
end
|
|
181
181
|
end
|
|
182
182
|
|
|
183
183
|
def supported_dns_provider?(provider)
|
|
184
|
-
|
|
184
|
+
Dash::Configuration::Proxy::Acme::SUPPORTED_DNS_PROVIDERS.include?(provider.to_s.downcase)
|
|
185
185
|
end
|
|
186
186
|
|
|
187
187
|
# The whole TLS surface lives in the one `ssl` hash: certificate material,
|
|
@@ -278,7 +278,7 @@ class Kamal::Configuration::Validator::Proxy < Kamal::Configuration::Validator
|
|
|
278
278
|
# Session affinity and scale-to-zero. The one rule NOT here is that sleep
|
|
279
279
|
# needs proxy/run/docker_socket: a role can carry `sleep` while the root
|
|
280
280
|
# carries the socket, and this validator runs against the role's own proxy
|
|
281
|
-
# block before it is merged.
|
|
281
|
+
# block before it is merged. Dash::Configuration checks that pairing on the
|
|
282
282
|
# merged config instead.
|
|
283
283
|
def validate_lifecycle!
|
|
284
284
|
affinity = config["session_affinity"] || {}
|
|
@@ -604,11 +604,11 @@ class Kamal::Configuration::Validator::Proxy < Kamal::Configuration::Validator
|
|
|
604
604
|
end
|
|
605
605
|
|
|
606
606
|
encodings.each do |encoding|
|
|
607
|
-
canonical =
|
|
607
|
+
canonical = Dash::Configuration::Proxy::COMPRESSION_ENCODING_ALIASES.fetch(encoding.to_s, encoding.to_s)
|
|
608
608
|
|
|
609
|
-
unless
|
|
609
|
+
unless Dash::Configuration::Proxy::SUPPORTED_COMPRESSION_ENCODINGS.include?(canonical)
|
|
610
610
|
error "unsupported encoding '#{encoding}'. " \
|
|
611
|
-
"Supported encodings: #{
|
|
611
|
+
"Supported encodings: #{Dash::Configuration::Proxy::SUPPORTED_COMPRESSION_ENCODINGS.join(", ")}"
|
|
612
612
|
end
|
|
613
613
|
end
|
|
614
614
|
|
|
@@ -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
|
|
@@ -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
|