/** This may be invoked by a continuous build */ public static void main(String[] args) { if (args.length != 2 && args.length != 3) { System.err.println("Usage: DeploymentSpec [file] [environment] [region]?" + "Returns 0 if the specified zone matches the deployment spec, 1 otherwise"); System.exit(1); } try (BufferedReader reader = new BufferedReader(new FileReader(args[0]))) { DeploymentSpec spec = DeploymentSpec.fromXml(reader); Environment environment = Environment.from(args[1]); Optional<RegionName> region = args.length == 3 ? Optional.of(RegionName.from(args[2])) : Optional.empty(); if (spec.includes(environment, region)) System.exit(0); else System.exit(1); } catch (Exception e) { System.err.println("Exception checking deployment spec: " + toMessageString(e)); System.exit(1); } }
/** Returns the athenz service for environment/region if configured */ public Optional<AthenzService> athenzService(Environment environment, RegionName region) { AthenzService athenzService = zones().stream() .filter(zone -> zone.deploysTo(environment, Optional.of(region))) .findFirst() .flatMap(DeclaredZone::athenzService) .orElse(this.athenzService.orElse(null)); return Optional.ofNullable(athenzService); }
public DeploymentSpec(Optional<String> globalServiceId, UpgradePolicy upgradePolicy, Optional<Integer> majorVersion, List<ChangeBlocker> changeBlockers, List<Step> steps, String xmlForm, Optional<AthenzDomain> athenzDomain, Optional<AthenzService> athenzService, Notifications notifications) { validateTotalDelay(steps); this.globalServiceId = globalServiceId; this.upgradePolicy = upgradePolicy; this.majorVersion = majorVersion; this.changeBlockers = changeBlockers; this.steps = ImmutableList.copyOf(completeSteps(new ArrayList<>(steps))); this.xmlForm = xmlForm; this.athenzDomain = athenzDomain; this.athenzService = athenzService; this.notifications = notifications; validateZones(this.steps); validateAthenz(); }
@Override public void validate(VespaModel model, DeployState deployState) { Optional<Reader> deployment = deployState.getApplicationPackage().getDeployment(); if (deployment.isPresent()) { Reader deploymentReader = deployment.get(); DeploymentSpec deploymentSpec = DeploymentSpec.fromXml(deploymentReader); final Optional<String> globalServiceId = deploymentSpec.globalServiceId(); if (globalServiceId.isPresent()) { Set<ContainerCluster> containerClusters = model.getRoot().configModelRepo().getModels(ContainerModel.class).stream(). map(ContainerModel::getCluster).filter(cc -> cc.getName().equals(globalServiceId.get())).collect(Collectors.toSet()); if (containerClusters.size() != 1) { throw new IllegalArgumentException("global-service-id '" + globalServiceId.get() + "' specified in deployment.xml does not match any container cluster id"); } } } } }
/** * Creates a deployment spec from XML. * * @throws IllegalArgumentException if the XML is invalid */ public static DeploymentSpec fromXml(String xmlForm) { return fromXml(xmlForm, true); }
private void addIdentityProvider(ContainerCluster cluster, List<ConfigServerSpec> configServerSpecs, HostName loadBalancerName, URI ztsUrl, String athenzDnsSuffix, Zone zone, DeploymentSpec spec) { spec.athenzDomain().ifPresent(domain -> { AthenzService service = spec.athenzService(zone.environment(), zone.region()) .orElseThrow(() -> new RuntimeException("Missing Athenz service configuration")); String zoneDnsSuffix = zone.environment().value() + "-" + zone.region().value() + "." + athenzDnsSuffix; IdentityProvider identityProvider = new IdentityProvider(domain, service, getLoadBalancerName(loadBalancerName, configServerSpecs), ztsUrl, zoneDnsSuffix, zone); cluster.addComponent(identityProvider); cluster.getContainers().forEach(container -> { container.setProp("identity.domain", domain.value()); container.setProp("identity.service", service.value()); }); }); }
/** Throw an IllegalArgumentException if any production zone is declared multiple times */ private void validateZones(List<Step> steps) { Set<DeclaredZone> zones = new HashSet<>(); for (Step step : steps) for (DeclaredZone zone : step.zones()) ensureUnique(zone, zones); }
/** Adds missing required steps and reorders steps to a permissible order */ private static List<Step> completeSteps(List<Step> steps) { // Add staging if required and missing if (steps.stream().anyMatch(step -> step.deploysTo(Environment.prod)) && steps.stream().noneMatch(step -> step.deploysTo(Environment.staging))) { steps.add(new 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))) { steps.add(new DeclaredZone(Environment.test)); } // Enforce order test, staging, prod DeclaredZone testStep = remove(Environment.test, steps); if (testStep != null) steps.add(0, testStep); DeclaredZone stagingStep = remove(Environment.staging, steps); if (stagingStep != null) steps.add(1, stagingStep); return steps; }
private void addRotationProperties(ContainerCluster cluster, Zone zone, Set<Rotation> rotations, DeploymentSpec spec) { cluster.getContainers().forEach(container -> { setRotations(container, rotations, spec.globalServiceId(), cluster.getName()); container.setProp("activeRotation", Boolean.toString(zoneHasActiveRotation(zone, spec))); }); }
return new DeploymentSpec(globalServiceId, readUpgradePolicy(root), optionalIntegerAttribute(majorVersionTag, root),
private void validateAthenz() { // If athenz domain is not set, athenz service cannot be set on any level if (! athenzDomain.isPresent()) { for (DeclaredZone zone : zones()) { if(zone.athenzService().isPresent()) { throw new IllegalArgumentException("Athenz service configured for zone: " + zone + ", but Athenz domain is not configured"); } } // if athenz domain is not set, athenz service must be set implicitly or directly on all zones. } else if(! athenzService.isPresent()) { for (DeclaredZone zone : zones()) { if(! zone.athenzService().isPresent()) { throw new IllegalArgumentException("Athenz domain is configured, but Athenz service not configured for zone: " + zone); } } } }
private boolean zoneHasActiveRotation(Zone zone, DeploymentSpec spec) { return spec.zones().stream() .anyMatch(declaredZone -> declaredZone.deploysTo(zone.environment(), Optional.of(zone.region())) && declaredZone.active()); }