Host specific env with tags
Allow hosts to be tagged so we can have host specific env variables.
We might want host specific env variables for things like datacenter
specific tags or testing GC settings on a specific host.
Right now you either need to set up a separate role, or have the app
be host aware.
Now you can define tag env variables and assign those to hosts.
For example:
```
servers:
- 1.1.1.1
- 1.1.1.2: tag1
- 1.1.1.2: tag2
- 1.1.1.3: [ tag1, tag2 ]
env_tags:
tag1:
ENV1: value1
tag2:
ENV2: value2
```
The tag env supports the full env format, allowing you to set secret and
clear values.
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