Package qm :: Package test :: Package classes :: Module ssh_host
[hide private]
[frames] | no frames]

Source Code for Module qm.test.classes.ssh_host

  1  ######################################################################## 
  2  # 
  3  # File:   ssh_host.py 
  4  # Author: Mark Mitchell 
  5  # Date:   2005-06-03 
  6  # 
  7  # Contents: 
  8  #   SSHHost, RSHHost 
  9  # 
 10  # Copyright (c) 2005 by CodeSourcery, LLC.  All rights reserved.  
 11  # 
 12  ######################################################################## 
 13   
 14  ######################################################################## 
 15  # Imports 
 16  ####################################################################### 
 17   
 18  from   qm.host import Host 
 19  import os 
 20  import os.path 
 21  from   qm.fields import TextField, SetField 
 22  import qm.common 
 23  import sys 
 24   
 25  ######################################################################## 
 26  # Classes 
 27  ####################################################################### 
 28   
29 -class SSHHost(Host):
30 """An 'SSHHost' is accessible via 'ssh' or a similar program.""" 31 32 # If not empty, the name of the remote host. 33 host_name = TextField() 34 # The path to "ssh". 35 ssh_program = TextField( 36 default_value = "ssh", 37 description = """The path to the remote shell program.""" 38 ) 39 # Any arguments that must be provided to "ssh". 40 ssh_args = SetField( 41 TextField(description = 42 """The arguments to the remote shell program.""")) 43 # The path to "scp". 44 scp_program = TextField( 45 default_value = "scp", 46 description = """The path to the remote copy program.""" 47 ) 48 # Any arguments that must be provided to "scp". 49 scp_args = SetField( 50 TextField(description = 51 """The arguments to the remote copy program.""")) 52 # The default directory on the remote system. 53 default_dir = TextField( 54 description = """The default directory on the remote system.""" 55 ) 56 57 nfs_dir = TextField( 58 description = """The default directory, as seen from the local host. 59 60 If not empty, 'nfs_dir' is a directory on the local machine 61 that is equivalent to the default directory on the remote 62 machine. In that case, files will be copied to and from this 63 directory on the local machine, rather than by using 64 'scp'.""" 65 ) 66 67 user_name = TextField( 68 description = """The user name on the remote host. 69 70 If not empty, the user name that should be used when 71 connecting to the remote host.""" 72 ) 73
74 - def Run(self, path, arguments, environment = None, timeout = -1, 75 relative = False):
76 77 default_dir = self.default_dir 78 if not default_dir: 79 default_dir = os.curdir 80 if (relative 81 or (not os.path.isabs(path) 82 and (path.find(os.path.sep) != -1 83 or (os.path.altsep 84 and path.find(os.path.altsep) != -1)))): 85 path = os.path.join(default_dir, path) 86 path, arguments = self._FormSSHCommandLine(path, arguments, 87 environment) 88 return super(SSHHost, self).Run(path, arguments, None, timeout)
89 90
91 - def UploadFile(self, local_file, remote_file = None):
92 93 if remote_file is None: 94 remote_file = os.path.basename(local_file) 95 if self.nfs_dir: 96 remote_file = os.path.join(self.nfs_dir, remote_file) 97 super(SSHHost, self).UploadFile(local_file, remote_file) 98 else: 99 if self.default_dir: 100 remote_file = os.path.join(self.default_dir, remote_file) 101 command = self._FormSCPCommandLine(True, local_file, 102 remote_file) 103 executable = self.Executable() 104 status = executable.Run(command) 105 if ((sys.platform != "win32" 106 and (not os.WIFEXITED(status) 107 or os.WEXITSTATUS(status) != 0)) 108 or (sys.platform == "win32" and status != 0)): 109 raise qm.common.QMException("could not upload file")
110 111
112 - def DownloadFile(self, remote_file, local_file = None):
113 114 if local_file is None: 115 local_file = os.path.basename(remote_file) 116 if self.nfs_dir: 117 remote_file = os.path.join(self.nfs_dir, remote_file) 118 super(SSHHost, self).DownloadFile(remote_file, local_file) 119 else: 120 if self.default_dir: 121 remote_file = os.path.join(self.default_dir, remote_file) 122 command = self._FormSCPCommandLine(False, local_file, 123 remote_file) 124 executable = self.Executable() 125 executable.Run(command)
126 127
128 - def DeleteFile(self, remote_file):
129 130 if self.default_dir: 131 remote_file = os.path.join(self.default_dir, remote_file) 132 return self.Run("rm", [remote_file])
133 134
135 - def _FormSSHCommandLine(self, path, arguments, environment = None):
136 """Form the 'ssh' command line. 137 138 'path' -- The remote command, in the same format expected by 139 'Run'. 140 141 'arguments' -- The arguments to the remote command. 142 143 'environment' -- As for 'Run'. 144 145 returns -- A pair '(path, arguments)' describing the command 146 to run on the local machine that will execute the remote 147 command.""" 148 149 command = self.ssh_args + [self.host_name] 150 if self.user_name: 151 command += ["-l", self.user_name] 152 if environment is not None: 153 command.append("env") 154 for (k, v) in environment.iteritems(): 155 command.append("%s='%s'" % (k, v)) 156 command.append(path) 157 command += arguments 158 159 return self.ssh_program, command
160 161
162 - def _FormSCPCommandLine(self, upload, local_file, remote_file):
163 """Form the 'scp' command line. 164 165 'upload' -- True iff the 'local_file' should be copied to the 166 remote host. 167 168 'local_file' -- The path to the local file. 169 170 'remote_file' -- The path to the remote file. 171 172 returns -- The list of arguments for a command to run on the 173 local machine that will perform the file copy.""" 174 175 if self.default_dir: 176 remote_file = os.path.join(self.default_dir, remote_file) 177 remote_file = self.host_name + ":" + remote_file 178 if self.user_name: 179 remote_file = self.user_name + "@" + remote_file 180 command = [self.scp_program] + self.scp_args 181 if upload: 182 command += [local_file, remote_file] 183 else: 184 command += [remote_file, local_file] 185 186 return command
187 188 189
190 -class RSHHost(SSHHost):
191 """An 'RSHHost' is an 'SSHHost' that uses 'rsh' instead of 'ssh'. 192 193 The reason that 'RSHHost' is a separate class is that (a) that 194 makes it easier for users to construct an 'SSHHost', and (b) 'rsh' 195 does not return the exit code of the remote program, so 'Run' 196 requires adjustment.""" 197 198 # Override the default values. 199 ssh_program = TextField( 200 default_value = "rsh", 201 description = """The path to the remote shell program.""" 202 ) 203 scp_program = TextField( 204 default_value = "rcp", 205 description = """The path to the remote copy program.""" 206 ) 207
208 - def Run(self, path, arguments, environment = None, timeout = -1):
209 210 status, output = \ 211 super(RSHHost, self).Run(path, arguments, 212 environment, timeout) 213 # The exit status of 'rsh' is not the exit status of the 214 # remote program. The exit status of the remote program is 215 # unavailable. 216 return (None, output)
217