Extract Kamal::Configuration::Proxy::Boot

This is for boot time configuration for the kamal proxy. Config in here
doesn't not belong in Kamal::Configuration::Proxy which is for deploy
time configuration for the app itself.

Kamal apps don't contain boot time config, because multiple apps can
share a proxy and the config could conflict.
This commit is contained in:
Donal McBreen
2025-04-23 16:01:04 +01:00
parent eb915f830e
commit 128294672d
15 changed files with 196 additions and 169 deletions

View File

@@ -13,7 +13,7 @@ class Kamal::Cli::App::ErrorPages
if KAMAL.config.error_pages_path if KAMAL.config.error_pages_path
with_error_pages_tmpdir do |local_error_pages_dir| with_error_pages_tmpdir do |local_error_pages_dir|
execute *KAMAL.app.create_error_pages_directory execute *KAMAL.app.create_error_pages_directory
upload! local_error_pages_dir, KAMAL.config.proxy_error_pages_directory, mode: "0700", recursive: true upload! local_error_pages_dir, KAMAL.config.proxy_boot.error_pages_directory, mode: "0700", recursive: true
end end
end end
end end

View File

@@ -13,8 +13,8 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
version = capture_with_info(*KAMAL.proxy.version).strip.presence version = capture_with_info(*KAMAL.proxy.version).strip.presence
if version && Kamal::Utils.older_version?(version, Kamal::Configuration::PROXY_MINIMUM_VERSION) if version && Kamal::Utils.older_version?(version, Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION)
raise "kamal-proxy version #{version} is too old, run `kamal proxy reboot` in order to update to at least #{Kamal::Configuration::PROXY_MINIMUM_VERSION}" raise "kamal-proxy version #{version} is too old, run `kamal proxy reboot` in order to update to at least #{Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION}"
end end
execute *KAMAL.proxy.ensure_apps_config_directory execute *KAMAL.proxy.ensure_apps_config_directory
execute *KAMAL.proxy.start_or_run execute *KAMAL.proxy.start_or_run
@@ -25,46 +25,48 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
desc "boot_config <set|get|reset>", "Manage kamal-proxy boot configuration" desc "boot_config <set|get|reset>", "Manage kamal-proxy boot configuration"
option :publish, type: :boolean, default: true, desc: "Publish the proxy ports on the host" option :publish, type: :boolean, default: true, desc: "Publish the proxy ports on the host"
option :publish_host_ip, type: :string, repeatable: true, default: nil, desc: "Host IP address to bind HTTP/HTTPS traffic to. Defaults to all interfaces" option :publish_host_ip, type: :string, repeatable: true, default: nil, desc: "Host IP address to bind HTTP/HTTPS traffic to. Defaults to all interfaces"
option :http_port, type: :numeric, default: Kamal::Configuration::PROXY_HTTP_PORT, desc: "HTTP port to publish on the host" option :http_port, type: :numeric, default: Kamal::Configuration::Proxy::Boot::DEFAULT_HTTP_PORT, desc: "HTTP port to publish on the host"
option :https_port, type: :numeric, default: Kamal::Configuration::PROXY_HTTPS_PORT, desc: "HTTPS port to publish on the host" option :https_port, type: :numeric, default: Kamal::Configuration::Proxy::Boot::DEFAULT_HTTPS_PORT, desc: "HTTPS port to publish on the host"
option :log_max_size, type: :string, default: Kamal::Configuration::PROXY_LOG_MAX_SIZE, desc: "Max size of proxy logs" option :log_max_size, type: :string, default: Kamal::Configuration::Proxy::Boot::DEFAULT_LOG_MAX_SIZE, desc: "Max size of proxy logs"
option :registry, type: :string, default: nil, desc: "Registry to use for the proxy image" option :registry, type: :string, default: nil, desc: "Registry to use for the proxy image"
option :repository, type: :string, default: nil, desc: "Repository for the proxy image" option :repository, type: :string, default: nil, desc: "Repository for the proxy image"
option :image_version, type: :string, default: nil, desc: "Version of the proxy to run" option :image_version, type: :string, default: nil, desc: "Version of the proxy to run"
option :docker_options, type: :array, default: [], desc: "Docker options to pass to the proxy container", banner: "option=value option2=value2" option :docker_options, type: :array, default: [], desc: "Docker options to pass to the proxy container", banner: "option=value option2=value2"
def boot_config(subcommand) def boot_config(subcommand)
proxy_boot_config = KAMAL.config.proxy_boot
case subcommand case subcommand
when "set" when "set"
boot_options = [ boot_options = [
*(KAMAL.config.proxy_publish_args(options[:http_port], options[:https_port], options[:publish_host_ip]) if options[:publish]), *(proxy_boot_config.publish_args(options[:http_port], options[:https_port], options[:publish_host_ip]) if options[:publish]),
*(KAMAL.config.proxy_logging_args(options[:log_max_size])), *(proxy_boot_config.logging_args(options[:log_max_size])),
*options[:docker_options].map { |option| "--#{option}" } *options[:docker_options].map { |option| "--#{option}" }
] ]
image = [ image = [
options[:registry].presence, options[:registry].presence,
options[:repository].presence || KAMAL.config.proxy_repository_name, options[:repository].presence || proxy_boot_config.repository_name,
KAMAL.config.proxy_image_name proxy_boot_config.image_name
].compact.join("/") ].compact.join("/")
image_version = options[:image_version] image_version = options[:image_version]
on(KAMAL.proxy_hosts) do |host| on(KAMAL.proxy_hosts) do |host|
execute(*KAMAL.proxy.ensure_proxy_directory) execute(*KAMAL.proxy.ensure_proxy_directory)
if boot_options != KAMAL.config.proxy_default_boot_options if boot_options != proxy_boot_config.default_boot_options
upload! StringIO.new(boot_options.join(" ")), KAMAL.config.proxy_options_file upload! StringIO.new(boot_options.join(" ")), proxy_boot_config.options_file
else else
execute *KAMAL.proxy.reset_boot_options, raise_on_non_zero_exit: false execute *KAMAL.proxy.reset_boot_options, raise_on_non_zero_exit: false
end end
if image != KAMAL.config.proxy_image_default if image != proxy_boot_config.image_default
upload! StringIO.new(image), KAMAL.config.proxy_image_file upload! StringIO.new(image), proxy_boot_config.image_file
else else
execute *KAMAL.proxy.reset_image, raise_on_non_zero_exit: false execute *KAMAL.proxy.reset_image, raise_on_non_zero_exit: false
end end
if image_version if image_version
upload! StringIO.new(image_version), KAMAL.config.proxy_image_version_file upload! StringIO.new(image_version), proxy_boot_config.image_version_file
else else
execute *KAMAL.proxy.reset_image_version, raise_on_non_zero_exit: false execute *KAMAL.proxy.reset_image_version, raise_on_non_zero_exit: false
end end

