def get(self, **kwargs): """ This method overrides baseclass get so we can do proper git clone/pulls, and check for updated versions. The result of this method will leave an up-to-date version of git repo at 'giturl' in 'repodir' directory to be used by build/install methods. @param **kwargs: Dictionary of parameters to the method get. """ if not self.is_repo_initialized(): # this is your first time ... logging.info('Cloning git repo %s', self.giturl) cmd = 'clone %s %s ' % (self.giturl, self.repodir) rv = self.gitcmd(cmd, True) if rv.exit_status != 0: logging.error(rv.stderr) raise error.CmdError('Failed to clone git url', rv) else: logging.info(rv.stdout) else: # exiting repo, check if we're up-to-date if self.is_out_of_date(): logging.info('Updating git repo %s', self.giturl) rv = self.gitcmd('pull', True) if rv.exit_status != 0: logging.error(rv.stderr) e_msg = 'Failed to pull git repo data' raise error.CmdError(e_msg, rv) else: logging.info('repo up-to-date') # remember where the source is self.source_material = self.repodir
def method(cmdResult): """ Parse method for systemctl list XXX.service. Return a dict from service name to status. e.g: {"sshd": "enabled", "vsftpd": "disabled", "systemd-sysctl": "static", ... } """ if cmdResult.exit_status: raise error.CmdError(cmdResult.command, cmdResult) # Dict to store service name to status. _service2status_dict = {} lines = cmdResult.stdout.strip().splitlines() for line in lines: sublines = line.strip().split() if (not len(sublines) == 2) or (not sublines[0].endswith("service")): # Some lines useless. continue service_name = sublines[0].rstrip(".service") status = sublines[-1] _service2status_dict[service_name] = status return _service2status_dict
def run(self, command, timeout=60, ignore_status=False): """ Method to provide a utils.run-like interface to execute command on remote host or guest. :param timeout: Total time duration to wait for command return. :param ignore_status: If ignore_status=True, do not raise an exception, no matter what the exit code of the command is. Else, raise CmdError if exit code of command is not zero. """ # Redirect the stdout and stderr to file, Deviding error message # from output, and taking off the color of output. To return the same # result with utils.run() function. command = "%s 1>%s 2>%s" % (command, self.stdout_pipe, self.stderr_pipe) status, _ = self.session.cmd_status_output(command, timeout=timeout) output = self.session.cmd_output("cat %s;rm -f %s" % (self.stdout_pipe, self.stdout_pipe)) errput = self.session.cmd_output("cat %s;rm -f %s" % (self.stderr_pipe, self.stderr_pipe)) cmd_result = utils.CmdResult(command=command, exit_status=status, stdout=output, stderr=errput) if (status and (not ignore_status)): raise error.CmdError(command, cmd_result) return cmd_result
def get_branch(self, all=False, remote_tracking=False): """ Show the branches. @param all: List both remote-tracking branches and local branches (True) or only the local ones (False). @param remote_tracking: Lists the remote-tracking branches. """ if not self.is_repo_initialized(): self.get() cmd = 'branch --no-color' if all: cmd = " ".join([cmd, "-a"]) if remote_tracking: cmd = " ".join([cmd, "-r"]) gitlog = self.gitcmd(cmd, True) if gitlog.exit_status != 0: logging.error(gitlog.stderr) raise error.CmdError('Failed to get git branch', gitlog) elif all or remote_tracking: return gitlog.stdout.strip('\n') else: branch = [ b[2:] for b in gitlog.stdout.split('\n') if b.startswith('*') ][0] return branch
def join_bg_jobs(bg_jobs, timeout=None): """Joins the bg_jobs with the current thread. Returns the same list of bg_jobs objects that was passed in. """ ret, timeout_error = 0, False for bg_job in bg_jobs: bg_job.output_prepare(StringIO.StringIO(), StringIO.StringIO()) try: # We are holding ends to stdin, stdout pipes # hence we need to be sure to close those fds no mater what start_time = time.time() timeout_error = _wait_for_commands(bg_jobs, start_time, timeout) for bg_job in bg_jobs: # Process stdout and stderr bg_job.process_output(stdout=True,final_read=True) bg_job.process_output(stdout=False,final_read=True) finally: # close our ends of the pipes to the sp no matter what for bg_job in bg_jobs: bg_job.cleanup() if timeout_error: # TODO: This needs to be fixed to better represent what happens when # running in parallel. However this is backwards compatible, so it will # do for the time being. raise error.CmdError(bg_jobs[0].command, bg_jobs[0].result, "Command(s) did not complete within %d seconds" % timeout) return bg_jobs
def remote(self): """ Return repository git remote name. """ gitlog = self.gitcmd('remote') if gitlog.exit_status != 0: logging.error(gitlog.stderr) raise error.CmdError('Failed to run git remote.') else: return gitlog.stdout.strip('\n')
def get_revision(self): """ Return current HEAD commit id """ if not self.is_repo_initialized(): self.get() cmd = 'rev-parse --verify HEAD' gitlog = self.gitcmd(cmd, True) if gitlog.exit_status != 0: logging.error(gitlog.stderr) raise error.CmdError('Failed to find git sha1 revision', gitlog) else: return gitlog.stdout.strip('\n')
def config(self, option_name): """ Return the git config value for the given option name. @option_name: The name of the git option to get. """ cmd = 'config ' + option_name gitlog = self.gitcmd(cmd) if gitlog.exit_status != 0: logging.error(gitlog.stderr) raise error.CmdError('Failed to get git config %', option_name) else: return gitlog.stdout.strip('\n')
def method(cmdResult): """ Parse method for service XXX list. Return dict from service name to status. e.g: {"sshd": {0: 'off', 1: 'off', 2: 'off', 3: 'off', 4: 'off', 5: 'off', 6: 'off'}, "vsftpd": {0: 'off', 1: 'off', 2: 'off', 3: 'off', 4: 'off', 5: 'off', 6: 'off'}, "xinetd": {'discard-dgram:': 'off', 'rsync:': 'off'...'chargen-stream:': 'off'}, ... } """ if cmdResult.exit_status: raise error.CmdError(cmdResult.command, cmdResult) # The final dict to return. _service2statusOnTarget_dict = {} # Dict to store status on every target for each service. _status_on_target = {} # Dict to store the status for service based on xinetd. _service2statusOnXinet_dict = {} lines = cmdResult.stdout.strip().splitlines() for line in lines: sublines = line.strip().split() if len(sublines) == 8: # Service and status on each target. service_name = sublines[0] # Store the status of each target in _status_on_target. for target in range(7): status = sublines[target + 1].split(":")[-1] _status_on_target[target] = status _service2statusOnTarget_dict[ service_name] = _status_on_target.copy() elif len(sublines) == 2: # Service based on xinetd. service_name = sublines[0].strip(":") status = sublines[-1] _service2statusOnXinet_dict[service_name] = status else: # Header or some lines useless. continue # Add xinetd based service in the main dict. _service2statusOnTarget_dict[ "xinetd"] = _service2statusOnXinet_dict return _service2statusOnTarget_dict
def run(command, timeout=None, ignore_status=False, stdout_tee=None, stderr_tee=None, verbose=True, stdin=None, stderr_is_expected=None, args=()): """ Run a command on the host. @param command: the command line string. @param timeout: time limit in seconds before attempting to kill the running process. The run() function will take a few seconds longer than 'timeout' to complete if it has to kill the process. @param ignore_status: do not raise an exception, no matter what the exit code of the command is. @param stdout_tee: optional file-like object to which stdout data will be written as it is generated (data will still be stored in result.stdout). @param stderr_tee: likewise for stderr. @param verbose: if True, log the command being run. @param stdin: stdin to pass to the executed process (can be a file descriptor, a file object of a real file or a string). @param args: sequence of strings of arguments to be given to the command inside " quotes after they have been escaped for that; each element in the sequence will be given as a separate command argument @return a CmdResult object @raise CmdError: the exit code of the command execution was not 0 """ if isinstance(args, basestring): raise TypeError('Got a string for the "args" keyword argument, ' 'need a sequence.') for arg in args: command += ' "%s"' % sh_escape(arg) if stderr_is_expected is None: stderr_is_expected = ignore_status bg_job = join_bg_jobs( (BgJob(command, stdout_tee, stderr_tee, verbose, stdin=stdin, stderr_level=get_stderr_level(stderr_is_expected)),), timeout)[0] if not ignore_status and bg_job.result.exit_status: raise error.CmdError(command, bg_job.result, "Command returned non-zero exit status") return bg_job.result
def status(self, short=True): """ Return the current status of the git repo. @param short: Whether to give the output in the short-format. """ cmd = 'status' if short: cmd += ' -s' gitlog = self.gitcmd(cmd, True) if gitlog.exit_status != 0: logging.error(gitlog.stderr) raise error.CmdError('Failed to get git status', gitlog) else: return gitlog.stdout.strip('\n')
def checkout(self, remote, local=None): """ Check out the git commit id, branch, or tag given by remote. Optional give the local branch name as local. @param remote: Remote commit hash @param local: Local commit hash @note: For git checkout tag git version >= 1.5.0 is required """ if not self.is_repo_initialized(): self.get() assert (isinstance(remote, basestring)) if local: cmd = 'checkout -b %s %s' % (local, remote) else: cmd = 'checkout %s' % (remote) gitlog = self.gitcmd(cmd, True) if gitlog.exit_status != 0: logging.error(gitlog.stderr) raise error.CmdError('Failed to checkout git branch', gitlog) else: logging.info(gitlog.stdout)