summaryrefslogtreecommitdiff
path: root/lib/leap_cli/ssh/remote_command.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/leap_cli/ssh/remote_command.rb')
-rw-r--r--lib/leap_cli/ssh/remote_command.rb107
1 files changed, 107 insertions, 0 deletions
diff --git a/lib/leap_cli/ssh/remote_command.rb b/lib/leap_cli/ssh/remote_command.rb
new file mode 100644
index 00000000..fe9a344a
--- /dev/null
+++ b/lib/leap_cli/ssh/remote_command.rb
@@ -0,0 +1,107 @@
+#
+# Provides SSH.remote_command for running commands in parallel or in sequence
+# on remote servers.
+#
+# The gem sshkit is used for this.
+#
+
+require 'sshkit'
+require 'leap_cli/ssh/options'
+require 'leap_cli/ssh/backend'
+
+SSHKit.config.backend = LeapCli::SSH::Backend
+LeapCli::SSH::Backend.config.ssh_options = LeapCli::SSH::Options.global_options
+
+#
+# define remote_command
+#
+module LeapCli
+ module SSH
+
+ class ExecuteError < StandardError
+ end
+
+ # override default runner mode
+ class CustomCoordinator < SSHKit::Coordinator
+ private
+ def default_options
+ { in: :groups, limit: 10, wait: 0 }
+ end
+ end
+
+ #
+ # Available options:
+ #
+ # :port -- ssh port
+ # :ip -- ssh ip
+ # :auth_methods -- e.g. ["pubkey", "password"]
+ #
+ def self.remote_command(nodes, options={}, &block)
+ CustomCoordinator.new(
+ host_list(
+ nodes,
+ SSH::Options.options_from_args(options)
+ )
+ ).each do |ssh, host|
+ LeapCli.log 2, "ssh options for #{host.hostname}: #{host.ssh_options.inspect}"
+ yield ssh, host
+ end
+ end
+
+ #
+ # For example:
+ #
+ # SSH.remote_sync(nodes) do |sync, host|
+ # sync.source = '/from'
+ # sync.dest = '/to'
+ # sync.flags = ''
+ # sync.includes = []
+ # sync.excludes = []
+ # sync.exec
+ # end
+ #
+ def self.remote_sync(nodes, options={}, &block)
+ require 'rsync_command'
+ hosts = host_list(
+ nodes,
+ SSH::Options.options_from_args(options)
+ )
+ rsync = RsyncCommand.new(:logger => LeapCli::logger)
+ rsync.asynchronously(hosts) do |sync, host|
+ sync.logger = LeapCli.new_logger
+ sync.user = host.user || fetch(:user, ENV['USER'])
+ sync.host = host.hostname
+ sync.ssh = SSH::Options.global_options.merge(host.ssh_options)
+ sync.chdir = Path.provider
+ yield(sync, host)
+ end
+ if rsync.failed?
+ LeapCli::Util.bail! do
+ LeapCli.log :failed, "to rsync to #{rsync.failures.map{|f|f[:dest][:host]}.join(' ')}"
+ end
+ end
+ end
+
+ private
+
+ def self.host_list(nodes, ssh_options_override={})
+ if nodes.is_a?(Config::ObjectList)
+ list = nodes.values
+ elsif nodes.is_a?(Config::Node)
+ list = [nodes]
+ else
+ raise ArgumentError, "I don't understand the type of argument `nodes`"
+ end
+ list.collect do |node|
+ SSHKit::Host.new(
+ :hostname => node.name,
+ :user => 'root',
+ :ssh_options => SSH::Options.node_options(node, ssh_options_override)
+ )
+ end
+ end
+
+ end
+end
+
+