diff options
Diffstat (limited to 'config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java')
-rw-r--r-- | config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java | 165 |
1 files changed, 127 insertions, 38 deletions
diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java b/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java index ea7df677e0f..67b3d585881 100644 --- a/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java +++ b/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java @@ -13,10 +13,12 @@ import java.io.Reader; import java.time.Duration; import java.util.ArrayList; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Specifies the environments and regions to which an application should be deployed. @@ -75,14 +77,14 @@ public class DeploymentSpec { List<Step> steps = new ArrayList<>(inputSteps); // Add staging if required and missing - if (steps.stream().anyMatch(step -> step.deploysTo(Environment.prod)) && - steps.stream().noneMatch(step -> step.deploysTo(Environment.staging))) { + if (steps.stream().anyMatch(step -> step.concerns(Environment.prod)) && + steps.stream().noneMatch(step -> step.concerns(Environment.staging))) { steps.add(new DeploymentSpec.DeclaredZone(Environment.staging)); } // Add test if required and missing - if (steps.stream().anyMatch(step -> step.deploysTo(Environment.staging)) && - steps.stream().noneMatch(step -> step.deploysTo(Environment.test))) { + if (steps.stream().anyMatch(step -> step.concerns(Environment.staging)) && + steps.stream().noneMatch(step -> step.concerns(Environment.test))) { steps.add(new DeploymentSpec.DeclaredZone(Environment.test)); } @@ -162,13 +164,6 @@ public class DeploymentSpec { // to have environment, instance or region variants on those. public Optional<AthenzService> athenzService() { return this.athenzService; } - // TODO remove when 7.135 is the oldest version - public Optional<AthenzService> athenzService(InstanceName instanceName, Environment environment, RegionName region) { - Optional<DeploymentInstanceSpec> instance = instance(instanceName); - if (instance.isEmpty()) return this.athenzService; - return instance.get().athenzService(environment, region).or(() -> this.athenzService); - } - /** Returns the XML form of this spec, or null if it was not created by fromXml, nor is empty */ public String xmlForm() { return xmlForm; } @@ -205,11 +200,15 @@ public class DeploymentSpec { private static List<DeploymentInstanceSpec> instances(List<DeploymentSpec.Step> steps) { return steps.stream() - .flatMap(step -> step instanceof ParallelZones ? ((ParallelZones) step).steps.stream() : List.of(step).stream()) - .filter(step -> step instanceof DeploymentInstanceSpec).map(DeploymentInstanceSpec.class::cast) + .flatMap(DeploymentSpec::flatten) .collect(Collectors.toList()); } + private static Stream<DeploymentInstanceSpec> flatten(Step step) { + if (step instanceof DeploymentInstanceSpec) return Stream.of((DeploymentInstanceSpec) step); + return step.steps().stream().flatMap(DeploymentSpec::flatten); + } + /** * Creates a deployment spec from XML. * @@ -272,23 +271,31 @@ public class DeploymentSpec { /** A deployment step */ public abstract static class Step { - /** Returns whether this step deploys to the given region */ - public final boolean deploysTo(Environment environment) { - return deploysTo(environment, Optional.empty()); + /** Returns whether this step specifies the given environment. */ + public final boolean concerns(Environment environment) { + return concerns(environment, Optional.empty()); } - /** Returns whether this step deploys to the given environment, and (if specified) region */ - public abstract boolean deploysTo(Environment environment, Optional<RegionName> region); + /** Returns whether this step specifies the given environment, and, optionally, region. */ + public abstract boolean concerns(Environment environment, Optional<RegionName> region); - /** Returns the zones deployed to in this step */ + /** Returns the zones deployed to in this step. */ public List<DeclaredZone> zones() { return Collections.emptyList(); } - /** The delay introduced by this step (beyond the time it takes to execute the step). Default is zero. */ + /** The delay introduced by this step (beyond the time it takes to execute the step). */ public Duration delay() { return Duration.ZERO; } - /** Returns all the steps nested in this. This default implementatiino returns an empty list. */ + /** Returns any steps nested in this. */ public List<Step> steps() { return List.of(); } + /** Returns whether this step is a test step. */ + public boolean isTest() { return false; } + + /** Returns whether the nested steps in this, if any, should be performed in declaration order. */ + public boolean isOrdered() { + return true; + } + } /** A deployment step which is to wait for some time before progressing to the next step */ @@ -304,7 +311,7 @@ public class DeploymentSpec { public Duration delay() { return duration; } @Override - public boolean deploysTo(Environment environment, Optional<RegionName> region) { return false; } + public boolean concerns(Environment environment, Optional<RegionName> region) { return false; } @Override public String toString() { @@ -355,13 +362,16 @@ public class DeploymentSpec { public List<DeclaredZone> zones() { return Collections.singletonList(this); } @Override - public boolean deploysTo(Environment environment, Optional<RegionName> region) { + public boolean concerns(Environment environment, Optional<RegionName> region) { if (environment != this.environment) return false; if (region.isPresent() && ! region.equals(this.region)) return false; return true; } @Override + public boolean isTest() { return environment.isTest(); } + + @Override public int hashCode() { return Objects.hash(environment, region); } @@ -383,39 +393,82 @@ public class DeploymentSpec { } - /** A deployment step which is to run multiple steps (zones or instances) in parallel */ - public static class ParallelZones extends Step { + /** A declared production test */ + public static class DeclaredTest extends Step { + + private final RegionName region; + + public DeclaredTest(RegionName region) { + this.region = Objects.requireNonNull(region); + } + + @Override + public boolean concerns(Environment environment, Optional<RegionName> region) { + return region.map(this.region::equals).orElse(true) && environment == Environment.prod; + } + + @Override + public boolean isTest() { return true; } + + /** Returns the region this test is for. */ + public RegionName region() { + return region; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DeclaredTest that = (DeclaredTest) o; + return region.equals(that.region); + } + + @Override + public int hashCode() { + return Objects.hash(region); + } + + @Override + public String toString() { + return "tests for prod." + region; + } + + } + + /** A container for several steps, by default in serial order */ + public static class Steps extends Step { private final List<Step> steps; - public ParallelZones(List<Step> steps) { + public Steps(List<Step> steps) { this.steps = List.copyOf(steps); } - /** Returns the steps inside this which are zones */ @Override public List<DeclaredZone> zones() { - return this.steps.stream() - .filter(step -> step instanceof DeclaredZone) - .map(DeclaredZone.class::cast) - .collect(Collectors.toList()); + return steps.stream() + .flatMap(step -> step.zones().stream()) + .collect(Collectors.toUnmodifiableList()); } - /** Returns all the steps nested in this */ @Override public List<Step> steps() { return steps; } @Override - public boolean deploysTo(Environment environment, Optional<RegionName> region) { - return steps().stream().anyMatch(zone -> zone.deploysTo(environment, region)); + public boolean concerns(Environment environment, Optional<RegionName> region) { + return steps.stream().anyMatch(step -> step.concerns(environment, region)); + } + + @Override + public Duration delay() { + return steps.stream().map(Step::delay).reduce(Duration.ZERO, Duration::plus); } @Override public boolean equals(Object o) { if (this == o) return true; - if (!(o instanceof ParallelZones)) return false; - ParallelZones that = (ParallelZones) o; - return Objects.equals(steps, that.steps); + if (o == null || getClass() != o.getClass()) return false; + return steps.equals(((Steps) o).steps); } @Override @@ -425,7 +478,43 @@ public class DeploymentSpec { @Override public String toString() { - return steps.size() + " parallel steps"; + return steps.size() + " steps"; + } + + } + + /** A container for multiple other steps, which are executed in parallel */ + public static class ParallelSteps extends Steps { + + public ParallelSteps(List<Step> steps) { + super(steps); + } + + @Override + public Duration delay() { + return steps().stream().map(Step::delay).max(Comparator.naturalOrder()).orElse(Duration.ZERO); + } + + @Override + public boolean isOrdered() { + return false; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if ( ! (o instanceof ParallelSteps)) return false; + return Objects.equals(steps(), ((ParallelSteps) o).steps()); + } + + @Override + public int hashCode() { + return Objects.hash(steps()); + } + + @Override + public String toString() { + return steps().size() + " parallel steps"; } } |