def check_job_metahost_dependencies(metahost_objects, job_dependencies): """ Check that at least one machine within the metahost spec satisfies the job's dependencies. @param metahost_objects A list of label objects representing the metahosts. @param job_dependencies A list of strings of the required label names. @raises NoEligibleHostException If a metahost cannot run the job. """ for metahost in metahost_objects: if metahost.is_replaced_by_static(): static_metahost = models.StaticLabel.smart_get(metahost.name) hosts = models.Host.objects.filter(static_labels=static_metahost) else: hosts = models.Host.objects.filter(labels=metahost) for label_name in job_dependencies: if not provision.is_for_special_action(label_name): try: label = models.Label.smart_get(label_name) except models.Label.DoesNotExist: logging.info( 'Label %r does not exist, so it cannot ' 'be replaced by static label.', label_name) label = None if label is not None and label.is_replaced_by_static(): hosts = hosts.filter(static_labels__name=label_name) else: hosts = hosts.filter(labels__name=label_name) if not any(hosts): raise error.NoEligibleHostException( "No hosts within %s satisfy %s." % (metahost.name, ', '.join(job_dependencies)))
def lock_host_with_labels(afe, lock_manager, labels): """Lookup and lock one host that matches the list of input labels. @param afe: An instance of the afe class, as defined in server.frontend. @param lock_manager: A lock manager capable of locking hosts, eg the one defined in server.cros.host_lock_manager. @param labels: A list of labels to look for on hosts. @return: The hostname of a host matching all labels, and locked through the lock_manager. The hostname will be as specified in the database the afe object is associated with, i.e if it exists in afe_hosts with a .cros suffix, the hostname returned will contain a .cros suffix. @raises: error.NoEligibleHostException: If no hosts matching the list of input labels are available. @raises: error.TestError: If unable to lock a host matching the labels. """ potential_hosts = afe.get_hosts(multiple_labels=labels) if not potential_hosts: raise error.NoEligibleHostException( 'No devices found with labels %s.' % labels) # This prevents errors where a fault might seem repeatable # because we lock, say, the same packet capturer for each test run. random.shuffle(potential_hosts) for host in potential_hosts: if lock_manager.lock([host.hostname]): logging.info('Locked device %s with labels %s.', host.hostname, labels) return host.hostname else: logging.info('Unable to lock device %s with labels %s.', host.hostname, labels) raise error.TestError('Could not lock a device with labels %s' % labels)
def check_job_metahost_dependencies(metahost_objects, job_dependencies): """ Check that at least one machine within the metahost spec satisfies the job's dependencies. @param metahost_objects A list of label objects representing the metahosts. @param job_dependencies A list of strings of the required label names. @raises NoEligibleHostException If a metahost cannot run the job. """ for metahost in metahost_objects: hosts = models.Host.objects.filter(labels=metahost) for label_name in job_dependencies: if not provision.is_for_special_action(label_name): hosts = hosts.filter(labels__name=label_name) if not any(hosts): raise error.NoEligibleHostException("No hosts within %s satisfy %s." % (metahost.name, ', '.join(job_dependencies)))
def expect_job_scheduling(self, recorder, tests_to_skip=[], ignore_deps=False, raises=False, suite_deps=[], suite=None, extra_keyvals={}): """Expect jobs to be scheduled for 'tests' in |self.files|. @param recorder: object with a record_entry to be used to record test results. @param tests_to_skip: [list, of, test, names] that we expect to skip. @param ignore_deps: If true, ignore tests' dependencies. @param raises: If True, expect exceptions. @param suite_deps: If True, add suite level dependencies. @param extra_keyvals: Extra keyvals set to tests. """ record_job_id = suite and suite._results_dir if record_job_id: self.mox.StubOutWithMock(suite, '_remember_job_keyval') recorder.record_entry( StatusContains.CreateFromStrings('INFO', 'Start %s' % self._TAG), log_in_subdir=False) tests = self.files.values() n = 1 for test in tests: if test.name in tests_to_skip: continue dependencies = [] if not ignore_deps: dependencies.extend(test.dependencies) if suite_deps: dependencies.extend(suite_deps) dependencies.append(self._BOARD) build = self._BUILDS[provision.CROS_VERSION_PREFIX] keyvals = { 'build': build, 'suite': self._TAG, 'builds': SuiteTest._BUILDS, 'experimental':test.experimental, } keyvals.update(extra_keyvals) job_mock = self.afe.create_job( control_file=test.text, name=mox.And(mox.StrContains(build), mox.StrContains(test.name)), control_type=mox.IgnoreArg(), meta_hosts=[self._BOARD], dependencies=dependencies, keyvals=keyvals, max_runtime_mins=24*60, timeout_mins=1440, parent_job_id=None, reboot_before=mox.IgnoreArg(), run_reset=mox.IgnoreArg(), priority=priorities.Priority.DEFAULT, synch_count=test.sync_count, require_ssp=test.require_ssp ) if raises: job_mock.AndRaise(error.NoEligibleHostException()) recorder.record_entry( StatusContains.CreateFromStrings('START', test.name), log_in_subdir=False) recorder.record_entry( StatusContains.CreateFromStrings('TEST_NA', test.name), log_in_subdir=False) recorder.record_entry( StatusContains.CreateFromStrings('END', test.name), log_in_subdir=False) else: fake_job = FakeJob(id=n) job_mock.AndReturn(fake_job) if record_job_id: suite._remember_job_keyval(fake_job) n += 1