• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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