Compare commits
1 Commits
v2.2.2
...
command-li
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff24fd9874 |
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
@@ -27,7 +27,6 @@ jobs:
|
||||
- "3.1"
|
||||
- "3.2"
|
||||
- "3.3"
|
||||
- "3.4.0-preview2"
|
||||
gemfile:
|
||||
- Gemfile
|
||||
- gemfiles/rails_edge.gemfile
|
||||
@@ -42,9 +41,6 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Remove gemfile.lock
|
||||
run: rm Gemfile.lock
|
||||
|
||||
- name: Install Ruby
|
||||
uses: ruby/setup-ruby@v1
|
||||
with:
|
||||
@@ -53,5 +49,3 @@ jobs:
|
||||
|
||||
- name: Run tests
|
||||
run: bin/test
|
||||
env:
|
||||
RUBYOPT: ${{ startsWith(matrix.ruby-version, '3.4.') && '--enable=frozen-string-literal' || '' }}
|
||||
|
||||
@@ -33,7 +33,7 @@ WORKDIR /workdir
|
||||
|
||||
# Tell git it's safe to access /workdir/.git even if
|
||||
# the directory is owned by a different user
|
||||
RUN git config --global --add safe.directory '*'
|
||||
RUN git config --global --add safe.directory /workdir
|
||||
|
||||
# Set the entrypoint to run the installed binary in /workdir
|
||||
# Example: docker run -it -v "$PWD:/workdir" kamal init
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
kamal (2.2.2)
|
||||
kamal (2.0.0)
|
||||
activesupport (>= 7.0)
|
||||
base64 (~> 0.2)
|
||||
bcrypt_pbkdf (~> 1.0)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require "active_support/core_ext/array/conversions"
|
||||
|
||||
class Kamal::Cli::Accessory < Kamal::Cli::Base
|
||||
desc "boot [NAME]", "Boot new accessory service on host (use NAME=all to boot all accessories)"
|
||||
def boot(name, prepare: true)
|
||||
|
||||
@@ -68,7 +68,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
||||
version = capture_with_info(*app.current_running_version, raise_on_non_zero_exit: false).strip
|
||||
endpoint = capture_with_info(*app.container_id_for_version(version)).strip
|
||||
if endpoint.present?
|
||||
execute *app.remove, raise_on_non_zero_exit: false
|
||||
execute *app.remove(target: endpoint), raise_on_non_zero_exit: false
|
||||
end
|
||||
end
|
||||
|
||||
@@ -203,7 +203,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
||||
run_locally do
|
||||
info "Following logs on #{KAMAL.primary_host}..."
|
||||
|
||||
KAMAL.specific_roles ||= [ KAMAL.primary_role.name ]
|
||||
KAMAL.specific_roles ||= [ "web" ]
|
||||
role = KAMAL.roles_on(KAMAL.primary_host).first
|
||||
|
||||
app = KAMAL.app(role: role, host: host)
|
||||
|
||||
@@ -135,7 +135,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
||||
puts "No documentation found for #{section}"
|
||||
end
|
||||
|
||||
desc "init", "Create config stub in config/deploy.yml and secrets stub in .kamal"
|
||||
desc "init", "Create config stub in config/deploy.yml and env stub in .env"
|
||||
option :bundle, type: :boolean, default: false, desc: "Add Kamal to the Gemfile and create a bin/kamal binstub"
|
||||
def init
|
||||
require "fileutils"
|
||||
|
||||
@@ -21,18 +21,16 @@ class Kamal::Cli::Proxy < Kamal::Cli::Base
|
||||
end
|
||||
end
|
||||
|
||||
desc "boot_config <set|get|reset>", "Manage kamal-proxy boot configuration"
|
||||
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 :log_max_size, type: :string, default: Kamal::Configuration::PROXY_LOG_MAX_SIZE, desc: "Max size of proxy logs"
|
||||
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]),
|
||||
*(KAMAL.config.proxy_logging_args(options[:log_max_size])),
|
||||
*options[:docker_options].map { |option| "--#{option}" }
|
||||
]
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ class Kamal::Cli::Secrets < Kamal::Cli::Base
|
||||
def fetch(*secrets)
|
||||
results = adapter(options[:adapter]).fetch(secrets, **options.slice(:account, :from).symbolize_keys)
|
||||
|
||||
return_or_puts JSON.dump(results).shellescape, inline: options[:inline]
|
||||
return_or_puts JSON.dump(results), inline: options[:inline]
|
||||
end
|
||||
|
||||
desc "extract", "Extract a single secret from the results of a fetch call"
|
||||
@@ -21,13 +21,6 @@ class Kamal::Cli::Secrets < Kamal::Cli::Base
|
||||
return_or_puts value, inline: options[:inline]
|
||||
end
|
||||
|
||||
desc "print", "Print the secrets (for debugging)"
|
||||
def print
|
||||
KAMAL.config.secrets.to_h.each do |key, value|
|
||||
puts "#{key}=#{value}"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def adapter(adapter)
|
||||
Kamal::Secrets::Adapters.lookup(adapter)
|
||||
|
||||
@@ -14,13 +14,10 @@ servers:
|
||||
# cmd: bin/jobs
|
||||
|
||||
# Enable SSL auto certification via Let's Encrypt (and allow for multiple apps on one server).
|
||||
# If using something like Cloudflare, it is recommended to set encryption mode
|
||||
# in Cloudflare's SSL/TLS setting to "Full" to enable end-to-end encryption.
|
||||
proxy:
|
||||
# Set ssl: false if using something like Cloudflare to terminate SSL (but keep host!).
|
||||
proxy:
|
||||
ssl: true
|
||||
host: app.example.com
|
||||
# kamal-proxy connects to your container over port 80, use `app_port` to specify a different port.
|
||||
# app_port: 3000
|
||||
|
||||
# Credentials for your image host.
|
||||
registry:
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
echo "Docker set up on $KAMAL_HOSTS..."
|
||||
# A sample docker-setup hook
|
||||
#
|
||||
# Sets up a Docker network on defined hosts which can then be used by the application’s containers
|
||||
|
||||
hosts = ENV["KAMAL_HOSTS"].split(",")
|
||||
|
||||
hosts.each do |ip|
|
||||
destination = "root@#{ip}"
|
||||
puts "Creating a Docker network \"kamal\" on #{destination}"
|
||||
`ssh #{destination} docker network create kamal`
|
||||
end
|
||||
|
||||
@@ -43,12 +43,7 @@ class Kamal::Commander::Specifics
|
||||
end
|
||||
|
||||
def specified_hosts
|
||||
specified_hosts = specific_hosts || config.all_hosts
|
||||
|
||||
if (specific_role_hosts = specific_roles&.flat_map(&:hosts)).present?
|
||||
specified_hosts.select { |host| specific_role_hosts.include?(host) }
|
||||
else
|
||||
specified_hosts
|
||||
end
|
||||
(specific_hosts || config.all_hosts) \
|
||||
.select { |host| (specific_roles || config.roles).flat_map(&:hosts).include?(host) }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,8 +5,8 @@ module Kamal::Commands::App::Proxy
|
||||
proxy_exec :deploy, role.container_prefix, *role.proxy.deploy_command_args(target: target)
|
||||
end
|
||||
|
||||
def remove
|
||||
proxy_exec :remove, role.container_prefix
|
||||
def remove(target:)
|
||||
proxy_exec :remove, role.container_prefix, *role.proxy.remove_command_args(target: target)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -11,7 +11,14 @@ module Kamal::Commands
|
||||
end
|
||||
|
||||
def run_over_ssh(*command, host:)
|
||||
"ssh#{ssh_proxy_args} -t #{config.ssh.user}@#{host} -p #{config.ssh.port} '#{command.join(" ").gsub("'", "'\\\\''")}'"
|
||||
"ssh".tap do |cmd|
|
||||
if config.ssh.proxy && config.ssh.proxy.is_a?(Net::SSH::Proxy::Jump)
|
||||
cmd << " -J #{config.ssh.proxy.jump_proxies}"
|
||||
elsif config.ssh.proxy && config.ssh.proxy.is_a?(Net::SSH::Proxy::Command)
|
||||
cmd << " -o ProxyCommand='#{config.ssh.proxy.command_line_template}'"
|
||||
end
|
||||
cmd << " -t #{config.ssh.user}@#{host} -p #{config.ssh.port} '#{command.join(" ").gsub("'", "'\\\\''")}'"
|
||||
end
|
||||
end
|
||||
|
||||
def container_id_for(container_name:, only_running: false)
|
||||
@@ -85,14 +92,5 @@ module Kamal::Commands
|
||||
def tags(**details)
|
||||
Kamal::Tags.from_config(config, **details)
|
||||
end
|
||||
|
||||
def ssh_proxy_args
|
||||
case config.ssh.proxy
|
||||
when Net::SSH::Proxy::Jump
|
||||
" -J #{config.ssh.proxy.jump_proxies}"
|
||||
when Net::SSH::Proxy::Command
|
||||
" -o ProxyCommand='#{config.ssh.proxy.command_line_template}'"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
module Kamal::Commands::Builder::Clone
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
delegate :clone_directory, :build_directory, to: :"config.builder"
|
||||
end
|
||||
|
||||
def clone
|
||||
git :clone, escaped_root, "--recurse-submodules", path: config.builder.clone_directory.shellescape
|
||||
git :clone, Kamal::Git.root, "--recurse-submodules", path: clone_directory
|
||||
end
|
||||
|
||||
def clone_reset_steps
|
||||
[
|
||||
git(:remote, "set-url", :origin, escaped_root, path: escaped_build_directory),
|
||||
git(:fetch, :origin, path: escaped_build_directory),
|
||||
git(:reset, "--hard", Kamal::Git.revision, path: escaped_build_directory),
|
||||
git(:clean, "-fdx", path: escaped_build_directory),
|
||||
git(:submodule, :update, "--init", path: escaped_build_directory)
|
||||
git(:remote, "set-url", :origin, Kamal::Git.root, path: build_directory),
|
||||
git(:fetch, :origin, path: build_directory),
|
||||
git(:reset, "--hard", Kamal::Git.revision, path: build_directory),
|
||||
git(:clean, "-fdx", path: build_directory),
|
||||
git(:submodule, :update, "--init", path: build_directory)
|
||||
]
|
||||
end
|
||||
|
||||
def clone_status
|
||||
git :status, "--porcelain", path: escaped_build_directory
|
||||
git :status, "--porcelain", path: build_directory
|
||||
end
|
||||
|
||||
def clone_revision
|
||||
git :"rev-parse", :HEAD, path: escaped_build_directory
|
||||
end
|
||||
|
||||
def escaped_root
|
||||
Kamal::Git.root.shellescape
|
||||
end
|
||||
|
||||
def escaped_build_directory
|
||||
config.builder.build_directory.shellescape
|
||||
git :"rev-parse", :HEAD, path: build_directory
|
||||
end
|
||||
end
|
||||
|
||||
@@ -14,15 +14,12 @@ class Kamal::Configuration
|
||||
|
||||
include Validation
|
||||
|
||||
PROXY_MINIMUM_VERSION = "v0.8.1"
|
||||
PROXY_MINIMUM_VERSION = "v0.6.0"
|
||||
PROXY_HTTP_PORT = 80
|
||||
PROXY_HTTPS_PORT = 443
|
||||
PROXY_LOG_MAX_SIZE = "10m"
|
||||
|
||||
class << self
|
||||
def create_from(config_file:, destination: nil, version: nil)
|
||||
ENV["KAMAL_DESTINATION"] = destination
|
||||
|
||||
raw_config = load_config_files(config_file, *destination_config_file(config_file, destination))
|
||||
|
||||
new raw_config, destination: destination, version: version
|
||||
@@ -253,12 +250,8 @@ class Kamal::Configuration
|
||||
argumentize "--publish", [ "#{http_port}:#{PROXY_HTTP_PORT}", "#{https_port}:#{PROXY_HTTPS_PORT}" ]
|
||||
end
|
||||
|
||||
def proxy_logging_args(max_size)
|
||||
argumentize "--log-opt", "max-size=#{max_size}"
|
||||
end
|
||||
|
||||
def proxy_options_default
|
||||
[ *proxy_publish_args(PROXY_HTTP_PORT, PROXY_HTTPS_PORT), *proxy_logging_args(PROXY_LOG_MAX_SIZE) ]
|
||||
proxy_publish_args PROXY_HTTP_PORT, PROXY_HTTPS_PORT
|
||||
end
|
||||
|
||||
def proxy_image
|
||||
@@ -367,7 +360,7 @@ class Kamal::Configuration
|
||||
end
|
||||
|
||||
def ensure_unique_hosts_for_ssl_roles
|
||||
hosts = roles.select(&:ssl?).flat_map { |role| role.proxy.hosts }
|
||||
hosts = roles.select(&:ssl?).map { |role| role.proxy.host }
|
||||
duplicates = hosts.tally.filter_map { |host, count| host if count > 1 }
|
||||
|
||||
raise Kamal::ConfigurationError, "Different roles can't share the same host for SSL: #{duplicates.join(", ")}" if duplicates.any?
|
||||
|
||||
@@ -17,19 +17,16 @@
|
||||
# `proxy: true` or providing a proxy configuration.
|
||||
proxy:
|
||||
|
||||
# Hosts
|
||||
# Host
|
||||
#
|
||||
# The hosts that will be used to serve the app. The proxy will only route requests
|
||||
# to this host to your app.
|
||||
#
|
||||
# If no hosts are set, then all requests will be forwarded, except for matching
|
||||
# requests for other apps deployed on that server that do have a host set.
|
||||
#
|
||||
# Specify one of `host` or `hosts`.
|
||||
host: foo.example.com
|
||||
hosts:
|
||||
- foo.example.com
|
||||
- bar.example.com
|
||||
# If multiple hosts are needed, these can be specified by comma-separating the hosts.
|
||||
host: foo.example.com,bar.example.com
|
||||
|
||||
# App port
|
||||
#
|
||||
|
||||
@@ -61,10 +61,3 @@ ssh:
|
||||
# An array of strings, with each element of the array being
|
||||
# a raw private key in PEM format.
|
||||
key_data: [ "-----BEGIN OPENSSH PRIVATE KEY-----" ]
|
||||
|
||||
# Config
|
||||
#
|
||||
# Set to true to load the default OpenSSH config files (~/.ssh/config,
|
||||
# /etc/ssh_config), to false ignore config files, or to a file path
|
||||
# (or array of paths) to load specific configuration. Defaults to true.
|
||||
config: true
|
||||
|
||||
@@ -22,14 +22,14 @@ class Kamal::Configuration::Proxy
|
||||
proxy_config.fetch("ssl", false)
|
||||
end
|
||||
|
||||
def hosts
|
||||
proxy_config["hosts"] || proxy_config["host"]&.split(",") || []
|
||||
def host
|
||||
proxy_config["host"]
|
||||
end
|
||||
|
||||
def deploy_options
|
||||
{
|
||||
host: hosts,
|
||||
tls: proxy_config["ssl"].presence,
|
||||
host: proxy_config["host"],
|
||||
tls: proxy_config["ssl"] ? true : nil,
|
||||
"deploy-timeout": seconds_duration(config.deploy_timeout),
|
||||
"drain-timeout": seconds_duration(config.drain_timeout),
|
||||
"health-check-interval": seconds_duration(proxy_config.dig("healthcheck", "interval")),
|
||||
@@ -48,7 +48,11 @@ class Kamal::Configuration::Proxy
|
||||
end
|
||||
|
||||
def deploy_command_args(target:)
|
||||
optionize ({ target: "#{target}:#{app_port}" }).merge(deploy_options), with: "="
|
||||
optionize ({ target: "#{target}:#{app_port}" }).merge(deploy_options)
|
||||
end
|
||||
|
||||
def remove_command_args(target:)
|
||||
optionize({ target: "#{target}:#{app_port}" })
|
||||
end
|
||||
|
||||
def merge(other)
|
||||
|
||||
@@ -3,13 +3,9 @@ class Kamal::Configuration::Validator::Proxy < Kamal::Configuration::Validator
|
||||
unless config.nil?
|
||||
super
|
||||
|
||||
if config["host"].blank? && config["hosts"].blank? && config["ssl"]
|
||||
if config["host"].blank? && config["ssl"]
|
||||
error "Must set a host to enable automatic SSL"
|
||||
end
|
||||
|
||||
if (config.keys & [ "host", "hosts" ]).size > 1
|
||||
error "Specify one of 'host' or 'hosts', not both"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -35,10 +35,8 @@ class Kamal::Secrets::Adapters::Bitwarden < Kamal::Secrets::Adapters::Base
|
||||
value = item_field["value"]
|
||||
results["#{item}/#{field}"] = value
|
||||
end
|
||||
elsif item_json.dig("login", "password")
|
||||
results[item] = item_json.dig("login", "password")
|
||||
else
|
||||
raise RuntimeError, "Item #{item} is not a login type item and no fields were specified"
|
||||
results[item] = item_json["login"]["password"]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -16,7 +16,7 @@ class Kamal::Secrets::Dotenv::InlineCommandSubstitution
|
||||
else
|
||||
if command =~ /\A\s*kamal\s*secrets\s+/
|
||||
# Inline the command
|
||||
inline_secrets_command(command)
|
||||
inline_secrets_command(command).shellescape
|
||||
else
|
||||
# Execute the command and return the value
|
||||
`#{command}`.chomp
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
module Kamal
|
||||
VERSION = "2.2.2"
|
||||
VERSION = "2.0.0"
|
||||
end
|
||||
|
||||
@@ -130,7 +130,7 @@ class CliAppTest < CliTestCase
|
||||
SSHKit::Backend::Abstract.any_instance.stubs(:execute)
|
||||
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-web-latest$", "--quiet", "|", :xargs, :docker, :stop, raise_on_non_zero_exit: false)
|
||||
SSHKit::Backend::Abstract.any_instance.expects(:execute)
|
||||
.with(:docker, :exec, "kamal-proxy", "kamal-proxy", :deploy, "app-web", "--target=\"123:80\"", "--deploy-timeout=\"1s\"", "--drain-timeout=\"30s\"", "--buffer-requests", "--buffer-responses", "--log-request-header=\"Cache-Control\"", "--log-request-header=\"Last-Modified\"", "--log-request-header=\"User-Agent\"").raises(SSHKit::Command::Failed.new("Failed to deploy"))
|
||||
.with(:docker, :exec, "kamal-proxy", "kamal-proxy", :deploy, "app-web", "--target", "\"123:80\"", "--deploy-timeout", "\"1s\"", "--drain-timeout", "\"30s\"", "--buffer-requests", "--buffer-responses", "--log-request-header", "\"Cache-Control\"", "--log-request-header", "\"Last-Modified\"", "--log-request-header", "\"User-Agent\"").raises(SSHKit::Command::Failed.new("Failed to deploy"))
|
||||
|
||||
stderred do
|
||||
run_command("boot", config: :with_roles, host: nil, allow_execute_error: true).tap do |output|
|
||||
@@ -190,7 +190,7 @@ class CliAppTest < CliTestCase
|
||||
|
||||
run_command("start").tap do |output|
|
||||
assert_match "docker start app-web-999", output
|
||||
assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"999:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\"", output
|
||||
assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target \"999:80\" --deploy-timeout \"30s\" --drain-timeout \"30s\" --buffer-requests --buffer-responses --log-request-header \"Cache-Control\" --log-request-header \"Last-Modified\"", output
|
||||
end
|
||||
end
|
||||
|
||||
@@ -383,7 +383,7 @@ class CliAppTest < CliTestCase
|
||||
assert_match /Renaming container .* to .* as already deployed on 1.1.1.1/, output # Rename
|
||||
assert_match /docker rename app-web-latest app-web-latest_replaced_[0-9a-f]{16}/, output
|
||||
assert_match /docker run --detach --restart unless-stopped --name app-web-latest --network kamal --hostname 1.1.1.1-[0-9a-f]{12} -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="123:80"/, output
|
||||
assert_match /docker exec kamal-proxy kamal-proxy deploy app-web --target "123:80"/, output
|
||||
assert_match "docker container ls --all --filter name=^app-web-123$ --quiet | xargs docker stop", output
|
||||
end
|
||||
end
|
||||
@@ -392,8 +392,8 @@ class CliAppTest < CliTestCase
|
||||
SSHKit::Backend::Abstract.any_instance.stubs(:capture_with_info).returns("123") # old version
|
||||
|
||||
run_command("boot", config: :with_proxy_roles, host: nil).tap do |output|
|
||||
assert_match "docker exec kamal-proxy kamal-proxy deploy app-web --target=\"123:80\" --deploy-timeout=\"6s\" --drain-timeout=\"30s\" --target-timeout=\"10s\" --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-web2 --target=\"123:80\" --deploy-timeout=\"6s\" --drain-timeout=\"30s\" --target-timeout=\"15s\" --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 \"123:80\" --deploy-timeout \"6s\" --drain-timeout \"30s\" --target-timeout \"10s\" --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-web2 --target \"123:80\" --deploy-timeout \"6s\" --drain-timeout \"30s\" --target-timeout \"15s\" --buffer-requests --buffer-responses --log-request-header \"Cache-Control\" --log-request-header \"Last-Modified\" --log-request-header \"User-Agent\"", output
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ class CliProxyTest < CliTestCase
|
||||
test "boot" do
|
||||
run_command("boot").tap do |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 --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
|
||||
|
||||
@@ -18,7 +18,7 @@ class CliProxyTest < CliTestCase
|
||||
exception = assert_raises do
|
||||
run_command("boot").tap do |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 --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
|
||||
|
||||
@@ -36,7 +36,7 @@ class CliProxyTest < CliTestCase
|
||||
|
||||
run_command("boot").tap do |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 --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
|
||||
ensure
|
||||
Thread.report_on_exception = false
|
||||
@@ -57,14 +57,14 @@ class CliProxyTest < CliTestCase
|
||||
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 "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 --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 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 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 "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 --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 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
|
||||
end
|
||||
end
|
||||
|
||||
@@ -198,13 +198,13 @@ class CliProxyTest < CliTestCase
|
||||
assert_match "/usr/bin/env mkdir -p .kamal", output
|
||||
assert_match "docker network create kamal", 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 --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 %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 "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 "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 tag dhh/app:latest dhh/app:latest", output
|
||||
assert_match "/usr/bin/env mkdir -p .kamal", output
|
||||
@@ -240,7 +240,7 @@ class CliProxyTest < CliTestCase
|
||||
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 --log-opt max-size=10m\" to .kamal/proxy/options on #{host}", output
|
||||
assert_match "Uploading \"--publish 80:80 --publish 443:443\" to .kamal/proxy/options on #{host}", output
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -249,16 +249,7 @@ class CliProxyTest < CliTestCase
|
||||
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 \"--log-opt max-size=10m\" to .kamal/proxy/options on #{host}", output
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "boot_config set custom max_size" do
|
||||
run_command("boot_config", "set", "--log-max-size", "100m").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 --log-opt max-size=100m\" to .kamal/proxy/options on #{host}", output
|
||||
assert_match "Uploading \"\" to .kamal/proxy/options on #{host}", output
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -267,7 +258,7 @@ class CliProxyTest < CliTestCase
|
||||
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 --log-opt max-size=10m\" to .kamal/proxy/options on #{host}", output
|
||||
assert_match "Uploading \"--publish 8080:80 --publish 8443:443\" to .kamal/proxy/options on #{host}", output
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -276,14 +267,14 @@ class CliProxyTest < CliTestCase
|
||||
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 --log-opt max-size=10m --label=foo=bar --add_host=thishost:thathost\" to .kamal/proxy/options 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 --log-opt max-size=10m\"")
|
||||
.with(:cat, ".kamal/proxy/options", "||", :echo, "\"--publish 80:80 --publish 443:443\"")
|
||||
.returns("--publish 80:80 --publish 8443:443 --label=foo=bar")
|
||||
.twice
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ require_relative "cli_test_case"
|
||||
class CliSecretsTest < CliTestCase
|
||||
test "fetch" do
|
||||
assert_equal \
|
||||
"\\{\\\"foo\\\":\\\"oof\\\",\\\"bar\\\":\\\"rab\\\",\\\"baz\\\":\\\"zab\\\"\\}",
|
||||
"{\"foo\":\"oof\",\"bar\":\"rab\",\"baz\":\"zab\"}",
|
||||
run_command("fetch", "foo", "bar", "baz", "--account", "myaccount", "--adapter", "test")
|
||||
end
|
||||
|
||||
@@ -15,12 +15,6 @@ class CliSecretsTest < CliTestCase
|
||||
assert_equal "oof", run_command("extract", "foo", "{\"abc/foo\":\"oof\", \"bar\":\"rab\", \"baz\":\"zab\"}")
|
||||
end
|
||||
|
||||
test "print" do
|
||||
with_test_secrets("secrets" => "SECRET1=ABC\nSECRET2=${SECRET1}DEF\n") do
|
||||
assert_equal "SECRET1=ABC\nSECRET2=ABCDEF", run_command("print")
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def run_command(*command)
|
||||
stdouted { Kamal::Cli::Secrets.start([ *command, "-c", "test/fixtures/deploy_with_accessories.yml" ]) }
|
||||
|
||||
@@ -150,27 +150,6 @@ class CommanderTest < ActiveSupport::TestCase
|
||||
assert_equal [ "1.1.1.2" ], @kamal.proxy_hosts
|
||||
end
|
||||
|
||||
test "accessory hosts without filtering" do
|
||||
configure_with(:deploy_with_single_accessory)
|
||||
assert_equal [ "1.1.1.5" ], @kamal.accessory_hosts
|
||||
|
||||
configure_with(:deploy_with_accessories_on_independent_server)
|
||||
assert_equal [ "1.1.1.5", "1.1.1.1", "1.1.1.2" ], @kamal.accessory_hosts
|
||||
end
|
||||
|
||||
test "accessory hosts with role filtering" do
|
||||
configure_with(:deploy_with_single_accessory)
|
||||
@kamal.specific_roles = [ "web" ]
|
||||
assert_equal [], @kamal.accessory_hosts
|
||||
|
||||
configure_with(:deploy_with_accessories_on_independent_server)
|
||||
@kamal.specific_roles = [ "web" ]
|
||||
assert_equal [ "1.1.1.1", "1.1.1.2" ], @kamal.accessory_hosts
|
||||
|
||||
@kamal.specific_roles = [ "workers" ]
|
||||
assert_equal [], @kamal.accessory_hosts
|
||||
end
|
||||
|
||||
private
|
||||
def configure_with(variant)
|
||||
@kamal = Kamal::Commander.new.tap do |kamal|
|
||||
|
||||
@@ -115,38 +115,14 @@ class CommandsAppTest < ActiveSupport::TestCase
|
||||
|
||||
test "deploy" do
|
||||
assert_equal \
|
||||
"docker exec kamal-proxy kamal-proxy deploy app-web --target=\"172.1.0.2:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"",
|
||||
new_command.deploy(target: "172.1.0.2").join(" ")
|
||||
end
|
||||
|
||||
test "deploy with SSL" do
|
||||
@config[:proxy] = { "ssl" => true, "host" => "example.com" }
|
||||
|
||||
assert_equal \
|
||||
"docker exec kamal-proxy kamal-proxy deploy app-web --target=\"172.1.0.2:80\" --host=\"example.com\" --tls --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"",
|
||||
new_command.deploy(target: "172.1.0.2").join(" ")
|
||||
end
|
||||
|
||||
test "deploy with SSL targeting multiple hosts" do
|
||||
@config[:proxy] = { "ssl" => true, "hosts" => [ "example.com", "anotherexample.com" ] }
|
||||
|
||||
assert_equal \
|
||||
"docker exec kamal-proxy kamal-proxy deploy app-web --target=\"172.1.0.2:80\" --host=\"example.com\" --host=\"anotherexample.com\" --tls --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"",
|
||||
new_command.deploy(target: "172.1.0.2").join(" ")
|
||||
end
|
||||
|
||||
test "deploy with SSL false" do
|
||||
@config[:proxy] = { "ssl" => false }
|
||||
|
||||
assert_equal \
|
||||
"docker exec kamal-proxy kamal-proxy deploy app-web --target=\"172.1.0.2:80\" --deploy-timeout=\"30s\" --drain-timeout=\"30s\" --buffer-requests --buffer-responses --log-request-header=\"Cache-Control\" --log-request-header=\"Last-Modified\" --log-request-header=\"User-Agent\"",
|
||||
"docker exec kamal-proxy kamal-proxy deploy app-web --target \"172.1.0.2:80\" --deploy-timeout \"30s\" --drain-timeout \"30s\" --buffer-requests --buffer-responses --log-request-header \"Cache-Control\" --log-request-header \"Last-Modified\" --log-request-header \"User-Agent\"",
|
||||
new_command.deploy(target: "172.1.0.2").join(" ")
|
||||
end
|
||||
|
||||
test "remove" do
|
||||
assert_equal \
|
||||
"docker exec kamal-proxy kamal-proxy remove app-web",
|
||||
new_command.remove.join(" ")
|
||||
"docker exec kamal-proxy kamal-proxy remove app-web --target \"172.1.0.2:80\"",
|
||||
new_command.remove(target: "172.1.0.2").join(" ")
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -149,26 +149,15 @@ class CommandsBuilderTest < ActiveSupport::TestCase
|
||||
assert_equal "docker info --format '{{index .RegistryConfig.Mirrors 0}}'", command.first_mirror.join(" ")
|
||||
end
|
||||
|
||||
test "clone path with spaces" do
|
||||
command = new_builder_command
|
||||
Kamal::Git.stubs(:root).returns("/absolute/path with spaces")
|
||||
clone_command = command.clone.join(" ")
|
||||
clone_reset_commands = command.clone_reset_steps.map { |a| a.join(" ") }
|
||||
|
||||
assert_match(%r{path\\ with\\ space}, clone_command)
|
||||
assert_no_match(%r{path with spaces}, clone_command)
|
||||
|
||||
clone_reset_commands.each do |command|
|
||||
assert_match(%r{path\\ with\\ space}, command)
|
||||
assert_no_match(%r{path with spaces}, command)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def new_builder_command(additional_config = {})
|
||||
Kamal::Commands::Builder.new(Kamal::Configuration.new(@config.deep_merge(additional_config), version: "123"))
|
||||
end
|
||||
|
||||
def build_directory
|
||||
"#{Dir.tmpdir}/kamal-clones/app/kamal/"
|
||||
end
|
||||
|
||||
def local_arch
|
||||
Kamal::Utils.docker_arch
|
||||
end
|
||||
|
||||
@@ -15,7 +15,7 @@ class CommandsProxyTest < ActiveSupport::TestCase
|
||||
|
||||
test "run" do
|
||||
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 --log-opt max-size=10m\") basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION}",
|
||||
"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
|
||||
|
||||
@@ -23,7 +23,7 @@ class CommandsProxyTest < ActiveSupport::TestCase
|
||||
@config.delete(:proxy)
|
||||
|
||||
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 --log-opt max-size=10m\") basecamp/kamal-proxy:#{Kamal::Configuration::PROXY_MINIMUM_VERSION}",
|
||||
"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
|
||||
|
||||
@@ -113,7 +113,7 @@ class CommandsProxyTest < ActiveSupport::TestCase
|
||||
|
||||
test "get_boot_options" do
|
||||
assert_equal \
|
||||
"cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443 --log-opt max-size=10m\"",
|
||||
"cat .kamal/proxy/options || echo \"--publish 80:80 --publish 443:443\"",
|
||||
new_command.get_boot_options.join(" ")
|
||||
end
|
||||
|
||||
|
||||
@@ -13,29 +13,15 @@ class ConfigurationProxyTest < ActiveSupport::TestCase
|
||||
assert_equal true, config.proxy.ssl?
|
||||
end
|
||||
|
||||
test "ssl with multiple hosts passed via host" do
|
||||
@deploy[:proxy] = { "ssl" => true, "host" => "example.com,anotherexample.com" }
|
||||
assert_equal true, config.proxy.ssl?
|
||||
end
|
||||
|
||||
test "ssl with multiple hosts passed via hosts" do
|
||||
@deploy[:proxy] = { "ssl" => true, "hosts" => [ "example.com", "anotherexample.com" ] }
|
||||
assert_equal true, config.proxy.ssl?
|
||||
end
|
||||
|
||||
test "ssl with no host" do
|
||||
@deploy[:proxy] = { "ssl" => true }
|
||||
assert_raises(Kamal::ConfigurationError) { config.proxy.ssl? }
|
||||
end
|
||||
|
||||
test "ssl with both host and hosts" do
|
||||
@deploy[:proxy] = { "ssl" => true, host: "example.com", hosts: [ "anotherexample.com" ] }
|
||||
assert_raises(Kamal::ConfigurationError) { config.proxy.ssl? }
|
||||
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
|
||||
|
||||
@@ -222,13 +222,6 @@ class ConfigurationTest < ActiveSupport::TestCase
|
||||
assert_equal "my-user", config.registry.username
|
||||
end
|
||||
|
||||
test "destination is loaded into env" do
|
||||
dest_config_file = Pathname.new(File.expand_path("fixtures/deploy_for_dest.yml", __dir__))
|
||||
|
||||
config = Kamal::Configuration.create_from config_file: dest_config_file, destination: "world"
|
||||
assert_equal ENV["KAMAL_DESTINATION"], "world"
|
||||
end
|
||||
|
||||
test "destination yml config merge" do
|
||||
dest_config_file = Pathname.new(File.expand_path("fixtures/deploy_for_dest.yml", __dir__))
|
||||
|
||||
@@ -384,15 +377,4 @@ class ConfigurationTest < ActiveSupport::TestCase
|
||||
|
||||
assert_equal "Different roles can't share the same host for SSL: foo.example.com", exception.message
|
||||
end
|
||||
|
||||
test "two proxy ssl roles with same host in a hosts array" do
|
||||
@deploy_with_roles[:servers]["web"] = { "hosts" => [ "1.1.1.1" ], "proxy" => { "ssl" => true, "hosts" => [ "foo.example.com", "bar.example.com" ] } }
|
||||
@deploy_with_roles[:servers]["workers"] = { "hosts" => [ "1.1.1.1" ], "proxy" => { "ssl" => true, "hosts" => [ "www.example.com", "foo.example.com" ] } }
|
||||
|
||||
exception = assert_raises(Kamal::ConfigurationError) do
|
||||
Kamal::Configuration.new(@deploy_with_roles)
|
||||
end
|
||||
|
||||
assert_equal "Different roles can't share the same host for SSL: foo.example.com", exception.message
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
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:
|
||||
username: user
|
||||
password: pw
|
||||
builder:
|
||||
arch: amd64
|
||||
|
||||
accessories:
|
||||
mysql:
|
||||
image: mysql:5.7
|
||||
host: 1.1.1.5
|
||||
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
|
||||
29
test/fixtures/deploy_with_single_accessory.yml
vendored
29
test/fixtures/deploy_with_single_accessory.yml
vendored
@@ -1,29 +0,0 @@
|
||||
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:
|
||||
username: user
|
||||
password: pw
|
||||
builder:
|
||||
arch: amd64
|
||||
|
||||
accessories:
|
||||
mysql:
|
||||
image: mysql:5.7
|
||||
host: 1.1.1.5
|
||||
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
|
||||
@@ -8,7 +8,7 @@ class AppTest < IntegrationTest
|
||||
|
||||
kamal :app, :stop
|
||||
|
||||
assert_app_not_found
|
||||
assert_app_is_down
|
||||
|
||||
kamal :app, :start
|
||||
|
||||
@@ -48,7 +48,7 @@ class AppTest < IntegrationTest
|
||||
|
||||
kamal :app, :remove
|
||||
|
||||
assert_app_not_found
|
||||
assert_app_is_down
|
||||
assert_app_directory_removed
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,15 +15,14 @@ readiness_delay: 0
|
||||
|
||||
proxy:
|
||||
host: localhost
|
||||
ssl: false
|
||||
healthcheck:
|
||||
interval: 1
|
||||
timeout: 1
|
||||
path: "/up"
|
||||
response_timeout: 2
|
||||
buffering:
|
||||
requests: false
|
||||
responses: false
|
||||
requests: true
|
||||
responses: true
|
||||
memory: 400_000
|
||||
max_request_body: 40_000_000
|
||||
max_response_body: 40_000_000
|
||||
|
||||
@@ -50,12 +50,6 @@ class IntegrationTest < ActiveSupport::TestCase
|
||||
assert_equal "502", response.code
|
||||
end
|
||||
|
||||
def assert_app_not_found
|
||||
response = app_response
|
||||
debug_response_code(response, "404")
|
||||
assert_equal "404", response.code
|
||||
end
|
||||
|
||||
def assert_app_is_up(version: nil, app: @app)
|
||||
response = app_response(app: app)
|
||||
debug_response_code(response, "200")
|
||||
|
||||
@@ -6,30 +6,19 @@ class BitwardenAdapterTest < SecretAdapterTestCase
|
||||
stub_ticks.with("bw sync").returns("")
|
||||
stub_mypassword
|
||||
|
||||
json = JSON.parse(shellunescape(run_command("fetch", "mypassword")))
|
||||
json = JSON.parse(run_command("fetch", "mypassword"))
|
||||
|
||||
expected_json = { "mypassword"=>"secret123" }
|
||||
|
||||
assert_equal expected_json, json
|
||||
end
|
||||
|
||||
test "fetch with no login" do
|
||||
stub_unlocked
|
||||
stub_ticks.with("bw sync").returns("")
|
||||
stub_noteitem
|
||||
|
||||
error = assert_raises RuntimeError do
|
||||
JSON.parse(shellunescape(run_command("fetch", "mynote")))
|
||||
end
|
||||
assert_match(/not a login type item/, error.message)
|
||||
end
|
||||
|
||||
test "fetch with from" do
|
||||
stub_unlocked
|
||||
stub_ticks.with("bw sync").returns("")
|
||||
stub_myitem
|
||||
|
||||
json = JSON.parse(shellunescape(run_command("fetch", "--from", "myitem", "field1", "field2", "field3")))
|
||||
json = JSON.parse(run_command("fetch", "--from", "myitem", "field1", "field2", "field3"))
|
||||
|
||||
expected_json = {
|
||||
"myitem/field1"=>"secret1", "myitem/field2"=>"blam", "myitem/field3"=>"fewgrwjgk"
|
||||
@@ -70,7 +59,7 @@ class BitwardenAdapterTest < SecretAdapterTestCase
|
||||
JSON
|
||||
|
||||
|
||||
json = JSON.parse(shellunescape(run_command("fetch", "mypassword", "myitem/field1", "myitem/field2", "myitem2/field3")))
|
||||
json = JSON.parse(run_command("fetch", "mypassword", "myitem/field1", "myitem/field2", "myitem2/field3"))
|
||||
|
||||
expected_json = {
|
||||
"mypassword"=>"secret123", "myitem/field1"=>"secret1", "myitem/field2"=>"blam", "myitem2/field3"=>"fewgrwjgk"
|
||||
@@ -93,7 +82,7 @@ class BitwardenAdapterTest < SecretAdapterTestCase
|
||||
stub_ticks.with("bw sync").returns("")
|
||||
stub_mypassword
|
||||
|
||||
json = JSON.parse(shellunescape(run_command("fetch", "mypassword")))
|
||||
json = JSON.parse(run_command("fetch", "mypassword"))
|
||||
|
||||
expected_json = { "mypassword"=>"secret123" }
|
||||
|
||||
@@ -118,7 +107,7 @@ class BitwardenAdapterTest < SecretAdapterTestCase
|
||||
stub_ticks.with("bw sync").returns("")
|
||||
stub_mypassword
|
||||
|
||||
json = JSON.parse(shellunescape(run_command("fetch", "mypassword")))
|
||||
json = JSON.parse(run_command("fetch", "mypassword"))
|
||||
|
||||
expected_json = { "mypassword"=>"secret123" }
|
||||
|
||||
@@ -143,7 +132,7 @@ class BitwardenAdapterTest < SecretAdapterTestCase
|
||||
stub_ticks.with("BW_SESSION=0987654321 bw sync").returns("")
|
||||
stub_mypassword(session: "0987654321")
|
||||
|
||||
json = JSON.parse(shellunescape(run_command("fetch", "mypassword")))
|
||||
json = JSON.parse(run_command("fetch", "mypassword"))
|
||||
|
||||
expected_json = { "mypassword"=>"secret123" }
|
||||
|
||||
@@ -192,30 +181,6 @@ class BitwardenAdapterTest < SecretAdapterTestCase
|
||||
JSON
|
||||
end
|
||||
|
||||
def stub_noteitem(session: nil)
|
||||
stub_ticks
|
||||
.with("#{"BW_SESSION=#{session} " if session}bw get item mynote")
|
||||
.returns(<<~JSON)
|
||||
{
|
||||
"passwordHistory":null,
|
||||
"revisionDate":"2024-09-28T09:07:27.461Z",
|
||||
"creationDate":"2024-09-28T09:07:00.740Z",
|
||||
"deletedDate":null,
|
||||
"object":"item",
|
||||
"id":"aaaaaaaa-cccc-eeee-0000-222222222222",
|
||||
"organizationId":null,
|
||||
"folderId":null,
|
||||
"type":2,
|
||||
"reprompt":0,
|
||||
"name":"noteitem",
|
||||
"notes":"NOTES",
|
||||
"favorite":false,
|
||||
"secureNote":{"type":0},
|
||||
"collectionIds":[]
|
||||
}
|
||||
JSON
|
||||
end
|
||||
|
||||
def stub_myitem
|
||||
stub_ticks
|
||||
.with("bw get item myitem")
|
||||
|
||||
@@ -12,4 +12,10 @@ class SecretsInlineCommandSubstitution < SecretAdapterTestCase
|
||||
substituted = Kamal::Secrets::Dotenv::InlineCommandSubstitution.call("FOO=$(blah)", nil, overwrite: false)
|
||||
assert_equal "FOO=results", substituted
|
||||
end
|
||||
|
||||
test "escapes correctly" do
|
||||
Kamal::Cli::Main.expects(:start).with { |command| command == [ "secrets", "fetch", "...", "--inline" ] }.returns("{ \"foo\" : \"bar\" }")
|
||||
substituted = Kamal::Secrets::Dotenv::InlineCommandSubstitution.call("SECRETS=$(kamal secrets fetch ...)", nil, overwrite: false)
|
||||
assert_equal "SECRETS=\\{\\ \\\"foo\\\"\\ :\\ \\\"bar\\\"\\ \\}", substituted
|
||||
end
|
||||
end
|
||||
|
||||
@@ -51,7 +51,7 @@ class LastPassAdapterTest < SecretAdapterTestCase
|
||||
]
|
||||
JSON
|
||||
|
||||
json = JSON.parse(shellunescape(run_command("fetch", "SECRET1", "FOLDER1/FSECRET1", "FOLDER1/FSECRET2")))
|
||||
json = JSON.parse(run_command("fetch", "SECRET1", "FOLDER1/FSECRET1", "FOLDER1/FSECRET2"))
|
||||
|
||||
expected_json = {
|
||||
"SECRET1"=>"secret1",
|
||||
@@ -96,7 +96,7 @@ class LastPassAdapterTest < SecretAdapterTestCase
|
||||
]
|
||||
JSON
|
||||
|
||||
json = JSON.parse(shellunescape(run_command("fetch", "--from", "FOLDER1", "FSECRET1", "FSECRET2")))
|
||||
json = JSON.parse(run_command("fetch", "--from", "FOLDER1", "FSECRET1", "FSECRET2"))
|
||||
|
||||
expected_json = {
|
||||
"FOLDER1/FSECRET1"=>"fsecret1",
|
||||
@@ -111,7 +111,7 @@ class LastPassAdapterTest < SecretAdapterTestCase
|
||||
stub_ticks_with("lpass login email@example.com", succeed: true).returns("")
|
||||
stub_ticks.with("lpass show SECRET1 --json").returns(single_item_json)
|
||||
|
||||
json = JSON.parse(shellunescape(run_command("fetch", "SECRET1")))
|
||||
json = JSON.parse(run_command("fetch", "SECRET1"))
|
||||
|
||||
expected_json = {
|
||||
"SECRET1"=>"secret1"
|
||||
|
||||
@@ -44,7 +44,7 @@ class SecretsOnePasswordAdapterTest < SecretAdapterTestCase
|
||||
]
|
||||
JSON
|
||||
|
||||
json = JSON.parse(shellunescape(run_command("fetch", "--from", "op://myvault/myitem", "section/SECRET1", "section/SECRET2", "section2/SECRET3")))
|
||||
json = JSON.parse(run_command("fetch", "--from", "op://myvault/myitem", "section/SECRET1", "section/SECRET2", "section2/SECRET3"))
|
||||
|
||||
expected_json = {
|
||||
"myvault/myitem/section/SECRET1"=>"VALUE1",
|
||||
@@ -103,7 +103,7 @@ class SecretsOnePasswordAdapterTest < SecretAdapterTestCase
|
||||
}
|
||||
JSON
|
||||
|
||||
json = JSON.parse(shellunescape(run_command("fetch", "--from", "op://myvault", "myitem/section/SECRET1", "myitem/section/SECRET2", "myitem2/section2/SECRET3")))
|
||||
json = JSON.parse(run_command("fetch", "--from", "op://myvault", "myitem/section/SECRET1", "myitem/section/SECRET2", "myitem2/section2/SECRET3"))
|
||||
|
||||
expected_json = {
|
||||
"myvault/myitem/section/SECRET1"=>"VALUE1",
|
||||
@@ -122,7 +122,7 @@ class SecretsOnePasswordAdapterTest < SecretAdapterTestCase
|
||||
.with("op item get myitem --vault \"myvault\" --fields \"label=section.SECRET1\" --format \"json\" --account \"myaccount\"")
|
||||
.returns(single_item_json)
|
||||
|
||||
json = JSON.parse(shellunescape(run_command("fetch", "--from", "op://myvault/myitem", "section/SECRET1")))
|
||||
json = JSON.parse(run_command("fetch", "--from", "op://myvault/myitem", "section/SECRET1"))
|
||||
|
||||
expected_json = {
|
||||
"myvault/myitem/section/SECRET1"=>"VALUE1"
|
||||
@@ -139,7 +139,7 @@ class SecretsOnePasswordAdapterTest < SecretAdapterTestCase
|
||||
.with("op item get myitem --vault \"myvault\" --fields \"label=section.SECRET1\" --format \"json\" --account \"myaccount\" --session \"1234567890\"")
|
||||
.returns(single_item_json)
|
||||
|
||||
json = JSON.parse(shellunescape(run_command("fetch", "--from", "op://myvault/myitem", "section/SECRET1")))
|
||||
json = JSON.parse(run_command("fetch", "--from", "op://myvault/myitem", "section/SECRET1"))
|
||||
|
||||
expected_json = {
|
||||
"myvault/myitem/section/SECRET1"=>"VALUE1"
|
||||
|
||||
@@ -86,8 +86,4 @@ class SecretAdapterTestCase < ActiveSupport::TestCase
|
||||
stub_ticks.with { |c| c == command && (succeed ? `true` : `false`) }
|
||||
Kamal::Secrets::Adapters::Base.any_instance.stubs(:`)
|
||||
end
|
||||
|
||||
def shellunescape(string)
|
||||
"\"#{string}\"".undump.gsub(/\\([{}])/, "\\1")
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user