dash 3.2.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +16 -16
- 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 +72 -48
- 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 +26 -8
- data/lib/{kamal → dash}/cli/doctor/host_checks.rb +22 -22
- 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 +82 -71
- data/lib/{kamal → dash}/cli/proxy/drift.rb +3 -3
- data/lib/dash/cli/proxy/legacy_rename.rb +58 -0
- data/lib/{kamal → dash}/cli/proxy/loadbalancer_claim.rb +3 -3
- data/lib/{kamal → dash}/cli/proxy/loadbalancer_reboot.rb +23 -23
- data/lib/{kamal → dash}/cli/proxy/reboot.rb +21 -21
- data/lib/{kamal → dash}/cli/proxy.rb +178 -162
- 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 +32 -24
- data/lib/{kamal → dash}/commands/accessory/proxy.rb +2 -2
- 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 +2 -2
- 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 +2 -2
- data/lib/{kamal → dash}/commands/app.rb +2 -2
- 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/dash/commands/docker.rb +89 -0
- data/lib/{kamal → dash}/commands/hook.rb +1 -1
- data/lib/{kamal → dash}/commands/loadbalancer.rb +55 -24
- data/lib/{kamal → dash}/commands/lock.rb +3 -3
- data/lib/{kamal → dash}/commands/proxy/cert_transfer.rb +6 -6
- data/lib/dash/commands/proxy.rb +375 -0
- data/lib/{kamal → dash}/commands/prune.rb +2 -2
- 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 +13 -13
- 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 +3 -3
- data/lib/{kamal → dash}/configuration/docs/builder.yml +3 -3
- data/lib/{kamal → dash}/configuration/docs/configuration.yml +13 -6
- data/lib/{kamal → dash}/configuration/docs/env.yml +10 -10
- data/lib/{kamal → dash}/configuration/docs/proxy.yml +68 -45
- 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 +5 -5
- 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 +9 -8
- data/lib/{kamal → dash}/configuration/proxy/boot.rb +9 -11
- data/lib/{kamal → dash}/configuration/proxy/run.rb +20 -20
- data/lib/{kamal → dash}/configuration/proxy.rb +51 -29
- 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 +14 -14
- 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 +31 -31
- 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 +47 -37
- 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 +16 -6
- data/lib/dash/version.rb +3 -0
- data/lib/{kamal.rb → dash.rb} +4 -4
- metadata +157 -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/docker.rb +0 -55
- data/lib/kamal/commands/proxy.rb +0 -266
- 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/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,4 +1,4 @@
|
|
|
1
|
-
module
|
|
1
|
+
module Dash::Commands::App::Proxy
|
|
2
2
|
delegate :container_name, to: :"config.proxy_boot", prefix: :proxy
|
|
3
3
|
|
|
4
4
|
def deploy(target:)
|
|
@@ -39,6 +39,6 @@ module Kamal::Commands::App::Proxy
|
|
|
39
39
|
|
|
40
40
|
private
|
|
41
41
|
def proxy_exec(*command)
|
|
42
|
-
docker :exec, proxy_container_name, "
|
|
42
|
+
docker :exec, proxy_container_name, "dash-proxy", *command
|
|
43
43
|
end
|
|
44
44
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class
|
|
1
|
+
class Dash::Commands::App < Dash::Commands::Base
|
|
2
2
|
include Assets, Containers, ErrorPages, Execution, Images, Logging, Proxy
|
|
3
3
|
|
|
4
4
|
ACTIVE_DOCKER_STATUSES = [ :running, :restarting ]
|
|
@@ -18,7 +18,7 @@ class Kamal::Commands::App < Kamal::Commands::Base
|
|
|
18
18
|
"--detach",
|
|
19
19
|
"--restart", role.restart_policy,
|
|
20
20
|
"--name", container_name,
|
|
21
|
-
"--network", "
|
|
21
|
+
"--network", "dash",
|
|
22
22
|
*([ "--hostname", hostname ] if hostname),
|
|
23
23
|
"--env", "KAMAL_CONTAINER_NAME=\"#{container_name}\"",
|
|
24
24
|
"--env", "KAMAL_VERSION=\"#{config.version}\"",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
class
|
|
1
|
+
class Dash::Commands::Auditor < Dash::Commands::Base
|
|
2
2
|
attr_reader :details
|
|
3
|
-
delegate :escape_shell_value, to:
|
|
3
|
+
delegate :escape_shell_value, to: Dash::Utils
|
|
4
4
|
|
|
5
5
|
def initialize(config, **details)
|
|
6
6
|
super(config)
|
|
@@ -10,7 +10,7 @@ class Kamal::Commands::Auditor < Kamal::Commands::Base
|
|
|
10
10
|
# Runs remotely
|
|
11
11
|
def record(line, **details)
|
|
12
12
|
combine \
|
|
13
|
-
|
|
13
|
+
ensure_run_directory,
|
|
14
14
|
append([ :echo, escape_shell_value(audit_line(line, **details)) ], audit_log_file)
|
|
15
15
|
end
|
|
16
16
|
|
|
@@ -29,10 +29,6 @@ class Kamal::Commands::Auditor < Kamal::Commands::Base
|
|
|
29
29
|
tags(**self.details, **details)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
def make_run_directory
|
|
33
|
-
[ :mkdir, "-p", config.run_directory ]
|
|
34
|
-
end
|
|
35
|
-
|
|
36
32
|
def audit_line(line, **details)
|
|
37
33
|
"#{audit_tags(**details).except(:version, :service_version, :service)} #{line}"
|
|
38
34
|
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
module
|
|
1
|
+
module Dash::Commands
|
|
2
2
|
class Base
|
|
3
|
-
delegate :sensitive, :argumentize, to:
|
|
3
|
+
delegate :sensitive, :argumentize, to: Dash::Utils
|
|
4
4
|
|
|
5
5
|
# Prefixed onto the docker state when the container declares no healthcheck at all, so
|
|
6
6
|
# "nothing is probing this container" stays distinguishable from "the probe passed" —
|
|
@@ -32,6 +32,32 @@ module Kamal::Commands
|
|
|
32
32
|
[ :mkdir, "-p", path ]
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
# Creates the run directory, renaming a pre-3b `.kamal` into place first.
|
|
36
|
+
#
|
|
37
|
+
# Lives on Base because two unlocked paths reach the run directory before
|
|
38
|
+
# Dash::Cli::Base#ensure_run_directory does — the auditor records "Pulled
|
|
39
|
+
# image" during `build:pull`, and every `mkdir -p .dash/...` underneath it
|
|
40
|
+
# creates the parent. If any of them made the directory with a bare mkdir,
|
|
41
|
+
# `.dash` would exist by the time the guard ran and the legacy tree would be
|
|
42
|
+
# stranded. Everything that can be first must run the same command.
|
|
43
|
+
#
|
|
44
|
+
# The migration is safe to repeat on every command:
|
|
45
|
+
#
|
|
46
|
+
# - Idempotent - once `.dash` exists the second guard is false forever.
|
|
47
|
+
# - Atomic - the two are siblings in the SSH user's home, so this is a
|
|
48
|
+
# rename within one filesystem, never a copy.
|
|
49
|
+
# - Invisible to running containers - a bind mount resolves to an inode,
|
|
50
|
+
# so the live proxy keeps serving from the renamed directory and only
|
|
51
|
+
# picks up the new path when it is next recreated.
|
|
52
|
+
#
|
|
53
|
+
# `test` leads deliberately: SSHKit's command map passes `if`/`test`/`time`/
|
|
54
|
+
# `exec` through untouched and prefixes everything else with `/usr/bin/env`.
|
|
55
|
+
# The trailing `|| true` keeps the exit status zero when there is nothing to
|
|
56
|
+
# migrate, since callers execute this with raise_on_non_zero_exit on.
|
|
57
|
+
def ensure_run_directory
|
|
58
|
+
combine migrate_legacy_run_directory, make_directory(config.run_directory)
|
|
59
|
+
end
|
|
60
|
+
|
|
35
61
|
def remove_directory(path)
|
|
36
62
|
[ :rm, "-r", path ]
|
|
37
63
|
end
|
|
@@ -51,6 +77,16 @@ module Kamal::Commands
|
|
|
51
77
|
end
|
|
52
78
|
|
|
53
79
|
private
|
|
80
|
+
def migrate_legacy_run_directory
|
|
81
|
+
any \
|
|
82
|
+
combine(
|
|
83
|
+
[ :test, "-d", Dash::Configuration::LEGACY_RUN_DIRECTORY ],
|
|
84
|
+
[ :test, "!", "-e", config.run_directory ],
|
|
85
|
+
[ :mv, Dash::Configuration::LEGACY_RUN_DIRECTORY, config.run_directory ]
|
|
86
|
+
),
|
|
87
|
+
[ :true ]
|
|
88
|
+
end
|
|
89
|
+
|
|
54
90
|
def combine(*commands, by: "&&")
|
|
55
91
|
commands
|
|
56
92
|
.compact
|
|
@@ -107,7 +143,7 @@ module Kamal::Commands
|
|
|
107
143
|
end
|
|
108
144
|
|
|
109
145
|
def tags(**details)
|
|
110
|
-
|
|
146
|
+
Dash::Tags.from_config(config, **details)
|
|
111
147
|
end
|
|
112
148
|
|
|
113
149
|
def ssh_config_args
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
class
|
|
1
|
+
class Dash::Commands::Builder::Base < Dash::Commands::Base
|
|
2
2
|
class BuilderError < StandardError; end
|
|
3
3
|
|
|
4
4
|
ENDPOINT_DOCKER_HOST_INSPECT = "'{{.Endpoints.docker.Host}}'"
|
|
5
5
|
|
|
6
|
-
delegate :argumentize, to:
|
|
6
|
+
delegate :argumentize, to: Dash::Utils
|
|
7
7
|
delegate \
|
|
8
8
|
:args, :secrets, :dockerfile, :target, :arches, :local_arches, :remote_arches, :remote,
|
|
9
9
|
:pack?, :pack_builder, :pack_buildpacks,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module
|
|
1
|
+
module Dash::Commands::Builder::Clone
|
|
2
2
|
def clone
|
|
3
3
|
git :clone, escaped_root, "--recurse-submodules", path: config.builder.clone_directory.shellescape
|
|
4
4
|
end
|
|
@@ -7,7 +7,7 @@ module Kamal::Commands::Builder::Clone
|
|
|
7
7
|
[
|
|
8
8
|
git(:remote, "set-url", :origin, escaped_root, path: escaped_build_directory),
|
|
9
9
|
git(:fetch, :origin, path: escaped_build_directory),
|
|
10
|
-
git(:reset, "--hard",
|
|
10
|
+
git(:reset, "--hard", Dash::Git.revision, path: escaped_build_directory),
|
|
11
11
|
git(:clean, "-fdx", path: escaped_build_directory),
|
|
12
12
|
git(:submodule, :update, "--init", path: escaped_build_directory),
|
|
13
13
|
git(:gc, "--auto", "--quiet", path: escaped_build_directory)
|
|
@@ -23,7 +23,7 @@ module Kamal::Commands::Builder::Clone
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def escaped_root
|
|
26
|
-
|
|
26
|
+
Dash::Git.root.shellescape
|
|
27
27
|
end
|
|
28
28
|
|
|
29
29
|
def escaped_build_directory
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class
|
|
1
|
+
class Dash::Commands::Builder::Pack < Dash::Commands::Builder::Base
|
|
2
2
|
def push(export_action = "registry", tag_as_dirty: false, no_cache: false)
|
|
3
3
|
combine \
|
|
4
4
|
build(tag_as_dirty: tag_as_dirty, no_cache: no_cache),
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
require "active_support/core_ext/string/filters"
|
|
2
2
|
|
|
3
|
-
class
|
|
3
|
+
class Dash::Commands::Builder < Dash::Commands::Base
|
|
4
4
|
delegate \
|
|
5
5
|
:create, :remove, :dev, :push, :clean, :pull, :info, :inspect_builder,
|
|
6
6
|
:validate_image, :first_mirror, :login_to_registry_locally?, :push_env,
|
|
@@ -13,7 +13,7 @@ class Kamal::Commands::Builder < Kamal::Commands::Base
|
|
|
13
13
|
include Clone
|
|
14
14
|
|
|
15
15
|
def name
|
|
16
|
-
target.class.to_s.remove("
|
|
16
|
+
target.class.to_s.remove("Dash::Commands::Builder::").underscore.inquiry
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def target
|
|
@@ -33,22 +33,22 @@ class Kamal::Commands::Builder < Kamal::Commands::Base
|
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def remote
|
|
36
|
-
@remote ||=
|
|
36
|
+
@remote ||= Dash::Commands::Builder::Remote.new(config)
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def local
|
|
40
|
-
@local ||=
|
|
40
|
+
@local ||= Dash::Commands::Builder::Local.new(config)
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
def hybrid
|
|
44
|
-
@hybrid ||=
|
|
44
|
+
@hybrid ||= Dash::Commands::Builder::Hybrid.new(config)
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
def pack
|
|
48
|
-
@pack ||=
|
|
48
|
+
@pack ||= Dash::Commands::Builder::Pack.new(config)
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
def cloud
|
|
52
|
-
@cloud ||=
|
|
52
|
+
@cloud ||= Dash::Commands::Builder::Cloud.new(config)
|
|
53
53
|
end
|
|
54
54
|
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
class Dash::Commands::Docker < Dash::Commands::Base
|
|
2
|
+
# Install Docker using the https://github.com/docker/docker-install convenience script.
|
|
3
|
+
def install
|
|
4
|
+
pipe get_docker, :sh
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
# Checks the Docker client version. Fails if Docker is not installed.
|
|
8
|
+
def installed?
|
|
9
|
+
docker "-v"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Checks the Docker server version. Fails if Docker is not running.
|
|
13
|
+
def running?
|
|
14
|
+
docker :version
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Do we have superuser access to install Docker and start system services?
|
|
18
|
+
def superuser?
|
|
19
|
+
[ '[ "${EUID:-$(id -u)}" -eq 0 ] || sudo -nl usermod >/dev/null' ]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def root?
|
|
23
|
+
[ '[ "${EUID:-$(id -u)}" -eq 0 ]' ]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def in_docker_group?
|
|
27
|
+
[ 'id -nG "${USER:-$(id -un)}" | grep -qw docker' ]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def add_to_docker_group
|
|
31
|
+
[ 'sudo -n usermod -aG docker "${USER:-$(id -un)}"' ]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def refresh_session
|
|
35
|
+
[ "kill -HUP $PPID" ]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Checks that an image's manifest can be fetched from its registry. Fails if it's missing or we're unauthorized.
|
|
39
|
+
def manifest_available?(image)
|
|
40
|
+
docker :manifest, :inspect, image
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def create_network
|
|
44
|
+
docker :network, :create, Dash::Configuration::Proxy::NETWORK
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Stage 3c: docker cannot rename a network, so `dash` is created alongside
|
|
48
|
+
# `kamal` and everything still on the old one is joined to the new one.
|
|
49
|
+
#
|
|
50
|
+
# App containers would be replaced by the next deploy anyway; accessories are
|
|
51
|
+
# not, and that is the whole point — without this a renamed proxy cannot
|
|
52
|
+
# reach `db` or `redis`. Connecting a container that is already attached
|
|
53
|
+
# fails, so each connect tolerates its own failure rather than aborting the
|
|
54
|
+
# sweep. The old network is never removed; that is documented manual cleanup
|
|
55
|
+
# and stage 3d's code change.
|
|
56
|
+
def connect_legacy_network_containers
|
|
57
|
+
any \
|
|
58
|
+
combine(
|
|
59
|
+
legacy_network_exists,
|
|
60
|
+
pipe(legacy_network_container_names, connect_each_to_network)
|
|
61
|
+
),
|
|
62
|
+
[ :true ]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
private
|
|
66
|
+
def legacy_network_exists
|
|
67
|
+
docker :network, :inspect, Dash::Configuration::Proxy::LEGACY_NETWORK, ">", "/dev/null", "2>&1"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def legacy_network_container_names
|
|
71
|
+
docker :network, :inspect, Dash::Configuration::Proxy::LEGACY_NETWORK,
|
|
72
|
+
"--format", "'{{range .Containers}}{{.Name}}{{\"\\n\"}}{{end}}'"
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Already-attached containers make `network connect` fail; tolerate each
|
|
76
|
+
# one's failure rather than letting it abort the sweep.
|
|
77
|
+
def connect_each_to_network
|
|
78
|
+
[ :xargs, "-r", "-I{}", "sh", "-c",
|
|
79
|
+
"'docker network connect #{Dash::Configuration::Proxy::NETWORK} {} 2>/dev/null || true'" ]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def get_docker
|
|
83
|
+
shell \
|
|
84
|
+
any \
|
|
85
|
+
[ :curl, "-fsSL", "https://get.docker.com" ],
|
|
86
|
+
[ :wget, "-O -", "https://get.docker.com" ],
|
|
87
|
+
[ :echo, "\"exit 1\"" ]
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
class
|
|
2
|
-
include
|
|
1
|
+
class Dash::Commands::Loadbalancer < Dash::Commands::Base
|
|
2
|
+
include Dash::Commands::Proxy::CertTransfer
|
|
3
3
|
|
|
4
|
-
delegate :argumentize, :optionize, to:
|
|
4
|
+
delegate :argumentize, :optionize, to: Dash::Utils
|
|
5
5
|
|
|
6
6
|
attr_reader :loadbalancer_config
|
|
7
7
|
|
|
@@ -14,11 +14,11 @@ class Kamal::Commands::Loadbalancer < Kamal::Commands::Base
|
|
|
14
14
|
docker \
|
|
15
15
|
:run,
|
|
16
16
|
"--name", container_name,
|
|
17
|
-
"--network", "
|
|
17
|
+
"--network", "dash",
|
|
18
18
|
"--detach",
|
|
19
19
|
"--restart", "unless-stopped",
|
|
20
20
|
"--label", label,
|
|
21
|
-
"--label", "#{
|
|
21
|
+
"--label", "#{Dash::Commands::Proxy::CONFIG_DIGEST_LABEL}=#{loadbalancer_config.run_config_digest}",
|
|
22
22
|
*config_volume,
|
|
23
23
|
*run_args,
|
|
24
24
|
*loadbalancer_config.run.image,
|
|
@@ -38,31 +38,32 @@ class Kamal::Commands::Loadbalancer < Kamal::Commands::Base
|
|
|
38
38
|
end
|
|
39
39
|
|
|
40
40
|
def deploy(targets: [])
|
|
41
|
-
docker :exec, container_name, "
|
|
41
|
+
docker :exec, container_name, "dash-proxy", "deploy", loadbalancer_config.config.service,
|
|
42
42
|
*loadbalancer_config.deploy_command_args(targets: targets)
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
# `retry` takes a host, or --all; the rest take no arguments.
|
|
46
|
+
def domains(subcommand, *args)
|
|
47
|
+
docker :exec, container_name, "dash-proxy", "domains", subcommand, *args
|
|
47
48
|
end
|
|
48
49
|
|
|
49
50
|
def list(json: false)
|
|
50
|
-
docker :exec, container_name, "
|
|
51
|
+
docker :exec, container_name, "dash-proxy", :list, *("--json" if json)
|
|
51
52
|
end
|
|
52
53
|
|
|
53
54
|
# Cache policy is edge-only under load balancing (see the layering contract),
|
|
54
55
|
# so the cache admin surface lives here - registered under the bare service
|
|
55
56
|
# name, unlike the per-role services on the proxy hosts.
|
|
56
57
|
def cache_stats(count: false, json: false)
|
|
57
|
-
docker :exec, container_name, "
|
|
58
|
+
docker :exec, container_name, "dash-proxy", :cache, :stats, *optionize({ count: count || nil, json: json || nil }.compact)
|
|
58
59
|
end
|
|
59
60
|
|
|
60
61
|
def cache_purge(service, path_prefix: nil)
|
|
61
|
-
docker :exec, container_name, "
|
|
62
|
+
docker :exec, container_name, "dash-proxy", :cache, :purge, service, *optionize({ "path-prefix": path_prefix }.compact)
|
|
62
63
|
end
|
|
63
64
|
|
|
64
65
|
def config_digest
|
|
65
|
-
docker :inspect, container_name, "--format",
|
|
66
|
+
docker :inspect, container_name, "--format", Dash::Commands::Proxy::CONFIG_DIGEST_FORMAT
|
|
66
67
|
end
|
|
67
68
|
|
|
68
69
|
def container_id(only_running: false)
|
|
@@ -93,16 +94,24 @@ class Kamal::Commands::Loadbalancer < Kamal::Commands::Base
|
|
|
93
94
|
end
|
|
94
95
|
|
|
95
96
|
# Prune by the label the container was actually created with - on a shared
|
|
96
|
-
# proxy host that is the
|
|
97
|
-
# title would leave the container behind for `run` to collide with.
|
|
97
|
+
# proxy host that is the dash-proxy title, and pruning by the loadbalancer
|
|
98
|
+
# title would leave the container behind for `run` to collide with. Both the
|
|
99
|
+
# current and the pre-rename title are pruned, so a container created before
|
|
100
|
+
# the rename is not left behind to collide either.
|
|
98
101
|
def remove_container
|
|
99
|
-
|
|
102
|
+
combine \
|
|
103
|
+
prune_containers_titled(image_title),
|
|
104
|
+
prune_containers_titled(legacy_image_title)
|
|
100
105
|
end
|
|
101
106
|
|
|
102
107
|
# Image label filters match labels baked into the image, and the load balancer
|
|
103
|
-
# runs the
|
|
108
|
+
# runs the dash-proxy image whichever host it sits on. Both titles are matched
|
|
109
|
+
# so a host still carrying a pre-rename image is cleaned up too; Docker ANDs
|
|
110
|
+
# multiple `--filter label=` values, so that is two commands.
|
|
104
111
|
def remove_image
|
|
105
|
-
|
|
112
|
+
combine \
|
|
113
|
+
prune_images_titled(Dash::Configuration::Proxy::IMAGE_TITLE),
|
|
114
|
+
prune_images_titled(Dash::Configuration::Proxy::LEGACY_IMAGE_TITLE)
|
|
106
115
|
end
|
|
107
116
|
|
|
108
117
|
def ensure_directory
|
|
@@ -110,7 +119,7 @@ class Kamal::Commands::Loadbalancer < Kamal::Commands::Base
|
|
|
110
119
|
end
|
|
111
120
|
|
|
112
121
|
# Where the proxy secrets env file lands (see Proxy::Run#secrets_path) -
|
|
113
|
-
# the same .
|
|
122
|
+
# the same .dash/proxy directory the per-app proxy hosts use.
|
|
114
123
|
def ensure_proxy_directory
|
|
115
124
|
make_directory loadbalancer_config.run.host_directory
|
|
116
125
|
end
|
|
@@ -152,28 +161,50 @@ class Kamal::Commands::Loadbalancer < Kamal::Commands::Base
|
|
|
152
161
|
loadbalancer_config.on_proxy_host?
|
|
153
162
|
end
|
|
154
163
|
|
|
164
|
+
# The full `key=value` the container is created with, so `--label #{label}`
|
|
165
|
+
# stays correct. The prune helpers take a bare title instead.
|
|
155
166
|
def label
|
|
167
|
+
"org.opencontainers.image.title=#{image_title}"
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def image_title
|
|
156
171
|
if on_proxy_host?
|
|
157
|
-
|
|
172
|
+
Dash::Configuration::Proxy::IMAGE_TITLE
|
|
158
173
|
else
|
|
159
|
-
|
|
174
|
+
Dash::Configuration::Proxy::LOADBALANCER_IMAGE_TITLE
|
|
160
175
|
end
|
|
161
176
|
end
|
|
162
177
|
|
|
163
|
-
|
|
178
|
+
def legacy_image_title
|
|
179
|
+
if on_proxy_host?
|
|
180
|
+
Dash::Configuration::Proxy::LEGACY_IMAGE_TITLE
|
|
181
|
+
else
|
|
182
|
+
Dash::Configuration::Proxy::LEGACY_LOADBALANCER_IMAGE_TITLE
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def prune_containers_titled(title)
|
|
187
|
+
docker :container, :prune, "--force", "--filter", "label=org.opencontainers.image.title=#{title}"
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
def prune_images_titled(title)
|
|
191
|
+
docker :image, :prune, "--all", "--force", "--filter", "label=org.opencontainers.image.title=#{title}"
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# dash-proxy keeps its state under /home/dash-proxy/.config/dash-proxy
|
|
164
195
|
# whichever host it runs on - only the volume name differs, so a dedicated
|
|
165
196
|
# load balancer and a shared proxy host never fight over the same volume.
|
|
166
197
|
# (The apps-config mount comes with run_args, via the proxy's run surface.)
|
|
167
198
|
def config_volume
|
|
168
199
|
if on_proxy_host?
|
|
169
|
-
[ "--volume", "
|
|
200
|
+
[ "--volume", "dash-proxy-config:/home/dash-proxy/.config/dash-proxy" ]
|
|
170
201
|
else
|
|
171
|
-
[ "--volume", "
|
|
202
|
+
[ "--volume", "dash-loadbalancer-config:/home/dash-proxy/.config/dash-proxy" ]
|
|
172
203
|
end
|
|
173
204
|
end
|
|
174
205
|
|
|
175
206
|
# The certificate store lives in whichever config volume this loadbalancer
|
|
176
|
-
# actually mounts — the shared
|
|
207
|
+
# actually mounts — the shared dash-proxy one on a proxy host.
|
|
177
208
|
def cert_store_volume_args
|
|
178
209
|
config_volume
|
|
179
210
|
end
|
|
@@ -2,9 +2,9 @@ require "active_support/duration"
|
|
|
2
2
|
require "time"
|
|
3
3
|
require "base64"
|
|
4
4
|
|
|
5
|
-
class
|
|
5
|
+
class Dash::Commands::Lock < Dash::Commands::Base
|
|
6
6
|
# The deploy lock is scoped to service+destination, so two destinations can
|
|
7
|
-
# deploy at once. Server-scoped resources — above all the single
|
|
7
|
+
# deploy at once. Server-scoped resources — above all the single dash-proxy
|
|
8
8
|
# container a host runs for every destination on it — need a lock that every
|
|
9
9
|
# destination contends for, hence :server.
|
|
10
10
|
SCOPES = %i[ destination server ].freeze
|
|
@@ -85,7 +85,7 @@ class Kamal::Commands::Lock < Kamal::Commands::Base
|
|
|
85
85
|
end
|
|
86
86
|
|
|
87
87
|
def locked_by
|
|
88
|
-
|
|
88
|
+
Dash::Git.user_name
|
|
89
89
|
rescue Errno::ENOENT
|
|
90
90
|
"Unknown"
|
|
91
91
|
end
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
# The including class provides `container_name`, `cert_store_volume_args` (the
|
|
11
11
|
# config volume mount) and `one_off_image` (the image tokens for a one-off
|
|
12
12
|
# container).
|
|
13
|
-
module
|
|
13
|
+
module Dash::Commands::Proxy::CertTransfer
|
|
14
14
|
CERT_ARCHIVE_FILENAME = "certs-export.tar.gz"
|
|
15
15
|
CERT_IMPORT_STAGING_FILENAME = "certs-import"
|
|
16
16
|
CONTAINER_IMPORT_PATH = "/tmp/kamal-cert-import"
|
|
@@ -18,20 +18,20 @@ module Kamal::Commands::Proxy::CertTransfer
|
|
|
18
18
|
# Through the RPC socket of the running container, under the proxy's own
|
|
19
19
|
# certificate write lock, so a backup taken mid-renewal is never torn.
|
|
20
20
|
def export_certs
|
|
21
|
-
docker :exec, container_name, "
|
|
21
|
+
docker :exec, container_name, "dash-proxy", :export, :certs, certs_archive_container_path
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
# Reads the data directory offline over the config volume — only safe when
|
|
25
|
-
# the container is stopped, which
|
|
25
|
+
# the container is stopped, which Dash::Cli::Proxy guarantees.
|
|
26
26
|
def export_certs_offline
|
|
27
27
|
docker :run, "--rm",
|
|
28
28
|
*cert_store_volume_args,
|
|
29
29
|
*config.proxy_boot.apps_volume.docker_args,
|
|
30
30
|
*one_off_image,
|
|
31
|
-
"
|
|
31
|
+
"dash-proxy", :export, :certs, certs_archive_container_path
|
|
32
32
|
end
|
|
33
33
|
|
|
34
|
-
# Offline by design (
|
|
34
|
+
# Offline by design (dash-proxy import has no RPC path): the one-off
|
|
35
35
|
# container mounts the config volume — creating it when no proxy has booted
|
|
36
36
|
# yet, which is the Traefik-migration case — and the staged source streams
|
|
37
37
|
# through stdin.
|
|
@@ -42,7 +42,7 @@ module Kamal::Commands::Proxy::CertTransfer
|
|
|
42
42
|
# run whatever follows on the target host.
|
|
43
43
|
import_command = shell [
|
|
44
44
|
"cat > #{CONTAINER_IMPORT_PATH} &&",
|
|
45
|
-
"
|
|
45
|
+
"dash-proxy import certs",
|
|
46
46
|
*optionize({ source_flag => CONTAINER_IMPORT_PATH, resolver: resolver, force: force || nil, verify: verify || nil }.compact, with: "=")
|
|
47
47
|
]
|
|
48
48
|
|