kamal 2.5.2 → 2.6.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 +16 -5
- data/lib/kamal/cli/app/{prepare_assets.rb → assets.rb} +1 -1
- data/lib/kamal/cli/app/boot.rb +1 -0
- data/lib/kamal/cli/app/error_pages.rb +33 -0
- data/lib/kamal/cli/app.rb +66 -22
- data/lib/kamal/cli/base.rb +13 -3
- data/lib/kamal/cli/build.rb +20 -4
- data/lib/kamal/cli/main.rb +4 -7
- data/lib/kamal/cli/proxy.rb +57 -10
- data/lib/kamal/cli/server.rb +4 -2
- data/lib/kamal/cli/templates/sample_hooks/post-deploy.sample +1 -1
- 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 +6 -5
- data/lib/kamal/commander/specifics.rb +4 -0
- data/lib/kamal/commander.rb +2 -2
- data/lib/kamal/commands/accessory/proxy.rb +1 -1
- data/lib/kamal/commands/accessory.rb +2 -3
- data/lib/kamal/commands/app/error_pages.rb +9 -0
- data/lib/kamal/commands/app/proxy.rb +13 -1
- data/lib/kamal/commands/app.rb +1 -1
- data/lib/kamal/commands/auditor.rb +11 -5
- data/lib/kamal/commands/base.rb +4 -0
- data/lib/kamal/commands/builder/base.rb +2 -1
- data/lib/kamal/commands/proxy.rb +55 -15
- data/lib/kamal/configuration/accessory.rb +24 -2
- data/lib/kamal/configuration/docs/accessory.yml +6 -1
- data/lib/kamal/configuration/docs/configuration.yml +6 -0
- data/lib/kamal/configuration/docs/env.yml +31 -0
- data/lib/kamal/configuration/docs/proxy.yml +7 -0
- data/lib/kamal/configuration/env.rb +13 -4
- data/lib/kamal/configuration/proxy/boot.rb +121 -0
- data/lib/kamal/configuration/proxy.rb +18 -1
- data/lib/kamal/configuration/servers.rb +8 -1
- data/lib/kamal/configuration/validator/accessory.rb +4 -2
- data/lib/kamal/configuration/validator/role.rb +1 -0
- data/lib/kamal/configuration/validator/servers.rb +1 -1
- data/lib/kamal/configuration/validator.rb +6 -0
- data/lib/kamal/configuration.rb +36 -74
- data/lib/kamal/secrets/adapters/aws_secrets_manager.rb +1 -0
- data/lib/kamal/secrets/dotenv/inline_command_substitution.rb +2 -1
- data/lib/kamal/version.rb +1 -1
- metadata +9 -10
data/lib/kamal/commander.rb
CHANGED
@@ -5,7 +5,7 @@ require "active_support/core_ext/object/blank"
|
|
5
5
|
class Kamal::Commander
|
6
6
|
attr_accessor :verbosity, :holding_lock, :connected
|
7
7
|
attr_reader :specific_roles, :specific_hosts
|
8
|
-
delegate :hosts, :roles, :primary_host, :primary_role, :roles_on, :proxy_hosts, :accessory_hosts, to: :specifics
|
8
|
+
delegate :hosts, :roles, :primary_host, :primary_role, :roles_on, :app_hosts, :proxy_hosts, :accessory_hosts, to: :specifics
|
9
9
|
|
10
10
|
def initialize
|
11
11
|
reset
|
@@ -13,7 +13,7 @@ class Kamal::Commander
|
|
13
13
|
|
14
14
|
def reset
|
15
15
|
self.verbosity = :info
|
16
|
-
self.holding_lock =
|
16
|
+
self.holding_lock = ENV["KAMAL_LOCK"] == "true"
|
17
17
|
self.connected = false
|
18
18
|
@specifics = @specific_roles = @specific_hosts = nil
|
19
19
|
@config = @config_kwargs = nil
|
@@ -6,7 +6,6 @@ class Kamal::Commands::Accessory < Kamal::Commands::Base
|
|
6
6
|
:network_args, :publish_args, :env_args, :volume_args, :label_args, :option_args,
|
7
7
|
:secrets_io, :secrets_path, :env_directory, :proxy, :running_proxy?, :registry,
|
8
8
|
to: :accessory_config
|
9
|
-
delegate :proxy_container_name, to: :config
|
10
9
|
|
11
10
|
def initialize(config, name:)
|
12
11
|
super(config)
|
@@ -37,8 +36,8 @@ class Kamal::Commands::Accessory < Kamal::Commands::Base
|
|
37
36
|
docker :container, :stop, service_name
|
38
37
|
end
|
39
38
|
|
40
|
-
def info
|
41
|
-
docker :ps, *service_filter
|
39
|
+
def info(all: false, quiet: false)
|
40
|
+
docker :ps, *("-a" if all), *("-q" if quiet), *service_filter
|
42
41
|
end
|
43
42
|
|
44
43
|
def logs(timestamps: true, since: nil, lines: nil, grep: nil, grep_options: nil)
|
@@ -0,0 +1,9 @@
|
|
1
|
+
module Kamal::Commands::App::ErrorPages
|
2
|
+
def create_error_pages_directory
|
3
|
+
make_directory(config.proxy_boot.error_pages_directory)
|
4
|
+
end
|
5
|
+
|
6
|
+
def clean_up_error_pages
|
7
|
+
[ :find, config.proxy_boot.error_pages_directory, "-mindepth", "1", "-maxdepth", "1", "!", "-name", KAMAL.config.version, "-exec", "rm", "-rf", "{} +" ]
|
8
|
+
end
|
9
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Kamal::Commands::App::Proxy
|
2
|
-
delegate :
|
2
|
+
delegate :container_name, to: :"config.proxy_boot", prefix: :proxy
|
3
3
|
|
4
4
|
def deploy(target:)
|
5
5
|
proxy_exec :deploy, role.container_prefix, *role.proxy.deploy_command_args(target: target)
|
@@ -9,6 +9,18 @@ module Kamal::Commands::App::Proxy
|
|
9
9
|
proxy_exec :remove, role.container_prefix
|
10
10
|
end
|
11
11
|
|
12
|
+
def live
|
13
|
+
proxy_exec :resume, role.container_prefix
|
14
|
+
end
|
15
|
+
|
16
|
+
def maintenance(**options)
|
17
|
+
proxy_exec :stop, role.container_prefix, *role.proxy.stop_command_args(**options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def remove_proxy_app_directory
|
21
|
+
remove_directory config.proxy_boot.app_directory
|
22
|
+
end
|
23
|
+
|
12
24
|
private
|
13
25
|
def proxy_exec(*command)
|
14
26
|
docker :exec, proxy_container_name, "kamal-proxy", *command
|
data/lib/kamal/commands/app.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
class Kamal::Commands::Auditor < Kamal::Commands::Base
|
2
2
|
attr_reader :details
|
3
|
+
delegate :escape_shell_value, to: Kamal::Utils
|
3
4
|
|
4
5
|
def initialize(config, **details)
|
5
6
|
super(config)
|
@@ -9,11 +10,8 @@ class Kamal::Commands::Auditor < Kamal::Commands::Base
|
|
9
10
|
# Runs remotely
|
10
11
|
def record(line, **details)
|
11
12
|
combine \
|
12
|
-
|
13
|
-
append(
|
14
|
-
[ :echo, audit_tags(**details).except(:version, :service_version, :service).to_s, line ],
|
15
|
-
audit_log_file
|
16
|
-
)
|
13
|
+
make_run_directory,
|
14
|
+
append([ :echo, escape_shell_value(audit_line(line, **details)) ], audit_log_file)
|
17
15
|
end
|
18
16
|
|
19
17
|
def reveal
|
@@ -30,4 +28,12 @@ class Kamal::Commands::Auditor < Kamal::Commands::Base
|
|
30
28
|
def audit_tags(**details)
|
31
29
|
tags(**self.details, **details)
|
32
30
|
end
|
31
|
+
|
32
|
+
def make_run_directory
|
33
|
+
[ :mkdir, "-p", config.run_directory ]
|
34
|
+
end
|
35
|
+
|
36
|
+
def audit_line(line, **details)
|
37
|
+
"#{audit_tags(**details).except(:version, :service_version, :service)} #{line}"
|
38
|
+
end
|
33
39
|
end
|
data/lib/kamal/commands/base.rb
CHANGED
data/lib/kamal/commands/proxy.rb
CHANGED
@@ -2,14 +2,7 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base
|
|
2
2
|
delegate :argumentize, :optionize, to: Kamal::Utils
|
3
3
|
|
4
4
|
def run
|
5
|
-
|
6
|
-
"--name", container_name,
|
7
|
-
"--network", "kamal",
|
8
|
-
"--detach",
|
9
|
-
"--restart", "unless-stopped",
|
10
|
-
"--volume", "kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy",
|
11
|
-
"\$\(#{get_boot_options.join(" ")}\)",
|
12
|
-
config.proxy_image
|
5
|
+
pipe boot_config, xargs(docker_run)
|
13
6
|
end
|
14
7
|
|
15
8
|
def start
|
@@ -31,7 +24,7 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base
|
|
31
24
|
def version
|
32
25
|
pipe \
|
33
26
|
docker(:inspect, container_name, "--format '{{.Config.Image}}'"),
|
34
|
-
[ :
|
27
|
+
[ :awk, "-F:", "'{print \$NF}'" ]
|
35
28
|
end
|
36
29
|
|
37
30
|
def logs(timestamps: true, since: nil, lines: nil, grep: nil, grep_options: nil)
|
@@ -65,23 +58,70 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base
|
|
65
58
|
end
|
66
59
|
|
67
60
|
def ensure_proxy_directory
|
68
|
-
make_directory config.
|
61
|
+
make_directory config.proxy_boot.host_directory
|
69
62
|
end
|
70
63
|
|
71
64
|
def remove_proxy_directory
|
72
|
-
remove_directory config.
|
65
|
+
remove_directory config.proxy_boot.host_directory
|
73
66
|
end
|
74
67
|
|
75
|
-
def
|
76
|
-
|
68
|
+
def ensure_apps_config_directory
|
69
|
+
make_directory config.proxy_boot.apps_directory
|
70
|
+
end
|
71
|
+
|
72
|
+
def boot_config
|
73
|
+
[ :echo, "#{substitute(read_boot_options)} #{substitute(read_image)}:#{substitute(read_image_version)} #{substitute(read_run_command)}" ]
|
74
|
+
end
|
75
|
+
|
76
|
+
def read_boot_options
|
77
|
+
read_file(config.proxy_boot.options_file, default: config.proxy_boot.default_boot_options.join(" "))
|
78
|
+
end
|
79
|
+
|
80
|
+
def read_image
|
81
|
+
read_file(config.proxy_boot.image_file, default: config.proxy_boot.image_default)
|
82
|
+
end
|
83
|
+
|
84
|
+
def read_image_version
|
85
|
+
read_file(config.proxy_boot.image_version_file, default: Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION)
|
86
|
+
end
|
87
|
+
|
88
|
+
def read_run_command
|
89
|
+
read_file(config.proxy_boot.run_command_file)
|
77
90
|
end
|
78
91
|
|
79
92
|
def reset_boot_options
|
80
|
-
remove_file config.
|
93
|
+
remove_file config.proxy_boot.options_file
|
94
|
+
end
|
95
|
+
|
96
|
+
def reset_image
|
97
|
+
remove_file config.proxy_boot.image_file
|
98
|
+
end
|
99
|
+
|
100
|
+
def reset_image_version
|
101
|
+
remove_file config.proxy_boot.image_version_file
|
102
|
+
end
|
103
|
+
|
104
|
+
def reset_run_command
|
105
|
+
remove_file config.proxy_boot.run_command_file
|
81
106
|
end
|
82
107
|
|
83
108
|
private
|
84
109
|
def container_name
|
85
|
-
config.
|
110
|
+
config.proxy_boot.container_name
|
111
|
+
end
|
112
|
+
|
113
|
+
def read_file(file, default: nil)
|
114
|
+
combine [ :cat, file, "2>", "/dev/null" ], [ :echo, "\"#{default}\"" ], by: "||"
|
115
|
+
end
|
116
|
+
|
117
|
+
def docker_run
|
118
|
+
docker \
|
119
|
+
:run,
|
120
|
+
"--name", container_name,
|
121
|
+
"--network", "kamal",
|
122
|
+
"--detach",
|
123
|
+
"--restart", "unless-stopped",
|
124
|
+
"--volume", "kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy",
|
125
|
+
*config.proxy_boot.apps_volume.docker_args
|
86
126
|
end
|
87
127
|
end
|
@@ -32,7 +32,7 @@ class Kamal::Configuration::Accessory
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def hosts
|
35
|
-
hosts_from_host || hosts_from_hosts || hosts_from_roles
|
35
|
+
hosts_from_host || hosts_from_hosts || hosts_from_roles || hosts_from_tags
|
36
36
|
end
|
37
37
|
|
38
38
|
def port
|
@@ -201,11 +201,31 @@ class Kamal::Configuration::Accessory
|
|
201
201
|
end
|
202
202
|
|
203
203
|
def hosts_from_roles
|
204
|
-
if accessory_config.key?("
|
204
|
+
if accessory_config.key?("role")
|
205
|
+
config.role(accessory_config["role"])&.hosts
|
206
|
+
elsif accessory_config.key?("roles")
|
205
207
|
accessory_config["roles"].flat_map { |role| config.role(role)&.hosts }
|
206
208
|
end
|
207
209
|
end
|
208
210
|
|
211
|
+
def hosts_from_tags
|
212
|
+
if accessory_config.key?("tag")
|
213
|
+
extract_hosts_from_config_with_tag(accessory_config["tag"])
|
214
|
+
elsif accessory_config.key?("tags")
|
215
|
+
accessory_config["tags"].flat_map { |tag| extract_hosts_from_config_with_tag(tag) }
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
def extract_hosts_from_config_with_tag(tag)
|
220
|
+
if (servers_with_roles = config.raw_config.servers).is_a?(Hash)
|
221
|
+
servers_with_roles.flat_map do |role, servers_in_role|
|
222
|
+
servers_in_role.filter_map do |host|
|
223
|
+
host.keys.first if host.is_a?(Hash) && host.values.first.include?(tag)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
209
229
|
def network
|
210
230
|
accessory_config["network"] || DEFAULT_NETWORK
|
211
231
|
end
|
@@ -213,6 +233,8 @@ class Kamal::Configuration::Accessory
|
|
213
233
|
def ensure_valid_roles
|
214
234
|
if accessory_config["roles"] && (missing_roles = accessory_config["roles"] - config.roles.map(&:name)).any?
|
215
235
|
raise Kamal::ConfigurationError, "accessories/#{name}: unknown roles #{missing_roles.join(", ")}"
|
236
|
+
elsif accessory_config["role"] && !config.role(accessory_config["role"])
|
237
|
+
raise Kamal::ConfigurationError, "accessories/#{name}: unknown role #{accessory_config["role"]}"
|
216
238
|
end
|
217
239
|
end
|
218
240
|
end
|
@@ -46,13 +46,18 @@ accessories:
|
|
46
46
|
|
47
47
|
# Accessory hosts
|
48
48
|
#
|
49
|
-
# Specify one of `host`, `hosts`, or `
|
49
|
+
# Specify one of `host`, `hosts`, `role`, `roles`, `tag` or `tags`:
|
50
50
|
host: mysql-db1
|
51
51
|
hosts:
|
52
52
|
- mysql-db1
|
53
53
|
- mysql-db2
|
54
|
+
role: mysql
|
54
55
|
roles:
|
55
56
|
- mysql
|
57
|
+
tag: writer
|
58
|
+
tags:
|
59
|
+
- writer
|
60
|
+
- reader
|
56
61
|
|
57
62
|
# Custom command
|
58
63
|
#
|
@@ -82,6 +82,12 @@ asset_path: /path/to/assets
|
|
82
82
|
# See https://kamal-deploy.org/docs/hooks for more information:
|
83
83
|
hooks_path: /user_home/kamal/hooks
|
84
84
|
|
85
|
+
# Error pages
|
86
|
+
#
|
87
|
+
# A directory relative to the app root to find error pages for the proxy to serve.
|
88
|
+
# Any files in the format 4xx.html or 5xx.html will be copied to the hosts.
|
89
|
+
error_pages_path: public
|
90
|
+
|
85
91
|
# Require destinations
|
86
92
|
#
|
87
93
|
# Whether deployments require a destination to be specified, defaults to `false`:
|
@@ -51,6 +51,37 @@ env:
|
|
51
51
|
secret:
|
52
52
|
- DB_PASSWORD
|
53
53
|
|
54
|
+
# Aliased secrets
|
55
|
+
#
|
56
|
+
# You can also alias secrets to other secrets using a `:` separator.
|
57
|
+
#
|
58
|
+
# This is useful when the ENV name is different from the secret name. For example, if you have two
|
59
|
+
# places where you need to define the ENV variable `DB_PASSWORD`, but the value is different depending
|
60
|
+
# on the context.
|
61
|
+
#
|
62
|
+
# ```shell
|
63
|
+
# SECRETS=$(kamal secrets fetch ...)
|
64
|
+
#
|
65
|
+
# MAIN_DB_PASSWORD=$(kamal secrets extract MAIN_DB_PASSWORD $SECRETS)
|
66
|
+
# SECONDARY_DB_PASSWORD=$(kamal secrets extract SECONDARY_DB_PASSWORD $SECRETS)
|
67
|
+
# ```
|
68
|
+
env:
|
69
|
+
secret:
|
70
|
+
- DB_PASSWORD:MAIN_DB_PASSWORD
|
71
|
+
tags:
|
72
|
+
secondary_db:
|
73
|
+
secret:
|
74
|
+
- DB_PASSWORD:SECONDARY_DB_PASSWORD
|
75
|
+
accessories:
|
76
|
+
main_db_accessory:
|
77
|
+
env:
|
78
|
+
secret:
|
79
|
+
- DB_PASSWORD:MAIN_DB_PASSWORD
|
80
|
+
secondary_db_accessory:
|
81
|
+
env:
|
82
|
+
secret:
|
83
|
+
- DB_PASSWORD:SECONDARY_DB_PASSWORD
|
84
|
+
|
54
85
|
# Tags
|
55
86
|
#
|
56
87
|
# Tags are used to add extra env variables to specific hosts.
|
@@ -52,6 +52,13 @@ proxy:
|
|
52
52
|
# Defaults to `false`:
|
53
53
|
ssl: true
|
54
54
|
|
55
|
+
# SSL redirect
|
56
|
+
#
|
57
|
+
# By default, kamal-proxy will redirect all HTTP requests to HTTPS when SSL is enabled.
|
58
|
+
# If you prefer that HTTP traffic is passed through to your application (along with
|
59
|
+
# HTTPS traffic), you can disable this redirect by setting `ssl_redirect: false`:
|
60
|
+
ssl_redirect: false
|
61
|
+
|
55
62
|
# Forward headers
|
56
63
|
#
|
57
64
|
# Whether to forward the `X-Forwarded-For` and `X-Forwarded-Proto` headers.
|
@@ -1,8 +1,7 @@
|
|
1
1
|
class Kamal::Configuration::Env
|
2
2
|
include Kamal::Configuration::Validation
|
3
3
|
|
4
|
-
attr_reader :context, :
|
5
|
-
attr_reader :clear, :secret_keys
|
4
|
+
attr_reader :context, :clear, :secret_keys
|
6
5
|
delegate :argumentize, to: Kamal::Utils
|
7
6
|
|
8
7
|
def initialize(config:, secrets:, context: "env")
|
@@ -18,12 +17,22 @@ class Kamal::Configuration::Env
|
|
18
17
|
end
|
19
18
|
|
20
19
|
def secrets_io
|
21
|
-
Kamal::EnvFile.new(
|
20
|
+
Kamal::EnvFile.new(aliased_secrets).to_io
|
22
21
|
end
|
23
22
|
|
24
23
|
def merge(other)
|
25
24
|
self.class.new \
|
26
25
|
config: { "clear" => clear.merge(other.clear), "secret" => secret_keys | other.secret_keys },
|
27
|
-
secrets: secrets
|
26
|
+
secrets: @secrets
|
28
27
|
end
|
28
|
+
|
29
|
+
private
|
30
|
+
def aliased_secrets
|
31
|
+
secret_keys.to_h { |key| extract_alias(key) }.transform_values { |secret_key| @secrets[secret_key] }
|
32
|
+
end
|
33
|
+
|
34
|
+
def extract_alias(key)
|
35
|
+
key_name, key_aliased_to = key.split(":", 2)
|
36
|
+
[ key_name, key_aliased_to || key_name ]
|
37
|
+
end
|
29
38
|
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
class Kamal::Configuration::Proxy::Boot
|
2
|
+
MINIMUM_VERSION = "v0.9.0"
|
3
|
+
DEFAULT_HTTP_PORT = 80
|
4
|
+
DEFAULT_HTTPS_PORT = 443
|
5
|
+
DEFAULT_LOG_MAX_SIZE = "10m"
|
6
|
+
|
7
|
+
attr_reader :config
|
8
|
+
delegate :argumentize, :optionize, to: Kamal::Utils
|
9
|
+
|
10
|
+
def initialize(config:)
|
11
|
+
@config = config
|
12
|
+
end
|
13
|
+
|
14
|
+
def publish_args(http_port, https_port, bind_ips = nil)
|
15
|
+
ensure_valid_bind_ips(bind_ips)
|
16
|
+
|
17
|
+
(bind_ips || [ nil ]).map do |bind_ip|
|
18
|
+
bind_ip = format_bind_ip(bind_ip)
|
19
|
+
publish_http = [ bind_ip, http_port, DEFAULT_HTTP_PORT ].compact.join(":")
|
20
|
+
publish_https = [ bind_ip, https_port, DEFAULT_HTTPS_PORT ].compact.join(":")
|
21
|
+
|
22
|
+
argumentize "--publish", [ publish_http, publish_https ]
|
23
|
+
end.join(" ")
|
24
|
+
end
|
25
|
+
|
26
|
+
def logging_args(max_size)
|
27
|
+
argumentize "--log-opt", "max-size=#{max_size}" if max_size.present?
|
28
|
+
end
|
29
|
+
|
30
|
+
def default_boot_options
|
31
|
+
[
|
32
|
+
*(publish_args(DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT, nil)),
|
33
|
+
*(logging_args(DEFAULT_LOG_MAX_SIZE))
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
37
|
+
def repository_name
|
38
|
+
"basecamp"
|
39
|
+
end
|
40
|
+
|
41
|
+
def image_name
|
42
|
+
"kamal-proxy"
|
43
|
+
end
|
44
|
+
|
45
|
+
def image_default
|
46
|
+
"#{repository_name}/#{image_name}"
|
47
|
+
end
|
48
|
+
|
49
|
+
def container_name
|
50
|
+
"kamal-proxy"
|
51
|
+
end
|
52
|
+
|
53
|
+
def host_directory
|
54
|
+
File.join config.run_directory, "proxy"
|
55
|
+
end
|
56
|
+
|
57
|
+
def options_file
|
58
|
+
File.join host_directory, "options"
|
59
|
+
end
|
60
|
+
|
61
|
+
def image_file
|
62
|
+
File.join host_directory, "image"
|
63
|
+
end
|
64
|
+
|
65
|
+
def image_version_file
|
66
|
+
File.join host_directory, "image_version"
|
67
|
+
end
|
68
|
+
|
69
|
+
def run_command_file
|
70
|
+
File.join host_directory, "run_command"
|
71
|
+
end
|
72
|
+
|
73
|
+
def apps_directory
|
74
|
+
File.join host_directory, "apps-config"
|
75
|
+
end
|
76
|
+
|
77
|
+
def apps_container_directory
|
78
|
+
"/home/kamal-proxy/.apps-config"
|
79
|
+
end
|
80
|
+
|
81
|
+
def apps_volume
|
82
|
+
Kamal::Configuration::Volume.new \
|
83
|
+
host_path: apps_directory,
|
84
|
+
container_path: apps_container_directory
|
85
|
+
end
|
86
|
+
|
87
|
+
def app_directory
|
88
|
+
File.join apps_directory, config.service_and_destination
|
89
|
+
end
|
90
|
+
|
91
|
+
def app_container_directory
|
92
|
+
File.join apps_container_directory, config.service_and_destination
|
93
|
+
end
|
94
|
+
|
95
|
+
def error_pages_directory
|
96
|
+
File.join app_directory, "error_pages"
|
97
|
+
end
|
98
|
+
|
99
|
+
def error_pages_container_directory
|
100
|
+
File.join app_container_directory, "error_pages"
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
def ensure_valid_bind_ips(bind_ips)
|
105
|
+
bind_ips.present? && bind_ips.each do |ip|
|
106
|
+
next if ip =~ Resolv::IPv4::Regex || ip =~ Resolv::IPv6::Regex
|
107
|
+
raise ArgumentError, "Invalid publish IP address: #{ip}"
|
108
|
+
end
|
109
|
+
|
110
|
+
true
|
111
|
+
end
|
112
|
+
|
113
|
+
def format_bind_ip(ip)
|
114
|
+
# Ensure IPv6 address inside square brackets - e.g. [::1]
|
115
|
+
if ip =~ Resolv::IPv6::Regex && ip !~ /\A\[.*\]\z/
|
116
|
+
"[#{ip}]"
|
117
|
+
else
|
118
|
+
ip
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -42,8 +42,10 @@ class Kamal::Configuration::Proxy
|
|
42
42
|
"max-request-body": proxy_config.dig("buffering", "max_request_body"),
|
43
43
|
"max-response-body": proxy_config.dig("buffering", "max_response_body"),
|
44
44
|
"forward-headers": proxy_config.dig("forward_headers"),
|
45
|
+
"tls-redirect": proxy_config.dig("ssl_redirect"),
|
45
46
|
"log-request-header": proxy_config.dig("logging", "request_headers") || DEFAULT_LOG_REQUEST_HEADERS,
|
46
|
-
"log-response-header": proxy_config.dig("logging", "response_headers")
|
47
|
+
"log-response-header": proxy_config.dig("logging", "response_headers"),
|
48
|
+
"error-pages": error_pages
|
47
49
|
}.compact
|
48
50
|
end
|
49
51
|
|
@@ -51,6 +53,17 @@ class Kamal::Configuration::Proxy
|
|
51
53
|
optionize ({ target: "#{target}:#{app_port}" }).merge(deploy_options), with: "="
|
52
54
|
end
|
53
55
|
|
56
|
+
def stop_options(drain_timeout: nil, message: nil)
|
57
|
+
{
|
58
|
+
"drain-timeout": seconds_duration(drain_timeout),
|
59
|
+
message: message
|
60
|
+
}.compact
|
61
|
+
end
|
62
|
+
|
63
|
+
def stop_command_args(**options)
|
64
|
+
optionize stop_options(**options), with: "="
|
65
|
+
end
|
66
|
+
|
54
67
|
def merge(other)
|
55
68
|
self.class.new config: config, proxy_config: proxy_config.deep_merge(other.proxy_config)
|
56
69
|
end
|
@@ -59,4 +72,8 @@ class Kamal::Configuration::Proxy
|
|
59
72
|
def seconds_duration(value)
|
60
73
|
value ? "#{value}s" : nil
|
61
74
|
end
|
75
|
+
|
76
|
+
def error_pages
|
77
|
+
File.join config.proxy_boot.error_pages_container_directory, config.version if config.error_pages_path
|
78
|
+
end
|
62
79
|
end
|
@@ -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,10 @@ 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_docker_options!(config["options"])
|
8
10
|
end
|
9
11
|
end
|
@@ -168,4 +168,10 @@ class Kamal::Configuration::Validator
|
|
168
168
|
unknown_keys.reject! { |key| extension?(key) } if allow_extensions?
|
169
169
|
unknown_keys_error unknown_keys if unknown_keys.present?
|
170
170
|
end
|
171
|
+
|
172
|
+
def validate_docker_options!(options)
|
173
|
+
if options
|
174
|
+
error "Cannot set restart policy in docker options, unless-stopped is required" if options["restart"]
|
175
|
+
end
|
176
|
+
end
|
171
177
|
end
|