View File

@@ -6,7 +6,6 @@ class Kamal::Commands::Accessory < Kamal::Commands::Base
:network_args, :publish_args, :env_args, :volume_args, :label_args, :option_args, :network_args, :publish_args, :env_args, :volume_args, :label_args, :option_args,
:secrets_io, :secrets_path, :env_directory, :proxy, :running_proxy?, :registry, :secrets_io, :secrets_path, :env_directory, :proxy, :running_proxy?, :registry,
to: :accessory_config to: :accessory_config
delegate :proxy_container_name, to: :config
def initialize(config, name:) def initialize(config, name:)
super(config) super(config)

View File

@@ -1,5 +1,5 @@
module Kamal::Commands::Accessory::Proxy module Kamal::Commands::Accessory::Proxy
delegate :proxy_container_name, to: :config delegate :container_name, to: :"config.proxy_boot", prefix: :proxy
def deploy(target:) def deploy(target:)
proxy_exec :deploy, service_name, *proxy.deploy_command_args(target: target) proxy_exec :deploy, service_name, *proxy.deploy_command_args(target: target)

View File

@@ -1,9 +1,9 @@
module Kamal::Commands::App::ErrorPages module Kamal::Commands::App::ErrorPages
def create_error_pages_directory def create_error_pages_directory
make_directory(config.proxy_error_pages_directory) make_directory(config.proxy_boot.error_pages_directory)
end end
def clean_up_error_pages def clean_up_error_pages
[ :find, config.proxy_error_pages_directory, "-mindepth", "1", "-maxdepth", "1", "!", "-name", KAMAL.config.version, "-exec", "rm", "-rf", "{} +" ] [ :find, config.proxy_boot.error_pages_directory, "-mindepth", "1", "-maxdepth", "1", "!", "-name", KAMAL.config.version, "-exec", "rm", "-rf", "{} +" ]
end end
end end

