kamal 2.10.1 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/kamal/cli/accessory.rb +48 -39
- data/lib/kamal/cli/alias/command.rb +2 -2
- data/lib/kamal/cli/app.rb +57 -48
- data/lib/kamal/cli/base.rb +118 -17
- data/lib/kamal/cli/build.rb +10 -7
- data/lib/kamal/cli/lock.rb +5 -16
- data/lib/kamal/cli/main.rb +59 -53
- data/lib/kamal/cli/proxy.rb +9 -9
- data/lib/kamal/cli/prune.rb +3 -3
- data/lib/kamal/cli/server.rb +34 -15
- data/lib/kamal/cli/templates/sample_hooks/docker-setup.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/post-app-boot.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/post-deploy.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/post-proxy-reboot.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/pre-app-boot.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/pre-build.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/pre-proxy-reboot.sample +1 -1
- data/lib/kamal/cli/templates/secrets +4 -0
- data/lib/kamal/commander.rb +71 -17
- data/lib/kamal/commands/accessory.rb +3 -2
- data/lib/kamal/commands/app/logging.rb +1 -1
- data/lib/kamal/commands/app.rb +1 -1
- data/lib/kamal/commands/base.rb +15 -2
- data/lib/kamal/commands/builder/clone.rb +2 -1
- data/lib/kamal/commands/docker.rb +17 -1
- data/lib/kamal/commands/proxy.rb +1 -1
- data/lib/kamal/configuration/accessory.rb +13 -5
- data/lib/kamal/configuration/docs/alias.yml +3 -0
- data/lib/kamal/configuration/docs/configuration.yml +37 -2
- data/lib/kamal/configuration/docs/env.yml +6 -4
- data/lib/kamal/configuration/docs/output.yml +25 -0
- data/lib/kamal/configuration/docs/role.yml +1 -0
- data/lib/kamal/configuration/docs/ssh.yml +8 -0
- data/lib/kamal/configuration/output.rb +34 -0
- data/lib/kamal/configuration/proxy/run.rb +10 -1
- data/lib/kamal/configuration/role.rb +18 -6
- data/lib/kamal/configuration/ssh.rb +5 -1
- data/lib/kamal/configuration/validator.rb +29 -2
- data/lib/kamal/configuration.rb +41 -3
- data/lib/kamal/git.rb +1 -1
- data/lib/kamal/otel_shipper.rb +176 -0
- data/lib/kamal/output/base_logger.rb +29 -0
- data/lib/kamal/output/file_logger.rb +51 -0
- data/lib/kamal/output/formatter.rb +36 -0
- data/lib/kamal/output/otel_logger.rb +70 -0
- data/lib/kamal/secrets/adapters/aws_secrets_manager.rb +10 -2
- data/lib/kamal/secrets/adapters/passbolt.rb +1 -1
- data/lib/kamal/secrets.rb +1 -1
- data/lib/kamal/sshkit_with_ext.rb +9 -4
- data/lib/kamal/version.rb +1 -1
- metadata +23 -2
data/lib/kamal/cli/lock.rb
CHANGED
|
@@ -2,22 +2,17 @@ class Kamal::Cli::Lock < Kamal::Cli::Base
|
|
|
2
2
|
desc "status", "Report lock status"
|
|
3
3
|
def status
|
|
4
4
|
handle_missing_lock do
|
|
5
|
-
|
|
6
|
-
puts capture_with_debug(*KAMAL.lock.status)
|
|
7
|
-
end
|
|
5
|
+
puts capture_lock_status
|
|
8
6
|
end
|
|
9
7
|
end
|
|
10
8
|
|
|
11
9
|
desc "acquire", "Acquire the deploy lock"
|
|
12
10
|
option :message, aliases: "-m", type: :string, desc: "A lock message", required: true
|
|
13
11
|
def acquire
|
|
14
|
-
message = options[:message]
|
|
15
12
|
ensure_run_directory
|
|
16
13
|
|
|
17
14
|
raise_if_locked do
|
|
18
|
-
|
|
19
|
-
execute *KAMAL.lock.acquire(message, KAMAL.config.version), verbosity: :debug
|
|
20
|
-
end
|
|
15
|
+
execute_lock_acquire(options[:message])
|
|
21
16
|
say "Acquired the deploy lock"
|
|
22
17
|
end
|
|
23
18
|
end
|
|
@@ -25,9 +20,7 @@ class Kamal::Cli::Lock < Kamal::Cli::Base
|
|
|
25
20
|
desc "release", "Release the deploy lock"
|
|
26
21
|
def release
|
|
27
22
|
handle_missing_lock do
|
|
28
|
-
|
|
29
|
-
execute *KAMAL.lock.release, verbosity: :debug
|
|
30
|
-
end
|
|
23
|
+
execute_lock_release
|
|
31
24
|
say "Released the deploy lock"
|
|
32
25
|
end
|
|
33
26
|
end
|
|
@@ -35,11 +28,7 @@ class Kamal::Cli::Lock < Kamal::Cli::Base
|
|
|
35
28
|
private
|
|
36
29
|
def handle_missing_lock
|
|
37
30
|
yield
|
|
38
|
-
rescue
|
|
39
|
-
|
|
40
|
-
say "There is no deploy lock"
|
|
41
|
-
else
|
|
42
|
-
raise
|
|
43
|
-
end
|
|
31
|
+
rescue LockMissingError
|
|
32
|
+
say "There is no deploy lock"
|
|
44
33
|
end
|
|
45
34
|
end
|
data/lib/kamal/cli/main.rb
CHANGED
|
@@ -4,7 +4,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
|
4
4
|
option :no_cache, type: :boolean, default: false, desc: "Build without using Docker's build cache"
|
|
5
5
|
def setup
|
|
6
6
|
print_runtime do
|
|
7
|
-
|
|
7
|
+
modify(lock: true) do
|
|
8
8
|
invoke_options = deploy_options
|
|
9
9
|
|
|
10
10
|
say "Ensure Docker is installed...", :magenta
|
|
@@ -19,88 +19,94 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
|
19
19
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
|
20
20
|
option :no_cache, type: :boolean, default: false, desc: "Build without using Docker's build cache"
|
|
21
21
|
def deploy(boot_accessories: false)
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
modify do
|
|
23
|
+
runtime = print_runtime do
|
|
24
|
+
invoke_options = deploy_options
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
26
|
+
if options[:skip_push]
|
|
27
|
+
say "Pull app image...", :magenta
|
|
28
|
+
invoke "kamal:cli:build:pull", [], invoke_options
|
|
29
|
+
else
|
|
30
|
+
say "Build and push app image...", :magenta
|
|
31
|
+
invoke "kamal:cli:build:deliver", [], invoke_options
|
|
32
|
+
end
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
modify(lock: true) do
|
|
35
|
+
run_hook "pre-deploy", secrets: true
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
37
|
+
say "Ensure kamal-proxy is running...", :magenta
|
|
38
|
+
invoke "kamal:cli:proxy:boot", [], invoke_options
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
invoke "kamal:cli:accessory:boot", [ "all" ], invoke_options if boot_accessories
|
|
40
41
|
|
|
41
|
-
|
|
42
|
-
|
|
42
|
+
say "Detect stale containers...", :magenta
|
|
43
|
+
invoke "kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true)
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
invoke "kamal:cli:app:boot", [], invoke_options
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
say "Prune old containers and images...", :magenta
|
|
48
|
+
invoke "kamal:cli:prune:all", [], invoke_options
|
|
49
|
+
end
|
|
48
50
|
end
|
|
49
|
-
end
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
run_hook "post-deploy", secrets: true, runtime: runtime.round.to_s
|
|
53
|
+
end
|
|
52
54
|
end
|
|
53
55
|
|
|
54
56
|
desc "redeploy", "Deploy app to servers without bootstrapping servers, starting kamal-proxy and pruning"
|
|
55
57
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip image build and push"
|
|
56
58
|
option :no_cache, type: :boolean, default: false, desc: "Build without using Docker's build cache"
|
|
57
59
|
def redeploy
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
modify do
|
|
61
|
+
runtime = print_runtime do
|
|
62
|
+
invoke_options = deploy_options
|
|
60
63
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
64
|
+
if options[:skip_push]
|
|
65
|
+
say "Pull app image...", :magenta
|
|
66
|
+
invoke "kamal:cli:build:pull", [], invoke_options
|
|
67
|
+
else
|
|
68
|
+
say "Build and push app image...", :magenta
|
|
69
|
+
invoke "kamal:cli:build:deliver", [], invoke_options
|
|
70
|
+
end
|
|
68
71
|
|
|
69
|
-
|
|
70
|
-
|
|
72
|
+
modify(lock: true) do
|
|
73
|
+
run_hook "pre-deploy", secrets: true
|
|
71
74
|
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
say "Detect stale containers...", :magenta
|
|
76
|
+
invoke "kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true)
|
|
74
77
|
|
|
75
|
-
|
|
78
|
+
invoke "kamal:cli:app:boot", [], invoke_options
|
|
79
|
+
end
|
|
76
80
|
end
|
|
77
|
-
end
|
|
78
81
|
|
|
79
|
-
|
|
82
|
+
run_hook "post-deploy", secrets: true, runtime: runtime.round.to_s
|
|
83
|
+
end
|
|
80
84
|
end
|
|
81
85
|
|
|
82
86
|
desc "rollback [VERSION]", "Rollback app to VERSION"
|
|
83
87
|
def rollback(version)
|
|
84
88
|
rolled_back = false
|
|
85
|
-
runtime = print_runtime do
|
|
86
|
-
with_lock do
|
|
87
|
-
invoke_options = deploy_options
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
|
|
90
|
+
modify do
|
|
91
|
+
runtime = print_runtime do
|
|
92
|
+
modify(lock: true) do
|
|
93
|
+
invoke_options = deploy_options
|
|
91
94
|
|
|
92
|
-
|
|
93
|
-
run_hook "pre-deploy", secrets: true
|
|
95
|
+
KAMAL.config.version = version
|
|
94
96
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
if container_available?(version)
|
|
98
|
+
run_hook "pre-deploy", secrets: true
|
|
99
|
+
|
|
100
|
+
invoke "kamal:cli:app:boot", [], invoke_options.merge(version: version)
|
|
101
|
+
rolled_back = true
|
|
102
|
+
else
|
|
103
|
+
say "The app version '#{version}' is not available as a container (use 'kamal app containers' for available versions)", :red
|
|
104
|
+
end
|
|
99
105
|
end
|
|
100
106
|
end
|
|
101
|
-
end
|
|
102
107
|
|
|
103
|
-
|
|
108
|
+
run_hook "post-deploy", secrets: true, runtime: runtime.round.to_s if rolled_back
|
|
109
|
+
end
|
|
104
110
|
end
|
|
105
111
|
|
|
106
112
|
desc "details", "Show details about all containers"
|
|
@@ -182,7 +188,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
|
182
188
|
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
|
183
189
|
def remove
|
|
184
190
|
confirming "This will remove all containers and images. Are you sure?" do
|
|
185
|
-
|
|
191
|
+
modify(lock: true) do
|
|
186
192
|
invoke "kamal:cli:app:remove", [], options.without(:confirmed)
|
|
187
193
|
invoke "kamal:cli:proxy:remove", [], options.without(:confirmed)
|
|
188
194
|
invoke "kamal:cli:accessory:remove", [ "all" ], options
|
|
@@ -196,7 +202,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
|
196
202
|
option :rolling, type: :boolean, default: false, desc: "Upgrade one host at a time"
|
|
197
203
|
def upgrade
|
|
198
204
|
confirming "This will replace Traefik with kamal-proxy and restart all accessories" do
|
|
199
|
-
|
|
205
|
+
modify(lock: true) do
|
|
200
206
|
if options[:rolling]
|
|
201
207
|
KAMAL.hosts.each do |host|
|
|
202
208
|
KAMAL.with_specific_hosts(host) do
|
data/lib/kamal/cli/proxy.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
2
2
|
desc "boot", "Boot proxy on servers"
|
|
3
3
|
def boot
|
|
4
|
-
|
|
4
|
+
modify(lock: true) do
|
|
5
5
|
on(KAMAL.hosts) do |host|
|
|
6
6
|
execute *KAMAL.docker.create_network
|
|
7
7
|
rescue SSHKit::Command::Failed => e
|
|
@@ -108,7 +108,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
|
108
108
|
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
|
109
109
|
def reboot
|
|
110
110
|
confirming "This will cause a brief outage on each host. Are you sure?" do
|
|
111
|
-
|
|
111
|
+
modify(lock: true) do
|
|
112
112
|
host_groups = options[:rolling] ? KAMAL.proxy_hosts : [ KAMAL.proxy_hosts ]
|
|
113
113
|
host_groups.each do |hosts|
|
|
114
114
|
host_list = Array(hosts).join(",")
|
|
@@ -174,7 +174,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
|
174
174
|
|
|
175
175
|
desc "start", "Start existing proxy container on servers"
|
|
176
176
|
def start
|
|
177
|
-
|
|
177
|
+
modify(lock: true) do
|
|
178
178
|
on(KAMAL.proxy_hosts) do |host|
|
|
179
179
|
execute *KAMAL.auditor.record("Started proxy"), verbosity: :debug
|
|
180
180
|
execute *KAMAL.proxy(host).start
|
|
@@ -184,7 +184,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
|
184
184
|
|
|
185
185
|
desc "stop", "Stop existing proxy container on servers"
|
|
186
186
|
def stop
|
|
187
|
-
|
|
187
|
+
modify(lock: true) do
|
|
188
188
|
on(KAMAL.proxy_hosts) do |host|
|
|
189
189
|
execute *KAMAL.auditor.record("Stopped proxy"), verbosity: :debug
|
|
190
190
|
execute *KAMAL.proxy(host).stop, raise_on_non_zero_exit: false
|
|
@@ -194,7 +194,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
|
194
194
|
|
|
195
195
|
desc "restart", "Restart existing proxy container on servers"
|
|
196
196
|
def restart
|
|
197
|
-
|
|
197
|
+
modify(lock: true) do
|
|
198
198
|
stop
|
|
199
199
|
start
|
|
200
200
|
end
|
|
@@ -236,7 +236,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
|
236
236
|
desc "remove", "Remove proxy container and image from servers"
|
|
237
237
|
option :force, type: :boolean, default: false, desc: "Force removing proxy when apps are still installed"
|
|
238
238
|
def remove
|
|
239
|
-
|
|
239
|
+
modify(lock: true) do
|
|
240
240
|
if removal_allowed?(options[:force])
|
|
241
241
|
stop
|
|
242
242
|
remove_container
|
|
@@ -248,7 +248,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
|
248
248
|
|
|
249
249
|
desc "remove_container", "Remove proxy container from servers", hide: true
|
|
250
250
|
def remove_container
|
|
251
|
-
|
|
251
|
+
modify(lock: true) do
|
|
252
252
|
on(KAMAL.proxy_hosts) do
|
|
253
253
|
execute *KAMAL.auditor.record("Removed proxy container"), verbosity: :debug
|
|
254
254
|
execute *KAMAL.proxy(host).remove_container
|
|
@@ -258,7 +258,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
|
258
258
|
|
|
259
259
|
desc "remove_image", "Remove proxy image from servers", hide: true
|
|
260
260
|
def remove_image
|
|
261
|
-
|
|
261
|
+
modify(lock: true) do
|
|
262
262
|
on(KAMAL.proxy_hosts) do
|
|
263
263
|
execute *KAMAL.auditor.record("Removed proxy image"), verbosity: :debug
|
|
264
264
|
execute *KAMAL.proxy(host).remove_image
|
|
@@ -268,7 +268,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|
|
268
268
|
|
|
269
269
|
desc "remove_proxy_directory", "Remove the proxy directory from servers", hide: true
|
|
270
270
|
def remove_proxy_directory
|
|
271
|
-
|
|
271
|
+
modify(lock: true) do
|
|
272
272
|
on(KAMAL.proxy_hosts) do
|
|
273
273
|
execute *KAMAL.proxy(host).remove_proxy_directory, raise_on_non_zero_exit: false
|
|
274
274
|
end
|
data/lib/kamal/cli/prune.rb
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
class Kamal::Cli::Prune < Kamal::Cli::Base
|
|
2
2
|
desc "all", "Prune unused images and stopped containers"
|
|
3
3
|
def all
|
|
4
|
-
|
|
4
|
+
modify(lock: true) do
|
|
5
5
|
containers
|
|
6
6
|
images
|
|
7
7
|
end
|
|
@@ -9,7 +9,7 @@ class Kamal::Cli::Prune < Kamal::Cli::Base
|
|
|
9
9
|
|
|
10
10
|
desc "images", "Prune unused images"
|
|
11
11
|
def images
|
|
12
|
-
|
|
12
|
+
modify(lock: true) do
|
|
13
13
|
on(KAMAL.hosts) do
|
|
14
14
|
execute *KAMAL.auditor.record("Pruned images"), verbosity: :debug
|
|
15
15
|
execute *KAMAL.prune.dangling_images
|
|
@@ -24,7 +24,7 @@ class Kamal::Cli::Prune < Kamal::Cli::Base
|
|
|
24
24
|
retain = options.fetch(:retain, KAMAL.config.retain_containers)
|
|
25
25
|
raise "retain must be at least 1" if retain < 1
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
modify(lock: true) do
|
|
28
28
|
on(KAMAL.hosts) do
|
|
29
29
|
execute *KAMAL.auditor.record("Pruned containers"), verbosity: :debug
|
|
30
30
|
execute *KAMAL.prune.app_containers(retain: retain)
|
data/lib/kamal/cli/server.rb
CHANGED
|
@@ -1,33 +1,42 @@
|
|
|
1
1
|
class Kamal::Cli::Server < Kamal::Cli::Base
|
|
2
2
|
desc "exec", "Run a custom command on the server (use --help to show options)"
|
|
3
3
|
option :interactive, type: :boolean, aliases: "-i", default: false, desc: "Run the command interactively (use for console/bash)"
|
|
4
|
+
option :raw, type: :boolean, default: false, desc: "Output raw, unmodified stdout"
|
|
4
5
|
def exec(*cmd)
|
|
5
|
-
|
|
6
|
+
raw = options[:raw]
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
if raw && options[:interactive]
|
|
9
|
+
raise ArgumentError, "Raw is not compatible with interactive"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
with_raw_output(raw) do
|
|
13
|
+
pre_connect_if_required
|
|
14
|
+
|
|
15
|
+
cmd = Kamal::Utils.join_commands(cmd)
|
|
16
|
+
hosts = KAMAL.hosts
|
|
17
|
+
quiet = options[:quiet]
|
|
10
18
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
19
|
+
case
|
|
20
|
+
when options[:interactive]
|
|
21
|
+
host = KAMAL.primary_host
|
|
14
22
|
|
|
15
|
-
|
|
23
|
+
say "Running '#{cmd}' on #{host} interactively...", :magenta
|
|
16
24
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
25
|
+
run_locally { exec KAMAL.server.run_over_ssh(cmd, host: host) }
|
|
26
|
+
else
|
|
27
|
+
say "Running '#{cmd}' on #{hosts.join(', ')}...", :magenta
|
|
20
28
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
29
|
+
on(hosts) do |host|
|
|
30
|
+
execute *KAMAL.auditor.record("Executed cmd '#{cmd}' on #{host}"), verbosity: :debug
|
|
31
|
+
puts_by_host host, capture_with_info(cmd, strip: !raw), quiet: quiet, raw: raw
|
|
32
|
+
end
|
|
24
33
|
end
|
|
25
34
|
end
|
|
26
35
|
end
|
|
27
36
|
|
|
28
37
|
desc "bootstrap", "Set up Docker to run Kamal apps"
|
|
29
38
|
def bootstrap
|
|
30
|
-
|
|
39
|
+
modify(lock: true) do
|
|
31
40
|
missing = []
|
|
32
41
|
|
|
33
42
|
on(KAMAL.hosts) do |host|
|
|
@@ -35,6 +44,16 @@ class Kamal::Cli::Server < Kamal::Cli::Base
|
|
|
35
44
|
if execute(*KAMAL.docker.superuser?, raise_on_non_zero_exit: false)
|
|
36
45
|
info "Missing Docker on #{host}. Installing…"
|
|
37
46
|
execute *KAMAL.docker.install
|
|
47
|
+
|
|
48
|
+
unless execute(*KAMAL.docker.root?, raise_on_non_zero_exit: false) ||
|
|
49
|
+
execute(*KAMAL.docker.in_docker_group?, raise_on_non_zero_exit: false)
|
|
50
|
+
execute *KAMAL.docker.add_to_docker_group
|
|
51
|
+
begin
|
|
52
|
+
execute *KAMAL.docker.refresh_session
|
|
53
|
+
rescue IOError
|
|
54
|
+
info "Session refreshed due to group change."
|
|
55
|
+
end
|
|
56
|
+
end
|
|
38
57
|
else
|
|
39
58
|
missing << host
|
|
40
59
|
end
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Secrets defined here are available for reference under registry/password, env/secret, builder/secrets,
|
|
2
2
|
# and accessories/*/env/secret in config/deploy.yml. All secrets should be pulled from either
|
|
3
3
|
# password manager, ENV, or a file. DO NOT ENTER RAW CREDENTIALS HERE! This file needs to be safe for git.
|
|
4
|
+
#
|
|
5
|
+
# When deploying with destinations, shared secrets can go in .kamal/secrets-common and
|
|
6
|
+
# destination-specific secrets in .kamal/secrets.<destination>. This .kamal/secrets file is used
|
|
7
|
+
# only when no destination is selected.
|
|
4
8
|
|
|
5
9
|
# Option 1: Read secrets from the environment
|
|
6
10
|
# KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
|
data/lib/kamal/commander.rb
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
require "active_support/core_ext/enumerable"
|
|
2
2
|
require "active_support/core_ext/module/delegation"
|
|
3
3
|
require "active_support/core_ext/object/blank"
|
|
4
|
+
require "active_support/broadcast_logger"
|
|
5
|
+
require "active_support/notifications"
|
|
4
6
|
|
|
5
7
|
class Kamal::Commander
|
|
6
|
-
attr_accessor :verbosity, :holding_lock, :connected
|
|
8
|
+
attr_accessor :verbosity, :holding_lock, :connected, :logging, :lock_wait, :lock_wait_timeout, :lock_wait_interval
|
|
7
9
|
attr_reader :specific_roles, :specific_hosts
|
|
8
10
|
delegate :hosts, :roles, :primary_host, :primary_role, :roles_on, :app_hosts, :proxy_hosts, :accessory_hosts, to: :specifics
|
|
9
11
|
|
|
@@ -15,8 +17,14 @@ class Kamal::Commander
|
|
|
15
17
|
self.verbosity = :info
|
|
16
18
|
self.holding_lock = ENV["KAMAL_LOCK"] == "true"
|
|
17
19
|
self.connected = false
|
|
20
|
+
self.logging = false
|
|
21
|
+
self.lock_wait = false
|
|
22
|
+
self.lock_wait_timeout = 900
|
|
23
|
+
self.lock_wait_interval = 15
|
|
24
|
+
@modify_depth = 0
|
|
18
25
|
@specifics = @specific_roles = @specific_hosts = nil
|
|
19
26
|
@config = @config_kwargs = nil
|
|
27
|
+
@output_logger = nil
|
|
20
28
|
@commands = {}
|
|
21
29
|
end
|
|
22
30
|
|
|
@@ -46,27 +54,19 @@ class Kamal::Commander
|
|
|
46
54
|
|
|
47
55
|
def specific_roles=(role_names)
|
|
48
56
|
@specifics = nil
|
|
49
|
-
if role_names.present?
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
raise ArgumentError, "No --roles match for #{role_names.join(',')}"
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
@specific_roles
|
|
57
|
+
@specific_roles = if role_names.present?
|
|
58
|
+
filtered = Kamal::Utils.filter_specific_items(role_names, config.roles)
|
|
59
|
+
raise ArgumentError, "No --roles match for #{role_names.join(',')}" if filtered.empty?
|
|
60
|
+
filtered
|
|
57
61
|
end
|
|
58
62
|
end
|
|
59
63
|
|
|
60
64
|
def specific_hosts=(hosts)
|
|
61
65
|
@specifics = nil
|
|
62
|
-
if hosts.present?
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
raise ArgumentError, "No --hosts match for #{hosts.join(',')}"
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
@specific_hosts
|
|
66
|
+
@specific_hosts = if hosts.present?
|
|
67
|
+
filtered = Kamal::Utils.filter_specific_items(hosts, config.all_hosts)
|
|
68
|
+
raise ArgumentError, "No --hosts match for #{hosts.join(',')}" if filtered.empty?
|
|
69
|
+
filtered
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
|
|
@@ -129,6 +129,15 @@ class Kamal::Commander
|
|
|
129
129
|
config.aliases[name]
|
|
130
130
|
end
|
|
131
131
|
|
|
132
|
+
def resolve_alias(name)
|
|
133
|
+
if @config
|
|
134
|
+
@config.aliases[name]&.command
|
|
135
|
+
else
|
|
136
|
+
raw_config = Kamal::Configuration.load_raw_config(**@config_kwargs.to_h.slice(:config_file, :destination))
|
|
137
|
+
raw_config[:aliases]&.dig(name)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
132
141
|
def with_verbosity(level)
|
|
133
142
|
old_level = self.verbosity
|
|
134
143
|
|
|
@@ -141,6 +150,22 @@ class Kamal::Commander
|
|
|
141
150
|
SSHKit.config.output_verbosity = old_level
|
|
142
151
|
end
|
|
143
152
|
|
|
153
|
+
def modify(command:, subcommand:)
|
|
154
|
+
@logging = true
|
|
155
|
+
if modify_started
|
|
156
|
+
ActiveSupport::Notifications.instrument("modify.kamal",
|
|
157
|
+
command: command, subcommand: subcommand, destination: config.destination, hosts: hosts) { yield }
|
|
158
|
+
else
|
|
159
|
+
yield
|
|
160
|
+
end
|
|
161
|
+
ensure
|
|
162
|
+
output_logger.close if modify_finished
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def log(line)
|
|
166
|
+
output_logger << "#{line}\n" if logging
|
|
167
|
+
end
|
|
168
|
+
|
|
144
169
|
def holding_lock?
|
|
145
170
|
self.holding_lock
|
|
146
171
|
end
|
|
@@ -150,6 +175,20 @@ class Kamal::Commander
|
|
|
150
175
|
end
|
|
151
176
|
|
|
152
177
|
private
|
|
178
|
+
def output_logger
|
|
179
|
+
@output_logger ||= ActiveSupport::BroadcastLogger.new
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def modify_started
|
|
183
|
+
@modify_depth += 1
|
|
184
|
+
@modify_depth == 1
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def modify_finished
|
|
188
|
+
@modify_depth -= 1
|
|
189
|
+
@modify_depth == 0
|
|
190
|
+
end
|
|
191
|
+
|
|
153
192
|
# Lazy setup of SSHKit
|
|
154
193
|
def configure_sshkit_with(config)
|
|
155
194
|
SSHKit::Backend::Netssh.pool.idle_timeout = config.sshkit.pool_idle_timeout
|
|
@@ -160,6 +199,21 @@ class Kamal::Commander
|
|
|
160
199
|
end
|
|
161
200
|
SSHKit.config.command_map[:docker] = "docker" # No need to use /usr/bin/env, just clogs up the logs
|
|
162
201
|
SSHKit.config.output_verbosity = verbosity
|
|
202
|
+
|
|
203
|
+
configure_output_with(config)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def configure_output_with(config)
|
|
207
|
+
return unless config.output.enabled?
|
|
208
|
+
|
|
209
|
+
config.output.loggers.each { |logger| output_logger.broadcast_to(logger) }
|
|
210
|
+
|
|
211
|
+
SSHKit.config.output = Kamal::Output::Formatter.new($stdout, output_logger)
|
|
212
|
+
|
|
213
|
+
at_exit { @output_logger&.close }
|
|
214
|
+
rescue => e
|
|
215
|
+
$stderr.puts "Output logger setup failed: #{e.class}: #{e.message}"
|
|
216
|
+
$stderr.puts e.backtrace.join("\n") if ENV["VERBOSE"]
|
|
163
217
|
end
|
|
164
218
|
|
|
165
219
|
def specifics
|
|
@@ -4,7 +4,7 @@ class Kamal::Commands::Accessory < Kamal::Commands::Base
|
|
|
4
4
|
attr_reader :accessory_config
|
|
5
5
|
delegate :service_name, :image, :hosts, :port, :files, :directories, :cmd,
|
|
6
6
|
:network_args, :publish_args, :env_args, :volume_args, :label_args, :option_args,
|
|
7
|
-
:secrets_io, :secrets_path, :env_directory, :proxy, :running_proxy?, :registry,
|
|
7
|
+
:restart_policy, :secrets_io, :secrets_path, :env_directory, :proxy, :running_proxy?, :registry,
|
|
8
8
|
to: :accessory_config
|
|
9
9
|
|
|
10
10
|
def initialize(config, name:)
|
|
@@ -16,7 +16,7 @@ class Kamal::Commands::Accessory < Kamal::Commands::Base
|
|
|
16
16
|
docker :run,
|
|
17
17
|
"--name", service_name,
|
|
18
18
|
"--detach",
|
|
19
|
-
"--restart",
|
|
19
|
+
"--restart", restart_policy,
|
|
20
20
|
*network_args,
|
|
21
21
|
*config.logging_args,
|
|
22
22
|
*publish_args,
|
|
@@ -68,6 +68,7 @@ class Kamal::Commands::Accessory < Kamal::Commands::Base
|
|
|
68
68
|
*network_args,
|
|
69
69
|
*env_args,
|
|
70
70
|
*volume_args,
|
|
71
|
+
*option_args,
|
|
71
72
|
image,
|
|
72
73
|
*command
|
|
73
74
|
end
|
|
@@ -21,7 +21,7 @@ module Kamal::Commands::App::Logging
|
|
|
21
21
|
def container_id_command(container_id)
|
|
22
22
|
case container_id
|
|
23
23
|
when Array then container_id
|
|
24
|
-
when String, Symbol then "echo #{container_id}"
|
|
24
|
+
when String, Symbol then shell([ "echo #{container_id}" ])
|
|
25
25
|
else current_running_container_id
|
|
26
26
|
end
|
|
27
27
|
end
|
data/lib/kamal/commands/app.rb
CHANGED
|
@@ -16,7 +16,7 @@ class Kamal::Commands::App < Kamal::Commands::Base
|
|
|
16
16
|
def run(hostname: nil)
|
|
17
17
|
docker :run,
|
|
18
18
|
"--detach",
|
|
19
|
-
"--restart
|
|
19
|
+
"--restart", role.restart_policy,
|
|
20
20
|
"--name", container_name,
|
|
21
21
|
"--network", "kamal",
|
|
22
22
|
*([ "--hostname", hostname ] if hostname),
|