Class: Kamal::Configuration::Role
- Inherits:
-
Object
- Object
- Kamal::Configuration::Role
show all
- Includes:
- Validation
- Defined in:
- lib/kamal/configuration/role.rb
Defined Under Namespace
Classes: Healthcheck
Instance Attribute Summary collapse
Instance Method Summary
collapse
Methods included from Validation
#validate!, #validation_yml
Constructor Details
#initialize(name, config:) ⇒ Role
Returns a new instance of Role.
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
# File 'lib/kamal/configuration/role.rb', line 10
def initialize(name, config:)
@name, @config = name.inquiry, config
validate! \
role_config,
example: validation_yml["servers"]["workers"],
context: "servers/#{name}",
with: Kamal::Configuration::Validator::Role
@specialized_env = Kamal::Configuration::Env.new \
config: specializations.fetch("env", {}),
secrets: config.secrets,
context: "servers/#{name}/env"
@specialized_logging = Kamal::Configuration::Logging.new \
logging_config: specializations.fetch("logging", {}),
context: "servers/#{name}/logging"
if healthcheck_config = specializations["healthcheck"]
@healthcheck = Kamal::Configuration::Role::Healthcheck.new \
healthcheck_config: healthcheck_config,
context: "servers/#{name}/healthcheck"
end
initialize_specialized_proxy
end
|
Instance Attribute Details
#config ⇒ Object
Returns the value of attribute config.
6
7
8
|
# File 'lib/kamal/configuration/role.rb', line 6
def config
@config
end
|
#healthcheck ⇒ Object
Returns the value of attribute healthcheck.
6
7
8
|
# File 'lib/kamal/configuration/role.rb', line 6
def healthcheck
@healthcheck
end
|
#name ⇒ Object
Also known as:
to_s
Returns the value of attribute name.
6
7
8
|
# File 'lib/kamal/configuration/role.rb', line 6
def name
@name
end
|
#specialized_env ⇒ Object
Returns the value of attribute specialized_env.
6
7
8
|
# File 'lib/kamal/configuration/role.rb', line 6
def specialized_env
@specialized_env
end
|
#specialized_logging ⇒ Object
Returns the value of attribute specialized_logging.
6
7
8
|
# File 'lib/kamal/configuration/role.rb', line 6
def specialized_logging
@specialized_logging
end
|
#specialized_proxy ⇒ Object
Returns the value of attribute specialized_proxy.
6
7
8
|
# File 'lib/kamal/configuration/role.rb', line 6
def specialized_proxy
@specialized_proxy
end
|
Instance Method Details
247
248
249
|
# File 'lib/kamal/configuration/role.rb', line 247
def (version = config.version)
File.join config.assets_directory, "extracted", [ name, version ].join("-")
end
|
#asset_path ⇒ Object
228
229
230
|
# File 'lib/kamal/configuration/role.rb', line 228
def asset_path
asset_path_config&.dig(0)
end
|
#asset_path_options ⇒ Object
243
244
245
|
# File 'lib/kamal/configuration/role.rb', line 243
def asset_path_options
asset_path_config&.dig(1)
end
|
#asset_volume(version = config.version) ⇒ Object
236
237
238
239
240
241
|
# File 'lib/kamal/configuration/role.rb', line 236
def asset_volume(version = config.version)
if assets?
Kamal::Configuration::Volume.new \
host_path: asset_volume_directory(version), container_path: asset_path, options: asset_path_options
end
end
|
#asset_volume_args ⇒ Object
209
210
211
|
# File 'lib/kamal/configuration/role.rb', line 209
def asset_volume_args
asset_volume&.docker_args
end
|
#asset_volume_directory(version = config.version) ⇒ Object
251
252
253
|
# File 'lib/kamal/configuration/role.rb', line 251
def asset_volume_directory(version = config.version)
File.join config.assets_directory, "volumes", [ name, version ].join("-")
end
|
#assets? ⇒ Boolean
232
233
234
|
# File 'lib/kamal/configuration/role.rb', line 232
def assets?
asset_path.present? && running_proxy?
end
|
#boot ⇒ Object
nil unless the role paces its own hosts. Deliberately not falling back to the global
boot: that limit is already spent slicing the cross-role host list in
Cli::App#host_boot_groups, and handing it to the per-role runner as well would sleep
boot.wait a second time inside every group.
Built on first read rather than in the initializer — Servers.new constructs every Role
before Kamal::Configuration#initialize has finished assigning its own collaborators.
98
99
100
101
102
103
104
105
106
|
# File 'lib/kamal/configuration/role.rb', line 98
def boot
return @boot if defined?(@boot)
@boot =
if (boot_config = specializations["boot"])
Kamal::Configuration::Boot.new \
config: config, boot_config: boot_config, context: "servers/#{name}/boot"
end
end
|
#boot_runner_options(hosts) ⇒ Object
hosts is what on_roles is about to pace — role.hosts & the run's hosts, so
--roles/--hosts have already narrowed it. A percentage limit has to count that, not
the role's configured hosts.
111
112
113
|
# File 'lib/kamal/configuration/role.rb', line 111
def boot_runner_options(hosts)
boot&.runner_options_for(hosts) || {}
end
|
#cmd ⇒ Object
57
58
59
|
# File 'lib/kamal/configuration/role.rb', line 57
def cmd
specializations["cmd"]
end
|
#container_name(version = nil) ⇒ Object
219
220
221
|
# File 'lib/kamal/configuration/role.rb', line 219
def container_name(version = nil)
[ container_prefix, version || config.version ].compact.join("-")
end
|
#container_prefix ⇒ Object
223
224
225
|
# File 'lib/kamal/configuration/role.rb', line 223
def container_prefix
[ config.service, name, config.destination ].compact.join("-")
end
|
#ensure_one_host_for_ssl ⇒ Object
255
256
257
258
259
260
|
# File 'lib/kamal/configuration/role.rb', line 255
def ensure_one_host_for_ssl
if running_proxy? && proxy.ssl? && hosts.size > 1 && !proxy.loadbalancer.present? && !proxy.custom_ssl_certificate?
raise Kamal::ConfigurationError, "SSL is only supported on a single server unless you provide custom certificates or configure a loadbalancer, found #{hosts.size} servers for role #{name}"
end
end
|
#env(host) ⇒ Object
188
189
190
191
|
# File 'lib/kamal/configuration/role.rb', line 188
def env(host)
@envs ||= {}
@envs[host] ||= [ config.env, specialized_env, *env_tags(host).map(&:env) ].reduce(:merge)
end
|
#env_args(host) ⇒ Object
193
194
195
|
# File 'lib/kamal/configuration/role.rb', line 193
def env_args(host)
[ *env(host).clear_args, *argumentize("--env-file", secrets_path) ]
end
|
#env_directory ⇒ Object
197
198
199
|
# File 'lib/kamal/configuration/role.rb', line 197
def env_directory
File.join(config.env_directory, "roles")
end
|
45
46
47
|
# File 'lib/kamal/configuration/role.rb', line 45
def env_tags(host)
tagged_hosts.fetch(host).collect { |tag| config.env_tag(tag) }.compact
end
|
#healthcheck_args ⇒ Object
Kept out of option_args on purpose: Commands::App::Execution splats those into
one-shot kamal app exec containers, which must not inherit a service healthcheck.
83
84
85
|
# File 'lib/kamal/configuration/role.rb', line 83
def healthcheck_args
healthcheck&.args || []
end
|
#hosts ⇒ Object
41
42
43
|
# File 'lib/kamal/configuration/role.rb', line 41
def hosts
tagged_hosts.keys
end
|
#hosts_with_tag(tag) ⇒ Object
The role's own hosts carrying tag in deploy.yml. Accessory tag:/tags: resolution
comes through here rather than re-walking raw_config.servers, so it inherits
extract_hosts_from_config's handling of every legal role shape — bare list, hosts:
mapping, and the top-level servers: array.
53
54
55
|
# File 'lib/kamal/configuration/role.rb', line 53
def hosts_with_tag(tag)
tagged_hosts.select { |_host, tags| tags.include?(tag) }.keys
end
|
#label_args ⇒ Object
73
74
75
|
# File 'lib/kamal/configuration/role.rb', line 73
def label_args
argumentize "--label", labels
end
|
#labels ⇒ Object
69
70
71
|
# File 'lib/kamal/configuration/role.rb', line 69
def labels
default_labels.merge(custom_labels)
end
|
#logging ⇒ Object
87
88
89
|
# File 'lib/kamal/configuration/role.rb', line 87
def logging
@logging ||= config.logging.merge(specialized_logging)
end
|
#logging_args ⇒ Object
77
78
79
|
# File 'lib/kamal/configuration/role.rb', line 77
def logging_args
logging.args
end
|
#option_args ⇒ Object
61
62
63
|
# File 'lib/kamal/configuration/role.rb', line 61
def option_args
optionize docker_options.reject { |key, _| key.to_s == "restart" }
end
|
#primary? ⇒ Boolean
214
215
216
|
# File 'lib/kamal/configuration/role.rb', line 214
def primary?
name == @config.primary_role_name
end
|
#primary_host ⇒ Object
37
38
39
|
# File 'lib/kamal/configuration/role.rb', line 37
def primary_host
hosts.first
end
|
#proxy ⇒ Object
115
116
117
|
# File 'lib/kamal/configuration/role.rb', line 115
def proxy
@proxy ||= specialized_proxy.merge(config.proxy) if running_proxy?
end
|
#readiness_delay ⇒ Object
How long a role that has no healthcheck must merely keep running before the deploy
accepts it. Role-specialized so a role that legitimately opts out can be tuned
without slowing every other role down.
184
185
186
|
# File 'lib/kamal/configuration/role.rb', line 184
def readiness_delay
specializations["readiness_delay"] || config.readiness_delay
end
|
#readiness_description ⇒ Object
One-line rendering of readiness_source, shared by the deploy banner and kamal doctor
so both name the same gate the same way.
148
149
150
151
152
153
154
155
156
157
158
159
160
161
|
# File 'lib/kamal/configuration/role.rb', line 148
def readiness_description
case readiness_source
when :proxy
[ "kamal-proxy health check", proxy.healthcheck_path ].compact.join(" ")
when :healthcheck
healthcheck.port ? "healthcheck #{healthcheck.path}:#{healthcheck.port}" : "healthcheck (custom cmd)"
when :healthcheck_exec
"healthcheck exec probe (#{healthcheck.exec})"
when :docker_options
"docker healthcheck (options: health-cmd)"
else
"NONE (old container stops #{readiness_delay}s after boot)"
end
end
|
#readiness_gated? ⇒ Boolean
Whether the operator has made a readiness decision for this role at all — declared a
healthcheck, hand-rolled a health-cmd option, or accepted the gap with healthcheck: false.
Distinct from readiness_source, which reports what actually gates the deploy.
166
167
168
|
# File 'lib/kamal/configuration/role.rb', line 166
def readiness_gated?
healthcheck.present? || health_cmd_option? || healthcheck_disabled?
end
|
#readiness_source ⇒ Object
Where a deploy of this role actually waits for readiness before stopping the
old container. Without a proxy or a docker healthcheck, Healthcheck::Poller
only sees .State.Status, so staying running for the readiness delay is
the whole gate. :healthcheck_exec is the odd one out: the container declares no
docker healthcheck, the deploy host polls the probe itself.
132
133
134
135
136
137
138
139
140
141
142
143
144
|
# File 'lib/kamal/configuration/role.rb', line 132
def readiness_source
if running_proxy?
:proxy
elsif healthcheck&.exec?
:healthcheck_exec
elsif healthcheck
:healthcheck
elsif health_cmd_option?
:docker_options
else
:none
end
end
|
#restart_policy ⇒ Object
65
66
67
|
# File 'lib/kamal/configuration/role.rb', line 65
def restart_policy
restart_policy_option || "unless-stopped"
end
|
#running_proxy? ⇒ Boolean
119
120
121
|
# File 'lib/kamal/configuration/role.rb', line 119
def running_proxy?
@running_proxy
end
|
#secrets_io(host) ⇒ Object
201
202
203
|
# File 'lib/kamal/configuration/role.rb', line 201
def secrets_io(host)
env(host).secrets_io
end
|
#secrets_path ⇒ Object
205
206
207
|
# File 'lib/kamal/configuration/role.rb', line 205
def secrets_path
File.join(config.env_directory, "roles", "#{name}.env")
end
|
#ssl? ⇒ Boolean
123
124
125
|
# File 'lib/kamal/configuration/role.rb', line 123
def ssl?
running_proxy? && proxy.ssl?
end
|
#stop_args ⇒ Object
170
171
172
173
174
175
|
# File 'lib/kamal/configuration/role.rb', line 170
def stop_args
timeout = stop_timeout || (running_proxy? ? nil : config.drain_timeout)
[ *argumentize("-t", timeout) ]
end
|
#stop_timeout ⇒ Object
177
178
179
|
# File 'lib/kamal/configuration/role.rb', line 177
def stop_timeout
specializations["stop_timeout"] || config.stop_timeout
end
|