Class: RemoteSystem
Overview
Copyright © 2013-2015 SUSE LLC
This program is free software; you can redistribute it and/or modify it under the terms of version 3 of the GNU General Public License as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, contact SUSE LLC.
To contact SUSE about this file by physical or electronic mail, you may find current contact information at www.suse.com
Instance Attribute Summary collapse
-
#host ⇒ Object
Returns the value of attribute host.
-
#remote_user ⇒ Object
Returns the value of attribute remote_user.
Instance Method Summary collapse
-
#connect ⇒ Object
Tries to run the noop-command(:) on the remote system as root (without a password or passphrase) and raises an Machinery::Errors::SshConnectionFailed exception when it’s not successful.
-
#initialize(host, remote_user = "root") ⇒ RemoteSystem
constructor
A new instance of RemoteSystem.
-
#read_file(file) ⇒ Object
Reads a file from the System.
- #requires_root? ⇒ Boolean
-
#retrieve_files(filelist, destination) ⇒ Object
Retrieves files specified in filelist from the remote system and raises an Machinery::Errors::RsyncFailed exception when it’s not successful.
- #run_command(*args) ⇒ Object
Methods inherited from System
#check_requirement, #create_archive, for, #has_command?, #run_script
Constructor Details
#initialize(host, remote_user = "root") ⇒ RemoteSystem
Returns a new instance of RemoteSystem.
22 23 24 25 26 27 |
# File 'lib/remote_system.rb', line 22 def initialize(host, remote_user = "root") @host = host @remote_user = remote_user connect end |
Instance Attribute Details
#host ⇒ Object
Returns the value of attribute host.
19 20 21 |
# File 'lib/remote_system.rb', line 19 def host @host end |
#remote_user ⇒ Object
Returns the value of attribute remote_user.
20 21 22 |
# File 'lib/remote_system.rb', line 20 def remote_user @remote_user end |
Instance Method Details
#connect ⇒ Object
Tries to run the noop-command(:) on the remote system as root (without a password or passphrase) and raises an Machinery::Errors::SshConnectionFailed exception when it’s not successful.
88 89 90 91 92 93 94 95 96 97 |
# File 'lib/remote_system.rb', line 88 def connect LoggedCheetah.run "ssh", "-q", "-o", "BatchMode=yes", "#{remote_user}@#{host}", ":" rescue Cheetah::ExecutionFailed raise Machinery::Errors::SshConnectionFailed.new( "Could not establish SSH connection to host '#{host}'. Please make sure that " \ "you can connect non-interactively as #{remote_user}, e.g. using ssh-agent.\n\n" \ "To copy your default ssh key to the machine run:\n" \ "ssh-copy-id #{remote_user}@#{host}" ) end |
#read_file(file) ⇒ Object
Reads a file from the System. Returns nil if it does not exist.
133 134 135 136 137 138 139 140 141 142 |
# File 'lib/remote_system.rb', line 133 def read_file(file) run_command("cat", file, stdout: :capture, privileged: true) rescue Cheetah::ExecutionFailed => e if e.status.exitstatus == 1 # File not found, return nil return else raise end end |
#requires_root? ⇒ Boolean
29 30 31 |
# File 'lib/remote_system.rb', line 29 def requires_root? false end |
#retrieve_files(filelist, destination) ⇒ Object
Retrieves files specified in filelist from the remote system and raises an Machinery::Errors::RsyncFailed exception when it’s not successful. Destination is the directory where to put the files.
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/remote_system.rb', line 103 def retrieve_files(filelist, destination) source = "#{remote_user}@#{host}:/" if remote_user != "root" rsync_path = "sudo -n rsync" else rsync_path = "rsync" end cmd = [ "rsync", "-e", "ssh", "--chmod=go-rwx", "--files-from=-", "--rsync-path=#{rsync_path}", source, destination, stdout: :capture, stdin: filelist.join("\n") ] begin LoggedCheetah.run(*cmd) rescue Cheetah::ExecutionFailed => e raise Machinery::Errors::RsyncFailed.new( "Could not rsync files from host '#{host}'.\n" \ "Error: #{e}" ) end end |
#run_command(*args) ⇒ Object
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/remote_system.rb', line 33 def run_command(*args) = args.last.is_a?(Hash) ? args.pop : {} # There are three valid ways how to call Cheetah.run, whose interface this # method mimics. The following code ensures that the "commands" variable # consistently (in all three cases) contains an array of arrays specifying # commands and their arguments. # # See comment in Cheetah.build_commands for more detailed explanation: # # https://github.com/openSUSE/cheetah/blob/0cd3f88c1210305e87dfc4852bb83040e82d783f/lib/cheetah.rb#L395 # commands = args.all? { |a| a.is_a?(Array) } ? args : [args] # When ssh executes commands, it passes them through shell expansion. For # example, compare # # $ echo '$HOME' # $HOME # # with # # $ ssh localhost echo '$HOME' # /home/dmajda # # To mitigate that and maintain usual Cheetah semantics, we need to protect # the command and its arguments using another layer of escaping. escaped_commands = commands.map do |command| command.map { |c| Shellwords.escape(c) } end # Arrange the commands in a way that allows piped commands trough ssh. piped_args = escaped_commands[0..-2].flat_map do |command| [*command, "|"] end + escaped_commands.last if [:disable_logging] cheetah_class = Cheetah else cheetah_class = LoggedCheetah end sudo = ["sudo", "-n"] if [:privileged] && remote_user != "root" cmds = ["ssh", "#{remote_user}@#{host}", sudo, "LC_ALL=C", *piped_args, ].compact.flatten cheetah_class.run(*cmds) rescue Cheetah::ExecutionFailed => e if e.stderr.include?("password is required") raise Machinery::Errors::InsufficientPrivileges.new(remote_user, host) else raise e end end |