Merge pull request #789 from basecamp/host-tags
Host specific env with tags
This commit is contained in:
@@ -37,7 +37,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
|
|
||||||
roles.each do |role|
|
roles.each do |role|
|
||||||
execute *KAMAL.auditor.record("Started app version #{KAMAL.config.version}"), verbosity: :debug
|
execute *KAMAL.auditor.record("Started app version #{KAMAL.config.version}"), verbosity: :debug
|
||||||
execute *KAMAL.app(role: role).start, raise_on_non_zero_exit: false
|
execute *KAMAL.app(role: role, host: host).start, raise_on_non_zero_exit: false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -51,7 +51,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
|
|
||||||
roles.each do |role|
|
roles.each do |role|
|
||||||
execute *KAMAL.auditor.record("Stopped app", role: role), verbosity: :debug
|
execute *KAMAL.auditor.record("Stopped app", role: role), verbosity: :debug
|
||||||
execute *KAMAL.app(role: role).stop, raise_on_non_zero_exit: false
|
execute *KAMAL.app(role: role, host: host).stop, raise_on_non_zero_exit: false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -64,7 +64,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
roles = KAMAL.roles_on(host)
|
roles = KAMAL.roles_on(host)
|
||||||
|
|
||||||
roles.each do |role|
|
roles.each do |role|
|
||||||
puts_by_host host, capture_with_info(*KAMAL.app(role: role).info)
|
puts_by_host host, capture_with_info(*KAMAL.app(role: role, host: host).info)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -80,7 +80,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
say "Get current version of running container...", :magenta unless options[:version]
|
say "Get current version of running container...", :magenta unless options[:version]
|
||||||
using_version(options[:version] || current_running_version) do |version|
|
using_version(options[:version] || current_running_version) do |version|
|
||||||
say "Launching interactive command with version #{version} via SSH from existing container on #{KAMAL.primary_host}...", :magenta
|
say "Launching interactive command with version #{version} via SSH from existing container on #{KAMAL.primary_host}...", :magenta
|
||||||
run_locally { exec KAMAL.app(role: KAMAL.primary_role).execute_in_existing_container_over_ssh(cmd, host: KAMAL.primary_host, env: env) }
|
run_locally { exec KAMAL.app(role: KAMAL.primary_role, host: KAMAL.primary_host).execute_in_existing_container_over_ssh(cmd, env: env) }
|
||||||
end
|
end
|
||||||
|
|
||||||
when options[:interactive]
|
when options[:interactive]
|
||||||
@@ -88,7 +88,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
using_version(version_or_latest) do |version|
|
using_version(version_or_latest) do |version|
|
||||||
say "Launching interactive command with version #{version} via SSH from new container on #{KAMAL.primary_host}...", :magenta
|
say "Launching interactive command with version #{version} via SSH from new container on #{KAMAL.primary_host}...", :magenta
|
||||||
run_locally do
|
run_locally do
|
||||||
exec KAMAL.app(role: KAMAL.primary_role).execute_in_new_container_over_ssh(cmd, host: KAMAL.primary_host, env: env)
|
exec KAMAL.app(role: KAMAL.primary_role, host: KAMAL.primary_host).execute_in_new_container_over_ssh(cmd, env: env)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
|
|
||||||
roles.each do |role|
|
roles.each do |role|
|
||||||
execute *KAMAL.auditor.record("Executed cmd '#{cmd}' on app version #{version}", role: role), verbosity: :debug
|
execute *KAMAL.auditor.record("Executed cmd '#{cmd}' on app version #{version}", role: role), verbosity: :debug
|
||||||
puts_by_host host, capture_with_info(*KAMAL.app(role: role).execute_in_existing_container(cmd, env: env))
|
puts_by_host host, capture_with_info(*KAMAL.app(role: role, host: host).execute_in_existing_container(cmd, env: env))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -116,7 +116,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
|
|
||||||
roles.each do |role|
|
roles.each do |role|
|
||||||
execute *KAMAL.auditor.record("Executed cmd '#{cmd}' on app version #{version}"), verbosity: :debug
|
execute *KAMAL.auditor.record("Executed cmd '#{cmd}' on app version #{version}"), verbosity: :debug
|
||||||
puts_by_host host, capture_with_info(*KAMAL.app(role: role).execute_in_new_container(cmd, env: env))
|
puts_by_host host, capture_with_info(*KAMAL.app(role: role, host: host).execute_in_new_container(cmd, env: env))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -140,13 +140,14 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
roles = KAMAL.roles_on(host)
|
roles = KAMAL.roles_on(host)
|
||||||
|
|
||||||
roles.each do |role|
|
roles.each do |role|
|
||||||
versions = capture_with_info(*KAMAL.app(role: role).list_versions, raise_on_non_zero_exit: false).split("\n")
|
app = KAMAL.app(role: role, host: host)
|
||||||
versions -= [ capture_with_info(*KAMAL.app(role: role).current_running_version, raise_on_non_zero_exit: false).strip ]
|
versions = capture_with_info(*app.list_versions, raise_on_non_zero_exit: false).split("\n")
|
||||||
|
versions -= [ capture_with_info(*app.current_running_version, raise_on_non_zero_exit: false).strip ]
|
||||||
|
|
||||||
versions.each do |version|
|
versions.each do |version|
|
||||||
if stop
|
if stop
|
||||||
puts_by_host host, "Stopping stale container for role #{role} with version #{version}"
|
puts_by_host host, "Stopping stale container for role #{role} with version #{version}"
|
||||||
execute *KAMAL.app(role: role).stop(version: version), raise_on_non_zero_exit: false
|
execute *app.stop(version: version), raise_on_non_zero_exit: false
|
||||||
else
|
else
|
||||||
puts_by_host host, "Detected stale container for role #{role} with version #{version} (use `kamal app stale_containers --stop` to stop)"
|
puts_by_host host, "Detected stale container for role #{role} with version #{version} (use `kamal app stale_containers --stop` to stop)"
|
||||||
end
|
end
|
||||||
@@ -180,8 +181,9 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
KAMAL.specific_roles ||= [ "web" ]
|
KAMAL.specific_roles ||= [ "web" ]
|
||||||
role = KAMAL.roles_on(KAMAL.primary_host).first
|
role = KAMAL.roles_on(KAMAL.primary_host).first
|
||||||
|
|
||||||
info KAMAL.app(role: role).follow_logs(host: KAMAL.primary_host, lines: lines, grep: grep)
|
app = KAMAL.app(role: role, host: host)
|
||||||
exec KAMAL.app(role: role).follow_logs(host: KAMAL.primary_host, lines: lines, grep: grep)
|
info app.follow_logs(host: KAMAL.primary_host, lines: lines, grep: grep)
|
||||||
|
exec app.follow_logs(host: KAMAL.primary_host, lines: lines, grep: grep)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
lines = options[:lines].presence || ((since || grep) ? nil : 100) # Default to 100 lines if since or grep isn't set
|
lines = options[:lines].presence || ((since || grep) ? nil : 100) # Default to 100 lines if since or grep isn't set
|
||||||
@@ -191,7 +193,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
|
|
||||||
roles.each do |role|
|
roles.each do |role|
|
||||||
begin
|
begin
|
||||||
puts_by_host host, capture_with_info(*KAMAL.app(role: role).logs(since: since, lines: lines, grep: grep))
|
puts_by_host host, capture_with_info(*KAMAL.app(role: role, host: host).logs(since: since, lines: lines, grep: grep))
|
||||||
rescue SSHKit::Command::Failed
|
rescue SSHKit::Command::Failed
|
||||||
puts_by_host host, "Nothing found"
|
puts_by_host host, "Nothing found"
|
||||||
end
|
end
|
||||||
@@ -217,7 +219,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
|
|
||||||
roles.each do |role|
|
roles.each do |role|
|
||||||
execute *KAMAL.auditor.record("Removed app container with version #{version}", role: role), verbosity: :debug
|
execute *KAMAL.auditor.record("Removed app container with version #{version}", role: role), verbosity: :debug
|
||||||
execute *KAMAL.app(role: role).remove_container(version: version)
|
execute *KAMAL.app(role: role, host: host).remove_container(version: version)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -231,7 +233,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
|
|
||||||
roles.each do |role|
|
roles.each do |role|
|
||||||
execute *KAMAL.auditor.record("Removed all app containers", role: role), verbosity: :debug
|
execute *KAMAL.auditor.record("Removed all app containers", role: role), verbosity: :debug
|
||||||
execute *KAMAL.app(role: role).remove_containers
|
execute *KAMAL.app(role: role, host: host).remove_containers
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -251,7 +253,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
def version
|
def version
|
||||||
on(KAMAL.hosts) do |host|
|
on(KAMAL.hosts) do |host|
|
||||||
role = KAMAL.roles_on(host).first
|
role = KAMAL.roles_on(host).first
|
||||||
puts_by_host host, capture_with_info(*KAMAL.app(role: role).current_running_version).strip
|
puts_by_host host, capture_with_info(*KAMAL.app(role: role, host: host).current_running_version).strip
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -274,7 +276,7 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
version = nil
|
version = nil
|
||||||
on(host) do
|
on(host) do
|
||||||
role = KAMAL.roles_on(host).first
|
role = KAMAL.roles_on(host).first
|
||||||
version = capture_with_info(*KAMAL.app(role: role).current_running_version).strip
|
version = capture_with_info(*KAMAL.app(role: role, host: host).current_running_version).strip
|
||||||
end
|
end
|
||||||
version.presence
|
version.presence
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class Kamal::Cli::App::Boot
|
|||||||
|
|
||||||
private
|
private
|
||||||
def app
|
def app
|
||||||
@app ||= KAMAL.app(role: role)
|
@app ||= KAMAL.app(role: role, host: host)
|
||||||
end
|
end
|
||||||
|
|
||||||
def auditor
|
def auditor
|
||||||
|
|||||||
@@ -19,6 +19,6 @@ class Kamal::Cli::App::PrepareAssets
|
|||||||
|
|
||||||
private
|
private
|
||||||
def app
|
def app
|
||||||
@app ||= KAMAL.app(role: role)
|
@app ||= KAMAL.app(role: role, host: host)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ class Kamal::Cli::Env < Kamal::Cli::Base
|
|||||||
execute *KAMAL.auditor.record("Pushed env files"), verbosity: :debug
|
execute *KAMAL.auditor.record("Pushed env files"), verbosity: :debug
|
||||||
|
|
||||||
KAMAL.roles_on(host).each do |role|
|
KAMAL.roles_on(host).each do |role|
|
||||||
execute *KAMAL.app(role: role).make_env_directory
|
execute *KAMAL.app(role: role, host: host).make_env_directory
|
||||||
upload! role.env.secrets_io, role.env.secrets_file, mode: 400
|
upload! role.env(host).secrets_io, role.env(host).secrets_file, mode: 400
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ class Kamal::Cli::Env < Kamal::Cli::Base
|
|||||||
execute *KAMAL.auditor.record("Deleted env files"), verbosity: :debug
|
execute *KAMAL.auditor.record("Deleted env files"), verbosity: :debug
|
||||||
|
|
||||||
KAMAL.roles_on(host).each do |role|
|
KAMAL.roles_on(host).each do |role|
|
||||||
execute *KAMAL.app(role: role).remove_env_file
|
execute *KAMAL.app(role: role, host: host).remove_env_file
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
begin
|
begin
|
||||||
on(KAMAL.hosts) do
|
on(KAMAL.hosts) do
|
||||||
KAMAL.roles_on(host).each do |role|
|
KAMAL.roles_on(host).each do |role|
|
||||||
container_id = capture_with_info(*KAMAL.app(role: role).container_id_for_version(version))
|
container_id = capture_with_info(*KAMAL.app(role: role, host: host).container_id_for_version(version))
|
||||||
raise "Container not found" unless container_id.present?
|
raise "Container not found" unless container_id.present?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -65,8 +65,8 @@ class Kamal::Commander
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def app(role: nil)
|
def app(role: nil, host: nil)
|
||||||
Kamal::Commands::App.new(config, role: role)
|
Kamal::Commands::App.new(config, role: role, host: host)
|
||||||
end
|
end
|
||||||
|
|
||||||
def accessory(name)
|
def accessory(name)
|
||||||
|
|||||||
@@ -3,11 +3,12 @@ class Kamal::Commands::App < Kamal::Commands::Base
|
|||||||
|
|
||||||
ACTIVE_DOCKER_STATUSES = [ :running, :restarting ]
|
ACTIVE_DOCKER_STATUSES = [ :running, :restarting ]
|
||||||
|
|
||||||
attr_reader :role, :role
|
attr_reader :role, :host
|
||||||
|
|
||||||
def initialize(config, role: nil)
|
def initialize(config, role: nil, host: nil)
|
||||||
super(config)
|
super(config)
|
||||||
@role = role
|
@role = role
|
||||||
|
@host = host
|
||||||
end
|
end
|
||||||
|
|
||||||
def run(hostname: nil)
|
def run(hostname: nil)
|
||||||
@@ -18,7 +19,7 @@ class Kamal::Commands::App < Kamal::Commands::Base
|
|||||||
*([ "--hostname", hostname ] if hostname),
|
*([ "--hostname", hostname ] if hostname),
|
||||||
"-e", "KAMAL_CONTAINER_NAME=\"#{container_name}\"",
|
"-e", "KAMAL_CONTAINER_NAME=\"#{container_name}\"",
|
||||||
"-e", "KAMAL_VERSION=\"#{config.version}\"",
|
"-e", "KAMAL_VERSION=\"#{config.version}\"",
|
||||||
*role.env_args,
|
*role.env_args(host),
|
||||||
*role.health_check_args,
|
*role.health_check_args,
|
||||||
*role.logging_args,
|
*role.logging_args,
|
||||||
*config.volume_args,
|
*config.volume_args,
|
||||||
@@ -70,11 +71,11 @@ class Kamal::Commands::App < Kamal::Commands::Base
|
|||||||
|
|
||||||
|
|
||||||
def make_env_directory
|
def make_env_directory
|
||||||
make_directory role.env.secrets_directory
|
make_directory role.env(host).secrets_directory
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_env_file
|
def remove_env_file
|
||||||
[ :rm, "-f", role.env.secrets_file ]
|
[ :rm, "-f", role.env(host).secrets_file ]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ module Kamal::Commands::App::Execution
|
|||||||
docker :run,
|
docker :run,
|
||||||
("-it" if interactive),
|
("-it" if interactive),
|
||||||
"--rm",
|
"--rm",
|
||||||
*role&.env_args,
|
*role&.env_args(host),
|
||||||
*argumentize("--env", env),
|
*argumentize("--env", env),
|
||||||
*config.volume_args,
|
*config.volume_args,
|
||||||
*role&.option_args,
|
*role&.option_args,
|
||||||
@@ -19,11 +19,11 @@ module Kamal::Commands::App::Execution
|
|||||||
*command
|
*command
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute_in_existing_container_over_ssh(*command, host:, env:)
|
def execute_in_existing_container_over_ssh(*command, env:)
|
||||||
run_over_ssh execute_in_existing_container(*command, interactive: true, env: env), host: host
|
run_over_ssh execute_in_existing_container(*command, interactive: true, env: env), host: host
|
||||||
end
|
end
|
||||||
|
|
||||||
def execute_in_new_container_over_ssh(*command, host:, env:)
|
def execute_in_new_container_over_ssh(*command, env:)
|
||||||
run_over_ssh execute_in_new_container(*command, interactive: true, env: env), host: host
|
run_over_ssh execute_in_new_container(*command, interactive: true, env: env), host: host
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class Kamal::Commands::Healthcheck < Kamal::Commands::Base
|
|||||||
"--publish", "#{exposed_port}:#{config.healthcheck["port"]}",
|
"--publish", "#{exposed_port}:#{config.healthcheck["port"]}",
|
||||||
"--label", "service=#{config.healthcheck_service}",
|
"--label", "service=#{config.healthcheck_service}",
|
||||||
"-e", "KAMAL_CONTAINER_NAME=\"#{config.healthcheck_service}\"",
|
"-e", "KAMAL_CONTAINER_NAME=\"#{config.healthcheck_service}\"",
|
||||||
*primary.env_args,
|
*primary.env_args(config.primary_host),
|
||||||
*primary.health_check_args(cord: false),
|
*primary.health_check_args(cord: false),
|
||||||
*config.volume_args,
|
*config.volume_args,
|
||||||
*primary.option_args,
|
*primary.option_args,
|
||||||
|
|||||||
@@ -233,6 +233,14 @@ class Kamal::Configuration
|
|||||||
raw_config.env || {}
|
raw_config.env || {}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def env_tags
|
||||||
|
raw_config.env_tags.collect { |name, config| Kamal::Configuration::Env::Tag.new(name, config: config) }
|
||||||
|
end
|
||||||
|
|
||||||
|
def env_tag(name)
|
||||||
|
env_tags.detect { |t| t.name == name.to_s }
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
def valid?
|
def valid?
|
||||||
ensure_destination_if_required && ensure_required_keys_present && ensure_valid_kamal_version && ensure_retain_containers_valid && ensure_valid_service_name
|
ensure_destination_if_required && ensure_required_keys_present && ensure_valid_kamal_version && ensure_retain_containers_valid && ensure_valid_service_name
|
||||||
|
|||||||
12
lib/kamal/configuration/env/tag.rb
vendored
Normal file
12
lib/kamal/configuration/env/tag.rb
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
class Kamal::Configuration::Env::Tag
|
||||||
|
attr_reader :name, :config
|
||||||
|
|
||||||
|
def initialize(name, config:)
|
||||||
|
@name = name
|
||||||
|
@config = config
|
||||||
|
end
|
||||||
|
|
||||||
|
def env
|
||||||
|
Kamal::Configuration::Env.from_config(config: config)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -7,6 +7,7 @@ class Kamal::Configuration::Role
|
|||||||
|
|
||||||
def initialize(name, config:)
|
def initialize(name, config:)
|
||||||
@name, @config = name.inquiry, config
|
@name, @config = name.inquiry, config
|
||||||
|
@tagged_hosts ||= extract_tagged_hosts_from_config
|
||||||
end
|
end
|
||||||
|
|
||||||
def primary_host
|
def primary_host
|
||||||
@@ -14,7 +15,11 @@ class Kamal::Configuration::Role
|
|||||||
end
|
end
|
||||||
|
|
||||||
def hosts
|
def hosts
|
||||||
@hosts ||= extract_hosts_from_config
|
tagged_hosts.keys
|
||||||
|
end
|
||||||
|
|
||||||
|
def env_tags(host)
|
||||||
|
tagged_hosts.fetch(host).collect { |tag| config.env_tag(tag) }
|
||||||
end
|
end
|
||||||
|
|
||||||
def cmd
|
def cmd
|
||||||
@@ -50,12 +55,13 @@ class Kamal::Configuration::Role
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def env
|
def env(host)
|
||||||
@env ||= base_env.merge(specialized_env)
|
@envs ||= {}
|
||||||
|
@envs[host] ||= [ base_env, specialized_env, *env_tags(host).map(&:env) ].reduce(:merge)
|
||||||
end
|
end
|
||||||
|
|
||||||
def env_args
|
def env_args(host)
|
||||||
env.args
|
env(host).args
|
||||||
end
|
end
|
||||||
|
|
||||||
def asset_volume_args
|
def asset_volume_args
|
||||||
@@ -164,7 +170,24 @@ class Kamal::Configuration::Role
|
|||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
attr_accessor :config
|
attr_accessor :config, :tagged_hosts
|
||||||
|
|
||||||
|
def extract_tagged_hosts_from_config
|
||||||
|
{}.tap do |tagged_hosts|
|
||||||
|
extract_hosts_from_config.map do |host_config|
|
||||||
|
if host_config.is_a?(Hash)
|
||||||
|
raise ArgumentError, "Multiple hosts found: #{host_config.inspect}" unless host_config.size == 1
|
||||||
|
|
||||||
|
host, tags = host_config.first
|
||||||
|
tagged_hosts[host] = Array(tags)
|
||||||
|
elsif host_config.is_a?(String) || host_config.is_a?(Symbol)
|
||||||
|
tagged_hosts[host_config] = []
|
||||||
|
else
|
||||||
|
raise ArgumentError, "Invalid host config: #{host_config.inspect}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def extract_hosts_from_config
|
def extract_hosts_from_config
|
||||||
if config.servers.is_a?(Array)
|
if config.servers.is_a?(Array)
|
||||||
|
|||||||
@@ -92,6 +92,32 @@ class CliAppTest < CliTestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "boot with host tags" do
|
||||||
|
Object.any_instance.stubs(:sleep)
|
||||||
|
|
||||||
|
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
|
||||||
|
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-web-latest$", "--quiet", raise_on_non_zero_exit: false)
|
||||||
|
.returns("12345678") # running version
|
||||||
|
|
||||||
|
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
|
||||||
|
.with(:docker, :container, :ls, "--all", "--filter", "name=^app-web-latest$", "--quiet", "|", :xargs, :docker, :inspect, "--format", "'{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'")
|
||||||
|
.returns("running") # health check
|
||||||
|
|
||||||
|
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
|
||||||
|
.with(:sh, "-c", "'docker ps --latest --format '\\''{{.Names}}'\\'' --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --format '\\''{{.Names}}'\\'' --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting'", "|", :head, "-1", "|", "while read line; do echo ${line#app-web-}; done", raise_on_non_zero_exit: false)
|
||||||
|
.returns("123") # old version
|
||||||
|
|
||||||
|
SSHKit::Backend::Abstract.any_instance.expects(:capture_with_info)
|
||||||
|
.with(:docker, :inspect, "-f '{{ range .Mounts }}{{printf \"%s %s\\n\" .Source .Destination}}{{ end }}'", "app-web-123", "|", :awk, "'$2 == \"/tmp/kamal-cord\" {print $1}'", raise_on_non_zero_exit: false)
|
||||||
|
.returns("") # old version
|
||||||
|
|
||||||
|
run_command("boot", config: :with_env_tags).tap do |output|
|
||||||
|
assert_match "docker tag dhh/app:latest dhh/app:latest", output
|
||||||
|
assert_match %r{docker run --detach --restart unless-stopped --name app-web-latest --hostname 1.1.1.1-[0-9a-f]{12} -e KAMAL_CONTAINER_NAME="app-web-latest" -e KAMAL_VERSION="latest" --env-file .kamal/env/roles/app-web.env --env TEST="root" --env EXPERIMENT="disabled" --env SITE="site1"}, output
|
||||||
|
assert_match "docker container ls --all --filter name=^app-web-123$ --quiet | xargs docker stop", output
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
test "start" do
|
test "start" do
|
||||||
run_command("start").tap do |output|
|
run_command("start").tap do |output|
|
||||||
assert_match "docker start app-web-999", output
|
assert_match "docker start app-web-999", output
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
@config[:servers] = { "web" => [ "1.1.1.1" ], "jobs" => { "hosts" => [ "1.1.1.2" ], "cmd" => "bin/jobs", "options" => { "mount" => "somewhere", "cap-add" => true } } }
|
@config[:servers] = { "web" => [ "1.1.1.1" ], "jobs" => { "hosts" => [ "1.1.1.2" ], "cmd" => "bin/jobs", "options" => { "mount" => "somewhere", "cap-add" => true } } }
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --detach --restart unless-stopped --name app-jobs-999 -e KAMAL_CONTAINER_NAME=\"app-jobs-999\" -e KAMAL_VERSION=\"999\" --env-file .kamal/env/roles/app-jobs.env --log-opt max-size=\"10m\" --label service=\"app\" --label role=\"jobs\" --label destination --mount \"somewhere\" --cap-add dhh/app:999 bin/jobs",
|
"docker run --detach --restart unless-stopped --name app-jobs-999 -e KAMAL_CONTAINER_NAME=\"app-jobs-999\" -e KAMAL_VERSION=\"999\" --env-file .kamal/env/roles/app-jobs.env --log-opt max-size=\"10m\" --label service=\"app\" --label role=\"jobs\" --label destination --mount \"somewhere\" --cap-add dhh/app:999 bin/jobs",
|
||||||
new_command(role: "jobs").run.join(" ")
|
new_command(role: "jobs", host: "1.1.1.2").run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "run with logging config" do
|
test "run with logging config" do
|
||||||
@@ -80,6 +80,15 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "run with tags" do
|
||||||
|
@config[:servers] = [ { "1.1.1.1" => "tag1" } ]
|
||||||
|
@config[:env_tags] = { "tag1" => { "ENV1" => "value1" } }
|
||||||
|
|
||||||
|
assert_equal \
|
||||||
|
"docker run --detach --restart unless-stopped --name app-web-999 -e KAMAL_CONTAINER_NAME=\"app-web-999\" -e KAMAL_VERSION=\"999\" --env-file .kamal/env/roles/app-web.env --env ENV1=\"value1\" --health-cmd \"(curl -f http://localhost:3000/up || exit 1) && (stat /tmp/kamal-cord/cord > /dev/null || exit 1)\" --health-interval \"1s\" --volume $(pwd)/.kamal/cords/app-web-12345678901234567890123456789012:/tmp/kamal-cord --log-opt max-size=\"10m\" --label service=\"app\" --label role=\"web\" --label destination --label traefik.http.services.app-web.loadbalancer.server.scheme=\"http\" --label traefik.http.routers.app-web.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.app-web.priority=\"2\" --label traefik.http.middlewares.app-web-retry.retry.attempts=\"5\" --label traefik.http.middlewares.app-web-retry.retry.initialinterval=\"500ms\" --label traefik.http.routers.app-web.middlewares=\"app-web-retry@docker\" dhh/app:999",
|
||||||
|
new_command.run.join(" ")
|
||||||
|
end
|
||||||
|
|
||||||
test "start" do
|
test "start" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker start app-web-999",
|
"docker start app-web-999",
|
||||||
@@ -183,6 +192,15 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
new_command.execute_in_new_container("bin/rails", "db:setup", env: { "foo" => "bar" }).join(" ")
|
new_command.execute_in_new_container("bin/rails", "db:setup", env: { "foo" => "bar" }).join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "execute in new container with tags" do
|
||||||
|
@config[:servers] = [ { "1.1.1.1" => "tag1" } ]
|
||||||
|
@config[:env_tags] = { "tag1" => { "ENV1" => "value1" } }
|
||||||
|
|
||||||
|
assert_equal \
|
||||||
|
"docker run --rm --env-file .kamal/env/roles/app-web.env --env ENV1=\"value1\" dhh/app:999 bin/rails db:setup",
|
||||||
|
new_command.execute_in_new_container("bin/rails", "db:setup", env: {}).join(" ")
|
||||||
|
end
|
||||||
|
|
||||||
test "execute in new container with custom options" do
|
test "execute in new container with custom options" do
|
||||||
@config[:servers] = { "web" => { "hosts" => [ "1.1.1.1" ], "options" => { "mount" => "somewhere", "cap-add" => true } } }
|
@config[:servers] = { "web" => { "hosts" => [ "1.1.1.1" ], "options" => { "mount" => "somewhere", "cap-add" => true } } }
|
||||||
assert_equal \
|
assert_equal \
|
||||||
@@ -204,18 +222,26 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
test "execute in new container over ssh" do
|
test "execute in new container over ssh" do
|
||||||
assert_match %r{docker run -it --rm --env-file .kamal/env/roles/app-web.env dhh/app:999 bin/rails c},
|
assert_match %r{docker run -it --rm --env-file .kamal/env/roles/app-web.env dhh/app:999 bin/rails c},
|
||||||
new_command.execute_in_new_container_over_ssh("bin/rails", "c", host: "app-1", env: {})
|
new_command.execute_in_new_container_over_ssh("bin/rails", "c", env: {})
|
||||||
|
end
|
||||||
|
|
||||||
|
test "execute in new container over ssh with tags" do
|
||||||
|
@config[:servers] = [ { "1.1.1.1" => "tag1" } ]
|
||||||
|
@config[:env_tags] = { "tag1" => { "ENV1" => "value1" } }
|
||||||
|
|
||||||
|
assert_equal "ssh -t root@1.1.1.1 -p 22 'docker run -it --rm --env-file .kamal/env/roles/app-web.env --env ENV1=\"value1\" dhh/app:999 bin/rails c'",
|
||||||
|
new_command.execute_in_new_container_over_ssh("bin/rails", "c", env: {})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "execute in new container with custom options over ssh" do
|
test "execute in new container with custom options over ssh" do
|
||||||
@config[:servers] = { "web" => { "hosts" => [ "1.1.1.1" ], "options" => { "mount" => "somewhere", "cap-add" => true } } }
|
@config[:servers] = { "web" => { "hosts" => [ "1.1.1.1" ], "options" => { "mount" => "somewhere", "cap-add" => true } } }
|
||||||
assert_match %r{docker run -it --rm --env-file .kamal/env/roles/app-web.env --mount \"somewhere\" --cap-add dhh/app:999 bin/rails c},
|
assert_match %r{docker run -it --rm --env-file .kamal/env/roles/app-web.env --mount \"somewhere\" --cap-add dhh/app:999 bin/rails c},
|
||||||
new_command.execute_in_new_container_over_ssh("bin/rails", "c", host: "app-1", env: {})
|
new_command.execute_in_new_container_over_ssh("bin/rails", "c", env: {})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "execute in existing container over ssh" do
|
test "execute in existing container over ssh" do
|
||||||
assert_match %r{docker exec -it app-web-999 bin/rails c},
|
assert_match %r{docker exec -it app-web-999 bin/rails c},
|
||||||
new_command.execute_in_existing_container_over_ssh("bin/rails", "c", host: "app-1", env: {})
|
new_command.execute_in_existing_container_over_ssh("bin/rails", "c", env: {})
|
||||||
end
|
end
|
||||||
|
|
||||||
test "run over ssh" do
|
test "run over ssh" do
|
||||||
@@ -418,8 +444,8 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def new_command(role: "web", **additional_config)
|
def new_command(role: "web", host: "1.1.1.1", **additional_config)
|
||||||
config = Kamal::Configuration.new(@config.merge(additional_config), destination: @destination, version: "999")
|
config = Kamal::Configuration.new(@config.merge(additional_config), destination: @destination, version: "999")
|
||||||
Kamal::Commands::App.new(config, role: config.role(role))
|
Kamal::Commands::App.new(config, role: config.role(role), host: host)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -46,6 +46,15 @@ class CommandsHealthcheckTest < ActiveSupport::TestCase
|
|||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "run with tags" do
|
||||||
|
@config[:servers] = [ { "1.1.1.1" => "tag1" } ]
|
||||||
|
@config[:env_tags] = { "tag1" => { "ENV1" => "value1" } }
|
||||||
|
|
||||||
|
assert_equal \
|
||||||
|
"docker run --detach --name healthcheck-app-123 --publish 3999:3000 --label service=healthcheck-app -e KAMAL_CONTAINER_NAME=\"healthcheck-app\" --env-file .kamal/env/roles/app-web.env --env ENV1=\"value1\" --health-cmd \"curl -f http://localhost:3000/up || exit 1\" --health-interval \"1s\" dhh/app:123",
|
||||||
|
new_command.run.join(" ")
|
||||||
|
end
|
||||||
|
|
||||||
test "status" do
|
test "status" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker container ls --all --filter name=^healthcheck-app-123$ --quiet | xargs docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'",
|
"docker container ls --all --filter name=^healthcheck-app-123$ --quiet | xargs docker inspect --format '{{if .State.Health}}{{.State.Health.Status}}{{else}}{{.State.Status}}{{end}}'",
|
||||||
|
|||||||
102
test/configuration/env/tags_test.rb
vendored
Normal file
102
test/configuration/env/tags_test.rb
vendored
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
require "test_helper"
|
||||||
|
|
||||||
|
class ConfigurationEnvTagsTest < ActiveSupport::TestCase
|
||||||
|
setup do
|
||||||
|
@deploy = {
|
||||||
|
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
|
||||||
|
servers: [ { "1.1.1.1" => "odd" }, { "1.1.1.2" => "even" }, { "1.1.1.3" => [ "odd", "three" ] } ],
|
||||||
|
env: { "REDIS_URL" => "redis://x/y", "THREE" => "false" },
|
||||||
|
env_tags: {
|
||||||
|
"odd" => { "TYPE" => "odd" },
|
||||||
|
"even" => { "TYPE" => "even" },
|
||||||
|
"three" => { "THREE" => "true" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@config = Kamal::Configuration.new(@deploy)
|
||||||
|
|
||||||
|
@deploy_with_roles = @deploy.dup.merge({
|
||||||
|
servers: {
|
||||||
|
"web" => [ { "1.1.1.1" => "odd" }, "1.1.1.2" ],
|
||||||
|
"workers" => {
|
||||||
|
"hosts" => [ { "1.1.1.3" => [ "odd", "oddjob" ] }, "1.1.1.4" ],
|
||||||
|
"cmd" => "bin/jobs",
|
||||||
|
"env" => {
|
||||||
|
"REDIS_URL" => "redis://a/b",
|
||||||
|
"WEB_CONCURRENCY" => 4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
env_tags: {
|
||||||
|
"odd" => { "TYPE" => "odd" },
|
||||||
|
"oddjob" => { "TYPE" => "oddjob" }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
@config_with_roles = Kamal::Configuration.new(@deploy_with_roles)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "tags" do
|
||||||
|
assert_equal 3, @config.env_tags.size
|
||||||
|
assert_equal %w[ odd even three ], @config.env_tags.map(&:name)
|
||||||
|
assert_equal({ "TYPE" => "odd" }, @config.env_tag("odd").env.clear)
|
||||||
|
assert_equal({ "TYPE" => "even" }, @config.env_tag("even").env.clear)
|
||||||
|
assert_equal({ "THREE" => "true" }, @config.env_tag("three").env.clear)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "tags with roles" do
|
||||||
|
assert_equal 2, @config_with_roles.env_tags.size
|
||||||
|
assert_equal %w[ odd oddjob ], @config_with_roles.env_tags.map(&:name)
|
||||||
|
assert_equal({ "TYPE" => "odd" }, @config_with_roles.env_tag("odd").env.clear)
|
||||||
|
assert_equal({ "TYPE" => "oddjob" }, @config_with_roles.env_tag("oddjob").env.clear)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "tag overrides env" do
|
||||||
|
assert_equal "false", @config.role("web").env("1.1.1.1").clear["THREE"]
|
||||||
|
assert_equal "true", @config.role("web").env("1.1.1.3").clear["THREE"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "later tag wins" do
|
||||||
|
deploy = {
|
||||||
|
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
|
||||||
|
servers: [ { "1.1.1.1" => [ "first", "second" ] } ],
|
||||||
|
env_tags: {
|
||||||
|
"first" => { "TYPE" => "first" },
|
||||||
|
"second" => { "TYPE" => "second" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config = Kamal::Configuration.new(deploy)
|
||||||
|
assert_equal "second", config.role("web").env("1.1.1.1").clear["TYPE"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "tag secret env" do
|
||||||
|
ENV["PASSWORD"] = "hello"
|
||||||
|
|
||||||
|
deploy = {
|
||||||
|
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
|
||||||
|
servers: [ { "1.1.1.1" => "secrets" } ],
|
||||||
|
env_tags: {
|
||||||
|
"secrets" => { "secret" => [ "PASSWORD" ] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config = Kamal::Configuration.new(deploy)
|
||||||
|
assert_equal "hello", config.role("web").env("1.1.1.1").secrets["PASSWORD"]
|
||||||
|
ensure
|
||||||
|
ENV.delete "PASSWORD"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "tag clear env" do
|
||||||
|
deploy = {
|
||||||
|
service: "app", image: "dhh/app", registry: { "username" => "dhh", "password" => "secret" },
|
||||||
|
servers: [ { "1.1.1.1" => "clearly" } ],
|
||||||
|
env_tags: {
|
||||||
|
"clearly" => { "clear" => { "FOO" => "bar" } }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config = Kamal::Configuration.new(deploy)
|
||||||
|
assert_equal "bar", config.role("web").env("1.1.1.1").clear["FOO"]
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -70,10 +70,10 @@ class ConfigurationRoleTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "env overwritten by role" do
|
test "env overwritten by role" do
|
||||||
assert_equal "redis://a/b", @config_with_roles.role(:workers).env.clear["REDIS_URL"]
|
assert_equal "redis://a/b", @config_with_roles.role(:workers).env("1.1.1.3").clear["REDIS_URL"]
|
||||||
|
|
||||||
assert_equal "\n", @config_with_roles.role(:workers).env.secrets_io.string
|
assert_equal "\n", @config_with_roles.role(:workers).env("1.1.1.3").secrets_io.string
|
||||||
assert_equal [ "--env-file", ".kamal/env/roles/app-workers.env", "--env", "REDIS_URL=\"redis://a/b\"", "--env", "WEB_CONCURRENCY=\"4\"" ], @config_with_roles.role(:workers).env_args
|
assert_equal [ "--env-file", ".kamal/env/roles/app-workers.env", "--env", "REDIS_URL=\"redis://a/b\"", "--env", "WEB_CONCURRENCY=\"4\"" ], @config_with_roles.role(:workers).env_args("1.1.1.3")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "container name" do
|
test "container name" do
|
||||||
@@ -86,7 +86,7 @@ class ConfigurationRoleTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "env args" do
|
test "env args" do
|
||||||
assert_equal [ "--env-file", ".kamal/env/roles/app-workers.env", "--env", "REDIS_URL=\"redis://a/b\"", "--env", "WEB_CONCURRENCY=\"4\"" ], @config_with_roles.role(:workers).env_args
|
assert_equal [ "--env-file", ".kamal/env/roles/app-workers.env", "--env", "REDIS_URL=\"redis://a/b\"", "--env", "WEB_CONCURRENCY=\"4\"" ], @config_with_roles.role(:workers).env_args("1.1.1.3")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "env secret overwritten by role" do
|
test "env secret overwritten by role" do
|
||||||
@@ -117,8 +117,8 @@ class ConfigurationRoleTest < ActiveSupport::TestCase
|
|||||||
DB_PASSWORD=secret&\"123
|
DB_PASSWORD=secret&\"123
|
||||||
ENV
|
ENV
|
||||||
|
|
||||||
assert_equal expected_secrets_file, @config_with_roles.role(:workers).env.secrets_io.string
|
assert_equal expected_secrets_file, @config_with_roles.role(:workers).env("1.1.1.3").secrets_io.string
|
||||||
assert_equal [ "--env-file", ".kamal/env/roles/app-workers.env", "--env", "REDIS_URL=\"redis://a/b\"", "--env", "WEB_CONCURRENCY=\"4\"" ], @config_with_roles.role(:workers).env_args
|
assert_equal [ "--env-file", ".kamal/env/roles/app-workers.env", "--env", "REDIS_URL=\"redis://a/b\"", "--env", "WEB_CONCURRENCY=\"4\"" ], @config_with_roles.role(:workers).env_args("1.1.1.3")
|
||||||
ensure
|
ensure
|
||||||
ENV["REDIS_PASSWORD"] = nil
|
ENV["REDIS_PASSWORD"] = nil
|
||||||
ENV["DB_PASSWORD"] = nil
|
ENV["DB_PASSWORD"] = nil
|
||||||
@@ -141,8 +141,8 @@ class ConfigurationRoleTest < ActiveSupport::TestCase
|
|||||||
DB_PASSWORD=secret123
|
DB_PASSWORD=secret123
|
||||||
ENV
|
ENV
|
||||||
|
|
||||||
assert_equal expected_secrets_file, @config_with_roles.role(:workers).env.secrets_io.string
|
assert_equal expected_secrets_file, @config_with_roles.role(:workers).env("1.1.1.3").secrets_io.string
|
||||||
assert_equal [ "--env-file", ".kamal/env/roles/app-workers.env", "--env", "REDIS_URL=\"redis://a/b\"", "--env", "WEB_CONCURRENCY=\"4\"" ], @config_with_roles.role(:workers).env_args
|
assert_equal [ "--env-file", ".kamal/env/roles/app-workers.env", "--env", "REDIS_URL=\"redis://a/b\"", "--env", "WEB_CONCURRENCY=\"4\"" ], @config_with_roles.role(:workers).env_args("1.1.1.3")
|
||||||
ensure
|
ensure
|
||||||
ENV["DB_PASSWORD"] = nil
|
ENV["DB_PASSWORD"] = nil
|
||||||
end
|
end
|
||||||
@@ -163,8 +163,8 @@ class ConfigurationRoleTest < ActiveSupport::TestCase
|
|||||||
REDIS_PASSWORD=secret456
|
REDIS_PASSWORD=secret456
|
||||||
ENV
|
ENV
|
||||||
|
|
||||||
assert_equal expected_secrets_file, @config_with_roles.role(:workers).env.secrets_io.string
|
assert_equal expected_secrets_file, @config_with_roles.role(:workers).env("1.1.1.3").secrets_io.string
|
||||||
assert_equal [ "--env-file", ".kamal/env/roles/app-workers.env", "--env", "REDIS_URL=\"redis://a/b\"", "--env", "WEB_CONCURRENCY=\"4\"" ], @config_with_roles.role(:workers).env_args
|
assert_equal [ "--env-file", ".kamal/env/roles/app-workers.env", "--env", "REDIS_URL=\"redis://a/b\"", "--env", "WEB_CONCURRENCY=\"4\"" ], @config_with_roles.role(:workers).env_args("1.1.1.3")
|
||||||
ensure
|
ensure
|
||||||
ENV["REDIS_PASSWORD"] = nil
|
ENV["REDIS_PASSWORD"] = nil
|
||||||
end
|
end
|
||||||
@@ -191,14 +191,14 @@ class ConfigurationRoleTest < ActiveSupport::TestCase
|
|||||||
REDIS_PASSWORD=secret456
|
REDIS_PASSWORD=secret456
|
||||||
ENV
|
ENV
|
||||||
|
|
||||||
assert_equal expected_secrets_file, @config_with_roles.role(:workers).env.secrets_io.string
|
assert_equal expected_secrets_file, @config_with_roles.role(:workers).env("1.1.1.3").secrets_io.string
|
||||||
assert_equal [ "--env-file", ".kamal/env/roles/app-workers.env", "--env", "REDIS_URL=\"redis://c/d\"" ], @config_with_roles.role(:workers).env_args
|
assert_equal [ "--env-file", ".kamal/env/roles/app-workers.env", "--env", "REDIS_URL=\"redis://c/d\"" ], @config_with_roles.role(:workers).env_args("1.1.1.3")
|
||||||
ensure
|
ensure
|
||||||
ENV["REDIS_PASSWORD"] = nil
|
ENV["REDIS_PASSWORD"] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
test "env secrets_file" do
|
test "env secrets_file" do
|
||||||
assert_equal ".kamal/env/roles/app-workers.env", @config_with_roles.role(:workers).env.secrets_file
|
assert_equal ".kamal/env/roles/app-workers.env", @config_with_roles.role(:workers).env("1.1.1.3").secrets_file
|
||||||
end
|
end
|
||||||
|
|
||||||
test "uses cord" do
|
test "uses cord" do
|
||||||
|
|||||||
29
test/fixtures/deploy_with_env_tags.yml
vendored
Normal file
29
test/fixtures/deploy_with_env_tags.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
service: app
|
||||||
|
image: dhh/app
|
||||||
|
servers:
|
||||||
|
web:
|
||||||
|
- 1.1.1.1: site1
|
||||||
|
- 1.1.1.2: [ site1 experimental ]
|
||||||
|
- 1.2.1.1: site2
|
||||||
|
- 1.2.1.2: site2
|
||||||
|
workers:
|
||||||
|
- 1.1.1.3: site1
|
||||||
|
- 1.1.1.4: site1
|
||||||
|
- 1.2.1.3: site2
|
||||||
|
- 1.2.1.4: [ site2 experimental ]
|
||||||
|
env:
|
||||||
|
clear:
|
||||||
|
TEST: "root"
|
||||||
|
EXPERIMENT: "disabled"
|
||||||
|
env_tags:
|
||||||
|
site1:
|
||||||
|
SITE: site1
|
||||||
|
site2:
|
||||||
|
SITE: site2
|
||||||
|
experimental:
|
||||||
|
env:
|
||||||
|
EXPERIMENT: "enabled"
|
||||||
|
|
||||||
|
registry:
|
||||||
|
username: user
|
||||||
|
password: pw
|
||||||
@@ -1 +1,2 @@
|
|||||||
SECRET_TOKEN='1234 with "中文"'
|
SECRET_TOKEN='1234 with "中文"'
|
||||||
|
SECRET_TAG='TAGME'
|
||||||
|
|||||||
@@ -2,13 +2,20 @@ service: app
|
|||||||
image: app
|
image: app
|
||||||
servers:
|
servers:
|
||||||
- vm1
|
- vm1
|
||||||
- vm2
|
- vm2: [ tag1, tag2 ]
|
||||||
env:
|
env:
|
||||||
clear:
|
clear:
|
||||||
CLEAR_TOKEN: 4321
|
CLEAR_TOKEN: 4321
|
||||||
|
CLEAR_TAG: ""
|
||||||
HOST_TOKEN: "${HOST_TOKEN}"
|
HOST_TOKEN: "${HOST_TOKEN}"
|
||||||
secret:
|
secret:
|
||||||
- SECRET_TOKEN
|
- SECRET_TOKEN
|
||||||
|
env_tags:
|
||||||
|
tag1:
|
||||||
|
CLEAR_TAG: tagged
|
||||||
|
tag2:
|
||||||
|
secret:
|
||||||
|
- SECRET_TAG
|
||||||
asset_path: /usr/share/nginx/html/versions
|
asset_path: /usr/share/nginx/html/versions
|
||||||
|
|
||||||
registry:
|
registry:
|
||||||
|
|||||||
@@ -3,8 +3,7 @@ require_relative "integration_test"
|
|||||||
class MainTest < IntegrationTest
|
class MainTest < IntegrationTest
|
||||||
test "envify, deploy, redeploy, rollback, details and audit" do
|
test "envify, deploy, redeploy, rollback, details and audit" do
|
||||||
kamal :envify
|
kamal :envify
|
||||||
assert_local_env_file "SECRET_TOKEN='1234 with \"中文\"'"
|
assert_env_files
|
||||||
assert_remote_env_file "SECRET_TOKEN=1234 with \"中文\""
|
|
||||||
remove_local_env_file
|
remove_local_env_file
|
||||||
|
|
||||||
first_version = latest_app_version
|
first_version = latest_app_version
|
||||||
@@ -14,9 +13,7 @@ class MainTest < IntegrationTest
|
|||||||
kamal :deploy
|
kamal :deploy
|
||||||
assert_app_is_up version: first_version
|
assert_app_is_up version: first_version
|
||||||
assert_hooks_ran "pre-connect", "pre-build", "pre-deploy", "post-deploy"
|
assert_hooks_ran "pre-connect", "pre-build", "pre-deploy", "post-deploy"
|
||||||
assert_env :CLEAR_TOKEN, "4321", version: first_version
|
assert_envs version: first_version
|
||||||
assert_env :HOST_TOKEN, "abcd", version: first_version
|
|
||||||
assert_env :SECRET_TOKEN, "1234 with \"中文\"", version: first_version
|
|
||||||
|
|
||||||
second_version = update_app_rev
|
second_version = update_app_rev
|
||||||
|
|
||||||
@@ -97,16 +94,38 @@ class MainTest < IntegrationTest
|
|||||||
assert_equal contents, deployer_exec("cat .env", capture: true)
|
assert_equal contents, deployer_exec("cat .env", capture: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def assert_env(key, value, version:)
|
def assert_envs(version:)
|
||||||
assert_equal "#{key}=#{value}", docker_compose("exec vm1 docker exec app-web-#{version} env | grep #{key}", capture: true)
|
assert_env :CLEAR_TOKEN, "4321", version: version, vm: :vm1
|
||||||
|
assert_env :HOST_TOKEN, "abcd", version: version, vm: :vm1
|
||||||
|
assert_env :SECRET_TOKEN, "1234 with \"中文\"", version: version, vm: :vm1
|
||||||
|
assert_no_env :CLEAR_TAG, version: version, vm: :vm1
|
||||||
|
assert_no_env :SECRET_TAG, version: version, vm: :vm11
|
||||||
|
assert_env :CLEAR_TAG, "tagged", version: version, vm: :vm2
|
||||||
|
assert_env :SECRET_TAG, "TAGME", version: version, vm: :vm2
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_env(key, value, vm:, version:)
|
||||||
|
assert_equal "#{key}=#{value}", docker_compose("exec #{vm} docker exec app-web-#{version} env | grep #{key}", capture: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_no_env(key, vm:, version:)
|
||||||
|
assert_raises(RuntimeError, /exit 1/) do
|
||||||
|
docker_compose("exec #{vm} docker exec app-web-#{version} env | grep #{key}", capture: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def assert_env_files
|
||||||
|
assert_local_env_file "SECRET_TOKEN='1234 with \"中文\"'\nSECRET_TAG='TAGME'"
|
||||||
|
assert_remote_env_file "SECRET_TOKEN=1234 with \"中文\"", vm: :vm1
|
||||||
|
assert_remote_env_file "SECRET_TOKEN=1234 with \"中文\"\nSECRET_TAG=TAGME", vm: :vm2
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_local_env_file
|
def remove_local_env_file
|
||||||
deployer_exec("rm .env")
|
deployer_exec("rm .env")
|
||||||
end
|
end
|
||||||
|
|
||||||
def assert_remote_env_file(contents)
|
def assert_remote_env_file(contents, vm:)
|
||||||
assert_equal contents, docker_compose("exec vm1 cat /root/.kamal/env/roles/app-web.env", capture: true)
|
assert_equal contents, docker_compose("exec #{vm} cat /root/.kamal/env/roles/app-web.env", capture: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
def assert_no_remote_env_file
|
def assert_no_remote_env_file
|
||||||
|
|||||||
Reference in New Issue
Block a user