diff options
20 files changed, 246 insertions, 200 deletions
diff --git a/config-model-api/abi-spec.json b/config-model-api/abi-spec.json index aeb1d28b824..4635070fee8 100644 --- a/config-model-api/abi-spec.json +++ b/config-model-api/abi-spec.json @@ -194,10 +194,11 @@ "public" ], "methods": [ - "public void <init>(com.yahoo.config.provision.InstanceName, java.util.List, com.yahoo.config.application.api.DeploymentSpec$UpgradePolicy, com.yahoo.config.application.api.DeploymentSpec$UpgradeRevision, com.yahoo.config.application.api.DeploymentSpec$UpgradeRollout, java.util.List, java.util.Optional, java.util.Optional, com.yahoo.config.application.api.Notifications, java.util.List, java.time.Instant)", + "public void <init>(com.yahoo.config.provision.InstanceName, java.util.List, com.yahoo.config.application.api.DeploymentSpec$UpgradePolicy, com.yahoo.config.application.api.DeploymentSpec$RevisionTarget, com.yahoo.config.application.api.DeploymentSpec$RevisionChange, com.yahoo.config.application.api.DeploymentSpec$UpgradeRollout, java.util.List, java.util.Optional, java.util.Optional, com.yahoo.config.application.api.Notifications, java.util.List, java.time.Instant)", "public com.yahoo.config.provision.InstanceName name()", "public com.yahoo.config.application.api.DeploymentSpec$UpgradePolicy upgradePolicy()", - "public com.yahoo.config.application.api.DeploymentSpec$UpgradeRevision upgradeRevision()", + "public com.yahoo.config.application.api.DeploymentSpec$RevisionTarget revisionTarget()", + "public com.yahoo.config.application.api.DeploymentSpec$RevisionChange revisionChange()", "public com.yahoo.config.application.api.DeploymentSpec$UpgradeRollout upgradeRollout()", "public java.util.List changeBlocker()", "public java.util.Optional globalServiceId()", @@ -311,6 +312,41 @@ ], "fields": [] }, + "com.yahoo.config.application.api.DeploymentSpec$RevisionChange": { + "superClass": "java.lang.Enum", + "interfaces": [], + "attributes": [ + "public", + "final", + "enum" + ], + "methods": [ + "public static com.yahoo.config.application.api.DeploymentSpec$RevisionChange[] values()", + "public static com.yahoo.config.application.api.DeploymentSpec$RevisionChange valueOf(java.lang.String)" + ], + "fields": [ + "public static final enum com.yahoo.config.application.api.DeploymentSpec$RevisionChange whenClear", + "public static final enum com.yahoo.config.application.api.DeploymentSpec$RevisionChange whenFailing", + "public static final enum com.yahoo.config.application.api.DeploymentSpec$RevisionChange always" + ] + }, + "com.yahoo.config.application.api.DeploymentSpec$RevisionTarget": { + "superClass": "java.lang.Enum", + "interfaces": [], + "attributes": [ + "public", + "final", + "enum" + ], + "methods": [ + "public static com.yahoo.config.application.api.DeploymentSpec$RevisionTarget[] values()", + "public static com.yahoo.config.application.api.DeploymentSpec$RevisionTarget valueOf(java.lang.String)" + ], + "fields": [ + "public static final enum com.yahoo.config.application.api.DeploymentSpec$RevisionTarget next", + "public static final enum com.yahoo.config.application.api.DeploymentSpec$RevisionTarget latest" + ] + }, "com.yahoo.config.application.api.DeploymentSpec$Step": { "superClass": "java.lang.Object", "interfaces": [], @@ -366,24 +402,6 @@ "public static final enum com.yahoo.config.application.api.DeploymentSpec$UpgradePolicy conservative" ] }, - "com.yahoo.config.application.api.DeploymentSpec$UpgradeRevision": { - "superClass": "java.lang.Enum", - "interfaces": [], - "attributes": [ - "public", - "final", - "enum" - ], - "methods": [ - "public static com.yahoo.config.application.api.DeploymentSpec$UpgradeRevision[] values()", - "public static com.yahoo.config.application.api.DeploymentSpec$UpgradeRevision valueOf(java.lang.String)" - ], - "fields": [ - "public static final enum com.yahoo.config.application.api.DeploymentSpec$UpgradeRevision exclusive", - "public static final enum com.yahoo.config.application.api.DeploymentSpec$UpgradeRevision separate", - "public static final enum com.yahoo.config.application.api.DeploymentSpec$UpgradeRevision latest" - ] - }, "com.yahoo.config.application.api.DeploymentSpec$UpgradeRollout": { "superClass": "java.lang.Enum", "interfaces": [], diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentInstanceSpec.java b/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentInstanceSpec.java index ea38860c29b..e701f3903cb 100644 --- a/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentInstanceSpec.java +++ b/config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentInstanceSpec.java @@ -31,7 +31,8 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps { private final InstanceName name; private final DeploymentSpec.UpgradePolicy upgradePolicy; - private final DeploymentSpec.UpgradeRevision upgradeRevision; + private final DeploymentSpec.RevisionTarget revisionTarget; + private final DeploymentSpec.RevisionChange revisionChange; private final DeploymentSpec.UpgradeRollout upgradeRollout; private final List<DeploymentSpec.ChangeBlocker> changeBlockers; private final Optional<String> globalServiceId; @@ -42,7 +43,8 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps { public DeploymentInstanceSpec(InstanceName name, List<DeploymentSpec.Step> steps, DeploymentSpec.UpgradePolicy upgradePolicy, - DeploymentSpec.UpgradeRevision upgradeRevision, + DeploymentSpec.RevisionTarget revisionTarget, + DeploymentSpec.RevisionChange revisionChange, DeploymentSpec.UpgradeRollout upgradeRollout, List<DeploymentSpec.ChangeBlocker> changeBlockers, Optional<String> globalServiceId, @@ -53,7 +55,8 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps { super(steps); this.name = name; this.upgradePolicy = upgradePolicy; - this.upgradeRevision = upgradeRevision; + this.revisionTarget = revisionTarget; + this.revisionChange = revisionChange; this.upgradeRollout = upgradeRollout; this.changeBlockers = changeBlockers; this.globalServiceId = globalServiceId; @@ -150,13 +153,16 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps { return true; } - /** Returns the upgrade policy of this, which is defaultPolicy if none is specified */ + /** Returns the upgrade policy of this, which is {@link DeploymentSpec.UpgradePolicy#defaultPolicy} by default */ public DeploymentSpec.UpgradePolicy upgradePolicy() { return upgradePolicy; } - /** Returns the upgrade revision strategy of this, which is separate if none is specified */ - public DeploymentSpec.UpgradeRevision upgradeRevision() { return upgradeRevision; } + /** Returns the revision target choice of this, which is {@link DeploymentSpec.RevisionTarget#latest} by default */ + public DeploymentSpec.RevisionTarget revisionTarget() { return revisionTarget; } - /** Returns the upgrade rollout strategy of this, which is separate if none is specified */ + /** Returns the revision change strategy of this, which is {@link DeploymentSpec.RevisionChange#whenFailing} by default */ + public DeploymentSpec.RevisionChange revisionChange() { return revisionChange; } + + /** Returns the upgrade rollout strategy of this, which is {@link DeploymentSpec.UpgradeRollout#separate} by default */ public DeploymentSpec.UpgradeRollout upgradeRollout() { return upgradeRollout; } /** Returns time windows where upgrades are disallowed for these instances */ @@ -204,7 +210,7 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps { DeploymentInstanceSpec other = (DeploymentInstanceSpec) o; return globalServiceId.equals(other.globalServiceId) && upgradePolicy == other.upgradePolicy && - upgradeRevision == other.upgradeRevision && + revisionTarget == other.revisionTarget && upgradeRollout == other.upgradeRollout && changeBlockers.equals(other.changeBlockers) && steps().equals(other.steps()) && @@ -215,7 +221,7 @@ public class DeploymentInstanceSpec extends DeploymentSpec.Steps { @Override public int hashCode() { - return Objects.hash(globalServiceId, upgradePolicy, upgradeRevision, upgradeRollout, changeBlockers, steps(), athenzService, notifications, endpoints); + return Objects.hash(globalServiceId, upgradePolicy, revisionTarget, upgradeRollout, changeBlockers, steps(), athenzService, notifications, endpoints); } @Override 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 3a66fb0c1a5..96e3ba75a38 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 @@ -550,14 +550,23 @@ public class DeploymentSpec { } - /** Determines when application changes deploy, when an older revision is already rolling out. */ - public enum UpgradeRevision { - /** Exclusive: Application changes are rolled one at a time through this instance, even when they fail. */ - exclusive, + /** Determines what application changes to deploy to the instance. */ + public enum RevisionTarget { + /** Next: Application changes are rolled through this instance in the same manner as they become ready. */ + next, + /** Latest: Application changes are merged, so the latest available is always chosen for roll-out. */ + latest + } + + + /** Determines when application changes deploy. */ + public enum RevisionChange { + /** Exclusive: Application changes always wait for already rolling application changes to complete. */ + whenClear, /** Separate: Application changes wait for already rolling application changes to complete, unless they fail. */ - separate, + whenFailing, /** Latest: Application changes immediately supersede previous application changes, unless currently blocked. */ - latest + always } 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 fdd7733a5f6..050fba1cd2f 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 @@ -165,7 +165,8 @@ public class DeploymentSpecXmlReader { // Values where the parent may provide a default DeploymentSpec.UpgradePolicy upgradePolicy = readUpgradePolicy(instanceTag, parentTag); - DeploymentSpec.UpgradeRevision upgradeRevision = readUpgradeRevision(instanceTag, parentTag); + DeploymentSpec.RevisionTarget revisionTarget = readRevisionTarget(instanceTag, parentTag); + DeploymentSpec.RevisionChange revisionChange = readRevisionChange(instanceTag, parentTag); DeploymentSpec.UpgradeRollout upgradeRollout = readUpgradeRollout(instanceTag, parentTag); List<DeploymentSpec.ChangeBlocker> changeBlockers = readChangeBlockers(instanceTag, parentTag); Optional<AthenzService> athenzService = mostSpecificAttribute(instanceTag, athenzServiceAttribute).map(AthenzService::from); @@ -184,7 +185,8 @@ public class DeploymentSpecXmlReader { .map(name -> new DeploymentInstanceSpec(InstanceName.from(name), steps, upgradePolicy, - upgradeRevision, + revisionTarget, + revisionChange, upgradeRollout, changeBlockers, globalServiceId.asOptional(), @@ -474,23 +476,42 @@ public class DeploymentSpecXmlReader { } } - private DeploymentSpec.UpgradeRevision readUpgradeRevision(Element parent, Element fallbackParent) { + private DeploymentSpec.RevisionChange readRevisionChange(Element parent, Element fallbackParent) { Element upgradeElement = XML.getChild(parent, upgradeTag); if (upgradeElement == null) upgradeElement = XML.getChild(fallbackParent, upgradeTag); if (upgradeElement == null) - return DeploymentSpec.UpgradeRevision.separate; + return DeploymentSpec.RevisionChange.whenFailing; - String revision = upgradeElement.getAttribute("revision"); + String revision = upgradeElement.getAttribute("revision-change"); if (revision.isEmpty()) - return DeploymentSpec.UpgradeRevision.separate; + return DeploymentSpec.RevisionChange.whenFailing; switch (revision) { - case "exclusive": return DeploymentSpec.UpgradeRevision.exclusive; - case "separate": return DeploymentSpec.UpgradeRevision.separate; - case "latest": return DeploymentSpec.UpgradeRevision.latest; - default: throw new IllegalArgumentException("Illegal upgrade revision '" + revision + "': " + - "Must be one of " + Arrays.toString(DeploymentSpec.UpgradeRevision.values())); + case "when-clear": return DeploymentSpec.RevisionChange.whenClear; + case "when-failing": return DeploymentSpec.RevisionChange.whenFailing; + case "always": return DeploymentSpec.RevisionChange.always; + default: throw new IllegalArgumentException("Illegal upgrade revision change policy '" + revision + "': " + + "Must be one of " + Arrays.toString(DeploymentSpec.RevisionTarget.values())); + } + } + + private DeploymentSpec.RevisionTarget readRevisionTarget(Element parent, Element fallbackParent) { + Element upgradeElement = XML.getChild(parent, upgradeTag); + if (upgradeElement == null) + upgradeElement = XML.getChild(fallbackParent, upgradeTag); + if (upgradeElement == null) + return DeploymentSpec.RevisionTarget.latest; + + String revision = upgradeElement.getAttribute("revision-target"); + if (revision.isEmpty()) + return DeploymentSpec.RevisionTarget.latest; + + switch (revision) { + case "next": return DeploymentSpec.RevisionTarget.next; + case "latest": return DeploymentSpec.RevisionTarget.latest; + default: throw new IllegalArgumentException("Illegal upgrade revision target '" + revision + "': " + + "Must be one of " + Arrays.toString(DeploymentSpec.RevisionTarget.values())); } } 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 f6af155ffc2..86a2ede85ab 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 @@ -121,7 +121,8 @@ public class DeploymentSpecTest { assertFalse(spec.requireInstance("default").globalServiceId().isPresent()); assertEquals(DeploymentSpec.UpgradePolicy.defaultPolicy, spec.requireInstance("default").upgradePolicy()); - assertEquals(DeploymentSpec.UpgradeRevision.separate, spec.requireInstance("default").upgradeRevision()); + assertEquals(DeploymentSpec.RevisionTarget.latest, spec.requireInstance("default").revisionTarget()); + assertEquals(DeploymentSpec.RevisionChange.whenFailing, spec.requireInstance("default").revisionChange()); assertEquals(DeploymentSpec.UpgradeRollout.separate, spec.requireInstance("default").upgradeRollout()); } @@ -365,18 +366,22 @@ public class DeploymentSpecTest { } @Test - public void productionSpecWithUpgradeRevision() { + public void productionSpecWithUpgradeRevisionSettings() { StringReader r = new StringReader( "<deployment>" + " <instance id='default'>" + - " <upgrade revision='latest' />" + + " <upgrade revision-change='when-clear' revision-target='next' />" + + " </instance>" + + " <instance id='custom'>" + + " <upgrade revision-change='always' />" + " </instance>" + - " <instance id='custom'/>" + "</deployment>" ); DeploymentSpec spec = DeploymentSpec.fromXml(r); - assertEquals("latest", spec.requireInstance("default").upgradeRevision().toString()); - assertEquals("separate", spec.requireInstance("custom").upgradeRevision().toString()); + assertEquals("next", spec.requireInstance("default").revisionTarget().toString()); + assertEquals("latest", spec.requireInstance("custom").revisionTarget().toString()); + assertEquals("whenClear", spec.requireInstance("default").revisionChange().toString()); + assertEquals("always", spec.requireInstance("custom").revisionChange().toString()); } @Test @@ -417,10 +422,10 @@ public class DeploymentSpecTest { public void upgradePolicyDefault() { StringReader r = new StringReader( "<deployment version='1.0'>" + - " <upgrade policy='canary' rollout='leading' revision='latest' />" + + " <upgrade policy='canary' rollout='leading' revision-target='next' revision-change='when-clear' />" + " <instance id='instance1'/>" + " <instance id='instance2'>" + - " <upgrade policy='conservative' rollout='separate' revision='separate'/>" + + " <upgrade policy='conservative' rollout='separate' revision-target='latest' revision-change='when-failing' />" + " </instance>" + "</deployment>" ); @@ -428,8 +433,10 @@ public class DeploymentSpecTest { DeploymentSpec spec = DeploymentSpec.fromXml(r); assertEquals("canary", spec.requireInstance("instance1").upgradePolicy().toString()); assertEquals("conservative", spec.requireInstance("instance2").upgradePolicy().toString()); - assertEquals("latest", spec.requireInstance("instance1").upgradeRevision().toString()); - assertEquals("separate", spec.requireInstance("instance2").upgradeRevision().toString()); + assertEquals("next", spec.requireInstance("instance1").revisionTarget().toString()); + assertEquals("latest", spec.requireInstance("instance2").revisionTarget().toString()); + assertEquals("whenClear", spec.requireInstance("instance1").revisionChange().toString()); + assertEquals("whenFailing", spec.requireInstance("instance2").revisionChange().toString()); assertEquals("leading", spec.requireInstance("instance1").upgradeRollout().toString()); assertEquals("separate", spec.requireInstance("instance2").upgradeRollout().toString()); } diff --git a/config-model/src/main/javacc/SDParser.jj b/config-model/src/main/javacc/SDParser.jj index 2ccb9a82bdf..f761aa6d066 100644 --- a/config-model/src/main/javacc/SDParser.jj +++ b/config-model/src/main/javacc/SDParser.jj @@ -433,9 +433,8 @@ Schema rootSchema() : * trailing newline tokens. * * @param schema the schema object to modify. - * @return Null. */ -Object rootSchemaItem(Schema schema) : { } +void rootSchemaItem(Schema schema) : { } { ( document(schema) | rawAsBase64(schema) @@ -451,7 +450,6 @@ Object rootSchemaItem(Schema schema) : { } | fieldSet(schema) | importField(schema) | onnxModel(schema) ) - { return null; } } /** @@ -472,12 +470,10 @@ Schema rootDocument() : * Consumes a single item from within a root document node. * * @param schema the schema object to modify. - * @return Null. */ -Object rootDocumentItem(Schema schema) : { } +void rootDocumentItem(Schema schema) : { } { ( namedDocument(schema) ) - { return null; } } /** @@ -533,9 +529,8 @@ void namedDocument(Schema schema) : * * @param document the document type to modify. * @param schema the schema object to add content to - * @return Null. */ -Object documentBody(SDDocumentType document, Schema schema) : +void documentBody(SDDocumentType document, Schema schema) : { } { @@ -545,7 +540,6 @@ Object documentBody(SDDocumentType document, Schema schema) : | bodycfg(document) | structInside(document, schema) | field(document, schema) ) - { return null; } } void rawAsBase64(Schema schema) : @@ -972,9 +966,8 @@ void structField(FieldOperationContainer field, Schema schema, SDDocumentType do * @param field the field being built * @param schema the schema object to add content to * @param document the owning document, or null if this is a search field - * @return Null */ -String fieldBody(SDField field, Schema schema, SDDocumentType document) : { } +void fieldBody(SDField field, Schema schema, SDDocumentType document) : { } { ( alias(field) | attribute(field) | @@ -998,7 +991,6 @@ String fieldBody(SDField field, Schema schema, SDDocumentType document) : { } summaryTo(field) | weight(field) | weightedset(field) ) - { return null; } } /** @@ -1008,9 +1000,8 @@ String fieldBody(SDField field, Schema schema, SDDocumentType document) : { } * @param field the field being built * @param schema the schema object to add content to * @param document the owning document, or null if this is a schema field - * @return Null */ -String structFieldBody(FieldOperationContainer field, Schema schema, SDDocumentType document) : { } +void structFieldBody(FieldOperationContainer field, Schema schema, SDDocumentType document) : { } { ( summaryInField(field) | indexing(field) | @@ -1019,19 +1010,16 @@ String structFieldBody(FieldOperationContainer field, Schema schema, SDDocumentT queryCommand(field) | structField(field, schema, document) | summaryTo(field) ) - { return null; } } /** * This rule consumes an indexing block of a field element. * * @param field The field to modify. - * @return Null. */ -Object indexing(FieldOperationContainer field) : { } +void indexing(FieldOperationContainer field) : { } { ( <INDEXING> ( (<COLON> indexingOperation(field, false)) | indexingOperation(field, true) ) ) - { return null; } } /** @@ -1090,9 +1078,8 @@ void weight(FieldOperationContainer field) : * This rule consumes a weighted set statement of a field element. * * @param field The field to modify. - * @return Null. */ -Object weightedset(FieldOperationContainer field) : +void weightedset(FieldOperationContainer field) : { WeightedSetOperation op = new WeightedSetOperation(); } @@ -1101,7 +1088,6 @@ Object weightedset(FieldOperationContainer field) : | (lbrace() (weightedsetBody(op) (<NL>)*)* <RBRACE>) ) { field.addOperation(op); - return null; } } @@ -1109,15 +1095,11 @@ Object weightedset(FieldOperationContainer field) : * This rule consumes one body item of a weighted set block. * * @param field The field to modify. - * @return Null. */ -Object weightedsetBody(WeightedSetOperation field) : { } +void weightedsetBody(WeightedSetOperation field) : { } { ( <CREATEIFNONEXISTENT> { field.setCreateIfNonExistent(true); } | <REMOVEIFZERO> { field.setRemoveIfZero(true); } ) - { - return null; - } } /** @@ -1144,9 +1126,8 @@ void rankType(FieldOperationContainer field) : * This rule consumes an attribute statement of a field element. * * @param field The field to modify. - * @return Null. */ -Object attribute(FieldOperationContainer field) : +void attribute(FieldOperationContainer field) : { String name = field.getName(); } @@ -1159,11 +1140,10 @@ Object attribute(FieldOperationContainer field) : | (lbrace() (attributeSetting(field, op, name) (<NL>)*)* <RBRACE>) ) { field.addOperation(op); - return null; } } -Object sorting(FieldOperationContainer field, String name) : +void sorting(FieldOperationContainer field, String name) : { SortingOperation op = new SortingOperation(name); } @@ -1173,11 +1153,10 @@ Object sorting(FieldOperationContainer field, String name) : | (lbrace() (sortingSetting(op, name) (<NL>)*)* <RBRACE>) ) { field.addOperation(op); - return null; } } -Object sortingSetting(SortingOperation sorting, String attributeName) : +void sortingSetting(SortingOperation sorting, String attributeName) : { String locale; } @@ -1199,7 +1178,6 @@ Object sortingSetting(SortingOperation sorting, String attributeName) : ) | <LOCALE> <COLON> locale = identifierWithDash() { sorting.setLocale(locale); } ) - { return null; } } /** @@ -1207,9 +1185,8 @@ Object sortingSetting(SortingOperation sorting, String attributeName) : * * @param field The field to modify. * @param attributeName The name of the attribute to change. - * @return Null. */ -Object attributeSetting(FieldOperationContainer field, AttributeOperation attribute, String attributeName) : +void attributeSetting(FieldOperationContainer field, AttributeOperation attribute, String attributeName) : { String str; } @@ -1231,16 +1208,14 @@ Object attributeSetting(FieldOperationContainer field, AttributeOperation attrib | attributeTensorType(attribute) | <DISTANCEMETRIC> <COLON> str = identifierWithDash() { attribute.setDistanceMetric(str); } ) - { return null; } } /** * This rule consumes a tensor type statement for an attribute element. * * @param attribute The attribute to modify. - * @return Null. */ -Object attributeTensorType(AttributeOperation attribute) : +void attributeTensorType(AttributeOperation attribute) : { TensorType tensorType; } @@ -1250,16 +1225,14 @@ Object attributeTensorType(AttributeOperation attribute) : // TODO: Remove on Vespa 8 deployLogger.logApplicationPackage(Level.WARNING, "In field '" + attribute.getName() + "': Specifying tensor type on the attribute is deprecated and has no effect."); } - { return null; } } /** * This rule consumes a summary statement defined inside a document-summary block. * * @param document The document summary to modify. - * @return Null. */ -Object summaryInDocument(DocumentSummary document) : +void summaryInDocument(DocumentSummary document) : { String name; DataType type; @@ -1282,7 +1255,6 @@ Object summaryInDocument(DocumentSummary document) : } op.applyToSummary(summary); document.add(summary); - return null; } } @@ -1290,9 +1262,8 @@ Object summaryInDocument(DocumentSummary document) : * The rule consumes a summary statement defined inside a field. * * @param field The field to modify. - * @return Null. */ -Object summaryInField(FieldOperationContainer field) : +void summaryInField(FieldOperationContainer field) : { SummaryInFieldOperation summary; } @@ -1301,7 +1272,6 @@ Object summaryInField(FieldOperationContainer field) : | summary = summaryInFieldLong(field)) ) { field.addOperation(summary); - return null; } } @@ -1354,30 +1324,26 @@ SummaryInFieldOperation summaryInFieldLong(FieldOperationContainer field) : * This rule consumes an item of a summary field block. * * @param field The field to modify. - * @return Null. */ -Object summaryItem(SummaryInFieldLongOperation field) : { } +void summaryItem(SummaryInFieldLongOperation field) : { } { ( summaryTransform(field) | summaryBolding(field) | summarySourceList(field) | summaryDestinationList(field) | summaryProperties(field) ) - { return null; } } /** * This rule consumes a transform statement for a summary field element. * * @param field The field to modify. - * @return Null. */ -Object summaryTransform(SummaryInFieldOperation field) : { } +void summaryTransform(SummaryInFieldOperation field) : { } { ( <DYNAMIC> { field.setTransform(SummaryTransform.DYNAMICTEASER); } | <MATCHEDELEMENTSONLY> { field.setTransform(SummaryTransform.MATCHED_ELEMENTS_FILTER); } | (<FULL> | <STATIC>) { field.setTransform(SummaryTransform.NONE); } ) - { return null; } } /** @@ -1603,15 +1569,13 @@ FieldOperationContainer match(FieldOperationContainer field) : { } * This rule consumes a single match item for a match block. * * @param field The field to modify. - * @return Null. */ -Object matchItem(FieldOperationContainer field) : { } +void matchItem(FieldOperationContainer field) : { } { ( matchType(field) | exactTerminator(field) | gramSize(field) | matchSize(field) ) - { return null; } } -Object matchType(FieldOperationContainer container) : +void matchType(FieldOperationContainer container) : { MatchOperation matchOp = new MatchOperation(); } @@ -1628,7 +1592,6 @@ Object matchType(FieldOperationContainer container) : | <SUFFIX> { matchOp.setMatchingAlgorithm(Matching.Algorithm.SUFFIX); } ) { container.addOperation(matchOp); - return null; } } @@ -1674,9 +1637,8 @@ void matchSize(FieldOperationContainer container) : * Consumes a rank statement of a field element. * * @param field The field to modify. - * @return Null. */ -Object rank(FieldOperationContainer field) : +void rank(FieldOperationContainer field) : { RankOperation op = new RankOperation(); } @@ -1685,7 +1647,6 @@ Object rank(FieldOperationContainer field) : | (lbrace() (rankSetting(op) (<NL>)*)* <RBRACE>) ) { field.addOperation(op); - return null; } } @@ -1693,14 +1654,12 @@ Object rank(FieldOperationContainer field) : * Consumes a single rank setting of a rank statement. * * @param field The field to modify. - * @return Null. */ -Object rankSetting(RankOperation field) : { } +void rankSetting(RankOperation field) : { } { ( <LITERAL> { field.setLiteral(true); } | <NORMAL> { field.setNormal(true); } | <FILTER> { field.setFilter(true); } ) - { return null; } } /** @@ -1738,9 +1697,8 @@ void indexingRewrite(FieldOperationContainer field) : { } * Consumes a document-summary block from within a schema block. * * @param schema the schema object to add content to - * @return Null */ -Object documentSummary(Schema schema) : +void documentSummary(Schema schema) : { String name; DocumentSummary summary; @@ -1758,7 +1716,6 @@ Object documentSummary(Schema schema) : )* <RBRACE> ) - { return null; } } /** @@ -1782,12 +1739,10 @@ void inheritsDocumentSummary(DocumentSummary documentSummary, Schema schema) : * Consumes a single document-summary item. * * @param summary The document summary to modify. - * @return Null. */ -Object documentSummaryItem(DocumentSummary summary) : { } +void documentSummaryItem(DocumentSummary summary) : { } { summaryInDocument(summary) - { return null; } } /** @@ -1795,9 +1750,8 @@ Object documentSummaryItem(DocumentSummary summary) : { } * * @param schema the schema object to add content to * @param field the field to modify - * @return Null */ -Object index(Schema schema, FieldOperationContainer field) : +void index(Schema schema, FieldOperationContainer field) : { IndexOperation op = new IndexOperation(); String indexName = (field != null) ? field.getName() : null; @@ -1821,7 +1775,6 @@ Object index(Schema schema, FieldOperationContainer field) : } else { field.addOperation(op); } - return null; } } @@ -1829,9 +1782,8 @@ Object index(Schema schema, FieldOperationContainer field) : * Consumes a single index statement for an index block. * * @param index The index to modify. - * @return Null. */ -Object indexBody(IndexOperation index) : +void indexBody(IndexOperation index) : { String str; int arity; @@ -1849,7 +1801,6 @@ Object indexBody(IndexOperation index) : | <ENABLE_BM25> { index.setEnableBm25(true); } | hnswIndex(index) { } ) - { return null; } } void hnswIndex(IndexOperation index) : @@ -1902,9 +1853,8 @@ void onnxModel(Schema schema) : * This rule consumes an onnx-model block. * * @param onnxModel The onnxModel to modify. - * @return Null. */ -Object onnxModelItem(OnnxModel onnxModel) : +void onnxModelItem(OnnxModel onnxModel) : { String path = null; } @@ -1925,9 +1875,6 @@ Object onnxModelItem(OnnxModel onnxModel) : onnxModel.addOutputNameMapping(name, as); } ) - { - return null; - } } /** @@ -2010,9 +1957,8 @@ void rankProfile(Schema schema) : * This rule consumes a single statement for a rank-profile block. * * @param profile The rank profile to modify. - * @return Null. */ -Object rankProfileItem(RankProfile profile) : { } +void rankProfileItem(RankProfile profile) : { } { ( fieldRankType(profile) | fieldWeight(profile) @@ -2033,7 +1979,6 @@ Object rankProfileItem(RankProfile profile) : { } | constants(profile) | matchFeatures(profile) | summaryFeatures(profile) ) - { return null; } } /** @@ -2203,7 +2148,7 @@ void firstPhase(RankProfile profile) : <FIRSTPHASE> lbrace() (firstPhaseItem(profile) (<NL>)*)* <RBRACE> } -Object firstPhaseItem(RankProfile profile) : +void firstPhaseItem(RankProfile profile) : { String expression; int rerankCount; @@ -2214,7 +2159,6 @@ Object firstPhaseItem(RankProfile profile) : | (<KEEPRANKCOUNT> <COLON> rerankCount = integer()) { profile.setKeepRankCount(rerankCount); } | (<RANKSCOREDROPLIMIT> <COLON> dropLimit = consumeFloat()) { profile.setRankScoreDropLimit(dropLimit); } ) - { return null; } } /** @@ -2231,9 +2175,8 @@ void secondPhase(RankProfile profile) : { } * Consumes a statement for a second-phase block. * * @param profile The rank profile to modify. - * @return Null. */ -Object secondPhaseItem(RankProfile profile) : +void secondPhaseItem(RankProfile profile) : { String expression; int rerankCount; @@ -2242,16 +2185,14 @@ Object secondPhaseItem(RankProfile profile) : ( expression = expression() { profile.setSecondPhaseRanking(expression); } | (<RERANKCOUNT> <COLON> rerankCount = integer()) { profile.setRerankCount(rerankCount); } ) - { return null; } } /** * This rule consumes a summary-features block of a rank profile. * * @param profile The rank profile to modify. - * @return Null. */ -Object summaryFeatures(RankProfile profile) : +void summaryFeatures(RankProfile profile) : { String features; String inherited = null; @@ -2269,7 +2210,6 @@ Object summaryFeatures(RankProfile profile) : ) { profile.addSummaryFeatures(getFeatureList(features)); - return null; } } @@ -2277,9 +2217,8 @@ Object summaryFeatures(RankProfile profile) : * This rule consumes a match-features block of a rank profile. * * @param profile The rank profile to modify. - * @return Null. */ -Object matchFeatures(RankProfile profile) : +void matchFeatures(RankProfile profile) : { String features; } @@ -2296,12 +2235,11 @@ Object matchFeatures(RankProfile profile) : ) { profile.addMatchFeatures(getFeatureList(features)); - return null; } } /** Consumes a rank-features block of a rank profile */ -Object rankFeatures(RankProfile profile) : +void rankFeatures(RankProfile profile) : { String features; } @@ -2311,7 +2249,6 @@ Object rankFeatures(RankProfile profile) : token.image.lastIndexOf("}")).trim(); } ) { profile.addRankFeatures(getFeatureList(features)); - return null; } } @@ -2505,14 +2442,13 @@ void rankDegradationPosbinSize() : /** * This rule consumes part of a rank-degradation statement of a rank profile. */ -Object rankDegradationItem() : +void rankDegradationItem() : { } { ( rankDegradationBinSize() | rankDegradationBinLow() | rankDegradationPosbinSize() ) - { return null; } } /** @@ -2520,7 +2456,7 @@ Object rankDegradationItem() : * * @param profile The rank profile to modify. */ -Object rankDegradation(RankProfile profile) : +void rankDegradation(RankProfile profile) : { double freq; } @@ -2529,9 +2465,6 @@ Object rankDegradation(RankProfile profile) : { deployLogger.logApplicationPackage(Level.WARNING, "Specifying 'rank-degradation-frequency' in 'rank-profile' is deprecated and has no effect."); } | <RANKDEGRADATION> lbrace() ( rankDegradationItem() (<NL>)*)+ <RBRACE> ) - { - return null; - } } /** diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java index 3a5bb96d985..b34d113d331 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java @@ -20,7 +20,8 @@ import java.util.Set; enum PathGroup { /** Paths exclusive to operators (including read), used for system management. */ - classifiedOperator("/configserver/v1/{*}", + classifiedOperator("/application/v4/notifications", + "/configserver/v1/{*}", "/deployment/v1/{*}"), /** Paths used for system management by operators. */ diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java index 5742e0a8816..d05a56a3ce0 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java @@ -36,7 +36,7 @@ import java.util.function.Function; import java.util.stream.Collectors; import java.util.stream.Stream; -import static com.yahoo.config.application.api.DeploymentSpec.UpgradeRevision.exclusive; +import static com.yahoo.config.application.api.DeploymentSpec.RevisionTarget.next; import static com.yahoo.config.provision.Environment.prod; import static com.yahoo.config.provision.Environment.staging; import static com.yahoo.config.provision.Environment.test; @@ -258,7 +258,7 @@ public class DeploymentStatus { public Change outstandingChange(InstanceName instance) { return Optional.ofNullable(instanceSteps().get(instance)) .flatMap(instanceStatus -> application.versions().stream() - .sorted(application.deploymentSpec().requireInstance(instance).upgradeRevision() == exclusive ? naturalOrder() : reverseOrder()) + .sorted(application.deploymentSpec().requireInstance(instance).revisionTarget() == next ? naturalOrder() : reverseOrder()) .filter(version -> instanceStatus.dependenciesCompletedAt(Change.of(version), Optional.empty()).map(at -> ! at.isAfter(now)).orElse(false)) .filter(version -> application.productionDeployments().getOrDefault(instance, List.of()).stream() .noneMatch(deployment -> deployment.applicationVersion().compareTo(version) > 0)) diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java index ade3c9cbaf5..64f879a3a5c 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java @@ -2,7 +2,6 @@ package com.yahoo.vespa.hosted.controller.deployment; import com.yahoo.config.application.api.DeploymentInstanceSpec; -import com.yahoo.config.application.api.DeploymentSpec; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.InstanceName; import com.yahoo.text.Text; @@ -389,11 +388,11 @@ public class DeploymentTrigger { private boolean acceptNewApplicationVersion(DeploymentStatus status, InstanceName instance, ApplicationVersion version) { if (status.application().deploymentSpec().instance(instance).isEmpty()) return false; // Unknown instance. boolean isChangingRevision = status.application().require(instance).change().application().isPresent(); - switch (status.application().deploymentSpec().requireInstance(instance).upgradeRevision()) { - case exclusive: return ! isChangingRevision; - case separate: return ! isChangingRevision || status.hasFailures(version); - case latest: return true; - default: throw new IllegalStateException("Unknown revision upgrade policy"); + switch (status.application().deploymentSpec().requireInstance(instance).revisionChange()) { + case whenClear: return ! isChangingRevision; + case whenFailing: return ! isChangingRevision || status.hasFailures(version); + case always: return true; + default: throw new IllegalStateException("Unknown revision upgrade policy"); } } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDb.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDb.java index 4fdfdfc461b..c0bd1ac03ff 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDb.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDb.java @@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.controller.notification; import com.yahoo.collections.Pair; import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.TenantName; import com.yahoo.text.Text; import com.yahoo.vespa.curator.Lock; import com.yahoo.vespa.hosted.controller.Controller; @@ -41,6 +42,10 @@ public class NotificationsDb { this.curatorDb = curatorDb; } + public List<TenantName> listTenantsWithNotifications() { + return curatorDb.listTenantsWithNotifications(); + } + public List<Notification> listNotifications(NotificationSource source, boolean productionOnly) { return curatorDb.readNotifications(source.tenant()).stream() .filter(notification -> source.contains(notification.source()) && (!productionOnly || notification.source().isProduction())) diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java index 9b1a03039fb..6eaad63251c 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java @@ -625,7 +625,7 @@ public class CuratorDb { } - public List<TenantName> listNotifications() { + public List<TenantName> listTenantsWithNotifications() { return curator.getChildren(notificationsRoot).stream() .map(TenantName::from) .collect(Collectors.toUnmodifiableList()); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java index 3b4154759ca..faa60afa176 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java @@ -144,6 +144,9 @@ import java.util.Optional; import java.util.OptionalLong; import java.util.Scanner; import java.util.StringJoiner; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; import java.util.logging.Level; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -233,11 +236,12 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { private HttpResponse handleGET(Path path, HttpRequest request) { if (path.matches("/application/v4/")) return root(request); + if (path.matches("/application/v4/notifications")) return notifications(request, Optional.ofNullable(request.getProperty("tenant")), true); if (path.matches("/application/v4/tenant")) return tenants(request); if (path.matches("/application/v4/tenant/{tenant}")) return tenant(path.get("tenant"), request); if (path.matches("/application/v4/tenant/{tenant}/access/request/ssh")) return accessRequests(path.get("tenant"), request); if (path.matches("/application/v4/tenant/{tenant}/info")) return tenantInfo(path.get("tenant"), request); - if (path.matches("/application/v4/tenant/{tenant}/notifications")) return notifications(path.get("tenant"), request); + if (path.matches("/application/v4/tenant/{tenant}/notifications")) return notifications(request, Optional.of(path.get("tenant")), false); if (path.matches("/application/v4/tenant/{tenant}/secret-store/{name}/validate")) return validateSecretStore(path.get("tenant"), path.get("name"), request); if (path.matches("/application/v4/tenant/{tenant}/application")) return applications(path.get("tenant"), Optional.empty(), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}")) return application(path.get("tenant"), path.get("application"), request); @@ -542,26 +546,41 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { .withAddress(updateTenantInfoAddress(insp.field("address"), oldContact.address())); } - private HttpResponse notifications(String tenantName, HttpRequest request) { - NotificationSource notificationSource = new NotificationSource(TenantName.from(tenantName), - Optional.ofNullable(request.getProperty("application")).map(ApplicationName::from), - Optional.ofNullable(request.getProperty("instance")).map(InstanceName::from), - Optional.empty(), Optional.empty(), Optional.empty(), OptionalLong.empty()); - + private HttpResponse notifications(HttpRequest request, Optional<String> tenant, boolean includeTenantFieldInResponse) { + boolean productionOnly = showOnlyProductionInstances(request); + boolean excludeMessages = "true".equals(request.getProperty("excludeMessages")); Slime slime = new Slime(); Cursor notificationsArray = slime.setObject().setArray("notifications"); - controller.notificationsDb().listNotifications(notificationSource, showOnlyProductionInstances(request)) - .forEach(notification -> toSlime(notificationsArray.addObject(), notification)); + + tenant.map(t -> Stream.of(TenantName.from(t))) + .orElseGet(() -> controller.notificationsDb().listTenantsWithNotifications().stream()) + .flatMap(tenantName -> controller.notificationsDb().listNotifications(NotificationSource.from(tenantName), productionOnly).stream()) + .filter(notification -> + propertyEquals(request, "application", ApplicationName::from, notification.source().application()) && + propertyEquals(request, "instance", InstanceName::from, notification.source().instance()) && + propertyEquals(request, "zone", ZoneId::from, notification.source().zoneId()) && + propertyEquals(request, "job", JobType::fromJobName, notification.source().jobType()) && + propertyEquals(request, "type", Notification.Type::valueOf, Optional.of(notification.type())) && + propertyEquals(request, "level", Notification.Level::valueOf, Optional.of(notification.level()))) + .forEach(notification -> toSlime(notificationsArray.addObject(), notification, includeTenantFieldInResponse, excludeMessages)); return new SlimeJsonResponse(slime); } + private static <T> boolean propertyEquals(HttpRequest request, String property, Function<String, T> mapper, Optional<T> value) { + return Optional.ofNullable(request.getProperty(property)) + .map(propertyValue -> value.isPresent() && mapper.apply(propertyValue).equals(value.get())) + .orElse(true); + } - private static void toSlime(Cursor cursor, Notification notification) { + private static void toSlime(Cursor cursor, Notification notification, boolean includeTenantFieldInResponse, boolean excludeMessages) { cursor.setLong("at", notification.at().toEpochMilli()); cursor.setString("level", notificationLevelAsString(notification.level())); cursor.setString("type", notificationTypeAsString(notification.type())); - Cursor messagesArray = cursor.setArray("messages"); - notification.messages().forEach(messagesArray::addString); + if (!excludeMessages) { + Cursor messagesArray = cursor.setArray("messages"); + notification.messages().forEach(messagesArray::addString); + } + if (includeTenantFieldInResponse) cursor.setString("tenant", notification.source().tenant().value()); notification.source().application().ifPresent(application -> cursor.setString("application", application.value())); notification.source().instance().ifPresent(instance -> cursor.setString("instance", instance.value())); notification.source().zoneId().ifPresent(zoneId -> { diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java index bc5a70b1fa0..640e6860eb6 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java @@ -57,7 +57,8 @@ public class ApplicationPackageBuilder { private OptionalInt majorVersion = OptionalInt.empty(); private String instances = "default"; private String upgradePolicy = null; - private String upgradeRevision = "latest"; + private String revisionTarget = "latest"; + private String revisionChange = "always"; private String upgradeRollout = null; private String globalServiceId = null; private String athenzIdentityAttributes = "athenz-domain='domain' athenz-service='service'"; @@ -81,8 +82,13 @@ public class ApplicationPackageBuilder { return this; } - public ApplicationPackageBuilder upgradeRevision(String upgradeRevision) { - this.upgradeRevision = upgradeRevision; + public ApplicationPackageBuilder revisionTarget(String revisionTarget) { + this.revisionTarget = revisionTarget; + return this; + } + + public ApplicationPackageBuilder revisionChange(String revisionChange) { + this.revisionChange = revisionChange; return this; } @@ -259,10 +265,11 @@ public class ApplicationPackageBuilder { } xml.append(">\n"); xml.append(" <instance id='").append(instances).append("'>\n"); - if (upgradePolicy != null || upgradeRevision != null || upgradeRollout != null) { + if (upgradePolicy != null || revisionTarget != null || revisionChange != null || upgradeRollout != null) { xml.append(" <upgrade "); if (upgradePolicy != null) xml.append("policy='").append(upgradePolicy).append("' "); - if (upgradeRevision != null) xml.append("revision='").append(upgradeRevision).append("' "); + if (revisionTarget != null) xml.append("revision-target='").append(revisionTarget).append("' "); + if (revisionChange != null) xml.append("revision-change='").append(revisionChange).append("' "); if (upgradeRollout != null) xml.append("rollout='").append(upgradeRollout).append("' "); xml.append("/>\n"); } diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java index 925aabf76e3..d0462fd6182 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java @@ -107,10 +107,10 @@ public class DeploymentTriggerTest { } @Test - public void separateRevisionMakesApplicationChangeWaitForPreviousToComplete() { + public void revisionChangeWhenFailingMakesApplicationChangeWaitForPreviousToComplete() { DeploymentContext app = tester.newDeploymentContext(); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() - .upgradeRevision(null) // separate by default, but we override this in test builder + .revisionChange(null) // separate by default, but we override this in test builder .region("us-east-3") .test("us-east-3") .build(); @@ -863,7 +863,7 @@ public class DeploymentTriggerTest { DeploymentContext i4 = tester.newDeploymentContext("t", "a", "i4"); ApplicationPackage applicationPackage = ApplicationPackageBuilder .fromDeploymentXml("<deployment version='1'>\n" + - " <upgrade revision='separate' />\n" + + " <upgrade revision-change='when-failing' />\n" + " <parallel>\n" + " <instance id='i1'>\n" + " <prod>\n" + @@ -1425,21 +1425,21 @@ public class DeploymentTriggerTest { " <instance id='alpha'>\n" + " <test />\n" + " <staging />\n" + - " <upgrade revision='latest' />\n" + + " <upgrade revision-change='always' />\n" + " <prod>\n" + " <region>us-east-3</region>\n" + " <test>us-east-3</test>\n" + " </prod>\n" + " </instance>\n" + " <instance id='beta'>\n" + - " <upgrade revision='separate' />\n" + + " <upgrade revision-change='when-failing' />\n" + " <prod>\n" + " <region>us-east-3</region>\n" + " <test>us-east-3</test>\n" + " </prod>\n" + " </instance>\n" + " <instance id='gamma'>\n" + - " <upgrade revision='exclusive' />\n" + + " <upgrade revision-change='when-clear' revision-target='next' />\n" + " <prod>\n" + " <region>us-east-3</region>\n" + " <test>us-east-3</test>\n" + diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java index acaa8b24d9d..052a8bffab1 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java @@ -28,10 +28,9 @@ public class OutstandingChangeDeployerTest { @Test public void testChangeDeployer() { DeploymentTester tester = new DeploymentTester(); - OutstandingChangeDeployer deployer = new OutstandingChangeDeployer(tester.controller(), Duration.ofMinutes(10)); ApplicationPackage applicationPackage = new ApplicationPackageBuilder() .region("us-west-1") - .upgradeRevision("separate") + .revisionChange("when-failing") .build(); var app = tester.newDeploymentContext().submit(applicationPackage).deploy(); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java index 516911b3c7b..61e9ea02acc 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java @@ -861,6 +861,10 @@ public class ApplicationApiTest extends ControllerContainerTest { ""); addNotifications(TenantName.from("tenant1")); + addNotifications(TenantName.from("tenant2")); + tester.assertResponse(request("/application/v4/notifications", GET) + .properties(Map.of("type", "applicationPackage", "excludeMessages", "true")).userIdentity(HOSTED_VESPA_OPERATOR), + new File("notifications-applicationPackage.json")); tester.assertResponse(request("/application/v4/tenant/tenant1/notifications", GET).userIdentity(USER_ID), new File("notifications-tenant1.json")); tester.assertResponse(request("/application/v4/tenant/tenant1/notifications", GET) diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/notifications-applicationPackage.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/notifications-applicationPackage.json new file mode 100644 index 00000000000..c0833ae0f05 --- /dev/null +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/notifications-applicationPackage.json @@ -0,0 +1,18 @@ +{ + "notifications": [ + { + "at": "(ignore)", + "level": "warning", + "type": "applicationPackage", + "tenant": "tenant1", + "application": "app1" + }, + { + "at": "(ignore)", + "level": "warning", + "type": "applicationPackage", + "tenant": "tenant2", + "application": "app1" + } + ] +} diff --git a/searchlib/src/tests/common/geogcd/geo_gcd_test.cpp b/searchlib/src/tests/common/geogcd/geo_gcd_test.cpp index 296ed89a903..e633c1f0e43 100644 --- a/searchlib/src/tests/common/geogcd/geo_gcd_test.cpp +++ b/searchlib/src/tests/common/geogcd/geo_gcd_test.cpp @@ -49,7 +49,7 @@ TEST(GeoGcdTest, computed_distances_seem_legit) { double miles = km / 1.609344; EXPECT_GE(miles, 0); if (from.name == to.name) { - EXPECT_DOUBLE_EQ(miles, 0.0); + EXPECT_NEAR(miles, 0.0, 1e-9); // EXPECT_DOUBLE_EQ does not work on arm64 for some reason } else { double exact = exact_distances[i][j]; printf("Distance from %s to %s (in miles): %.1f [more exact would be %.1f]\n", from.name, to.name, miles, exact); diff --git a/searchlib/src/tests/tensor/distance_functions/distance_functions_test.cpp b/searchlib/src/tests/tensor/distance_functions/distance_functions_test.cpp index 7abc83b0047..f4faabde559 100644 --- a/searchlib/src/tests/tensor/distance_functions/distance_functions_test.cpp +++ b/searchlib/src/tests/tensor/distance_functions/distance_functions_test.cpp @@ -37,7 +37,7 @@ void verify_geo_miles(const DistanceFunction *dist_fun, // compare with common Great Circle Distance implementation: search::common::GeoGcd gp1{p1[0], p1[1]}; double km_gcd = gp1.km_great_circle_distance(p2[0], p2[1]); - EXPECT_DOUBLE_EQ(km, km_gcd); + EXPECT_NEAR(km, km_gcd, 1e-9); // EXPECT_DOUBLE_EQ does not work on arm64 for some reason } else { EXPECT_LE(d_miles, 7e-13); EXPECT_LE(abstract_distance, 6e-33); diff --git a/vespalib/src/vespa/vespalib/datastore/sharded_hash_map.cpp b/vespalib/src/vespa/vespalib/datastore/sharded_hash_map.cpp index 019b98a53dd..2ae22084472 100644 --- a/vespalib/src/vespa/vespalib/datastore/sharded_hash_map.cpp +++ b/vespalib/src/vespa/vespalib/datastore/sharded_hash_map.cpp @@ -88,7 +88,7 @@ ShardedHashMap::KvType* ShardedHashMap::find(const EntryComparator& comp, EntryRef key_ref) { ShardedHashComparator shardedComp(comp, key_ref, num_shards); - auto map = _maps[shardedComp.shard_idx()].load(std::memory_order_relaxed); + auto map = _maps[shardedComp.shard_idx()].load(std::memory_order_acquire); if (map == nullptr) { return nullptr; } @@ -99,7 +99,7 @@ const ShardedHashMap::KvType* ShardedHashMap::find(const EntryComparator& comp, EntryRef key_ref) const { ShardedHashComparator shardedComp(comp, key_ref, num_shards); - auto map = _maps[shardedComp.shard_idx()].load(std::memory_order_relaxed); + auto map = _maps[shardedComp.shard_idx()].load(std::memory_order_acquire); if (map == nullptr) { return nullptr; } @@ -135,7 +135,7 @@ ShardedHashMap::size() const noexcept { size_t result = 0; for (size_t i = 0; i < num_shards; ++i) { - auto map = _maps[i].load(std::memory_order_relaxed); + auto map = _maps[i].load(std::memory_order_acquire); if (map != nullptr) { result += map->size(); } @@ -148,7 +148,7 @@ ShardedHashMap::get_memory_usage() const { MemoryUsage memory_usage(sizeof(ShardedHashMap), sizeof(ShardedHashMap), 0, 0); for (size_t i = 0; i < num_shards; ++i) { - auto map = _maps[i].load(std::memory_order_relaxed); + auto map = _maps[i].load(std::memory_order_acquire); if (map != nullptr) { memory_usage.merge(map->get_memory_usage()); } @@ -163,7 +163,7 @@ void ShardedHashMap::foreach_key(std::function<void(EntryRef)> callback) const { for (size_t i = 0; i < num_shards; ++i) { - auto map = _maps[i].load(std::memory_order_relaxed); + auto map = _maps[i].load(std::memory_order_acquire); if (map != nullptr) { map->foreach_key(callback); } @@ -211,7 +211,7 @@ void ShardedHashMap::foreach_value(std::function<void(const std::vector<EntryRef>&)> callback, const EntryRefFilter& filter) { for (size_t i = 0; i < num_shards; ++i) { - auto map = _maps[i].load(std::memory_order_relaxed); + auto map = _maps[i].load(std::memory_order_acquire); if (map != nullptr) { map->foreach_value(callback, filter); } |