View File

@@ -1,5 +1,5 @@
module Kamal::Commands::App::Proxy module Kamal::Commands::App::Proxy
delegate :proxy_container_name, to: :config delegate :container_name, to: :"config.proxy_boot", prefix: :proxy
def deploy(target:) def deploy(target:)
proxy_exec :deploy, role.container_prefix, *role.proxy.deploy_command_args(target: target) proxy_exec :deploy, role.container_prefix, *role.proxy.deploy_command_args(target: target)
@@ -18,7 +18,7 @@ module Kamal::Commands::App::Proxy
end end
def remove_proxy_app_directory def remove_proxy_app_directory
remove_directory config.proxy_app_directory remove_directory config.proxy_boot.app_directory
end end
private private

View File

@@ -58,15 +58,15 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base
end end
def ensure_proxy_directory def ensure_proxy_directory
make_directory config.proxy_directory make_directory config.proxy_boot.host_directory
end end
def remove_proxy_directory def remove_proxy_directory
remove_directory config.proxy_directory remove_directory config.proxy_boot.host_directory
end end
def ensure_apps_config_directory def ensure_apps_config_directory
make_directory config.proxy_apps_directory make_directory config.proxy_boot.apps_directory
end end
def boot_config def boot_config
@@ -74,32 +74,32 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base
end end
def read_boot_options def read_boot_options
read_file(config.proxy_options_file, default: config.proxy_options_default.join(" ")) read_file(config.proxy_boot.options_file, default: config.proxy_boot.default_boot_options.join(" "))
end end
def read_image def read_image
read_file(config.proxy_image_file, default: config.proxy_image_default) read_file(config.proxy_boot.image_file, default: config.proxy_boot.image_default)
end end
def read_image_version def read_image_version
read_file(config.proxy_image_version_file, default: Kamal::Configuration::PROXY_MINIMUM_VERSION) read_file(config.proxy_boot.image_version_file, default: Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION)
end end
def reset_boot_options def reset_boot_options
remove_file config.proxy_options_file remove_file config.proxy_boot.options_file
end end
def reset_image def reset_image
remove_file config.proxy_image_file remove_file config.proxy_boot.image_file
end end
def reset_image_version def reset_image_version
remove_file config.proxy_image_version_file remove_file config.proxy_boot.image_version_file
end end
private private
def container_name def container_name
config.proxy_container_name config.proxy_boot.container_name
end end
def read_file(file, default: nil) def read_file(file, default: nil)
@@ -114,6 +114,6 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base
"--detach", "--detach",
"--restart", "unless-stopped", "--restart", "unless-stopped",
"--volume", "kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", "--volume", "kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy",
*config.proxy_apps_volume.docker_args *config.proxy_boot.apps_volume.docker_args
end end
end end

View File

