198 lines
7.5 KiB
Python
198 lines
7.5 KiB
Python
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)
|