def submit_bkr_xml(self):
        """Submit a beaker job XML to Beaker.

        This method will upload (submit) a beaker job XML to Beaker. If the
        job was successfully uploaded, the beaker job id will be returned.
        """
        # setup beaker client job submit commnand
        _cmd = "bkr job-submit --xml %s" % os.path.join(
            self.data_folder, self.job_xml)

        self.logger.info('Submitting beaker job XML..')
        self.logger.debug('Command to be run: %s' % _cmd)

        # submit beaker XML
        results = exec_local_cmd(_cmd)
        if results[0] != 0:
            self.logger.error(results[2])
            raise BeakerProvisionerError('Failed to submit beaker job XML!')
        output = results[1]

        # post results tasks
        if output.find("Submitted:") != "-1":
            mod_output = output[output.find("Submitted:"):]

            # set the result as ascii instead of unicode
            job_id = mod_output[mod_output.find("[") + 2:mod_output.find("]") -
                                1]
            job_url = os.path.join(self.url, 'jobs', job_id[2:])

            self.logger.info('Beaker job ID: %s.' % job_id)
            self.logger.info('Beaker job URL: %s.' % job_url)

            self.logger.info('Successfully submitted beaker XML!')

            return job_id, job_url
 def _connect(self):
     """Connect to beaker."""
     data = exec_local_cmd('bkr whoami')
     if data[0] != 0:
         self.logger.error(data[2])
         raise BeakerProvisionerError('Connection to beaker failed!')
     self.logger.info('Connected to beaker!')
    def gen_bkr_xml(self):
        """Create beaker job xml based on host requirements.

        This method builds xml content and writes xml to file.
        """
        # set beaker xml absolute file path
        bkr_xml_file = os.path.join(self.data_folder, self.job_xml)

        # set attributes for beaker xml object
        for key, value in self.provider_params.items():
            if key is not 'name':
                if value:
                    setattr(self.bkr_xml, key, value)

        # generate beaker job xml (workflow-simple command)
        self.bkr_xml.generate_beaker_xml(bkr_xml_file,
                                         kickstart_path=self.workspace,
                                         savefile=True)

        if 'force' in self.bkr_xml.hrname:
            self.logger.warning(
                'Force was specified as a host_require_option.'
                'Any other host_require_options will be ignored since '
                'force is a mutually exclusive option in beaker.')
        # format beaker client command to run
        # Latest version of beaker client fails to generate xml with this
        # replacement
        # _cmd = self.bkr_xml.cmd.replace('=', "\=")

        self.logger.info('Generating beaker job XML..')
        self.logger.debug('Command to be run: %s' % self.bkr_xml.cmd)

        # generate beaker job XML
        results = exec_local_cmd(self.bkr_xml.cmd)
        if results[0] != 0:
            self.logger.error(results[2])
            raise BeakerProvisionerError('Failed to generate beaker job XML!')
        output = results[1]

        # generate complete beaker job XML
        self.bkr_xml.generate_xml_dom(bkr_xml_file, output, savefile=True)
        self.logger.info('Successfully generated beaker job XML!')
    def cancel_job(self, job_id):
        """Cancel a existing beaker job.

        This method will cancel a existing beaker job using the job id.
        """

        # setup beaker job cancel command
        _cmd = "bkr job-cancel {0}".format(job_id)

        self.logger.info('Canceling beaker job..')

        # cancel beaker job
        results = exec_local_cmd(_cmd)
        if results[0] != 0:
            self.logger.error(results[2])
            raise BeakerProvisionerError('Failed to cancel job.')
        output = results[1]

        if "Cancelled" in output:
            self.logger.info("Job %s cancelled." % job_id)
        else:
            raise BeakerProvisionerError('Failed to cancel beaker job!')

        self.logger.info('Successfully cancelled beaker job!')
    def wait_for_bkr_job(self, job_id):
        """Wait for submitted beaker job to have complete status.

        This method will wait for the beaker job to be complete depending on
        the timeout set. Users can define their own custom timeout or it will
        wait indefinitely for the machine to be provisioned.
        """
        # set max wait time (default is 8 hours)
        wait = self.provider_params.get('bkr_timeout', None)
        if wait is None:
            wait = 28800

        self.logger.debug('Beaker timeout limit: %s.' % wait)

        # check Beaker status every 60 seconds
        total_attempts = wait / 60

        attempt = 0
        while wait > 0:
            attempt += 1
            self.logger.info('Waiting for machine to be ready, attempt %s of '
                             '%s.' % (attempt, total_attempts))

            # setup beaker job results command
            _cmd = "bkr job-results %s" % job_id

            self.logger.debug('Fetching beaker job status..')

            # fetch beaker job status
            results = exec_local_cmd(_cmd)
            if results[0] != 0:
                self.logger.error(results[2])
                raise BeakerProvisionerError('Failed to fetch job status!')
            xml_output = results[1]

            self.logger.debug('Successfully fetched beaker job status!')

            bkr_job_status_dict = self.get_job_status(xml_output)
            self.logger.debug("Beaker job status: %s" % bkr_job_status_dict)
            status = self.analyze_results(bkr_job_status_dict)

            self.logger.info('Beaker Job: id: %s status: %s.' %
                             (job_id, status))

            if status == "wait":
                wait -= 60
                time.sleep(60)
                continue
            elif status == "success":
                self.logger.info("Machine is successfully provisioned from "
                                 "Beaker!")
                # get machine info
                return self.get_machine_info(xml_output)
            elif status == "fail":
                raise BeakerProvisionerError(
                    'Beaker job %s provision failed!' % job_id)
            else:
                raise BeakerProvisionerError(
                    'Beaker job %s has unknown status!' % job_id)

        # timeout reached for Beaker job
        self.logger.error('Maximum number of attempts reached!')

        # cancel job
        self.cancel_job(job_id)

        raise BeakerProvisionerError(
            'Timeout reached waiting for beaker job to finish!')