Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aca7796e9d | ||
|
|
8b6d8306d1 | ||
|
|
bb50546467 | ||
|
|
acc6b9ad71 | ||
|
|
9c681d4a38 | ||
|
|
2a8924b53c | ||
|
|
c5ae54d7d4 | ||
|
|
4b05068493 | ||
|
|
68eb549795 | ||
|
|
1a3dd52af4 | ||
|
|
457f06da13 | ||
|
|
7fa53d90bd | ||
|
|
a155b7baab | ||
|
|
175e3bc159 | ||
|
|
e3d8a2aa82 | ||
|
|
0e067fb5e1 | ||
|
|
63babecba7 | ||
|
|
79baa598fa | ||
|
|
b1dc188841 | ||
|
|
635876bdb9 | ||
|
|
11521517fa | ||
|
|
610d9de3fd | ||
|
|
bf79df0f72 | ||
|
|
a0959b5afd | ||
|
|
7472e5dfa6 | ||
|
|
887b7dd46d | ||
|
|
77a79b299a | ||
|
|
efcb855db7 | ||
|
|
7137850354 | ||
|
|
8a85840a47 | ||
|
|
80cc0c23d8 | ||
|
|
14a9129410 | ||
|
|
60187cc3a4 | ||
|
|
87cb8c1f71 | ||
|
|
ed58ce6e61 | ||
|
|
263b4a4fb8 | ||
|
|
073f745677 | ||
|
|
a9cc7c73d2 | ||
|
|
6898e8789e | ||
|
|
d0ac6507e7 | ||
|
|
628a47ad88 | ||
|
|
47f8725cf3 | ||
|
|
5fd4a28bf7 | ||
|
|
97ba6b746b | ||
|
|
9e25d8a012 | ||
|
|
da161445fa | ||
|
|
f339626667 | ||
|
|
2d86d4f7cc | ||
|
|
792aa1dbdf | ||
|
|
24a2f51641 | ||
|
|
8f53104d00 | ||
|
|
2d22143a24 | ||
|
|
78fc91f2ec | ||
|
|
dd748fac8c | ||
|
|
b732b2dd55 | ||
|
|
e3254b2aa8 | ||
|
|
e9269d2ee8 | ||
|
|
d2214b43b7 | ||
|
|
370481921e | ||
|
|
aa23f26330 | ||
|
|
f4933d83bf | ||
|
|
6c36c82153 | ||
|
|
8ca04032a1 | ||
|
|
2fb22c934b | ||
|
|
f96d071222 | ||
|
|
f6662c7a8f | ||
|
|
645f5ab72d | ||
|
|
8dca65f48f | ||
|
|
1a2796a7d0 | ||
|
|
d80fdf8468 |
18
.github/workflows/ci.yml
vendored
18
.github/workflows/ci.yml
vendored
@@ -12,17 +12,29 @@ jobs:
|
|||||||
- "2.7"
|
- "2.7"
|
||||||
- "3.1"
|
- "3.1"
|
||||||
- "3.2"
|
- "3.2"
|
||||||
|
- "3.3"
|
||||||
gemfile:
|
gemfile:
|
||||||
- Gemfile
|
- Gemfile
|
||||||
|
- gemfiles/ruby_2.7.gemfile
|
||||||
- gemfiles/rails_edge.gemfile
|
- gemfiles/rails_edge.gemfile
|
||||||
continue-on-error: [false]
|
exclude:
|
||||||
|
- ruby-version: "2.7"
|
||||||
|
gemfile: Gemfile
|
||||||
|
- ruby-version: "2.7"
|
||||||
|
gemfile: gemfiles/rails_edge.gemfile
|
||||||
|
- ruby-version: "3.1"
|
||||||
|
gemfile: gemfiles/ruby_2.7.gemfile
|
||||||
|
- ruby-version: "3.2"
|
||||||
|
gemfile: gemfiles/ruby_2.7.gemfile
|
||||||
|
- ruby-version: "3.3"
|
||||||
|
gemfile: gemfiles/ruby_2.7.gemfile
|
||||||
name: ${{ format('Tests (Ruby {0})', matrix.ruby-version) }}
|
name: ${{ format('Tests (Ruby {0})', matrix.ruby-version) }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
continue-on-error: ${{ matrix.continue-on-error }}
|
continue-on-error: true
|
||||||
env:
|
env:
|
||||||
BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}
|
BUNDLE_GEMFILE: ${{ github.workspace }}/${{ matrix.gemfile }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Ruby
|
- name: Install Ruby
|
||||||
uses: ruby/setup-ruby@v1
|
uses: ruby/setup-ruby@v1
|
||||||
|
|||||||
122
Gemfile.lock
122
Gemfile.lock
@@ -1,8 +1,9 @@
|
|||||||
PATH
|
PATH
|
||||||
remote: .
|
remote: .
|
||||||
specs:
|
specs:
|
||||||
kamal (1.0.0)
|
kamal (1.3.1)
|
||||||
activesupport (>= 7.0)
|
activesupport (>= 7.0)
|
||||||
|
base64 (~> 0.2)
|
||||||
bcrypt_pbkdf (~> 1.0)
|
bcrypt_pbkdf (~> 1.0)
|
||||||
concurrent-ruby (~> 1.2)
|
concurrent-ruby (~> 1.2)
|
||||||
dotenv (~> 2.8)
|
dotenv (~> 2.8)
|
||||||
@@ -15,82 +16,111 @@ PATH
|
|||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actionpack (7.0.4.3)
|
actionpack (7.1.2)
|
||||||
actionview (= 7.0.4.3)
|
actionview (= 7.1.2)
|
||||||
activesupport (= 7.0.4.3)
|
activesupport (= 7.1.2)
|
||||||
rack (~> 2.0, >= 2.2.0)
|
nokogiri (>= 1.8.5)
|
||||||
|
racc
|
||||||
|
rack (>= 2.2.4)
|
||||||
|
rack-session (>= 1.0.1)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.2)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
rails-html-sanitizer (~> 1.6)
|
||||||
actionview (7.0.4.3)
|
actionview (7.1.2)
|
||||||
activesupport (= 7.0.4.3)
|
activesupport (= 7.1.2)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.4)
|
erubi (~> 1.11)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.2)
|
||||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
rails-html-sanitizer (~> 1.6)
|
||||||
activesupport (7.0.4.3)
|
activesupport (7.1.2)
|
||||||
|
base64
|
||||||
|
bigdecimal
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
|
connection_pool (>= 2.2.5)
|
||||||
|
drb
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.6, < 2)
|
||||||
minitest (>= 5.1)
|
minitest (>= 5.1)
|
||||||
|
mutex_m
|
||||||
tzinfo (~> 2.0)
|
tzinfo (~> 2.0)
|
||||||
|
base64 (0.2.0)
|
||||||
bcrypt_pbkdf (1.1.0)
|
bcrypt_pbkdf (1.1.0)
|
||||||
|
bigdecimal (3.1.5)
|
||||||
builder (3.2.4)
|
builder (3.2.4)
|
||||||
concurrent-ruby (1.2.2)
|
concurrent-ruby (1.2.2)
|
||||||
|
connection_pool (2.4.1)
|
||||||
crass (1.0.6)
|
crass (1.0.6)
|
||||||
debug (1.7.2)
|
debug (1.9.1)
|
||||||
irb (>= 1.5.0)
|
irb (~> 1.10)
|
||||||
reline (>= 0.3.1)
|
reline (>= 0.3.8)
|
||||||
dotenv (2.8.1)
|
dotenv (2.8.1)
|
||||||
|
drb (2.2.0)
|
||||||
|
ruby2_keywords
|
||||||
ed25519 (1.3.0)
|
ed25519 (1.3.0)
|
||||||
erubi (1.12.0)
|
erubi (1.12.0)
|
||||||
i18n (1.12.0)
|
i18n (1.14.1)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
io-console (0.6.0)
|
io-console (0.7.1)
|
||||||
irb (1.6.3)
|
irb (1.11.0)
|
||||||
reline (>= 0.3.0)
|
rdoc
|
||||||
loofah (2.20.0)
|
reline (>= 0.3.8)
|
||||||
|
loofah (2.22.0)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.5.9)
|
nokogiri (>= 1.12.0)
|
||||||
method_source (1.0.0)
|
minitest (5.20.0)
|
||||||
minitest (5.18.0)
|
mocha (2.1.0)
|
||||||
mocha (2.0.2)
|
|
||||||
ruby2_keywords (>= 0.0.5)
|
ruby2_keywords (>= 0.0.5)
|
||||||
|
mutex_m (0.2.0)
|
||||||
net-scp (4.0.0)
|
net-scp (4.0.0)
|
||||||
net-ssh (>= 2.6.5, < 8.0.0)
|
net-ssh (>= 2.6.5, < 8.0.0)
|
||||||
net-ssh (7.1.0)
|
net-ssh (7.2.1)
|
||||||
nokogiri (1.14.2-arm64-darwin)
|
nokogiri (1.16.0-arm64-darwin)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.14.2-x86_64-darwin)
|
nokogiri (1.16.0-x86_64-darwin)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.14.2-x86_64-linux)
|
nokogiri (1.16.0-x86_64-linux)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
racc (1.6.2)
|
psych (5.1.2)
|
||||||
rack (2.2.6.4)
|
stringio
|
||||||
|
racc (1.7.3)
|
||||||
|
rack (3.0.8)
|
||||||
|
rack-session (2.0.0)
|
||||||
|
rack (>= 3.0.0)
|
||||||
rack-test (2.1.0)
|
rack-test (2.1.0)
|
||||||
rack (>= 1.3)
|
rack (>= 1.3)
|
||||||
rails-dom-testing (2.0.3)
|
rackup (2.1.0)
|
||||||
activesupport (>= 4.2.0)
|
rack (>= 3)
|
||||||
|
webrick (~> 1.8)
|
||||||
|
rails-dom-testing (2.2.0)
|
||||||
|
activesupport (>= 5.0.0)
|
||||||
|
minitest
|
||||||
nokogiri (>= 1.6)
|
nokogiri (>= 1.6)
|
||||||
rails-html-sanitizer (1.5.0)
|
rails-html-sanitizer (1.6.0)
|
||||||
loofah (~> 2.19, >= 2.19.1)
|
loofah (~> 2.21)
|
||||||
railties (7.0.4.3)
|
nokogiri (~> 1.14)
|
||||||
actionpack (= 7.0.4.3)
|
railties (7.1.2)
|
||||||
activesupport (= 7.0.4.3)
|
actionpack (= 7.1.2)
|
||||||
method_source
|
activesupport (= 7.1.2)
|
||||||
|
irb
|
||||||
|
rackup (>= 1.0.0)
|
||||||
rake (>= 12.2)
|
rake (>= 12.2)
|
||||||
thor (~> 1.0)
|
thor (~> 1.0, >= 1.2.2)
|
||||||
zeitwerk (~> 2.5)
|
zeitwerk (~> 2.6)
|
||||||
rake (13.0.6)
|
rake (13.1.0)
|
||||||
reline (0.3.3)
|
rdoc (6.6.2)
|
||||||
|
psych (>= 4.0.0)
|
||||||
|
reline (0.4.2)
|
||||||
io-console (~> 0.5)
|
io-console (~> 0.5)
|
||||||
ruby2_keywords (0.0.5)
|
ruby2_keywords (0.0.5)
|
||||||
sshkit (1.21.4)
|
sshkit (1.21.7)
|
||||||
|
mutex_m
|
||||||
net-scp (>= 1.1.2)
|
net-scp (>= 1.1.2)
|
||||||
net-ssh (>= 2.8.0)
|
net-ssh (>= 2.8.0)
|
||||||
thor (1.2.1)
|
stringio (3.1.0)
|
||||||
|
thor (1.3.0)
|
||||||
tzinfo (2.0.6)
|
tzinfo (2.0.6)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
zeitwerk (2.6.7)
|
webrick (1.8.1)
|
||||||
|
zeitwerk (2.6.12)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
arm64-darwin
|
arm64-darwin
|
||||||
|
|||||||
6
gemfiles/ruby_2.7.gemfile
Normal file
6
gemfiles/ruby_2.7.gemfile
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
source 'https://rubygems.org'
|
||||||
|
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
|
||||||
|
|
||||||
|
gemspec path: "../"
|
||||||
|
|
||||||
|
gem "nokogiri", "~> 1.15.0"
|
||||||
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
|
|||||||
spec.add_dependency "ed25519", "~> 1.2"
|
spec.add_dependency "ed25519", "~> 1.2"
|
||||||
spec.add_dependency "bcrypt_pbkdf", "~> 1.0"
|
spec.add_dependency "bcrypt_pbkdf", "~> 1.0"
|
||||||
spec.add_dependency "concurrent-ruby", "~> 1.2"
|
spec.add_dependency "concurrent-ruby", "~> 1.2"
|
||||||
|
spec.add_dependency "base64", "~> 0.2"
|
||||||
|
|
||||||
spec.add_development_dependency "debug"
|
spec.add_development_dependency "debug"
|
||||||
spec.add_development_dependency "mocha"
|
spec.add_development_dependency "mocha"
|
||||||
|
|||||||
@@ -49,17 +49,21 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "reboot [NAME]", "Reboot existing accessory on host (stop container, remove container, start new container)"
|
desc "reboot [NAME]", "Reboot existing accessory on host (stop container, remove container, start new container; use NAME=all to boot all accessories)"
|
||||||
def reboot(name)
|
def reboot(name)
|
||||||
mutating do
|
mutating do
|
||||||
with_accessory(name) do |accessory|
|
if name == "all"
|
||||||
on(accessory.hosts) do
|
KAMAL.accessory_names.each { |accessory_name| reboot(accessory_name) }
|
||||||
execute *KAMAL.registry.login
|
else
|
||||||
end
|
with_accessory(name) do |accessory|
|
||||||
|
on(accessory.hosts) do
|
||||||
|
execute *KAMAL.registry.login
|
||||||
|
end
|
||||||
|
|
||||||
stop(name)
|
stop(name)
|
||||||
remove_container(name)
|
remove_container(name)
|
||||||
boot(name, login: false)
|
boot(name, login: false)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -147,8 +147,12 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
using_version(version_or_latest) do |version|
|
using_version(version_or_latest) do |version|
|
||||||
say "Launching command with version #{version} from new container...", :magenta
|
say "Launching command with version #{version} from new container...", :magenta
|
||||||
on(KAMAL.hosts) do |host|
|
on(KAMAL.hosts) do |host|
|
||||||
execute *KAMAL.auditor.record("Executed cmd '#{cmd}' on app version #{version}"), verbosity: :debug
|
roles = KAMAL.roles_on(host)
|
||||||
puts_by_host host, capture_with_info(*KAMAL.app.execute_in_new_container(cmd))
|
|
||||||
|
roles.each do |role|
|
||||||
|
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))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ module Kamal::Cli
|
|||||||
class_option :version, desc: "Run commands against a specific app version"
|
class_option :version, desc: "Run commands against a specific app version"
|
||||||
|
|
||||||
class_option :primary, type: :boolean, aliases: "-p", desc: "Run commands only on primary host instead of all"
|
class_option :primary, type: :boolean, aliases: "-p", desc: "Run commands only on primary host instead of all"
|
||||||
class_option :hosts, aliases: "-h", desc: "Run commands on these hosts instead of all (separate by comma)"
|
class_option :hosts, aliases: "-h", desc: "Run commands on these hosts instead of all (separate by comma, supports wildcards with *)"
|
||||||
class_option :roles, aliases: "-r", desc: "Run commands on these roles instead of all (separate by comma)"
|
class_option :roles, aliases: "-r", desc: "Run commands on these roles instead of all (separate by comma, supports wildcards with *)"
|
||||||
|
|
||||||
class_option :config_file, aliases: "-c", default: "config/deploy.yml", desc: "Path to config file"
|
class_option :config_file, aliases: "-c", default: "config/deploy.yml", desc: "Path to config file"
|
||||||
class_option :destination, aliases: "-d", desc: "Specify destination to be used for config file (staging -> deploy.staging.yml)"
|
class_option :destination, aliases: "-d", desc: "Specify destination to be used for config file (staging -> deploy.staging.yml)"
|
||||||
@@ -24,6 +24,7 @@ module Kamal::Cli
|
|||||||
|
|
||||||
def initialize(*)
|
def initialize(*)
|
||||||
super
|
super
|
||||||
|
@original_env = ENV.to_h.dup
|
||||||
load_envs
|
load_envs
|
||||||
initialize_commander(options_with_subcommand_class_options)
|
initialize_commander(options_with_subcommand_class_options)
|
||||||
end
|
end
|
||||||
@@ -37,6 +38,12 @@ module Kamal::Cli
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reload_envs
|
||||||
|
ENV.clear
|
||||||
|
ENV.update(@original_env)
|
||||||
|
load_envs
|
||||||
|
end
|
||||||
|
|
||||||
def options_with_subcommand_class_options
|
def options_with_subcommand_class_options
|
||||||
options.merge(@_initializer.last[:class_options] || {})
|
options.merge(@_initializer.last[:class_options] || {})
|
||||||
end
|
end
|
||||||
@@ -75,8 +82,6 @@ module Kamal::Cli
|
|||||||
def mutating
|
def mutating
|
||||||
return yield if KAMAL.holding_lock?
|
return yield if KAMAL.holding_lock?
|
||||||
|
|
||||||
KAMAL.config.ensure_env_available
|
|
||||||
|
|
||||||
run_hook "pre-connect"
|
run_hook "pre-connect"
|
||||||
|
|
||||||
ensure_run_directory
|
ensure_run_directory
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ class Kamal::Cli::Healthcheck < Kamal::Cli::Base
|
|||||||
|
|
||||||
desc "perform", "Health check current app version"
|
desc "perform", "Health check current app version"
|
||||||
def perform
|
def perform
|
||||||
|
raise "The primary host is not configured to run Traefik" unless KAMAL.config.role(KAMAL.config.primary_role).running_traefik?
|
||||||
on(KAMAL.primary_host) do
|
on(KAMAL.primary_host) do
|
||||||
begin
|
begin
|
||||||
execute *KAMAL.healthcheck.run
|
execute *KAMAL.healthcheck.run
|
||||||
|
|||||||
@@ -38,8 +38,10 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
say "Ensure Traefik is running...", :magenta
|
say "Ensure Traefik is running...", :magenta
|
||||||
invoke "kamal:cli:traefik:boot", [], invoke_options
|
invoke "kamal:cli:traefik:boot", [], invoke_options
|
||||||
|
|
||||||
say "Ensure app can pass healthcheck...", :magenta
|
if KAMAL.config.role(KAMAL.config.primary_role).running_traefik?
|
||||||
invoke "kamal:cli:healthcheck:perform", [], invoke_options
|
say "Ensure app can pass healthcheck...", :magenta
|
||||||
|
invoke "kamal:cli:healthcheck:perform", [], invoke_options
|
||||||
|
end
|
||||||
|
|
||||||
say "Detect stale containers...", :magenta
|
say "Detect stale containers...", :magenta
|
||||||
invoke "kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true)
|
invoke "kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true)
|
||||||
@@ -170,6 +172,7 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
desc "envify", "Create .env by evaluating .env.erb (or .env.staging.erb -> .env.staging when using -d staging)"
|
desc "envify", "Create .env by evaluating .env.erb (or .env.staging.erb -> .env.staging when using -d staging)"
|
||||||
|
option :skip_push, aliases: "-P", type: :boolean, default: false, desc: "Skip .env file push"
|
||||||
def envify
|
def envify
|
||||||
if destination = options[:destination]
|
if destination = options[:destination]
|
||||||
env_template_path = ".env.#{destination}.erb"
|
env_template_path = ".env.#{destination}.erb"
|
||||||
@@ -179,10 +182,12 @@ class Kamal::Cli::Main < Kamal::Cli::Base
|
|||||||
env_path = ".env"
|
env_path = ".env"
|
||||||
end
|
end
|
||||||
|
|
||||||
File.write(env_path, ERB.new(File.read(env_template_path)).result, perm: 0600)
|
File.write(env_path, ERB.new(File.read(env_template_path), trim_mode: "-").result, perm: 0600)
|
||||||
|
|
||||||
load_envs # reload new file
|
unless options[:skip_push]
|
||||||
invoke "kamal:cli:env:push", options
|
reload_envs
|
||||||
|
invoke "kamal:cli:env:push", options
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
desc "remove", "Remove Traefik, app, accessories, and registry session from servers"
|
desc "remove", "Remove Traefik, app, accessories, and registry session from servers"
|
||||||
|
|||||||
@@ -83,3 +83,15 @@ registry:
|
|||||||
# boot:
|
# boot:
|
||||||
# limit: 10 # Can also specify as a percentage of total hosts, such as "25%"
|
# limit: 10 # Can also specify as a percentage of total hosts, such as "25%"
|
||||||
# wait: 2
|
# wait: 2
|
||||||
|
|
||||||
|
# Configure the role used to determine the primary_host. This host takes
|
||||||
|
# deploy locks, runs health checks during the deploy, and follow logs, etc.
|
||||||
|
#
|
||||||
|
# Caution: there's no support for role renaming yet, so be careful to cleanup
|
||||||
|
# the previous role on the deployed hosts.
|
||||||
|
# primary_role: web
|
||||||
|
|
||||||
|
# Controls if we abort when see a role with no hosts. Disabling this may be
|
||||||
|
# useful for more complex deploy configurations.
|
||||||
|
#
|
||||||
|
# allow_empty_roles: false
|
||||||
|
|||||||
3
lib/kamal/cli/templates/sample_hooks/post-traefik-reboot.sample
Executable file
3
lib/kamal/cli/templates/sample_hooks/post-traefik-reboot.sample
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "Rebooted Traefik on $KAMAL_HOSTS"
|
||||||
@@ -32,7 +32,7 @@ fi
|
|||||||
current_branch=$(git branch --show-current)
|
current_branch=$(git branch --show-current)
|
||||||
|
|
||||||
if [ -z "$current_branch" ]; then
|
if [ -z "$current_branch" ]; then
|
||||||
echo "No git remote set, aborting..." >&2
|
echo "Not on a git branch, aborting..." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|||||||
3
lib/kamal/cli/templates/sample_hooks/pre-traefik-reboot.sample
Executable file
3
lib/kamal/cli/templates/sample_hooks/pre-traefik-reboot.sample
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
echo "Rebooting Traefik on $KAMAL_HOSTS..."
|
||||||
@@ -13,12 +13,18 @@ class Kamal::Cli::Traefik < Kamal::Cli::Base
|
|||||||
option :rolling, type: :boolean, default: false, desc: "Reboot traefik on hosts in sequence, rather than in parallel"
|
option :rolling, type: :boolean, default: false, desc: "Reboot traefik on hosts in sequence, rather than in parallel"
|
||||||
def reboot
|
def reboot
|
||||||
mutating do
|
mutating do
|
||||||
on(KAMAL.traefik_hosts, in: options[:rolling] ? :sequence : :parallel) do
|
host_groups = options[:rolling] ? KAMAL.traefik_hosts : [KAMAL.traefik_hosts]
|
||||||
execute *KAMAL.auditor.record("Rebooted traefik"), verbosity: :debug
|
host_groups.each do |hosts|
|
||||||
execute *KAMAL.registry.login
|
host_list = Array(hosts).join(",")
|
||||||
execute *KAMAL.traefik.stop
|
run_hook "pre-traefik-reboot", hosts: host_list
|
||||||
execute *KAMAL.traefik.remove_container
|
on(hosts) do
|
||||||
execute *KAMAL.traefik.run
|
execute *KAMAL.auditor.record("Rebooted traefik"), verbosity: :debug
|
||||||
|
execute *KAMAL.registry.login
|
||||||
|
execute *KAMAL.traefik.stop
|
||||||
|
execute *KAMAL.traefik.remove_container
|
||||||
|
execute *KAMAL.traefik.run
|
||||||
|
end
|
||||||
|
run_hook "post-traefik-reboot", hosts: host_list
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -24,19 +24,36 @@ class Kamal::Commander
|
|||||||
attr_reader :specific_roles, :specific_hosts
|
attr_reader :specific_roles, :specific_hosts
|
||||||
|
|
||||||
def specific_primary!
|
def specific_primary!
|
||||||
self.specific_hosts = [ config.primary_web_host ]
|
self.specific_hosts = [ config.primary_host ]
|
||||||
end
|
end
|
||||||
|
|
||||||
def specific_roles=(role_names)
|
def specific_roles=(role_names)
|
||||||
@specific_roles = config.roles.select { |r| role_names.include?(r.name) } if role_names.present?
|
if role_names.present?
|
||||||
|
@specific_roles = Kamal::Utils.filter_specific_items(role_names, config.roles)
|
||||||
|
|
||||||
|
if @specific_roles.empty?
|
||||||
|
raise ArgumentError, "No --roles match for #{role_names.join(',')}"
|
||||||
|
end
|
||||||
|
|
||||||
|
@specific_roles
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def specific_hosts=(hosts)
|
def specific_hosts=(hosts)
|
||||||
@specific_hosts = config.all_hosts & hosts if hosts.present?
|
if hosts.present?
|
||||||
|
@specific_hosts = Kamal::Utils.filter_specific_items(hosts, config.all_hosts)
|
||||||
|
|
||||||
|
if @specific_hosts.empty?
|
||||||
|
raise ArgumentError, "No --hosts match for #{hosts.join(',')}"
|
||||||
|
end
|
||||||
|
|
||||||
|
@specific_hosts
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def primary_host
|
def primary_host
|
||||||
specific_hosts&.first || specific_roles&.first&.primary_host || config.primary_web_host
|
# Given a list of specific roles, make an effort to match up with the primary_role
|
||||||
|
specific_hosts&.first || specific_roles&.detect { |role| role.name == config.primary_role }&.primary_host || specific_roles&.first&.primary_host || config.primary_host
|
||||||
end
|
end
|
||||||
|
|
||||||
def primary_role
|
def primary_role
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ class Kamal::Commands::App < Kamal::Commands::Base
|
|||||||
"--name", container_name,
|
"--name", container_name,
|
||||||
*(["--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}\"",
|
||||||
*role_config.env_args,
|
*role_config.env_args,
|
||||||
*role_config.health_check_args,
|
*role_config.health_check_args,
|
||||||
*config.logging_args,
|
*config.logging_args,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ module Kamal::Commands
|
|||||||
elsif config.ssh.proxy && config.ssh.proxy.is_a?(Net::SSH::Proxy::Command)
|
elsif config.ssh.proxy && config.ssh.proxy.is_a?(Net::SSH::Proxy::Command)
|
||||||
cmd << " -o ProxyCommand='#{config.ssh.proxy.command_line_template}'"
|
cmd << " -o ProxyCommand='#{config.ssh.proxy.command_line_template}'"
|
||||||
end
|
end
|
||||||
cmd << " -t #{config.ssh.user}@#{host} '#{command.join(" ")}'"
|
cmd << " -t #{config.ssh.user}@#{host} -p #{config.ssh.port} '#{command.join(" ")}'"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,6 @@ class Kamal::Commands::Docker < Kamal::Commands::Base
|
|||||||
|
|
||||||
# Do we have superuser access to install Docker and start system services?
|
# Do we have superuser access to install Docker and start system services?
|
||||||
def superuser?
|
def superuser?
|
||||||
[ '[ "${EUID:-$(id -u)}" -eq 0 ]' ]
|
[ '[ "${EUID:-$(id -u)}" -eq 0 ] || command -v sudo >/dev/null || command -v su >/dev/null' ]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
class Kamal::Commands::Healthcheck < Kamal::Commands::Base
|
class Kamal::Commands::Healthcheck < Kamal::Commands::Base
|
||||||
|
|
||||||
def run
|
def run
|
||||||
web = config.role(:web)
|
primary = config.role(config.primary_role)
|
||||||
|
|
||||||
docker :run,
|
docker :run,
|
||||||
"--detach",
|
"--detach",
|
||||||
@@ -9,12 +9,12 @@ 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}\"",
|
||||||
*web.env_args,
|
*primary.env_args,
|
||||||
*web.health_check_args(cord: false),
|
*primary.health_check_args(cord: false),
|
||||||
*config.volume_args,
|
*config.volume_args,
|
||||||
*web.option_args,
|
*primary.option_args,
|
||||||
config.absolute_image,
|
config.absolute_image,
|
||||||
web.cmd
|
primary.cmd
|
||||||
end
|
end
|
||||||
|
|
||||||
def status
|
def status
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
require "active_support/duration"
|
require "active_support/duration"
|
||||||
require "time"
|
require "time"
|
||||||
|
require "base64"
|
||||||
|
|
||||||
class Kamal::Commands::Lock < Kamal::Commands::Base
|
class Kamal::Commands::Lock < Kamal::Commands::Base
|
||||||
def acquire(message, version)
|
def acquire(message, version)
|
||||||
|
|||||||
@@ -6,6 +6,14 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
|
|||||||
DEFAULT_ARGS = {
|
DEFAULT_ARGS = {
|
||||||
'log.level' => 'DEBUG'
|
'log.level' => 'DEBUG'
|
||||||
}
|
}
|
||||||
|
DEFAULT_LABELS = {
|
||||||
|
# These ensure we serve a 502 rather than a 404 if no containers are available
|
||||||
|
"traefik.http.routers.catchall.entryPoints" => "http",
|
||||||
|
"traefik.http.routers.catchall.rule" => "PathPrefix(`/`)",
|
||||||
|
"traefik.http.routers.catchall.service" => "unavailable",
|
||||||
|
"traefik.http.routers.catchall.priority" => 1,
|
||||||
|
"traefik.http.services.unavailable.loadbalancer.server.port" => "0"
|
||||||
|
}
|
||||||
|
|
||||||
def run
|
def run
|
||||||
docker :run, "--name traefik",
|
docker :run, "--name traefik",
|
||||||
@@ -97,7 +105,7 @@ class Kamal::Commands::Traefik < Kamal::Commands::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def labels
|
def labels
|
||||||
config.traefik["labels"] || []
|
DEFAULT_LABELS.merge(config.traefik["labels"] || {})
|
||||||
end
|
end
|
||||||
|
|
||||||
def image
|
def image
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ class Kamal::Configuration
|
|||||||
|
|
||||||
def load_config_file(file)
|
def load_config_file(file)
|
||||||
if file.exist?
|
if file.exist?
|
||||||
YAML.load(ERB.new(IO.read(file)).result).symbolize_keys
|
# Newer Psych doesn't load aliases by default
|
||||||
|
load_method = YAML.respond_to?(:unsafe_load) ? :unsafe_load : :load
|
||||||
|
YAML.send(load_method, ERB.new(IO.read(file)).result).symbolize_keys
|
||||||
else
|
else
|
||||||
raise "Configuration file not found in #{file}"
|
raise "Configuration file not found in #{file}"
|
||||||
end
|
end
|
||||||
@@ -89,15 +91,22 @@ class Kamal::Configuration
|
|||||||
roles.flat_map(&:hosts).uniq
|
roles.flat_map(&:hosts).uniq
|
||||||
end
|
end
|
||||||
|
|
||||||
def primary_web_host
|
def primary_host
|
||||||
role(:web).primary_host
|
role(primary_role)&.primary_host
|
||||||
|
end
|
||||||
|
|
||||||
|
def traefik_roles
|
||||||
|
roles.select(&:running_traefik?)
|
||||||
|
end
|
||||||
|
|
||||||
|
def traefik_role_names
|
||||||
|
traefik_roles.flat_map(&:name)
|
||||||
end
|
end
|
||||||
|
|
||||||
def traefik_hosts
|
def traefik_hosts
|
||||||
roles.select(&:running_traefik?).flat_map(&:hosts).uniq
|
traefik_roles.flat_map(&:hosts).uniq
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def repository
|
def repository
|
||||||
[ raw_config.registry["server"], image ].compact.join("/")
|
[ raw_config.registry["server"], image ].compact.join("/")
|
||||||
end
|
end
|
||||||
@@ -199,23 +208,24 @@ class Kamal::Configuration
|
|||||||
raw_config.asset_path
|
raw_config.asset_path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def primary_role
|
||||||
|
raw_config.primary_role || "web"
|
||||||
|
end
|
||||||
|
|
||||||
|
def allow_empty_roles?
|
||||||
|
raw_config.allow_empty_roles
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
def valid?
|
def valid?
|
||||||
ensure_destination_if_required && ensure_required_keys_present && ensure_valid_kamal_version
|
ensure_destination_if_required && ensure_required_keys_present && ensure_valid_kamal_version
|
||||||
end
|
end
|
||||||
|
|
||||||
# Will raise KeyError if any secret ENVs are missing
|
|
||||||
def ensure_env_available
|
|
||||||
roles.collect(&:env_file).each(&:to_s)
|
|
||||||
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_h
|
def to_h
|
||||||
{
|
{
|
||||||
roles: role_names,
|
roles: role_names,
|
||||||
hosts: all_hosts,
|
hosts: all_hosts,
|
||||||
primary_host: primary_web_host,
|
primary_host: primary_host,
|
||||||
version: version,
|
version: version,
|
||||||
repository: repository,
|
repository: repository,
|
||||||
absolute_image: absolute_image,
|
absolute_image: absolute_image,
|
||||||
@@ -254,9 +264,19 @@ class Kamal::Configuration
|
|||||||
raise ArgumentError, "You must specify a password for the registry in config/deploy.yml (or set the ENV variable if that's used)"
|
raise ArgumentError, "You must specify a password for the registry in config/deploy.yml (or set the ENV variable if that's used)"
|
||||||
end
|
end
|
||||||
|
|
||||||
roles.each do |role|
|
unless role_names.include?(primary_role)
|
||||||
if role.hosts.empty?
|
raise ArgumentError, "The primary_role #{primary_role} isn't defined"
|
||||||
raise ArgumentError, "No servers specified for the #{role.name} role"
|
end
|
||||||
|
|
||||||
|
if role(primary_role).hosts.empty?
|
||||||
|
raise ArgumentError, "No servers specified for the #{primary_role} primary_role"
|
||||||
|
end
|
||||||
|
|
||||||
|
unless allow_empty_roles?
|
||||||
|
roles.each do |role|
|
||||||
|
if role.hosts.empty?
|
||||||
|
raise ArgumentError, "No servers specified for the #{role.name} role. You can ignore this with allow_empty_roles: true"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -70,8 +70,8 @@ class Kamal::Configuration::Accessory
|
|||||||
|
|
||||||
def directories
|
def directories
|
||||||
specifics["directories"]&.to_h do |host_to_container_mapping|
|
specifics["directories"]&.to_h do |host_to_container_mapping|
|
||||||
host_relative_path, container_path = host_to_container_mapping.split(":")
|
host_path, container_path = host_to_container_mapping.split(":")
|
||||||
[ expand_host_path(host_relative_path), container_path ]
|
[ expand_host_path(host_path), container_path ]
|
||||||
end || {}
|
end || {}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -138,13 +138,17 @@ class Kamal::Configuration::Accessory
|
|||||||
|
|
||||||
def remote_directories_as_volumes
|
def remote_directories_as_volumes
|
||||||
specifics["directories"]&.collect do |host_to_container_mapping|
|
specifics["directories"]&.collect do |host_to_container_mapping|
|
||||||
host_relative_path, container_path = host_to_container_mapping.split(":")
|
host_path, container_path = host_to_container_mapping.split(":")
|
||||||
[ expand_host_path(host_relative_path), container_path ].join(":")
|
[ expand_host_path(host_path), container_path ].join(":")
|
||||||
end || []
|
end || []
|
||||||
end
|
end
|
||||||
|
|
||||||
def expand_host_path(host_relative_path)
|
def expand_host_path(host_path)
|
||||||
"#{service_data_directory}/#{host_relative_path}"
|
absolute_path?(host_path) ? host_path : "#{service_data_directory}/#{host_path}"
|
||||||
|
end
|
||||||
|
|
||||||
|
def absolute_path?(path)
|
||||||
|
Pathname.new(path).absolute?
|
||||||
end
|
end
|
||||||
|
|
||||||
def service_data_directory
|
def service_data_directory
|
||||||
|
|||||||
@@ -93,7 +93,15 @@ class Kamal::Configuration::Role
|
|||||||
|
|
||||||
|
|
||||||
def running_traefik?
|
def running_traefik?
|
||||||
name.web? || specializations["traefik"]
|
if specializations["traefik"].nil?
|
||||||
|
primary?
|
||||||
|
else
|
||||||
|
specializations["traefik"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def primary?
|
||||||
|
@config.primary_role == name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@@ -185,6 +193,7 @@ class Kamal::Configuration::Role
|
|||||||
"traefik.http.services.#{traefik_service}.loadbalancer.server.scheme" => "http",
|
"traefik.http.services.#{traefik_service}.loadbalancer.server.scheme" => "http",
|
||||||
|
|
||||||
"traefik.http.routers.#{traefik_service}.rule" => "PathPrefix(`/`)",
|
"traefik.http.routers.#{traefik_service}.rule" => "PathPrefix(`/`)",
|
||||||
|
"traefik.http.routers.#{traefik_service}.priority" => "2",
|
||||||
"traefik.http.middlewares.#{traefik_service}-retry.retry.attempts" => "5",
|
"traefik.http.middlewares.#{traefik_service}-retry.retry.attempts" => "5",
|
||||||
"traefik.http.middlewares.#{traefik_service}-retry.retry.initialinterval" => "500ms",
|
"traefik.http.middlewares.#{traefik_service}-retry.retry.initialinterval" => "500ms",
|
||||||
"traefik.http.routers.#{traefik_service}.middlewares" => "#{traefik_service}-retry@docker"
|
"traefik.http.routers.#{traefik_service}.middlewares" => "#{traefik_service}-retry@docker"
|
||||||
@@ -230,7 +239,7 @@ class Kamal::Configuration::Role
|
|||||||
clear_app_env = config.env["secret"] ? Array(config.env["clear"]) : Array(config.env["clear"] || config.env)
|
clear_app_env = config.env["secret"] ? Array(config.env["clear"]) : Array(config.env["clear"] || config.env)
|
||||||
clear_role_env = specialized_env["secret"] ? Array(specialized_env["clear"]) : Array(specialized_env["clear"] || specialized_env)
|
clear_role_env = specialized_env["secret"] ? Array(specialized_env["clear"]) : Array(specialized_env["clear"] || specialized_env)
|
||||||
|
|
||||||
new_env["clear"] = (clear_app_env + clear_role_env).uniq
|
new_env["clear"] = clear_app_env.to_h.merge(clear_role_env.to_h)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ class Kamal::Configuration::Ssh
|
|||||||
config.fetch("user", "root")
|
config.fetch("user", "root")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def port
|
||||||
|
config.fetch("port", 22)
|
||||||
|
end
|
||||||
|
|
||||||
def proxy
|
def proxy
|
||||||
if (proxy = config["proxy"])
|
if (proxy = config["proxy"])
|
||||||
Net::SSH::Proxy::Jump.new(proxy.include?("@") ? proxy : "root@#{proxy}")
|
Net::SSH::Proxy::Jump.new(proxy.include?("@") ? proxy : "root@#{proxy}")
|
||||||
@@ -18,7 +22,7 @@ class Kamal::Configuration::Ssh
|
|||||||
end
|
end
|
||||||
|
|
||||||
def options
|
def options
|
||||||
{ user: user, proxy: proxy, logger: logger, keepalive: true, keepalive_interval: 30 }.compact
|
{ user: user, port: port, proxy: proxy, logger: logger, keepalive: true, keepalive_interval: 30 }.compact
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_h
|
def to_h
|
||||||
|
|||||||
@@ -58,4 +58,20 @@ module Kamal::Utils
|
|||||||
.gsub(/`/, '\\\\`')
|
.gsub(/`/, '\\\\`')
|
||||||
.gsub(DOLLAR_SIGN_WITHOUT_SHELL_EXPANSION_REGEX, '\$')
|
.gsub(DOLLAR_SIGN_WITHOUT_SHELL_EXPANSION_REGEX, '\$')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Apply a list of host or role filters, including wildcard matches
|
||||||
|
def filter_specific_items(filters, items)
|
||||||
|
matches = []
|
||||||
|
|
||||||
|
Array(filters).select do |filter|
|
||||||
|
matches += Array(items).select do |item|
|
||||||
|
# Only allow * for a wildcard
|
||||||
|
pattern = Regexp.escape(filter).gsub('\*', '.*')
|
||||||
|
# items are roles or hosts
|
||||||
|
(item.respond_to?(:name) ? item.name : item).match(/^#{pattern}$/)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
matches
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
require "active_support/core_ext/module/delegation"
|
require "active_support/core_ext/module/delegation"
|
||||||
|
require "sshkit"
|
||||||
|
|
||||||
class Kamal::Utils::Sensitive
|
class Kamal::Utils::Sensitive
|
||||||
# So SSHKit knows to redact these values.
|
# So SSHKit knows to redact these values.
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
module Kamal
|
module Kamal
|
||||||
VERSION = "1.0.0"
|
VERSION = "1.3.1"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -48,6 +48,18 @@ class CliAccessoryTest < CliTestCase
|
|||||||
run_command("reboot", "mysql")
|
run_command("reboot", "mysql")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "reboot all" do
|
||||||
|
Kamal::Commands::Registry.any_instance.expects(:login).times(3)
|
||||||
|
Kamal::Cli::Accessory.any_instance.expects(:stop).with("mysql")
|
||||||
|
Kamal::Cli::Accessory.any_instance.expects(:remove_container).with("mysql")
|
||||||
|
Kamal::Cli::Accessory.any_instance.expects(:boot).with("mysql", login: false)
|
||||||
|
Kamal::Cli::Accessory.any_instance.expects(:stop).with("redis")
|
||||||
|
Kamal::Cli::Accessory.any_instance.expects(:remove_container).with("redis")
|
||||||
|
Kamal::Cli::Accessory.any_instance.expects(:boot).with("redis", login: false)
|
||||||
|
|
||||||
|
run_command("reboot", "all")
|
||||||
|
end
|
||||||
|
|
||||||
test "start" do
|
test "start" do
|
||||||
assert_match "docker container start app-mysql", run_command("start", "mysql")
|
assert_match "docker container start app-mysql", run_command("start", "mysql")
|
||||||
end
|
end
|
||||||
@@ -97,7 +109,7 @@ class CliAccessoryTest < CliTestCase
|
|||||||
|
|
||||||
test "logs with follow" do
|
test "logs with follow" do
|
||||||
SSHKit::Backend::Abstract.any_instance.stubs(:exec)
|
SSHKit::Backend::Abstract.any_instance.stubs(:exec)
|
||||||
.with("ssh -t root@1.1.1.3 'docker logs app-mysql --timestamps --tail 10 --follow 2>&1'")
|
.with("ssh -t root@1.1.1.3 -p 22 'docker logs app-mysql --timestamps --tail 10 --follow 2>&1'")
|
||||||
|
|
||||||
assert_match "docker logs app-mysql --timestamps --tail 10 --follow 2>&1", run_command("logs", "mysql", "--follow")
|
assert_match "docker logs app-mysql --timestamps --tail 10 --follow 2>&1", run_command("logs", "mysql", "--follow")
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ class CliAppTest < CliTestCase
|
|||||||
|
|
||||||
test "exec" do
|
test "exec" do
|
||||||
run_command("exec", "ruby -v").tap do |output|
|
run_command("exec", "ruby -v").tap do |output|
|
||||||
assert_match "docker run --rm dhh/app:latest ruby -v", output
|
assert_match "docker run --rm --env-file .kamal/env/roles/app-web.env dhh/app:latest ruby -v", output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ class CliAppTest < CliTestCase
|
|||||||
|
|
||||||
test "exec interactive" do
|
test "exec interactive" do
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:exec)
|
SSHKit::Backend::Abstract.any_instance.expects(:exec)
|
||||||
.with("ssh -t root@1.1.1.1 'docker run -it --rm --env-file .kamal/env/roles/app-web.env dhh/app:latest ruby -v'")
|
.with("ssh -t root@1.1.1.1 -p 22 'docker run -it --rm --env-file .kamal/env/roles/app-web.env dhh/app:latest ruby -v'")
|
||||||
run_command("exec", "-i", "ruby -v").tap do |output|
|
run_command("exec", "-i", "ruby -v").tap do |output|
|
||||||
assert_match "Get most recent version available as an image...", output
|
assert_match "Get most recent version available as an image...", output
|
||||||
assert_match "Launching interactive command with version latest via SSH from new container on 1.1.1.1...", output
|
assert_match "Launching interactive command with version latest via SSH from new container on 1.1.1.1...", output
|
||||||
@@ -181,7 +181,7 @@ class CliAppTest < CliTestCase
|
|||||||
|
|
||||||
test "exec interactive with reuse" do
|
test "exec interactive with reuse" do
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:exec)
|
SSHKit::Backend::Abstract.any_instance.expects(:exec)
|
||||||
.with("ssh -t root@1.1.1.1 'docker exec -it app-web-999 ruby -v'")
|
.with("ssh -t root@1.1.1.1 -p 22 'docker exec -it app-web-999 ruby -v'")
|
||||||
run_command("exec", "-i", "--reuse", "ruby -v").tap do |output|
|
run_command("exec", "-i", "--reuse", "ruby -v").tap do |output|
|
||||||
assert_match "Get current version of running container...", output
|
assert_match "Get current version of running container...", output
|
||||||
assert_match "Running docker ps --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --latest --format \"{{.Names}}\" | while read line; do echo ${line#app-web-}; done on 1.1.1.1", output
|
assert_match "Running docker ps --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --latest --format \"{{.Names}}\" | while read line; do echo ${line#app-web-}; done on 1.1.1.1", output
|
||||||
@@ -210,7 +210,7 @@ class CliAppTest < CliTestCase
|
|||||||
|
|
||||||
test "logs with follow" do
|
test "logs with follow" do
|
||||||
SSHKit::Backend::Abstract.any_instance.stubs(:exec)
|
SSHKit::Backend::Abstract.any_instance.stubs(:exec)
|
||||||
.with("ssh -t root@1.1.1.1 'docker ps --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --latest | xargs docker logs --timestamps --tail 10 --follow 2>&1'")
|
.with("ssh -t root@1.1.1.1 -p 22 'docker ps --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --latest | xargs docker logs --timestamps --tail 10 --follow 2>&1'")
|
||||||
|
|
||||||
assert_match "docker ps --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --latest | xargs docker logs --timestamps --tail 10 --follow 2>&1", run_command("logs", "--follow")
|
assert_match "docker ps --quiet --filter label=service=app --filter label=role=web --filter status=running --filter status=restarting --latest | xargs docker logs --timestamps --tail 10 --follow 2>&1", run_command("logs", "--follow")
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -65,8 +65,18 @@ class CliHealthcheckTest < CliTestCase
|
|||||||
assert_match "container not ready (unhealthy)", exception.message
|
assert_match "container not ready (unhealthy)", exception.message
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "raises an exception if primary does not have traefik" do
|
||||||
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).never
|
||||||
|
|
||||||
|
exception = assert_raises do
|
||||||
|
run_command("perform", config_file: "test/fixtures/deploy_workers_only.yml")
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_equal "The primary host is not configured to run Traefik", exception.message
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def run_command(*command)
|
def run_command(*command, config_file: "test/fixtures/deploy_with_accessories.yml")
|
||||||
stdouted { Kamal::Cli::Healthcheck.start([*command, "-c", "test/fixtures/deploy_with_accessories.yml"]) }
|
stdouted { Kamal::Cli::Healthcheck.start([*command, "-c", config_file]) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -123,10 +123,33 @@ class CliMainTest < CliTestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "deploy without healthcheck if primary host doesn't have traefik" do
|
||||||
|
invoke_options = { "config_file" => "test/fixtures/deploy_workers_only.yml", "version" => "999", "skip_hooks" => false }
|
||||||
|
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:healthcheck:perform", [], invoke_options).never
|
||||||
|
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:login", [], invoke_options)
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:deliver", [], invoke_options)
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:traefik:boot", [], invoke_options)
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true))
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:boot", [], invoke_options)
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:prune:all", [], invoke_options)
|
||||||
|
|
||||||
|
run_command("deploy", config_file: "deploy_workers_only")
|
||||||
|
end
|
||||||
|
|
||||||
test "deploy with missing secrets" do
|
test "deploy with missing secrets" do
|
||||||
assert_raises(KeyError) do
|
invoke_options = { "config_file" => "test/fixtures/deploy_with_secrets.yml", "version" => "999", "skip_hooks" => false }
|
||||||
run_command("deploy", config_file: "deploy_with_secrets")
|
|
||||||
end
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:registry:login", [], invoke_options)
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:build:deliver", [], invoke_options)
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:traefik:boot", [], invoke_options)
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:healthcheck:perform", [], invoke_options)
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:stale_containers", [], invoke_options.merge(stop: true))
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:app:boot", [], invoke_options)
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:prune:all", [], invoke_options)
|
||||||
|
|
||||||
|
run_command("deploy", config_file: "deploy_with_secrets")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "redeploy" do
|
test "redeploy" do
|
||||||
@@ -275,6 +298,16 @@ class CliMainTest < CliTestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "config with primary web role override" do
|
||||||
|
run_command("config", config_file: "deploy_primary_web_role_override").tap do |output|
|
||||||
|
config = YAML.load(output)
|
||||||
|
|
||||||
|
assert_equal ["web_chicago", "web_tokyo"], config[:roles]
|
||||||
|
assert_equal ["1.1.1.1", "1.1.1.2", "1.1.1.3", "1.1.1.4"], config[:hosts]
|
||||||
|
assert_equal "1.1.1.3", config[:primary_host]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
test "config with destination" do
|
test "config with destination" do
|
||||||
run_command("config", "-d", "world", config_file: "deploy_for_dest").tap do |output|
|
run_command("config", "-d", "world", config_file: "deploy_for_dest").tap do |output|
|
||||||
config = YAML.load(output)
|
config = YAML.load(output)
|
||||||
@@ -288,6 +321,19 @@ class CliMainTest < CliTestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "config with aliases" do
|
||||||
|
run_command("config", config_file: "deploy_with_aliases").tap do |output|
|
||||||
|
config = YAML.load(output)
|
||||||
|
|
||||||
|
assert_equal ["web", "web_tokyo", "workers", "workers_tokyo"], config[:roles]
|
||||||
|
assert_equal ["1.1.1.1", "1.1.1.2", "1.1.1.3", "1.1.1.4"], config[:hosts]
|
||||||
|
assert_equal "999", config[:version]
|
||||||
|
assert_equal "registry.digitalocean.com/dhh/app", config[:repository]
|
||||||
|
assert_equal "registry.digitalocean.com/dhh/app:999", config[:absolute_image]
|
||||||
|
assert_equal "app-999", config[:service_with_version]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
test "init" do
|
test "init" do
|
||||||
Pathname.any_instance.expects(:exist?).returns(false).times(3)
|
Pathname.any_instance.expects(:exist?).returns(false).times(3)
|
||||||
Pathname.any_instance.stubs(:mkpath)
|
Pathname.any_instance.stubs(:mkpath)
|
||||||
@@ -346,6 +392,20 @@ class CliMainTest < CliTestCase
|
|||||||
run_command("envify")
|
run_command("envify")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "envify with blank line trimming" do
|
||||||
|
file = <<~EOF
|
||||||
|
HELLO=<%= 'world' %>
|
||||||
|
<% if true -%>
|
||||||
|
KEY=value
|
||||||
|
<% end -%>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
File.expects(:read).with(".env.erb").returns(file.strip)
|
||||||
|
File.expects(:write).with(".env", "HELLO=world\nKEY=value\n", perm: 0600)
|
||||||
|
|
||||||
|
run_command("envify")
|
||||||
|
end
|
||||||
|
|
||||||
test "envify with destination" do
|
test "envify with destination" do
|
||||||
File.expects(:read).with(".env.world.erb").returns("HELLO=<%= 'world' %>")
|
File.expects(:read).with(".env.world.erb").returns("HELLO=<%= 'world' %>")
|
||||||
File.expects(:write).with(".env.world", "HELLO=world", perm: 0600)
|
File.expects(:write).with(".env.world", "HELLO=world", perm: 0600)
|
||||||
@@ -353,6 +413,14 @@ class CliMainTest < CliTestCase
|
|||||||
run_command("envify", "-d", "world", config_file: "deploy_for_dest")
|
run_command("envify", "-d", "world", config_file: "deploy_for_dest")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "envify with skip_push" do
|
||||||
|
File.expects(:read).with(".env.erb").returns("HELLO=<%= 'world' %>")
|
||||||
|
File.expects(:write).with(".env", "HELLO=world", perm: 0600)
|
||||||
|
|
||||||
|
Kamal::Cli::Main.any_instance.expects(:invoke).with("kamal:cli:env:push").never
|
||||||
|
run_command("envify", "--skip-push")
|
||||||
|
end
|
||||||
|
|
||||||
test "remove with confirmation" do
|
test "remove with confirmation" do
|
||||||
run_command("remove", "-y", config_file: "deploy_with_accessories").tap do |output|
|
run_command("remove", "-y", config_file: "deploy_with_accessories").tap do |output|
|
||||||
assert_match /docker container stop traefik/, output
|
assert_match /docker container stop traefik/, output
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ class CliServerTest < CliTestCase
|
|||||||
|
|
||||||
test "bootstrap install as non-root user" do
|
test "bootstrap install as non-root user" do
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:docker, "-v", raise_on_non_zero_exit: false).returns(false).at_least_once
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:docker, "-v", raise_on_non_zero_exit: false).returns(false).at_least_once
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with('[ "${EUID:-$(id -u)}" -eq 0 ]', raise_on_non_zero_exit: false).returns(false).at_least_once
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with('[ "${EUID:-$(id -u)}" -eq 0 ] || command -v sudo >/dev/null || command -v su >/dev/null', raise_on_non_zero_exit: false).returns(false).at_least_once
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:mkdir, "-p", ".kamal").returns("").at_least_once
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:mkdir, "-p", ".kamal").returns("").at_least_once
|
||||||
|
|
||||||
assert_raise RuntimeError, "Docker is not installed on 1.1.1.1, 1.1.1.3, 1.1.1.4, 1.1.1.2 and can't be automatically installed without having root access and the `curl` command available. Install Docker manually: https://docs.docker.com/engine/install/" do
|
assert_raise RuntimeError, "Docker is not installed on 1.1.1.1, 1.1.1.3, 1.1.1.4, 1.1.1.2 and can't be automatically installed without having root access and the `curl` command available. Install Docker manually: https://docs.docker.com/engine/install/" do
|
||||||
@@ -20,7 +20,7 @@ class CliServerTest < CliTestCase
|
|||||||
|
|
||||||
test "bootstrap install as root user" do
|
test "bootstrap install as root user" do
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:docker, "-v", raise_on_non_zero_exit: false).returns(false).at_least_once
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:docker, "-v", raise_on_non_zero_exit: false).returns(false).at_least_once
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with('[ "${EUID:-$(id -u)}" -eq 0 ]', raise_on_non_zero_exit: false).returns(true).at_least_once
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with('[ "${EUID:-$(id -u)}" -eq 0 ] || command -v sudo >/dev/null || command -v su >/dev/null', raise_on_non_zero_exit: false).returns(true).at_least_once
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:curl, "-fsSL", "https://get.docker.com", "|", :sh).at_least_once
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:curl, "-fsSL", "https://get.docker.com", "|", :sh).at_least_once
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:mkdir, "-p", ".kamal").returns("").at_least_once
|
SSHKit::Backend::Abstract.any_instance.expects(:execute).with(:mkdir, "-p", ".kamal").returns("").at_least_once
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ class CliTraefikTest < CliTestCase
|
|||||||
test "boot" do
|
test "boot" do
|
||||||
run_command("boot").tap do |output|
|
run_command("boot").tap do |output|
|
||||||
assert_match "docker login", output
|
assert_match "docker login", output
|
||||||
assert_match "docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" #{Kamal::Commands::Traefik::DEFAULT_IMAGE} --providers.docker --log.level=\"DEBUG\"", output
|
assert_match "docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" #{Kamal::Commands::Traefik::DEFAULT_IMAGE} --providers.docker --log.level=\"DEBUG\"", output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ class CliTraefikTest < CliTestCase
|
|||||||
run_command("reboot").tap do |output|
|
run_command("reboot").tap do |output|
|
||||||
assert_match "docker container stop traefik", output
|
assert_match "docker container stop traefik", output
|
||||||
assert_match "docker container prune --force --filter label=org.opencontainers.image.title=Traefik", output
|
assert_match "docker container prune --force --filter label=org.opencontainers.image.title=Traefik", output
|
||||||
assert_match "docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" #{Kamal::Commands::Traefik::DEFAULT_IMAGE} --providers.docker --log.level=\"DEBUG\"", output
|
assert_match "docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" #{Kamal::Commands::Traefik::DEFAULT_IMAGE} --providers.docker --log.level=\"DEBUG\"", output
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ class CliTraefikTest < CliTestCase
|
|||||||
|
|
||||||
test "logs with follow" do
|
test "logs with follow" do
|
||||||
SSHKit::Backend::Abstract.any_instance.stubs(:exec)
|
SSHKit::Backend::Abstract.any_instance.stubs(:exec)
|
||||||
.with("ssh -t root@1.1.1.1 'docker logs traefik --timestamps --tail 10 --follow 2>&1'")
|
.with("ssh -t root@1.1.1.1 -p 22 'docker logs traefik --timestamps --tail 10 --follow 2>&1'")
|
||||||
|
|
||||||
assert_match "docker logs traefik --timestamps --tail 10 --follow", run_command("logs", "--follow")
|
assert_match "docker logs traefik --timestamps --tail 10 --follow", run_command("logs", "--follow")
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -14,6 +14,20 @@ class CommanderTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
@kamal.specific_hosts = [ "1.1.1.1", "1.1.1.2" ]
|
@kamal.specific_hosts = [ "1.1.1.1", "1.1.1.2" ]
|
||||||
assert_equal [ "1.1.1.1", "1.1.1.2" ], @kamal.hosts
|
assert_equal [ "1.1.1.1", "1.1.1.2" ], @kamal.hosts
|
||||||
|
|
||||||
|
@kamal.specific_hosts = [ "1.1.1.1*" ]
|
||||||
|
assert_equal [ "1.1.1.1" ], @kamal.hosts
|
||||||
|
|
||||||
|
@kamal.specific_hosts = [ "1.1.1.*", "*.1.2.*" ]
|
||||||
|
assert_equal [ "1.1.1.1", "1.1.1.2", "1.1.1.3", "1.1.1.4" ], @kamal.hosts
|
||||||
|
|
||||||
|
@kamal.specific_hosts = [ "*" ]
|
||||||
|
assert_equal [ "1.1.1.1", "1.1.1.2", "1.1.1.3", "1.1.1.4" ], @kamal.hosts
|
||||||
|
|
||||||
|
exception = assert_raises(ArgumentError) do
|
||||||
|
@kamal.specific_hosts = [ "*miss" ]
|
||||||
|
end
|
||||||
|
assert_match /hosts match for \*miss/, exception.message
|
||||||
end
|
end
|
||||||
|
|
||||||
test "filtering hosts by filtering roles" do
|
test "filtering hosts by filtering roles" do
|
||||||
@@ -21,6 +35,11 @@ class CommanderTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
@kamal.specific_roles = [ "web" ]
|
@kamal.specific_roles = [ "web" ]
|
||||||
assert_equal [ "1.1.1.1", "1.1.1.2" ], @kamal.hosts
|
assert_equal [ "1.1.1.1", "1.1.1.2" ], @kamal.hosts
|
||||||
|
|
||||||
|
exception = assert_raises(ArgumentError) do
|
||||||
|
@kamal.specific_roles = [ "*miss" ]
|
||||||
|
end
|
||||||
|
assert_match /roles match for \*miss/, exception.message
|
||||||
end
|
end
|
||||||
|
|
||||||
test "filtering roles" do
|
test "filtering roles" do
|
||||||
@@ -28,6 +47,20 @@ class CommanderTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
@kamal.specific_roles = [ "workers" ]
|
@kamal.specific_roles = [ "workers" ]
|
||||||
assert_equal [ "workers" ], @kamal.roles.map(&:name)
|
assert_equal [ "workers" ], @kamal.roles.map(&:name)
|
||||||
|
|
||||||
|
@kamal.specific_roles = [ "w*" ]
|
||||||
|
assert_equal [ "web", "workers" ], @kamal.roles.map(&:name)
|
||||||
|
|
||||||
|
@kamal.specific_roles = [ "we*", "*orkers" ]
|
||||||
|
assert_equal [ "web", "workers" ], @kamal.roles.map(&:name)
|
||||||
|
|
||||||
|
@kamal.specific_roles = [ "*" ]
|
||||||
|
assert_equal [ "web", "workers" ], @kamal.roles.map(&:name)
|
||||||
|
|
||||||
|
exception = assert_raises(ArgumentError) do
|
||||||
|
@kamal.specific_roles = [ "*miss" ]
|
||||||
|
end
|
||||||
|
assert_match /roles match for \*miss/, exception.message
|
||||||
end
|
end
|
||||||
|
|
||||||
test "filtering roles by filtering hosts" do
|
test "filtering roles by filtering hosts" do
|
||||||
@@ -76,6 +109,15 @@ class CommanderTest < ActiveSupport::TestCase
|
|||||||
assert_equal({ in: :groups, limit: 1, wait: 2 }, @kamal.boot_strategy)
|
assert_equal({ in: :groups, limit: 1, wait: 2 }, @kamal.boot_strategy)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "try to match the primary role from a list of specific roles" do
|
||||||
|
configure_with(:deploy_primary_web_role_override)
|
||||||
|
|
||||||
|
@kamal.specific_roles = [ "web_*" ]
|
||||||
|
assert_equal [ "web_chicago", "web_tokyo" ], @kamal.roles.map(&:name)
|
||||||
|
assert_equal "web_tokyo", @kamal.primary_role
|
||||||
|
assert_equal "1.1.1.3", @kamal.primary_host
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def configure_with(variant)
|
def configure_with(variant)
|
||||||
@kamal = Kamal::Commander.new.tap do |kamal|
|
@kamal = Kamal::Commander.new.tap do |kamal|
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ class CommandsAccessoryTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
test "follow logs" do
|
test "follow logs" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"ssh -t root@1.1.1.5 'docker logs app-mysql --timestamps --tail 10 --follow 2>&1'",
|
"ssh -t root@1.1.1.5 -p 22 'docker logs app-mysql --timestamps --tail 10 --follow 2>&1'",
|
||||||
new_command(:mysql).follow_logs
|
new_command(:mysql).follow_logs
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -14,13 +14,13 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
test "run" do
|
test "run" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --detach --restart unless-stopped --name app-web-999 -e KAMAL_CONTAINER_NAME=\"app-web-999\" --env-file .kamal/env/roles/app-web.env --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 traefik.http.services.app-web.loadbalancer.server.scheme=\"http\" --label traefik.http.routers.app-web.rule=\"PathPrefix(\\`/\\`)\" --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",
|
"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 --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 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(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "run with hostname" do
|
test "run with hostname" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --detach --restart unless-stopped --name app-web-999 --hostname myhost -e KAMAL_CONTAINER_NAME=\"app-web-999\" --env-file .kamal/env/roles/app-web.env --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 traefik.http.services.app-web.loadbalancer.server.scheme=\"http\" --label traefik.http.routers.app-web.rule=\"PathPrefix(\\`/\\`)\" --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",
|
"docker run --detach --restart unless-stopped --name app-web-999 --hostname myhost -e KAMAL_CONTAINER_NAME=\"app-web-999\" -e KAMAL_VERSION=\"999\" --env-file .kamal/env/roles/app-web.env --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 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(hostname: "myhost").join(" ")
|
new_command.run(hostname: "myhost").join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
@config[:volumes] = ["/local/path:/container/path" ]
|
@config[:volumes] = ["/local/path:/container/path" ]
|
||||||
|
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --detach --restart unless-stopped --name app-web-999 -e KAMAL_CONTAINER_NAME=\"app-web-999\" --env-file .kamal/env/roles/app-web.env --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\" --volume /local/path:/container/path --label service=\"app\" --label role=\"web\" --label traefik.http.services.app-web.loadbalancer.server.scheme=\"http\" --label traefik.http.routers.app-web.rule=\"PathPrefix(\\`/\\`)\" --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",
|
"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 --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\" --volume /local/path:/container/path --label service=\"app\" --label role=\"web\" --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(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
@config[:healthcheck] = { "path" => "/healthz" }
|
@config[:healthcheck] = { "path" => "/healthz" }
|
||||||
|
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --detach --restart unless-stopped --name app-web-999 -e KAMAL_CONTAINER_NAME=\"app-web-999\" --env-file .kamal/env/roles/app-web.env --health-cmd \"(curl -f http://localhost:3000/healthz || 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 traefik.http.services.app-web.loadbalancer.server.scheme=\"http\" --label traefik.http.routers.app-web.rule=\"PathPrefix(\\`/\\`)\" --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",
|
"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 --health-cmd \"(curl -f http://localhost:3000/healthz || 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 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(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
@config[:healthcheck] = { "cmd" => "/bin/up" }
|
@config[:healthcheck] = { "cmd" => "/bin/up" }
|
||||||
|
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --detach --restart unless-stopped --name app-web-999 -e KAMAL_CONTAINER_NAME=\"app-web-999\" --env-file .kamal/env/roles/app-web.env --health-cmd \"(/bin/up) && (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 traefik.http.services.app-web.loadbalancer.server.scheme=\"http\" --label traefik.http.routers.app-web.rule=\"PathPrefix(\\`/\\`)\" --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",
|
"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 --health-cmd \"(/bin/up) && (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 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(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -52,14 +52,14 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
@config[:servers] = { "web" => { "hosts" => [ "1.1.1.1" ], "healthcheck" => { "cmd" => "/bin/healthy" } } }
|
@config[:servers] = { "web" => { "hosts" => [ "1.1.1.1" ], "healthcheck" => { "cmd" => "/bin/healthy" } } }
|
||||||
|
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --detach --restart unless-stopped --name app-web-999 -e KAMAL_CONTAINER_NAME=\"app-web-999\" --env-file .kamal/env/roles/app-web.env --health-cmd \"(/bin/healthy) && (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 traefik.http.services.app-web.loadbalancer.server.scheme=\"http\" --label traefik.http.routers.app-web.rule=\"PathPrefix(\\`/\\`)\" --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",
|
"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 --health-cmd \"(/bin/healthy) && (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 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(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "run with custom options" do
|
test "run with custom options" do
|
||||||
@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\" --env-file .kamal/env/roles/app-jobs.env --log-opt max-size=\"10m\" --label service=\"app\" --label role=\"jobs\" --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\" --mount \"somewhere\" --cap-add dhh/app:999 bin/jobs",
|
||||||
new_command(role: "jobs").run.join(" ")
|
new_command(role: "jobs").run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
@config[:logging] = { "driver" => "local", "options" => { "max-size" => "100m", "max-file" => "3" } }
|
@config[:logging] = { "driver" => "local", "options" => { "max-size" => "100m", "max-file" => "3" } }
|
||||||
|
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --detach --restart unless-stopped --name app-web-999 -e KAMAL_CONTAINER_NAME=\"app-web-999\" --env-file .kamal/env/roles/app-web.env --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-driver \"local\" --log-opt max-size=\"100m\" --log-opt max-file=\"3\" --label service=\"app\" --label role=\"web\" --label traefik.http.services.app-web.loadbalancer.server.scheme=\"http\" --label traefik.http.routers.app-web.rule=\"PathPrefix(\\`/\\`)\" --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",
|
"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 --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-driver \"local\" --log-opt max-size=\"100m\" --log-opt max-file=\"3\" --label service=\"app\" --label role=\"web\" --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(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -190,32 +190,37 @@ class CommandsAppTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "run over ssh" do
|
test "run over ssh" do
|
||||||
assert_equal "ssh -t root@1.1.1.1 'ls'", new_command.run_over_ssh("ls", host: "1.1.1.1")
|
assert_equal "ssh -t root@1.1.1.1 -p 22 'ls'", new_command.run_over_ssh("ls", host: "1.1.1.1")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "run over ssh with custom user" do
|
test "run over ssh with custom user" do
|
||||||
@config[:ssh] = { "user" => "app" }
|
@config[:ssh] = { "user" => "app" }
|
||||||
assert_equal "ssh -t app@1.1.1.1 'ls'", new_command.run_over_ssh("ls", host: "1.1.1.1")
|
assert_equal "ssh -t app@1.1.1.1 -p 22 'ls'", new_command.run_over_ssh("ls", host: "1.1.1.1")
|
||||||
|
end
|
||||||
|
|
||||||
|
test "run over ssh with custom port" do
|
||||||
|
@config[:ssh] = { "port" => "2222" }
|
||||||
|
assert_equal "ssh -t root@1.1.1.1 -p 2222 'ls'", new_command.run_over_ssh("ls", host: "1.1.1.1")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "run over ssh with proxy" do
|
test "run over ssh with proxy" do
|
||||||
@config[:ssh] = { "proxy" => "2.2.2.2" }
|
@config[:ssh] = { "proxy" => "2.2.2.2" }
|
||||||
assert_equal "ssh -J root@2.2.2.2 -t root@1.1.1.1 'ls'", new_command.run_over_ssh("ls", host: "1.1.1.1")
|
assert_equal "ssh -J root@2.2.2.2 -t root@1.1.1.1 -p 22 'ls'", new_command.run_over_ssh("ls", host: "1.1.1.1")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "run over ssh with proxy user" do
|
test "run over ssh with proxy user" do
|
||||||
@config[:ssh] = { "proxy" => "app@2.2.2.2" }
|
@config[:ssh] = { "proxy" => "app@2.2.2.2" }
|
||||||
assert_equal "ssh -J app@2.2.2.2 -t root@1.1.1.1 'ls'", new_command.run_over_ssh("ls", host: "1.1.1.1")
|
assert_equal "ssh -J app@2.2.2.2 -t root@1.1.1.1 -p 22 'ls'", new_command.run_over_ssh("ls", host: "1.1.1.1")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "run over ssh with custom user with proxy" do
|
test "run over ssh with custom user with proxy" do
|
||||||
@config[:ssh] = { "user" => "app", "proxy" => "2.2.2.2" }
|
@config[:ssh] = { "user" => "app", "proxy" => "2.2.2.2" }
|
||||||
assert_equal "ssh -J root@2.2.2.2 -t app@1.1.1.1 'ls'", new_command.run_over_ssh("ls", host: "1.1.1.1")
|
assert_equal "ssh -J root@2.2.2.2 -t app@1.1.1.1 -p 22 'ls'", new_command.run_over_ssh("ls", host: "1.1.1.1")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "run over ssh with proxy_command" do
|
test "run over ssh with proxy_command" do
|
||||||
@config[:ssh] = { "proxy_command" => "ssh -W %h:%p user@proxy-server" }
|
@config[:ssh] = { "proxy_command" => "ssh -W %h:%p user@proxy-server" }
|
||||||
assert_equal "ssh -o ProxyCommand='ssh -W %h:%p user@proxy-server' -t root@1.1.1.1 'ls'", new_command.run_over_ssh("ls", host: "1.1.1.1")
|
assert_equal "ssh -o ProxyCommand='ssh -W %h:%p user@proxy-server' -t root@1.1.1.1 -p 22 'ls'", new_command.run_over_ssh("ls", host: "1.1.1.1")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "current_running_container_id" do
|
test "current_running_container_id" do
|
||||||
|
|||||||
@@ -21,6 +21,6 @@ class CommandsDockerTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "superuser?" do
|
test "superuser?" do
|
||||||
assert_equal '[ "${EUID:-$(id -u)}" -eq 0 ]', @docker.superuser?.join(" ")
|
assert_equal '[ "${EUID:-$(id -u)}" -eq 0 ] || command -v sudo >/dev/null || command -v su >/dev/null', @docker.superuser?.join(" ")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -18,72 +18,72 @@ class CommandsTraefikTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
test "run" do
|
test "run" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
|
|
||||||
@config[:traefik]["host_port"] = "8080"
|
@config[:traefik]["host_port"] = "8080"
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --name traefik --detach --restart unless-stopped --publish 8080:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
"docker run --name traefik --detach --restart unless-stopped --publish 8080:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
|
|
||||||
@config[:traefik]["publish"] = false
|
@config[:traefik]["publish"] = false
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --name traefik --detach --restart unless-stopped --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
"docker run --name traefik --detach --restart unless-stopped --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "run with ports configured" do
|
test "run with ports configured" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
|
|
||||||
@config[:traefik]["options"] = {"publish" => %w[9000:9000 9001:9001]}
|
@config[:traefik]["options"] = {"publish" => %w[9000:9000 9001:9001]}
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --publish \"9000:9000\" --publish \"9001:9001\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" --publish \"9000:9000\" --publish \"9001:9001\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "run with volumes configured" do
|
test "run with volumes configured" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
|
|
||||||
@config[:traefik]["options"] = {"volume" => %w[./letsencrypt/acme.json:/letsencrypt/acme.json] }
|
@config[:traefik]["options"] = {"volume" => %w[./letsencrypt/acme.json:/letsencrypt/acme.json] }
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --volume \"./letsencrypt/acme.json:/letsencrypt/acme.json\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" --volume \"./letsencrypt/acme.json:/letsencrypt/acme.json\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "run with several options configured" do
|
test "run with several options configured" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
|
|
||||||
@config[:traefik]["options"] = {"volume" => %w[./letsencrypt/acme.json:/letsencrypt/acme.json], "publish" => %w[8080:8080], "memory" => "512m"}
|
@config[:traefik]["options"] = {"volume" => %w[./letsencrypt/acme.json:/letsencrypt/acme.json], "publish" => %w[8080:8080], "memory" => "512m"}
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --volume \"./letsencrypt/acme.json:/letsencrypt/acme.json\" --publish \"8080:8080\" --memory \"512m\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" --volume \"./letsencrypt/acme.json:/letsencrypt/acme.json\" --publish \"8080:8080\" --memory \"512m\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "run with labels configured" do
|
test "run with labels configured" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
|
|
||||||
@config[:traefik]["labels"] = { "traefik.http.routers.dashboard.service" => "api@internal", "traefik.http.routers.dashboard.middlewares" => "auth" }
|
@config[:traefik]["labels"] = { "traefik.http.routers.dashboard.service" => "api@internal", "traefik.http.routers.dashboard.middlewares" => "auth" }
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.dashboard.service=\"api@internal\" --label traefik.http.routers.dashboard.middlewares=\"auth\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" --label traefik.http.routers.dashboard.service=\"api@internal\" --label traefik.http.routers.dashboard.middlewares=\"auth\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
test "run with env configured" do
|
test "run with env configured" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
|
|
||||||
@config[:traefik]["env"] = { "secret" => %w[EXAMPLE_API_KEY] }
|
@config[:traefik]["env"] = { "secret" => %w[EXAMPLE_API_KEY] }
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ class CommandsTraefikTest < ActiveSupport::TestCase
|
|||||||
@config.delete(:traefik)
|
@config.delete(:traefik)
|
||||||
|
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" #{Kamal::Commands::Traefik::DEFAULT_IMAGE} --providers.docker --log.level=\"DEBUG\"",
|
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" #{Kamal::Commands::Traefik::DEFAULT_IMAGE} --providers.docker --log.level=\"DEBUG\"",
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -99,7 +99,7 @@ class CommandsTraefikTest < ActiveSupport::TestCase
|
|||||||
@config[:logging] = { "driver" => "local", "options" => { "max-size" => "100m", "max-file" => "3" } }
|
@config[:logging] = { "driver" => "local", "options" => { "max-size" => "100m", "max-file" => "3" } }
|
||||||
|
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-driver \"local\" --log-opt max-size=\"100m\" --log-opt max-file=\"3\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-driver \"local\" --log-opt max-size=\"100m\" --log-opt max-file=\"3\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" #{@image} --providers.docker --log.level=\"DEBUG\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ class CommandsTraefikTest < ActiveSupport::TestCase
|
|||||||
@config[:traefik]["args"]["log.level"] = "ERROR"
|
@config[:traefik]["args"]["log.level"] = "ERROR"
|
||||||
|
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" #{@image} --providers.docker --log.level=\"ERROR\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
"docker run --name traefik --detach --restart unless-stopped --publish 80:80 --volume /var/run/docker.sock:/var/run/docker.sock --env-file .kamal/env/traefik/traefik.env --log-opt max-size=\"10m\" --label traefik.http.routers.catchall.entryPoints=\"http\" --label traefik.http.routers.catchall.rule=\"PathPrefix(\\`/\\`)\" --label traefik.http.routers.catchall.service=\"unavailable\" --label traefik.http.routers.catchall.priority=\"1\" --label traefik.http.services.unavailable.loadbalancer.server.port=\"0\" #{@image} --providers.docker --log.level=\"ERROR\" --accesslog.format=\"json\" --api.insecure --metrics.prometheus.buckets=\"0.1,0.3,1.2,5.0\"",
|
||||||
new_command.run.join(" ")
|
new_command.run.join(" ")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -167,13 +167,13 @@ class CommandsTraefikTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
test "traefik follow logs" do
|
test "traefik follow logs" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"ssh -t root@1.1.1.1 'docker logs traefik --timestamps --tail 10 --follow 2>&1'",
|
"ssh -t root@1.1.1.1 -p 22 'docker logs traefik --timestamps --tail 10 --follow 2>&1'",
|
||||||
new_command.follow_logs(host: @config[:servers].first)
|
new_command.follow_logs(host: @config[:servers].first)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "traefik follow logs with grep hello!" do
|
test "traefik follow logs with grep hello!" do
|
||||||
assert_equal \
|
assert_equal \
|
||||||
"ssh -t root@1.1.1.1 'docker logs traefik --timestamps --tail 10 --follow 2>&1 | grep \"hello!\"'",
|
"ssh -t root@1.1.1.1 -p 22 'docker logs traefik --timestamps --tail 10 --follow 2>&1 | grep \"hello!\"'",
|
||||||
new_command.follow_logs(host: @config[:servers].first, grep: 'hello!')
|
new_command.follow_logs(host: @config[:servers].first, grep: 'hello!')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -149,10 +149,16 @@ class ConfigurationAccessoryTest < ActiveSupport::TestCase
|
|||||||
assert_match "%", @config.accessory(:mysql).files.keys[2].read
|
assert_match "%", @config.accessory(:mysql).files.keys[2].read
|
||||||
end
|
end
|
||||||
|
|
||||||
test "directories" do
|
test "directory with a relative path" do
|
||||||
|
@deploy[:accessories]["mysql"]["directories"] = [ "data:/var/lib/mysql" ]
|
||||||
assert_equal({"$PWD/app-mysql/data"=>"/var/lib/mysql"}, @config.accessory(:mysql).directories)
|
assert_equal({"$PWD/app-mysql/data"=>"/var/lib/mysql"}, @config.accessory(:mysql).directories)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "directory with an absolute path" do
|
||||||
|
@deploy[:accessories]["mysql"]["directories"] = [ "/var/data/mysql:/var/lib/mysql" ]
|
||||||
|
assert_equal({"/var/data/mysql"=>"/var/lib/mysql"}, @config.accessory(:mysql).directories)
|
||||||
|
end
|
||||||
|
|
||||||
test "options" do
|
test "options" do
|
||||||
assert_equal ["--cpus", "\"4\"", "--memory", "\"2GB\""], @config.accessory(:redis).option_args
|
assert_equal ["--cpus", "\"4\"", "--memory", "\"2GB\""], @config.accessory(:redis).option_args
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class ConfigurationRoleTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "special label args for web" do
|
test "special label args for web" do
|
||||||
assert_equal [ "--label", "service=\"app\"", "--label", "role=\"web\"", "--label", "traefik.http.services.app-web.loadbalancer.server.scheme=\"http\"", "--label", "traefik.http.routers.app-web.rule=\"PathPrefix(\\`/\\`)\"", "--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\"" ], @config.role(:web).label_args
|
assert_equal [ "--label", "service=\"app\"", "--label", "role=\"web\"", "--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\"" ], @config.role(:web).label_args
|
||||||
end
|
end
|
||||||
|
|
||||||
test "custom labels" do
|
test "custom labels" do
|
||||||
@@ -66,7 +66,7 @@ class ConfigurationRoleTest < ActiveSupport::TestCase
|
|||||||
c[:servers]["beta"] = { "traefik" => "true", "hosts" => [ "1.1.1.5" ] }
|
c[:servers]["beta"] = { "traefik" => "true", "hosts" => [ "1.1.1.5" ] }
|
||||||
})
|
})
|
||||||
|
|
||||||
assert_equal [ "--label", "service=\"app\"", "--label", "role=\"beta\"", "--label", "traefik.http.services.app-beta.loadbalancer.server.scheme=\"http\"", "--label", "traefik.http.routers.app-beta.rule=\"PathPrefix(\\`/\\`)\"", "--label", "traefik.http.middlewares.app-beta-retry.retry.attempts=\"5\"", "--label", "traefik.http.middlewares.app-beta-retry.retry.initialinterval=\"500ms\"", "--label", "traefik.http.routers.app-beta.middlewares=\"app-beta-retry@docker\"" ], config.role(:beta).label_args
|
assert_equal [ "--label", "service=\"app\"", "--label", "role=\"beta\"", "--label", "traefik.http.services.app-beta.loadbalancer.server.scheme=\"http\"", "--label", "traefik.http.routers.app-beta.rule=\"PathPrefix(\\`/\\`)\"", "--label", "traefik.http.routers.app-beta.priority=\"2\"", "--label", "traefik.http.middlewares.app-beta-retry.retry.attempts=\"5\"", "--label", "traefik.http.middlewares.app-beta-retry.retry.initialinterval=\"500ms\"", "--label", "traefik.http.routers.app-beta.middlewares=\"app-beta-retry@docker\"" ], config.role(:beta).label_args
|
||||||
end
|
end
|
||||||
|
|
||||||
test "env overwritten by role" do
|
test "env overwritten by role" do
|
||||||
@@ -176,6 +176,34 @@ class ConfigurationRoleTest < ActiveSupport::TestCase
|
|||||||
ENV["REDIS_PASSWORD"] = nil
|
ENV["REDIS_PASSWORD"] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "env overwritten by role with secrets" do
|
||||||
|
@deploy_with_roles[:env] = {
|
||||||
|
"clear" => {
|
||||||
|
"REDIS_URL" => "redis://a/b"
|
||||||
|
},
|
||||||
|
"secret" => [
|
||||||
|
"REDIS_PASSWORD"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
@deploy_with_roles[:servers]["workers"]["env"] = {
|
||||||
|
"clear" => {
|
||||||
|
"REDIS_URL" => "redis://c/d",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
ENV["REDIS_PASSWORD"] = "secret456"
|
||||||
|
|
||||||
|
expected = <<~ENV
|
||||||
|
REDIS_PASSWORD=secret456
|
||||||
|
REDIS_URL=redis://c/d
|
||||||
|
ENV
|
||||||
|
|
||||||
|
assert_equal expected, @config_with_roles.role(:workers).env_file.to_s
|
||||||
|
ensure
|
||||||
|
ENV["REDIS_PASSWORD"] = nil
|
||||||
|
end
|
||||||
|
|
||||||
test "host_env_directory" do
|
test "host_env_directory" do
|
||||||
assert_equal ".kamal/env/roles", @config_with_roles.role(:workers).host_env_directory
|
assert_equal ".kamal/env/roles", @config_with_roles.role(:workers).host_env_directory
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ class ConfigurationSshTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
config = Kamal::Configuration.new(@deploy.tap { |c| c.merge!(ssh: { "log_level" => "debug" }) })
|
config = Kamal::Configuration.new(@deploy.tap { |c| c.merge!(ssh: { "log_level" => "debug" }) })
|
||||||
assert_equal 0, config.ssh.options[:logger].level
|
assert_equal 0, config.ssh.options[:logger].level
|
||||||
|
|
||||||
|
config = Kamal::Configuration.new(@deploy.tap { |c| c.merge!(ssh: { "port" => 2222 }) })
|
||||||
|
assert_equal 2222, config.ssh.options[:port]
|
||||||
end
|
end
|
||||||
|
|
||||||
test "ssh options with proxy host" do
|
test "ssh options with proxy host" do
|
||||||
|
|||||||
@@ -58,9 +58,9 @@ class ConfigurationTest < ActiveSupport::TestCase
|
|||||||
assert_equal [ "1.1.1.1", "1.1.1.2", "1.1.1.3" ], @config_with_roles.all_hosts
|
assert_equal [ "1.1.1.1", "1.1.1.2", "1.1.1.3" ], @config_with_roles.all_hosts
|
||||||
end
|
end
|
||||||
|
|
||||||
test "primary web host" do
|
test "primary host" do
|
||||||
assert_equal "1.1.1.1", @config.primary_web_host
|
assert_equal "1.1.1.1", @config.primary_host
|
||||||
assert_equal "1.1.1.1", @config_with_roles.primary_web_host
|
assert_equal "1.1.1.1", @config_with_roles.primary_host
|
||||||
end
|
end
|
||||||
|
|
||||||
test "traefik hosts" do
|
test "traefik hosts" do
|
||||||
@@ -128,14 +128,6 @@ class ConfigurationTest < ActiveSupport::TestCase
|
|||||||
assert_equal "healthcheck-app", @config.healthcheck_service
|
assert_equal "healthcheck-app", @config.healthcheck_service
|
||||||
end
|
end
|
||||||
|
|
||||||
test "env with missing secret" do
|
|
||||||
assert_raises(KeyError) do
|
|
||||||
config = Kamal::Configuration.new(@deploy.tap { |c| c.merge!({
|
|
||||||
env: { "secret" => [ "PASSWORD" ] }
|
|
||||||
}) }).ensure_env_available
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
test "valid config" do
|
test "valid config" do
|
||||||
assert @config.valid?
|
assert @config.valid?
|
||||||
assert @config_with_roles.valid?
|
assert @config_with_roles.valid?
|
||||||
@@ -173,6 +165,16 @@ class ConfigurationTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "allow_empty_roles" do
|
||||||
|
assert_silent do
|
||||||
|
Kamal::Configuration.new @deploy.merge(servers: { "web" => %w[ web ], "workers" => { "hosts" => %w[ ] } }, allow_empty_roles: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
assert_raises(ArgumentError) do
|
||||||
|
Kamal::Configuration.new @deploy.merge(servers: { "web" => %w[], "workers" => { "hosts" => %w[] } }, allow_empty_roles: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
test "volume_args" do
|
test "volume_args" do
|
||||||
assert_equal ["--volume", "/local/path:/container/path"], @config.volume_args
|
assert_equal ["--volume", "/local/path:/container/path"], @config.volume_args
|
||||||
end
|
end
|
||||||
@@ -235,7 +237,7 @@ class ConfigurationTest < ActiveSupport::TestCase
|
|||||||
:repository=>"dhh/app",
|
:repository=>"dhh/app",
|
||||||
:absolute_image=>"dhh/app:missing",
|
:absolute_image=>"dhh/app:missing",
|
||||||
:service_with_version=>"app-missing",
|
:service_with_version=>"app-missing",
|
||||||
:ssh_options=>{ :user=>"root", log_level: :fatal, keepalive: true, keepalive_interval: 30 },
|
:ssh_options=>{ :user=>"root", port: 22, log_level: :fatal, keepalive: true, keepalive_interval: 30 },
|
||||||
:sshkit=>{},
|
:sshkit=>{},
|
||||||
:volume_args=>["--volume", "/local/path:/container/path"],
|
:volume_args=>["--volume", "/local/path:/container/path"],
|
||||||
:builder=>{},
|
:builder=>{},
|
||||||
@@ -286,4 +288,25 @@ class ConfigurationTest < ActiveSupport::TestCase
|
|||||||
assert_nil @config.asset_path
|
assert_nil @config.asset_path
|
||||||
assert_equal "foo", Kamal::Configuration.new(@deploy.merge!(asset_path: "foo")).asset_path
|
assert_equal "foo", Kamal::Configuration.new(@deploy.merge!(asset_path: "foo")).asset_path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "primary role" do
|
||||||
|
assert_equal "web", @config.primary_role
|
||||||
|
|
||||||
|
config = Kamal::Configuration.new(@deploy_with_roles.deep_merge({
|
||||||
|
servers: { "alternate_web" => { "hosts" => [ "1.1.1.4", "1.1.1.5" ] } },
|
||||||
|
primary_role: "alternate_web" } ))
|
||||||
|
|
||||||
|
|
||||||
|
assert_equal "alternate_web", config.primary_role
|
||||||
|
assert_equal "1.1.1.4", config.primary_host
|
||||||
|
assert config.role(:alternate_web).primary?
|
||||||
|
assert config.role(:alternate_web).running_traefik?
|
||||||
|
end
|
||||||
|
|
||||||
|
test "primary role missing" do
|
||||||
|
error = assert_raises(ArgumentError) do
|
||||||
|
Kamal::Configuration.new(@deploy.merge(primary_role: "bar"))
|
||||||
|
end
|
||||||
|
assert_match /bar isn't defined/, error.message
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
20
test/fixtures/deploy_primary_web_role_override.yml
vendored
Normal file
20
test/fixtures/deploy_primary_web_role_override.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
service: app
|
||||||
|
image: dhh/app
|
||||||
|
servers:
|
||||||
|
web_chicago:
|
||||||
|
traefik: enabled
|
||||||
|
hosts:
|
||||||
|
- 1.1.1.1
|
||||||
|
- 1.1.1.2
|
||||||
|
web_tokyo:
|
||||||
|
traefik: enabled
|
||||||
|
hosts:
|
||||||
|
- 1.1.1.3
|
||||||
|
- 1.1.1.4
|
||||||
|
env:
|
||||||
|
REDIS_URL: redis://x/y
|
||||||
|
registry:
|
||||||
|
server: registry.digitalocean.com
|
||||||
|
username: user
|
||||||
|
password: pw
|
||||||
|
primary_role: web_tokyo
|
||||||
36
test/fixtures/deploy_with_aliases.yml
vendored
Normal file
36
test/fixtures/deploy_with_aliases.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# helper aliases
|
||||||
|
chicago_hosts: &chicago_hosts
|
||||||
|
hosts:
|
||||||
|
- 1.1.1.1
|
||||||
|
- 1.1.1.2
|
||||||
|
tokyo_hosts: &tokyo_hosts
|
||||||
|
hosts:
|
||||||
|
- 1.1.1.3
|
||||||
|
- 1.1.1.4
|
||||||
|
web_common: &web_common
|
||||||
|
env:
|
||||||
|
ROLE: "web"
|
||||||
|
traefik: true
|
||||||
|
|
||||||
|
# actual config
|
||||||
|
service: app
|
||||||
|
image: dhh/app
|
||||||
|
servers:
|
||||||
|
web:
|
||||||
|
<<: *chicago_hosts
|
||||||
|
<<: *web_common
|
||||||
|
web_tokyo:
|
||||||
|
<<: *tokyo_hosts
|
||||||
|
<<: *web_common
|
||||||
|
workers:
|
||||||
|
cmd: bin/jobs
|
||||||
|
<<: *chicago_hosts
|
||||||
|
workers_tokyo:
|
||||||
|
cmd: bin/jobs
|
||||||
|
<<: *tokyo_hosts
|
||||||
|
env:
|
||||||
|
REDIS_URL: redis://x/y
|
||||||
|
registry:
|
||||||
|
server: registry.digitalocean.com
|
||||||
|
username: user
|
||||||
|
password: pw
|
||||||
12
test/fixtures/deploy_workers_only.yml
vendored
Normal file
12
test/fixtures/deploy_workers_only.yml
vendored
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
service: app
|
||||||
|
image: dhh/app
|
||||||
|
servers:
|
||||||
|
workers:
|
||||||
|
traefik: false
|
||||||
|
hosts:
|
||||||
|
- 1.1.1.1
|
||||||
|
- 1.1.1.2
|
||||||
|
primary_role: workers
|
||||||
|
registry:
|
||||||
|
username: user
|
||||||
|
password: pw
|
||||||
@@ -10,8 +10,7 @@ class AppTest < IntegrationTest
|
|||||||
|
|
||||||
kamal :app, :stop
|
kamal :app, :stop
|
||||||
|
|
||||||
# traefik is up and returns 404s when it can't match a route
|
assert_app_is_down
|
||||||
assert_app_not_found
|
|
||||||
|
|
||||||
kamal :app, :start
|
kamal :app, :start
|
||||||
|
|
||||||
@@ -51,7 +50,6 @@ class AppTest < IntegrationTest
|
|||||||
|
|
||||||
kamal :app, :remove
|
kamal :app, :remove
|
||||||
|
|
||||||
# traefik is up and returns 404s when it can't match a route
|
assert_app_is_down
|
||||||
assert_app_not_found
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
3
test/integration/docker/deployer/app/.kamal/hooks/post-traefik-reboot
Executable file
3
test/integration/docker/deployer/app/.kamal/hooks/post-traefik-reboot
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
echo "Rebooted Traefik on ${KAMAL_HOSTS}"
|
||||||
|
mkdir -p /tmp/${TEST_ID} && touch /tmp/${TEST_ID}/post-traefik-reboot
|
||||||
3
test/integration/docker/deployer/app/.kamal/hooks/pre-traefik-reboot
Executable file
3
test/integration/docker/deployer/app/.kamal/hooks/pre-traefik-reboot
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
echo "Rebooting Traefik on ${KAMAL_HOSTS}..."
|
||||||
|
mkdir -p /tmp/${TEST_ID} && touch /tmp/${TEST_ID}/pre-traefik-reboot
|
||||||
@@ -21,3 +21,7 @@ install_kamal
|
|||||||
push_image_to_registry_4443 nginx 1-alpine-slim
|
push_image_to_registry_4443 nginx 1-alpine-slim
|
||||||
push_image_to_registry_4443 traefik v2.9
|
push_image_to_registry_4443 traefik v2.9
|
||||||
push_image_to_registry_4443 busybox 1.36.0
|
push_image_to_registry_4443 busybox 1.36.0
|
||||||
|
|
||||||
|
# .ssh is on a shared volume that persists between runs. Clean it up as the
|
||||||
|
# churn of temporary vm IPs can eventually create conflicts.
|
||||||
|
rm -f /root/.ssh/known_hosts
|
||||||
|
|||||||
@@ -55,12 +55,6 @@ class IntegrationTest < ActiveSupport::TestCase
|
|||||||
assert_app_version(version, response) if version
|
assert_app_version(version, response) if version
|
||||||
end
|
end
|
||||||
|
|
||||||
def assert_app_not_found
|
|
||||||
response = app_response
|
|
||||||
debug_response_code(response, "404")
|
|
||||||
assert_equal "404", response.code
|
|
||||||
end
|
|
||||||
|
|
||||||
def wait_for_app_to_be_up(timeout: 20, up_count: 3)
|
def wait_for_app_to_be_up(timeout: 20, up_count: 3)
|
||||||
timeout_at = Time.now + timeout
|
timeout_at = Time.now + timeout
|
||||||
up_times = 0
|
up_times = 0
|
||||||
@@ -109,7 +103,7 @@ class IntegrationTest < ActiveSupport::TestCase
|
|||||||
assert_equal "200", code
|
assert_equal "200", code
|
||||||
end
|
end
|
||||||
|
|
||||||
def wait_for_healthy(timeout: 20)
|
def wait_for_healthy(timeout: 30)
|
||||||
timeout_at = Time.now + timeout
|
timeout_at = Time.now + timeout
|
||||||
while docker_compose("ps -a | tail -n +2 | grep -v '(healthy)' | wc -l", capture: true) != "0"
|
while docker_compose("ps -a | tail -n +2 | grep -v '(healthy)' | wc -l", capture: true) != "0"
|
||||||
if timeout_at < Time.now
|
if timeout_at < Time.now
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ class MainTest < IntegrationTest
|
|||||||
kamal :envify
|
kamal :envify
|
||||||
assert_local_env_file "SECRET_TOKEN=1234"
|
assert_local_env_file "SECRET_TOKEN=1234"
|
||||||
assert_remote_env_file "SECRET_TOKEN=1234\nCLEAR_TOKEN=4321"
|
assert_remote_env_file "SECRET_TOKEN=1234\nCLEAR_TOKEN=4321"
|
||||||
|
remove_local_env_file
|
||||||
|
|
||||||
first_version = latest_app_version
|
first_version = latest_app_version
|
||||||
|
|
||||||
@@ -53,7 +54,7 @@ class MainTest < IntegrationTest
|
|||||||
assert_equal "registry:4443/app:#{version}", config[:absolute_image]
|
assert_equal "registry:4443/app:#{version}", config[:absolute_image]
|
||||||
assert_equal "app-#{version}", config[:service_with_version]
|
assert_equal "app-#{version}", config[:service_with_version]
|
||||||
assert_equal [], config[:volume_args]
|
assert_equal [], config[:volume_args]
|
||||||
assert_equal({ user: "root", keepalive: true, keepalive_interval: 30, log_level: :fatal }, config[:ssh_options])
|
assert_equal({ user: "root", port: 22, keepalive: true, keepalive_interval: 30, log_level: :fatal }, config[:ssh_options])
|
||||||
assert_equal({ "multiarch" => false, "args" => { "COMMIT_SHA" => version } }, config[:builder])
|
assert_equal({ "multiarch" => false, "args" => { "COMMIT_SHA" => version } }, config[:builder])
|
||||||
assert_equal [ "--log-opt", "max-size=\"10m\"" ], config[:logging]
|
assert_equal [ "--log-opt", "max-size=\"10m\"" ], config[:logging]
|
||||||
assert_equal({ "path" => "/up", "port" => 3000, "max_attempts" => 7, "exposed_port" => 3999, "cord"=>"/tmp/kamal-cord", "log_lines" => 50, "cmd"=>"wget -qO- http://localhost > /dev/null || exit 1" }, config[:healthcheck])
|
assert_equal({ "path" => "/up", "port" => 3000, "max_attempts" => 7, "exposed_port" => 3999, "cord"=>"/tmp/kamal-cord", "log_lines" => 50, "cmd"=>"wget -qO- http://localhost > /dev/null || exit 1" }, config[:healthcheck])
|
||||||
@@ -64,6 +65,10 @@ class MainTest < IntegrationTest
|
|||||||
assert_equal contents, deployer_exec("cat .env", capture: true)
|
assert_equal contents, deployer_exec("cat .env", capture: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def remove_local_env_file
|
||||||
|
deployer_exec("rm .env")
|
||||||
|
end
|
||||||
|
|
||||||
def assert_remote_env_file(contents)
|
def assert_remote_env_file(contents)
|
||||||
assert_equal contents, docker_compose("exec vm1 cat /root/.kamal/env/roles/app-web.env", capture: true)
|
assert_equal contents, docker_compose("exec vm1 cat /root/.kamal/env/roles/app-web.env", capture: true)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,8 +7,19 @@ class TraefikTest < IntegrationTest
|
|||||||
kamal :traefik, :boot
|
kamal :traefik, :boot
|
||||||
assert_traefik_running
|
assert_traefik_running
|
||||||
|
|
||||||
kamal :traefik, :reboot
|
output = kamal :traefik, :reboot, capture: true
|
||||||
assert_traefik_running
|
assert_traefik_running
|
||||||
|
assert_hooks_ran "pre-traefik-reboot", "post-traefik-reboot"
|
||||||
|
assert_match /Rebooting Traefik on vm1,vm2.../, output
|
||||||
|
assert_match /Rebooted Traefik on vm1,vm2/, output
|
||||||
|
|
||||||
|
output = kamal :traefik, :reboot, :"--rolling", capture: true
|
||||||
|
assert_traefik_running
|
||||||
|
assert_hooks_ran "pre-traefik-reboot", "post-traefik-reboot"
|
||||||
|
assert_match /Rebooting Traefik on vm1.../, output
|
||||||
|
assert_match /Rebooted Traefik on vm1/, output
|
||||||
|
assert_match /Rebooting Traefik on vm2.../, output
|
||||||
|
assert_match /Rebooted Traefik on vm2/, output
|
||||||
|
|
||||||
kamal :traefik, :boot
|
kamal :traefik, :boot
|
||||||
assert_traefik_running
|
assert_traefik_running
|
||||||
|
|||||||
Reference in New Issue
Block a user