@@ -10,15 +10,10 @@ class Kamal::Configuration
delegate :argumentize, :optionize, to: Kamal::Utils delegate :argumentize, :optionize, to: Kamal::Utils
attr_reader :destination, :raw_config, :secrets attr_reader :destination, :raw_config, :secrets
attr_reader :accessories, :aliases, :boot, :builder, :env, :logging, :proxy, :servers, :ssh, :sshkit, :registry attr_reader :accessories, :aliases, :boot, :builder, :env, :logging, :proxy, :proxy_boot, :servers, :ssh, :sshkit, :registry
include Validation include Validation
PROXY_MINIMUM_VERSION = "v0.8.7"
PROXY_HTTP_PORT = 80
PROXY_HTTPS_PORT = 443
PROXY_LOG_MAX_SIZE = "10m"
class << self class << self
def create_from(config_file:, destination: nil, version: nil) def create_from(config_file:, destination: nil, version: nil)
ENV["KAMAL_DESTINATION"] = destination ENV["KAMAL_DESTINATION"] = destination
@@ -69,6 +64,7 @@ class Kamal::Configuration
@logging = Logging.new(logging_config: @raw_config.logging) @logging = Logging.new(logging_config: @raw_config.logging)
@proxy = Proxy.new(config: self, proxy_config: @raw_config.key?(:proxy) ? @raw_config.proxy : {}) @proxy = Proxy.new(config: self, proxy_config: @raw_config.key?(:proxy) ? @raw_config.proxy : {})
@proxy_boot = Proxy::Boot.new(config: self)
@ssh = Ssh.new(config: self) @ssh = Ssh.new(config: self)
@sshkit = Sshkit.new(config: self) @sshkit = Sshkit.new(config: self)
@@ -257,95 +253,6 @@ class Kamal::Configuration
env_tags.detect { |t| t.name == name.to_s } env_tags.detect { |t| t.name == name.to_s }
end end
def proxy_publish_args(http_port, https_port, bind_ips = nil)
ensure_valid_bind_ips(bind_ips)
(bind_ips || [ nil ]).map do |bind_ip|
bind_ip = format_bind_ip(bind_ip)
publish_http = [ bind_ip, http_port, PROXY_HTTP_PORT ].compact.join(":")
publish_https = [ bind_ip, https_port, PROXY_HTTPS_PORT ].compact.join(":")
argumentize "--publish", [ publish_http, publish_https ]
end.join(" ")
end
def proxy_logging_args(max_size)
argumentize "--log-opt", "max-size=#{max_size}" if max_size.present?
end
def proxy_default_boot_options
[
*(KAMAL.config.proxy_publish_args(Kamal::Configuration::PROXY_HTTP_PORT, Kamal::Configuration::PROXY_HTTPS_PORT, nil)),
*(KAMAL.config.proxy_logging_args(Kamal::Configuration::PROXY_LOG_MAX_SIZE))
]
end
def proxy_options_default
[ *proxy_publish_args(PROXY_HTTP_PORT, PROXY_HTTPS_PORT), *proxy_logging_args(PROXY_LOG_MAX_SIZE) ]
end
def proxy_repository_name
"basecamp"
end
def proxy_image_name
"kamal-proxy"
end
def proxy_image_default
"#{proxy_repository_name}/#{proxy_image_name}"
end
def proxy_container_name
"kamal-proxy"
end
def proxy_directory
File.join run_directory, "proxy"
end
def proxy_options_file
File.join proxy_directory, "options"
end
def proxy_image_file
File.join proxy_directory, "image"
end
def proxy_image_version_file
File.join proxy_directory, "image_version"
end
def proxy_apps_directory
File.join proxy_directory, "apps-config"
end
def proxy_apps_container_directory
"/home/kamal-proxy/.apps-config"
end
def proxy_apps_volume
Volume.new \
host_path: proxy_apps_directory,
container_path: proxy_apps_container_directory
end
def proxy_app_directory
File.join proxy_apps_directory, service_and_destination
end
def proxy_app_container_directory
File.join proxy_apps_container_directory, service_and_destination
end
def proxy_error_pages_directory
File.join proxy_app_directory, "error_pages"
end
def proxy_error_pages_container_directory
File.join proxy_app_container_directory, "error_pages"
end
def to_h def to_h
{ {
roles: role_names, roles: role_names,
@@ -416,15 +323,6 @@ class Kamal::Configuration
true true
end end
def ensure_valid_bind_ips(bind_ips)
bind_ips.present? && bind_ips.each do |ip|
next if ip =~ Resolv::IPv4::Regex || ip =~ Resolv::IPv6::Regex
raise ArgumentError, "Invalid publish IP address: #{ip}"
end
true
end
def ensure_retain_containers_valid def ensure_retain_containers_valid
raise Kamal::ConfigurationError, "Must retain at least 1 container" if retain_containers < 1 raise Kamal::ConfigurationError, "Must retain at least 1 container" if retain_containers < 1
@@ -456,15 +354,6 @@ class Kamal::Configuration
true true
end end
def format_bind_ip(ip)
# Ensure IPv6 address inside square brackets - e.g. [::1]
if ip =~ Resolv::IPv6::Regex && ip !~ /\[.*\]/
"[#{ip}]"
else
ip
end
end
def role_names def role_names
raw_config.servers.is_a?(Array) ? [ "web" ] : raw_config.servers.keys.sort raw_config.servers.is_a?(Array) ? [ "web" ] : raw_config.servers.keys.sort
end end

View File

@@ -74,6 +74,6 @@ class Kamal::Configuration::Proxy
end end
def error_pages def error_pages
File.join config.proxy_error_pages_container_directory, config.version if config.error_pages_path File.join config.proxy_boot.error_pages_container_directory, config.version if config.error_pages_path
end end
end end

View File

@@ -0,0 +1,117 @@
class Kamal::Configuration::Proxy::Boot
MINIMUM_VERSION = "v0.8.7"
DEFAULT_HTTP_PORT = 80
DEFAULT_HTTPS_PORT = 443
DEFAULT_LOG_MAX_SIZE = "10m"
attr_reader :config
delegate :argumentize, :optionize, to: Kamal::Utils
def initialize(config:)
@config = config
end
def publish_args(http_port, https_port, bind_ips = nil)
ensure_valid_bind_ips(bind_ips)
(bind_ips || [ nil ]).map do |bind_ip|
bind_ip = format_bind_ip(bind_ip)
publish_http = [ bind_ip, http_port, DEFAULT_HTTP_PORT ].compact.join(":")
publish_https = [ bind_ip, https_port, DEFAULT_HTTPS_PORT ].compact.join(":")
argumentize "--publish", [ publish_http, publish_https ]
end.join(" ")
end
def logging_args(max_size)
argumentize "--log-opt", "max-size=#{max_size}" if max_size.present?
end
def default_boot_options
[
*(publish_args(DEFAULT_HTTP_PORT, DEFAULT_HTTPS_PORT, nil)),
*(logging_args(DEFAULT_LOG_MAX_SIZE))
]
end
def repository_name
"basecamp"
end
def image_name
"kamal-proxy"
end
def image_default
"#{repository_name}/#{image_name}"
end
def container_name
"kamal-proxy"
end
def host_directory
File.join config.run_directory, "proxy"
end
def options_file
File.join host_directory, "options"
end
def image_file
File.join host_directory, "image"
end
def image_version_file
File.join host_directory, "image_version"
end
def apps_directory
File.join host_directory, "apps-config"
end
def apps_container_directory
"/home/kamal-proxy/.apps-config"
end
def apps_volume
Kamal::Configuration::Volume.new \
host_path: apps_directory,
container_path: apps_container_directory
end
def app_directory
File.join apps_directory, config.service_and_destination
end
def app_container_directory
File.join apps_container_directory, config.service_and_destination
end
def error_pages_directory
File.join app_directory, "error_pages"
end
def error_pages_container_directory
File.join app_container_directory, "error_pages"
end
private
def ensure_valid_bind_ips(bind_ips)
bind_ips.present? && bind_ips.each do |ip|
next if ip =~ Resolv::IPv4::Regex || ip =~ Resolv::IPv6::Regex
raise ArgumentError, "Invalid publish IP address: #{ip}"
end
true
end
def format_bind_ip(ip)
# Ensure IPv6 address inside square brackets - e.g. [::1]
if ip =~ Resolv::IPv6::Regex && ip !~ /\[.*\]/
"[#{ip}]"
else
ip
end
end
end

View File

@@ -5,7 +5,7 @@ class CliProxyTest < CliTestCase
run_command("boot").tap do |output| run_command("boot").tap do |output|
assert_match "docker login", output assert_match "docker login", output
assert_match "mkdir -p .kamal/proxy/apps-config", output assert_match "mkdir -p .kamal/proxy/apps-config", output
assert_match "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::PROXY_MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", output assert_match "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", output
end end
end end
@@ -19,11 +19,11 @@ class CliProxyTest < CliTestCase
exception = assert_raises do exception = assert_raises do
run_command("boot").tap do |output| run_command("boot").tap do |output|
assert_match "docker login", output assert_match "docker login", output
assert_match "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::PROXY_MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", output assert_match "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", output
end end
end end
assert_includes exception.message, "kamal-proxy version v0.0.1 is too old, run `kamal proxy reboot` in order to update to at least #{Kamal::Configuration::PROXY_MINIMUM_VERSION}" assert_includes exception.message, "kamal-proxy version v0.0.1 is too old, run `kamal proxy reboot` in order to update to at least #{Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION}"
ensure ensure
Thread.report_on_exception = false Thread.report_on_exception = false
end end
@@ -32,12 +32,12 @@ class CliProxyTest < CliTestCase
Thread.report_on_exception = false Thread.report_on_exception = false
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
.with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'") .with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'")
.returns(Kamal::Configuration::PROXY_MINIMUM_VERSION) .returns(Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION)
.at_least_once .at_least_once
run_command("boot").tap do |output| run_command("boot").tap do |output|
assert_match "docker login", output assert_match "docker login", output
assert_match "docker container start kamal-proxy || echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::PROXY_MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", output assert_match "docker container start kamal-proxy || echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", output
end end
ensure ensure
Thread.report_on_exception = false Thread.report_on_exception = false
@@ -58,13 +58,13 @@ class CliProxyTest < CliTestCase
assert_match "docker container stop kamal-proxy on 1.1.1.1", output assert_match "docker container stop kamal-proxy on 1.1.1.1", output
assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.1", output assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.1", output
assert_match "mkdir -p .kamal/proxy/apps-config on 1.1.1.1", output assert_match "mkdir -p .kamal/proxy/apps-config on 1.1.1.1", output
assert_match "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::PROXY_MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $(pwd)/.kamal/proxy/apps-config:/home/kamal-proxy/.apps-config on 1.1.1.1", output assert_match "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $(pwd)/.kamal/proxy/apps-config:/home/kamal-proxy/.apps-config on 1.1.1.1", output
assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"abcdefabcdef:80\" --deploy-timeout=\"6s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\" on 1.1.1.1", output assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"abcdefabcdef:80\" --deploy-timeout=\"6s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\" on 1.1.1.1", output
assert_match "docker container stop kamal-proxy on 1.1.1.2", output assert_match "docker container stop kamal-proxy on 1.1.1.2", output
assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.2", output assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy on 1.1.1.2", output
assert_match "mkdir -p .kamal/proxy/apps-config on 1.1.1.1", output assert_match "mkdir -p .kamal/proxy/apps-config on 1.1.1.1", output
assert_match "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::PROXY_MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $(pwd)/.kamal/proxy/apps-config:/home/kamal-proxy/.apps-config on 1.1.1.2", output assert_match "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $(pwd)/.kamal/proxy/apps-config:/home/kamal-proxy/.apps-config on 1.1.1.2", output
assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"abcdefabcdef:80\" --deploy-timeout=\"6s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\" on 1.1.1.2", output assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"abcdefabcdef:80\" --deploy-timeout=\"6s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\" on 1.1.1.2", output
end end
end end
@@ -183,7 +183,7 @@ class CliProxyTest < CliTestCase
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
.with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'") .with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'")
.returns(Kamal::Configuration::PROXY_MINIMUM_VERSION) .returns(Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION)
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-workers-latest$", "--quiet", "|", :xargs, :docker, :inspect, "--format", "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'") .with(:docker, :container, :ls, "--all", "--filter", "name=^app-workers-latest$", "--quiet", "|", :xargs, :docker, :inspect, "--format", "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'")
@@ -199,7 +199,7 @@ class CliProxyTest < CliTestCase
assert_match "/usr/bin/env mkdir -p .kamal", output assert_match "/usr/bin/env mkdir -p .kamal", output
assert_match "docker network create kamal", output assert_match "docker network create kamal", output
assert_match "docker login -u [REDACTED] -p [REDACTED]", output assert_match "docker login -u [REDACTED] -p [REDACTED]", output
assert_match "docker container start kamal-proxy || echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::PROXY_MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", output assert_match "docker container start kamal-proxy || echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy", output
assert_match "/usr/bin/env mkdir -p .kamal", output assert_match "/usr/bin/env mkdir -p .kamal", output
assert_match %r{docker rename app-web-latest app-web-latest_replaced_.*}, output assert_match %r{docker rename app-web-latest app-web-latest_replaced_.*}, output
assert_match "/usr/bin/env mkdir -p .kamal/apps/app/env/roles", output assert_match "/usr/bin/env mkdir -p .kamal/apps/app/env/roles", output
@@ -222,7 +222,7 @@ class CliProxyTest < CliTestCase
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
.with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'") .with(:docker, :inspect, "kamal-proxy", "--format '{{.Config.Image}}'", "|", :awk, "-F:", "'{print $NF}'")
.returns(Kamal::Configuration::PROXY_MINIMUM_VERSION) .returns(Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION)
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info) SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-workers-latest$", "--quiet", "|", :xargs, :docker, :inspect, "--format", "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'") .with(:docker, :container, :ls, "--all", "--filter", "name=^app-workers-latest$", "--quiet", "|", :xargs, :docker, :inspect, "--format", "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'")

View File

@@ -15,7 +15,7 @@ class CommandsProxyTest < ActiveSupport::TestCase
test "run" do test "run" do
assert_equal \ assert_equal \
"echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::PROXY_MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $(pwd)/.kamal/proxy/apps-config:/home/kamal-proxy/.apps-config", "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $(pwd)/.kamal/proxy/apps-config:/home/kamal-proxy/.apps-config",
new_command.run.join(" ") new_command.run.join(" ")
end end
@@ -23,7 +23,7 @@ class CommandsProxyTest < ActiveSupport::TestCase
@config.delete(:proxy) @config.delete(:proxy)
assert_equal \ assert_equal \
"echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::PROXY_MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $(pwd)/.kamal/proxy/apps-config:/home/kamal-proxy/.apps-config", "echo $(cat .kamal/proxy/options 2> /dev/null || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\") $(cat .kamal/proxy/image 2> /dev/null || echo \"basecamp/kamal-proxy\"):$(cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION}\") | xargs docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --volume $(pwd)/.kamal/proxy/apps-config:/home/kamal-proxy/.apps-config",
new_command.run.join(" ") new_command.run.join(" ")
end end
@@ -125,7 +125,7 @@ class CommandsProxyTest < ActiveSupport::TestCase
test "read_image_version" do test "read_image_version" do
assert_equal \ assert_equal \
"cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::PROXY_MINIMUM_VERSION}\"", "cat .kamal/proxy/image_version 2> /dev/null || echo \"#{Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION}\"",
new_command.read_image_version.join(" ") new_command.read_image_version.join(" ")
end end

View File

@@ -0,0 +1,29 @@
require "test_helper"
class ConfigurationProxyBootTest < ActiveSupport::TestCase
setup do
ENV["RAILS_MASTER_KEY"] = "456"
ENV["VERSION"] = "missing"
@deploy = {
service: "app", image: "dhh/app",
registry: { "username" => "dhh", "password" => "secret" },
builder: { "arch" => "amd64" },
env: { "REDIS_URL" => "redis://x/y" },
servers: [ "1.1.1.1", "1.1.1.2" ],
volumes: [ "/local/path:/container/path" ]
}
@config = Kamal::Configuration.new(@deploy)
@proxy_boot_config = @config.proxy_boot
end
test "proxy directories" do
assert_equal ".kamal/proxy/apps-config", @proxy_boot_config.apps_directory
assert_equal "/home/kamal-proxy/.apps-config", @proxy_boot_config.apps_container_directory
assert_equal ".kamal/proxy/apps-config/app", @proxy_boot_config.app_directory
assert_equal "/home/kamal-proxy/.apps-config/app", @proxy_boot_config.app_container_directory
assert_equal ".kamal/proxy/apps-config/app/error_pages", @proxy_boot_config.error_pages_directory
assert_equal "/home/kamal-proxy/.apps-config/app/error_pages", @proxy_boot_config.error_pages_container_directory
end
end

View File

@@ -410,13 +410,4 @@ class ConfigurationTest < ActiveSupport::TestCase
assert_equal "Different roles can't share the same host for SSL: foo.example.com", exception.message assert_equal "Different roles can't share the same host for SSL: foo.example.com", exception.message
end end
test "proxy directories" do
assert_equal ".kamal/proxy/apps-config", @config.proxy_apps_directory
assert_equal "/home/kamal-proxy/.apps-config", @config.proxy_apps_container_directory
assert_equal ".kamal/proxy/apps-config/app", @config.proxy_app_directory
assert_equal "/home/kamal-proxy/.apps-config/app", @config.proxy_app_container_directory
assert_equal ".kamal/proxy/apps-config/app/error_pages", @config.proxy_error_pages_directory
assert_equal "/home/kamal-proxy/.apps-config/app/error_pages", @config.proxy_error_pages_container_directory
end
end end

View File

@@ -32,7 +32,7 @@ class MainTest < IntegrationTest
assert_match /Proxy Host: vm2/, details assert_match /Proxy Host: vm2/, details
assert_match /App Host: vm1/, details assert_match /App Host: vm1/, details
assert_match /App Host: vm2/, details assert_match /App Host: vm2/, details
assert_match /basecamp\/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION}/, details assert_match /basecamp\/kamal-proxy:#{Kamal::Configuration::Proxy::Boot::MINIMUM_VERSION}/, details
assert_match /registry:4443\/app:#{first_version}/, details assert_match /registry:4443\/app:#{first_version}/, details
audit = kamal :audit, capture: true audit = kamal :audit, capture: true