Run pre-connect hooks before ssh commands
We hook into the SSHKit `on` method to run the pre-connect hook before the first SSH command. This doesn't work for interactive exec commands where ssh is called directly. Fixes: https://github.com/basecamp/kamal/issues/1157
This commit is contained in:
@@ -141,6 +141,8 @@ class Kamal::Cli::Accessory < Kamal::Cli::Base
|
|||||||
option :interactive, aliases: "-i", type: :boolean, default: false, desc: "Execute command over ssh for an interactive shell (use for console/bash)"
|
option :interactive, aliases: "-i", type: :boolean, default: false, desc: "Execute command over ssh for an interactive shell (use for console/bash)"
|
||||||
option :reuse, type: :boolean, default: false, desc: "Reuse currently running container instead of starting a new one"
|
option :reuse, type: :boolean, default: false, desc: "Reuse currently running container instead of starting a new one"
|
||||||
def exec(name, *cmd)
|
def exec(name, *cmd)
|
||||||
|
pre_connect_if_required
|
||||||
|
|
||||||
cmd = Kamal::Utils.join_commands(cmd)
|
cmd = Kamal::Utils.join_commands(cmd)
|
||||||
with_accessory(name) do |accessory, hosts|
|
with_accessory(name) do |accessory, hosts|
|
||||||
case
|
case
|
||||||
|
|||||||
@@ -106,6 +106,8 @@ class Kamal::Cli::App < Kamal::Cli::Base
|
|||||||
option :env, aliases: "-e", type: :hash, desc: "Set environment variables for the command"
|
option :env, aliases: "-e", type: :hash, desc: "Set environment variables for the command"
|
||||||
option :detach, type: :boolean, default: false, desc: "Execute command in a detached container"
|
option :detach, type: :boolean, default: false, desc: "Execute command in a detached container"
|
||||||
def exec(*cmd)
|
def exec(*cmd)
|
||||||
|
pre_connect_if_required
|
||||||
|
|
||||||
if (incompatible_options = [ :interactive, :reuse ].select { |key| options[:detach] && options[key] }.presence)
|
if (incompatible_options = [ :interactive, :reuse ].select { |key| options[:detach] && options[key] }.presence)
|
||||||
raise ArgumentError, "Detach is not compatible with #{incompatible_options.join(" or ")}"
|
raise ArgumentError, "Detach is not compatible with #{incompatible_options.join(" or ")}"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -147,12 +147,16 @@ module Kamal::Cli
|
|||||||
end
|
end
|
||||||
|
|
||||||
def on(*args, &block)
|
def on(*args, &block)
|
||||||
|
pre_connect_if_required
|
||||||
|
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
def pre_connect_if_required
|
||||||
if !KAMAL.connected?
|
if !KAMAL.connected?
|
||||||
run_hook "pre-connect"
|
run_hook "pre-connect"
|
||||||
KAMAL.connected = true
|
KAMAL.connected = true
|
||||||
end
|
end
|
||||||
|
|
||||||
super
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def command
|
def command
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ class Kamal::Cli::Server < Kamal::Cli::Base
|
|||||||
desc "exec", "Run a custom command on the server (use --help to show options)"
|
desc "exec", "Run a custom command on the server (use --help to show options)"
|
||||||
option :interactive, type: :boolean, aliases: "-i", default: false, desc: "Run the command interactively (use for console/bash)"
|
option :interactive, type: :boolean, aliases: "-i", default: false, desc: "Run the command interactively (use for console/bash)"
|
||||||
def exec(*cmd)
|
def exec(*cmd)
|
||||||
|
pre_connect_if_required
|
||||||
|
|
||||||
cmd = Kamal::Utils.join_commands(cmd)
|
cmd = Kamal::Utils.join_commands(cmd)
|
||||||
hosts = KAMAL.hosts
|
hosts = KAMAL.hosts
|
||||||
|
|
||||||
|
|||||||
@@ -334,18 +334,24 @@ class CliAppTest < CliTestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
test "exec interactive" do
|
test "exec interactive" do
|
||||||
|
Kamal::Commands::Hook.any_instance.stubs(:hook_exists?).returns(true)
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:exec)
|
SSHKit::Backend::Abstract.any_instance.expects(:exec)
|
||||||
.with("ssh -t root@1.1.1.1 -p 22 'docker run -it --rm --network kamal --env-file .kamal/apps/app/env/roles/web.env --log-opt max-size=\"10m\" dhh/app:latest ruby -v'")
|
.with("ssh -t root@1.1.1.1 -p 22 'docker run -it --rm --network kamal --env-file .kamal/apps/app/env/roles/web.env --log-opt max-size=\"10m\" dhh/app:latest ruby -v'")
|
||||||
|
|
||||||
run_command("exec", "-i", "ruby -v").tap do |output|
|
run_command("exec", "-i", "ruby -v").tap do |output|
|
||||||
|
assert_hook_ran "pre-connect", 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
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "exec interactive with reuse" do
|
test "exec interactive with reuse" do
|
||||||
|
Kamal::Commands::Hook.any_instance.stubs(:hook_exists?).returns(true)
|
||||||
SSHKit::Backend::Abstract.any_instance.expects(:exec)
|
SSHKit::Backend::Abstract.any_instance.expects(:exec)
|
||||||
.with("ssh -t root@1.1.1.1 -p 22 '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_hook_ran "pre-connect", output
|
||||||
assert_match "Get current version of running container...", output
|
assert_match "Get current version of running container...", output
|
||||||
assert_match "Running /usr/bin/env sh -c 'docker ps --latest --format '\\''{{.Names}}'\\'' --filter label=service=app --filter label=destination= --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --format '\\''{{.Names}}'\\'' --filter label=service=app --filter label=destination= --filter label=role=web --filter status=running --filter status=restarting' | head -1 | while read line; do echo ${line#app-web-}; done on 1.1.1.1", output
|
assert_match "Running /usr/bin/env sh -c 'docker ps --latest --format '\\''{{.Names}}'\\'' --filter label=service=app --filter label=destination= --filter label=role=web --filter status=running --filter status=restarting --filter ancestor=$(docker image ls --filter reference=dhh/app:latest --format '\\''{{.ID}}'\\'') ; docker ps --latest --format '\\''{{.Names}}'\\'' --filter label=service=app --filter label=destination= --filter label=role=web --filter status=running --filter status=restarting' | head -1 | while read line; do echo ${line#app-web-}; done on 1.1.1.1", output
|
||||||
assert_match "Launching interactive command with version 999 via SSH from existing container on 1.1.1.1...", output
|
assert_match "Launching interactive command with version 999 via SSH from existing container on 1.1.1.1...", output
|
||||||
|
|||||||
Reference in New Issue
Block a user