summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config-model-api/abi-spec.json58
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentInstanceSpec.java24
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/DeploymentSpec.java21
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/application/api/xml/DeploymentSpecXmlReader.java43
-rw-r--r--config-model-api/src/test/java/com/yahoo/config/application/api/DeploymentSpecTest.java27
-rw-r--r--config-model/src/main/javacc/SDParser.jj135
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java3
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentStatus.java4
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java11
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/NotificationsDb.java5
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java43
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/ApplicationPackageBuilder.java17
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTriggerTest.java12
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OutstandingChangeDeployerTest.java3
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java4
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/notifications-applicationPackage.json18
-rw-r--r--searchlib/src/tests/common/geogcd/geo_gcd_test.cpp2
-rw-r--r--searchlib/src/tests/tensor/distance_functions/distance_functions_test.cpp2
-rw-r--r--vespalib/src/vespa/vespalib/datastore/sharded_hash_map.cpp12
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);
}