| 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) |