Extract ssh and sshkit configuration

This commit is contained in:
Donal McBreen
2023-07-26 12:26:23 +01:00
parent eb8c97a417
commit 94d6a763a8
9 changed files with 127 additions and 76 deletions

View File

@@ -143,10 +143,10 @@ class Mrsk::Commander
private private
# Lazy setup of SSHKit # Lazy setup of SSHKit
def configure_sshkit_with(config) def configure_sshkit_with(config)
SSHKit::Backend::Netssh.pool.idle_timeout = config.sshkit_pool_idle_timeout SSHKit::Backend::Netssh.pool.idle_timeout = config.sshkit.pool_idle_timeout
SSHKit::Backend::Netssh.configure do |sshkit| SSHKit::Backend::Netssh.configure do |sshkit|
sshkit.max_concurrent_starts = config.sshkit_max_concurrent_starts if config.sshkit_max_concurrent_starts sshkit.max_concurrent_starts = config.sshkit.max_concurrent_starts
sshkit.ssh_options = config.ssh_options sshkit.ssh_options = config.ssh.options
end end
SSHKit.config.command_map[:docker] = "docker" # No need to use /usr/bin/env, just clogs up the logs SSHKit.config.command_map[:docker] = "docker" # No need to use /usr/bin/env, just clogs up the logs
SSHKit.config.output_verbosity = verbosity SSHKit.config.output_verbosity = verbosity

View File

@@ -13,12 +13,12 @@ module Mrsk::Commands
def run_over_ssh(*command, host:) def run_over_ssh(*command, host:)
"ssh".tap do |cmd| "ssh".tap do |cmd|
if config.ssh_proxy && config.ssh_proxy.is_a?(Net::SSH::Proxy::Jump) if config.ssh.proxy && config.ssh.proxy.is_a?(Net::SSH::Proxy::Jump)
cmd << " -J #{config.ssh_proxy.jump_proxies}" cmd << " -J #{config.ssh.proxy.jump_proxies}"
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} '#{command.join(" ")}'"
end end
end end

View File

@@ -135,38 +135,12 @@ class Mrsk::Configuration
end end
def ssh_user def ssh
if raw_config.ssh.present? Mrsk::Configuration::Ssh.new(config: self)
raw_config.ssh["user"] || "root"
else
"root"
end
end end
def ssh_proxy def sshkit
if raw_config.ssh.present? && raw_config.ssh["proxy"] Mrsk::Configuration::Sshkit.new(config: self)
Net::SSH::Proxy::Jump.new \
raw_config.ssh["proxy"].include?("@") ? raw_config.ssh["proxy"] : "root@#{raw_config.ssh["proxy"]}"
elsif raw_config.ssh.present? && raw_config.ssh["proxy_command"]
Net::SSH::Proxy::Command.new(raw_config.ssh["proxy_command"])
end
end
def ssh_options
{ user: ssh_user, proxy: ssh_proxy, auth_methods: [ "publickey" ], keepalive: true, keepalive_interval: 30 }.compact
end
def sshkit_max_concurrent_starts
raw_config.sshkit["max_concurrent_starts"] if raw_config.sshkit.present?
end
def sshkit_pool_idle_timeout
if raw_config.sshkit.present?
raw_config.sshkit["pool_idle_timeout"] || 900
else
900
end
end end
@@ -198,7 +172,8 @@ class Mrsk::Configuration
service_with_version: service_with_version, service_with_version: service_with_version,
env_args: env_args, env_args: env_args,
volume_args: volume_args, volume_args: volume_args,
ssh_options: ssh_options, ssh_options: ssh.options,
sshkit: sshkit.to_h,
builder: builder.to_h, builder: builder.to_h,
accessories: raw_config.accessories, accessories: raw_config.accessories,
logging: logging_args, logging: logging_args,

View File

@@ -0,0 +1,24 @@
class Mrsk::Configuration::Ssh
def initialize(config:)
@config = config.raw_config.ssh || {}
end
def user
config.fetch("user", "root")
end
def proxy
if (proxy = config["proxy"])
Net::SSH::Proxy::Jump.new(proxy.include?("@") ? proxy : "root@#{proxy}")
elsif (proxy_command = config["proxy_command"])
Net::SSH::Proxy::Command.new(proxy_command)
end
end
def options
{ user: user, proxy: proxy, auth_methods: [ "publickey" ], keepalive: true, keepalive_interval: 30 }.compact
end
private
attr_accessor :config
end

View File

@@ -0,0 +1,20 @@
class Mrsk::Configuration::Sshkit
def initialize(config:)
@options = config.raw_config.sshkit || {}
end
def max_concurrent_starts
options.fetch("max_concurrent_starts", 30)
end
def pool_idle_timeout
options.fetch("pool_idle_timeout", 900)
end
def to_h
options
end
private
attr_accessor :options
end

View File

@@ -56,13 +56,7 @@ class SSHKit::Backend::Abstract
end end
class SSHKit::Backend::Netssh::Configuration class SSHKit::Backend::Netssh::Configuration
DEFAULT_MAX_CONCURRENT_STARTS = 30 attr_accessor :max_concurrent_starts
attr_writer :max_concurrent_starts
def max_concurrent_starts
@max_concurrent_starts ||= DEFAULT_MAX_CONCURRENT_STARTS
end
end end
class SSHKit::Backend::Netssh class SSHKit::Backend::Netssh
@@ -72,9 +66,11 @@ class SSHKit::Backend::Netssh
def configure(&block) def configure(&block)
super &block super &block
# Create this here to avoid lazy creation by multiple threads # Create this here to avoid lazy creation by multiple threads
if config.max_concurrent_starts
@start_semaphore = Concurrent::Semaphore.new(config.max_concurrent_starts) @start_semaphore = Concurrent::Semaphore.new(config.max_concurrent_starts)
end end
end end
end
class << self class << self
prepend LimitConcurrentStartsClass prepend LimitConcurrentStartsClass
@@ -94,9 +90,13 @@ class SSHKit::Backend::Netssh
end end
def start_with_concurrency_limit(*args) def start_with_concurrency_limit(*args)
if self.class.start_semaphore
self.class.start_semaphore.acquire do self.class.start_semaphore.acquire do
Net::SSH.start(*args) Net::SSH.start(*args)
end end
else
Net::SSH.start(*args)
end
end end
end end

View File

@@ -0,0 +1,32 @@
require "test_helper"
class ConfigurationSshTest < ActiveSupport::TestCase
setup do
@deploy = {
service: "app", image: "dhh/app",
registry: { "username" => "dhh", "password" => "secret" },
env: { "REDIS_URL" => "redis://x/y" },
servers: [ "1.1.1.1", "1.1.1.2" ],
volumes: ["/local/path:/container/path"]
}
@config = Mrsk::Configuration.new(@deploy)
end
test "ssh options" do
assert_equal "root", @config.ssh.options[:user]
config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!(ssh: { "user" => "app" }) })
assert_equal "app", @config.ssh.options[:user]
end
test "ssh options with proxy host" do
config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!(ssh: { "proxy" => "1.2.3.4" }) })
assert_equal "root@1.2.3.4", @config.ssh.options[:proxy].jump_proxies
end
test "ssh options with proxy host and user" do
config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!(ssh: { "proxy" => "app@1.2.3.4" }) })
assert_equal "app@1.2.3.4", @config.ssh.options[:proxy].jump_proxies
end
end

View File

@@ -0,0 +1,27 @@
require "test_helper"
class ConfigurationSshkitTest < ActiveSupport::TestCase
setup do
@deploy = {
service: "app", image: "dhh/app",
registry: { "username" => "dhh", "password" => "secret" },
env: { "REDIS_URL" => "redis://x/y" },
servers: [ "1.1.1.1", "1.1.1.2" ],
volumes: ["/local/path:/container/path"]
}
@config = Mrsk::Configuration.new(@deploy)
end
test "sshkit max concurrent starts" do
assert_equal 30, @config.sshkit.max_concurrent_starts
@config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!(sshkit: { "max_concurrent_starts" => 50 }) })
assert_equal 50, @config.sshkit.max_concurrent_starts
end
test "sshkit pool idle timeout" do
assert_equal 900, @config.sshkit.pool_idle_timeout
@config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!(sshkit: { "pool_idle_timeout" => 600 }) })
assert_equal 600, @config.sshkit.pool_idle_timeout
end
end

View File

@@ -207,34 +207,6 @@ class ConfigurationTest < ActiveSupport::TestCase
end end
end end
test "ssh options" do
assert_equal "root", @config.ssh_options[:user]
config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!(ssh: { "user" => "app" }) })
assert_equal "app", @config.ssh_options[:user]
end
test "ssh options with proxy host" do
config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!(ssh: { "proxy" => "1.2.3.4" }) })
assert_equal "root@1.2.3.4", @config.ssh_options[:proxy].jump_proxies
end
test "ssh options with proxy host and user" do
config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!(ssh: { "proxy" => "app@1.2.3.4" }) })
assert_equal "app@1.2.3.4", @config.ssh_options[:proxy].jump_proxies
end
test "sshkit max concurrent starts" do
config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!(sshkit: { "max_concurrent_starts" => 50 }) })
assert_equal 50, config.sshkit_max_concurrent_starts
end
test "sshkit pool idle timeout" do
assert_equal 900, @config.sshkit_pool_idle_timeout
config = Mrsk::Configuration.new(@deploy.tap { |c| c.merge!(sshkit: { "pool_idle_timeout" => 600 }) })
assert_equal 600, config.sshkit_pool_idle_timeout
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
@@ -287,6 +259,7 @@ class ConfigurationTest < ActiveSupport::TestCase
:service_with_version=>"app-missing", :service_with_version=>"app-missing",
:env_args=>["-e", "REDIS_URL=\"redis://x/y\""], :env_args=>["-e", "REDIS_URL=\"redis://x/y\""],
:ssh_options=>{ :user=>"root", :auth_methods=>["publickey"], keepalive: true, keepalive_interval: 30 }, :ssh_options=>{ :user=>"root", :auth_methods=>["publickey"], keepalive: true, keepalive_interval: 30 },
:sshkit=>{},
:volume_args=>["--volume", "/local/path:/container/path"], :volume_args=>["--volume", "/local/path:/container/path"],
:builder=>{}, :builder=>{},
:logging=>["--log-opt", "max-size=\"10m\""], :logging=>["--log-opt", "max-size=\"10m\""],