def _run(self, command, timeout, ignore_status, stdout, stderr, connect_timeout, env, options, stdin, args): """Helper function for run""" ssh_cmd = self.ssh_command(connect_timeout, options) if not env.strip(): env = "" else: env = "export %s;" % env for arg in args: command += ' "%s"' % utils.sh_escape(arg) full_cmd = '%s "%s %s"' % (ssh_cmd, env, utils.sh_escape(command)) result = utils.run(full_cmd, timeout, True, stdout, stderr, verbose=False, stdin=stdin, stderr_is_expected=ignore_status) # the error message will show up in band(indistinguishable from stuff # sent through the SSH connection). so we hace the remote computer # echo the message "Connected." before running any command. if result.exit_status == 255: if re.search(r'^ssh: connect to the host .* port .*: ' r'Connection timed out\r$', result.stderr): raise error.ServSSHTimeour("ssh timed out", result) if "Permission Denied." in result.stderr: msg = "ssh permission denied" raise error.ServSSHPemissionDenidError(msg, result) if not ignore_status and result.exit_status > 0: raise error.ServRunError("command execution error", result) return result
def _run(self, command, timeout, ignore_status, stdout, stderr, connect_timeout, env, options, stdin, args): """Helper function for run""" ssh_cmd = self.ssh_command(connect_timeout, options) if not env.strip(): env = "" else: env = "export %s;" % env for arg in args: command += ' "%s"' % utils.sh_escape(arg) full_cmd = '%s "%s %s"' % (ssh_cmd, env, utils.sh_escape(command)) result = utils.run(full_cmd, timeout, True, stdout, stderr, verbose=False, stdin=stdin, stderr_is_expected=ignore_status) #have no utils.run, need to realize # the error message will show up in band(indistinguishable from stuff sent through the # SSH connection). so we hace the remote computer echo the message "Connected." before # running any command. if result.exit_status == 255: if re.search(r'^ssh: connect to the host .* port .*: ' r'Connection timed out\r$', result.stderr): raise error.ServSSHTimeour("ssh timed out", result) if "Permission Denied." in result.stderr: msg = "ssh permission denied" raise error.ServSSHPemissionDenidError(msg, result) if not ignore_status and result.exit_status > 0: raise error.ServRunError("command execution error", result) return result
def run_async(self, command, stdout_tee=None, stderr_tee=None, args=(), connect_timeout=30, options='', verbose=True, stderr_level=utils.DEFAULT_STDERR_LEVEL, cmd_outside_subshell=''): """ Run a command on the remote host. Return an AsyncJob object to interact with the remote process. """ if verbose: logging.debug("Running (async ssh) '%s'" % command) # start a master SSH connection if necessary self.start_master_ssh() self.send_file( os.path.join(self.job.clientdir, "shared", "hosts", "scripts", "run_helper.py"), os.path.join(self.job.tmpdir, "run_helper.py")) env = " ".join("=".join(pair) for pair in self.env.iteritems()) ssh_cmd = self.ssh_command(connect_timeout, options) if not env.strip(): env = "" else: env = "export %s;" % env for arg in args: command += ' "%s"' % utils.sh_escape(arg) full_cmd = '{ssh_cmd} "{env} {cmd}"'.format( ssh_cmd=ssh_cmd, env=env, cmd=utils.sh_escape( "%s (%s '%s')" % (cmd_outside_subshell, os.path.join(self.job.tmpdir, "run_helper.py"), utils.sh_escape(command)))) job = utils.AsyncJob(full_cmd, stdout_tee=stdout_tee, stderr_tee=stderr_tee, verbose=verbose, stderr_level=stderr_level, stdin=subprocess.PIPE) def kill_func(): utils.nuke_subprocess(job.sp) job.kill_func = kill_func return job
def _make_rsync_compatible_globs(self, path, is_local): """ given an rsync-style path, returns a list of globbed paths that will hopefully provide equivalent behaviour for scp. Does not support the full range of rsync pattern matching behaviour, only that exposed in the get/send_file interface. """ if len(path) == 0 or path[-1] != "/": return [path] if is_local: def glob_matches_files(path, pattern): return len(glob.glob(path + pattern)) > 0 else: def glob_matches_files(path, pattern): result = self.run("ls \"%s\"%s" % (utils.sh_escape(path), pattern), stdout_tee=None, ignore_status=True) return result.exit_status == 0 patterns = ["*", ".[!.]*"] patterns = [p for p in patterns if glob_matches_files(path, p)] # convert them into a set of paths suitable for the commandline if is_local: return ["\"%s\"%s" % (utils.sh_escape(path), pattern) for pattern in patterns] else: return [utils.scp_remote_escape(path) + pattern for pattern in patterns]
def _make_rsync_compatible_globs(self, path, is_local): """ given an rsync-style path, returns a list of globbed paths that will hopefully provide equivalent behaviour for scp. Does not support the full range of rsync pattern matching behaviour, only that exposed in the get/send_file interface. """ if len(path)==0 or path[-1]!= "/": return [path] if is_local: def glob_matches_files(path, pattern): return len(glob.glob(path + pattern)) > 0 else: def glob_matches_files(path, pattern): result = self.run("ls \"%s\"%s" % (utils.sh_escape(path), pattern), stdout_tee=None, ignore_status=True) return result.exit_status == 0 patterns = ["*", ".[!.]*"] patterns = [p for p in patterns if glob_matches_files(path, p)] # convert them into a set of paths suitable for the commandline if is_local: return ["\"%s\"%s" % (utils.sh_escape(path), pattern) for pattern in patterns] else: return [utils.scp_remote_escape(path) + pattern for pattern in patterns]
def close(): super(RemoteHost, self).close() self.stop_loggers() if hasattr(self, "tmp_dirs"): for dir in self.tmp_dirs: try: self.run('rm -fr "%s"' % utils.sh_escape(dir)) except error.AutoError: pass
def close(): super(RemoteHost, self).close() self.stop_loggers() if hasattr(self, 'tmp_dirs'): for dir in self.tmp_dirs: try: self.run('rm -fr "%s"' % utils.sh_escape(dir)) except error.AutoError: pass
def run_async(self, command, stdout_tee=None, stderr_tee=None, args=(), connect_timeout=30, options='', verbose=True, stderr_level=utils.DEFAULT_STDERR_LEVEL, cmd_outside_subshell=''): """ Run a command on the remote host. Return an AsyncJob object to interact with the remote process. """ if verbose: logging.debug("Running (async ssh) '%s'" % command) # start a master SSH connection if necessary self.start_master_ssh() self.send_file(os.path.join(self.job.clientdir, "shared", "hosts", "scripts", "run_helper.py"), os.path.join(self.job.tmpdir, "run_helper.py")) env = " ".join("=".join(pair) for pair in self.env.iteritems()) ssh_cmd = self.ssh_command(connect_timeout, options) if not env.strip(): env = "" else: env = "export %s;" % env for arg in args: command += ' "%s"' % utils.sh_escape(arg) full_cmd = '{ssh_cmd} "{env} {cmd}"'.format(ssh_cmd=ssh_cmd, env=env, cmd=utils.sh_escape("%s (%s '%s')" % (cmd_outside_subshell, os.path.join(self.job.tmpdir, "run_helper.py"), utils.sh_escape(command)))) job = utils.AsyncJob(full_cmd, stdout_tee=stdout_tee, stderr_tee=stderr_tee, verbose=verbose, stderr_level=stderr_level, stdin=subprocess.PIPE) def kill_func(): utils.nuke_subprocess(job.sp) job.kill_func = kill_func return job
def get_file(self, source, dest, delete_dest=False, preserve_perm=True, preserve_symlinks=False): """ Copy files from the remote host to a local path Directories will be copied recursively. Args: delete_dest: if it is true, the command will also clear out any old files at dest that are not in the source preserve_perm: tells get_file() to try to preserve the sources permissions on files and dirs preserve_symlinks: try to preserver symlinks instead of transforming them into files/dirs on copy Raiseds: the scp command failed """ self.start_master_ssh() if isinstance(source, basestring): source = [source] dest = os.path.abspath(dest) try_scp = True if try_scp: if delete_dest and os.path.isdir(dest): shutil.rmtree(dest) os.mkdir(dest) remote_source = self._make_rsync_compatible_source(source, False) if remote_source: remote_source = self._encode_remote_paths(remote_source, escape=False) local_dest = utils.sh_escape(dest) scp = self._make_scp_cmd([remote_source], local_dest) try: utils.run(scp) except error.CmdError, e: raise error.ServeRunError(e.args[0], e.args[1])
def _make_ssh_cmd(self, cmd): base_cmd = _make_ssh_cmd_default(user=self.user, port=self.port, opts=self.master_ssh_option, hosts_file=self.known_hosts_file) return '%s %s "%s"' % (base_cmd, self.hostname, utils.sh_escape(cmd))
def glob_matches_files(path, pattern): result = self.run("ls \"%s\"%s" % (utils.sh_escape(path), pattern), stdout_tee=None, ignore_status=True) return result.exit_status == 0
def delete_tmp_dir(self, tmpdir): """ delete the given temporary directory on the remote machine """ self.run('rm -fr "%s"' % utils.sh_escape(tmpdir), ignore_status=True) self.tmp_dirs.remove(tmpdir)