def remote_scp(self, files, target): logger.debug("Running remote_scp function from %s" % self.parent_module) scp_command = self.scp_command(files, target) pipe = subprocess.Popen(scp_command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=self.get_env()) signal.alarm(SSH_CONNECT_TIMEOUT) err = '' try: _, err = pipe.communicate() except IOError as exc: #pipe.terminate() # only in python 2.6 allowed os.kill(pipe.pid, signal.SIGTERM) signal.alarm(0) # disable alarm logger.warning("%s (under %s): %s" % (' '.join(scp_command), self.username, str(exc))) signal.alarm(0) # disable alarm returncode = pipe.returncode if returncode != 0: # ssh client error logger.warning("%s (under %s): %s" % (' '.join(scp_command), self.username, err.strip())) logger.debug("Ending remote_scp function from %s" % self.parent_module)
def close(self): try: if self._trans: self._trans.close() except Exception as err: logger.warning("Could not close the SSH connection to '%s': %s" % (self.frontend, str(err)))
def scp_command(self, files, target, debug=False): """ Build the command string to transfer the files identified by filenames. Include target(s) if specified. Internal function """ logger.debug("Running scp_command function from %s" % self.parent_module) cmd = ['scp', debug and '-vvvv' or '-q', '-r'] if self.username: remotename = '%s@%s' % (self.username, self.frontend) else: remotename = self.frontend if self.configfile: cmd += ['-F', self.configfile] if self.private_key: cmd += ['-i', self.private_key] if self.port: cmd += ['-P', str(self.port)] if not isinstance(files, list): logger.warning( '"files" argument has to be an iterable (list or tuple)') if len(files) < 1: logger.warning('You should name at least one file to copy') for f in files: cmd.append('%s:%s' % (remotename, f)) cmd.append(target) logger.debug("The command is " + str(cmd)) logger.debug("Ending scp_command function from %s" % self.parent_module) return cmd
def copy(self, source_url, destination_url, execution_mode=''): try: logger.debug("Running copy function from %s" % self.parent_module) if not self.conn: self.connect() with self._sem: if 'file://' in source_url: from_dir = urlparse(source_url).path to_dir = self._set_dir(urlparse(destination_url).path) self.conn.scp([from_dir], target=to_dir) if execution_mode == 'X': stdout, stderr = self.execCommand("chmod +x %s" % to_dir) if stderr: logger.warning( "Could not change access permissions of %s file: %s" % (to_dir, stderr)) else: from_dir = self._set_dir(urlparse(source_url).path) to_dir = urlparse(destination_url).path self.remote_scp([from_dir], target=to_dir) logger.debug("Ending copy function from %s" % self.parent_module) except Exception as excep: if "disabling multiplexing" in str(excep): logger.debug( "Mux isn't working from the copy function. Eliminating " + self.parent_module + "'s socket file.") self._delete_socket() self.copy(source_url, destination_url) else: logger.warning(str(excep))
def createConfFiles(self): logger.debug("Running createConfFiles function from %s" % self.parent_module) #the maximum length of the path of a unix domain socket is 108 on Linux, 104 on Mac OS X conf_text = ("Host *\n" " ControlMaster auto\n" " ControlPath %s/%s-%s\n" " ControlPersist 10m\n" " StrictHostKeyChecking no") for manager in ['im', 'tm', 'em', 'rocci']: with io.FileIO(join(DRM4G_DIR, 'etc', 'openssh_%s.conf' % manager), 'w') as conf_file: conf_file.write(conf_text % (Communicator.socket_dir, manager, '%r@%h:%p')) try: if not exists(Communicator.socket_dir): logger.debug("Creating socket directory in %s" % Communicator.socket_dir) os.makedirs(Communicator.socket_dir) except OSError as excep: if "File exists" in str(excep): logger.warning("The directory %s already exists" % Communicator.socket_dir) else: logger.error("An unexpected exception ocurred:\n" + str(excep)) logger.debug("Ending createConfFiles function from %s" % self.parent_module)
def first_ssh(): try: logger.debug( "Running first_ssh function\n - Creating first connection for %s" % self.parent_module) #this is here because the threads are created at the same time, so the moment one creates the conection, the rest are going to cause an UnboundLocalError exception #(which probably shouldn't be ocurring since ControlMaster is set to auto - only if they execute this at the same time) if not exists( join( Communicator.socket_dir, '%s-%s@%s:%s' % (self.parent_module, self.username, self.frontend, self.port))): command = 'ssh -F %s -i %s -p %s -T %s@%s' % ( self.configfile, self.private_key, str(self.port), self.username, self.frontend) pipe = subprocess.Popen(command.split(), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = pipe.communicate() if err: if "too long for Unix domain socket" in str( err) or "ControlPath too long" in str(err): logger.debug( "Socket path was too long for Unix domain socket.\n Creating sockets in ~/.ssh/dmr4g.\n Exception captured in first_ssh." ) self._change_socket_dir() logger.debug( "Calling first_ssh once again, but with a new socket_dir" ) first_ssh() elif "disabling multiplexing" in str(err): logger.debug( "connect function: The multiplexing of connections isn't working. Eliminating " + self.parent_module + "'s socket file.") self._delete_socket() first_ssh() elif "bind: No such file or directory" in str( err) or "cannot bind to path" in str(err): logger.debug( "The connection through the socket %s-%s@%s:%s wasn't established since the socket directory %s hasn't been created yet." % (self.parent_module, self.username, self.frontend, self.port, Communicator.socket_dir)) self.createConfFiles() first_ssh() else: logger.debug( "Unexpected error occured while running first_ssh:\n" + str(err)) logger.warning(str(err)) except UnboundLocalError as err: logger.warning( "Local variable referenced before assignment") logger.debug(str(err))
def copy(self, source_url, destination_url, execution_mode=''): with self._sem: self.connect() scp = SCPClient(self._trans) if 'file://' in source_url: from_dir = urlparse(source_url).path to_dir = self._set_dir(urlparse(destination_url).path) scp.put(from_dir, to_dir) if execution_mode == 'X': stdout, stderr = self.execCommand("chmod +x %s" % to_dir) else: from_dir = self._set_dir(urlparse(source_url).path) to_dir = urlparse(destination_url).path logger.warning("%s , %s" % (from_dir, to_dir)) scp.get(from_dir, to_dir)
def _change_socket_dir(self): logger.debug("Running _change_socket_dir function from %s" % self.parent_module) try: if exists(Communicator.socket_dir): os.rmdir(Communicator.socket_dir) except OSError as excep: if "No such file or directory" in str(excep): logger.debug( "The old socket directory %s has already been deleted" % Communicator.socket_dir) else: logger.warning(str(excep)) Communicator.socket_dir = join(expanduser('~'), '.ssh/drm4g') self.createConfFiles() logger.debug("Ending _change_socket_dir function from %s" % self.parent_module)
def _delete_socket(self): try: logger.debug("Running _delete_socket function from %s" % self.parent_module) os.remove("%s/%s-%s@%s:%s" % (Communicator.socket_dir, self.parent_module, self.username, self.frontend, str(self.port))) logger.debug("Ending _delete_socket function from %s" % self.parent_module) except OSError as excep: if "No such file or directory" in str(excep): logger.debug("The socket %s/%s-%s@%s:%s does not exist" % (Communicator.socket_dir, self.parent_module, self.username, self.frontend, str(self.port))) logger.debug("Ending _delete_socket function from %s" % self.parent_module) else: logger.warning(str(excep))
def rmDirectory(self, url): try: logger.debug("Running rmDirectory function from %s" % self.parent_module) to_dir = self._set_dir(urlparse(url).path) stdout, stderr = self.execCommand("rm -rf %s" % to_dir) if stderr: logger.warning("Could not remove %s directory: %s" % (to_dir, stderr)) logger.debug("Ending rmDirectory function from %s" % self.parent_module) except Exception as excep: if "disabling multiplexing" in str(excep): logger.debug( "Mux isn't working from the rmDirectory function. Eliminating " + self.parent_module + "'s socket file.") self._delete_socket() self.rmDirectory(url) else: logger.warning(str(excep))
def execCommand(self, command, input=None): try: logger.debug("Running execCommand function from " + self.parent_module + "\n - Trying to execute command " + str(command)) if not self.conn: logger.debug( "Going to run connect function.\n - That should already have been done, so it shouldn't do anything." ) self.connect() ret = self.conn.run(command) logger.debug("Ending execCommand function.") return ret.stdout, ret.stderr except Exception as excep: if "disabling multiplexing" in str(excep): logger.debug( "Mux isn't working from the execCommand function. Eliminating " + self.parent_module + "'s socket file.") self._delete_socket() self.execCommand(command, input) else: logger.warning(str(excep))
def connect(self): try: with self._lock: if not self._trans or not self._trans.is_authenticated(): logger.debug("Opening ssh connection ... ") keys = None logger.debug("Trying ssh-agent ... ") drm4g_agent = drm4g.commands.Agent() drm4g_agent.start() drm4g_agent.update_agent_env() # paramiko agent agent = Agent() keys = agent.get_keys() if not keys: logger.debug("Error trying to connect to '%s'" % self.frontend) logger.debug( "Impossible to load '%s' key from the ssh-agent" % self.private_key) try: status_ssh_agent = agent._conn except Exception as err: logger.warning( "Probably you are using paramiko version <= 1.7.7.2 : %s " % err) status_ssh_agent = agent.conn if not status_ssh_agent: logger.warning("'ssh-agent' is not running") else: if agent.get_keys(): logger.warning( "ssh-agent is running but none of the keys have been accepted" "by remote frontend %s." % self.frontend) else: logger.debug( "'ssh-agent' is running but without any keys" ) if self.private_key: logger.debug("Trying '%s' key ... " % self.private_key) private_key_path = expanduser(self.private_key) if (not exists(private_key_path)) and ( not 'PRIVATE KEY' in self.private_key): output = "'%s'key does not exist" % private_key_path raise ComException(output) for pkey_class in (RSAKey, DSSKey): try: if 'PRIVATE KEY' in self.private_key: import StringIO key = pkey_class.from_private_key( StringIO.StringIO( self.private_key.strip("'"))) else: key = pkey_class.from_private_key_file( private_key_path) keys = keys + (key, ) except Exception: pass if not keys: output = "Impossible to load any keys" logger.error(output) raise ComException(output) for key in keys: try: sock = socket.socket() try: sock.settimeout(SSH_CONNECT_TIMEOUT) except: output = "Timeout trying to connect to '%s'" % self.frontend raise ComException(output) logger.debug( "Connecting to '%s' as user '%s' port '%s' ..." % (self.frontend, self.username, self.port)) if ':' in self.frontend: self.frontend, self.port = self.frontend.split( ':') sock.connect((self.frontend, self.port)) self._trans = Transport(sock) self._trans.connect(username=self.username, pkey=key) if self._trans.is_authenticated(): break except socket.gaierror: output = "Could not resolve hostname '%s' " % self.frontend raise ComException(output) except Exception as err: logger.warning("Error connecting '%s': %s" % (self.frontend, str(err))) if not self._trans: output = "Authentication failed for '%s'. Try to execute `ssh -vvv -p %d %s@%s` and see the response." % ( self.frontend, self.port, self.username, self.frontend) raise ComException(output) except ComException: raise except Exception as err: if "No handlers could be found for logger" in str(err): raise Exception( "The connect function is the one causing problems : %s" % str(err)) else: raise