Compare commits
41 Commits
v2.0.0.bet
...
v2.0.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c32e6af07 | ||
|
|
a765c501a3 | ||
|
|
ae990efd02 | ||
|
|
b3a6921118 | ||
|
|
325bf9a797 | ||
|
|
7bdf6cd2e8 | ||
|
|
7633fe0293 | ||
|
|
f6851048a6 | ||
|
|
f0d7f786fa | ||
|
|
4d8387b1c9 | ||
|
|
0258ac4297 | ||
|
|
4a13803119 | ||
|
|
bda252835b | ||
|
|
0f5dfa204f | ||
|
|
9dde204480 | ||
|
|
b6cd4f8070 | ||
|
|
e71bfcbadd | ||
|
|
567309596a | ||
|
|
b89ec2bf63 | ||
|
|
3172adca30 | ||
|
|
04d21f45bb | ||
|
|
eabd57350c | ||
|
|
487f6f5f53 | ||
|
|
d98500982d | ||
|
|
8693e968c1 | ||
|
|
6ab5fc9459 | ||
|
|
6fc2915884 | ||
|
|
afa6898a82 | ||
|
|
384b36d158 | ||
|
|
6df169a4fb | ||
|
|
ab109afc52 | ||
|
|
a6a48c456c | ||
|
|
a4e5dbe5d4 | ||
|
|
56e90906b1 | ||
|
|
6e65968bdc | ||
|
|
85f1e14b97 | ||
|
|
2c829a4824 | ||
|
|
45a58f7e15 | ||
|
|
834b343ded | ||
|
|
9fe1821cae | ||
|
|
1d7c9fec1d |
@@ -1,7 +1,7 @@
|
|||||||
PATH
|
PATH
|
||||||
remote: .
|
remote: .
|
||||||
specs:
|
specs:
|
||||||
kamal (2.0.0.beta1)
|
kamal (2.0.0)
|
||||||
activesupport (>= 7.0)
|
activesupport (>= 7.0)
|
||||||
base64 (~> 0.2)
|
base64 (~> 0.2)
|
||||||
bcrypt_pbkdf (~> 1.0)
|
bcrypt_pbkdf (~> 1.0)
|
||||||
|
|||||||
@@ -147,23 +147,25 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|||||||
option :grep, aliases: "-g", desc: "Show lines with grep match only (use this to fetch specific requests by id)"
|
option :grep, aliases: "-g", desc: "Show lines with grep match only (use this to fetch specific requests by id)"
|
||||||
option :grep_options, aliases: "-o", desc: "Additional options supplied to grep"
|
option :grep_options, aliases: "-o", desc: "Additional options supplied to grep"
|
||||||
option :follow, aliases: "-f", desc: "Follow logs on primary server (or specific host set by --hosts)"
|
option :follow, aliases: "-f", desc: "Follow logs on primary server (or specific host set by --hosts)"
|
||||||
|
option :skip_timestamps, type: :boolean, aliases: "-T", desc: "Skip appending timestamps to logging output"
|
||||||
def logs(name)
|
def logs(name)
|
||||||
with_accessory(name) do |accessory, hosts|
|
with_accessory(name) do |accessory, hosts|
|
||||||
grep = options[:grep]
|
grep = options[:grep]
|
||||||
grep_options = options[:grep_options]
|
grep_options = options[:grep_options]
|
||||||
|
timestamps = !options[:skip_timestamps]
|
||||||
|
|
||||||
if options[:follow]
|
if options[:follow]
|
||||||
run_locally do
|
run_locally do
|
||||||
info "Following logs on #{hosts}..."
|
info "Following logs on #{hosts}..."
|
||||||
info accessory.follow_logs(grep: grep, grep_options: grep_options)
|
info accessory.follow_logs(timestamps: timestamps, grep: grep, grep_options: grep_options)
|
||||||
exec accessory.follow_logs(grep: grep, grep_options: grep_options)
|
exec accessory.follow_logs(timestamps: timestamps, grep: grep, grep_options: grep_options)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
since = options[:since]
|
since = options[:since]
|
||||||
lines = options[:lines].presence || ((since || grep) ? nil : 100) # Default to 100 lines if since or grep isn't set
|
lines = options[:lines].presence || ((since || grep) ? nil : 100) # Default to 100 lines if since or grep isn't set
|
||||||
|
|
||||||
on(hosts) do
|
on(hosts) do
|
||||||
puts capture_with_info(*accessory.logs(since: since, lines: lines, grep: grep, grep_options: grep_options))
|
puts capture_with_info(*accessory.logs(timestamps: timestamps, since: since, lines: lines, grep: grep, grep_options: grep_options))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -188,12 +188,14 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
option :grep, aliases: "-g", desc: "Show lines with grep match only (use this to fetch specific requests by id)"
|
option :grep, aliases: "-g", desc: "Show lines with grep match only (use this to fetch specific requests by id)"
|
||||||
option :grep_options, aliases: "-o", desc: "Additional options supplied to grep"
|
option :grep_options, aliases: "-o", desc: "Additional options supplied to grep"
|
||||||
option :follow, aliases: "-f", desc: "Follow log on primary server (or specific host set by --hosts)"
|
option :follow, aliases: "-f", desc: "Follow log on primary server (or specific host set by --hosts)"
|
||||||
|
option :skip_timestamps, type: :boolean, aliases: "-T", desc: "Skip appending timestamps to logging output"
|
||||||
def logs
|
def logs
|
||||||
# FIXME: Catch when app containers aren't running
|
# FIXME: Catch when app containers aren't running
|
||||||
|
|
||||||
grep = options[:grep]
|
grep = options[:grep]
|
||||||
grep_options = options[:grep_options]
|
grep_options = options[:grep_options]
|
||||||
since = options[:since]
|
since = options[:since]
|
||||||
|
timestamps = !options[:skip_timestamps]
|
||||||
|
|
||||||
if options[:follow]
|
if options[:follow]
|
||||||
lines = options[:lines].presence || ((since || grep) ? nil : 10) # Default to 10 lines if since or grep isn't set
|
lines = options[:lines].presence || ((since || grep) ? nil : 10) # Default to 10 lines if since or grep isn't set
|
||||||
@@ -205,8 +207,8 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
role = KAMAL.roles_on(KAMAL.primary_host).first
|
role = KAMAL.roles_on(KAMAL.primary_host).first
|
||||||
|
|
||||||
app = KAMAL.app(role: role, host: host)
|
app = KAMAL.app(role: role, host: host)
|
||||||
info app.follow_logs(host: KAMAL.primary_host, lines: lines, grep: grep, grep_options: grep_options)
|
info app.follow_logs(host: KAMAL.primary_host, timestamps: timestamps, lines: lines, grep: grep, grep_options: grep_options)
|
||||||
exec app.follow_logs(host: KAMAL.primary_host, lines: lines, grep: grep, grep_options: grep_options)
|
exec app.follow_logs(host: KAMAL.primary_host, timestamps: timestamps, lines: lines, grep: grep, grep_options: grep_options)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
lines = options[:lines].presence || ((since || grep) ? nil : 100) # Default to 100 lines if since or grep isn't set
|
lines = options[:lines].presence || ((since || grep) ? nil : 100) # Default to 100 lines if since or grep isn't set
|
||||||
@@ -216,7 +218,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
|
|
||||||
roles.each do |role|
|
roles.each do |role|
|
||||||
begin
|
begin
|
||||||
puts_by_host host, capture_with_info(*KAMAL.app(role: role, host: host).logs(since: since, lines: lines, grep: grep, grep_options: grep_options))
|
puts_by_host host, capture_with_info(*KAMAL.app(role: role, host: host).logs(timestamps: timestamps, since: since, lines: lines, grep: grep, grep_options: grep_options))
|
||||||
rescue SSHKit::Command::Failed
|
rescue SSHKit::Command::Failed
|
||||||
puts_by_host host, "Nothing found"
|
puts_by_host host, "Nothing found"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -135,8 +135,10 @@ module Kamal::Cli
|
|||||||
details = { hosts: KAMAL.hosts.join(","), command: command, subcommand: subcommand }
|
details = { hosts: KAMAL.hosts.join(","), command: command, subcommand: subcommand }
|
||||||
|
|
||||||
say "Running the #{hook} hook...", :magenta
|
say "Running the #{hook} hook...", :magenta
|
||||||
|
with_env KAMAL.hook.env(**details, **extra_details) do
|
||||||
run_locally do
|
run_locally do
|
||||||
execute *KAMAL.hook.run(hook, **details, **extra_details)
|
execute *KAMAL.hook.run(hook)
|
||||||
|
end
|
||||||
rescue SSHKit::Command::Failed => e
|
rescue SSHKit::Command::Failed => e
|
||||||
raise HookError.new("Hook `#{hook}` failed:\n#{e.message}")
|
raise HookError.new("Hook `#{hook}` failed:\n#{e.message}")
|
||||||
end
|
end
|
||||||
@@ -183,5 +185,14 @@ module Kamal::Cli
|
|||||||
execute(*KAMAL.server.ensure_run_directory)
|
execute(*KAMAL.server.ensure_run_directory)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def with_env(env)
|
||||||
|
current_env = ENV.to_h.dup
|
||||||
|
ENV.update(env)
|
||||||
|
yield
|
||||||
|
ensure
|
||||||
|
ENV.clear
|
||||||
|
ENV.update(current_env)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|||||||
say "Building with uncommitted changes:\n #{uncommitted_changes}", :yellow
|
say "Building with uncommitted changes:\n #{uncommitted_changes}", :yellow
|
||||||
end
|
end
|
||||||
|
|
||||||
|
with_env(KAMAL.config.builder.secrets) do
|
||||||
run_locally do
|
run_locally do
|
||||||
begin
|
begin
|
||||||
execute *KAMAL.builder.inspect_builder
|
execute *KAMAL.builder.inspect_builder
|
||||||
@@ -51,7 +52,8 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|||||||
push = KAMAL.builder.push
|
push = KAMAL.builder.push
|
||||||
|
|
||||||
KAMAL.with_verbosity(:debug) do
|
KAMAL.with_verbosity(:debug) do
|
||||||
Dir.chdir(KAMAL.config.builder.build_directory) { execute *push, env: KAMAL.config.builder.secrets }
|
Dir.chdir(KAMAL.config.builder.build_directory) { execute *push }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
run_hook "post-deploy", secrets: true, runtime: runtime.round
|
run_hook "post-deploy", secrets: true, runtime: runtime.round.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "redeploy", "Deploy app to servers without bootstrapping servers, starting kamal-proxy, pruning, and registry login"
|
desc "redeploy", "Deploy app to servers without bootstrapping servers, starting kamal-proxy, pruning, and registry login"
|
||||||
@@ -75,7 +75,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
run_hook "post-deploy", secrets: true, runtime: runtime.round
|
run_hook "post-deploy", secrets: true, runtime: runtime.round.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "rollback [VERSION]", "Rollback app to VERSION"
|
desc "rollback [VERSION]", "Rollback app to VERSION"
|
||||||
@@ -99,7 +99,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
run_hook "post-deploy", secrets: true, runtime: runtime.round if rolled_back
|
run_hook "post-deploy", secrets: true, runtime: runtime.round.to_s if rolled_back
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "details", "Show details about all containers"
|
desc "details", "Show details about all containers"
|
||||||
|
|||||||
@@ -21,6 +21,36 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
desc "boot_config <set|get|clear>", "Mange kamal-proxy boot configuration"
|
||||||
|
option :publish, type: :boolean, default: true, desc: "Publish the proxy ports on the host"
|
||||||
|
option :http_port, type: :numeric, default: Kamal::Configuration::PROXY_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 :docker_options, type: :array, default: [], desc: "Docker options to pass to the proxy container", banner: "option=value option2=value2"
|
||||||
|
def boot_config(subcommand)
|
||||||
|
case subcommand
|
||||||
|
when "set"
|
||||||
|
boot_options = [
|
||||||
|
*(KAMAL.config.proxy_publish_args(options[:http_port], options[:https_port]) if options[:publish]),
|
||||||
|
*options[:docker_options].map { |option| "--#{option}" }
|
||||||
|
]
|
||||||
|
|
||||||
|
on(KAMAL.proxy_hosts) do |host|
|
||||||
|
execute(*KAMAL.proxy.ensure_proxy_directory)
|
||||||
|
upload! StringIO.new(boot_options.join(" ")), KAMAL.config.proxy_options_file
|
||||||
|
end
|
||||||
|
when "get"
|
||||||
|
on(KAMAL.proxy_hosts) do |host|
|
||||||
|
puts "Host #{host}: #{capture_with_info(*KAMAL.proxy.get_boot_options)}"
|
||||||
|
end
|
||||||
|
when "reset"
|
||||||
|
on(KAMAL.proxy_hosts) do |host|
|
||||||
|
execute *KAMAL.proxy.reset_boot_options
|
||||||
|
end
|
||||||
|
else
|
||||||
|
raise ArgumentError, "Unknown boot_config subcommand #{subcommand}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
desc "reboot", "Reboot proxy on servers (stop container, remove container, start new container)"
|
desc "reboot", "Reboot proxy on servers (stop container, remove container, start new container)"
|
||||||
option :rolling, type: :boolean, default: false, desc: "Reboot proxy on hosts in sequence, rather than in parallel"
|
option :rolling, type: :boolean, default: false, desc: "Reboot proxy on hosts in sequence, rather than in parallel"
|
||||||
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
option :confirmed, aliases: "-y", type: :boolean, default: false, desc: "Proceed without confirmation question"
|
||||||
@@ -140,21 +170,23 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|||||||
option :lines, type: :numeric, aliases: "-n", desc: "Number of log lines to pull from each server"
|
option :lines, type: :numeric, aliases: "-n", desc: "Number of log lines to pull from each server"
|
||||||
option :grep, aliases: "-g", desc: "Show lines with grep match only (use this to fetch specific requests by id)"
|
option :grep, aliases: "-g", desc: "Show lines with grep match only (use this to fetch specific requests by id)"
|
||||||
option :follow, aliases: "-f", desc: "Follow logs on primary server (or specific host set by --hosts)"
|
option :follow, aliases: "-f", desc: "Follow logs on primary server (or specific host set by --hosts)"
|
||||||
|
option :skip_timestamps, type: :boolean, aliases: "-T", desc: "Skip appending timestamps to logging output"
|
||||||
def logs
|
def logs
|
||||||
grep = options[:grep]
|
grep = options[:grep]
|
||||||
|
timestamps = !options[:skip_timestamps]
|
||||||
|
|
||||||
if options[:follow]
|
if options[:follow]
|
||||||
run_locally do
|
run_locally do
|
||||||
info "Following logs on #{KAMAL.primary_host}..."
|
info "Following logs on #{KAMAL.primary_host}..."
|
||||||
info KAMAL.proxy.follow_logs(host: KAMAL.primary_host, grep: grep)
|
info KAMAL.proxy.follow_logs(host: KAMAL.primary_host, timestamps: timestamps, grep: grep)
|
||||||
exec KAMAL.proxy.follow_logs(host: KAMAL.primary_host, grep: grep)
|
exec KAMAL.proxy.follow_logs(host: KAMAL.primary_host, timestamps: timestamps, grep: grep)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
since = options[:since]
|
since = options[:since]
|
||||||
lines = options[:lines].presence || ((since || grep) ? nil : 100) # Default to 100 lines if since or grep isn't set
|
lines = options[:lines].presence || ((since || grep) ? nil : 100) # Default to 100 lines if since or grep isn't set
|
||||||
|
|
||||||
on(KAMAL.proxy_hosts) do |host|
|
on(KAMAL.proxy_hosts) do |host|
|
||||||
puts_by_host host, capture(*KAMAL.proxy.logs(since: since, lines: lines, grep: grep)), type: "Proxy"
|
puts_by_host host, capture(*KAMAL.proxy.logs(timestamps: timestamps, since: since, lines: lines, grep: grep)), type: "Proxy"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -167,7 +199,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|||||||
stop
|
stop
|
||||||
remove_container
|
remove_container
|
||||||
remove_image
|
remove_image
|
||||||
remove_host_directory
|
remove_proxy_directory
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -192,12 +224,11 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "remove_host_directory", "Remove proxy directory from servers", hide: true
|
desc "remove_proxy_directory", "Remove the proxy directory from servers", hide: true
|
||||||
def remove_host_directory
|
def remove_proxy_directory
|
||||||
with_lock do
|
with_lock do
|
||||||
on(KAMAL.proxy_hosts) do
|
on(KAMAL.proxy_hosts) do
|
||||||
execute *KAMAL.auditor.record("Removed #{KAMAL.config.proxy_directory}"), verbosity: :debug
|
execute *KAMAL.proxy.remove_proxy_directory, raise_on_non_zero_exit: false
|
||||||
execute *KAMAL.proxy.remove_host_directory, raise_on_non_zero_exit: false
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,11 +2,22 @@
|
|||||||
service: my-app
|
service: my-app
|
||||||
|
|
||||||
# Name of the container image.
|
# Name of the container image.
|
||||||
image: user/my-app
|
image: my-user/my-app
|
||||||
|
|
||||||
# Deploy to these servers.
|
# Deploy to these servers.
|
||||||
servers:
|
servers:
|
||||||
|
web:
|
||||||
- 192.168.0.1
|
- 192.168.0.1
|
||||||
|
# job:
|
||||||
|
# hosts:
|
||||||
|
# - 192.168.0.1
|
||||||
|
# cmd: bin/jobs
|
||||||
|
|
||||||
|
# Enable SSL auto certification via Let's Encrypt (and allow for multiple apps on one server).
|
||||||
|
# Set ssl: false if using something like Cloudflare to terminate SSL (but keep host!).
|
||||||
|
proxy:
|
||||||
|
ssl: true
|
||||||
|
host: app.example.com
|
||||||
|
|
||||||
# Credentials for your image host.
|
# Credentials for your image host.
|
||||||
registry:
|
registry:
|
||||||
@@ -14,7 +25,7 @@ registry:
|
|||||||
# server: registry.digitalocean.com / ghcr.io / ...
|
# server: registry.digitalocean.com / ghcr.io / ...
|
||||||
username: my-user
|
username: my-user
|
||||||
|
|
||||||
# Always use an access token rather than real password when possible.
|
# Always use an access token rather than real password (pulled from .kamal/secrets).
|
||||||
password:
|
password:
|
||||||
- KAMAL_REGISTRY_PASSWORD
|
- KAMAL_REGISTRY_PASSWORD
|
||||||
|
|
||||||
@@ -22,19 +33,44 @@ registry:
|
|||||||
builder:
|
builder:
|
||||||
arch: amd64
|
arch: amd64
|
||||||
|
|
||||||
# Inject ENV variables into containers (secrets come from .env).
|
# Inject ENV variables into containers (secrets come from .kamal/secrets).
|
||||||
# Remember to run `kamal env push` after making changes!
|
#
|
||||||
# env:
|
# env:
|
||||||
# clear:
|
# clear:
|
||||||
# DB_HOST: 192.168.0.2
|
# DB_HOST: 192.168.0.2
|
||||||
# secret:
|
# secret:
|
||||||
# - RAILS_MASTER_KEY
|
# - RAILS_MASTER_KEY
|
||||||
|
|
||||||
|
# Aliases are triggered with "bin/kamal <alias>". You can overwrite arguments on invocation:
|
||||||
|
# "bin/kamal logs -r job" will tail logs from the first server in the job section.
|
||||||
|
#
|
||||||
|
# aliases:
|
||||||
|
# shell: app exec --interactive --reuse "bash"
|
||||||
|
|
||||||
# Use a different ssh user than root
|
# Use a different ssh user than root
|
||||||
|
#
|
||||||
# ssh:
|
# ssh:
|
||||||
# user: app
|
# user: app
|
||||||
|
|
||||||
# Use accessory services (secrets come from .env).
|
# Use a persistent storage volume.
|
||||||
|
#
|
||||||
|
# volumes:
|
||||||
|
# - "app_storage:/app/storage"
|
||||||
|
|
||||||
|
# Bridge fingerprinted assets, like JS and CSS, between versions to avoid
|
||||||
|
# hitting 404 on in-flight requests. Combines all files from new and old
|
||||||
|
# version inside the asset_path.
|
||||||
|
#
|
||||||
|
# asset_path: /app/public/assets
|
||||||
|
|
||||||
|
# Configure rolling deploys by setting a wait time between batches of restarts.
|
||||||
|
#
|
||||||
|
# boot:
|
||||||
|
# limit: 10 # Can also specify as a percentage of total hosts, such as "25%"
|
||||||
|
# wait: 2
|
||||||
|
|
||||||
|
# Use accessory services (secrets come from .kamal/secrets).
|
||||||
|
#
|
||||||
# accessories:
|
# accessories:
|
||||||
# db:
|
# db:
|
||||||
# image: mysql:8.0
|
# image: mysql:8.0
|
||||||
@@ -56,29 +92,3 @@ builder:
|
|||||||
# port: 6379
|
# port: 6379
|
||||||
# directories:
|
# directories:
|
||||||
# - data:/data
|
# - data:/data
|
||||||
|
|
||||||
# Bridge fingerprinted assets, like JS and CSS, between versions to avoid
|
|
||||||
# hitting 404 on in-flight requests. Combines all files from new and old
|
|
||||||
# version inside the asset_path.
|
|
||||||
#
|
|
||||||
# If your app is using the Sprockets gem, ensure it sets `config.assets.manifest`.
|
|
||||||
# See https://github.com/basecamp/kamal/issues/626 for details
|
|
||||||
#
|
|
||||||
# asset_path: /rails/public/assets
|
|
||||||
|
|
||||||
# Configure rolling deploys by setting a wait time between batches of restarts.
|
|
||||||
# boot:
|
|
||||||
# limit: 10 # Can also specify as a percentage of total hosts, such as "25%"
|
|
||||||
# wait: 2
|
|
||||||
|
|
||||||
# Configure the role used to determine the primary_host. This host takes
|
|
||||||
# deploy locks, runs health checks during the deploy, and follow logs, etc.
|
|
||||||
#
|
|
||||||
# Caution: there's no support for role renaming yet, so be careful to cleanup
|
|
||||||
# the previous role on the deployed hosts.
|
|
||||||
# primary_role: web
|
|
||||||
|
|
||||||
# Controls if we abort when see a role with no hosts. Disabling this may be
|
|
||||||
# useful for more complex deploy configurations.
|
|
||||||
#
|
|
||||||
# allow_empty_roles: false
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
echo "Rebooting Traefik on $KAMAL_HOSTS..."
|
echo "Rebooting kamal-proxy on $KAMAL_HOSTS..."
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
# WARNING: Avoid adding secrets directly to this file
|
# Secrets defined here are available for reference under registry/password, env/secret, builder/secrets,
|
||||||
# If you must, then add `.kamal/secrets*` to your .gitignore file
|
# and accessories/*/env/secret in config/deploy.yml. All secrets should be pulled from either
|
||||||
|
# password manager, ENV, or a file. DO NOT ENTER RAW CREDENTIALS HERE! This file needs to be safe for git.
|
||||||
|
|
||||||
# Option 1: Read secrets from the environment
|
# Option 1: Read secrets from the environment
|
||||||
KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
|
KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD
|
||||||
|
|||||||
@@ -39,16 +39,16 @@ class Kamal::Commands::Accessory < Kamal::Commands::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def logs(since: nil, lines: nil, grep: nil, grep_options: nil)
|
def logs(timestamps: true, since: nil, lines: nil, grep: nil, grep_options: nil)
|
||||||
pipe \
|
pipe \
|
||||||
docker(:logs, service_name, (" --since #{since}" if since), (" --tail #{lines}" if lines), "--timestamps", "2>&1"),
|
docker(:logs, service_name, (" --since #{since}" if since), (" --tail #{lines}" if lines), ("--timestamps" if timestamps), "2>&1"),
|
||||||
("grep '#{grep}'#{" #{grep_options}" if grep_options}" if grep)
|
("grep '#{grep}'#{" #{grep_options}" if grep_options}" if grep)
|
||||||
end
|
end
|
||||||
|
|
||||||
def follow_logs(grep: nil, grep_options: nil)
|
def follow_logs(timestamps: true, grep: nil, grep_options: nil)
|
||||||
run_over_ssh \
|
run_over_ssh \
|
||||||
pipe \
|
pipe \
|
||||||
docker(:logs, service_name, "--timestamps", "--tail", "10", "--follow", "2>&1"),
|
docker(:logs, service_name, ("--timestamps" if timestamps), "--tail", "10", "--follow", "2>&1"),
|
||||||
(%(grep "#{grep}"#{" #{grep_options}" if grep_options}) if grep)
|
(%(grep "#{grep}"#{" #{grep_options}" if grep_options}) if grep)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ module Kamal::Commands::App::Execution
|
|||||||
docker :run,
|
docker :run,
|
||||||
("-it" if interactive),
|
("-it" if interactive),
|
||||||
"--rm",
|
"--rm",
|
||||||
|
"--network", "kamal",
|
||||||
*role&.env_args(host),
|
*role&.env_args(host),
|
||||||
*argumentize("--env", env),
|
*argumentize("--env", env),
|
||||||
*config.volume_args,
|
*config.volume_args,
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
module Kamal::Commands::App::Logging
|
module Kamal::Commands::App::Logging
|
||||||
def logs(version: nil, since: nil, lines: nil, grep: nil, grep_options: nil)
|
def logs(version: nil, timestamps: true, since: nil, lines: nil, grep: nil, grep_options: nil)
|
||||||
pipe \
|
pipe \
|
||||||
version ? container_id_for_version(version) : current_running_container_id,
|
version ? container_id_for_version(version) : current_running_container_id,
|
||||||
"xargs docker logs#{" --since #{since}" if since}#{" --tail #{lines}" if lines} 2>&1",
|
"xargs docker logs#{" --timestamps" if timestamps}#{" --since #{since}" if since}#{" --tail #{lines}" if lines} 2>&1",
|
||||||
("grep '#{grep}'#{" #{grep_options}" if grep_options}" if grep)
|
("grep '#{grep}'#{" #{grep_options}" if grep_options}" if grep)
|
||||||
end
|
end
|
||||||
|
|
||||||
def follow_logs(host:, lines: nil, grep: nil, grep_options: nil)
|
def follow_logs(host:, timestamps: true, lines: nil, grep: nil, grep_options: nil)
|
||||||
run_over_ssh \
|
run_over_ssh \
|
||||||
pipe(
|
pipe(
|
||||||
current_running_container_id,
|
current_running_container_id,
|
||||||
"xargs docker logs --timestamps#{" --tail #{lines}" if lines} --follow 2>&1",
|
"xargs docker logs#{" --timestamps" if timestamps}#{" --tail #{lines}" if lines} --follow 2>&1",
|
||||||
(%(grep "#{grep}"#{" #{grep_options}" if grep_options}) if grep)
|
(%(grep "#{grep}"#{" #{grep_options}" if grep_options}) if grep)
|
||||||
),
|
),
|
||||||
host: host
|
host: host
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
class Kamal::Commands::Hook < Kamal::Commands::Base
|
class Kamal::Commands::Hook < Kamal::Commands::Base
|
||||||
def run(hook, secrets: false, **details)
|
def run(hook)
|
||||||
env = tags(**details).env
|
[ hook_file(hook) ]
|
||||||
env.merge!(config.secrets.to_h) if secrets
|
end
|
||||||
|
|
||||||
[ hook_file(hook), env: env ]
|
def env(secrets: false, **details)
|
||||||
|
tags(**details).env.tap do |env|
|
||||||
|
env.merge!(config.secrets.to_h) if secrets
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def hook_exists?(hook)
|
def hook_exists?(hook)
|
||||||
|
|||||||
@@ -7,10 +7,8 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base
|
|||||||
"--network", "kamal",
|
"--network", "kamal",
|
||||||
"--detach",
|
"--detach",
|
||||||
"--restart", "unless-stopped",
|
"--restart", "unless-stopped",
|
||||||
*config.proxy_publish_args,
|
"--volume", "kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy",
|
||||||
"--volume", "/var/run/docker.sock:/var/run/docker.sock",
|
"\$\(#{get_boot_options.join(" ")}\)",
|
||||||
*config.proxy_config_volume.docker_args,
|
|
||||||
*config.logging_args,
|
|
||||||
config.proxy_image
|
config.proxy_image
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -36,15 +34,15 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base
|
|||||||
[ :cut, "-d:", "-f2" ]
|
[ :cut, "-d:", "-f2" ]
|
||||||
end
|
end
|
||||||
|
|
||||||
def logs(since: nil, lines: nil, grep: nil, grep_options: nil)
|
def logs(timestamps: true, since: nil, lines: nil, grep: nil, grep_options: nil)
|
||||||
pipe \
|
pipe \
|
||||||
docker(:logs, container_name, (" --since #{since}" if since), (" --tail #{lines}" if lines), "--timestamps", "2>&1"),
|
docker(:logs, container_name, ("--since #{since}" if since), ("--tail #{lines}" if lines), ("--timestamps" if timestamps), "2>&1"),
|
||||||
("grep '#{grep}'#{" #{grep_options}" if grep_options}" if grep)
|
("grep '#{grep}'#{" #{grep_options}" if grep_options}" if grep)
|
||||||
end
|
end
|
||||||
|
|
||||||
def follow_logs(host:, grep: nil, grep_options: nil)
|
def follow_logs(host:, timestamps: true, grep: nil, grep_options: nil)
|
||||||
run_over_ssh pipe(
|
run_over_ssh pipe(
|
||||||
docker(:logs, container_name, "--timestamps", "--tail", "10", "--follow", "2>&1"),
|
docker(:logs, container_name, ("--timestamps" if timestamps), "--tail", "10", "--follow", "2>&1"),
|
||||||
(%(grep "#{grep}"#{" #{grep_options}" if grep_options}) if grep)
|
(%(grep "#{grep}"#{" #{grep_options}" if grep_options}) if grep)
|
||||||
).join(" "), host: host
|
).join(" "), host: host
|
||||||
end
|
end
|
||||||
@@ -57,10 +55,6 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base
|
|||||||
docker :image, :prune, "--all", "--force", "--filter", "label=org.opencontainers.image.title=kamal-proxy"
|
docker :image, :prune, "--all", "--force", "--filter", "label=org.opencontainers.image.title=kamal-proxy"
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_host_directory
|
|
||||||
remove_directory config.proxy_directory
|
|
||||||
end
|
|
||||||
|
|
||||||
def cleanup_traefik
|
def cleanup_traefik
|
||||||
chain \
|
chain \
|
||||||
docker(:container, :stop, "traefik"),
|
docker(:container, :stop, "traefik"),
|
||||||
@@ -70,6 +64,22 @@ class Kamal::Commands::Proxy < Kamal::Commands::Base
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def ensure_proxy_directory
|
||||||
|
make_directory config.proxy_directory
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove_proxy_directory
|
||||||
|
remove_directory config.proxy_directory
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_boot_options
|
||||||
|
combine [ :cat, config.proxy_options_file ], [ :echo, "\"#{config.proxy_options_default.join(" ")}\"" ], by: "||"
|
||||||
|
end
|
||||||
|
|
||||||
|
def reset_boot_options
|
||||||
|
remove_file config.proxy_options_file
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def container_name
|
def container_name
|
||||||
config.proxy_container_name
|
config.proxy_container_name
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class Kamal::Configuration
|
|||||||
|
|
||||||
include Validation
|
include Validation
|
||||||
|
|
||||||
PROXY_MINIMUM_VERSION = "v0.3.0"
|
PROXY_MINIMUM_VERSION = "v0.6.0"
|
||||||
PROXY_HTTP_PORT = 80
|
PROXY_HTTP_PORT = 80
|
||||||
PROXY_HTTPS_PORT = 443
|
PROXY_HTTPS_PORT = 443
|
||||||
|
|
||||||
@@ -216,10 +216,6 @@ class Kamal::Configuration
|
|||||||
File.join apps_directory, [ service, destination ].compact.join("-")
|
File.join apps_directory, [ service, destination ].compact.join("-")
|
||||||
end
|
end
|
||||||
|
|
||||||
def proxy_directory
|
|
||||||
File.join run_directory, "proxy"
|
|
||||||
end
|
|
||||||
|
|
||||||
def env_directory
|
def env_directory
|
||||||
File.join app_directory, "env"
|
File.join app_directory, "env"
|
||||||
end
|
end
|
||||||
@@ -250,8 +246,12 @@ 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
|
def proxy_publish_args(http_port, https_port)
|
||||||
argumentize "--publish", [ "#{PROXY_HTTP_PORT}:#{PROXY_HTTP_PORT}", "#{PROXY_HTTPS_PORT}:#{PROXY_HTTPS_PORT}" ]
|
argumentize "--publish", [ "#{http_port}:#{PROXY_HTTP_PORT}", "#{https_port}:#{PROXY_HTTPS_PORT}" ]
|
||||||
|
end
|
||||||
|
|
||||||
|
def proxy_options_default
|
||||||
|
proxy_publish_args PROXY_HTTP_PORT, PROXY_HTTPS_PORT
|
||||||
end
|
end
|
||||||
|
|
||||||
def proxy_image
|
def proxy_image
|
||||||
@@ -262,10 +262,12 @@ class Kamal::Configuration
|
|||||||
"kamal-proxy"
|
"kamal-proxy"
|
||||||
end
|
end
|
||||||
|
|
||||||
def proxy_config_volume
|
def proxy_directory
|
||||||
Kamal::Configuration::Volume.new \
|
File.join run_directory, "proxy"
|
||||||
host_path: File.join(proxy_directory, "config"),
|
end
|
||||||
container_path: "/home/kamal-proxy/.config/kamal-proxy"
|
|
||||||
|
def proxy_options_file
|
||||||
|
File.join proxy_directory, "options"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,10 +2,6 @@
|
|||||||
#
|
#
|
||||||
# The builder configuration controls how the application is built with `docker build`
|
# The builder configuration controls how the application is built with `docker build`
|
||||||
#
|
#
|
||||||
# If no configuration is specified, Kamal will:
|
|
||||||
# 1. Create a buildx context called `kamal-local-docker-container`, using the docker-container driver
|
|
||||||
# 2. Use `docker build` to build a multiarch image for linux/amd64,linux/arm64 with that context
|
|
||||||
#
|
|
||||||
# See https://kamal-deploy.org/docs/configuration/builder-examples/ for more information
|
# See https://kamal-deploy.org/docs/configuration/builder-examples/ for more information
|
||||||
|
|
||||||
# Builder options
|
# Builder options
|
||||||
@@ -78,7 +74,7 @@ builder:
|
|||||||
|
|
||||||
# Build secrets
|
# Build secrets
|
||||||
#
|
#
|
||||||
# Values are read from the .kamal/secrets.
|
# Values are read from .kamal/secrets.
|
||||||
#
|
#
|
||||||
secrets:
|
secrets:
|
||||||
- SECRET1
|
- SECRET1
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ image: my-image
|
|||||||
labels:
|
labels:
|
||||||
my-label: my-value
|
my-label: my-value
|
||||||
|
|
||||||
|
# Volumes
|
||||||
|
#
|
||||||
# Additional volumes to mount into the container
|
# Additional volumes to mount into the container
|
||||||
volumes:
|
volumes:
|
||||||
- /path/on/host:/path/in/container:ro
|
- /path/on/host:/path/in/container:ro
|
||||||
@@ -58,7 +60,7 @@ servers:
|
|||||||
env:
|
env:
|
||||||
...
|
...
|
||||||
|
|
||||||
# Asset Bridging
|
# Asset Path
|
||||||
#
|
#
|
||||||
# Used for asset bridging across deployments, default to `nil`
|
# Used for asset bridging across deployments, default to `nil`
|
||||||
#
|
#
|
||||||
@@ -74,6 +76,8 @@ env:
|
|||||||
# To configure this, set the path to the assets:
|
# To configure this, set the path to the assets:
|
||||||
asset_path: /path/to/assets
|
asset_path: /path/to/assets
|
||||||
|
|
||||||
|
# Hooks path
|
||||||
|
#
|
||||||
# Path to hooks, defaults to `.kamal/hooks`
|
# Path to hooks, defaults to `.kamal/hooks`
|
||||||
# See https://kamal-deploy.org/docs/hooks for more information
|
# See https://kamal-deploy.org/docs/hooks for more information
|
||||||
hooks_path: /user_home/kamal/hooks
|
hooks_path: /user_home/kamal/hooks
|
||||||
@@ -83,7 +87,7 @@ hooks_path: /user_home/kamal/hooks
|
|||||||
# Whether deployments require a destination to be specified, defaults to `false`
|
# Whether deployments require a destination to be specified, defaults to `false`
|
||||||
require_destination: true
|
require_destination: true
|
||||||
|
|
||||||
# The primary role
|
# Primary role
|
||||||
#
|
#
|
||||||
# This defaults to `web`, but if you have no web role, you can change this
|
# This defaults to `web`, but if you have no web role, you can change this
|
||||||
primary_role: workers
|
primary_role: workers
|
||||||
|
|||||||
@@ -12,11 +12,16 @@ env:
|
|||||||
DATABASE_HOST: mysql-db1
|
DATABASE_HOST: mysql-db1
|
||||||
DATABASE_PORT: 3306
|
DATABASE_PORT: 3306
|
||||||
|
|
||||||
# Using .kamal/secrets file to load required environment variables
|
# Secrets
|
||||||
#
|
#
|
||||||
# Kamal uses dotenv to automatically load environment variables set in the .kamal/secrets file.
|
# Kamal uses dotenv to automatically load environment variables set in the `.kamal/secrets` file.
|
||||||
#
|
#
|
||||||
# This file can be used to set variables like KAMAL_REGISTRY_PASSWORD or database passwords.
|
# If you are using destinations, secrets will instead be read from `.kamal/secrets-<DESTINATION>` if
|
||||||
|
# it exists.
|
||||||
|
#
|
||||||
|
# Common secrets across all destinations can be set in `.kamal/secrets-common`.
|
||||||
|
#
|
||||||
|
# This file can be used to set variables like `KAMAL_REGISTRY_PASSWORD` or database passwords.
|
||||||
# You can use variable or command substitution in the secrets file.
|
# You can use variable or command substitution in the secrets file.
|
||||||
#
|
#
|
||||||
# ```
|
# ```
|
||||||
@@ -24,6 +29,14 @@ env:
|
|||||||
# RAILS_MASTER_KEY=$(cat config/master.key)
|
# RAILS_MASTER_KEY=$(cat config/master.key)
|
||||||
# ```
|
# ```
|
||||||
#
|
#
|
||||||
|
# You can also use [secret helpers](../commands/secrets) for some common password managers.
|
||||||
|
# ```
|
||||||
|
# SECRETS=$(kamal secrets fetch ...)
|
||||||
|
#
|
||||||
|
# REGISTRY_PASSWORD=$(kamal secrets extract REGISTRY_PASSWORD $SECRETS)
|
||||||
|
# DB_PASSWORD=$(kamal secrets extract DB_PASSWORD $SECRETS)
|
||||||
|
# ```
|
||||||
|
#
|
||||||
# If you store secrets directly in .kamal/secrets, ensure that it is not checked into version control.
|
# If you store secrets directly in .kamal/secrets, ensure that it is not checked into version control.
|
||||||
#
|
#
|
||||||
# To pass the secrets you should list them under the `secret` key. When you do this the
|
# To pass the secrets you should list them under the `secret` key. When you do this the
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ proxy:
|
|||||||
# Response timeout
|
# Response timeout
|
||||||
#
|
#
|
||||||
# How long to wait for requests to complete before timing out, defaults to 30 seconds
|
# How long to wait for requests to complete before timing out, defaults to 30 seconds
|
||||||
response_timeout: 10s
|
response_timeout: 10
|
||||||
|
|
||||||
# Healthcheck
|
# Healthcheck
|
||||||
#
|
#
|
||||||
@@ -91,7 +91,7 @@ proxy:
|
|||||||
|
|
||||||
# Forward headers
|
# Forward headers
|
||||||
#
|
#
|
||||||
# Whether to forward the X-Forwarded-For and X-Forwarded-Proto headers (defaults to false)
|
# Whether to forward the X-Forwarded-For and X-Forwarded-Proto headers.
|
||||||
#
|
#
|
||||||
# If you are behind a trusted proxy, you can set this to true to forward the headers.
|
# If you are behind a trusted proxy, you can set this to true to forward the headers.
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -26,8 +26,12 @@ servers:
|
|||||||
#
|
#
|
||||||
# When there are other options to set, the list of hosts goes under the `hosts` key
|
# When there are other options to set, the list of hosts goes under the `hosts` key
|
||||||
#
|
#
|
||||||
# By default only the primary role uses a proxy, but you can set `proxy` to change
|
# By default only the primary role uses a proxy.
|
||||||
# it.
|
#
|
||||||
|
# For other roles, you can set it to `proxy: true` enable it and inherit the root proxy
|
||||||
|
# configuration or provide a map of options to override the root configuration.
|
||||||
|
#
|
||||||
|
# For the primary role, you can set `proxy: false` to disable the proxy.
|
||||||
#
|
#
|
||||||
# You can also set a custom cmd to run in the container, and overwrite other settings
|
# You can also set a custom cmd to run in the container, and overwrite other settings
|
||||||
# from the root configuration.
|
# from the root configuration.
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class Kamal::Configuration::Proxy
|
|||||||
def deploy_options
|
def deploy_options
|
||||||
{
|
{
|
||||||
host: proxy_config["host"],
|
host: proxy_config["host"],
|
||||||
tls: proxy_config["ssl"],
|
tls: proxy_config["ssl"] ? true : nil,
|
||||||
"deploy-timeout": seconds_duration(config.deploy_timeout),
|
"deploy-timeout": seconds_duration(config.deploy_timeout),
|
||||||
"drain-timeout": seconds_duration(config.drain_timeout),
|
"drain-timeout": seconds_duration(config.drain_timeout),
|
||||||
"health-check-interval": seconds_duration(proxy_config.dig("healthcheck", "interval")),
|
"health-check-interval": seconds_duration(proxy_config.dig("healthcheck", "interval")),
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ class Kamal::Secrets::Adapters::LastPass < Kamal::Secrets::Adapters::Base
|
|||||||
def login(account)
|
def login(account)
|
||||||
unless loggedin?(account)
|
unless loggedin?(account)
|
||||||
`lpass login #{account.shellescape}`
|
`lpass login #{account.shellescape}`
|
||||||
raise RuntimeError, "Failed to login to 1Password" unless $?.success?
|
raise RuntimeError, "Failed to login to LastPass" unless $?.success?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ class Kamal::Secrets::Adapters::LastPass < Kamal::Secrets::Adapters::Base
|
|||||||
|
|
||||||
def fetch_secrets(secrets, account:, session:)
|
def fetch_secrets(secrets, account:, session:)
|
||||||
items = `lpass show #{secrets.map(&:shellescape).join(" ")} --json`
|
items = `lpass show #{secrets.map(&:shellescape).join(" ")} --json`
|
||||||
raise RuntimeError, "Could not read #{secrets} from 1Password" unless $?.success?
|
raise RuntimeError, "Could not read #{secrets} from LastPass" unless $?.success?
|
||||||
|
|
||||||
items = JSON.parse(items)
|
items = JSON.parse(items)
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module Kamal
|
module Kamal
|
||||||
VERSION = "2.0.0.beta1"
|
VERSION = "2.0.0"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class CliAccessoryTest < CliTestCase
|
|||||||
test "upload" do
|
test "upload" do
|
||||||
run_command("upload", "mysql").tap do |output|
|
run_command("upload", "mysql").tap do |output|
|
||||||
assert_match "mkdir -p app-mysql/etc/mysql", output
|
assert_match "mkdir -p app-mysql/etc/mysql", output
|
||||||
assert_match "test/fixtures/files/my.cnf app-mysql/etc/mysql/my.cnf", output
|
assert_match "test/fixtures/files/my.cnf to app-mysql/etc/mysql/my.cnf", output
|
||||||
assert_match "chmod 755 app-mysql/etc/mysql/my.cnf", output
|
assert_match "chmod 755 app-mysql/etc/mysql/my.cnf", output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -263,13 +263,13 @@ class CliAppTest < CliTestCase
|
|||||||
|
|
||||||
test "exec" do
|
test "exec" do
|
||||||
run_command("exec", "ruby -v").tap do |output|
|
run_command("exec", "ruby -v").tap do |output|
|
||||||
assert_match "docker run --rm --env-file .kamal/apps/app/env/roles/web.env dhh/app:latest ruby -v", output
|
assert_match "docker run --rm --network kamal --env-file .kamal/apps/app/env/roles/web.env dhh/app:latest ruby -v", output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "exec separate arguments" do
|
test "exec separate arguments" do
|
||||||
run_command("exec", "ruby", " -v").tap do |output|
|
run_command("exec", "ruby", " -v").tap do |output|
|
||||||
assert_match "docker run --rm --env-file .kamal/apps/app/env/roles/web.env dhh/app:latest ruby -v", output
|
assert_match "docker run --rm --network kamal --env-file .kamal/apps/app/env/roles/web.env dhh/app:latest ruby -v", output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -282,7 +282,7 @@ class CliAppTest < CliTestCase
|
|||||||
|
|
||||||
test "exec interactive" do
|
test "exec interactive" do
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:exec)
|
SSHKit::Backend::Abstract.any_instance.expects(:exec)
|
||||||
.with("ssh -t root@1.1.1.1 -p 22 'docker run -it --rm --env-file .kamal/apps/app/env/roles/web.env dhh/app:latest ruby -v'")
|
.with("ssh -t root@1.1.1.1 -p 22 'docker run -it --rm --network kamal --env-file .kamal/apps/app/env/roles/web.env dhh/app:latest ruby -v'")
|
||||||
run_command("exec", "-i", "ruby -v").tap do |output|
|
run_command("exec", "-i", "ruby -v").tap do |output|
|
||||||
assert_match "Get most recent version available as an image...", output
|
assert_match "Get most recent version available as an image...", output
|
||||||
assert_match "Launching interactive command with version latest via SSH from new container on 1.1.1.1...", output
|
assert_match "Launching interactive command with version latest via SSH from new container on 1.1.1.1...", output
|
||||||
@@ -315,11 +315,11 @@ class CliAppTest < CliTestCase
|
|||||||
SSHKit::Backend::Abstract.any_instance.stubs(:exec)
|
SSHKit::Backend::Abstract.any_instance.stubs(:exec)
|
||||||
.with("ssh -t root@1.1.1.1 'sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1| xargs docker logs --timestamps --tail 10 2>&1'")
|
.with("ssh -t root@1.1.1.1 'sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1| xargs docker logs --timestamps --tail 10 2>&1'")
|
||||||
|
|
||||||
assert_match "sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs --tail 100 2>&1", run_command("logs")
|
assert_match "sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs --timestamps --tail 100 2>&1", run_command("logs")
|
||||||
|
|
||||||
assert_match "sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs 2>&1 | grep 'hey'", run_command("logs", "--grep", "hey")
|
assert_match "sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs --timestamps 2>&1 | grep 'hey'", run_command("logs", "--grep", "hey")
|
||||||
|
|
||||||
assert_match "sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs 2>&1 | grep 'hey' -C 2", run_command("logs", "--grep", "hey", "--grep-options", "-C 2")
|
assert_match "sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs --timestamps 2>&1 | grep 'hey' -C 2", run_command("logs", "--grep", "hey", "--grep-options", "-C 2")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "logs with follow" do
|
test "logs with follow" do
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class CliBuildTest < CliTestCase
|
|||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:git, "-C", build_directory, :submodule, :update, "--init")
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:git, "-C", build_directory, :submodule, :update, "--init")
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute)
|
SSHKit::Backend::Abstract.any_instance.expects(:execute)
|
||||||
.with(:docker, :buildx, :build, "--push", "--platform", "linux/amd64", "--builder", "kamal-local-docker-container", "-t", "dhh/app:999", "-t", "dhh/app:latest", "--label", "service=\"app\"", "--file", "Dockerfile", ".", env: {})
|
.with(:docker, :buildx, :build, "--push", "--platform", "linux/amd64", "--builder", "kamal-local-docker-container", "-t", "dhh/app:999", "-t", "dhh/app:latest", "--label", "service=\"app\"", "--file", "Dockerfile", ".")
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
|
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
|
||||||
.with(:git, "-C", anything, :"rev-parse", :HEAD)
|
.with(:git, "-C", anything, :"rev-parse", :HEAD)
|
||||||
@@ -140,7 +140,7 @@ class CliBuildTest < CliTestCase
|
|||||||
.returns("")
|
.returns("")
|
||||||
|
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute)
|
SSHKit::Backend::Abstract.any_instance.expects(:execute)
|
||||||
.with(:docker, :buildx, :build, "--push", "--platform", "linux/amd64", "--builder", "kamal-local-docker-container", "-t", "dhh/app:999", "-t", "dhh/app:latest", "--label", "service=\"app\"", "--file", "Dockerfile", ".", env: {})
|
.with(:docker, :buildx, :build, "--push", "--platform", "linux/amd64", "--builder", "kamal-local-docker-container", "-t", "dhh/app:999", "-t", "dhh/app:latest", "--label", "service=\"app\"", "--file", "Dockerfile", ".")
|
||||||
|
|
||||||
run_command("push").tap do |output|
|
run_command("push").tap do |output|
|
||||||
assert_match /WARN Missing compatible builder, so creating a new one first/, output
|
assert_match /WARN Missing compatible builder, so creating a new one first/, output
|
||||||
|
|||||||
@@ -41,27 +41,7 @@ class CliTestCase < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def assert_hook_ran(hook, output, version:, service_version:, hosts:, command:, subcommand: nil, runtime: false, secrets: false)
|
def assert_hook_ran(hook, output, version:, service_version:, hosts:, command:, subcommand: nil, runtime: false, secrets: false)
|
||||||
whoami = `whoami`.chomp
|
assert_match %r{usr/bin/env\s\.kamal/hooks/#{hook}}, output
|
||||||
performer = Kamal::Git.email.presence || whoami
|
|
||||||
service = service_version.split("@").first
|
|
||||||
|
|
||||||
assert_match "Running the #{hook} hook...\n", output
|
|
||||||
|
|
||||||
expected = %r{Running\s/usr/bin/env\s\.kamal/hooks/#{hook}\sas\s#{whoami}@localhost\n\s
|
|
||||||
DEBUG\s\[[0-9a-f]*\]\sCommand:\s\(\sexport\s
|
|
||||||
KAMAL_RECORDED_AT=\"\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ\"\s
|
|
||||||
KAMAL_PERFORMER=\"#{performer}\"\s
|
|
||||||
KAMAL_VERSION=\"#{version}\"\s
|
|
||||||
KAMAL_SERVICE_VERSION=\"#{service_version}\"\s
|
|
||||||
KAMAL_SERVICE=\"#{service}\"\s
|
|
||||||
KAMAL_HOSTS=\"#{hosts}\"\s
|
|
||||||
KAMAL_COMMAND=\"#{command}\"\s
|
|
||||||
#{"KAMAL_SUBCOMMAND=\\\"#{subcommand}\\\"\\s" if subcommand}
|
|
||||||
#{"KAMAL_RUNTIME=\\\"\\d+\\\"\\s" if runtime}
|
|
||||||
#{"DB_PASSWORD=\"secret\"\\s" if secrets}
|
|
||||||
;\s/usr/bin/env\s\.kamal/hooks/#{hook} }x
|
|
||||||
|
|
||||||
assert_match expected, output
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def with_argv(*argv)
|
def with_argv(*argv)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ class CliProxyTest < CliTestCase
|
|||||||
test "boot" do
|
test "boot" 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 "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume /var/run/docker.sock:/var/run/docker.sock --volume $(pwd)/.kamal/proxy/config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" #{KAMAL.config.proxy_image}", output
|
assert_match "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy $(cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\") #{KAMAL.config.proxy_image}", output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ 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 "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume /var/run/docker.sock:/var/run/docker.sock --volume $(pwd)/.kamal/proxy/config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" #{KAMAL.config.proxy_image}", output
|
assert_match "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy $(cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\") #{KAMAL.config.proxy_image}", output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -36,7 +36,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 "docker container start kamal-proxy || docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume /var/run/docker.sock:/var/run/docker.sock --volume $(pwd)/.kamal/proxy/config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" #{KAMAL.config.proxy_image}", output
|
assert_match "docker container start kamal-proxy || docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy $(cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\") #{KAMAL.config.proxy_image}", output
|
||||||
end
|
end
|
||||||
ensure
|
ensure
|
||||||
Thread.report_on_exception = false
|
Thread.report_on_exception = false
|
||||||
@@ -57,13 +57,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 "Running docker container stop traefik ; docker container prune --force --filter label=org.opencontainers.image.title=Traefik && docker image prune --all --force --filter label=org.opencontainers.image.title=Traefik on 1.1.1.1", output
|
assert_match "Running docker container stop traefik ; docker container prune --force --filter label=org.opencontainers.image.title=Traefik && docker image prune --all --force --filter label=org.opencontainers.image.title=Traefik 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 "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume /var/run/docker.sock:/var/run/docker.sock --volume $(pwd)/.kamal/proxy/config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" #{KAMAL.config.proxy_image} on 1.1.1.1", output
|
assert_match "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy $(cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\") #{KAMAL.config.proxy_image} 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 "Running docker container stop traefik ; docker container prune --force --filter label=org.opencontainers.image.title=Traefik && docker image prune --all --force --filter label=org.opencontainers.image.title=Traefik on 1.1.1.2", output
|
assert_match "Running docker container stop traefik ; docker container prune --force --filter label=org.opencontainers.image.title=Traefik && docker image prune --all --force --filter label=org.opencontainers.image.title=Traefik 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 "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume /var/run/docker.sock:/var/run/docker.sock --volume $(pwd)/.kamal/proxy/config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" #{KAMAL.config.proxy_image} on 1.1.1.2", output
|
assert_match "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy $(cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\") #{KAMAL.config.proxy_image} 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
|
||||||
@@ -136,7 +136,6 @@ class CliProxyTest < CliTestCase
|
|||||||
assert_match "/usr/bin/env ls .kamal/apps | wc -l", output
|
assert_match "/usr/bin/env ls .kamal/apps | wc -l", output
|
||||||
assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy", output
|
assert_match "docker container prune --force --filter label=org.opencontainers.image.title=kamal-proxy", output
|
||||||
assert_match "docker image prune --all --force --filter label=org.opencontainers.image.title=kamal-proxy", output
|
assert_match "docker image prune --all --force --filter label=org.opencontainers.image.title=kamal-proxy", output
|
||||||
assert_match "/usr/bin/env rm -r .kamal/proxy", output
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -176,12 +175,6 @@ class CliProxyTest < CliTestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "remove_host_directory" do
|
|
||||||
run_command("remove_host_directory").tap do |output|
|
|
||||||
assert_match "/usr/bin/env rm -r .kamal/proxy", output
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test "upgrade" do
|
test "upgrade" do
|
||||||
Object.any_instance.stubs(:sleep)
|
Object.any_instance.stubs(:sleep)
|
||||||
|
|
||||||
@@ -205,11 +198,11 @@ 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 || docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume /var/run/docker.sock:/var/run/docker.sock --volume $(pwd)/.kamal/proxy/config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION}", output
|
assert_match "docker container start kamal-proxy || docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy $(cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\") basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION}", 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
|
||||||
assert_match %r{/usr/bin/env .* .kamal/apps/app/env/roles/web.env}, output
|
assert_match "Uploading \"\\n\" to .kamal/apps/app/env/roles/web.env", output
|
||||||
assert_match %r{docker run --detach --restart unless-stopped --name app-web-latest --network kamal --hostname 1.1.1.1-.* -e KAMAL_CONTAINER_NAME="app-web-latest" -e KAMAL_VERSION="latest" --env-file .kamal/apps/app/env/roles/web.env --log-opt max-size="10m" --label service="app" --label role="web" --label destination dhh/app:latest}, output
|
assert_match %r{docker run --detach --restart unless-stopped --name app-web-latest --network kamal --hostname 1.1.1.1-.* -e KAMAL_CONTAINER_NAME="app-web-latest" -e KAMAL_VERSION="latest" --env-file .kamal/apps/app/env/roles/web.env --log-opt max-size="10m" --label service="app" --label role="web" --label destination dhh/app:latest}, output
|
||||||
assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target \"12345678: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\"", output
|
assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target \"12345678: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\"", output
|
||||||
assert_match "docker container ls --all --filter name=^app-web-12345678$ --quiet | xargs docker stop", output
|
assert_match "docker container ls --all --filter name=^app-web-12345678$ --quiet | xargs docker stop", output
|
||||||
@@ -243,6 +236,62 @@ class CliProxyTest < CliTestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "boot_config set" do
|
||||||
|
run_command("boot_config", "set").tap do |output|
|
||||||
|
%w[ 1.1.1.1 1.1.1.2 ].each do |host|
|
||||||
|
assert_match "Running /usr/bin/env mkdir -p .kamal/proxy on #{host}", output
|
||||||
|
assert_match "Uploading \"--publish 80:80 --publish 443:443\" to .kamal/proxy/options on #{host}", output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "boot_config set no publish" do
|
||||||
|
run_command("boot_config", "set", "--publish", "false").tap do |output|
|
||||||
|
%w[ 1.1.1.1 1.1.1.2 ].each do |host|
|
||||||
|
assert_match "Running /usr/bin/env mkdir -p .kamal/proxy on #{host}", output
|
||||||
|
assert_match "Uploading \"\" to .kamal/proxy/options on #{host}", output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "boot_config set custom ports" do
|
||||||
|
run_command("boot_config", "set", "--http-port", "8080", "--https-port", "8443").tap do |output|
|
||||||
|
%w[ 1.1.1.1 1.1.1.2 ].each do |host|
|
||||||
|
assert_match "Running /usr/bin/env mkdir -p .kamal/proxy on #{host}", output
|
||||||
|
assert_match "Uploading \"--publish 8080:80 --publish 8443:443\" to .kamal/proxy/options on #{host}", output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "boot_config set docker options" do
|
||||||
|
run_command("boot_config", "set", "--docker_options", "label=foo=bar", "add_host=thishost:thathost").tap do |output|
|
||||||
|
%w[ 1.1.1.1 1.1.1.2 ].each do |host|
|
||||||
|
assert_match "Running /usr/bin/env mkdir -p .kamal/proxy on #{host}", output
|
||||||
|
assert_match "Uploading \"--publish 80:80 --publish 443:443 --label=foo=bar --add_host=thishost:thathost\" to .kamal/proxy/options on #{host}", output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "boot_config get" do
|
||||||
|
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
|
||||||
|
.with(:cat, ".kamal/proxy/options", "||", :echo, "\"--publish 80:80 --publish 443:443\"")
|
||||||
|
.returns("--publish 80:80 --publish 8443:443 --label=foo=bar")
|
||||||
|
.twice
|
||||||
|
|
||||||
|
run_command("boot_config", "get").tap do |output|
|
||||||
|
assert_match "Host 1.1.1.1: --publish 80:80 --publish 8443:443 --label=foo=bar", output
|
||||||
|
assert_match "Host 1.1.1.2: --publish 80:80 --publish 8443:443 --label=foo=bar", output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "boot_config reset" do
|
||||||
|
run_command("boot_config", "reset").tap do |output|
|
||||||
|
%w[ 1.1.1.1 1.1.1.2 ].each do |host|
|
||||||
|
assert_match "rm .kamal/proxy/options on #{host}", output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def run_command(*command, fixture: :with_proxy)
|
def run_command(*command, fixture: :with_proxy)
|
||||||
stdouted { Kamal::Cli::Proxy.start([ *command, "-c", "test/fixtures/deploy_#{fixture}.yml" ]) }
|
stdouted { Kamal::Cli::Proxy.start([ *command, "-c", "test/fixtures/deploy_#{fixture}.yml" ]) }
|
||||||
|
|||||||
@@ -130,12 +130,20 @@ class CommandsAccessoryTest < ActiveSupport::TestCase
|
|||||||
assert_equal \
|
assert_equal \
|
||||||
"docker logs app-mysql --since 5m --tail 100 --timestamps 2>&1 | grep 'thing' -C 2",
|
"docker logs app-mysql --since 5m --tail 100 --timestamps 2>&1 | grep 'thing' -C 2",
|
||||||
new_command(:mysql).logs(since: "5m", lines: 100, grep: "thing", grep_options: "-C 2").join(" ")
|
new_command(:mysql).logs(since: "5m", lines: 100, grep: "thing", grep_options: "-C 2").join(" ")
|
||||||
|
|
||||||
|
assert_equal \
|
||||||
|
"docker logs app-mysql --since 5m --tail 100 2>&1 | grep 'thing' -C 2",
|
||||||
|
new_command(:mysql).logs(timestamps: false, since: "5m", lines: 100, grep: "thing", grep_options: "-C 2").join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "follow logs" do
|
test "follow logs" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"ssh -t root@1.1.1.5 -p 22 'docker logs app-mysql --timestamps --tail 10 --follow 2>&1'",
|
"ssh -t root@1.1.1.5 -p 22 'docker logs app-mysql --timestamps --tail 10 --follow 2>&1'",
|
||||||
new_command(:mysql).follow_logs
|
new_command(:mysql).follow_logs
|
||||||
|
|
||||||
|
assert_equal \
|
||||||
|
"ssh -t root@1.1.1.5 -p 22 'docker logs app-mysql --tail 10 --follow 2>&1'",
|
||||||
|
new_command(:mysql).follow_logs(timestamps: false)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "remove container" do
|
test "remove container" do
|
||||||
|
|||||||
@@ -129,49 +129,49 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
test "logs" do
|
test "logs" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs 2>&1",
|
"sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs --timestamps 2>&1",
|
||||||
new_command.logs.join(" ")
|
new_command.logs.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "logs with since" do
|
test "logs with since" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs --since 5m 2>&1",
|
"sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs --timestamps --since 5m 2>&1",
|
||||||
new_command.logs(since: "5m").join(" ")
|
new_command.logs(since: "5m").join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "logs with lines" do
|
test "logs with lines" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs --tail 100 2>&1",
|
"sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs --timestamps --tail 100 2>&1",
|
||||||
new_command.logs(lines: "100").join(" ")
|
new_command.logs(lines: "100").join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "logs with since and lines" do
|
test "logs with since and lines" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs --since 5m --tail 100 2>&1",
|
"sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs --timestamps --since 5m --tail 100 2>&1",
|
||||||
new_command.logs(since: "5m", lines: "100").join(" ")
|
new_command.logs(since: "5m", lines: "100").join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "logs with grep" do
|
test "logs with grep" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs 2>&1 | grep 'my-id'",
|
"sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs --timestamps 2>&1 | grep 'my-id'",
|
||||||
new_command.logs(grep: "my-id").join(" ")
|
new_command.logs(grep: "my-id").join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "logs with grep and grep options" do
|
test "logs with grep and grep options" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs 2>&1 | grep 'my-id' -C 2",
|
"sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs --timestamps 2>&1 | grep 'my-id' -C 2",
|
||||||
new_command.logs(grep: "my-id", grep_options: "-C 2").join(" ")
|
new_command.logs(grep: "my-id", grep_options: "-C 2").join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "logs with since, grep and grep options" do
|
test "logs with since, grep and grep options" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs --since 5m 2>&1 | grep 'my-id' -C 2",
|
"sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs --timestamps --since 5m 2>&1 | grep 'my-id' -C 2",
|
||||||
new_command.logs(since: "5m", grep: "my-id", grep_options: "-C 2").join(" ")
|
new_command.logs(since: "5m", grep: "my-id", grep_options: "-C 2").join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "logs with since and grep" do
|
test "logs with since and grep" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs --since 5m 2>&1 | grep 'my-id'",
|
"sh -c 'docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting' | head -1 | xargs docker logs --timestamps --since 5m 2>&1 | grep 'my-id'",
|
||||||
new_command.logs(since: "5m", grep: "my-id").join(" ")
|
new_command.logs(since: "5m", grep: "my-id").join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -191,18 +191,22 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
assert_equal \
|
assert_equal \
|
||||||
"ssh -t root@app-1 -p 22 'sh -c '\\''docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''\\'\\'''\\''{{.ID}}'\\''\\'\\'''\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting'\\'' | head -1 | xargs docker logs --timestamps --tail 123 --follow 2>&1 | grep \"Completed\"'",
|
"ssh -t root@app-1 -p 22 'sh -c '\\''docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''\\'\\'''\\''{{.ID}}'\\''\\'\\'''\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting'\\'' | head -1 | xargs docker logs --timestamps --tail 123 --follow 2>&1 | grep \"Completed\"'",
|
||||||
new_command.follow_logs(host: "app-1", lines: 123, grep: "Completed")
|
new_command.follow_logs(host: "app-1", lines: 123, grep: "Completed")
|
||||||
|
|
||||||
|
assert_equal \
|
||||||
|
"ssh -t root@app-1 -p 22 'sh -c '\\''docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''\\'\\'''\\''{{.ID}}'\\''\\'\\'''\\'') ; docker ps --latest --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting'\\'' | head -1 | xargs docker logs --tail 123 --follow 2>&1 | grep \"Completed\"'",
|
||||||
|
new_command.follow_logs(host: "app-1", timestamps: false, lines: 123, grep: "Completed")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
test "execute in new container" do
|
test "execute in new container" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --rm --env-file .kamal/apps/app/env/roles/web.env dhh/app:999 bin/rails db:setup",
|
"docker run --rm --network kamal --env-file .kamal/apps/app/env/roles/web.env dhh/app:999 bin/rails db:setup",
|
||||||
new_command.execute_in_new_container("bin/rails", "db:setup", env: {}).join(" ")
|
new_command.execute_in_new_container("bin/rails", "db:setup", env: {}).join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "execute in new container with env" do
|
test "execute in new container with env" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --rm --env-file .kamal/apps/app/env/roles/web.env --env foo=\"bar\" dhh/app:999 bin/rails db:setup",
|
"docker run --rm --network kamal --env-file .kamal/apps/app/env/roles/web.env --env foo=\"bar\" dhh/app:999 bin/rails db:setup",
|
||||||
new_command.execute_in_new_container("bin/rails", "db:setup", env: { "foo" => "bar" }).join(" ")
|
new_command.execute_in_new_container("bin/rails", "db:setup", env: { "foo" => "bar" }).join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -211,14 +215,14 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
@config[:env]["tags"] = { "tag1" => { "ENV1" => "value1" } }
|
@config[:env]["tags"] = { "tag1" => { "ENV1" => "value1" } }
|
||||||
|
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --rm --env ENV1=\"value1\" --env-file .kamal/apps/app/env/roles/web.env dhh/app:999 bin/rails db:setup",
|
"docker run --rm --network kamal --env ENV1=\"value1\" --env-file .kamal/apps/app/env/roles/web.env dhh/app:999 bin/rails db:setup",
|
||||||
new_command.execute_in_new_container("bin/rails", "db:setup", env: {}).join(" ")
|
new_command.execute_in_new_container("bin/rails", "db:setup", env: {}).join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "execute in new container with custom options" do
|
test "execute in new container with custom options" do
|
||||||
@config[:servers] = { "web" => { "hosts" => [ "1.1.1.1" ], "options" => { "mount" => "somewhere", "cap-add" => true } } }
|
@config[:servers] = { "web" => { "hosts" => [ "1.1.1.1" ], "options" => { "mount" => "somewhere", "cap-add" => true } } }
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --rm --env-file .kamal/apps/app/env/roles/web.env --mount \"somewhere\" --cap-add dhh/app:999 bin/rails db:setup",
|
"docker run --rm --network kamal --env-file .kamal/apps/app/env/roles/web.env --mount \"somewhere\" --cap-add dhh/app:999 bin/rails db:setup",
|
||||||
new_command.execute_in_new_container("bin/rails", "db:setup", env: {}).join(" ")
|
new_command.execute_in_new_container("bin/rails", "db:setup", env: {}).join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -235,7 +239,7 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "execute in new container over ssh" do
|
test "execute in new container over ssh" do
|
||||||
assert_match %r{docker run -it --rm --env-file .kamal/apps/app/env/roles/web.env dhh/app:999 bin/rails c},
|
assert_match %r{docker run -it --rm --network kamal --env-file .kamal/apps/app/env/roles/web.env dhh/app:999 bin/rails c},
|
||||||
new_command.execute_in_new_container_over_ssh("bin/rails", "c", env: {})
|
new_command.execute_in_new_container_over_ssh("bin/rails", "c", env: {})
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -243,13 +247,13 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
@config[:servers] = [ { "1.1.1.1" => "tag1" } ]
|
@config[:servers] = [ { "1.1.1.1" => "tag1" } ]
|
||||||
@config[:env]["tags"] = { "tag1" => { "ENV1" => "value1" } }
|
@config[:env]["tags"] = { "tag1" => { "ENV1" => "value1" } }
|
||||||
|
|
||||||
assert_equal "ssh -t root@1.1.1.1 -p 22 'docker run -it --rm --env ENV1=\"value1\" --env-file .kamal/apps/app/env/roles/web.env dhh/app:999 bin/rails c'",
|
assert_equal "ssh -t root@1.1.1.1 -p 22 'docker run -it --rm --network kamal --env ENV1=\"value1\" --env-file .kamal/apps/app/env/roles/web.env dhh/app:999 bin/rails c'",
|
||||||
new_command.execute_in_new_container_over_ssh("bin/rails", "c", env: {})
|
new_command.execute_in_new_container_over_ssh("bin/rails", "c", env: {})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "execute in new container with custom options over ssh" do
|
test "execute in new container with custom options over ssh" do
|
||||||
@config[:servers] = { "web" => { "hosts" => [ "1.1.1.1" ], "options" => { "mount" => "somewhere", "cap-add" => true } } }
|
@config[:servers] = { "web" => { "hosts" => [ "1.1.1.1" ], "options" => { "mount" => "somewhere", "cap-add" => true } } }
|
||||||
assert_match %r{docker run -it --rm --env-file .kamal/apps/app/env/roles/web.env --mount \"somewhere\" --cap-add dhh/app:999 bin/rails c},
|
assert_match %r{docker run -it --rm --network kamal --env-file .kamal/apps/app/env/roles/web.env --mount \"somewhere\" --cap-add dhh/app:999 bin/rails c},
|
||||||
new_command.execute_in_new_container_over_ssh("bin/rails", "c", env: {})
|
new_command.execute_in_new_container_over_ssh("bin/rails", "c", env: {})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -16,41 +16,34 @@ class CommandsHookTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "run" do
|
test "run" do
|
||||||
assert_equal [
|
assert_equal [ ".kamal/hooks/foo" ], new_command.run("foo")
|
||||||
".kamal/hooks/foo",
|
end
|
||||||
{ env: {
|
|
||||||
|
test "env" do
|
||||||
|
assert_equal ({
|
||||||
"KAMAL_RECORDED_AT" => @recorded_at,
|
"KAMAL_RECORDED_AT" => @recorded_at,
|
||||||
"KAMAL_PERFORMER" => @performer,
|
"KAMAL_PERFORMER" => @performer,
|
||||||
"KAMAL_VERSION" => "123",
|
"KAMAL_VERSION" => "123",
|
||||||
"KAMAL_SERVICE_VERSION" => "app@123",
|
"KAMAL_SERVICE_VERSION" => "app@123",
|
||||||
"KAMAL_SERVICE" => "app" } }
|
"KAMAL_SERVICE" => "app"
|
||||||
], new_command.run("foo")
|
}), new_command.env
|
||||||
end
|
end
|
||||||
|
|
||||||
test "run with custom hooks_path" do
|
test "run with custom hooks_path" do
|
||||||
assert_equal [
|
assert_equal [ "custom/hooks/path/foo" ], new_command(hooks_path: "custom/hooks/path").run("foo")
|
||||||
"custom/hooks/path/foo",
|
|
||||||
{ env: {
|
|
||||||
"KAMAL_RECORDED_AT" => @recorded_at,
|
|
||||||
"KAMAL_PERFORMER" => @performer,
|
|
||||||
"KAMAL_VERSION" => "123",
|
|
||||||
"KAMAL_SERVICE_VERSION" => "app@123",
|
|
||||||
"KAMAL_SERVICE" => "app" } }
|
|
||||||
], new_command(hooks_path: "custom/hooks/path").run("foo")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
test "hook with secrets" do
|
test "env with secrets" do
|
||||||
with_test_secrets("secrets" => "DB_PASSWORD=secret") do
|
with_test_secrets("secrets" => "DB_PASSWORD=secret") do
|
||||||
assert_equal [
|
assert_equal (
|
||||||
".kamal/hooks/foo",
|
{
|
||||||
{ env: {
|
|
||||||
"KAMAL_RECORDED_AT" => @recorded_at,
|
"KAMAL_RECORDED_AT" => @recorded_at,
|
||||||
"KAMAL_PERFORMER" => @performer,
|
"KAMAL_PERFORMER" => @performer,
|
||||||
"KAMAL_VERSION" => "123",
|
"KAMAL_VERSION" => "123",
|
||||||
"KAMAL_SERVICE_VERSION" => "app@123",
|
"KAMAL_SERVICE_VERSION" => "app@123",
|
||||||
"KAMAL_SERVICE" => "app",
|
"KAMAL_SERVICE" => "app",
|
||||||
"DB_PASSWORD" => "secret" } }
|
"DB_PASSWORD" => "secret" }
|
||||||
], new_command(env: { "secret" => [ "DB_PASSWORD" ] }).run("foo", secrets: true)
|
), new_command.env(secrets: true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -15,13 +15,7 @@ class CommandsProxyTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
test "run" do
|
test "run" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume /var/run/docker.sock:/var/run/docker.sock --volume $(pwd)/.kamal/proxy/config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" #{KAMAL.config.proxy_image}",
|
"docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy $(cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\") basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION}",
|
||||||
new_command.run.join(" ")
|
|
||||||
end
|
|
||||||
|
|
||||||
test "run with ports configured" do
|
|
||||||
assert_equal \
|
|
||||||
"docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume /var/run/docker.sock:/var/run/docker.sock --volume $(pwd)/.kamal/proxy/config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" #{KAMAL.config.proxy_image}",
|
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -29,15 +23,7 @@ class CommandsProxyTest < ActiveSupport::TestCase
|
|||||||
@config.delete(:proxy)
|
@config.delete(:proxy)
|
||||||
|
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume /var/run/docker.sock:/var/run/docker.sock --volume $(pwd)/.kamal/proxy/config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" #{KAMAL.config.proxy_image}",
|
"docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy $(cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\") basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION}",
|
||||||
new_command.run.join(" ")
|
|
||||||
end
|
|
||||||
|
|
||||||
test "run with logging config" do
|
|
||||||
@config[:logging] = { "driver" => "local", "options" => { "max-size" => "100m", "max-file" => "3" } }
|
|
||||||
|
|
||||||
assert_equal \
|
|
||||||
"docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume /var/run/docker.sock:/var/run/docker.sock --volume $(pwd)/.kamal/proxy/config:/home/kamal-proxy/.config/kamal-proxy --log-driver \"local\" --log-opt max-size=\"100m\" --log-opt max-file=\"3\" #{KAMAL.config.proxy_image}",
|
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -77,6 +63,12 @@ class CommandsProxyTest < ActiveSupport::TestCase
|
|||||||
new_command.logs(lines: 10).join(" ")
|
new_command.logs(lines: 10).join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "proxy logs without timestamps" do
|
||||||
|
assert_equal \
|
||||||
|
"docker logs kamal-proxy 2>&1",
|
||||||
|
new_command.logs(timestamps: false).join(" ")
|
||||||
|
end
|
||||||
|
|
||||||
test "proxy logs with grep hello!" do
|
test "proxy logs with grep hello!" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker logs kamal-proxy --timestamps 2>&1 | grep 'hello!'",
|
"docker logs kamal-proxy --timestamps 2>&1 | grep 'hello!'",
|
||||||
@@ -113,6 +105,24 @@ class CommandsProxyTest < ActiveSupport::TestCase
|
|||||||
new_command.version.join(" ")
|
new_command.version.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "ensure_proxy_directory" do
|
||||||
|
assert_equal \
|
||||||
|
"mkdir -p .kamal/proxy",
|
||||||
|
new_command.ensure_proxy_directory.join(" ")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "get_boot_options" do
|
||||||
|
assert_equal \
|
||||||
|
"cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\"",
|
||||||
|
new_command.get_boot_options.join(" ")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "reset_boot_options" do
|
||||||
|
assert_equal \
|
||||||
|
"rm .kamal/proxy/options",
|
||||||
|
new_command.reset_boot_options.join(" ")
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def new_command
|
def new_command
|
||||||
Kamal::Commands::Proxy.new(Kamal::Configuration.new(@config, version: "123"))
|
Kamal::Commands::Proxy.new(Kamal::Configuration.new(@config, version: "123"))
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
require "test_helper"
|
require "test_helper"
|
||||||
|
|
||||||
class ConfigurationEnvTest < ActiveSupport::TestCase
|
class ConfigurationProxyTest < ActiveSupport::TestCase
|
||||||
setup do
|
setup do
|
||||||
@deploy = {
|
@deploy = {
|
||||||
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
|
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
|
||||||
@@ -18,6 +18,12 @@ class ConfigurationEnvTest < ActiveSupport::TestCase
|
|||||||
assert_raises(Kamal::ConfigurationError) { config.proxy.ssl? }
|
assert_raises(Kamal::ConfigurationError) { config.proxy.ssl? }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "ssl false" do
|
||||||
|
@deploy[:proxy] = { "ssl" => false }
|
||||||
|
assert_not config.proxy.ssl?
|
||||||
|
assert_not config.proxy.deploy_options.has_key?(:tls)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def config
|
def config
|
||||||
Kamal::Configuration.new(@deploy)
|
Kamal::Configuration.new(@deploy)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class BrokenDeployTest < IntegrationTest
|
|||||||
kamal :deploy
|
kamal :deploy
|
||||||
|
|
||||||
assert_app_is_up version: first_version
|
assert_app_is_up version: first_version
|
||||||
assert_container_running host: :vm3, name: "app-workers-#{first_version}"
|
assert_container_running host: :vm3, name: "app_with_roles-workers-#{first_version}"
|
||||||
|
|
||||||
second_version = break_app
|
second_version = break_app
|
||||||
|
|
||||||
@@ -17,8 +17,8 @@ class BrokenDeployTest < IntegrationTest
|
|||||||
|
|
||||||
assert_failed_deploy output
|
assert_failed_deploy output
|
||||||
assert_app_is_up version: first_version
|
assert_app_is_up version: first_version
|
||||||
assert_container_running host: :vm3, name: "app-workers-#{first_version}"
|
assert_container_running host: :vm3, name: "app_with_roles-workers-#{first_version}"
|
||||||
assert_container_not_running host: :vm3, name: "app-workers-#{second_version}"
|
assert_container_not_running host: :vm3, name: "app_with_roles-workers-#{second_version}"
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ RUN apt-get update --fix-missing && apt-get install -y docker-ce docker-ce-cli c
|
|||||||
COPY *.sh .
|
COPY *.sh .
|
||||||
COPY app/ app/
|
COPY app/ app/
|
||||||
COPY app_with_roles/ app_with_roles/
|
COPY app_with_roles/ app_with_roles/
|
||||||
|
COPY app_with_traefik/ app_with_traefik/
|
||||||
|
|
||||||
RUN rm -rf /root/.ssh
|
RUN rm -rf /root/.ssh
|
||||||
RUN ln -s /shared/ssh /root/.ssh
|
RUN ln -s /shared/ssh /root/.ssh
|
||||||
@@ -28,6 +29,7 @@ RUN git config --global user.email "deployer@example.com"
|
|||||||
RUN git config --global user.name "Deployer"
|
RUN git config --global user.name "Deployer"
|
||||||
RUN cd app && git init && git add . && git commit -am "Initial version"
|
RUN cd app && git init && git add . && git commit -am "Initial version"
|
||||||
RUN cd app_with_roles && git init && git add . && git commit -am "Initial version"
|
RUN cd app_with_roles && git init && git add . && git commit -am "Initial version"
|
||||||
|
RUN cd app_with_traefik && git init && git add . && git commit -am "Initial version"
|
||||||
|
|
||||||
HEALTHCHECK --interval=1s CMD pgrep sleep
|
HEALTHCHECK --interval=1s CMD pgrep sleep
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
echo "Rebooting Traefik on ${KAMAL_HOSTS}..."
|
echo "Rebooting kamal-proxy on ${KAMAL_HOSTS}..."
|
||||||
mkdir -p /tmp/${TEST_ID} && touch /tmp/${TEST_ID}/pre-proxy-reboot
|
mkdir -p /tmp/${TEST_ID} && touch /tmp/${TEST_ID}/pre-proxy-reboot
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ asset_path: /usr/share/nginx/html/versions
|
|||||||
deploy_timeout: 2
|
deploy_timeout: 2
|
||||||
drain_timeout: 2
|
drain_timeout: 2
|
||||||
readiness_delay: 0
|
readiness_delay: 0
|
||||||
|
proxy:
|
||||||
|
host: 127.0.0.1
|
||||||
registry:
|
registry:
|
||||||
server: registry:4443
|
server: registry:4443
|
||||||
username: root
|
username: root
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
service: app
|
service: app_with_roles
|
||||||
image: app
|
image: app_with_roles
|
||||||
servers:
|
servers:
|
||||||
web:
|
web:
|
||||||
hosts:
|
hosts:
|
||||||
@@ -14,6 +14,7 @@ drain_timeout: 2
|
|||||||
readiness_delay: 0
|
readiness_delay: 0
|
||||||
|
|
||||||
proxy:
|
proxy:
|
||||||
|
host: localhost
|
||||||
healthcheck:
|
healthcheck:
|
||||||
interval: 1
|
interval: 1
|
||||||
timeout: 1
|
timeout: 1
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
kamal proxy boot_config set --publish false \
|
||||||
|
--docker_options label=traefik.http.services.kamal_proxy.loadbalancer.server.scheme=http \
|
||||||
|
label=traefik.http.routers.kamal_proxy.rule=PathPrefix\(\`/\`\)
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
SECRET_TOKEN='1234 with "中文"'
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
FROM registry:4443/nginx:1-alpine-slim
|
||||||
|
|
||||||
|
COPY default.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
|
ARG COMMIT_SHA
|
||||||
|
RUN echo $COMMIT_SHA > /usr/share/nginx/html/version
|
||||||
|
RUN mkdir -p /usr/share/nginx/html/versions && echo "version" > /usr/share/nginx/html/versions/$COMMIT_SHA
|
||||||
|
RUN mkdir -p /usr/share/nginx/html/versions && echo "hidden" > /usr/share/nginx/html/versions/.hidden
|
||||||
|
RUN echo "Up!" > /usr/share/nginx/html/up
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
service: app_with_traefik
|
||||||
|
image: app_with_traefik
|
||||||
|
servers:
|
||||||
|
- vm1
|
||||||
|
- vm2
|
||||||
|
deploy_timeout: 2
|
||||||
|
drain_timeout: 2
|
||||||
|
readiness_delay: 0
|
||||||
|
|
||||||
|
registry:
|
||||||
|
server: registry:4443
|
||||||
|
username: root
|
||||||
|
password: root
|
||||||
|
builder:
|
||||||
|
driver: docker
|
||||||
|
arch: <%= Kamal::Utils.docker_arch %>
|
||||||
|
args:
|
||||||
|
COMMIT_SHA: <%= `git rev-parse HEAD` %>
|
||||||
|
accessories:
|
||||||
|
traefik:
|
||||||
|
service: traefik
|
||||||
|
image: traefik:v2.10
|
||||||
|
port: 80
|
||||||
|
cmd: "--providers.docker"
|
||||||
|
options:
|
||||||
|
volume:
|
||||||
|
- "/var/run/docker.sock:/var/run/docker.sock"
|
||||||
|
roles:
|
||||||
|
- web
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html index.htm;
|
||||||
|
}
|
||||||
|
|
||||||
|
# redirect server error pages to the static page /50x.html
|
||||||
|
#
|
||||||
|
error_page 500 502 503 504 /50x.html;
|
||||||
|
location = /50x.html {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,8 @@ server {
|
|||||||
|
|
||||||
location / {
|
location / {
|
||||||
proxy_pass http://loadbalancer;
|
proxy_pass http://loadbalancer;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
|
||||||
proxy_connect_timeout 10;
|
proxy_connect_timeout 10;
|
||||||
proxy_send_timeout 10;
|
proxy_send_timeout 10;
|
||||||
proxy_read_timeout 10;
|
proxy_read_timeout 10;
|
||||||
|
|||||||
@@ -50,8 +50,8 @@ class IntegrationTest < ActiveSupport::TestCase
|
|||||||
assert_equal "502", response.code
|
assert_equal "502", response.code
|
||||||
end
|
end
|
||||||
|
|
||||||
def assert_app_is_up(version: nil)
|
def assert_app_is_up(version: nil, app: @app)
|
||||||
response = app_response
|
response = app_response(app: app)
|
||||||
debug_response_code(response, "200")
|
debug_response_code(response, "200")
|
||||||
assert_equal "200", response.code
|
assert_equal "200", response.code
|
||||||
assert_app_version(version, response) if version
|
assert_app_version(version, response) if version
|
||||||
@@ -69,8 +69,8 @@ class IntegrationTest < ActiveSupport::TestCase
|
|||||||
assert_equal up_times, up_count
|
assert_equal up_times, up_count
|
||||||
end
|
end
|
||||||
|
|
||||||
def app_response
|
def app_response(app: @app)
|
||||||
Net::HTTP.get_response(URI.parse("http://localhost:12345/version"))
|
Net::HTTP.get_response(URI.parse("http://#{app_host(app)}:12345/version"))
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_app_rev
|
def update_app_rev
|
||||||
@@ -153,11 +153,24 @@ class IntegrationTest < ActiveSupport::TestCase
|
|||||||
assert_directory_removed("./kamal/apps/#{@app}")
|
assert_directory_removed("./kamal/apps/#{@app}")
|
||||||
end
|
end
|
||||||
|
|
||||||
def assert_proxy_directory_removed
|
|
||||||
assert_directory_removed("./kamal/proxy")
|
|
||||||
end
|
|
||||||
|
|
||||||
def assert_directory_removed(directory)
|
def assert_directory_removed(directory)
|
||||||
assert docker_compose("exec vm1 ls #{directory} | wc -l", capture: true).strip == "0"
|
assert docker_compose("exec vm1 ls #{directory} | wc -l", capture: true).strip == "0"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def assert_proxy_running
|
||||||
|
assert_container_running(host: "vm1", name: "kamal-proxy")
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_proxy_not_running
|
||||||
|
assert_container_not_running(host: "vm1", name: "kamal-proxy")
|
||||||
|
end
|
||||||
|
|
||||||
|
def app_host(app = @app)
|
||||||
|
case app
|
||||||
|
when "app"
|
||||||
|
"127.0.0.1"
|
||||||
|
else
|
||||||
|
"localhost"
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -46,13 +46,13 @@ class MainTest < IntegrationTest
|
|||||||
|
|
||||||
assert_app_is_up version: version
|
assert_app_is_up version: version
|
||||||
assert_hooks_ran "pre-connect", "pre-build", "pre-deploy", "post-deploy"
|
assert_hooks_ran "pre-connect", "pre-build", "pre-deploy", "post-deploy"
|
||||||
assert_container_running host: :vm3, name: "app-workers-#{version}"
|
assert_container_running host: :vm3, name: "app_with_roles-workers-#{version}"
|
||||||
|
|
||||||
second_version = update_app_rev
|
second_version = update_app_rev
|
||||||
|
|
||||||
kamal :redeploy
|
kamal :redeploy
|
||||||
assert_app_is_up version: second_version
|
assert_app_is_up version: second_version
|
||||||
assert_container_running host: :vm3, name: "app-workers-#{second_version}"
|
assert_container_running host: :vm3, name: "app_with_roles-workers-#{second_version}"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "config" do
|
test "config" do
|
||||||
@@ -88,6 +88,14 @@ class MainTest < IntegrationTest
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "setup and remove" do
|
test "setup and remove" do
|
||||||
|
@app = "app_with_roles"
|
||||||
|
|
||||||
|
kamal :proxy, :set_config,
|
||||||
|
"--publish=false",
|
||||||
|
"--options=label=traefik.http.services.kamal_proxy.loadbalancer.server.scheme=http",
|
||||||
|
"label=traefik.http.routers.kamal_proxy.rule=PathPrefix\\\(\\\`/\\\`\\\)",
|
||||||
|
"label=traefik.http.routers.kamal_proxy.priority=2"
|
||||||
|
|
||||||
# Check remove completes when nothing has been setup yet
|
# Check remove completes when nothing has been setup yet
|
||||||
kamal :remove, "-y"
|
kamal :remove, "-y"
|
||||||
assert_no_images_or_containers
|
assert_no_images_or_containers
|
||||||
@@ -98,7 +106,38 @@ class MainTest < IntegrationTest
|
|||||||
kamal :remove, "-y"
|
kamal :remove, "-y"
|
||||||
assert_no_images_or_containers
|
assert_no_images_or_containers
|
||||||
assert_app_directory_removed
|
assert_app_directory_removed
|
||||||
assert_proxy_directory_removed
|
end
|
||||||
|
|
||||||
|
test "two apps" do
|
||||||
|
@app = "app"
|
||||||
|
kamal :deploy
|
||||||
|
app1_version = latest_app_version
|
||||||
|
|
||||||
|
@app = "app_with_roles"
|
||||||
|
kamal :deploy
|
||||||
|
app2_version = latest_app_version
|
||||||
|
|
||||||
|
assert_app_is_up version: app1_version, app: "app"
|
||||||
|
assert_app_is_up version: app2_version, app: "app_with_roles"
|
||||||
|
|
||||||
|
@app = "app"
|
||||||
|
kamal :remove, "-y"
|
||||||
|
assert_app_directory_removed
|
||||||
|
assert_proxy_running
|
||||||
|
|
||||||
|
@app = "app_with_roles"
|
||||||
|
kamal :remove, "-y"
|
||||||
|
assert_app_directory_removed
|
||||||
|
assert_proxy_not_running
|
||||||
|
end
|
||||||
|
|
||||||
|
test "deploy with traefik" do
|
||||||
|
@app = "app_with_traefik"
|
||||||
|
|
||||||
|
first_version = latest_app_version
|
||||||
|
|
||||||
|
kamal :setup
|
||||||
|
assert_app_is_up version: first_version
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@@ -116,21 +155,21 @@ class MainTest < IntegrationTest
|
|||||||
end
|
end
|
||||||
|
|
||||||
def assert_env(key, value, vm:, version:)
|
def assert_env(key, value, vm:, version:)
|
||||||
assert_equal "#{key}=#{value}", docker_compose("exec #{vm} docker exec app-web-#{version} env | grep #{key}", capture: true)
|
assert_equal "#{key}=#{value}", docker_compose("exec #{vm} docker exec #{@app}-web-#{version} env | grep #{key}", capture: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def assert_no_env(key, vm:, version:)
|
def assert_no_env(key, vm:, version:)
|
||||||
assert_raises(RuntimeError, /exit 1/) do
|
assert_raises(RuntimeError, /exit 1/) do
|
||||||
docker_compose("exec #{vm} docker exec app-web-#{version} env | grep #{key}", capture: true)
|
docker_compose("exec #{vm} docker exec #{@app}-web-#{version} env | grep #{key}", capture: true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def assert_accumulated_assets(*versions)
|
def assert_accumulated_assets(*versions)
|
||||||
versions.each do |version|
|
versions.each do |version|
|
||||||
assert_equal "200", Net::HTTP.get_response(URI.parse("http://localhost:12345/versions/#{version}")).code
|
assert_equal "200", Net::HTTP.get_response(URI.parse("http://#{app_host}:12345/versions/#{version}")).code
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_equal "200", Net::HTTP.get_response(URI.parse("http://localhost:12345/versions/.hidden")).code
|
assert_equal "200", Net::HTTP.get_response(URI.parse("http://#{app_host}:12345/versions/.hidden")).code
|
||||||
end
|
end
|
||||||
|
|
||||||
def vm1_image_ids
|
def vm1_image_ids
|
||||||
|
|||||||
@@ -48,19 +48,5 @@ class ProxyTest < IntegrationTest
|
|||||||
|
|
||||||
kamal :proxy, :remove
|
kamal :proxy, :remove
|
||||||
assert_proxy_not_running
|
assert_proxy_not_running
|
||||||
assert_proxy_directory_removed
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
def assert_proxy_running
|
|
||||||
assert_match /basecamp\/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION} \"kamal-proxy run\"/, proxy_details
|
|
||||||
end
|
|
||||||
|
|
||||||
def assert_proxy_not_running
|
|
||||||
assert_no_match /basecamp\/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION} \"kamal-proxy run\"/, proxy_details
|
|
||||||
end
|
|
||||||
|
|
||||||
def proxy_details
|
|
||||||
kamal :proxy, :details, capture: true
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -13,6 +13,13 @@ ActiveSupport::LogSubscriber.logger = ActiveSupport::Logger.new(STDOUT) if ENV["
|
|||||||
# Applies to remote commands only.
|
# Applies to remote commands only.
|
||||||
SSHKit.config.backend = SSHKit::Backend::Printer
|
SSHKit.config.backend = SSHKit::Backend::Printer
|
||||||
|
|
||||||
|
class SSHKit::Backend::Printer
|
||||||
|
def upload!(local, location, **kwargs)
|
||||||
|
local = local.string.inspect if local.respond_to?(:string)
|
||||||
|
puts "Uploading #{local} to #{location} on #{host}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# Ensure local commands use the printer backend too.
|
# Ensure local commands use the printer backend too.
|
||||||
# See https://github.com/capistrano/sshkit/blob/master/lib/sshkit/dsl.rb#L9
|
# See https://github.com/capistrano/sshkit/blob/master/lib/sshkit/dsl.rb#L9
|
||||||
module SSHKit
|
module SSHKit
|
||||||
|
|||||||
Reference in New Issue
Block a user