Class: RemoteSystem
Overview
Copyright © 2013-2016 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
readonly
Returns the value of attribute host.
-
#remote_user ⇒ Object
readonly
Returns the value of attribute remote_user.
-
#ssh_identity_file ⇒ Object
readonly
Returns the value of attribute ssh_identity_file.
-
#ssh_port ⇒ Object
readonly
Returns the value of attribute ssh_port.
Attributes inherited from System
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, opts = {}) ⇒ RemoteSystem
constructor
A new instance of RemoteSystem.
-
#inject_file(source, destination) ⇒ Object
Copies a file to the system.
-
#read_file(file) ⇒ Object
Reads a file from the System.
-
#remove_file(file) ⇒ Object
Removes 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
- #type ⇒ Object
Methods inherited from System
#arch, #check_create_archive_dependencies, #check_requirement, #check_retrieve_files_dependencies, #create_archive, for, #has_command?, #managed_files_database, #run_command_with_progress, #run_script, #run_script_with_progress
Constructor Details
#initialize(host, opts = {}) ⇒ RemoteSystem
Returns a new instance of RemoteSystem.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/remote_system.rb', line 25 def initialize(host, opts = {}) = { remote_user: "root", ssh_port: nil, ssh_identity_file: nil }.merge(opts) @host = host @remote_user = [:remote_user] @ssh_port = [:ssh_port] @ssh_identity_file = [:ssh_identity_file] connect end |
Instance Attribute Details
#host ⇒ Object (readonly)
Returns the value of attribute host.
19 20 21 |
# File 'lib/remote_system.rb', line 19 def host @host end |
#remote_user ⇒ Object (readonly)
Returns the value of attribute remote_user.
19 20 21 |
# File 'lib/remote_system.rb', line 19 def remote_user @remote_user end |
#ssh_identity_file ⇒ Object (readonly)
Returns the value of attribute ssh_identity_file.
19 20 21 |
# File 'lib/remote_system.rb', line 19 def ssh_identity_file @ssh_identity_file end |
#ssh_port ⇒ Object (readonly)
Returns the value of attribute ssh_port.
19 20 21 |
# File 'lib/remote_system.rb', line 19 def ssh_port @ssh_port 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.
103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/remote_system.rb', line 103 def connect LoggedCheetah.run(*build_command(: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 |
#inject_file(source, destination) ⇒ Object
Copies a file to the system
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/remote_system.rb', line 161 def inject_file(source, destination) destination = "#{remote_user}@#{host}:#{destination}" cmd = [ *build_command(:scp), source, destination ] begin LoggedCheetah.run(*cmd) rescue Cheetah::ExecutionFailed => e raise Machinery::Errors::InjectFileFailed.new( "Could not inject file '#{source}' to host '#{host}'.\nError: #{e}" ) end end |
#read_file(file) ⇒ Object
Reads a file from the System. Returns nil if it does not exist.
149 150 151 152 153 154 155 156 157 158 |
# File 'lib/remote_system.rb', line 149 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 |
#remove_file(file) ⇒ Object
Removes a file from the system
180 181 182 183 184 185 186 |
# File 'lib/remote_system.rb', line 180 def remove_file(file) run_command("rm", file) rescue Cheetah::ExecutionFailed => e raise Machinery::Errors::RemoveFileFailed.new( "Could not remove file '#{file}' on host '#{host}'.\nError: #{e}" ) end |
#requires_root? ⇒ Boolean
40 41 42 |
# File 'lib/remote_system.rb', line 40 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.
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/remote_system.rb', line 119 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", build_command(:ssh).join(" "), "--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
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 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/remote_system.rb', line 44 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 = [ *build_command(:ssh), "#{remote_user}@#{host}", "-o", \ "LogLevel=ERROR", sudo, "LANGUAGE=", "LC_ALL=#{locale}", *piped_args, ].compact.flatten cheetah_class.run(*cmds) rescue Cheetah::ExecutionFailed => e if e.stderr && e.stderr.include?("password is required") raise Machinery::Errors::InsufficientPrivileges.new(remote_user, host) else raise e end end |
#type ⇒ Object
21 22 23 |
# File 'lib/remote_system.rb', line 21 def type "remote" end |