Compare commits
3 Commits
v2.0.0.rc4
...
local-dock
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10f3d33cb5 | ||
|
|
9fd4001a88 | ||
|
|
6aa707e233 |
@@ -1,7 +1,7 @@
|
|||||||
PATH
|
PATH
|
||||||
remote: .
|
remote: .
|
||||||
specs:
|
specs:
|
||||||
kamal (2.0.0.rc4)
|
kamal (2.0.0.rc2)
|
||||||
activesupport (>= 7.0)
|
activesupport (>= 7.0)
|
||||||
base64 (~> 0.2)
|
base64 (~> 0.2)
|
||||||
bcrypt_pbkdf (~> 1.0)
|
bcrypt_pbkdf (~> 1.0)
|
||||||
@@ -9,6 +9,7 @@ PATH
|
|||||||
dotenv (~> 3.1)
|
dotenv (~> 3.1)
|
||||||
ed25519 (~> 1.2)
|
ed25519 (~> 1.2)
|
||||||
net-ssh (~> 7.0)
|
net-ssh (~> 7.0)
|
||||||
|
net-ssh-gateway
|
||||||
sshkit (>= 1.23.0, < 2.0)
|
sshkit (>= 1.23.0, < 2.0)
|
||||||
thor (~> 1.3)
|
thor (~> 1.3)
|
||||||
zeitwerk (~> 2.5)
|
zeitwerk (~> 2.5)
|
||||||
@@ -79,6 +80,8 @@ GEM
|
|||||||
net-sftp (4.0.0)
|
net-sftp (4.0.0)
|
||||||
net-ssh (>= 5.0.0, < 8.0.0)
|
net-ssh (>= 5.0.0, < 8.0.0)
|
||||||
net-ssh (7.2.3)
|
net-ssh (7.2.3)
|
||||||
|
net-ssh-gateway (2.0.0)
|
||||||
|
net-ssh (>= 4.0.0)
|
||||||
nokogiri (1.16.7-arm64-darwin)
|
nokogiri (1.16.7-arm64-darwin)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.16.7-x86_64-darwin)
|
nokogiri (1.16.7-x86_64-darwin)
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ Gem::Specification.new do |spec|
|
|||||||
spec.add_dependency "activesupport", ">= 7.0"
|
spec.add_dependency "activesupport", ">= 7.0"
|
||||||
spec.add_dependency "sshkit", ">= 1.23.0", "< 2.0"
|
spec.add_dependency "sshkit", ">= 1.23.0", "< 2.0"
|
||||||
spec.add_dependency "net-ssh", "~> 7.0"
|
spec.add_dependency "net-ssh", "~> 7.0"
|
||||||
|
spec.add_dependency "net-ssh-gateway"
|
||||||
spec.add_dependency "thor", "~> 1.3"
|
spec.add_dependency "thor", "~> 1.3"
|
||||||
spec.add_dependency "dotenv", "~> 3.1"
|
spec.add_dependency "dotenv", "~> 3.1"
|
||||||
spec.add_dependency "zeitwerk", "~> 2.5"
|
spec.add_dependency "zeitwerk", "~> 2.5"
|
||||||
|
|||||||
@@ -275,7 +275,7 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|||||||
def prepare(name)
|
def prepare(name)
|
||||||
with_accessory(name) do |accessory, hosts|
|
with_accessory(name) do |accessory, hosts|
|
||||||
on(hosts) do
|
on(hosts) do
|
||||||
execute *KAMAL.registry.login
|
execute *KAMAL.registry.login unless KAMAL.config.registry.local?
|
||||||
execute *KAMAL.docker.create_network
|
execute *KAMAL.docker.create_network
|
||||||
rescue SSHKit::Command::Failed => e
|
rescue SSHKit::Command::Failed => e
|
||||||
raise unless e.message.include?("already exists")
|
raise unless e.message.include?("already exists")
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
require "uri"
|
require "uri"
|
||||||
|
require "net/ssh"
|
||||||
|
|
||||||
class Kamal::Cli::Build < Kamal::Cli::Base
|
class Kamal::Cli::Build < Kamal::Cli::Base
|
||||||
class BuildError < StandardError; end
|
class BuildError < StandardError; end
|
||||||
@@ -60,6 +61,8 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "pull", "Pull app image from registry onto servers"
|
desc "pull", "Pull app image from registry onto servers"
|
||||||
def pull
|
def pull
|
||||||
|
tunnels = Kamal::Cli::Tunnel::RemotePorts.new(KAMAL.hosts, KAMAL.config.registry.local_port).tap(&:open) if KAMAL.config.registry.local?
|
||||||
|
|
||||||
if (first_hosts = mirror_hosts).any?
|
if (first_hosts = mirror_hosts).any?
|
||||||
# Pull on a single host per mirror first to seed them
|
# Pull on a single host per mirror first to seed them
|
||||||
say "Pulling image on #{first_hosts.join(", ")} to seed the #{"mirror".pluralize(first_hosts.count)}...", :magenta
|
say "Pulling image on #{first_hosts.join(", ")} to seed the #{"mirror".pluralize(first_hosts.count)}...", :magenta
|
||||||
@@ -69,6 +72,8 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|||||||
else
|
else
|
||||||
pull_on_hosts(KAMAL.hosts)
|
pull_on_hosts(KAMAL.hosts)
|
||||||
end
|
end
|
||||||
|
ensure
|
||||||
|
tunnels&.close
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "create", "Create a build setup"
|
desc "create", "Create a build setup"
|
||||||
@@ -152,7 +157,7 @@ class Kamal::Cli::Build < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def pull_on_hosts(hosts)
|
def pull_on_hosts(hosts)
|
||||||
on(hosts) do
|
on(hosts) do |host|
|
||||||
execute *KAMAL.auditor.record("Pulled image with version #{KAMAL.config.version}"), verbosity: :debug
|
execute *KAMAL.auditor.record("Pulled image with version #{KAMAL.config.version}"), verbosity: :debug
|
||||||
execute *KAMAL.builder.clean, raise_on_non_zero_exit: false
|
execute *KAMAL.builder.clean, raise_on_non_zero_exit: false
|
||||||
execute *KAMAL.builder.pull
|
execute *KAMAL.builder.pull
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
invoke_options = deploy_options
|
invoke_options = deploy_options
|
||||||
|
|
||||||
say "Log into image registry...", :magenta
|
say "Log into image registry...", :magenta
|
||||||
invoke "kamal:cli:registry:login", [], invoke_options.merge(skip_local: options[:skip_push])
|
invoke "kamal:cli:registry:setup", [], invoke_options.merge(skip_local: options[:skip_push])
|
||||||
|
|
||||||
if options[:skip_push]
|
if options[:skip_push]
|
||||||
say "Pull app image...", :magenta
|
say "Pull app image...", :magenta
|
||||||
@@ -184,7 +184,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
invoke "kamal:cli:app:remove", [], options.without(:confirmed)
|
invoke "kamal:cli:app:remove", [], options.without(:confirmed)
|
||||||
invoke "kamal:cli:proxy:remove", [], options.without(:confirmed)
|
invoke "kamal:cli:proxy:remove", [], options.without(:confirmed)
|
||||||
invoke "kamal:cli:accessory:remove", [ "all" ], options
|
invoke "kamal:cli:accessory:remove", [ "all" ], options
|
||||||
invoke "kamal:cli:registry:logout", [], options.without(:confirmed).merge(skip_local: true)
|
invoke "kamal:cli:registry:remove", [], options.without(:confirmed).merge(skip_local: true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
on(KAMAL.proxy_hosts) do |host|
|
on(KAMAL.proxy_hosts) do |host|
|
||||||
execute *KAMAL.registry.login
|
execute *KAMAL.registry.login unless KAMAL.config.registry.local?
|
||||||
|
|
||||||
version = capture_with_info(*KAMAL.proxy.version).strip.presence
|
version = capture_with_info(*KAMAL.proxy.version).strip.presence
|
||||||
|
|
||||||
@@ -21,36 +21,6 @@ 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"
|
||||||
@@ -63,7 +33,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|||||||
run_hook "pre-proxy-reboot", hosts: host_list
|
run_hook "pre-proxy-reboot", hosts: host_list
|
||||||
on(hosts) do |host|
|
on(hosts) do |host|
|
||||||
execute *KAMAL.auditor.record("Rebooted proxy"), verbosity: :debug
|
execute *KAMAL.auditor.record("Rebooted proxy"), verbosity: :debug
|
||||||
execute *KAMAL.registry.login
|
execute *KAMAL.registry.login unless KAMAL.config.registry.local?
|
||||||
|
|
||||||
"Stopping and removing Traefik on #{host}, if running..."
|
"Stopping and removing Traefik on #{host}, if running..."
|
||||||
execute *KAMAL.proxy.cleanup_traefik
|
execute *KAMAL.proxy.cleanup_traefik
|
||||||
@@ -106,7 +76,7 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|||||||
run_hook "pre-proxy-reboot", hosts: host_list
|
run_hook "pre-proxy-reboot", hosts: host_list
|
||||||
on(hosts) do |host|
|
on(hosts) do |host|
|
||||||
execute *KAMAL.auditor.record("Rebooted proxy"), verbosity: :debug
|
execute *KAMAL.auditor.record("Rebooted proxy"), verbosity: :debug
|
||||||
execute *KAMAL.registry.login
|
execute *KAMAL.registry.login unless KAMAL.config.registry.local?
|
||||||
|
|
||||||
"Stopping and removing Traefik on #{host}, if running..."
|
"Stopping and removing Traefik on #{host}, if running..."
|
||||||
execute *KAMAL.proxy.cleanup_traefik
|
execute *KAMAL.proxy.cleanup_traefik
|
||||||
@@ -199,7 +169,6 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|||||||
stop
|
stop
|
||||||
remove_container
|
remove_container
|
||||||
remove_image
|
remove_image
|
||||||
remove_proxy_directory
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -224,15 +193,6 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "remove_proxy_directory", "Remove the proxy directory from servers", hide: true
|
|
||||||
def remove_proxy_directory
|
|
||||||
with_lock do
|
|
||||||
on(KAMAL.proxy_hosts) do
|
|
||||||
execute *KAMAL.proxy.remove_proxy_directory, raise_on_non_zero_exit: false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
def removal_allowed?(force)
|
def removal_allowed?(force)
|
||||||
on(KAMAL.proxy_hosts) do |host|
|
on(KAMAL.proxy_hosts) do |host|
|
||||||
|
|||||||
@@ -1,17 +1,25 @@
|
|||||||
class Kamal::Cli::Registry < Kamal::Cli::Base
|
class Kamal::Cli::Registry < Kamal::Cli::Base
|
||||||
desc "login", "Log in to registry locally and remotely"
|
desc "login", "Setup local registry or log in to remote registry locally and remotely"
|
||||||
option :skip_local, aliases: "-L", type: :boolean, default: false, desc: "Skip local login"
|
option :skip_local, aliases: "-L", type: :boolean, default: false, desc: "Skip local login"
|
||||||
option :skip_remote, aliases: "-R", type: :boolean, default: false, desc: "Skip remote login"
|
option :skip_remote, aliases: "-R", type: :boolean, default: false, desc: "Skip remote login"
|
||||||
def login
|
def setup
|
||||||
run_locally { execute *KAMAL.registry.login } unless options[:skip_local]
|
if KAMAL.registry.local?
|
||||||
on(KAMAL.hosts) { execute *KAMAL.registry.login } unless options[:skip_remote]
|
run_locally { execute *KAMAL.registry.setup } unless options[:skip_local]
|
||||||
|
else
|
||||||
|
run_locally { execute *KAMAL.registry.login } unless options[:skip_local]
|
||||||
|
on(KAMAL.hosts) { execute *KAMAL.registry.login } unless options[:skip_remote]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "logout", "Log out of registry locally and remotely"
|
desc "remove", "Remove local registry or log out of remote registry locally and remotely"
|
||||||
option :skip_local, aliases: "-L", type: :boolean, default: false, desc: "Skip local login"
|
option :skip_local, aliases: "-L", type: :boolean, default: false, desc: "Skip local login"
|
||||||
option :skip_remote, aliases: "-R", type: :boolean, default: false, desc: "Skip remote login"
|
option :skip_remote, aliases: "-R", type: :boolean, default: false, desc: "Skip remote login"
|
||||||
def logout
|
def remove
|
||||||
run_locally { execute *KAMAL.registry.logout } unless options[:skip_local]
|
if KAMAL.registry.local?
|
||||||
on(KAMAL.hosts) { execute *KAMAL.registry.logout } unless options[:skip_remote]
|
run_locally { execute *KAMAL.registry.remove, raise_on_non_zero_exit: false } unless options[:skip_local]
|
||||||
|
else
|
||||||
|
run_locally { execute *KAMAL.registry.logout } unless options[:skip_local]
|
||||||
|
on(KAMAL.hosts) { execute *KAMAL.registry.logout } unless options[:skip_remote]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,22 +2,11 @@
|
|||||||
service: my-app
|
service: my-app
|
||||||
|
|
||||||
# Name of the container image.
|
# Name of the container image.
|
||||||
image: my-user/my-app
|
image: 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:
|
||||||
@@ -25,7 +14,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 (pulled from .kamal/secrets).
|
# Always use an access token rather than real password when possible.
|
||||||
password:
|
password:
|
||||||
- KAMAL_REGISTRY_PASSWORD
|
- KAMAL_REGISTRY_PASSWORD
|
||||||
|
|
||||||
@@ -33,44 +22,19 @@ registry:
|
|||||||
builder:
|
builder:
|
||||||
arch: amd64
|
arch: amd64
|
||||||
|
|
||||||
# Inject ENV variables into containers (secrets come from .kamal/secrets).
|
# Inject ENV variables into containers (secrets come from .env).
|
||||||
#
|
# 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 a persistent storage volume.
|
# Use accessory services (secrets come from .env).
|
||||||
#
|
|
||||||
# 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
|
||||||
@@ -92,3 +56,29 @@ 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 kamal-proxy on $KAMAL_HOSTS..."
|
echo "Rebooting Traefik on $KAMAL_HOSTS..."
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
# Secrets defined here are available for reference under registry/password, env/secret, builder/secrets,
|
# WARNING: Avoid adding secrets directly to this file
|
||||||
# and accessories/*/env/secret in config/deploy.yml. All secrets should be pulled from either
|
# If you must, then add `.kamal/secrets*` to your .gitignore file
|
||||||
# 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
|
||||||
|
|||||||
66
lib/kamal/cli/tunnel/remote_ports.rb
Normal file
66
lib/kamal/cli/tunnel/remote_ports.rb
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
Signal.trap "SIGPROF" do
|
||||||
|
Thread.list.each do |thread|
|
||||||
|
puts thread.name
|
||||||
|
puts thread.backtrace.map { |bt| " #{bt}" }
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
require "concurrent/map"
|
||||||
|
|
||||||
|
class Kamal::Cli::Tunnel::RemotePorts
|
||||||
|
attr_reader :hosts, :port
|
||||||
|
|
||||||
|
def initialize(hosts, port)
|
||||||
|
@hosts = hosts
|
||||||
|
@port = port
|
||||||
|
@open = false
|
||||||
|
end
|
||||||
|
|
||||||
|
def open
|
||||||
|
@open = true
|
||||||
|
@opened = Concurrent::Map.new
|
||||||
|
|
||||||
|
@threads = hosts.map do |host|
|
||||||
|
Thread.new do
|
||||||
|
Net::SSH.start(host, KAMAL.config.ssh.user) do |ssh|
|
||||||
|
forwarding = nil
|
||||||
|
ssh.forward.remote(port, "localhost", port, "localhost") do |actual_remote_port|
|
||||||
|
forwarding = !!actual_remote_port
|
||||||
|
:no_exception # will yield the exception on my own thread
|
||||||
|
end
|
||||||
|
ssh.loop { forwarding.nil? }
|
||||||
|
if forwarding
|
||||||
|
@opened[host] = true
|
||||||
|
ssh.loop(0.1) { @open }
|
||||||
|
|
||||||
|
ssh.forward.cancel_remote(port, "localhost")
|
||||||
|
ssh.loop(0.1) { ssh.forward.active_remotes.include?([ port, "localhost" ]) }
|
||||||
|
else
|
||||||
|
@opened[host] = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rescue => e
|
||||||
|
@opened[host] = false
|
||||||
|
|
||||||
|
puts e.message
|
||||||
|
puts e.backtrace
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
loop do
|
||||||
|
break if @opened.size == hosts.size
|
||||||
|
sleep 0.1
|
||||||
|
end
|
||||||
|
|
||||||
|
raise "Could not open tunnels on #{opened.reject { |k, v| v }.join(", ")}" unless @opened.values.all?
|
||||||
|
end
|
||||||
|
|
||||||
|
def close
|
||||||
|
p "Closing"
|
||||||
|
@open = false
|
||||||
|
p "Joining"
|
||||||
|
@threads.each(&:join)
|
||||||
|
p "Joined"
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -7,8 +7,9 @@ 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", "kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy",
|
||||||
"\$\(#{get_boot_options.join(" ")}\)",
|
*config.logging_args,
|
||||||
config.proxy_image
|
config.proxy_image
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -64,22 +65,6 @@ 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
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
class Kamal::Commands::Registry < Kamal::Commands::Base
|
class Kamal::Commands::Registry < Kamal::Commands::Base
|
||||||
delegate :registry, to: :config
|
delegate :registry, to: :config
|
||||||
|
delegate :local?, :local_port, to: :registry
|
||||||
|
|
||||||
def login
|
def login
|
||||||
docker :login,
|
docker :login,
|
||||||
@@ -11,4 +12,26 @@ class Kamal::Commands::Registry < Kamal::Commands::Base
|
|||||||
def logout
|
def logout
|
||||||
docker :logout, registry.server
|
docker :logout, registry.server
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def setup
|
||||||
|
combine \
|
||||||
|
docker(:start, "kamal-docker-registry"),
|
||||||
|
docker(:run, "--detach", "-p", "127.0.0.1:#{local_port}:5000", "--name", "kamal-docker-registry", "registry:2"),
|
||||||
|
by: "||"
|
||||||
|
end
|
||||||
|
|
||||||
|
def remove
|
||||||
|
combine \
|
||||||
|
docker(:stop, "kamal-docker-registry"),
|
||||||
|
docker(:rm, "kamal-docker-registry"),
|
||||||
|
by: "&&"
|
||||||
|
end
|
||||||
|
|
||||||
|
def logout
|
||||||
|
docker :logout, registry.server
|
||||||
|
end
|
||||||
|
|
||||||
|
def tunnel(host)
|
||||||
|
run_over_ssh "-R", "#{local_port}:localhost:#{local_port}", host: host
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class Kamal::Configuration
|
|||||||
|
|
||||||
include Validation
|
include Validation
|
||||||
|
|
||||||
PROXY_MINIMUM_VERSION = "v0.6.0"
|
PROXY_MINIMUM_VERSION = "v0.4.0"
|
||||||
PROXY_HTTP_PORT = 80
|
PROXY_HTTP_PORT = 80
|
||||||
PROXY_HTTPS_PORT = 443
|
PROXY_HTTPS_PORT = 443
|
||||||
|
|
||||||
@@ -246,12 +246,8 @@ class Kamal::Configuration
|
|||||||
env_tags.detect { |t| t.name == name.to_s }
|
env_tags.detect { |t| t.name == name.to_s }
|
||||||
end
|
end
|
||||||
|
|
||||||
def proxy_publish_args(http_port, https_port)
|
def proxy_publish_args
|
||||||
argumentize "--publish", [ "#{http_port}:#{PROXY_HTTP_PORT}", "#{https_port}:#{PROXY_HTTPS_PORT}" ]
|
argumentize "--publish", [ "#{PROXY_HTTP_PORT}:#{PROXY_HTTP_PORT}", "#{PROXY_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,14 +258,6 @@ class Kamal::Configuration
|
|||||||
"kamal-proxy"
|
"kamal-proxy"
|
||||||
end
|
end
|
||||||
|
|
||||||
def proxy_directory
|
|
||||||
File.join run_directory, "proxy"
|
|
||||||
end
|
|
||||||
|
|
||||||
def proxy_options_file
|
|
||||||
File.join proxy_directory, "options"
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
def to_h
|
def to_h
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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"] ? true : nil,
|
tls: proxy_config["ssl"],
|
||||||
"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")),
|
||||||
|
|||||||
@@ -21,6 +21,14 @@ class Kamal::Configuration::Registry
|
|||||||
lookup("password")
|
lookup("password")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def local?
|
||||||
|
server&.match?("^localhost[:$]")
|
||||||
|
end
|
||||||
|
|
||||||
|
def local_port
|
||||||
|
local? ? (server.split(":").last.to_i || 80) : nil
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def lookup(key)
|
def lookup(key)
|
||||||
if registry_config[key].is_a?(Array)
|
if registry_config[key].is_a?(Array)
|
||||||
|
|||||||
@@ -15,10 +15,12 @@ class Kamal::Configuration::Validator::Registry < Kamal::Configuration::Validato
|
|||||||
with_context(key) do
|
with_context(key) do
|
||||||
value = config[key]
|
value = config[key]
|
||||||
|
|
||||||
error "is required" unless value.present?
|
unless config["server"]&.match?("^localhost[:$]")
|
||||||
|
error "is required" unless value.present?
|
||||||
|
|
||||||
unless value.is_a?(String) || (value.is_a?(Array) && value.size == 1 && value.first.is_a?(String))
|
unless value.is_a?(String) || (value.is_a?(Array) && value.size == 1 && value.first.is_a?(String))
|
||||||
error "should be a string or an array with one string (for secret lookup)"
|
error "should be a string or an array with one string (for secret lookup)"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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 LastPass" unless $?.success?
|
raise RuntimeError, "Failed to login to 1Password" 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 LastPass" unless $?.success?
|
raise RuntimeError, "Could not read #{secrets} from 1Password" unless $?.success?
|
||||||
|
|
||||||
items = JSON.parse(items)
|
items = JSON.parse(items)
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module Kamal
|
module Kamal
|
||||||
VERSION = "2.0.0.rc4"
|
VERSION = "2.0.0.rc2"
|
||||||
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 to app-mysql/etc/mysql/my.cnf", output
|
assert_match "test/fixtures/files/my.cnf 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
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class CliMainTest < CliTestCase
|
|||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:server:bootstrap", [], invoke_options)
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:server:bootstrap", [], invoke_options)
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:accessory:boot", [ "all" ], invoke_options)
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:accessory:boot", [ "all" ], invoke_options)
|
||||||
# deploy
|
# deploy
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:login", [], invoke_options.merge(skip_local: true))
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:setup", [], invoke_options.merge(skip_local: true))
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:pull", [], invoke_options)
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:pull", [], invoke_options)
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:proxy:boot", [], invoke_options)
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:proxy:boot", [], invoke_options)
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true))
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true))
|
||||||
@@ -46,7 +46,7 @@ class CliMainTest < CliTestCase
|
|||||||
with_test_secrets("secrets" => "DB_PASSWORD=secret") do
|
with_test_secrets("secrets" => "DB_PASSWORD=secret") do
|
||||||
invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false, "verbose" => true }
|
invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false, "verbose" => true }
|
||||||
|
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:login", [], invoke_options.merge(skip_local: false))
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:setup", [], invoke_options.merge(skip_local: false))
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:deliver", [], invoke_options)
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:deliver", [], invoke_options)
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:proxy:boot", [], invoke_options)
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:proxy:boot", [], invoke_options)
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true))
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true))
|
||||||
@@ -72,7 +72,7 @@ class CliMainTest < CliTestCase
|
|||||||
test "deploy with skip_push" do
|
test "deploy with skip_push" do
|
||||||
invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false }
|
invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false }
|
||||||
|
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:login", [], invoke_options.merge(skip_local: true))
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:setup", [], invoke_options.merge(skip_local: true))
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:pull", [], invoke_options)
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:pull", [], invoke_options)
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:proxy:boot", [], invoke_options)
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:proxy:boot", [], invoke_options)
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true))
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true))
|
||||||
@@ -159,7 +159,7 @@ class CliMainTest < CliTestCase
|
|||||||
invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false, :skip_local => false }
|
invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => false, :skip_local => false }
|
||||||
|
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke)
|
Kamal::Cli::Main.any_instance.expects(:invoke)
|
||||||
.with("kamal:cli:registry:login", [], invoke_options.merge(skip_local: false))
|
.with("kamal:cli:registry:setup", [], invoke_options.merge(skip_local: false))
|
||||||
.raises(RuntimeError)
|
.raises(RuntimeError)
|
||||||
|
|
||||||
assert_not KAMAL.holding_lock?
|
assert_not KAMAL.holding_lock?
|
||||||
@@ -172,7 +172,7 @@ class CliMainTest < CliTestCase
|
|||||||
test "deploy with skipped hooks" do
|
test "deploy with skipped hooks" do
|
||||||
invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => true }
|
invoke_options = { "config_file" => "test/fixtures/deploy_simple.yml", "version" => "999", "skip_hooks" => true }
|
||||||
|
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:login", [], invoke_options.merge(skip_local: false))
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:setup", [], invoke_options.merge(skip_local: false))
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:deliver", [], invoke_options)
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:deliver", [], invoke_options)
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:proxy:boot", [], invoke_options)
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:proxy:boot", [], invoke_options)
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true))
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true))
|
||||||
@@ -187,7 +187,7 @@ class CliMainTest < CliTestCase
|
|||||||
test "deploy with missing secrets" do
|
test "deploy with missing secrets" do
|
||||||
invoke_options = { "config_file" => "test/fixtures/deploy_with_secrets.yml", "version" => "999", "skip_hooks" => false }
|
invoke_options = { "config_file" => "test/fixtures/deploy_with_secrets.yml", "version" => "999", "skip_hooks" => false }
|
||||||
|
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:login", [], invoke_options.merge(skip_local: false))
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:setup", [], invoke_options.merge(skip_local: false))
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:deliver", [], invoke_options)
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:deliver", [], invoke_options)
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:proxy:boot", [], invoke_options)
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:proxy:boot", [], invoke_options)
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true))
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true))
|
||||||
@@ -289,6 +289,16 @@ class CliMainTest < CliTestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "remove" do
|
||||||
|
options = { "config_file" => "test/fixtures/deploy_simple.yml", "skip_hooks" => false, "confirmed" => true }
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:proxy:remove", [], options)
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:remove", [], options)
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:accessory:remove", [ "all" ], options)
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:remove", [], options.merge(skip_local: true))
|
||||||
|
|
||||||
|
run_command("remove", "-y")
|
||||||
|
end
|
||||||
|
|
||||||
test "details" do
|
test "details" do
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:proxy:details")
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:proxy:details")
|
||||||
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:details")
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:details")
|
||||||
|
|||||||
@@ -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 --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
|
assert_match "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" #{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 --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
|
assert_match "docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" #{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 --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
|
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 kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" #{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 --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 run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume 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 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 --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 run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume 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 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
|
||||||
@@ -198,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 --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 "docker container start kamal-proxy || docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume 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 "/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 "Uploading \"\\n\" to .kamal/apps/app/env/roles/web.env", output
|
assert_match %r{/usr/bin/env .* .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
|
||||||
@@ -236,62 +236,6 @@ 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" ]) }
|
||||||
|
|||||||
@@ -1,50 +1,62 @@
|
|||||||
require_relative "cli_test_case"
|
require_relative "cli_test_case"
|
||||||
|
|
||||||
class CliRegistryTest < CliTestCase
|
class CliRegistryTest < CliTestCase
|
||||||
test "login" do
|
test "setup" do
|
||||||
run_command("login").tap do |output|
|
run_command("setup").tap do |output|
|
||||||
assert_match /docker login -u \[REDACTED\] -p \[REDACTED\] as .*@localhost/, output
|
assert_match /docker login -u \[REDACTED\] -p \[REDACTED\] as .*@localhost/, output
|
||||||
assert_match /docker login -u \[REDACTED\] -p \[REDACTED\] on 1.1.1.\d/, output
|
assert_match /docker login -u \[REDACTED\] -p \[REDACTED\] on 1.1.1.\d/, output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "login skip local" do
|
test "setup skip local" do
|
||||||
run_command("login", "-L").tap do |output|
|
run_command("setup", "-L").tap do |output|
|
||||||
assert_no_match /docker login -u \[REDACTED\] -p \[REDACTED\] as .*@localhost/, output
|
assert_no_match /docker login -u \[REDACTED\] -p \[REDACTED\] as .*@localhost/, output
|
||||||
assert_match /docker login -u \[REDACTED\] -p \[REDACTED\] on 1.1.1.\d/, output
|
assert_match /docker login -u \[REDACTED\] -p \[REDACTED\] on 1.1.1.\d/, output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "login skip remote" do
|
test "setup skip remote" do
|
||||||
run_command("login", "-R").tap do |output|
|
run_command("setup", "-R").tap do |output|
|
||||||
assert_match /docker login -u \[REDACTED\] -p \[REDACTED\] as .*@localhost/, output
|
assert_match /docker login -u \[REDACTED\] -p \[REDACTED\] as .*@localhost/, output
|
||||||
assert_no_match /docker login -u \[REDACTED\] -p \[REDACTED\] on 1.1.1.\d/, output
|
assert_no_match /docker login -u \[REDACTED\] -p \[REDACTED\] on 1.1.1.\d/, output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "logout" do
|
test "remove" do
|
||||||
run_command("logout").tap do |output|
|
run_command("remove").tap do |output|
|
||||||
assert_match /docker logout as .*@localhost/, output
|
assert_match /docker logout as .*@localhost/, output
|
||||||
assert_match /docker logout on 1.1.1.\d/, output
|
assert_match /docker logout on 1.1.1.\d/, output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "logout skip local" do
|
test "remove skip local" do
|
||||||
run_command("logout", "-L").tap do |output|
|
run_command("remove", "-L").tap do |output|
|
||||||
assert_no_match /docker logout as .*@localhost/, output
|
assert_no_match /docker logout as .*@localhost/, output
|
||||||
assert_match /docker logout on 1.1.1.\d/, output
|
assert_match /docker logout on 1.1.1.\d/, output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "logout skip remote" do
|
test "remove skip remote" do
|
||||||
run_command("logout", "-R").tap do |output|
|
run_command("remove", "-R").tap do |output|
|
||||||
assert_match /docker logout as .*@localhost/, output
|
assert_match /docker logout as .*@localhost/, output
|
||||||
assert_no_match /docker logout on 1.1.1.\d/, output
|
assert_no_match /docker logout on 1.1.1.\d/, output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "setup local registry" do
|
||||||
|
run_command("setup", fixture: :with_local_registry).tap do |output|
|
||||||
|
assert_match /docker start kamal-docker-registry || docker run --detach -p 127.0.0.1:5000:5000 --name kamal-docker-registry registry:2 as .*@localhost/, output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "remove local registry" do
|
||||||
|
run_command("remove", fixture: :with_local_registry).tap do |output|
|
||||||
|
assert_match /docker stop kamal-docker-registry && docker rm kamal-docker-registry as .*@localhost/, output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def run_command(*command)
|
def run_command(*command, fixture: :with_accessories)
|
||||||
stdouted { Kamal::Cli::Registry.start([ *command, "-c", "test/fixtures/deploy_with_accessories.yml" ]) }
|
stdouted { Kamal::Cli::Registry.start([ *command, "-c", "test/fixtures/deploy_#{fixture}.yml" ]) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -15,7 +15,13 @@ 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 --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}",
|
"docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" 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 kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION}",
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -23,7 +29,15 @@ 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 --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}",
|
"docker run --name kamal-proxy --network kamal --detach --restart unless-stopped --publish 80:80 --publish 443:443 --volume kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --log-opt max-size=\"10m\" 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 kamal-proxy-config:/home/kamal-proxy/.config/kamal-proxy --log-driver \"local\" --log-opt max-size=\"100m\" --log-opt max-file=\"3\" basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION}",
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -105,24 +119,6 @@ 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"))
|
||||||
|
|||||||
@@ -55,6 +55,15 @@ class CommandsRegistryTest < ActiveSupport::TestCase
|
|||||||
registry.logout.join(" ")
|
registry.logout.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "registry setup" do
|
||||||
|
@config[:registry] = { "server" => "localhost:5000" }
|
||||||
|
assert_equal "docker start kamal-docker-registry || docker run --detach -p 5000:5000 --name kamal-docker-registry registry:2", registry.setup.join(" ")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "registry remove" do
|
||||||
|
assert_equal "docker stop kamal-docker-registry && docker rm kamal-docker-registry", registry.remove.join(" ")
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def registry
|
def registry
|
||||||
Kamal::Commands::Registry.new Kamal::Configuration.new(@config)
|
Kamal::Commands::Registry.new Kamal::Configuration.new(@config)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
require "test_helper"
|
require "test_helper"
|
||||||
|
|
||||||
class ConfigurationProxyTest < ActiveSupport::TestCase
|
class ConfigurationEnvTest < 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,12 +18,6 @@ class ConfigurationProxyTest < 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)
|
||||||
|
|||||||
37
test/fixtures/deploy_with_local_registry.yml
vendored
Normal file
37
test/fixtures/deploy_with_local_registry.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
service: app
|
||||||
|
image: dhh/app
|
||||||
|
servers:
|
||||||
|
web:
|
||||||
|
- "1.1.1.1"
|
||||||
|
- "1.1.1.2"
|
||||||
|
workers:
|
||||||
|
- "1.1.1.3"
|
||||||
|
- "1.1.1.4"
|
||||||
|
registry:
|
||||||
|
server: localhost:5000
|
||||||
|
builder:
|
||||||
|
arch: amd64
|
||||||
|
|
||||||
|
accessories:
|
||||||
|
mysql:
|
||||||
|
image: mysql:5.7
|
||||||
|
host: 1.1.1.3
|
||||||
|
port: 3306
|
||||||
|
env:
|
||||||
|
clear:
|
||||||
|
MYSQL_ROOT_HOST: '%'
|
||||||
|
secret:
|
||||||
|
- MYSQL_ROOT_PASSWORD
|
||||||
|
files:
|
||||||
|
- test/fixtures/files/my.cnf:/etc/mysql/my.cnf
|
||||||
|
directories:
|
||||||
|
- data:/var/lib/mysql
|
||||||
|
redis:
|
||||||
|
image: redis:latest
|
||||||
|
roles:
|
||||||
|
- web
|
||||||
|
port: 6379
|
||||||
|
directories:
|
||||||
|
- data:/data
|
||||||
|
|
||||||
|
readiness_delay: 0
|
||||||
@@ -27,14 +27,14 @@ class AppTest < IntegrationTest
|
|||||||
images = kamal :app, :images, capture: true
|
images = kamal :app, :images, capture: true
|
||||||
assert_match "App Host: vm1", images
|
assert_match "App Host: vm1", images
|
||||||
assert_match "App Host: vm2", images
|
assert_match "App Host: vm2", images
|
||||||
assert_match /registry:4443\/app\s+#{latest_app_version}/, images
|
assert_match /localhost:5000\/app\s+#{latest_app_version}/, images
|
||||||
assert_match /registry:4443\/app\s+latest/, images
|
assert_match /localhost:5000\/app\s+latest/, images
|
||||||
|
|
||||||
containers = kamal :app, :containers, capture: true
|
containers = kamal :app, :containers, capture: true
|
||||||
assert_match "App Host: vm1", containers
|
assert_match "App Host: vm1", containers
|
||||||
assert_match "App Host: vm2", containers
|
assert_match "App Host: vm2", containers
|
||||||
assert_match "registry:4443/app:#{latest_app_version}", containers
|
assert_match "localhost:5000/app:#{latest_app_version}", containers
|
||||||
assert_match "registry:4443/app:latest", containers
|
assert_match "localhost:5000/app:latest", containers
|
||||||
|
|
||||||
exec_output = kamal :app, :exec, :ps, capture: true
|
exec_output = kamal :app, :exec, :ps, capture: true
|
||||||
assert_match "App Host: vm1", exec_output
|
assert_match "App Host: vm1", exec_output
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ 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
|
||||||
@@ -29,7 +28,6 @@ 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 kamal-proxy on ${KAMAL_HOSTS}..."
|
echo "Rebooting Traefik 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
|
||||||
|
|||||||
@@ -26,9 +26,7 @@ readiness_delay: 0
|
|||||||
proxy:
|
proxy:
|
||||||
host: 127.0.0.1
|
host: 127.0.0.1
|
||||||
registry:
|
registry:
|
||||||
server: registry:4443
|
server: localhost:5000
|
||||||
username: root
|
|
||||||
password: root
|
|
||||||
builder:
|
builder:
|
||||||
driver: docker
|
driver: docker
|
||||||
arch: <%= Kamal::Utils.docker_arch %>
|
arch: <%= Kamal::Utils.docker_arch %>
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
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\(\`/\`\)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
SECRET_TOKEN='1234 with "中文"'
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -169,8 +169,10 @@ class IntegrationTest < ActiveSupport::TestCase
|
|||||||
case app
|
case app
|
||||||
when "app"
|
when "app"
|
||||||
"127.0.0.1"
|
"127.0.0.1"
|
||||||
else
|
when "app_with_roles"
|
||||||
"localhost"
|
"localhost"
|
||||||
|
else
|
||||||
|
raise "Unknown app: #{app}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class MainTest < IntegrationTest
|
|||||||
assert_match /App Host: vm1/, details
|
assert_match /App Host: vm1/, details
|
||||||
assert_match /App Host: vm2/, details
|
assert_match /App Host: vm2/, details
|
||||||
assert_match /basecamp\/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION}/, details
|
assert_match /basecamp\/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION}/, details
|
||||||
assert_match /registry:4443\/app:#{first_version}/, details
|
assert_match /localhost:5000\/app:#{first_version}/, details
|
||||||
|
|
||||||
audit = kamal :audit, capture: true
|
audit = kamal :audit, capture: true
|
||||||
assert_match /Booted app version #{first_version}.*Booted app version #{second_version}.*Booted app version #{first_version}.*/m, audit
|
assert_match /Booted app version #{first_version}.*Booted app version #{second_version}.*Booted app version #{first_version}.*/m, audit
|
||||||
@@ -63,8 +63,8 @@ class MainTest < IntegrationTest
|
|||||||
assert_equal [ "vm1", "vm2" ], config[:hosts]
|
assert_equal [ "vm1", "vm2" ], config[:hosts]
|
||||||
assert_equal "vm1", config[:primary_host]
|
assert_equal "vm1", config[:primary_host]
|
||||||
assert_equal version, config[:version]
|
assert_equal version, config[:version]
|
||||||
assert_equal "registry:4443/app", config[:repository]
|
assert_equal "localhost:5000/app", config[:repository]
|
||||||
assert_equal "registry:4443/app:#{version}", config[:absolute_image]
|
assert_equal "localhost:5000/app:#{version}", config[:absolute_image]
|
||||||
assert_equal "app-#{version}", config[:service_with_version]
|
assert_equal "app-#{version}", config[:service_with_version]
|
||||||
assert_equal [], config[:volume_args]
|
assert_equal [], config[:volume_args]
|
||||||
assert_equal({ user: "root", port: 22, keepalive: true, keepalive_interval: 30, log_level: :fatal }, config[:ssh_options])
|
assert_equal({ user: "root", port: 22, keepalive: true, keepalive_interval: 30, log_level: :fatal }, config[:ssh_options])
|
||||||
@@ -88,14 +88,6 @@ 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
|
||||||
@@ -131,15 +123,6 @@ class MainTest < IntegrationTest
|
|||||||
assert_proxy_not_running
|
assert_proxy_not_running
|
||||||
end
|
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
|
|
||||||
|
|
||||||
private
|
private
|
||||||
def assert_envs(version:)
|
def assert_envs(version:)
|
||||||
assert_env :CLEAR_TOKEN, "4321", version: version, vm: :vm1
|
assert_env :CLEAR_TOKEN, "4321", version: version, vm: :vm1
|
||||||
|
|||||||
@@ -13,13 +13,6 @@ 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