import os, re, sys, pwd, time, socket, getpass
import inspect, new, logging, string, tempfile
from autotest_lib.cli import topic_common, action_common
from autotest_lib.cli import job
from autotest_lib.client.common_lib import logging_config
from autotest_lib.client.virt import virt_utils
logging_config.LoggingConfig().configure_logging(verbose=True)
class site_job(job.job):
pass
class site_job_create(job.job_create):
"""
Adds job manipulation including installing packages from brew
"""
op_action = 'create'
def __init__(self):
super(site_job_create, self).__init__()
self.parser.add_option('-T', '--template', action='store_true',
help='Control file is actually a template')
self.parser.add_option('-x', '--extra-cartesian-config',
action='append',
help='Add extra configuration to the cartesian '
'config file')
self.parser.add_option('--timestamp', action='store_true',
help='Add a timestamp to the name of the job')
self.parser.add_option('--koji-arch', default='x86_64',
help='Default architecture for packages '
'that will be fetched from koji build. '
'This will be combined with "noarch".'
'This option is used to help to validate '
'packages from the job submitting machine.')
self.parser.add_option('--koji-tag', help='Sets a default koji tag '
'for koji packages specified with --koji-pkg')
self.parser.add_option('--koji-pkg', action='append',
help='Packages to add to host installation '
'based on koji build. This options may be '
'specified multiple times.')
self.koji_client = None
def parse(self):
'''
Parse options.
If any brew options is specified, instantiate KojiDownloader
'''
(self.command_line_options,
self.command_line_leftover) = super(site_job_create, self).parse()
#
# creating the new control file
#
if (self.command_line_options.template and
self.command_line_options.control_file):
generated_control_file = self._generate_control_file()
self.data['control_file'] = open(generated_control_file).read()
if self.command_line_options.koji_pkg:
if self.koji_client is None:
self.koji_client = virt_utils.KojiClient()
return (self.command_line_options, self.command_line_leftover)
def _process_options(self):
'''
Process all options given on command line
'''
all_options_valid = True
self._set_koji_tag()
if not self._check_koji_packages():
all_options_valid = False
return all_options_valid
def _set_koji_tag(self):
'''
Sets the default koji tag.
Configuration item on file is: koji_tag
'''
if self.command_line_options.koji_tag is not None:
virt_utils.set_default_koji_tag(self.command_line_options.koji_tag)
def _check_koji_packages(self):
'''
Check if packages specification are valid and exist on koji/brew
Configuration item on file is: koji_pkgs
'''
all_packages_found = True
if self.command_line_options.koji_pkg is not None:
logging.debug('Checking koji packages specification')
for pkg_spec_text in self.command_line_options.koji_pkg:
pkg_spec = virt_utils.KojiPkgSpec(pkg_spec_text)
if not (pkg_spec.is_valid() and
self.koji_client.is_pkg_valid(pkg_spec)):
logging.error('Koji package spec is not valid, skipping: '
'%s' % pkg_spec)
all_packages_found = False
else:
rpms = self.koji_client.get_pkg_rpm_info(
pkg_spec,
self.command_line_options.koji_arch)
for subpackage in pkg_spec.subpackages:
if subpackage not in [rpm['name'] for rpm in rpms]:
logging.error('Package specified but not found in '
'koji: %s' % subpackage)
all_packages_found = False
rpms = ", ".join(rpm['nvr'] for rpm in rpms)
logging.debug('Koji package spec is valid')
logging.debug('Koji packages to be fetched and installed: '
'%s' % rpms)
return all_packages_found
def _generate_job_config(self):
'''
Converts all options given on the command line to config file syntax
'''
extra = []
if self.command_line_options.extra_cartesian_config:
extra += self.command_line_options.extra_cartesian_config
if self.command_line_options.koji_tag:
extra.append("koji_tag = %s" % self.command_line_options.koji_tag)
if self.command_line_options.koji_pkg:
koji_pkgs = []
for koji_pkg in self.command_line_options.koji_pkg:
koji_pkgs.append('"%s"' % koji_pkg)
extra.append("koji_pkgs = [%s]" % ', '.join(koji_pkgs))
# add quotes...
extra = ["'%s'" % e for e in extra]
# ... and return as string that will be eval'd as a Python list
return "[%s]" % ', '.join(extra)
def _generate_control_file(self):
'''
Generates a controle file from a template
'''
custom_job_cfg = self._generate_job_config()
input_file = self.command_line_options.control_file
logging.debug('Generating control file from template: %s' % input_file)
template = string.Template(open(input_file).read())
output_fd, path = tempfile.mkstemp(prefix='atest_control_', dir='/tmp')
logging.debug('Generated control file to be saved at: %s' % path)
parameters_dict = {"custom_job_cfg": custom_job_cfg}
control_file_text = template.substitute(parameters_dict)
os.write(output_fd, control_file_text)
os.close(output_fd)
return path
def execute(self):
if not self._process_options():
self.generic_error('Some command line options validation failed. '
'Aborting job creation.')
return
#
# add timestamp to the jobname
#
if self.command_line_options.timestamp:
logging.debug("Adding timestamp to jobname")
timestamp = time.strftime(" %m-%d-%Y %H:%M:%S", time.localtime())
self.jobname += timestamp
self.data['name'] = self.jobname
execute_results = super(site_job_create, self).execute()
self.output(execute_results)
for cls in [getattr(job, n) for n in dir(job) if not n.startswith("_")]:
if not inspect.isclass(cls):
continue
cls_name = cls.__name__
site_cls_name = 'site_' + cls_name
if hasattr(sys.modules[__name__], site_cls_name):
continue
bases = (site_job, cls)
members = {'__doc__': cls.__doc__}
site_cls = new.classobj(site_cls_name, bases, members)
setattr(sys.modules[__name__], site_cls_name, site_cls)