All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.yahoo.vespa.hosted.controller.deployment.JobList Maven / Gradle / Ivy

There is a newer version: 8.253.3
Show newest version
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.deployment;

import com.yahoo.collections.AbstractFilteringList;
import com.yahoo.component.Version;
import com.yahoo.config.provision.InstanceName;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.ApplicationVersion;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;

import java.time.Instant;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;

/**
 * A list of deployment jobs that can be filtered in various ways.
 *
 * @author jonmv
 */
public class JobList extends AbstractFilteringList {

    private JobList(Collection jobs, boolean negate) {
        super(jobs, negate, JobList::new);
    }

    // ----------------------------------- Factories

    public static JobList from(Collection jobs) {
        return new JobList(jobs, false);
    }

    // ----------------------------------- Basic filters

    /** Returns the status of the job of the given type, if it is contained in this. */
    public Optional get(JobId id) {
        return asList().stream().filter(job -> job.id().equals(id)).findAny();
    }

    /** Returns the subset of jobs which are currently upgrading */
    public JobList upgrading() {
        return matching(job ->    job.isRunning()
                               && job.lastSuccess().isPresent()
                               && job.lastSuccess().get().versions().targetPlatform().isBefore(job.lastTriggered().get().versions().targetPlatform()));
    }

    /** Returns the subset of jobs which are currently failing */
    public JobList failing() {
        return matching(job -> job.lastCompleted().isPresent() && ! job.isSuccess());
    }

    public JobList running() {
        return matching(job -> job.isRunning());
    }

    /** Returns the subset of jobs which must be failing due to an application change */
    public JobList failingApplicationChange() {
        return matching(JobList::failingApplicationChange);
    }

    /** Returns the subset of jobs which are failing with the given run status. */
    public JobList withStatus(RunStatus status) {
        return matching(job -> job.lastStatus().map(status::equals).orElse(false));
    }

    /** Returns the subset of jobs of the given type -- most useful when negated. */
    public JobList type(Collection types) {
        return matching(job -> types.contains(job.id().type()));
    }

    /** Returns the subset of jobs of the given type -- most useful when negated. */
    public JobList type(JobType... types) {
        return type(List.of(types));
    }

    /** Returns the subset of jobs run for the given instance. */
    public JobList instance(InstanceName instance) {
        return matching(job -> job.id().application().instance().equals(instance));
    }

    /** Returns the subset of jobs of which are production jobs. */
    public JobList production() {
        return matching(job -> job.id().type().isProduction());
    }

    /** Returns the jobs with any runs matching the given versions — targets only for system test, everything present otherwise. */
    public JobList triggeredOn(Versions versions) {
        return matching(job -> ! RunList.from(job).on(versions).isEmpty());
    }

    /** Returns the jobs with successful runs matching the given versions — targets only for system test, everything present otherwise. */
    public JobList successOn(Versions versions) {
        return matching(job -> ! RunList.from(job).status(RunStatus.success).on(versions).isEmpty());
    }

    // ----------------------------------- JobRun filtering

    /** Returns the list in a state where the next filter is for the lastTriggered run type */
    public RunFilter lastTriggered() {
        return new RunFilter(JobStatus::lastTriggered);
    }

    /** Returns the list in a state where the next filter is for the lastCompleted run type */
    public RunFilter lastCompleted() {
        return new RunFilter(JobStatus::lastCompleted);
    }

    /** Returns the list in a state where the next filter is for the lastSuccess run type */
    public RunFilter lastSuccess() {
        return new RunFilter(JobStatus::lastSuccess);
    }

    /** Returns the list in a state where the next filter is for the firstFailing run type */
    public RunFilter firstFailing() {
        return new RunFilter(JobStatus::firstFailing);
    }

    /** Allows sub-filters for runs of the indicated kind */
    public class RunFilter {

        private final Function> which;

        private RunFilter(Function> which) {
            this.which = which;
        }

        /** Returns the subset of jobs where the run of the indicated type exists */
        public JobList present() {
            return matching(run -> true);
        }

        /** Returns the runs of the indicated kind, mapped by the given function, as a list. */
        public  List mapToList(Function mapper) {
            return present().mapToList(which.andThen(Optional::get).andThen(mapper));
        }

        /** Returns the runs of the indicated kind. */
        public List asList() {
            return mapToList(Function.identity());
        }

        /** Returns the subset of jobs where the run of the indicated type ended no later than the given instant */
        public JobList endedNoLaterThan(Instant threshold) {
            return matching(run -> ! run.end().orElse(Instant.MAX).isAfter(threshold));
        }

        /** Returns the subset of jobs where the run of the indicated type was on the given version */
        public JobList on(ApplicationVersion version) {
            return matching(run -> run.versions().targetApplication().equals(version));
        }

        /** Returns the subset of jobs where the run of the indicated type was on the given version */
        public JobList on(Version version) {
            return matching(run -> run.versions().targetPlatform().equals(version));
        }

        /** Transforms the JobRun condition to a JobStatus condition, by considering only the JobRun mapped by which, and executes */
        private JobList matching(Predicate condition) {
            return JobList.this.matching(job -> which.apply(job).filter(condition).isPresent());
        }

    }

    // ----------------------------------- Internal helpers

    private static boolean failingApplicationChange(JobStatus job) {
        if (job.isSuccess()) return false;
        if (job.lastSuccess().isEmpty()) return true; // An application which never succeeded is surely bad.
        if ( ! job.firstFailing().get().versions().targetPlatform().equals(job.lastSuccess().get().versions().targetPlatform())) return false; // Version change may be to blame.
        return ! job.firstFailing().get().versions().targetApplication().equals(job.lastSuccess().get().versions().targetApplication()); // Return whether there is an application change.
    }

}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy