Skip to content

Commit

Permalink
Add "pharos ssh" command to launch ssh into cluster hosts (#581)
Browse files Browse the repository at this point in the history
  • Loading branch information
kke authored and jakolehm committed Oct 18, 2018
1 parent bcda3be commit 20d7fce
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 1 deletion.
4 changes: 3 additions & 1 deletion lib/pharos/root_command.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require_relative 'reset_command'
require_relative 'version_command'
require_relative 'kubeconfig_command'
require_relative 'ssh_command'

module Pharos
class RootCommand < Pharos::Command
Expand All @@ -12,7 +13,8 @@ class RootCommand < Pharos::Command
subcommand ["build", "up"], "initialize/upgrade cluster", UpCommand
subcommand "kubeconfig", "fetch admin kubeconfig file", KubeconfigCommand
subcommand "reset", "reset cluster", ResetCommand
subcommand ["version"], "show version information", VersionCommand
subcommand "ssh", "start an ssh session to a server in a pharos cluster", SSHCommand
subcommand "version", "show version information", VersionCommand

def self.run
super
Expand Down
85 changes: 85 additions & 0 deletions lib/pharos/ssh_command.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# frozen_string_literal: true

module Pharos
class SSHCommand < UpCommand
usage "[OPTIONS] -- [COMMANDS] ..."
parameter "[COMMAND] ...", "Run command on host"

banner "Opens SSH sessions to hosts in the Kontena Pharos cluster."

option ['-r', '--role'], 'ROLE', 'select a host by role'
option ['-l', '--label'], 'LABEL=VALUE', 'select a host by label, can be specified multiple times', multivalued: true do |pair|
Hash[*[:key, :value].zip(pair.split('=', 2))]
end
option ['-a', '--address'], 'ADDRESS', 'select a host by public address'

option ['-f', '--first'], :flag, 'only perform on the first matching host'

def hosts
@hosts ||= Array(
load_config.hosts.send(first? ? :find : :select) do |host|
next if role && host.role != role
next if address && host.address != address

unless label_list.empty?
next unless label_list.all? { |l| host.labels[l[:key]] == l[:value] }
end

true
end
).tap do |result|
signal_usage_error 'no host matched in configuration' if result.empty?
end
end

def execute
exit run_interactive if command_list.empty?
exit run_single(hosts.first) if hosts.size == 1
exit run_parallel
end

private

def run_interactive
exit_statuses = hosts.map do |host|
target = "#{host.user}@#{host.address}"
puts pastel.green("==> Opening a session to #{target} ..") unless !$stdout.tty?
system('ssh', '-i', host.ssh_key_path, target)
end
exit_statuses.all?(&:itself) ? 0 : 1
end

def run_single(host)
result = ssh_manager.client_for(host).exec(command_list)
puts result.output
result.exit_status
end

def run_parallel
threads = hosts.map do |host|
Thread.new do
begin
[host, ssh_manager.client_for(host).exec(command_list)]
rescue StandardError => ex
[
host,
Pharos::SSH::RemoteCommand::Result.new.tap do |r|
r.output << ex.message
end
]
end
end
end
results = threads.map(&:value)
results.each do |host, result|
puts pastel.send(result.exit_status.zero? ? :green : :red, "==> Result from #{host.user}@#{host.address}")
puts result.output.gsub(/^/, " ")
end
results.all? { |_, result| result.success? } ? 0 : 1
end

def ssh_manager
@ssh_manager ||= Pharos::SSH::Manager.new
end
end
end

0 comments on commit 20d7fce

Please sign in to comment.