kamal 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/kamal/cli/accessory.rb +3 -2
- data/lib/kamal/cli/app/boot.rb +67 -0
- data/lib/kamal/cli/app/prepare_assets.rb +24 -0
- data/lib/kamal/cli/app.rb +20 -61
- data/lib/kamal/cli/base.rb +21 -7
- data/lib/kamal/cli/env.rb +3 -3
- data/lib/kamal/cli/main.rb +1 -1
- data/lib/kamal/cli/templates/deploy.yml +1 -1
- data/lib/kamal/cli/templates/sample_hooks/docker-setup.sample +0 -0
- data/lib/kamal/cli/traefik.rb +15 -12
- data/lib/kamal/commander/specifics.rb +49 -0
- data/lib/kamal/commander.rb +9 -33
- data/lib/kamal/commands/accessory.rb +2 -2
- data/lib/kamal/commands/app/assets.rb +4 -4
- data/lib/kamal/commands/app/cord.rb +2 -2
- data/lib/kamal/commands/app/execution.rb +8 -6
- data/lib/kamal/commands/app/images.rb +1 -1
- data/lib/kamal/commands/app.rb +29 -8
- data/lib/kamal/commands/auditor.rb +1 -1
- data/lib/kamal/commands/base.rb +5 -1
- data/lib/kamal/commands/builder/base.rb +14 -4
- data/lib/kamal/commands/builder/multiarch.rb +9 -9
- data/lib/kamal/commands/builder/native/cached.rb +7 -6
- data/lib/kamal/commands/builder/native/remote.rb +9 -9
- data/lib/kamal/commands/builder/native.rb +8 -7
- data/lib/kamal/commands/healthcheck.rb +0 -1
- data/lib/kamal/commands/hook.rb +1 -1
- data/lib/kamal/commands/lock.rb +19 -9
- data/lib/kamal/commands/prune.rb +2 -2
- data/lib/kamal/commands/server.rb +1 -1
- data/lib/kamal/commands/traefik.rb +8 -14
- data/lib/kamal/configuration/accessory.rb +9 -19
- data/lib/kamal/configuration/boot.rb +1 -1
- data/lib/kamal/configuration/builder.rb +7 -3
- data/lib/kamal/configuration/env.rb +40 -0
- data/lib/kamal/configuration/role.rb +12 -42
- data/lib/kamal/configuration.rb +20 -8
- data/lib/kamal/env_file.rb +12 -15
- data/lib/kamal/utils.rb +7 -3
- data/lib/kamal/version.rb +1 -1
- data/lib/kamal.rb +1 -1
- metadata +6 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8429a6060103f16d9aadb517e77fbb32fc6c6d2e6b9b3cf2989c8a9309e0067
|
4
|
+
data.tar.gz: e997f3c5765639c4b14aad08a81344c5af182904e3d80f4867792ed55a9fc25b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 575353b6ea9e9d429a6c6e6b89013fd36f0b371b4edbffbf3ab33f707a9637191872d7463fb670dbe45f9a36bc7a1792335fa9c0709e31d2339b1549c4da32ff
|
7
|
+
data.tar.gz: 6a71437092b0ce21cce12a6d127098e2aba2a0b18846026b6df1c9bb1d33f60d27da3ac1c3b553490a2f4daa76a7ae2e725b4f2ee7918d4cc808bc29b556e8f3
|
data/lib/kamal/cli/accessory.rb
CHANGED
@@ -177,7 +177,7 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|
177
177
|
if name == "all"
|
178
178
|
KAMAL.accessory_names.each { |accessory_name| remove(accessory_name) }
|
179
179
|
else
|
180
|
-
|
180
|
+
confirming "This will remove all containers, images and data directories for #{name}. Are you sure?" do
|
181
181
|
with_accessory(name) do
|
182
182
|
stop(name)
|
183
183
|
remove_container(name)
|
@@ -226,7 +226,8 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|
226
226
|
|
227
227
|
private
|
228
228
|
def with_accessory(name)
|
229
|
-
if
|
229
|
+
if KAMAL.config.accessory(name)
|
230
|
+
accessory = KAMAL.accessory(name)
|
230
231
|
yield accessory, accessory_hosts(accessory)
|
231
232
|
else
|
232
233
|
error_on_missing_accessory(name)
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class Kamal::Cli::App::Boot
|
2
|
+
attr_reader :host, :role, :version, :sshkit
|
3
|
+
delegate :execute, :capture_with_info, :info, to: :sshkit
|
4
|
+
delegate :uses_cord?, :assets?, to: :role
|
5
|
+
|
6
|
+
def initialize(host, role, version, sshkit)
|
7
|
+
@host = host
|
8
|
+
@role = role
|
9
|
+
@version = version
|
10
|
+
@sshkit = sshkit
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
old_version = old_version_renamed_if_clashing
|
15
|
+
|
16
|
+
start_new_version
|
17
|
+
|
18
|
+
if old_version
|
19
|
+
stop_old_version(old_version)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
def app
|
25
|
+
@app ||= KAMAL.app(role: role)
|
26
|
+
end
|
27
|
+
|
28
|
+
def auditor
|
29
|
+
@auditor = KAMAL.auditor(role: role)
|
30
|
+
end
|
31
|
+
|
32
|
+
def audit(message)
|
33
|
+
execute *auditor.record(message), verbosity: :debug
|
34
|
+
end
|
35
|
+
|
36
|
+
def old_version_renamed_if_clashing
|
37
|
+
if capture_with_info(*app.container_id_for_version(version), raise_on_non_zero_exit: false).present?
|
38
|
+
renamed_version = "#{version}_replaced_#{SecureRandom.hex(8)}"
|
39
|
+
info "Renaming container #{version} to #{renamed_version} as already deployed on #{host}"
|
40
|
+
audit("Renaming container #{version} to #{renamed_version}")
|
41
|
+
execute *app.rename_container(version: version, new_version: renamed_version)
|
42
|
+
end
|
43
|
+
|
44
|
+
capture_with_info(*app.current_running_version, raise_on_non_zero_exit: false).strip.presence
|
45
|
+
end
|
46
|
+
|
47
|
+
def start_new_version
|
48
|
+
audit "Booted app version #{version}"
|
49
|
+
execute *app.tie_cord(role.cord_host_file) if uses_cord?
|
50
|
+
execute *app.run(hostname: "#{host}-#{SecureRandom.hex(6)}")
|
51
|
+
Kamal::Cli::Healthcheck::Poller.wait_for_healthy(pause_after_ready: true) { capture_with_info(*app.status(version: version)) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def stop_old_version(version)
|
55
|
+
if uses_cord?
|
56
|
+
cord = capture_with_info(*app.cord(version: version), raise_on_non_zero_exit: false).strip
|
57
|
+
if cord.present?
|
58
|
+
execute *app.cut_cord(cord)
|
59
|
+
Kamal::Cli::Healthcheck::Poller.wait_for_unhealthy(pause_after_ready: true) { capture_with_info(*app.status(version: version)) }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
execute *app.stop(version: version), raise_on_non_zero_exit: false
|
64
|
+
|
65
|
+
execute *app.clean_up_assets if assets?
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class Kamal::Cli::App::PrepareAssets
|
2
|
+
attr_reader :host, :role, :sshkit
|
3
|
+
delegate :execute, :capture_with_info, :info, to: :sshkit
|
4
|
+
delegate :assets?, to: :role
|
5
|
+
|
6
|
+
def initialize(host, role, sshkit)
|
7
|
+
@host = host
|
8
|
+
@role = role
|
9
|
+
@sshkit = sshkit
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
if assets?
|
14
|
+
execute *app.extract_assets
|
15
|
+
old_version = capture_with_info(*app.current_running_version, raise_on_non_zero_exit: false).strip
|
16
|
+
execute *app.sync_asset_volumes(old_version: old_version)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
def app
|
22
|
+
@app ||= KAMAL.app(role: role)
|
23
|
+
end
|
24
|
+
end
|
data/lib/kamal/cli/app.rb
CHANGED
@@ -7,58 +7,23 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|
7
7
|
using_version(version_or_latest) do |version|
|
8
8
|
say "Start container with version #{version} using a #{KAMAL.config.readiness_delay}s readiness delay (or reboot if already running)...", :magenta
|
9
9
|
|
10
|
+
# Assets are prepared in a separate step to ensure they are on all hosts before booting
|
10
11
|
on(KAMAL.hosts) do
|
11
|
-
execute *KAMAL.auditor.record("Tagging #{KAMAL.config.absolute_image} as the latest image"), verbosity: :debug
|
12
|
-
execute *KAMAL.app.tag_current_image_as_latest
|
13
|
-
|
14
12
|
KAMAL.roles_on(host).each do |role|
|
15
|
-
|
16
|
-
|
17
|
-
if role.assets?
|
18
|
-
execute *app.extract_assets
|
19
|
-
old_version = capture_with_info(*app.current_running_version, raise_on_non_zero_exit: false).strip
|
20
|
-
execute *app.sync_asset_volumes(old_version: old_version)
|
21
|
-
end
|
13
|
+
Kamal::Cli::App::PrepareAssets.new(host, role, self).run
|
22
14
|
end
|
23
15
|
end
|
24
16
|
|
25
17
|
on(KAMAL.hosts, **KAMAL.boot_strategy) do |host|
|
26
18
|
KAMAL.roles_on(host).each do |role|
|
27
|
-
|
28
|
-
auditor = KAMAL.auditor(role: role)
|
29
|
-
|
30
|
-
if capture_with_info(*app.container_id_for_version(version), raise_on_non_zero_exit: false).present?
|
31
|
-
tmp_version = "#{version}_replaced_#{SecureRandom.hex(8)}"
|
32
|
-
info "Renaming container #{version} to #{tmp_version} as already deployed on #{host}"
|
33
|
-
execute *auditor.record("Renaming container #{version} to #{tmp_version}"), verbosity: :debug
|
34
|
-
execute *app.rename_container(version: version, new_version: tmp_version)
|
35
|
-
end
|
36
|
-
|
37
|
-
old_version = capture_with_info(*app.current_running_version, raise_on_non_zero_exit: false).strip
|
38
|
-
|
39
|
-
execute *app.tie_cord(role.cord_host_file) if role.uses_cord?
|
40
|
-
|
41
|
-
execute *auditor.record("Booted app version #{version}"), verbosity: :debug
|
42
|
-
|
43
|
-
execute *app.run(hostname: "#{host}-#{SecureRandom.hex(6)}")
|
44
|
-
|
45
|
-
Kamal::Cli::Healthcheck::Poller.wait_for_healthy(pause_after_ready: true) { capture_with_info(*app.status(version: version)) }
|
46
|
-
|
47
|
-
if old_version.present?
|
48
|
-
if role.uses_cord?
|
49
|
-
cord = capture_with_info(*app.cord(version: old_version), raise_on_non_zero_exit: false).strip
|
50
|
-
if cord.present?
|
51
|
-
execute *app.cut_cord(cord)
|
52
|
-
Kamal::Cli::Healthcheck::Poller.wait_for_unhealthy(pause_after_ready: true) { capture_with_info(*app.status(version: old_version)) }
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
execute *app.stop(version: old_version), raise_on_non_zero_exit: false
|
57
|
-
|
58
|
-
execute *app.clean_up_assets if role.assets?
|
59
|
-
end
|
19
|
+
Kamal::Cli::App::Boot.new(host, role, version, self).run
|
60
20
|
end
|
61
21
|
end
|
22
|
+
|
23
|
+
on(KAMAL.hosts) do |host|
|
24
|
+
execute *KAMAL.auditor.record("Tagging #{KAMAL.config.absolute_image} as the latest image"), verbosity: :debug
|
25
|
+
execute *KAMAL.app.tag_latest_image
|
26
|
+
end
|
62
27
|
end
|
63
28
|
end
|
64
29
|
end
|
@@ -107,13 +72,15 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|
107
72
|
desc "exec [CMD]", "Execute a custom command on servers (use --help to show options)"
|
108
73
|
option :interactive, aliases: "-i", type: :boolean, default: false, desc: "Execute command over ssh for an interactive shell (use for console/bash)"
|
109
74
|
option :reuse, type: :boolean, default: false, desc: "Reuse currently running container instead of starting a new one"
|
75
|
+
option :env, aliases: "-e", type: :hash, desc: "Set environment variables for the command"
|
110
76
|
def exec(cmd)
|
77
|
+
env = options[:env]
|
111
78
|
case
|
112
79
|
when options[:interactive] && options[:reuse]
|
113
80
|
say "Get current version of running container...", :magenta unless options[:version]
|
114
81
|
using_version(options[:version] || current_running_version) do |version|
|
115
82
|
say "Launching interactive command with version #{version} via SSH from existing container on #{KAMAL.primary_host}...", :magenta
|
116
|
-
run_locally { exec KAMAL.app(role: KAMAL.primary_role).execute_in_existing_container_over_ssh(cmd, host: KAMAL.primary_host) }
|
83
|
+
run_locally { exec KAMAL.app(role: KAMAL.primary_role).execute_in_existing_container_over_ssh(cmd, host: KAMAL.primary_host, env: env) }
|
117
84
|
end
|
118
85
|
|
119
86
|
when options[:interactive]
|
@@ -121,7 +88,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|
121
88
|
using_version(version_or_latest) do |version|
|
122
89
|
say "Launching interactive command with version #{version} via SSH from new container on #{KAMAL.primary_host}...", :magenta
|
123
90
|
run_locally do
|
124
|
-
exec KAMAL.app(role: KAMAL.primary_role).execute_in_new_container_over_ssh(cmd, host: KAMAL.primary_host)
|
91
|
+
exec KAMAL.app(role: KAMAL.primary_role).execute_in_new_container_over_ssh(cmd, host: KAMAL.primary_host, env: env)
|
125
92
|
end
|
126
93
|
end
|
127
94
|
|
@@ -135,7 +102,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|
135
102
|
|
136
103
|
roles.each do |role|
|
137
104
|
execute *KAMAL.auditor.record("Executed cmd '#{cmd}' on app version #{version}", role: role), verbosity: :debug
|
138
|
-
puts_by_host host, capture_with_info(*KAMAL.app(role: role).execute_in_existing_container(cmd))
|
105
|
+
puts_by_host host, capture_with_info(*KAMAL.app(role: role).execute_in_existing_container(cmd, env: env))
|
139
106
|
end
|
140
107
|
end
|
141
108
|
end
|
@@ -149,7 +116,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|
149
116
|
|
150
117
|
roles.each do |role|
|
151
118
|
execute *KAMAL.auditor.record("Executed cmd '#{cmd}' on app version #{version}"), verbosity: :debug
|
152
|
-
puts_by_host host, capture_with_info(*KAMAL.app(role: role).execute_in_new_container(cmd))
|
119
|
+
puts_by_host host, capture_with_info(*KAMAL.app(role: role).execute_in_new_container(cmd, env: env))
|
153
120
|
end
|
154
121
|
end
|
155
122
|
end
|
@@ -173,7 +140,10 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|
173
140
|
roles = KAMAL.roles_on(host)
|
174
141
|
|
175
142
|
roles.each do |role|
|
176
|
-
|
143
|
+
versions = capture_with_info(*KAMAL.app(role: role).list_versions, raise_on_non_zero_exit: false).split("\n")
|
144
|
+
versions -= [ capture_with_info(*KAMAL.app(role: role).current_running_version, raise_on_non_zero_exit: false).strip ]
|
145
|
+
|
146
|
+
versions.each do |version|
|
177
147
|
if stop
|
178
148
|
puts_by_host host, "Stopping stale container for role #{role} with version #{version}"
|
179
149
|
execute *KAMAL.app(role: role).stop(version: version), raise_on_non_zero_exit: false
|
@@ -207,7 +177,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|
207
177
|
run_locally do
|
208
178
|
info "Following logs on #{KAMAL.primary_host}..."
|
209
179
|
|
210
|
-
KAMAL.specific_roles ||= ["web"]
|
180
|
+
KAMAL.specific_roles ||= [ "web" ]
|
211
181
|
role = KAMAL.roles_on(KAMAL.primary_host).first
|
212
182
|
|
213
183
|
info KAMAL.app(role: role).follow_logs(host: KAMAL.primary_host, lines: lines, grep: grep)
|
@@ -309,18 +279,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|
309
279
|
version.presence
|
310
280
|
end
|
311
281
|
|
312
|
-
def stale_versions(host:, role:)
|
313
|
-
versions = nil
|
314
|
-
on(host) do
|
315
|
-
versions = \
|
316
|
-
capture_with_info(*KAMAL.app(role: role).list_versions, raise_on_non_zero_exit: false)
|
317
|
-
.split("\n")
|
318
|
-
.drop(1)
|
319
|
-
end
|
320
|
-
versions
|
321
|
-
end
|
322
|
-
|
323
282
|
def version_or_latest
|
324
|
-
options[:version] ||
|
283
|
+
options[:version] || KAMAL.config.latest_tag
|
325
284
|
end
|
326
285
|
end
|
data/lib/kamal/cli/base.rb
CHANGED
@@ -73,7 +73,7 @@ module Kamal::Cli
|
|
73
73
|
def print_runtime
|
74
74
|
started_at = Time.now
|
75
75
|
yield
|
76
|
-
|
76
|
+
Time.now - started_at
|
77
77
|
ensure
|
78
78
|
runtime = Time.now - started_at
|
79
79
|
puts " Finished all in #{sprintf("%.1f seconds", runtime)}"
|
@@ -84,7 +84,7 @@ module Kamal::Cli
|
|
84
84
|
|
85
85
|
run_hook "pre-connect"
|
86
86
|
|
87
|
-
|
87
|
+
ensure_run_and_locks_directory
|
88
88
|
|
89
89
|
acquire_lock
|
90
90
|
|
@@ -103,6 +103,16 @@ module Kamal::Cli
|
|
103
103
|
release_lock
|
104
104
|
end
|
105
105
|
|
106
|
+
def confirming(question)
|
107
|
+
return yield if options[:confirmed]
|
108
|
+
|
109
|
+
if ask(question, limited_to: %w[ y N ], default: "N") == "y"
|
110
|
+
yield
|
111
|
+
else
|
112
|
+
say "Aborted", :red
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
106
116
|
def acquire_lock
|
107
117
|
raise_if_locked do
|
108
118
|
say "Acquiring the deploy lock...", :magenta
|
@@ -147,9 +157,9 @@ module Kamal::Cli
|
|
147
157
|
|
148
158
|
say "Running the #{hook} hook...", :magenta
|
149
159
|
run_locally do
|
150
|
-
|
151
|
-
rescue SSHKit::Command::Failed
|
152
|
-
raise HookError.new("Hook `#{hook}` failed")
|
160
|
+
execute *KAMAL.hook.run(hook, **details, **extra_details)
|
161
|
+
rescue SSHKit::Command::Failed => e
|
162
|
+
raise HookError.new("Hook `#{hook}` failed:\n#{e.message}")
|
153
163
|
end
|
154
164
|
end
|
155
165
|
end
|
@@ -176,10 +186,14 @@ module Kamal::Cli
|
|
176
186
|
instance_variable_get("@_invocations").first
|
177
187
|
end
|
178
188
|
|
179
|
-
def
|
189
|
+
def ensure_run_and_locks_directory
|
180
190
|
on(KAMAL.hosts) do
|
181
191
|
execute(*KAMAL.server.ensure_run_directory)
|
182
192
|
end
|
193
|
+
|
194
|
+
on(KAMAL.primary_host) do
|
195
|
+
execute(*KAMAL.lock.ensure_locks_directory)
|
196
|
+
end
|
183
197
|
end
|
184
|
-
|
198
|
+
end
|
185
199
|
end
|
data/lib/kamal/cli/env.rb
CHANGED
@@ -9,20 +9,20 @@ class Kamal::Cli::Env < Kamal::Cli::Base
|
|
9
9
|
|
10
10
|
KAMAL.roles_on(host).each do |role|
|
11
11
|
execute *KAMAL.app(role: role).make_env_directory
|
12
|
-
upload!
|
12
|
+
upload! role.env.secrets_io, role.env.secrets_file, mode: 400
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
16
|
on(KAMAL.traefik_hosts) do
|
17
17
|
execute *KAMAL.traefik.make_env_directory
|
18
|
-
upload!
|
18
|
+
upload! KAMAL.traefik.env.secrets_io, KAMAL.traefik.env.secrets_file, mode: 400
|
19
19
|
end
|
20
20
|
|
21
21
|
on(KAMAL.accessory_hosts) do
|
22
22
|
KAMAL.accessories_on(host).each do |accessory|
|
23
23
|
accessory_config = KAMAL.config.accessory(accessory)
|
24
24
|
execute *KAMAL.accessory(accessory).make_env_directory
|
25
|
-
upload!
|
25
|
+
upload! accessory_config.env.secrets_io, accessory_config.env.secrets_file, mode: 400
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
data/lib/kamal/cli/main.rb
CHANGED
@@ -197,7 +197,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
197
197
|
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
198
198
|
def remove
|
199
199
|
mutating do
|
200
|
-
|
200
|
+
confirming "This will remove all containers and images. Are you sure?" do
|
201
201
|
invoke "kamal:cli:traefik:remove", [], options.without(:confirmed)
|
202
202
|
invoke "kamal:cli:app:remove", [], options.without(:confirmed)
|
203
203
|
invoke "kamal:cli:accessory:remove", [ "all" ], options
|
File without changes
|
data/lib/kamal/cli/traefik.rb
CHANGED
@@ -11,20 +11,23 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|
11
11
|
|
12
12
|
desc "reboot", "Reboot Traefik on servers (stop container, remove container, start new container)"
|
13
13
|
option :rolling, type: :boolean, default: false, desc: "Reboot traefik on hosts in sequence, rather than in parallel"
|
14
|
+
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
14
15
|
def reboot
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
16
|
+
confirming "This will cause a brief outage on each host. Are you sure?" do
|
17
|
+
mutating do
|
18
|
+
host_groups = options[:rolling] ? KAMAL.traefik_hosts : [ KAMAL.traefik_hosts ]
|
19
|
+
host_groups.each do |hosts|
|
20
|
+
host_list = Array(hosts).join(",")
|
21
|
+
run_hook "pre-traefik-reboot", hosts: host_list
|
22
|
+
on(hosts) do
|
23
|
+
execute *KAMAL.auditor.record("Rebooted traefik"), verbosity: :debug
|
24
|
+
execute *KAMAL.registry.login
|
25
|
+
execute *KAMAL.traefik.stop, raise_on_non_zero_exit: false
|
26
|
+
execute *KAMAL.traefik.remove_container
|
27
|
+
execute *KAMAL.traefik.run
|
28
|
+
end
|
29
|
+
run_hook "post-traefik-reboot", hosts: host_list
|
26
30
|
end
|
27
|
-
run_hook "post-traefik-reboot", hosts: host_list
|
28
31
|
end
|
29
32
|
end
|
30
33
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class Kamal::Commander::Specifics
|
2
|
+
attr_reader :primary_host, :primary_role, :hosts, :roles
|
3
|
+
delegate :stable_sort!, to: Kamal::Utils
|
4
|
+
|
5
|
+
def initialize(config, specific_hosts, specific_roles)
|
6
|
+
@config, @specific_hosts, @specific_roles = config, specific_hosts, specific_roles
|
7
|
+
|
8
|
+
@roles, @hosts = specified_roles, specified_hosts
|
9
|
+
|
10
|
+
@primary_host = specific_hosts&.first || primary_specific_role&.primary_host || config.primary_host
|
11
|
+
@primary_role = primary_or_first_role(roles_on(primary_host))
|
12
|
+
|
13
|
+
stable_sort!(roles) { |role| role == primary_role ? 0 : 1 }
|
14
|
+
stable_sort!(hosts) { |host| roles_on(host).any? { |role| role == primary_role } ? 0 : 1 }
|
15
|
+
end
|
16
|
+
|
17
|
+
def roles_on(host)
|
18
|
+
roles.select { |role| role.hosts.include?(host.to_s) }
|
19
|
+
end
|
20
|
+
|
21
|
+
def traefik_hosts
|
22
|
+
specific_hosts || config.traefik_hosts
|
23
|
+
end
|
24
|
+
|
25
|
+
def accessory_hosts
|
26
|
+
specific_hosts || config.accessories.flat_map(&:hosts)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
attr_reader :config, :specific_hosts, :specific_roles
|
31
|
+
|
32
|
+
def primary_specific_role
|
33
|
+
primary_or_first_role(specific_roles) if specific_roles.present?
|
34
|
+
end
|
35
|
+
|
36
|
+
def primary_or_first_role(roles)
|
37
|
+
roles.detect { |role| role == config.primary_role } || roles.first
|
38
|
+
end
|
39
|
+
|
40
|
+
def specified_roles
|
41
|
+
(specific_roles || config.roles) \
|
42
|
+
.select { |role| ((specific_hosts || config.all_hosts) & role.hosts).any? }
|
43
|
+
end
|
44
|
+
|
45
|
+
def specified_hosts
|
46
|
+
(specific_hosts || config.all_hosts) \
|
47
|
+
.select { |host| (specific_roles || config.roles).flat_map(&:hosts).include?(host) }
|
48
|
+
end
|
49
|
+
end
|
data/lib/kamal/commander.rb
CHANGED
@@ -3,11 +3,13 @@ require "active_support/core_ext/module/delegation"
|
|
3
3
|
|
4
4
|
class Kamal::Commander
|
5
5
|
attr_accessor :verbosity, :holding_lock, :hold_lock_on_error
|
6
|
+
delegate :hosts, :roles, :primary_host, :primary_role, :roles_on, :traefik_hosts, :accessory_hosts, to: :specifics
|
6
7
|
|
7
8
|
def initialize
|
8
9
|
self.verbosity = :info
|
9
10
|
self.holding_lock = false
|
10
11
|
self.hold_lock_on_error = false
|
12
|
+
@specifics = nil
|
11
13
|
end
|
12
14
|
|
13
15
|
def config
|
@@ -24,10 +26,12 @@ class Kamal::Commander
|
|
24
26
|
attr_reader :specific_roles, :specific_hosts
|
25
27
|
|
26
28
|
def specific_primary!
|
29
|
+
@specifics = nil
|
27
30
|
self.specific_hosts = [ config.primary_host ]
|
28
31
|
end
|
29
32
|
|
30
33
|
def specific_roles=(role_names)
|
34
|
+
@specifics = nil
|
31
35
|
if role_names.present?
|
32
36
|
@specific_roles = Kamal::Utils.filter_specific_items(role_names, config.roles)
|
33
37
|
|
@@ -40,6 +44,7 @@ class Kamal::Commander
|
|
40
44
|
end
|
41
45
|
|
42
46
|
def specific_hosts=(hosts)
|
47
|
+
@specifics = nil
|
43
48
|
if hosts.present?
|
44
49
|
@specific_hosts = Kamal::Utils.filter_specific_items(hosts, config.all_hosts)
|
45
50
|
|
@@ -51,39 +56,6 @@ class Kamal::Commander
|
|
51
56
|
end
|
52
57
|
end
|
53
58
|
|
54
|
-
def primary_host
|
55
|
-
# Given a list of specific roles, make an effort to match up with the primary_role
|
56
|
-
specific_hosts&.first || specific_roles&.detect { |role| role == config.primary_role }&.primary_host || specific_roles&.first&.primary_host || config.primary_host
|
57
|
-
end
|
58
|
-
|
59
|
-
def primary_role
|
60
|
-
roles_on(primary_host).first
|
61
|
-
end
|
62
|
-
|
63
|
-
def roles
|
64
|
-
(specific_roles || config.roles).select do |role|
|
65
|
-
((specific_hosts || config.all_hosts) & role.hosts).any?
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def hosts
|
70
|
-
(specific_hosts || config.all_hosts).select do |host|
|
71
|
-
(specific_roles || config.roles).flat_map(&:hosts).include?(host)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def roles_on(host)
|
76
|
-
roles.select { |role| role.hosts.include?(host.to_s) }
|
77
|
-
end
|
78
|
-
|
79
|
-
def traefik_hosts
|
80
|
-
specific_hosts || config.traefik_hosts
|
81
|
-
end
|
82
|
-
|
83
|
-
def accessory_hosts
|
84
|
-
specific_hosts || config.accessories.flat_map(&:hosts)
|
85
|
-
end
|
86
|
-
|
87
59
|
def accessory_names
|
88
60
|
config.accessories&.collect(&:name) || []
|
89
61
|
end
|
@@ -181,4 +153,8 @@ class Kamal::Commander
|
|
181
153
|
SSHKit.config.command_map[:docker] = "docker" # No need to use /usr/bin/env, just clogs up the logs
|
182
154
|
SSHKit.config.output_verbosity = verbosity
|
183
155
|
end
|
156
|
+
|
157
|
+
def specifics
|
158
|
+
@specifics ||= Kamal::Commander::Specifics.new(config, specific_hosts, specific_roles)
|
159
|
+
end
|
184
160
|
end
|
@@ -99,11 +99,11 @@ class Kamal::Commands::Accessory < Kamal::Commands::Base
|
|
99
99
|
end
|
100
100
|
|
101
101
|
def make_env_directory
|
102
|
-
make_directory accessory_config.
|
102
|
+
make_directory accessory_config.env.secrets_directory
|
103
103
|
end
|
104
104
|
|
105
105
|
def remove_env_file
|
106
|
-
[:rm, "-f", accessory_config.
|
106
|
+
[ :rm, "-f", accessory_config.env.secrets_file ]
|
107
107
|
end
|
108
108
|
|
109
109
|
private
|
@@ -4,8 +4,8 @@ module Kamal::Commands::App::Assets
|
|
4
4
|
|
5
5
|
combine \
|
6
6
|
make_directory(role.asset_extracted_path),
|
7
|
-
[*docker(:stop, "-t 1", asset_container, "2> /dev/null"), "|| true"],
|
8
|
-
docker(:run, "--name", asset_container, "--detach", "--rm", config.
|
7
|
+
[ *docker(:stop, "-t 1", asset_container, "2> /dev/null"), "|| true" ],
|
8
|
+
docker(:run, "--name", asset_container, "--detach", "--rm", config.absolute_image, "sleep 1000000"),
|
9
9
|
docker(:cp, "-L", "#{asset_container}:#{role.asset_path}/.", role.asset_extracted_path),
|
10
10
|
docker(:stop, "-t 1", asset_container),
|
11
11
|
by: "&&"
|
@@ -17,7 +17,7 @@ module Kamal::Commands::App::Assets
|
|
17
17
|
old_extracted_path, old_volume_path = role.asset_extracted_path(old_version), role.asset_volume(old_version).host_path
|
18
18
|
end
|
19
19
|
|
20
|
-
commands = [make_directory(new_volume_path), copy_contents(new_extracted_path, new_volume_path)]
|
20
|
+
commands = [ make_directory(new_volume_path), copy_contents(new_extracted_path, new_volume_path) ]
|
21
21
|
|
22
22
|
if old_version.present?
|
23
23
|
commands << copy_contents(new_extracted_path, old_volume_path, continue_on_error: true)
|
@@ -46,6 +46,6 @@ module Kamal::Commands::App::Assets
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def copy_contents(source, destination, continue_on_error: false)
|
49
|
-
[ :cp, "-rnT", "#{source}", destination, *("|| true" if continue_on_error)]
|
49
|
+
[ :cp, "-rnT", "#{source}", destination, *("|| true" if continue_on_error) ]
|
50
50
|
end
|
51
51
|
end
|
@@ -2,7 +2,7 @@ module Kamal::Commands::App::Cord
|
|
2
2
|
def cord(version:)
|
3
3
|
pipe \
|
4
4
|
docker(:inspect, "-f '{{ range .Mounts }}{{printf \"%s %s\\n\" .Source .Destination}}{{ end }}'", container_name(version)),
|
5
|
-
[:awk, "'$2 == \"#{role.cord_volume.container_path}\" {print $1}'"]
|
5
|
+
[ :awk, "'$2 == \"#{role.cord_volume.container_path}\" {print $1}'" ]
|
6
6
|
end
|
7
7
|
|
8
8
|
def tie_cord(cord)
|
@@ -17,6 +17,6 @@ module Kamal::Commands::App::Cord
|
|
17
17
|
def create_empty_file(file)
|
18
18
|
chain \
|
19
19
|
make_directory_for(file),
|
20
|
-
[:touch, file]
|
20
|
+
[ :touch, file ]
|
21
21
|
end
|
22
22
|
end
|
@@ -1,27 +1,29 @@
|
|
1
1
|
module Kamal::Commands::App::Execution
|
2
|
-
def execute_in_existing_container(*command, interactive: false)
|
2
|
+
def execute_in_existing_container(*command, interactive: false, env:)
|
3
3
|
docker :exec,
|
4
4
|
("-it" if interactive),
|
5
|
+
*argumentize("--env", env),
|
5
6
|
container_name,
|
6
7
|
*command
|
7
8
|
end
|
8
9
|
|
9
|
-
def execute_in_new_container(*command, interactive: false)
|
10
|
+
def execute_in_new_container(*command, interactive: false, env:)
|
10
11
|
docker :run,
|
11
12
|
("-it" if interactive),
|
12
13
|
"--rm",
|
13
14
|
*role&.env_args,
|
15
|
+
*argumentize("--env", env),
|
14
16
|
*config.volume_args,
|
15
17
|
*role&.option_args,
|
16
18
|
config.absolute_image,
|
17
19
|
*command
|
18
20
|
end
|
19
21
|
|
20
|
-
def execute_in_existing_container_over_ssh(*command, host:)
|
21
|
-
run_over_ssh execute_in_existing_container(*command, interactive: true), host: host
|
22
|
+
def execute_in_existing_container_over_ssh(*command, host:, env:)
|
23
|
+
run_over_ssh execute_in_existing_container(*command, interactive: true, env: env), host: host
|
22
24
|
end
|
23
25
|
|
24
|
-
def execute_in_new_container_over_ssh(*command, host:)
|
25
|
-
run_over_ssh execute_in_new_container(*command, interactive: true), host: host
|
26
|
+
def execute_in_new_container_over_ssh(*command, host:, env:)
|
27
|
+
run_over_ssh execute_in_new_container(*command, interactive: true, env: env), host: host
|
26
28
|
end
|
27
29
|
end
|