1import os, re, sys, pwd, time, socket, getpass 2import inspect, new, logging, string, tempfile 3 4from autotest_lib.cli import topic_common, action_common 5from autotest_lib.cli import job 6from autotest_lib.client.common_lib import logging_config 7from autotest_lib.client.virt import virt_utils 8 9logging_config.LoggingConfig().configure_logging(verbose=True) 10 11 12class site_job(job.job): 13 pass 14 15 16class site_job_create(job.job_create): 17 """ 18 Adds job manipulation including installing packages from brew 19 """ 20 21 op_action = 'create' 22 23 def __init__(self): 24 super(site_job_create, self).__init__() 25 self.parser.add_option('-T', '--template', action='store_true', 26 help='Control file is actually a template') 27 self.parser.add_option('-x', '--extra-cartesian-config', 28 action='append', 29 help='Add extra configuration to the cartesian ' 30 'config file') 31 self.parser.add_option('--timestamp', action='store_true', 32 help='Add a timestamp to the name of the job') 33 self.parser.add_option('--koji-arch', default='x86_64', 34 help='Default architecture for packages ' 35 'that will be fetched from koji build. ' 36 'This will be combined with "noarch".' 37 'This option is used to help to validate ' 38 'packages from the job submitting machine.') 39 self.parser.add_option('--koji-tag', help='Sets a default koji tag ' 40 'for koji packages specified with --koji-pkg') 41 self.parser.add_option('--koji-pkg', action='append', 42 help='Packages to add to host installation ' 43 'based on koji build. This options may be ' 44 'specified multiple times.') 45 self.koji_client = None 46 47 48 def parse(self): 49 ''' 50 Parse options. 51 52 If any brew options is specified, instantiate KojiDownloader 53 ''' 54 (self.command_line_options, 55 self.command_line_leftover) = super(site_job_create, self).parse() 56 57 # 58 # creating the new control file 59 # 60 if (self.command_line_options.template and 61 self.command_line_options.control_file): 62 generated_control_file = self._generate_control_file() 63 self.data['control_file'] = open(generated_control_file).read() 64 65 if self.command_line_options.koji_pkg: 66 if self.koji_client is None: 67 self.koji_client = virt_utils.KojiClient() 68 69 return (self.command_line_options, self.command_line_leftover) 70 71 72 def _process_options(self): 73 ''' 74 Process all options given on command line 75 ''' 76 all_options_valid = True 77 78 self._set_koji_tag() 79 if not self._check_koji_packages(): 80 all_options_valid = False 81 82 return all_options_valid 83 84 85 def _set_koji_tag(self): 86 ''' 87 Sets the default koji tag. 88 89 Configuration item on file is: koji_tag 90 ''' 91 if self.command_line_options.koji_tag is not None: 92 virt_utils.set_default_koji_tag(self.command_line_options.koji_tag) 93 94 95 def _check_koji_packages(self): 96 ''' 97 Check if packages specification are valid and exist on koji/brew 98 99 Configuration item on file is: koji_pkgs 100 ''' 101 all_packages_found = True 102 if self.command_line_options.koji_pkg is not None: 103 logging.debug('Checking koji packages specification') 104 for pkg_spec_text in self.command_line_options.koji_pkg: 105 pkg_spec = virt_utils.KojiPkgSpec(pkg_spec_text) 106 107 if not (pkg_spec.is_valid() and 108 self.koji_client.is_pkg_valid(pkg_spec)): 109 logging.error('Koji package spec is not valid, skipping: ' 110 '%s' % pkg_spec) 111 all_packages_found = False 112 else: 113 rpms = self.koji_client.get_pkg_rpm_info( 114 pkg_spec, 115 self.command_line_options.koji_arch) 116 for subpackage in pkg_spec.subpackages: 117 if subpackage not in [rpm['name'] for rpm in rpms]: 118 logging.error('Package specified but not found in ' 119 'koji: %s' % subpackage) 120 all_packages_found = False 121 122 rpms = ", ".join(rpm['nvr'] for rpm in rpms) 123 logging.debug('Koji package spec is valid') 124 logging.debug('Koji packages to be fetched and installed: ' 125 '%s' % rpms) 126 127 return all_packages_found 128 129 def _generate_job_config(self): 130 ''' 131 Converts all options given on the command line to config file syntax 132 ''' 133 extra = [] 134 if self.command_line_options.extra_cartesian_config: 135 extra += self.command_line_options.extra_cartesian_config 136 137 if self.command_line_options.koji_tag: 138 extra.append("koji_tag = %s" % self.command_line_options.koji_tag) 139 140 if self.command_line_options.koji_pkg: 141 koji_pkgs = [] 142 for koji_pkg in self.command_line_options.koji_pkg: 143 koji_pkgs.append('"%s"' % koji_pkg) 144 extra.append("koji_pkgs = [%s]" % ', '.join(koji_pkgs)) 145 146 # add quotes... 147 extra = ["'%s'" % e for e in extra] 148 # ... and return as string that will be eval'd as a Python list 149 return "[%s]" % ', '.join(extra) 150 151 152 def _generate_control_file(self): 153 ''' 154 Generates a controle file from a template 155 ''' 156 custom_job_cfg = self._generate_job_config() 157 input_file = self.command_line_options.control_file 158 logging.debug('Generating control file from template: %s' % input_file) 159 template = string.Template(open(input_file).read()) 160 output_fd, path = tempfile.mkstemp(prefix='atest_control_', dir='/tmp') 161 logging.debug('Generated control file to be saved at: %s' % path) 162 parameters_dict = {"custom_job_cfg": custom_job_cfg} 163 control_file_text = template.substitute(parameters_dict) 164 os.write(output_fd, control_file_text) 165 os.close(output_fd) 166 return path 167 168 169 def execute(self): 170 if not self._process_options(): 171 self.generic_error('Some command line options validation failed. ' 172 'Aborting job creation.') 173 return 174 175 # 176 # add timestamp to the jobname 177 # 178 if self.command_line_options.timestamp: 179 logging.debug("Adding timestamp to jobname") 180 timestamp = time.strftime(" %m-%d-%Y %H:%M:%S", time.localtime()) 181 self.jobname += timestamp 182 self.data['name'] = self.jobname 183 184 execute_results = super(site_job_create, self).execute() 185 self.output(execute_results) 186 187 188for cls in [getattr(job, n) for n in dir(job) if not n.startswith("_")]: 189 if not inspect.isclass(cls): 190 continue 191 cls_name = cls.__name__ 192 site_cls_name = 'site_' + cls_name 193 if hasattr(sys.modules[__name__], site_cls_name): 194 continue 195 bases = (site_job, cls) 196 members = {'__doc__': cls.__doc__} 197 site_cls = new.classobj(site_cls_name, bases, members) 198 setattr(sys.modules[__name__], site_cls_name, site_cls) 199