def create_new_job(owner, options, host_objects, metahost_objects):
    all_host_objects = host_objects + metahost_objects
    dependencies = options.get('dependencies', [])
    synch_count = options.get('synch_count')

    if synch_count is not None and synch_count > len(all_host_objects):
        raise model_logic.ValidationError({
            'hosts':
            'only %d hosts provided for job with synch_count = %d' %
            (len(all_host_objects), synch_count)
        })

    check_for_duplicate_hosts(host_objects)

    for label_name in dependencies:
        if provision.is_for_special_action(label_name):
            # TODO: We could save a few queries
            # if we had a bulk ensure-label-exists function, which used
            # a bulk .get() call. The win is probably very small.
            _ensure_label_exists(label_name)

    # This only checks targeted hosts, not hosts eligible due to the metahost
    check_job_dependencies(host_objects, dependencies)
    check_job_metahost_dependencies(metahost_objects, dependencies)

    options['dependencies'] = list(
        models.Label.objects.filter(name__in=dependencies))

    job = models.Job.create(owner=owner,
                            options=options,
                            hosts=all_host_objects)
    job.queue(all_host_objects, is_template=options.get('is_template', False))
    return job.id
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 check_job_dependencies(host_objects, job_dependencies):
    """
    Check that a set of machines satisfies a job's dependencies.
    host_objects: list of models.Host objects
    job_dependencies: list of names of labels
    """
    # check that hosts satisfy dependencies
    host_ids = [host.id for host in host_objects]
    hosts_in_job = models.Host.objects.filter(id__in=host_ids)
    ok_hosts = hosts_in_job
    for index, dependency in enumerate(job_dependencies):
        if not provision.is_for_special_action(dependency):
            try:
                label = models.Label.smart_get(dependency)
            except models.Label.DoesNotExist:
                logging.info(
                    'Label %r does not exist, so it cannot '
                    'be replaced by static label.', dependency)
                label = None

            if label is not None and label.is_replaced_by_static():
                ok_hosts = ok_hosts.filter(static_labels__name=dependency)
            else:
                ok_hosts = ok_hosts.filter(labels__name=dependency)

    failing_hosts = (set(host.hostname
                         for host in host_objects) - set(host.hostname
                                                         for host in ok_hosts))
    if failing_hosts:
        raise model_logic.ValidationError({
            'hosts':
            'Host(s) failed to meet job dependencies (' +
            (', '.join(job_dependencies)) + '): ' + (', '.join(failing_hosts))
        })
    def get_job_info(self, queue_entry):
        """Extract job information from a queue_entry/host-scheduler.

        @param queue_entry: The queue_entry for which we need job information.

        @return: A dictionary representing job related information.
        """
        job_id = queue_entry.job_id
        job_deps, job_preferred_deps = [], []
        for dep in self._job_deps.get(job_id, []):
            if not provision.is_for_special_action(self._labels[dep].name):
                job_deps.append(dep)
            elif provision.Provision.acts_on(self._labels[dep].name):
                job_preferred_deps.append(dep)

        job_acls = self._job_acls.get(job_id, [])
        parent_id = queue_entry.job.parent_job_id
        min_duts = self._suite_min_duts.get(parent_id, 0) if parent_id else 0

        return {
            'deps': job_deps,
            'acls': job_acls,
            'preferred_deps': job_preferred_deps,
            'host_id': queue_entry.host_id,
            'parent_job_id': queue_entry.job.parent_job_id,
            'priority': queue_entry.job.priority,
            'suite_min_duts': min_duts
        }
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 check_job_dependencies(host_objects, job_dependencies):
    """
    Check that a set of machines satisfies a job's dependencies.
    host_objects: list of models.Host objects
    job_dependencies: list of names of labels
    """
    # check that hosts satisfy dependencies
    host_ids = [host.id for host in host_objects]
    hosts_in_job = models.Host.objects.filter(id__in=host_ids)
    ok_hosts = hosts_in_job
    for index, dependency in enumerate(job_dependencies):
        if not provision.is_for_special_action(dependency):
            ok_hosts = ok_hosts.filter(labels__name=dependency)
    failing_hosts = (set(host.hostname for host in host_objects) -
                     set(host.hostname for host in ok_hosts))
    if failing_hosts:
        raise model_logic.ValidationError(
            {'hosts' : 'Host(s) failed to meet job dependencies (' +
                       (', '.join(job_dependencies)) + '): ' +
                       (', '.join(failing_hosts))})