kamal 1.0.0 → 1.3.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 +12 -8
- data/lib/kamal/cli/app.rb +6 -2
- data/lib/kamal/cli/base.rb +9 -4
- data/lib/kamal/cli/healthcheck.rb +1 -0
- data/lib/kamal/cli/main.rb +10 -5
- data/lib/kamal/cli/templates/deploy.yml +12 -0
- data/lib/kamal/cli/templates/sample_hooks/post-traefik-reboot.sample +3 -0
- data/lib/kamal/cli/templates/sample_hooks/pre-build.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/pre-traefik-reboot.sample +3 -0
- data/lib/kamal/cli/traefik.rb +12 -6
- data/lib/kamal/commander.rb +21 -4
- data/lib/kamal/commands/app.rb +1 -0
- data/lib/kamal/commands/base.rb +1 -1
- data/lib/kamal/commands/docker.rb +1 -1
- data/lib/kamal/commands/healthcheck.rb +5 -5
- data/lib/kamal/commands/traefik.rb +9 -1
- data/lib/kamal/configuration/accessory.rb +10 -6
- data/lib/kamal/configuration/role.rb +10 -1
- data/lib/kamal/configuration/ssh.rb +5 -1
- data/lib/kamal/configuration.rb +35 -15
- data/lib/kamal/utils/sensitive.rb +1 -0
- data/lib/kamal/utils.rb +16 -0
- data/lib/kamal/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4a11bf8b2153b8bc4323e4b03e289d7c0c5e60a9dcc9012103ae701ae2c3256b
|
4
|
+
data.tar.gz: bc4b5c88e63a717fc539c71c00fb8207ee78693ade9658ac8effd3ecdd5249ab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8cbc84077617cfd72ad225cb458b0df9d36fe88b2f2a640bec9f012b4f92272d5cd62617580e75f217715be97e88c126bfe842dcdc1ab262c82db3fc9e0c746
|
7
|
+
data.tar.gz: c3e1de191ebcf4621fe15e59ee8b976491a58e8ffbd40a8862d15040837b7669f7e26372382711b118eb357035f047d920dd7817de7fc415aa5b8aa8a7e74a60
|
data/lib/kamal/cli/accessory.rb
CHANGED
@@ -49,17 +49,21 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
-
desc "reboot [NAME]", "Reboot existing accessory on host (stop container, remove container, start new container)"
|
52
|
+
desc "reboot [NAME]", "Reboot existing accessory on host (stop container, remove container, start new container; use NAME=all to boot all accessories)"
|
53
53
|
def reboot(name)
|
54
54
|
mutating do
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
55
|
+
if name == "all"
|
56
|
+
KAMAL.accessory_names.each { |accessory_name| reboot(accessory_name) }
|
57
|
+
else
|
58
|
+
with_accessory(name) do |accessory|
|
59
|
+
on(accessory.hosts) do
|
60
|
+
execute *KAMAL.registry.login
|
61
|
+
end
|
59
62
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
+
stop(name)
|
64
|
+
remove_container(name)
|
65
|
+
boot(name, login: false)
|
66
|
+
end
|
63
67
|
end
|
64
68
|
end
|
65
69
|
end
|
data/lib/kamal/cli/app.rb
CHANGED
@@ -147,8 +147,12 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|
147
147
|
using_version(version_or_latest) do |version|
|
148
148
|
say "Launching command with version #{version} from new container...", :magenta
|
149
149
|
on(KAMAL.hosts) do |host|
|
150
|
-
|
151
|
-
|
150
|
+
roles = KAMAL.roles_on(host)
|
151
|
+
|
152
|
+
roles.each do |role|
|
153
|
+
execute *KAMAL.auditor.record("Executed cmd '#{cmd}' on app version #{version}"), verbosity: :debug
|
154
|
+
puts_by_host host, capture_with_info(*KAMAL.app(role: role).execute_in_new_container(cmd))
|
155
|
+
end
|
152
156
|
end
|
153
157
|
end
|
154
158
|
end
|
data/lib/kamal/cli/base.rb
CHANGED
@@ -14,8 +14,8 @@ module Kamal::Cli
|
|
14
14
|
class_option :version, desc: "Run commands against a specific app version"
|
15
15
|
|
16
16
|
class_option :primary, type: :boolean, aliases: "-p", desc: "Run commands only on primary host instead of all"
|
17
|
-
class_option :hosts, aliases: "-h", desc: "Run commands on these hosts instead of all (separate by comma)"
|
18
|
-
class_option :roles, aliases: "-r", desc: "Run commands on these roles instead of all (separate by comma)"
|
17
|
+
class_option :hosts, aliases: "-h", desc: "Run commands on these hosts instead of all (separate by comma, supports wildcards with *)"
|
18
|
+
class_option :roles, aliases: "-r", desc: "Run commands on these roles instead of all (separate by comma, supports wildcards with *)"
|
19
19
|
|
20
20
|
class_option :config_file, aliases: "-c", default: "config/deploy.yml", desc: "Path to config file"
|
21
21
|
class_option :destination, aliases: "-d", desc: "Specify destination to be used for config file (staging -> deploy.staging.yml)"
|
@@ -24,6 +24,7 @@ module Kamal::Cli
|
|
24
24
|
|
25
25
|
def initialize(*)
|
26
26
|
super
|
27
|
+
@original_env = ENV.to_h.dup
|
27
28
|
load_envs
|
28
29
|
initialize_commander(options_with_subcommand_class_options)
|
29
30
|
end
|
@@ -37,6 +38,12 @@ module Kamal::Cli
|
|
37
38
|
end
|
38
39
|
end
|
39
40
|
|
41
|
+
def reload_envs
|
42
|
+
ENV.clear
|
43
|
+
ENV.update(@original_env)
|
44
|
+
load_envs
|
45
|
+
end
|
46
|
+
|
40
47
|
def options_with_subcommand_class_options
|
41
48
|
options.merge(@_initializer.last[:class_options] || {})
|
42
49
|
end
|
@@ -75,8 +82,6 @@ module Kamal::Cli
|
|
75
82
|
def mutating
|
76
83
|
return yield if KAMAL.holding_lock?
|
77
84
|
|
78
|
-
KAMAL.config.ensure_env_available
|
79
|
-
|
80
85
|
run_hook "pre-connect"
|
81
86
|
|
82
87
|
ensure_run_directory
|
@@ -3,6 +3,7 @@ class Kamal::Cli::Healthcheck < Kamal::Cli::Base
|
|
3
3
|
|
4
4
|
desc "perform", "Health check current app version"
|
5
5
|
def perform
|
6
|
+
raise "The primary host is not configured to run Traefik" unless KAMAL.config.role(KAMAL.config.primary_role).running_traefik?
|
6
7
|
on(KAMAL.primary_host) do
|
7
8
|
begin
|
8
9
|
execute *KAMAL.healthcheck.run
|
data/lib/kamal/cli/main.rb
CHANGED
@@ -38,8 +38,10 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
38
38
|
say "Ensure Traefik is running...", :magenta
|
39
39
|
invoke "kamal:cli:traefik:boot", [], invoke_options
|
40
40
|
|
41
|
-
|
42
|
-
|
41
|
+
if KAMAL.config.role(KAMAL.config.primary_role).running_traefik?
|
42
|
+
say "Ensure app can pass healthcheck...", :magenta
|
43
|
+
invoke "kamal:cli:healthcheck:perform", [], invoke_options
|
44
|
+
end
|
43
45
|
|
44
46
|
say "Detect stale containers...", :magenta
|
45
47
|
invoke "kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true)
|
@@ -170,6 +172,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
170
172
|
end
|
171
173
|
|
172
174
|
desc "envify", "Create .env by evaluating .env.erb (or .env.staging.erb -> .env.staging when using -d staging)"
|
175
|
+
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip .env file push"
|
173
176
|
def envify
|
174
177
|
if destination = options[:destination]
|
175
178
|
env_template_path = ".env.#{destination}.erb"
|
@@ -179,10 +182,12 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|
179
182
|
env_path = ".env"
|
180
183
|
end
|
181
184
|
|
182
|
-
File.write(env_path, ERB.new(File.read(env_template_path)).result, perm: 0600)
|
185
|
+
File.write(env_path, ERB.new(File.read(env_template_path), trim_mode: "-").result, perm: 0600)
|
183
186
|
|
184
|
-
|
185
|
-
|
187
|
+
unless options[:skip_push]
|
188
|
+
reload_envs
|
189
|
+
invoke "kamal:cli:env:push", options
|
190
|
+
end
|
186
191
|
end
|
187
192
|
|
188
193
|
desc "remove", "Remove Traefik, app, accessories, and registry session from servers"
|
@@ -83,3 +83,15 @@ registry:
|
|
83
83
|
# boot:
|
84
84
|
# limit: 10 # Can also specify as a percentage of total hosts, such as "25%"
|
85
85
|
# wait: 2
|
86
|
+
|
87
|
+
# Configure the role used to determine the primary_host. This host takes
|
88
|
+
# deploy locks, runs health checks during the deploy, and follow logs, etc.
|
89
|
+
#
|
90
|
+
# Caution: there's no support for role renaming yet, so be careful to cleanup
|
91
|
+
# the previous role on the deployed hosts.
|
92
|
+
# primary_role: web
|
93
|
+
|
94
|
+
# Controls if we abort when see a role with no hosts. Disabling this may be
|
95
|
+
# useful for more complex deploy configurations.
|
96
|
+
#
|
97
|
+
# allow_empty_roles: false
|
data/lib/kamal/cli/traefik.rb
CHANGED
@@ -13,12 +13,18 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|
13
13
|
option :rolling, type: :boolean, default: false, desc: "Reboot traefik on hosts in sequence, rather than in parallel"
|
14
14
|
def reboot
|
15
15
|
mutating do
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
host_groups = options[:rolling] ? KAMAL.traefik_hosts : [KAMAL.traefik_hosts]
|
17
|
+
host_groups.each do |hosts|
|
18
|
+
host_list = Array(hosts).join(",")
|
19
|
+
run_hook "pre-traefik-reboot", hosts: host_list
|
20
|
+
on(hosts) do
|
21
|
+
execute *KAMAL.auditor.record("Rebooted traefik"), verbosity: :debug
|
22
|
+
execute *KAMAL.registry.login
|
23
|
+
execute *KAMAL.traefik.stop
|
24
|
+
execute *KAMAL.traefik.remove_container
|
25
|
+
execute *KAMAL.traefik.run
|
26
|
+
end
|
27
|
+
run_hook "post-traefik-reboot", hosts: host_list
|
22
28
|
end
|
23
29
|
end
|
24
30
|
end
|
data/lib/kamal/commander.rb
CHANGED
@@ -24,19 +24,36 @@ class Kamal::Commander
|
|
24
24
|
attr_reader :specific_roles, :specific_hosts
|
25
25
|
|
26
26
|
def specific_primary!
|
27
|
-
self.specific_hosts = [ config.
|
27
|
+
self.specific_hosts = [ config.primary_host ]
|
28
28
|
end
|
29
29
|
|
30
30
|
def specific_roles=(role_names)
|
31
|
-
|
31
|
+
if role_names.present?
|
32
|
+
@specific_roles = Kamal::Utils.filter_specific_items(role_names, config.roles)
|
33
|
+
|
34
|
+
if @specific_roles.empty?
|
35
|
+
raise ArgumentError, "No --roles match for #{role_names.join(',')}"
|
36
|
+
end
|
37
|
+
|
38
|
+
@specific_roles
|
39
|
+
end
|
32
40
|
end
|
33
41
|
|
34
42
|
def specific_hosts=(hosts)
|
35
|
-
|
43
|
+
if hosts.present?
|
44
|
+
@specific_hosts = Kamal::Utils.filter_specific_items(hosts, config.all_hosts)
|
45
|
+
|
46
|
+
if @specific_hosts.empty?
|
47
|
+
raise ArgumentError, "No --hosts match for #{hosts.join(',')}"
|
48
|
+
end
|
49
|
+
|
50
|
+
@specific_hosts
|
51
|
+
end
|
36
52
|
end
|
37
53
|
|
38
54
|
def primary_host
|
39
|
-
|
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.name == config.primary_role }&.primary_host || specific_roles&.first&.primary_host || config.primary_host
|
40
57
|
end
|
41
58
|
|
42
59
|
def primary_role
|
data/lib/kamal/commands/app.rb
CHANGED
@@ -18,6 +18,7 @@ class Kamal::Commands::App < Kamal::Commands::Base
|
|
18
18
|
"--name", container_name,
|
19
19
|
*(["--hostname", hostname] if hostname),
|
20
20
|
"-e", "KAMAL_CONTAINER_NAME=\"#{container_name}\"",
|
21
|
+
"-e", "KAMAL_VERSION=\"#{config.version}\"",
|
21
22
|
*role_config.env_args,
|
22
23
|
*role_config.health_check_args,
|
23
24
|
*config.logging_args,
|
data/lib/kamal/commands/base.rb
CHANGED
@@ -18,7 +18,7 @@ module Kamal::Commands
|
|
18
18
|
elsif config.ssh.proxy && config.ssh.proxy.is_a?(Net::SSH::Proxy::Command)
|
19
19
|
cmd << " -o ProxyCommand='#{config.ssh.proxy.command_line_template}'"
|
20
20
|
end
|
21
|
-
cmd << " -t #{config.ssh.user}@#{host} '#{command.join(" ")}'"
|
21
|
+
cmd << " -t #{config.ssh.user}@#{host} -p #{config.ssh.port} '#{command.join(" ")}'"
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -16,6 +16,6 @@ class Kamal::Commands::Docker < Kamal::Commands::Base
|
|
16
16
|
|
17
17
|
# Do we have superuser access to install Docker and start system services?
|
18
18
|
def superuser?
|
19
|
-
[ '[ "${EUID:-$(id -u)}" -eq 0 ]' ]
|
19
|
+
[ '[ "${EUID:-$(id -u)}" -eq 0 ] || command -v sudo >/dev/null || command -v su >/dev/null' ]
|
20
20
|
end
|
21
21
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class Kamal::Commands::Healthcheck < Kamal::Commands::Base
|
2
2
|
|
3
3
|
def run
|
4
|
-
|
4
|
+
primary = config.role(config.primary_role)
|
5
5
|
|
6
6
|
docker :run,
|
7
7
|
"--detach",
|
@@ -9,12 +9,12 @@ class Kamal::Commands::Healthcheck < Kamal::Commands::Base
|
|
9
9
|
"--publish", "#{exposed_port}:#{config.healthcheck["port"]}",
|
10
10
|
"--label", "service=#{config.healthcheck_service}",
|
11
11
|
"-e", "KAMAL_CONTAINER_NAME=\"#{config.healthcheck_service}\"",
|
12
|
-
*
|
13
|
-
*
|
12
|
+
*primary.env_args,
|
13
|
+
*primary.health_check_args(cord: false),
|
14
14
|
*config.volume_args,
|
15
|
-
*
|
15
|
+
*primary.option_args,
|
16
16
|
config.absolute_image,
|
17
|
-
|
17
|
+
primary.cmd
|
18
18
|
end
|
19
19
|
|
20
20
|
def status
|
@@ -6,6 +6,14 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
|
|
6
6
|
DEFAULT_ARGS = {
|
7
7
|
'log.level' => 'DEBUG'
|
8
8
|
}
|
9
|
+
DEFAULT_LABELS = {
|
10
|
+
# These ensure we serve a 502 rather than a 404 if no containers are available
|
11
|
+
"traefik.http.routers.catchall.entryPoints" => "http",
|
12
|
+
"traefik.http.routers.catchall.rule" => "PathPrefix(`/`)",
|
13
|
+
"traefik.http.routers.catchall.service" => "unavailable",
|
14
|
+
"traefik.http.routers.catchall.priority" => 1,
|
15
|
+
"traefik.http.services.unavailable.loadbalancer.server.port" => "0"
|
16
|
+
}
|
9
17
|
|
10
18
|
def run
|
11
19
|
docker :run, "--name traefik",
|
@@ -97,7 +105,7 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
|
|
97
105
|
end
|
98
106
|
|
99
107
|
def labels
|
100
|
-
config.traefik["labels"] ||
|
108
|
+
DEFAULT_LABELS.merge(config.traefik["labels"] || {})
|
101
109
|
end
|
102
110
|
|
103
111
|
def image
|
@@ -70,8 +70,8 @@ class Kamal::Configuration::Accessory
|
|
70
70
|
|
71
71
|
def directories
|
72
72
|
specifics["directories"]&.to_h do |host_to_container_mapping|
|
73
|
-
|
74
|
-
[ expand_host_path(
|
73
|
+
host_path, container_path = host_to_container_mapping.split(":")
|
74
|
+
[ expand_host_path(host_path), container_path ]
|
75
75
|
end || {}
|
76
76
|
end
|
77
77
|
|
@@ -138,13 +138,17 @@ class Kamal::Configuration::Accessory
|
|
138
138
|
|
139
139
|
def remote_directories_as_volumes
|
140
140
|
specifics["directories"]&.collect do |host_to_container_mapping|
|
141
|
-
|
142
|
-
[ expand_host_path(
|
141
|
+
host_path, container_path = host_to_container_mapping.split(":")
|
142
|
+
[ expand_host_path(host_path), container_path ].join(":")
|
143
143
|
end || []
|
144
144
|
end
|
145
145
|
|
146
|
-
def expand_host_path(
|
147
|
-
"#{service_data_directory}/#{
|
146
|
+
def expand_host_path(host_path)
|
147
|
+
absolute_path?(host_path) ? host_path : "#{service_data_directory}/#{host_path}"
|
148
|
+
end
|
149
|
+
|
150
|
+
def absolute_path?(path)
|
151
|
+
Pathname.new(path).absolute?
|
148
152
|
end
|
149
153
|
|
150
154
|
def service_data_directory
|
@@ -93,7 +93,15 @@ class Kamal::Configuration::Role
|
|
93
93
|
|
94
94
|
|
95
95
|
def running_traefik?
|
96
|
-
|
96
|
+
if specializations["traefik"].nil?
|
97
|
+
primary?
|
98
|
+
else
|
99
|
+
specializations["traefik"]
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def primary?
|
104
|
+
@config.primary_role == name
|
97
105
|
end
|
98
106
|
|
99
107
|
|
@@ -185,6 +193,7 @@ class Kamal::Configuration::Role
|
|
185
193
|
"traefik.http.services.#{traefik_service}.loadbalancer.server.scheme" => "http",
|
186
194
|
|
187
195
|
"traefik.http.routers.#{traefik_service}.rule" => "PathPrefix(`/`)",
|
196
|
+
"traefik.http.routers.#{traefik_service}.priority" => "2",
|
188
197
|
"traefik.http.middlewares.#{traefik_service}-retry.retry.attempts" => "5",
|
189
198
|
"traefik.http.middlewares.#{traefik_service}-retry.retry.initialinterval" => "500ms",
|
190
199
|
"traefik.http.routers.#{traefik_service}.middlewares" => "#{traefik_service}-retry@docker"
|
@@ -9,6 +9,10 @@ class Kamal::Configuration::Ssh
|
|
9
9
|
config.fetch("user", "root")
|
10
10
|
end
|
11
11
|
|
12
|
+
def port
|
13
|
+
config.fetch("port", 22)
|
14
|
+
end
|
15
|
+
|
12
16
|
def proxy
|
13
17
|
if (proxy = config["proxy"])
|
14
18
|
Net::SSH::Proxy::Jump.new(proxy.include?("@") ? proxy : "root@#{proxy}")
|
@@ -18,7 +22,7 @@ class Kamal::Configuration::Ssh
|
|
18
22
|
end
|
19
23
|
|
20
24
|
def options
|
21
|
-
{ user: user, proxy: proxy, logger: logger, keepalive: true, keepalive_interval: 30 }.compact
|
25
|
+
{ user: user, port: port, proxy: proxy, logger: logger, keepalive: true, keepalive_interval: 30 }.compact
|
22
26
|
end
|
23
27
|
|
24
28
|
def to_h
|
data/lib/kamal/configuration.rb
CHANGED
@@ -25,7 +25,9 @@ class Kamal::Configuration
|
|
25
25
|
|
26
26
|
def load_config_file(file)
|
27
27
|
if file.exist?
|
28
|
-
|
28
|
+
# Newer Psych doesn't load aliases by default
|
29
|
+
load_method = YAML.respond_to?(:unsafe_load) ? :unsafe_load : :load
|
30
|
+
YAML.send(load_method, ERB.new(IO.read(file)).result).symbolize_keys
|
29
31
|
else
|
30
32
|
raise "Configuration file not found in #{file}"
|
31
33
|
end
|
@@ -89,14 +91,21 @@ class Kamal::Configuration
|
|
89
91
|
roles.flat_map(&:hosts).uniq
|
90
92
|
end
|
91
93
|
|
92
|
-
def
|
93
|
-
role(
|
94
|
+
def primary_host
|
95
|
+
role(primary_role)&.primary_host
|
94
96
|
end
|
95
97
|
|
96
|
-
def
|
97
|
-
roles.select(&:running_traefik?)
|
98
|
+
def traefik_roles
|
99
|
+
roles.select(&:running_traefik?)
|
98
100
|
end
|
99
101
|
|
102
|
+
def traefik_role_names
|
103
|
+
traefik_roles.flat_map(&:name)
|
104
|
+
end
|
105
|
+
|
106
|
+
def traefik_hosts
|
107
|
+
traefik_roles.flat_map(&:hosts).uniq
|
108
|
+
end
|
100
109
|
|
101
110
|
def repository
|
102
111
|
[ raw_config.registry["server"], image ].compact.join("/")
|
@@ -199,23 +208,24 @@ class Kamal::Configuration
|
|
199
208
|
raw_config.asset_path
|
200
209
|
end
|
201
210
|
|
211
|
+
def primary_role
|
212
|
+
raw_config.primary_role || "web"
|
213
|
+
end
|
202
214
|
|
203
|
-
def
|
204
|
-
|
215
|
+
def allow_empty_roles?
|
216
|
+
raw_config.allow_empty_roles
|
205
217
|
end
|
206
218
|
|
207
|
-
# Will raise KeyError if any secret ENVs are missing
|
208
|
-
def ensure_env_available
|
209
|
-
roles.collect(&:env_file).each(&:to_s)
|
210
219
|
|
211
|
-
|
220
|
+
def valid?
|
221
|
+
ensure_destination_if_required && ensure_required_keys_present && ensure_valid_kamal_version
|
212
222
|
end
|
213
223
|
|
214
224
|
def to_h
|
215
225
|
{
|
216
226
|
roles: role_names,
|
217
227
|
hosts: all_hosts,
|
218
|
-
primary_host:
|
228
|
+
primary_host: primary_host,
|
219
229
|
version: version,
|
220
230
|
repository: repository,
|
221
231
|
absolute_image: absolute_image,
|
@@ -254,9 +264,19 @@ class Kamal::Configuration
|
|
254
264
|
raise ArgumentError, "You must specify a password for the registry in config/deploy.yml (or set the ENV variable if that's used)"
|
255
265
|
end
|
256
266
|
|
257
|
-
|
258
|
-
|
259
|
-
|
267
|
+
unless role_names.include?(primary_role)
|
268
|
+
raise ArgumentError, "The primary_role #{primary_role} isn't defined"
|
269
|
+
end
|
270
|
+
|
271
|
+
if role(primary_role).hosts.empty?
|
272
|
+
raise ArgumentError, "No servers specified for the #{primary_role} primary_role"
|
273
|
+
end
|
274
|
+
|
275
|
+
unless allow_empty_roles?
|
276
|
+
roles.each do |role|
|
277
|
+
if role.hosts.empty?
|
278
|
+
raise ArgumentError, "No servers specified for the #{role.name} role. You can ignore this with allow_empty_roles: true"
|
279
|
+
end
|
260
280
|
end
|
261
281
|
end
|
262
282
|
|
data/lib/kamal/utils.rb
CHANGED
@@ -58,4 +58,20 @@ module Kamal::Utils
|
|
58
58
|
.gsub(/`/, '\\\\`')
|
59
59
|
.gsub(DOLLAR_SIGN_WITHOUT_SHELL_EXPANSION_REGEX, '\$')
|
60
60
|
end
|
61
|
+
|
62
|
+
# Apply a list of host or role filters, including wildcard matches
|
63
|
+
def filter_specific_items(filters, items)
|
64
|
+
matches = []
|
65
|
+
|
66
|
+
Array(filters).select do |filter|
|
67
|
+
matches += Array(items).select do |item|
|
68
|
+
# Only allow * for a wildcard
|
69
|
+
pattern = Regexp.escape(filter).gsub('\*', '.*')
|
70
|
+
# items are roles or hosts
|
71
|
+
(item.respond_to?(:name) ? item.name : item).match(/^#{pattern}$/)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
matches
|
76
|
+
end
|
61
77
|
end
|
data/lib/kamal/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kamal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-11-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -204,9 +204,11 @@ files:
|
|
204
204
|
- lib/kamal/cli/server.rb
|
205
205
|
- lib/kamal/cli/templates/deploy.yml
|
206
206
|
- lib/kamal/cli/templates/sample_hooks/post-deploy.sample
|
207
|
+
- lib/kamal/cli/templates/sample_hooks/post-traefik-reboot.sample
|
207
208
|
- lib/kamal/cli/templates/sample_hooks/pre-build.sample
|
208
209
|
- lib/kamal/cli/templates/sample_hooks/pre-connect.sample
|
209
210
|
- lib/kamal/cli/templates/sample_hooks/pre-deploy.sample
|
211
|
+
- lib/kamal/cli/templates/sample_hooks/pre-traefik-reboot.sample
|
210
212
|
- lib/kamal/cli/templates/template.env
|
211
213
|
- lib/kamal/cli/traefik.rb
|
212
214
|
- lib/kamal/commander.rb
|
@@ -270,7 +272,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
270
272
|
- !ruby/object:Gem::Version
|
271
273
|
version: '0'
|
272
274
|
requirements: []
|
273
|
-
rubygems_version: 3.4.
|
275
|
+
rubygems_version: 3.4.22
|
274
276
|
signing_key:
|
275
277
|
specification_version: 4
|
276
278
|
summary: Deploy web apps in containers to servers running Docker with zero downtime.
|