diff options
author | Morten Tokle <mortent@oath.com> | 2017-11-20 14:12:53 +0100 |
---|---|---|
committer | Morten Tokle <mortent@oath.com> | 2017-11-21 14:04:51 +0100 |
commit | 28f6fb192d3ba9d019fa9265b2770cc4325d5240 (patch) | |
tree | 5a39cb23602499ece36cb240b443f59e28aa8ed9 /config-model-api | |
parent | ef6ad29be045374dbd5a885d036fe12a95c5dc9c (diff) |
Move identity configuration services.xml -> deployment.xml
Diffstat (limited to 'config-model-api')
3 files changed, 125 insertions, 9 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 4d370ba5039..1a2335c82db 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 @@ -39,28 +39,36 @@ public class DeploymentSpec { UpgradePolicy.defaultPolicy, Collections.emptyList(), Collections.emptyList(), - "<deployment version='1.0'/>"); + "<deployment version='1.0'/>", + Optional.empty(), + Optional.empty()); private final Optional<String> globalServiceId; private final UpgradePolicy upgradePolicy; private final List<ChangeBlocker> changeBlockers; private final List<Step> steps; private final String xmlForm; + private final Optional<String> athenzDomain; + private final Optional<String> athenzService; public DeploymentSpec(Optional<String> globalServiceId, UpgradePolicy upgradePolicy, List<ChangeBlocker> changeBlockers, List<Step> steps) { - this(globalServiceId, upgradePolicy, changeBlockers, steps, null); + this(globalServiceId, upgradePolicy, changeBlockers, steps, null, Optional.empty(), Optional.empty()); } public DeploymentSpec(Optional<String> globalServiceId, UpgradePolicy upgradePolicy, - List<ChangeBlocker> changeBlockers, List<Step> steps, String xmlForm) { + List<ChangeBlocker> changeBlockers, List<Step> steps, String xmlForm, + Optional<String> athenzDomain, Optional<String> athenzService) { validateTotalDelay(steps); this.globalServiceId = globalServiceId; this.upgradePolicy = upgradePolicy; this.changeBlockers = changeBlockers; this.steps = ImmutableList.copyOf(completeSteps(new ArrayList<>(steps))); this.xmlForm = xmlForm; + this.athenzDomain = athenzDomain; + this.athenzService = athenzService; validateZones(this.steps); + validateAthenz(); } /** Throw an IllegalArgumentException if the total delay exceeds 24 hours */ @@ -81,7 +89,30 @@ public class DeploymentSpec { for (DeclaredZone zone : step.zones()) ensureUnique(zone, zones); } - + + /* + * Throw an IllegalArgumentException if Athenz configuration violates: + * domain not configured -> no zone can configure service + * domain configured -> all zones must configure service + */ + 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 configured, 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 void ensureUnique(DeclaredZone zone, Set<DeclaredZone> zones) { if ( ! zones.add(zone)) throw new IllegalArgumentException(zone + " is listed twice in deployment.xml"); @@ -212,6 +243,20 @@ public class DeploymentSpec { return b.toString(); } + /** Returns the athenz domain if configured */ + public Optional<String> athenzDomain() { + return athenzDomain; + } + + /** Returns the athenz service for environment/region if configured */ + public Optional<String> athenzService(Environment environment, RegionName region) { + return zones().stream() + .filter(zone -> zone.deploysTo(environment, Optional.of(region))) + .findFirst() + .map(DeclaredZone::athenzService) + .orElse(athenzService); + } + /** This may be invoked by a continuous build */ public static void main(String[] args) { if (args.length != 2 && args.length != 3) { @@ -276,11 +321,17 @@ public class DeploymentSpec { private final boolean active; + private Optional<String> athenzService; + public DeclaredZone(Environment environment) { this(environment, Optional.empty(), false); } public DeclaredZone(Environment environment, Optional<RegionName> region, boolean active) { + this(environment, region, active, Optional.empty()); + } + + public DeclaredZone(Environment environment, Optional<RegionName> region, boolean active, Optional<String> athenzService) { if (environment != Environment.prod && region.isPresent()) throw new IllegalArgumentException("Non-prod environments cannot specify a region"); if (environment == Environment.prod && ! region.isPresent()) @@ -288,6 +339,7 @@ public class DeploymentSpec { this.environment = environment; this.region = region; this.active = active; + this.athenzService = athenzService; } public Environment environment() { return environment; } @@ -298,6 +350,8 @@ public class DeploymentSpec { /** Returns whether this zone should receive production traffic */ public boolean active() { return active; } + public Optional<String> athenzService() { return athenzService; } + @Override public List<DeclaredZone> zones() { return Collections.singletonList(this); } diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/xml/DeploymentSpecXmlReader.java b/config-model-api/src/main/java/com/yahoo/config/application/api/xml/DeploymentSpecXmlReader.java index 5599b257b16..1a970e53713 100644 --- a/config-model-api/src/main/java/com/yahoo/config/application/api/xml/DeploymentSpecXmlReader.java +++ b/config-model-api/src/main/java/com/yahoo/config/application/api/xml/DeploymentSpecXmlReader.java @@ -72,6 +72,7 @@ public class DeploymentSpecXmlReader { if (environment == Environment.prod) { for (Element stepTag : XML.getChildren(environmentTag)) { + Optional<String> athenzService = stringAttribute("athenz-service", environmentTag); if (stepTag.getTagName().equals("delay")) { steps.add(new Delay(Duration.ofSeconds(longAttribute("hours", stepTag) * 60 * 60 + longAttribute("minutes", stepTag) * 60 + @@ -79,11 +80,11 @@ public class DeploymentSpecXmlReader { } else if (stepTag.getTagName().equals("parallel")) { List<DeclaredZone> zones = new ArrayList<>(); for (Element regionTag : XML.getChildren(stepTag)) { - zones.add(readDeclaredZone(environment, regionTag)); + zones.add(readDeclaredZone(environment, athenzService, regionTag)); } steps.add(new ParallelZones(zones)); } else { // a region: deploy step - steps.add(readDeclaredZone(environment, stepTag)); + steps.add(readDeclaredZone(environment, athenzService, stepTag)); } } } else { @@ -94,8 +95,11 @@ public class DeploymentSpecXmlReader { globalServiceId = readGlobalServiceId(environmentTag); else if (readGlobalServiceId(environmentTag).isPresent()) throw new IllegalArgumentException("Attribute 'global-service-id' is only valid on 'prod' tag."); + } - return new DeploymentSpec(globalServiceId, readUpgradePolicy(root), readChangeBlockers(root), steps, xmlForm); + Optional<String> athenzDomain = stringAttribute("athenz-domain", root); + Optional<String> athenzService = stringAttribute("athenz-service", root); + return new DeploymentSpec(globalServiceId, readUpgradePolicy(root), readChangeBlockers(root), steps, xmlForm, athenzDomain, athenzService); } /** Imposes some constraints on tag order which are not expressible in the schema */ @@ -132,13 +136,19 @@ public class DeploymentSpecXmlReader { } } + /** Returns the given attribute as a string, or Optional.empty if it is not present or empty */ + private Optional<String> stringAttribute(String attributeName, Element tag) { + String value = tag.getAttribute(attributeName); + return Optional.ofNullable(value).filter(s -> ! s.equals("")); + } + private boolean isEnvironmentName(String tagName) { return tagName.equals(testTag) || tagName.equals(stagingTag) || tagName.equals(prodTag); } - private DeclaredZone readDeclaredZone(Environment environment, Element regionTag) { + private DeclaredZone readDeclaredZone(Environment environment, Optional<String> athenzService, Element regionTag) { return new DeclaredZone(environment, Optional.of(RegionName.from(XML.getValue(regionTag).trim())), - readActive(regionTag)); + readActive(regionTag), athenzService); } private Optional<String> readGlobalServiceId(Element environmentTag) { diff --git a/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java b/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java index 5050f88af31..5dcb3bc1ebe 100644 --- a/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java +++ b/config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java @@ -367,4 +367,56 @@ public class DeploymentSpecTest { assertTrue(spec.canUpgradeAt(Instant.parse("2017-09-23T10:15:30.00Z"))); } + @Test + public void deploymentSpecWithAthenzIdentity() { + StringReader r = new StringReader( + "<deployment athenz-domain='domain' athenz-service='service'>\n" + + " <prod>\n" + + " <region active='true'>us-west-1</region>\n" + + " </prod>\n" + + "</deployment>" + ); + DeploymentSpec spec = DeploymentSpec.fromXml(r); + assertEquals(spec.athenzDomain().get(), "domain"); + assertEquals(spec.athenzService(Environment.prod, RegionName.from("us-west-1")).get(), "service"); + } + + @Test + public void deploymentSpecUsesServiceFromEnvironment() { + StringReader r = new StringReader( + "<deployment athenz-domain='domain' athenz-service='service'>\n" + + " <test/>\n" + + " <prod athenz-service='prod-service'>\n" + + " <region active='true'>us-west-1</region>\n" + + " </prod>\n" + + "</deployment>" + ); + DeploymentSpec spec = DeploymentSpec.fromXml(r); + assertEquals(spec.athenzDomain().get(), "domain"); + assertEquals(spec.athenzService(Environment.prod, RegionName.from("us-west-1")).get(), "prodservice"); + } + + @Test(expected = IllegalArgumentException.class) + public void athenzDomainMissingService() { + StringReader r = new StringReader( + "<deployment athenz-domain='domain'>\n" + + " <prod>\n" + + " <region active='true'>us-west-1</region>\n" + + " </prod>\n" + + "</deployment>" + ); + DeploymentSpec spec = DeploymentSpec.fromXml(r); + } + + @Test(expected = IllegalArgumentException.class) + public void athenzDomainMissingDomain() { + StringReader r = new StringReader( + "<deployment>\n" + + " <prod athenz-service='service'>\n" + + " <region active='true'>us-west-1</region>\n" + + " </prod>\n" + + "</deployment>" + ); + DeploymentSpec spec = DeploymentSpec.fromXml(r); + } } |