kamal 1.8.3 → 2.7.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 +92 -38
- data/lib/kamal/cli/alias/command.rb +10 -0
- data/lib/kamal/cli/app/{prepare_assets.rb → assets.rb} +1 -1
- data/lib/kamal/cli/app/boot.rb +23 -16
- data/lib/kamal/cli/app/error_pages.rb +33 -0
- data/lib/kamal/cli/app/ssl_certificates.rb +28 -0
- data/lib/kamal/cli/app.rb +132 -30
- data/lib/kamal/cli/base.rb +57 -53
- data/lib/kamal/cli/build.rb +81 -38
- data/lib/kamal/cli/healthcheck/barrier.rb +2 -0
- data/lib/kamal/cli/healthcheck/poller.rb +18 -39
- data/lib/kamal/cli/lock.rb +2 -3
- data/lib/kamal/cli/main.rb +60 -59
- data/lib/kamal/cli/proxy.rb +290 -0
- data/lib/kamal/cli/prune.rb +0 -1
- data/lib/kamal/cli/registry.rb +2 -0
- data/lib/kamal/cli/secrets.rb +49 -0
- data/lib/kamal/cli/server.rb +6 -5
- data/lib/kamal/cli/templates/deploy.yml +53 -53
- data/lib/kamal/cli/templates/sample_hooks/docker-setup.sample +2 -12
- data/lib/kamal/cli/templates/sample_hooks/post-app-boot.sample +3 -0
- data/lib/kamal/cli/templates/sample_hooks/post-deploy.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/post-proxy-reboot.sample +3 -0
- data/lib/kamal/cli/templates/sample_hooks/pre-app-boot.sample +3 -0
- data/lib/kamal/cli/templates/sample_hooks/pre-build.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/pre-connect.sample +1 -1
- data/lib/kamal/cli/templates/sample_hooks/pre-deploy.sample +19 -6
- data/lib/kamal/cli/templates/sample_hooks/pre-proxy-reboot.sample +3 -0
- data/lib/kamal/cli/templates/secrets +17 -0
- data/lib/kamal/cli.rb +2 -0
- data/lib/kamal/commander/specifics.rb +19 -6
- data/lib/kamal/commander.rb +39 -32
- data/lib/kamal/commands/accessory/proxy.rb +16 -0
- data/lib/kamal/commands/accessory.rb +19 -19
- data/lib/kamal/commands/app/assets.rb +10 -10
- data/lib/kamal/commands/app/containers.rb +2 -2
- data/lib/kamal/commands/app/error_pages.rb +9 -0
- data/lib/kamal/commands/app/execution.rb +7 -4
- data/lib/kamal/commands/app/images.rb +1 -1
- data/lib/kamal/commands/app/logging.rb +16 -6
- data/lib/kamal/commands/app/proxy.rb +32 -0
- data/lib/kamal/commands/app.rb +25 -24
- data/lib/kamal/commands/auditor.rb +12 -3
- data/lib/kamal/commands/base.rb +54 -8
- data/lib/kamal/commands/builder/base.rb +46 -16
- data/lib/kamal/commands/builder/clone.rb +16 -14
- data/lib/kamal/commands/builder/cloud.rb +22 -0
- data/lib/kamal/commands/builder/hybrid.rb +21 -0
- data/lib/kamal/commands/builder/local.rb +14 -0
- data/lib/kamal/commands/builder/pack.rb +46 -0
- data/lib/kamal/commands/builder/remote.rb +63 -0
- data/lib/kamal/commands/builder.rb +21 -45
- data/lib/kamal/commands/docker.rb +4 -0
- data/lib/kamal/commands/hook.rb +8 -2
- data/lib/kamal/commands/lock.rb +2 -6
- data/lib/kamal/commands/proxy.rb +127 -0
- data/lib/kamal/commands/prune.rb +1 -9
- data/lib/kamal/commands/registry.rb +9 -7
- data/lib/kamal/commands/server.rb +11 -1
- data/lib/kamal/configuration/accessory.rb +89 -12
- data/lib/kamal/configuration/alias.rb +15 -0
- data/lib/kamal/configuration/builder.rb +73 -15
- data/lib/kamal/configuration/docs/accessory.yml +53 -15
- data/lib/kamal/configuration/docs/alias.yml +26 -0
- data/lib/kamal/configuration/docs/boot.yml +3 -3
- data/lib/kamal/configuration/docs/builder.yml +63 -38
- data/lib/kamal/configuration/docs/configuration.yml +62 -46
- data/lib/kamal/configuration/docs/env.yml +61 -17
- data/lib/kamal/configuration/docs/logging.yml +3 -3
- data/lib/kamal/configuration/docs/proxy.yml +168 -0
- data/lib/kamal/configuration/docs/registry.yml +20 -13
- data/lib/kamal/configuration/docs/role.yml +14 -13
- data/lib/kamal/configuration/docs/servers.yml +2 -2
- data/lib/kamal/configuration/docs/ssh.yml +23 -19
- data/lib/kamal/configuration/docs/sshkit.yml +4 -4
- data/lib/kamal/configuration/env/tag.rb +4 -3
- data/lib/kamal/configuration/env.rb +19 -17
- data/lib/kamal/configuration/proxy/boot.rb +129 -0
- data/lib/kamal/configuration/proxy.rb +124 -0
- data/lib/kamal/configuration/registry.rb +7 -6
- data/lib/kamal/configuration/role.rb +69 -98
- data/lib/kamal/configuration/servers.rb +8 -1
- data/lib/kamal/configuration/validator/accessory.rb +6 -2
- data/lib/kamal/configuration/validator/alias.rb +15 -0
- data/lib/kamal/configuration/validator/builder.rb +6 -0
- data/lib/kamal/configuration/validator/proxy.rb +25 -0
- data/lib/kamal/configuration/validator/role.rb +3 -1
- data/lib/kamal/configuration/validator/servers.rb +1 -1
- data/lib/kamal/configuration/validator.rb +62 -24
- data/lib/kamal/configuration.rb +96 -50
- data/lib/kamal/docker.rb +30 -0
- data/lib/kamal/env_file.rb +7 -1
- data/lib/kamal/git.rb +10 -0
- data/lib/kamal/secrets/adapters/aws_secrets_manager.rb +51 -0
- data/lib/kamal/secrets/adapters/base.rb +33 -0
- data/lib/kamal/secrets/adapters/bitwarden.rb +81 -0
- data/lib/kamal/secrets/adapters/bitwarden_secrets_manager.rb +66 -0
- data/lib/kamal/secrets/adapters/doppler.rb +57 -0
- data/lib/kamal/secrets/adapters/enpass.rb +71 -0
- data/lib/kamal/secrets/adapters/gcp_secret_manager.rb +112 -0
- data/lib/kamal/secrets/adapters/last_pass.rb +40 -0
- data/lib/kamal/secrets/adapters/one_password.rb +104 -0
- data/lib/kamal/secrets/adapters/passbolt.rb +130 -0
- data/lib/kamal/secrets/adapters/test.rb +14 -0
- data/lib/kamal/secrets/adapters.rb +16 -0
- data/lib/kamal/secrets/dotenv/inline_command_substitution.rb +33 -0
- data/lib/kamal/secrets.rb +42 -0
- data/lib/kamal/sshkit_with_ext.rb +1 -0
- data/lib/kamal/utils.rb +30 -0
- data/lib/kamal/version.rb +1 -1
- data/lib/kamal.rb +3 -1
- metadata +63 -36
- data/lib/kamal/cli/env.rb +0 -54
- data/lib/kamal/cli/templates/sample_hooks/post-traefik-reboot.sample +0 -3
- data/lib/kamal/cli/templates/sample_hooks/pre-traefik-reboot.sample +0 -3
- data/lib/kamal/cli/templates/template.env +0 -2
- data/lib/kamal/cli/traefik.rb +0 -122
- data/lib/kamal/commands/app/cord.rb +0 -22
- data/lib/kamal/commands/builder/multiarch/remote.rb +0 -65
- data/lib/kamal/commands/builder/multiarch.rb +0 -41
- data/lib/kamal/commands/builder/native/cached.rb +0 -25
- data/lib/kamal/commands/builder/native/remote.rb +0 -67
- data/lib/kamal/commands/builder/native.rb +0 -20
- data/lib/kamal/commands/traefik.rb +0 -85
- data/lib/kamal/configuration/docs/healthcheck.yml +0 -59
- data/lib/kamal/configuration/docs/traefik.yml +0 -62
- data/lib/kamal/configuration/healthcheck.rb +0 -63
- data/lib/kamal/configuration/traefik.rb +0 -60
@@ -1,33 +1,30 @@
|
|
1
1
|
class Kamal::Configuration::Role
|
2
2
|
include Kamal::Configuration::Validation
|
3
3
|
|
4
|
-
CORD_FILE = "cord"
|
5
4
|
delegate :argumentize, :optionize, to: Kamal::Utils
|
6
5
|
|
7
|
-
attr_reader :name, :config, :specialized_env, :specialized_logging, :
|
6
|
+
attr_reader :name, :config, :specialized_env, :specialized_logging, :specialized_proxy
|
8
7
|
|
9
8
|
alias to_s name
|
10
9
|
|
11
10
|
def initialize(name, config:)
|
12
11
|
@name, @config = name.inquiry, config
|
13
12
|
validate! \
|
14
|
-
|
13
|
+
role_config,
|
15
14
|
example: validation_yml["servers"]["workers"],
|
16
15
|
context: "servers/#{name}",
|
17
16
|
with: Kamal::Configuration::Validator::Role
|
18
17
|
|
19
18
|
@specialized_env = Kamal::Configuration::Env.new \
|
20
19
|
config: specializations.fetch("env", {}),
|
21
|
-
|
20
|
+
secrets: config.secrets,
|
22
21
|
context: "servers/#{name}/env"
|
23
22
|
|
24
23
|
@specialized_logging = Kamal::Configuration::Logging.new \
|
25
24
|
logging_config: specializations.fetch("logging", {}),
|
26
25
|
context: "servers/#{name}/logging"
|
27
26
|
|
28
|
-
|
29
|
-
healthcheck_config: specializations.fetch("healthcheck", {}),
|
30
|
-
context: "servers/#{name}/healthcheck"
|
27
|
+
initialize_specialized_proxy
|
31
28
|
end
|
32
29
|
|
33
30
|
def primary_host
|
@@ -55,7 +52,7 @@ class Kamal::Configuration::Role
|
|
55
52
|
end
|
56
53
|
|
57
54
|
def labels
|
58
|
-
default_labels.merge(
|
55
|
+
default_labels.merge(custom_labels)
|
59
56
|
end
|
60
57
|
|
61
58
|
def label_args
|
@@ -70,87 +67,53 @@ class Kamal::Configuration::Role
|
|
70
67
|
@logging ||= config.logging.merge(specialized_logging)
|
71
68
|
end
|
72
69
|
|
73
|
-
|
74
|
-
|
75
|
-
@envs ||= {}
|
76
|
-
@envs[host] ||= [ config.env, specialized_env, *env_tags(host).map(&:env) ].reduce(:merge)
|
70
|
+
def proxy
|
71
|
+
@proxy ||= specialized_proxy.merge(config.proxy) if running_proxy?
|
77
72
|
end
|
78
73
|
|
79
|
-
def
|
80
|
-
|
74
|
+
def running_proxy?
|
75
|
+
@running_proxy
|
81
76
|
end
|
82
77
|
|
83
|
-
def
|
84
|
-
|
78
|
+
def ssl?
|
79
|
+
running_proxy? && proxy.ssl?
|
85
80
|
end
|
86
81
|
|
82
|
+
def stop_args
|
83
|
+
# When deploying with the proxy, kamal-proxy will drain request before returning so we don't need to wait.
|
84
|
+
timeout = running_proxy? ? nil : config.drain_timeout
|
87
85
|
|
88
|
-
|
89
|
-
if running_traefik? || healthcheck.set_port_or_path?
|
90
|
-
if cord && uses_cord?
|
91
|
-
optionize({ "health-cmd" => health_check_cmd_with_cord, "health-interval" => healthcheck.interval })
|
92
|
-
.concat(cord_volume.docker_args)
|
93
|
-
else
|
94
|
-
optionize({ "health-cmd" => healthcheck.cmd, "health-interval" => healthcheck.interval })
|
95
|
-
end
|
96
|
-
else
|
97
|
-
[]
|
98
|
-
end
|
86
|
+
[ *argumentize("-t", timeout) ]
|
99
87
|
end
|
100
88
|
|
101
|
-
def
|
102
|
-
@
|
103
|
-
|
104
|
-
config.healthcheck.merge(specialized_healthcheck)
|
105
|
-
else
|
106
|
-
specialized_healthcheck
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
def health_check_cmd_with_cord
|
111
|
-
"(#{healthcheck.cmd}) && (stat #{cord_container_file} > /dev/null || exit 1)"
|
112
|
-
end
|
113
|
-
|
114
|
-
|
115
|
-
def running_traefik?
|
116
|
-
if specializations["traefik"].nil?
|
117
|
-
primary?
|
118
|
-
else
|
119
|
-
specializations["traefik"]
|
120
|
-
end
|
89
|
+
def env(host)
|
90
|
+
@envs ||= {}
|
91
|
+
@envs[host] ||= [ config.env, specialized_env, *env_tags(host).map(&:env) ].reduce(:merge)
|
121
92
|
end
|
122
93
|
|
123
|
-
def
|
124
|
-
|
94
|
+
def env_args(host)
|
95
|
+
[ *env(host).clear_args, *argumentize("--env-file", secrets_path) ]
|
125
96
|
end
|
126
97
|
|
127
|
-
|
128
|
-
|
129
|
-
running_traefik? && cord_volume && healthcheck.cmd.present?
|
98
|
+
def env_directory
|
99
|
+
File.join(config.env_directory, "roles")
|
130
100
|
end
|
131
101
|
|
132
|
-
def
|
133
|
-
|
102
|
+
def secrets_io(host)
|
103
|
+
env(host).secrets_io
|
134
104
|
end
|
135
105
|
|
136
|
-
def
|
137
|
-
|
138
|
-
@cord_volume ||= Kamal::Configuration::Volume.new \
|
139
|
-
host_path: File.join(config.run_directory, "cords", [ container_prefix, config.run_id ].join("-")),
|
140
|
-
container_path: cord
|
141
|
-
end
|
106
|
+
def secrets_path
|
107
|
+
File.join(config.env_directory, "roles", "#{name}.env")
|
142
108
|
end
|
143
109
|
|
144
|
-
def
|
145
|
-
|
110
|
+
def asset_volume_args
|
111
|
+
asset_volume&.docker_args
|
146
112
|
end
|
147
113
|
|
148
|
-
def cord_container_directory
|
149
|
-
health_check_options.fetch("cord", nil)
|
150
|
-
end
|
151
114
|
|
152
|
-
def
|
153
|
-
|
115
|
+
def primary?
|
116
|
+
name == @config.primary_role_name
|
154
117
|
end
|
155
118
|
|
156
119
|
|
@@ -168,25 +131,54 @@ class Kamal::Configuration::Role
|
|
168
131
|
end
|
169
132
|
|
170
133
|
def assets?
|
171
|
-
asset_path.present? &&
|
134
|
+
asset_path.present? && running_proxy?
|
172
135
|
end
|
173
136
|
|
174
|
-
def asset_volume(version =
|
137
|
+
def asset_volume(version = config.version)
|
175
138
|
if assets?
|
176
139
|
Kamal::Configuration::Volume.new \
|
177
|
-
host_path:
|
140
|
+
host_path: asset_volume_directory(version), container_path: asset_path
|
178
141
|
end
|
179
142
|
end
|
180
143
|
|
181
|
-
def
|
182
|
-
File.join config.
|
144
|
+
def asset_extracted_directory(version = config.version)
|
145
|
+
File.join config.assets_directory, "extracted", [ name, version ].join("-")
|
146
|
+
end
|
147
|
+
|
148
|
+
def asset_volume_directory(version = config.version)
|
149
|
+
File.join config.assets_directory, "volumes", [ name, version ].join("-")
|
183
150
|
end
|
184
151
|
|
185
|
-
def
|
186
|
-
|
152
|
+
def ensure_one_host_for_ssl
|
153
|
+
if running_proxy? && proxy.ssl? && hosts.size > 1 && !proxy.custom_ssl_certificate?
|
154
|
+
raise Kamal::ConfigurationError, "SSL is only supported on a single server unless you provide custom certificates, found #{hosts.size} servers for role #{name}"
|
155
|
+
end
|
187
156
|
end
|
188
157
|
|
189
158
|
private
|
159
|
+
def initialize_specialized_proxy
|
160
|
+
proxy_specializations = specializations["proxy"]
|
161
|
+
|
162
|
+
if primary?
|
163
|
+
# only false means no proxy for non-primary roles
|
164
|
+
@running_proxy = proxy_specializations != false
|
165
|
+
else
|
166
|
+
# false and nil both mean no proxy for non-primary roles
|
167
|
+
@running_proxy = !!proxy_specializations
|
168
|
+
end
|
169
|
+
|
170
|
+
if running_proxy?
|
171
|
+
proxy_config = proxy_specializations == true || proxy_specializations.nil? ? {} : proxy_specializations
|
172
|
+
|
173
|
+
@specialized_proxy = Kamal::Configuration::Proxy.new \
|
174
|
+
config: config,
|
175
|
+
proxy_config: proxy_config,
|
176
|
+
secrets: config.secrets,
|
177
|
+
role_name: name,
|
178
|
+
context: "servers/#{name}/proxy"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
190
182
|
def tagged_hosts
|
191
183
|
{}.tap do |tagged_hosts|
|
192
184
|
extract_hosts_from_config.map do |host_config|
|
@@ -214,32 +206,11 @@ class Kamal::Configuration::Role
|
|
214
206
|
end
|
215
207
|
|
216
208
|
def specializations
|
217
|
-
|
218
|
-
{}
|
219
|
-
else
|
220
|
-
config.raw_config.servers[name]
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
def traefik_labels
|
225
|
-
if running_traefik?
|
226
|
-
{
|
227
|
-
# Setting a service property ensures that the generated service name will be consistent between versions
|
228
|
-
"traefik.http.services.#{traefik_service}.loadbalancer.server.scheme" => "http",
|
229
|
-
|
230
|
-
"traefik.http.routers.#{traefik_service}.rule" => "PathPrefix(`/`)",
|
231
|
-
"traefik.http.routers.#{traefik_service}.priority" => "2",
|
232
|
-
"traefik.http.middlewares.#{traefik_service}-retry.retry.attempts" => "5",
|
233
|
-
"traefik.http.middlewares.#{traefik_service}-retry.retry.initialinterval" => "500ms",
|
234
|
-
"traefik.http.routers.#{traefik_service}.middlewares" => "#{traefik_service}-retry@docker"
|
235
|
-
}
|
236
|
-
else
|
237
|
-
{}
|
238
|
-
end
|
209
|
+
@specializations ||= role_config.is_a?(Array) ? {} : role_config
|
239
210
|
end
|
240
211
|
|
241
|
-
def
|
242
|
-
|
212
|
+
def role_config
|
213
|
+
@role_config ||= config.raw_config.servers.is_a?(Array) ? {} : config.raw_config.servers[name]
|
243
214
|
end
|
244
215
|
|
245
216
|
def custom_labels
|
@@ -13,6 +13,13 @@ class Kamal::Configuration::Servers
|
|
13
13
|
|
14
14
|
private
|
15
15
|
def role_names
|
16
|
-
|
16
|
+
case servers_config
|
17
|
+
when Array
|
18
|
+
[ "web" ]
|
19
|
+
when NilClass
|
20
|
+
[]
|
21
|
+
else
|
22
|
+
servers_config.keys.sort
|
23
|
+
end
|
17
24
|
end
|
18
25
|
end
|
@@ -2,8 +2,12 @@ class Kamal::Configuration::Validator::Accessory < Kamal::Configuration::Validat
|
|
2
2
|
def validate!
|
3
3
|
super
|
4
4
|
|
5
|
-
if (config.keys & [ "host", "hosts", "roles" ]).size != 1
|
6
|
-
error "specify one of `host`, `hosts` or `
|
5
|
+
if (config.keys & [ "host", "hosts", "role", "roles", "tag", "tags" ]).size != 1
|
6
|
+
error "specify one of `host`, `hosts`, `role`, `roles`, `tag` or `tags`"
|
7
7
|
end
|
8
|
+
|
9
|
+
validate_labels!(config["labels"])
|
10
|
+
|
11
|
+
validate_docker_options!(config["options"])
|
8
12
|
end
|
9
13
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Kamal::Configuration::Validator::Alias < Kamal::Configuration::Validator
|
2
|
+
def validate!
|
3
|
+
super
|
4
|
+
|
5
|
+
name = context.delete_prefix("aliases/")
|
6
|
+
|
7
|
+
if name !~ /\A[a-z0-9_-]+\z/
|
8
|
+
error "Invalid alias name: '#{name}'. Must only contain lowercase letters, alphanumeric, hyphens and underscores."
|
9
|
+
end
|
10
|
+
|
11
|
+
if Kamal::Cli::Main.commands.include?(name)
|
12
|
+
error "Alias '#{name}' conflicts with a built-in command."
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -5,5 +5,11 @@ class Kamal::Configuration::Validator::Builder < Kamal::Configuration::Validator
|
|
5
5
|
if config["cache"] && config["cache"]["type"]
|
6
6
|
error "Invalid cache type: #{config["cache"]["type"]}" unless [ "gha", "registry" ].include?(config["cache"]["type"])
|
7
7
|
end
|
8
|
+
|
9
|
+
error "Builder arch not set" unless config["arch"].present?
|
10
|
+
|
11
|
+
error "buildpacks only support building for one arch" if config["pack"] && config["arch"].is_a?(Array) && config["arch"].size > 1
|
12
|
+
|
13
|
+
error "Cannot disable local builds, no remote is set" if config["local"] == false && config["remote"].blank?
|
8
14
|
end
|
9
15
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class Kamal::Configuration::Validator::Proxy < Kamal::Configuration::Validator
|
2
|
+
def validate!
|
3
|
+
unless config.nil?
|
4
|
+
super
|
5
|
+
|
6
|
+
if config["host"].blank? && config["hosts"].blank? && config["ssl"]
|
7
|
+
error "Must set a host to enable automatic SSL"
|
8
|
+
end
|
9
|
+
|
10
|
+
if (config.keys & [ "host", "hosts" ]).size > 1
|
11
|
+
error "Specify one of 'host' or 'hosts', not both"
|
12
|
+
end
|
13
|
+
|
14
|
+
if config["ssl"].is_a?(Hash)
|
15
|
+
if config["ssl"]["certificate_pem"].present? && config["ssl"]["private_key_pem"].blank?
|
16
|
+
error "Missing private_key_pem setting (required when certificate_pem is present)"
|
17
|
+
end
|
18
|
+
|
19
|
+
if config["ssl"]["private_key_pem"].present? && config["ssl"]["certificate_pem"].blank?
|
20
|
+
error "Missing certificate_pem setting (required when private_key_pem is present)"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -3,9 +3,11 @@ class Kamal::Configuration::Validator::Role < Kamal::Configuration::Validator
|
|
3
3
|
validate_type! config, Array, Hash
|
4
4
|
|
5
5
|
if config.is_a?(Array)
|
6
|
-
validate_servers!
|
6
|
+
validate_servers!(config)
|
7
7
|
else
|
8
8
|
super
|
9
|
+
validate_labels!(config["labels"])
|
10
|
+
validate_docker_options!(config["options"])
|
9
11
|
end
|
10
12
|
end
|
11
13
|
end
|
@@ -13,32 +13,42 @@ class Kamal::Configuration::Validator
|
|
13
13
|
|
14
14
|
private
|
15
15
|
def validate_against_example!(validation_config, example)
|
16
|
-
validate_type! validation_config,
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
16
|
+
validate_type! validation_config, example.class
|
17
|
+
|
18
|
+
if example.class == Hash
|
19
|
+
check_unknown_keys! validation_config, example
|
20
|
+
|
21
|
+
validation_config.each do |key, value|
|
22
|
+
next if extension?(key)
|
23
|
+
with_context(key) do
|
24
|
+
example_value = example[key]
|
25
|
+
|
26
|
+
if example_value == "..."
|
27
|
+
if key.to_s == "ssl"
|
28
|
+
validate_type! value, TrueClass, FalseClass, Hash
|
29
|
+
elsif key.to_s != "proxy" || !boolean?(value.class)
|
30
|
+
validate_type! value, *(Array if key == :servers), Hash
|
31
|
+
end
|
32
|
+
elsif key == "hosts"
|
33
|
+
validate_servers! value
|
34
|
+
elsif example_value.is_a?(Array)
|
35
|
+
if key == "arch"
|
36
|
+
validate_array_of_or_type! value, example_value.first.class
|
37
|
+
else
|
38
|
+
validate_array_of! value, example_value.first.class
|
39
|
+
end
|
40
|
+
elsif example_value.is_a?(Hash)
|
41
|
+
case key.to_s
|
42
|
+
when "options", "args"
|
43
|
+
validate_type! value, Hash
|
44
|
+
when "labels"
|
45
|
+
validate_hash_of! value, example_value.first[1].class
|
46
|
+
else
|
47
|
+
validate_against_example! value, example_value
|
48
|
+
end
|
37
49
|
else
|
38
|
-
|
50
|
+
validate_type! value, example_value.class
|
39
51
|
end
|
40
|
-
else
|
41
|
-
validate_type! value, example_value.class
|
42
52
|
end
|
43
53
|
end
|
44
54
|
end
|
@@ -69,6 +79,16 @@ class Kamal::Configuration::Validator
|
|
69
79
|
value.is_a?(String) || value.is_a?(Symbol) || value.is_a?(Numeric) || value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
70
80
|
end
|
71
81
|
|
82
|
+
def validate_array_of_or_type!(value, type)
|
83
|
+
if value.is_a?(Array)
|
84
|
+
validate_array_of! value, type
|
85
|
+
else
|
86
|
+
validate_type! value, type
|
87
|
+
end
|
88
|
+
rescue Kamal::ConfigurationError
|
89
|
+
type_error(Array, type)
|
90
|
+
end
|
91
|
+
|
72
92
|
def validate_array_of!(array, type)
|
73
93
|
validate_type! array, Array
|
74
94
|
|
@@ -150,4 +170,22 @@ class Kamal::Configuration::Validator
|
|
150
170
|
unknown_keys.reject! { |key| extension?(key) } if allow_extensions?
|
151
171
|
unknown_keys_error unknown_keys if unknown_keys.present?
|
152
172
|
end
|
173
|
+
|
174
|
+
def validate_labels!(labels)
|
175
|
+
return true if labels.blank?
|
176
|
+
|
177
|
+
with_context("labels") do
|
178
|
+
labels.each do |key, _|
|
179
|
+
with_context(key) do
|
180
|
+
error "invalid label. destination, role, and service are reserved labels" if %w[destination role service].include?(key)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def validate_docker_options!(options)
|
187
|
+
if options
|
188
|
+
error "Cannot set restart policy in docker options, unless-stopped is required" if options["restart"]
|
189
|
+
end
|
190
|
+
end
|
153
191
|
end
|