aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/go/script-utils/main.go2
-rw-r--r--client/go/script-utils/services/configproxy.go9
-rw-r--r--client/go/script-utils/services/sentinel.go9
-rw-r--r--client/go/script-utils/services/stop.go35
-rw-r--r--client/go/util/run_cmd.go4
-rw-r--r--config-application-package/src/main/java/com/yahoo/config/model/application/AbstractApplicationPackage.java14
-rw-r--r--config-application-package/src/main/java/com/yahoo/config/model/application/provider/FilesApplicationPackage.java4
-rw-r--r--config-application-package/src/test/java/com/yahoo/config/model/application/AbstractApplicationPackageTest.java34
-rw-r--r--config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java23
-rw-r--r--config-model/src/main/java/com/yahoo/schema/ApplicationBuilder.java5
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java19
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/CertificateRemovalChangeValidator.java16
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ChangeValidator.java5
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/CloudAccountChangeValidator.java5
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ClusterSizeReductionValidator.java21
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ConfigValueChangeValidator.java38
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidator.java7
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentClusterRemovalValidator.java9
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentTypeRemovalValidator.java9
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/GlobalDocumentChangeValidator.java8
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/IndexedSearchClusterChangeValidator.java22
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/IndexingModeChangeValidator.java6
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidator.java7
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/RedundancyIncreaseValidator.java11
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ResourcesReductionValidator.java18
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/StartupCommandChangeValidator.java7
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/StreamingSearchClusterChangeValidator.java5
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/search/AttributeChangeValidator.java16
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/search/DocumentDatabaseChangeValidator.java14
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/first/RedundancyOnFirstDeploymentValidator.java32
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/first/RedundancyValidator.java62
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/search/ContainerSearch.java26
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java2
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/search/SearchCluster.java1
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/CertificateRemovalChangeValidatorTest.java15
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/CloudAccountChangeValidatorTest.java8
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ConfigValueChangeValidatorTest.java25
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidatorTest.java7
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContentClusterRemovalValidatorTest.java6
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/IndexedSchemaClusterChangeValidatorTest.java5
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidatorTest.java6
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RedundancyChangeValidatorTest.java65
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/StreamingSchemaClusterChangeValidatorTest.java42
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/search/AttributeChangeValidatorTest.java5
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/search/DocumentDatabaseChangeValidatorTest.java6
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java5
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackage.java8
-rw-r--r--container-core/src/test/java/com/yahoo/processing/test/ProcessorLibrary.java (renamed from container-core/src/main/java/com/yahoo/processing/test/ProcessorLibrary.java)0
-rw-r--r--container-core/src/test/java/com/yahoo/processing/test/Responses.java (renamed from container-core/src/main/java/com/yahoo/processing/test/Responses.java)0
-rw-r--r--container-search/src/main/java/com/yahoo/search/schema/SchemaInfo.java1
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzDbMock.java12
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java26
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/role/PathGroup.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java4
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java4
-rw-r--r--model-integration/src/main/java/ai/vespa/modelintegration/evaluator/OnnxEvaluatorOptions.java5
-rw-r--r--searchcore/src/tests/proton/documentdb/configurer/configurer_test.cpp29
-rw-r--r--searchcore/src/vespa/searchcore/proton/docsummary/isummarymanager.h4
-rw-r--r--searchcore/src/vespa/searchcore/proton/docsummary/summarymanager.cpp9
-rw-r--r--searchcore/src/vespa/searchcore/proton/docsummary/summarymanager.h6
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/reconfig_params.cpp2
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/searchable_doc_subdb_configurer.cpp3
-rw-r--r--searchcore/src/vespa/searchcore/proton/server/searchabledocsubdb.cpp3
-rw-r--r--searchcore/src/vespa/searchcore/proton/test/dummy_summary_manager.h3
-rw-r--r--searchsummary/CMakeLists.txt1
-rw-r--r--searchsummary/src/tests/docsummary/keyword_extractor_factory/CMakeLists.txt9
-rw-r--r--searchsummary/src/tests/docsummary/keyword_extractor_factory/keyword_extractor_factory_test.cpp73
-rw-r--r--searchsummary/src/vespa/searchsummary/docsummary/CMakeLists.txt2
-rw-r--r--searchsummary/src/vespa/searchsummary/docsummary/keyword_extractor.cpp22
-rw-r--r--searchsummary/src/vespa/searchsummary/docsummary/keyword_extractor.h24
-rw-r--r--searchsummary/src/vespa/searchsummary/docsummary/keyword_extractor_factory.cpp41
-rw-r--r--searchsummary/src/vespa/searchsummary/docsummary/keyword_extractor_factory.h26
-rw-r--r--streamingvisitors/CMakeLists.txt1
-rw-r--r--streamingvisitors/src/tests/keyword_extractor_factory/CMakeLists.txt9
-rw-r--r--streamingvisitors/src/tests/keyword_extractor_factory/keyword_extractor_factory_test.cpp116
-rw-r--r--streamingvisitors/src/vespa/vsm/vsm/CMakeLists.txt1
-rw-r--r--streamingvisitors/src/vespa/vsm/vsm/keyword_extractor_factory.cpp80
-rw-r--r--streamingvisitors/src/vespa/vsm/vsm/keyword_extractor_factory.h39
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AthenzDomainMeta.java12
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/DefaultZmsClient.java30
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/ZmsClient.java5
81 files changed, 1005 insertions, 307 deletions
diff --git a/client/go/script-utils/main.go b/client/go/script-utils/main.go
index 89802ad5697..79125292632 100644
--- a/client/go/script-utils/main.go
+++ b/client/go/script-utils/main.go
@@ -34,6 +34,8 @@ func main() {
os.Args = os.Args[1:]
}
switch action {
+ case "vespa-stop-services":
+ os.Exit(services.VespaStopServices())
case "vespa-start-services":
os.Exit(services.VespaStartServices())
case "start-services":
diff --git a/client/go/script-utils/services/configproxy.go b/client/go/script-utils/services/configproxy.go
index fb452a4de00..9714d9af284 100644
--- a/client/go/script-utils/services/configproxy.go
+++ b/client/go/script-utils/services/configproxy.go
@@ -132,3 +132,12 @@ func StartConfigproxy() int {
}
return 1
}
+
+func stopProxyWithRunserver() {
+ _, err := util.SystemCommand.Run("vespa-runserver",
+ "-s", PROXY_SERVICE_NAME,
+ "-p", CONFIGPROXY_PIDFILE, "-S")
+ if err != nil {
+ trace.Warning("Stopping sentinel:", err)
+ }
+}
diff --git a/client/go/script-utils/services/sentinel.go b/client/go/script-utils/services/sentinel.go
index 17f07ce4d55..352acde38bd 100644
--- a/client/go/script-utils/services/sentinel.go
+++ b/client/go/script-utils/services/sentinel.go
@@ -82,3 +82,12 @@ func StartConfigSentinel() int {
}
return 1
}
+
+func stopSentinelWithRunserver() {
+ _, err := util.SystemCommand.Run("vespa-runserver",
+ "-s", SENTINEL_SERVICE_NAME,
+ "-p", SENTINEL_PIDFILE, "-S")
+ if err != nil {
+ trace.Warning("Stopping sentinel:", err)
+ }
+}
diff --git a/client/go/script-utils/services/stop.go b/client/go/script-utils/services/stop.go
new file mode 100644
index 00000000000..c2ad332a89d
--- /dev/null
+++ b/client/go/script-utils/services/stop.go
@@ -0,0 +1,35 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Author: arnej
+
+package services
+
+import (
+ "os"
+
+ "github.com/vespa-engine/vespa/client/go/envvars"
+ "github.com/vespa-engine/vespa/client/go/trace"
+ "github.com/vespa-engine/vespa/client/go/util"
+ "github.com/vespa-engine/vespa/client/go/vespa"
+)
+
+func VespaStopServices() int {
+ if doTrace := os.Getenv(envvars.TRACE_STARTUP); doTrace != "" {
+ trace.AdjustVerbosity(1)
+ }
+ if doDebug := os.Getenv(envvars.DEBUG_STARTUP); doDebug != "" {
+ trace.AdjustVerbosity(2)
+ }
+ err := vespa.LoadDefaultEnv()
+ if err != nil {
+ util.JustExitWith(err)
+ }
+ err = vespa.MaybeSwitchUser("vespa-stop-services")
+ if err != nil {
+ util.JustExitWith(err)
+ }
+ vespa.CheckCorrectUser()
+ trace.Debug("running as correct user")
+ stopSentinelWithRunserver()
+ stopProxyWithRunserver()
+ return 0
+}
diff --git a/client/go/util/run_cmd.go b/client/go/util/run_cmd.go
index 0b66bc66ee9..bbdda0915fd 100644
--- a/client/go/util/run_cmd.go
+++ b/client/go/util/run_cmd.go
@@ -18,6 +18,7 @@ const (
BackTicksWithStderr BackTicks = iota
BackTicksIgnoreStderr
BackTicksForwardStderr
+ SystemCommand
)
func (b BackTicks) Run(program string, args ...string) (string, error) {
@@ -31,6 +32,9 @@ func (b BackTicks) Run(program string, args ...string) (string, error) {
cmd.Stderr = nil
case BackTicksForwardStderr:
cmd.Stderr = os.Stderr
+ case SystemCommand:
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
}
trace.Debug("running command:", program, strings.Join(args, " "))
err := cmd.Run()
diff --git a/config-application-package/src/main/java/com/yahoo/config/model/application/AbstractApplicationPackage.java b/config-application-package/src/main/java/com/yahoo/config/model/application/AbstractApplicationPackage.java
index c616784c7be..005c54498fc 100644
--- a/config-application-package/src/main/java/com/yahoo/config/model/application/AbstractApplicationPackage.java
+++ b/config-application-package/src/main/java/com/yahoo/config/model/application/AbstractApplicationPackage.java
@@ -41,4 +41,18 @@ public abstract class AbstractApplicationPackage implements ApplicationPackage {
return result;
}
+ public static boolean validSchemaFilename(String fn) {
+ if (! fn.endsWith(SD_NAME_SUFFIX)) {
+ return false;
+ }
+ int lastSlash = fn.lastIndexOf('/');
+ if (lastSlash >= 0) {
+ fn = fn.substring(lastSlash+1);
+ }
+ if (fn.startsWith(".")) {
+ return false;
+ }
+ return true;
+ }
+
}
diff --git a/config-application-package/src/main/java/com/yahoo/config/model/application/provider/FilesApplicationPackage.java b/config-application-package/src/main/java/com/yahoo/config/model/application/provider/FilesApplicationPackage.java
index c095b9ad586..5707206019f 100644
--- a/config-application-package/src/main/java/com/yahoo/config/model/application/provider/FilesApplicationPackage.java
+++ b/config-application-package/src/main/java/com/yahoo/config/model/application/provider/FilesApplicationPackage.java
@@ -432,11 +432,11 @@ public class FilesApplicationPackage extends AbstractApplicationPackage {
File sdDir = applicationFile(appDir, SEARCH_DEFINITIONS_DIR.getRelative());
if (sdDir.isDirectory())
- schemaFiles.addAll(Arrays.asList(sdDir.listFiles((dir, name) -> name.matches(".*\\" + SD_NAME_SUFFIX))));
+ schemaFiles.addAll(Arrays.asList(sdDir.listFiles((dir, name) -> validSchemaFilename(name))));
sdDir = applicationFile(appDir, SCHEMAS_DIR.getRelative());
if (sdDir.isDirectory())
- schemaFiles.addAll(Arrays.asList(sdDir.listFiles((dir, name) -> name.matches(".*\\" + SD_NAME_SUFFIX))));
+ schemaFiles.addAll(Arrays.asList(sdDir.listFiles((dir, name) -> validSchemaFilename(name))));
return schemaFiles;
}
diff --git a/config-application-package/src/test/java/com/yahoo/config/model/application/AbstractApplicationPackageTest.java b/config-application-package/src/test/java/com/yahoo/config/model/application/AbstractApplicationPackageTest.java
new file mode 100644
index 00000000000..1f56e3b37b8
--- /dev/null
+++ b/config-application-package/src/test/java/com/yahoo/config/model/application/AbstractApplicationPackageTest.java
@@ -0,0 +1,34 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.model.application;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author arnej
+ */
+public class AbstractApplicationPackageTest {
+
+ private static void checkValid(String fn) {
+ assertTrue(AbstractApplicationPackage.validSchemaFilename(fn));
+ }
+
+ private static void checkInvalid(String fn) {
+ assertFalse(AbstractApplicationPackage.validSchemaFilename(fn));
+ }
+
+ @Test
+ public void testValidSchemaFilename() {
+ checkValid("foo.sd");
+ checkValid("schemas/foo.sd");
+ checkValid("./foo.sd");
+ checkValid("./schemas/foo.sd");
+ checkInvalid("foo");
+ checkInvalid("foo.ds");
+ checkInvalid(".foo.sd");
+ checkInvalid("schemas/.foo.sd");
+ checkInvalid("schemas/subdir/._foo.sd");
+ }
+}
diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java b/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java
index 54521b946dd..1813e183a60 100644
--- a/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java
+++ b/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java
@@ -122,7 +122,8 @@ public class DeployState implements ConfigDefinitionStore {
Version wantedNodeVespaVersion,
boolean accessLoggingEnabledByDefault,
Optional<DockerImage> wantedDockerImageRepo,
- Reindexing reindexing) {
+ Reindexing reindexing,
+ Optional<ValidationOverrides> validationOverrides) {
this.logger = deployLogger;
this.fileRegistry = fileRegistry;
this.executor = executor;
@@ -143,8 +144,8 @@ public class DeployState implements ConfigDefinitionStore {
this.semanticRules = semanticRules; // TODO: Remove this by seeing how pagetemplates are propagated
this.importedModels = importMlModels(applicationPackage, modelImporters, executor);
- this.validationOverrides = applicationPackage.getValidationOverrides().map(ValidationOverrides::fromXml)
- .orElse(ValidationOverrides.empty);
+ this.validationOverrides = validationOverrides.orElse(applicationPackage.getValidationOverrides().map(ValidationOverrides::fromXml)
+ .orElse(ValidationOverrides.empty));
this.wantedNodeVespaVersion = wantedNodeVespaVersion;
this.now = now;
@@ -327,9 +328,10 @@ public class DeployState implements ConfigDefinitionStore {
private Version wantedNodeVespaVersion = Vtag.currentVersion;
private boolean accessLoggingEnabledByDefault = true;
private Optional<DockerImage> wantedDockerImageRepo = Optional.empty();
- private Reindexing reindexing = null;
private RankProfileRegistry rankProfileRegistry = new RankProfileRegistry();
private QueryProfiles queryProfiles = null;
+ private Reindexing reindexing = null;
+ private Optional<ValidationOverrides> validationOverrides = Optional.empty();
public Builder() {}
@@ -437,7 +439,15 @@ public class DeployState implements ConfigDefinitionStore {
return this;
}
- public Builder reindexing(Reindexing reindexing) { this.reindexing = Objects.requireNonNull(reindexing); return this; }
+ public Builder reindexing(Reindexing reindexing) {
+ this.reindexing = Objects.requireNonNull(reindexing);
+ return this;
+ }
+
+ public Builder validationOverrides(ValidationOverrides validationOverrides) {
+ this.validationOverrides = Optional.of(validationOverrides);
+ return this;
+ }
public DeployState build() {
return build(new ValidationParameters());
@@ -470,7 +480,8 @@ public class DeployState implements ConfigDefinitionStore {
wantedNodeVespaVersion,
accessLoggingEnabledByDefault,
wantedDockerImageRepo,
- reindexing);
+ reindexing,
+ validationOverrides);
}
}
diff --git a/config-model/src/main/java/com/yahoo/schema/ApplicationBuilder.java b/config-model/src/main/java/com/yahoo/schema/ApplicationBuilder.java
index f002676f05d..9184eb3c4be 100644
--- a/config-model/src/main/java/com/yahoo/schema/ApplicationBuilder.java
+++ b/config-model/src/main/java/com/yahoo/schema/ApplicationBuilder.java
@@ -5,6 +5,7 @@ import com.yahoo.config.application.api.ApplicationPackage;
import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.application.api.FileRegistry;
import com.yahoo.config.model.api.ModelContext;
+import com.yahoo.config.model.application.AbstractApplicationPackage;
import com.yahoo.config.model.application.provider.BaseDeployLogger;
import com.yahoo.config.model.application.provider.MockFileRegistry;
import com.yahoo.config.model.deploy.TestProperties;
@@ -354,7 +355,7 @@ public class ApplicationBuilder {
}
/**
- * Convenience factory methdd to create a SearchBuilder from multiple SD files..
+ * Convenience factory method to create a SearchBuilder from multiple SD files.
*/
private static ApplicationBuilder createFromFiles(Collection<String> fileNames,
FileRegistry fileRegistry,
@@ -413,7 +414,7 @@ public class ApplicationBuilder {
var fnli = Files.list(new File(dir).toPath())
.map(p -> p.toString())
- .filter(fn -> fn.endsWith(".sd"))
+ .filter(fn -> AbstractApplicationPackage.validSchemaFilename(fn))
.sorted();
for (var i = fnli.iterator(); i.hasNext(); ) {
builder.addSchemaFile(i.next());
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java
index 93a28820125..7b380cd5acf 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java
@@ -26,7 +26,7 @@ import com.yahoo.vespa.model.application.validation.change.RedundancyIncreaseVal
import com.yahoo.vespa.model.application.validation.change.ResourcesReductionValidator;
import com.yahoo.vespa.model.application.validation.change.StartupCommandChangeValidator;
import com.yahoo.vespa.model.application.validation.change.StreamingSearchClusterChangeValidator;
-import com.yahoo.vespa.model.application.validation.first.RedundancyOnFirstDeploymentValidator;
+import com.yahoo.vespa.model.application.validation.first.RedundancyValidator;
import java.time.Instant;
import java.util.Arrays;
@@ -98,8 +98,7 @@ public class Validation {
} else {
Optional<Model> currentActiveModel = deployState.getPreviousModel();
if (currentActiveModel.isPresent() && (currentActiveModel.get() instanceof VespaModel)) {
- result = validateChanges((VespaModel) currentActiveModel.get(), model,
- deployState.validationOverrides(), deployState.getDeployLogger(), deployState.now());
+ result = validateChanges((VespaModel) currentActiveModel.get(), model, deployState);
deferConfigChangesForClustersToBeRestarted(result, model);
}
}
@@ -107,14 +106,13 @@ public class Validation {
}
private static List<ConfigChangeAction> validateChanges(VespaModel currentModel, VespaModel nextModel,
- ValidationOverrides overrides, DeployLogger logger,
- Instant now) {
+ DeployState deployState) {
ChangeValidator[] validators = new ChangeValidator[] {
new IndexingModeChangeValidator(),
new GlobalDocumentChangeValidator(),
new IndexedSearchClusterChangeValidator(),
new StreamingSearchClusterChangeValidator(),
- new ConfigValueChangeValidator(logger),
+ new ConfigValueChangeValidator(),
new StartupCommandChangeValidator(),
new ContentTypeRemovalValidator(),
new ContentClusterRemovalValidator(),
@@ -124,10 +122,11 @@ public class Validation {
new NodeResourceChangeValidator(),
new RedundancyIncreaseValidator(),
new CloudAccountChangeValidator(),
- new CertificateRemovalChangeValidator()
+ new CertificateRemovalChangeValidator(),
+ new RedundancyValidator()
};
List<ConfigChangeAction> actions = Arrays.stream(validators)
- .flatMap(v -> v.validate(currentModel, nextModel, overrides, now).stream())
+ .flatMap(v -> v.validate(currentModel, nextModel, deployState).stream())
.toList();
Map<ValidationId, Collection<String>> disallowableActions = actions.stream()
@@ -135,12 +134,12 @@ public class Validation {
.collect(groupingBy(action -> action.validationId().orElseThrow(),
mapping(ConfigChangeAction::getMessage,
toCollection(LinkedHashSet::new))));
- overrides.invalid(disallowableActions, now);
+ deployState.validationOverrides().invalid(disallowableActions, deployState.now());
return actions;
}
private static void validateFirstTimeDeployment(VespaModel model, DeployState deployState) {
- new RedundancyOnFirstDeploymentValidator().validate(model, deployState);
+ new RedundancyValidator().validate(model, deployState);
}
private static void deferConfigChangesForClustersToBeRestarted(List<ConfigChangeAction> actions, VespaModel model) {
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/CertificateRemovalChangeValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/CertificateRemovalChangeValidator.java
index b225c25a8d3..6f80c3da469 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/CertificateRemovalChangeValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/CertificateRemovalChangeValidator.java
@@ -2,13 +2,12 @@
package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.application.api.ValidationId;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.container.http.Client;
import java.security.cert.X509Certificate;
-import java.time.Instant;
import java.util.Collection;
import java.util.List;
import java.util.logging.Level;
@@ -25,19 +24,22 @@ public class CertificateRemovalChangeValidator implements ChangeValidator {
private static final Logger logger = Logger.getLogger(CertificateRemovalChangeValidator.class.getName());
@Override
- public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, ValidationOverrides overrides, Instant now) {
+ public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, DeployState deployState) {
// Skip for tester applications
if (current.applicationPackage().getApplicationId().instance().isTester()) return List.of();
current.getContainerClusters()
.forEach((clusterId, currentCluster) -> {
if(next.getContainerClusters().containsKey(clusterId))
- validateClients(clusterId, currentCluster.getClients(), next.getContainerClusters().get(clusterId).getClients(), overrides, now);
+ validateClients(clusterId,
+ currentCluster.getClients(),
+ next.getContainerClusters().get(clusterId).getClients(),
+ deployState);
});
return List.of();
}
- void validateClients(String clusterId, List<Client> current, List<Client> next, ValidationOverrides overrides, Instant now) {
+ void validateClients(String clusterId, List<Client> current, List<Client> next, DeployState deployState) {
List<X509Certificate> currentCertificates = current.stream()
.filter(client -> !client.internal())
.map(Client::certificates)
@@ -56,11 +58,11 @@ public class CertificateRemovalChangeValidator implements ChangeValidator {
List<X509Certificate> missingCerts = currentCertificates.stream().filter(cert -> !nextCertificates.contains(cert)).toList();
if (!missingCerts.isEmpty()) {
- overrides.invalid(ValidationId.certificateRemoval,
+ deployState.validationOverrides().invalid(ValidationId.certificateRemoval,
"Data plane certificate(s) from cluster '" + clusterId + "' is removed " +
"(removed certificates: " + missingCerts.stream().map(x509Certificate -> x509Certificate.getSubjectX500Principal().getName()).toList() + ") " +
"This can cause client connection issues.",
- now);
+ deployState.now());
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ChangeValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ChangeValidator.java
index 772b6a37b02..9992fa37e45 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ChangeValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ChangeValidator.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.config.application.api.ValidationOverrides;
@@ -21,12 +22,10 @@ public interface ChangeValidator {
*
* @param current the current active model
* @param next the next model we would like to activate
- * @param overrides validation overrides
- * @param now the instant to use as now
* @return a list of actions specifying what needs to be done in order to activate the new model.
* Return an empty list if nothing needs to be done
* @throws IllegalArgumentException if the change fails validation
*/
- List<ConfigChangeAction> validate(VespaModel current, VespaModel next, ValidationOverrides overrides, Instant now);
+ List<ConfigChangeAction> validate(VespaModel current, VespaModel next, DeployState deployState);
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/CloudAccountChangeValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/CloudAccountChangeValidator.java
index ba8a8819c5b..c55cfbc5075 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/CloudAccountChangeValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/CloudAccountChangeValidator.java
@@ -1,14 +1,13 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.application.validation.change;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.CloudAccount;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.vespa.model.VespaModel;
-import java.time.Instant;
import java.util.List;
/**
@@ -17,7 +16,7 @@ import java.util.List;
public class CloudAccountChangeValidator implements ChangeValidator {
@Override
- public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, ValidationOverrides overrides, Instant now) {
+ public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, DeployState deployState) {
for (var clusterId : current.allClusters()) {
CloudAccount currentAccount = cloudAccountOf(current, clusterId);
CloudAccount nextAccount = cloudAccountOf(next, clusterId);
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ClusterSizeReductionValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ClusterSizeReductionValidator.java
index 14fb903a547..353be99cfa9 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ClusterSizeReductionValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ClusterSizeReductionValidator.java
@@ -2,13 +2,12 @@
package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.config.application.api.ValidationId;
-import com.yahoo.config.application.api.ValidationOverrides;
-import java.time.Instant;
import java.util.List;
/**
@@ -19,34 +18,26 @@ import java.util.List;
public class ClusterSizeReductionValidator implements ChangeValidator {
@Override
- public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, ValidationOverrides overrides, Instant now) {
+ public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, DeployState deployState) {
for (var clusterId : current.allClusters()) {
Capacity currentCapacity = current.provisioned().all().get(clusterId);
Capacity nextCapacity = next.provisioned().all().get(clusterId);
if (currentCapacity == null || nextCapacity == null) continue;
- validate(currentCapacity,
- nextCapacity,
- clusterId,
- overrides,
- now);
+ validate(currentCapacity, nextCapacity, clusterId, deployState);
}
return List.of();
}
- private void validate(Capacity current,
- Capacity next,
- ClusterSpec.Id clusterId,
- ValidationOverrides overrides,
- Instant now) {
+ private void validate(Capacity current, Capacity next, ClusterSpec.Id clusterId, DeployState deployState) {
int currentSize = current.minResources().nodes();
int nextSize = next.minResources().nodes();
// don't allow more than 50% reduction, but always allow to reduce size with 1
if ( nextSize < currentSize * 0.5 && nextSize != currentSize - 1)
- overrides.invalid(ValidationId.clusterSizeReduction,
+ deployState.validationOverrides().invalid(ValidationId.clusterSizeReduction,
"Size reduction in '" + clusterId.value() + "' is too large: " +
"New min size must be at least 50% of the current min size. " +
"Current size: " + currentSize + ", new size: " + nextSize,
- now);
+ deployState.now());
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ConfigValueChangeValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ConfigValueChangeValidator.java
index 077855b4b23..84730a18265 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ConfigValueChangeValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ConfigValueChangeValidator.java
@@ -4,8 +4,8 @@ package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.ChangesRequiringRestart;
import com.yahoo.config.ConfigInstance;
import com.yahoo.config.application.api.DeployLogger;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.model.producer.AbstractConfigProducerRoot;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.vespa.model.Service;
@@ -13,12 +13,10 @@ import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.application.validation.RestartConfigs;
import com.yahoo.vespa.model.utils.internal.ReflectionUtil;
-import java.time.Instant;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.logging.Level;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.util.stream.Collectors.joining;
@@ -32,31 +30,26 @@ import static java.util.stream.Collectors.joining;
*/
public class ConfigValueChangeValidator implements ChangeValidator {
- private final DeployLogger logger;
-
- public ConfigValueChangeValidator(DeployLogger logger) {
- this.logger = logger;
- }
-
/** Inspects the configuration in the new and old Vespa model to determine which services that require restart */
@Override
- public List<ConfigChangeAction> validate(VespaModel currentModel, VespaModel nextModel,
- ValidationOverrides overrides, Instant now) {
- return findConfigChangesFromModels(currentModel, nextModel).toList();
+ public List<ConfigChangeAction> validate(VespaModel currentModel, VespaModel nextModel, DeployState deployState) {
+ return findConfigChangesFromModels(currentModel, nextModel, deployState.getDeployLogger()).toList();
}
public Stream<ConfigChangeAction> findConfigChangesFromModels(AbstractConfigProducerRoot currentModel,
- AbstractConfigProducerRoot nextModel) {
+ AbstractConfigProducerRoot nextModel,
+ DeployLogger logger) {
return nextModel.getDescendantServices().stream()
- .map(service -> findConfigChangeActionForService(service, currentModel, nextModel))
+ .map(service -> findConfigChangeActionForService(service, currentModel, nextModel, logger))
.filter(Optional::isPresent)
.map(Optional::get);
}
private Optional<ConfigChangeAction> findConfigChangeActionForService(Service service,
AbstractConfigProducerRoot currentModel,
- AbstractConfigProducerRoot nextModel) {
- List<ChangesRequiringRestart> changes = findConfigChangesForService(service, currentModel, nextModel)
+ AbstractConfigProducerRoot nextModel,
+ DeployLogger logger) {
+ List<ChangesRequiringRestart> changes = findConfigChangesForService(service, currentModel, nextModel, logger)
.toList();
if (changes.isEmpty()) {
return Optional.empty();
@@ -70,14 +63,15 @@ public class ConfigValueChangeValidator implements ChangeValidator {
private Stream<ChangesRequiringRestart> findConfigChangesForService(Service service,
AbstractConfigProducerRoot currentModel,
- AbstractConfigProducerRoot nextModel) {
+ AbstractConfigProducerRoot nextModel,
+ DeployLogger logger) {
Class<? extends Service> serviceClass = service.getClass();
if (!currentModel.getService(service.getConfigId()).isPresent()) {
// Service does not exist in the current model.
return Stream.empty();
}
return getConfigInstancesFromServiceAnnotations(serviceClass)
- .map(configClass -> compareConfigFromCurrentAndNextModel(service, configClass, currentModel, nextModel))
+ .map(configClass -> compareConfigFromCurrentAndNextModel(service, configClass, currentModel, nextModel, logger))
.filter(Optional::isPresent)
.map(Optional::get)
.filter(ChangesRequiringRestart::needsRestart);
@@ -114,9 +108,11 @@ public class ConfigValueChangeValidator implements ChangeValidator {
.distinct();
}
- private Optional<ChangesRequiringRestart> compareConfigFromCurrentAndNextModel(
- Service service, Class<? extends ConfigInstance> configClass,
- AbstractConfigProducerRoot currentModel, AbstractConfigProducerRoot nextModel) {
+ private Optional<ChangesRequiringRestart> compareConfigFromCurrentAndNextModel(Service service,
+ Class<? extends ConfigInstance> configClass,
+ AbstractConfigProducerRoot currentModel,
+ AbstractConfigProducerRoot nextModel,
+ DeployLogger logger) {
if (!hasConfigFieldsFlaggedWithRestart(configClass, service.getClass())) {
logger.logApplicationPackage(Level.FINE, String.format("%s is listed in the annotation for %s, " +
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidator.java
index 3a0b1348d7e..0703d4fa3d6 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidator.java
@@ -2,18 +2,16 @@
package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.container.QrConfig;
import com.yahoo.vespa.model.VespaModel;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.vespa.model.container.ApplicationContainer;
import com.yahoo.vespa.model.container.Container;
import com.yahoo.vespa.model.container.ContainerCluster;
-import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
-import java.util.stream.Collectors;
/**
* Returns a restart action for each container that has turned on {@link QrConfig#restartOnDeploy()}.
@@ -23,8 +21,7 @@ import java.util.stream.Collectors;
public class ContainerRestartValidator implements ChangeValidator {
@Override
- public List<ConfigChangeAction> validate(VespaModel currentModel, VespaModel nextModel, ValidationOverrides ignored,
- Instant now) {
+ public List<ConfigChangeAction> validate(VespaModel currentModel, VespaModel nextModel, DeployState deployState) {
List<ConfigChangeAction> actions = new ArrayList<>();
for (ContainerCluster<ApplicationContainer> cluster : nextModel.getContainerClusters().values()) {
actions.addAll(cluster.getContainers().stream()
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentClusterRemovalValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentClusterRemovalValidator.java
index c33b349ced7..0cc52edf3cc 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentClusterRemovalValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentClusterRemovalValidator.java
@@ -2,12 +2,11 @@
package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.config.application.api.ValidationId;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.vespa.model.content.cluster.ContentCluster;
-import java.time.Instant;
import java.util.List;
/**
@@ -19,14 +18,14 @@ import java.util.List;
public class ContentClusterRemovalValidator implements ChangeValidator {
@Override
- public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, ValidationOverrides overrides, Instant now) {
+ public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, DeployState deployState) {
for (String currentClusterId : current.getContentClusters().keySet()) {
ContentCluster nextCluster = next.getContentClusters().get(currentClusterId);
if (nextCluster == null)
- overrides.invalid(ValidationId.contentClusterRemoval,
+ deployState.validationOverrides().invalid(ValidationId.contentClusterRemoval,
"Content cluster '" + currentClusterId + "' is removed. " +
"This will cause loss of all data in this cluster",
- now);
+ deployState.now());
}
return List.of();
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentTypeRemovalValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentTypeRemovalValidator.java
index b6b62ec3ac0..396cd471ca5 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentTypeRemovalValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ContentTypeRemovalValidator.java
@@ -2,13 +2,12 @@
package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.application.api.ValidationId;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.documentmodel.NewDocumentType;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.content.cluster.ContentCluster;
-import java.time.Instant;
import java.util.List;
/**
@@ -20,18 +19,18 @@ import java.util.List;
public class ContentTypeRemovalValidator implements ChangeValidator {
@Override
- public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, ValidationOverrides overrides, Instant now) {
+ public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, DeployState deployState) {
for (ContentCluster currentCluster : current.getContentClusters().values()) {
ContentCluster nextCluster = next.getContentClusters().get(currentCluster.getSubId());
if (nextCluster == null) continue; // validated elsewhere
for (NewDocumentType type : currentCluster.getDocumentDefinitions().values()) {
if ( ! nextCluster.getDocumentDefinitions().containsKey(type.getName())) {
- overrides.invalid(ValidationId.contentTypeRemoval,
+ deployState.validationOverrides().invalid(ValidationId.contentTypeRemoval,
"Schema '" + type.getName() + "' is removed " +
"in content cluster '" + currentCluster.getName() + "'. " +
"This will cause loss of all data in this schema",
- now);
+ deployState.now());
}
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/GlobalDocumentChangeValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/GlobalDocumentChangeValidator.java
index 43b5e646cc5..fe85da584c8 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/GlobalDocumentChangeValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/GlobalDocumentChangeValidator.java
@@ -2,13 +2,12 @@
package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.application.api.ValidationId;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.documentmodel.NewDocumentType;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.content.cluster.ContentCluster;
-import java.time.Instant;
import java.util.List;
import java.util.Map;
@@ -19,9 +18,8 @@ import java.util.Map;
public class GlobalDocumentChangeValidator implements ChangeValidator {
@Override
- public List<ConfigChangeAction> validate(VespaModel currentModel, VespaModel nextModel,
- ValidationOverrides overrides, Instant now) {
- if (!overrides.allows(ValidationId.globalDocumentChange.value(), now)) {
+ public List<ConfigChangeAction> validate(VespaModel currentModel, VespaModel nextModel, DeployState deployState) {
+ if (!deployState.validationOverrides().allows(ValidationId.globalDocumentChange.value(), deployState.now())) {
for (Map.Entry<String, ContentCluster> currentEntry : currentModel.getContentClusters().entrySet()) {
ContentCluster nextCluster = nextModel.getContentClusters().get(currentEntry.getKey());
if (nextCluster == null) continue;
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/IndexedSearchClusterChangeValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/IndexedSearchClusterChangeValidator.java
index 778ae604333..0a50c050b0b 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/IndexedSearchClusterChangeValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/IndexedSearchClusterChangeValidator.java
@@ -3,6 +3,7 @@ package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.model.api.ConfigChangeAction;
import com.yahoo.config.model.api.ServiceInfo;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.documentmodel.NewDocumentType;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.config.application.api.ValidationOverrides;
@@ -27,13 +28,12 @@ import java.util.stream.Collectors;
public class IndexedSearchClusterChangeValidator implements ChangeValidator {
@Override
- public List<ConfigChangeAction> validate(VespaModel current, VespaModel next,
- ValidationOverrides overrides, Instant now) {
+ public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, DeployState deployState) {
List<ConfigChangeAction> result = new ArrayList<>();
for (Map.Entry<String, ContentCluster> currentEntry : current.getContentClusters().entrySet()) {
ContentCluster nextCluster = next.getContentClusters().get(currentEntry.getKey());
if (nextCluster != null && nextCluster.getSearch().hasIndexedCluster()) {
- result.addAll(validateContentCluster(currentEntry.getValue(), nextCluster, overrides, now));
+ result.addAll(validateContentCluster(currentEntry.getValue(), nextCluster, deployState));
}
}
return result;
@@ -41,15 +41,13 @@ public class IndexedSearchClusterChangeValidator implements ChangeValidator {
private static List<ConfigChangeAction> validateContentCluster(ContentCluster currentCluster,
ContentCluster nextCluster,
- ValidationOverrides overrides,
- Instant now) {
- return validateDocumentDatabases(currentCluster, nextCluster, overrides, now);
+ DeployState deployState) {
+ return validateDocumentDatabases(currentCluster, nextCluster, deployState);
}
private static List<ConfigChangeAction> validateDocumentDatabases(ContentCluster currentCluster,
ContentCluster nextCluster,
- ValidationOverrides overrides,
- Instant now) {
+ DeployState deployState) {
List<ConfigChangeAction> result = new ArrayList<>();
for (DocumentDatabase currentDb : getDocumentDbs(currentCluster.getSearch())) {
String docTypeName = currentDb.getName();
@@ -57,7 +55,7 @@ public class IndexedSearchClusterChangeValidator implements ChangeValidator {
filter(db -> db.getName().equals(docTypeName)).findFirst();
if (nextDb.isPresent()) {
result.addAll(validateDocumentDatabase(currentCluster, nextCluster, docTypeName,
- currentDb, nextDb.get(), overrides, now));
+ currentDb, nextDb.get(), deployState));
}
}
return result;
@@ -68,8 +66,7 @@ public class IndexedSearchClusterChangeValidator implements ChangeValidator {
String docTypeName,
DocumentDatabase currentDb,
DocumentDatabase nextDb,
- ValidationOverrides overrides,
- Instant now) {
+ DeployState deployState) {
NewDocumentType currentDocType = currentCluster.getDocumentDefinitions().get(docTypeName);
NewDocumentType nextDocType = nextCluster.getDocumentDefinitions().get(docTypeName);
List<VespaConfigChangeAction> result =
@@ -78,8 +75,7 @@ public class IndexedSearchClusterChangeValidator implements ChangeValidator {
currentDocType,
nextDb,
nextDocType,
- overrides,
- now).validate();
+ deployState).validate();
return modifyActions(result, getSearchNodeServices(nextCluster.getSearch().getIndexed()), docTypeName);
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/IndexingModeChangeValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/IndexingModeChangeValidator.java
index 4acdda03166..b7e63fa4904 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/IndexingModeChangeValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/IndexingModeChangeValidator.java
@@ -2,16 +2,15 @@
package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.application.api.ValidationId;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.model.api.ConfigChangeAction;
import com.yahoo.config.model.api.ServiceInfo;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.documentmodel.NewDocumentType;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.content.ContentSearchCluster;
import com.yahoo.vespa.model.content.cluster.ContentCluster;
import com.yahoo.vespa.model.search.SearchNode;
-import java.time.Instant;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
@@ -28,8 +27,7 @@ import java.util.stream.Collectors;
public class IndexingModeChangeValidator implements ChangeValidator {
@Override
- public List<ConfigChangeAction> validate(VespaModel currentModel, VespaModel nextModel,
- ValidationOverrides overrides, Instant now) {
+ public List<ConfigChangeAction> validate(VespaModel currentModel, VespaModel nextModel, DeployState deployState) {
List<ConfigChangeAction> actions = new ArrayList<>();
for (Map.Entry<String, ContentCluster> currentEntry : currentModel.getContentClusters().entrySet()) {
ContentCluster nextCluster = nextModel.getContentClusters().get(currentEntry.getKey());
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidator.java
index 490fea40fab..7979c3c8069 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidator.java
@@ -1,8 +1,8 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.application.validation.change;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.HostSpec;
import com.yahoo.config.provision.NodeResources;
@@ -10,7 +10,6 @@ import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.container.ApplicationContainerCluster;
import com.yahoo.vespa.model.content.cluster.ContentCluster;
-import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -19,7 +18,7 @@ import java.util.stream.Collectors;
/**
* Emits restart change actions for clusters where the node resources are changed in a way
* which requires a "restart" (container recreation) to take effect.
- * Nodes will restart on their own on this condition but we want to emit restart actions to
+ * Nodes will restart on their own on this condition, but we want to emit restart actions to
* defer applying new config until restart.
*
* @author bratseth
@@ -27,7 +26,7 @@ import java.util.stream.Collectors;
public class NodeResourceChangeValidator implements ChangeValidator {
@Override
- public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, ValidationOverrides overrides, Instant now) {
+ public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, DeployState deployState) {
var restartActions = new ArrayList<ConfigChangeAction>();
for (ClusterSpec.Id clusterId : current.allClusters()) {
Optional<NodeResources> currentResources = resourcesOf(clusterId, current);
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/RedundancyIncreaseValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/RedundancyIncreaseValidator.java
index beea302d23d..82ad8e5d6e8 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/RedundancyIncreaseValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/RedundancyIncreaseValidator.java
@@ -2,34 +2,33 @@
package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.application.api.ValidationId;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.content.cluster.ContentCluster;
-import java.time.Instant;
import java.util.List;
/**
* Checks that redundancy is not increased (without a validation override),
- * as that may easily cause the cluster to run out of reasources.
+ * as that may easily cause the cluster to run out of resources.
*
* @author bratseth
*/
public class RedundancyIncreaseValidator implements ChangeValidator {
@Override
- public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, ValidationOverrides overrides, Instant now) {
+ public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, DeployState deployState) {
for (ContentCluster currentCluster : current.getContentClusters().values()) {
ContentCluster nextCluster = next.getContentClusters().get(currentCluster.getSubId());
if (nextCluster == null) continue;
if (redundancyOf(nextCluster) > redundancyOf(currentCluster)) {
- overrides.invalid(ValidationId.redundancyIncrease,
+ deployState.validationOverrides().invalid(ValidationId.redundancyIncrease,
"Increasing redundancy from " + redundancyOf(currentCluster) + " to " +
redundancyOf(nextCluster) + " in '" + currentCluster + ". " +
"This is a safe operation but verify that you have room for a " +
redundancyOf(nextCluster) + "/" + redundancyOf(currentCluster) + "x increase " +
"in content size",
- now);
+ deployState.now());
}
}
return List.of();
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ResourcesReductionValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ResourcesReductionValidator.java
index 6486b5aff1b..b27266221d2 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ResourcesReductionValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ResourcesReductionValidator.java
@@ -2,17 +2,15 @@
package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.application.api.ValidationId;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.vespa.model.VespaModel;
-import java.time.Instant;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
@@ -23,22 +21,18 @@ import java.util.stream.Stream;
public class ResourcesReductionValidator implements ChangeValidator {
@Override
- public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, ValidationOverrides overrides, Instant now) {
+ public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, DeployState deployState) {
for (var clusterId : current.allClusters()) {
Capacity currentCapacity = current.provisioned().all().get(clusterId);
Capacity nextCapacity = next.provisioned().all().get(clusterId);
if (currentCapacity == null || nextCapacity == null) continue;
- validate(currentCapacity, nextCapacity, clusterId, overrides, now);
+ validate(currentCapacity, nextCapacity, clusterId, deployState);
}
return List.of();
}
- private void validate(Capacity current,
- Capacity next,
- ClusterSpec.Id clusterId,
- ValidationOverrides overrides,
- Instant now) {
+ private void validate(Capacity current, Capacity next, ClusterSpec.Id clusterId, DeployState deployState) {
if (current.minResources().nodeResources().isUnspecified()) return;
if (next.minResources().nodeResources().isUnspecified()) return;
@@ -56,11 +50,11 @@ public class ResourcesReductionValidator implements ChangeValidator {
.toList();
if (illegalChanges.isEmpty()) return;
- overrides.invalid(ValidationId.resourcesReduction,
+ deployState.validationOverrides().invalid(ValidationId.resourcesReduction,
"Resource reduction in '" + clusterId.value() + "' is too large. " +
String.join(" ", illegalChanges) +
" New min resources must be at least 50% of the current min resources",
- now);
+ deployState.now());
}
private static Optional<String> validateResource(String resourceName, double currentValue, double nextValue) {
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/StartupCommandChangeValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/StartupCommandChangeValidator.java
index 1f5a54d6b0f..9ccedc4f5c4 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/StartupCommandChangeValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/StartupCommandChangeValidator.java
@@ -2,17 +2,15 @@
package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.model.producer.AbstractConfigProducerRoot;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.vespa.model.Service;
import com.yahoo.vespa.model.VespaModel;
-import com.yahoo.config.application.api.ValidationOverrides;
-import java.time.Instant;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
-import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
@@ -24,8 +22,7 @@ import java.util.stream.Stream;
public class StartupCommandChangeValidator implements ChangeValidator {
@Override
- public List<ConfigChangeAction> validate(VespaModel currentModel, VespaModel nextModel,
- ValidationOverrides overrides, Instant now) {
+ public List<ConfigChangeAction> validate(VespaModel currentModel, VespaModel nextModel, DeployState deployState) {
return findServicesWithChangedStartupCommand(currentModel, nextModel).toList();
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/StreamingSearchClusterChangeValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/StreamingSearchClusterChangeValidator.java
index 83d723398a6..ffab63740b9 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/StreamingSearchClusterChangeValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/StreamingSearchClusterChangeValidator.java
@@ -1,9 +1,9 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.application.validation.change;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.model.api.ConfigChangeAction;
import com.yahoo.config.model.api.ServiceInfo;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.documentmodel.NewDocumentType;
import com.yahoo.schema.derived.AttributeFields;
@@ -15,7 +15,6 @@ import com.yahoo.vespa.model.application.validation.change.search.DocumentTypeCh
import com.yahoo.vespa.model.content.cluster.ContentCluster;
import com.yahoo.vespa.model.search.StreamingSearchCluster;
-import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -29,7 +28,7 @@ import java.util.stream.Collectors;
public class StreamingSearchClusterChangeValidator implements ChangeValidator {
@Override
- public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, ValidationOverrides overrides, Instant now) {
+ public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, DeployState deployState) {
List<ConfigChangeAction> result = new ArrayList<>();
current.getContentClusters().forEach((clusterName, currentCluster) -> {
ContentCluster nextCluster = next.getContentClusters().get(clusterName);
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/search/AttributeChangeValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/search/AttributeChangeValidator.java
index 838c96a8249..f23a7720157 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/search/AttributeChangeValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/search/AttributeChangeValidator.java
@@ -2,7 +2,7 @@
package com.yahoo.vespa.model.application.validation.change.search;
import com.yahoo.config.application.api.ValidationId;
-import com.yahoo.config.application.api.ValidationOverrides;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.documentmodel.NewDocumentType;
import com.yahoo.schema.derived.AttributeFields;
@@ -14,7 +14,6 @@ import com.yahoo.schema.document.HnswIndexParams;
import com.yahoo.vespa.model.application.validation.change.VespaConfigChangeAction;
import com.yahoo.vespa.model.application.validation.change.VespaRestartAction;
-import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -36,8 +35,7 @@ public class AttributeChangeValidator {
private final AttributeFields nextFields;
private final IndexSchema nextIndexSchema;
private final NewDocumentType nextDocType;
- private final ValidationOverrides overrides;
- private final Instant now;
+ private final DeployState deployState;
public AttributeChangeValidator(ClusterSpec.Id id,
AttributeFields currentFields,
@@ -46,8 +44,7 @@ public class AttributeChangeValidator {
AttributeFields nextFields,
IndexSchema nextIndexSchema,
NewDocumentType nextDocType,
- ValidationOverrides overrides,
- Instant now) {
+ DeployState deployState) {
this.id = id;
this.currentFields = currentFields;
this.currentIndexSchema = currentIndexSchema;
@@ -55,8 +52,7 @@ public class AttributeChangeValidator {
this.nextFields = nextFields;
this.nextIndexSchema = nextIndexSchema;
this.nextDocType = nextDocType;
- this.overrides = overrides;
- this.now = now;
+ this.deployState = deployState;
}
public List<VespaConfigChangeAction> validate() {
@@ -167,10 +163,10 @@ public class AttributeChangeValidator {
private void validatePagedAttributeRemoval(Attribute current, Attribute next) {
if (current.isPaged() && !next.isPaged()) {
- overrides.invalid(ValidationId.pagedSettingRemoval,
+ deployState.validationOverrides().invalid(ValidationId.pagedSettingRemoval,
current + "' has setting 'paged' removed. " +
"This may cause content nodes to run out of memory as the entire attribute is loaded into memory",
- now);
+ deployState.now());
}
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/search/DocumentDatabaseChangeValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/search/DocumentDatabaseChangeValidator.java
index 55fc268e805..bbe79f0ecc8 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/search/DocumentDatabaseChangeValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/search/DocumentDatabaseChangeValidator.java
@@ -1,13 +1,12 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.application.validation.change.search;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.documentmodel.NewDocumentType;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.vespa.model.application.validation.change.VespaConfigChangeAction;
import com.yahoo.vespa.model.search.DocumentDatabase;
-import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
@@ -23,23 +22,20 @@ public class DocumentDatabaseChangeValidator {
private final NewDocumentType currentDocType;
private final DocumentDatabase nextDatabase;
private final NewDocumentType nextDocType;
- private final ValidationOverrides overrides;
- private final Instant now;
+ private final DeployState deployState;
public DocumentDatabaseChangeValidator(ClusterSpec.Id id,
DocumentDatabase currentDatabase,
NewDocumentType currentDocType,
DocumentDatabase nextDatabase,
NewDocumentType nextDocType,
- ValidationOverrides overrides,
- Instant now) {
+ DeployState deployState) {
this.id = id;
this.currentDatabase = currentDatabase;
this.currentDocType = currentDocType;
this.nextDatabase = nextDatabase;
this.nextDocType = nextDocType;
- this.overrides = overrides;
- this.now = now;
+ this.deployState = deployState;
}
public List<VespaConfigChangeAction> validate() {
@@ -57,7 +53,7 @@ public class DocumentDatabaseChangeValidator {
currentDatabase.getDerivedConfiguration().getIndexSchema(), currentDocType,
nextDatabase.getDerivedConfiguration().getAttributeFields(),
nextDatabase.getDerivedConfiguration().getIndexSchema(), nextDocType,
- overrides, now)
+ deployState)
.validate();
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/first/RedundancyOnFirstDeploymentValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/first/RedundancyOnFirstDeploymentValidator.java
deleted file mode 100644
index b0cfc832389..00000000000
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/first/RedundancyOnFirstDeploymentValidator.java
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.model.application.validation.first;
-
-import com.yahoo.config.application.api.ValidationId;
-import com.yahoo.config.model.deploy.DeployState;
-import com.yahoo.vespa.model.VespaModel;
-import com.yahoo.vespa.model.application.validation.Validator;
-import com.yahoo.vespa.model.content.cluster.ContentCluster;
-
-/**
- * Validates that applications in prod zones do not have redundancy 1 (without a validation override).
- *
- * @author bratseth
- */
-public class RedundancyOnFirstDeploymentValidator extends Validator {
-
- @Override
- public void validate(VespaModel model, DeployState deployState) {
- if ( ! deployState.isHosted()) return;
- if ( ! deployState.zone().environment().isProduction()) return;
-
- for (ContentCluster cluster : model.getContentClusters().values()) {
- if (cluster.redundancy().finalRedundancy() == 1 && cluster.redundancy().groups() == 1)
- deployState.validationOverrides().invalid(ValidationId.redundancyOne,
- cluster + " has redundancy 1, which will cause it to lose data " +
- "if a node fails. This requires an override on first deployment " +
- "in a production zone",
- deployState.now());
- }
- }
-
-}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/first/RedundancyValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/first/RedundancyValidator.java
new file mode 100644
index 00000000000..5228610537f
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/first/RedundancyValidator.java
@@ -0,0 +1,62 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.model.application.validation.first;
+
+import com.yahoo.config.application.api.ValidationId;
+import com.yahoo.config.application.api.ValidationOverrides;
+import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.config.model.deploy.DeployState;
+import com.yahoo.vespa.model.VespaModel;
+import com.yahoo.vespa.model.application.validation.Validator;
+import com.yahoo.vespa.model.application.validation.change.ChangeValidator;
+import com.yahoo.vespa.model.content.cluster.ContentCluster;
+
+import java.time.Instant;
+import java.util.List;
+import java.util.stream.Stream;
+
+/**
+ * Validates that applications in prod zones do not have redundancy 1 (without a validation override).
+ *
+ * @author bratseth
+ */
+public class RedundancyValidator extends Validator implements ChangeValidator {
+
+ /** Validate on first deployment. */
+ @Override
+ public void validate(VespaModel model, DeployState deployState) {
+ if ( ! shouldValidate(deployState)) return;
+ clustersWithRedundancyOne(model).forEach(cluster -> invalidRedundancy(cluster, deployState));
+ }
+
+ /** Validate on change. */
+ @Override
+ public List<ConfigChangeAction> validate(VespaModel current, VespaModel next, DeployState deployState) {
+ if ( ! shouldValidate(deployState)) return List.of();
+
+ clustersWithRedundancyOne(next)
+ .filter(cluster -> ! hasRedundancyOne(current.getContentClusters().get(cluster.id().value())))
+ .forEach(cluster -> invalidRedundancy(cluster, deployState));
+ return List.of();
+ }
+
+ private boolean shouldValidate(DeployState deployState) {
+ return deployState.isHosted() && deployState.zone().environment().isProduction();
+ }
+
+ private Stream<ContentCluster> clustersWithRedundancyOne(VespaModel model) {
+ return model.getContentClusters().values().stream().filter(cluster -> hasRedundancyOne(cluster));
+ }
+
+ private boolean hasRedundancyOne(ContentCluster cluster) {
+ return cluster != null && cluster.redundancy().finalRedundancy() == 1 && cluster.redundancy().groups() == 1;
+ }
+
+ private void invalidRedundancy(ContentCluster cluster, DeployState deployState) {
+ deployState.validationOverrides().invalid(ValidationId.redundancyOne,
+ cluster + " has redundancy 1, which will cause it to lose data " +
+ "if a node fails. This requires an override on first deployment " +
+ "in a production zone",
+ deployState.now());
+ }
+
+}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/search/ContainerSearch.java b/config-model/src/main/java/com/yahoo/vespa/model/container/search/ContainerSearch.java
index 7a0b6c8e023..f949f2d5cfc 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/search/ContainerSearch.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/search/ContainerSearch.java
@@ -5,9 +5,7 @@ import com.yahoo.container.QrSearchersConfig;
import com.yahoo.prelude.semantics.SemanticRulesConfig;
import com.yahoo.search.config.IndexInfoConfig;
import com.yahoo.search.config.SchemaInfoConfig;
-import com.yahoo.search.handler.observability.SearchStatusExtension;
import com.yahoo.search.pagetemplates.PageTemplatesConfig;
-import com.yahoo.search.query.profile.compiled.CompiledQueryProfileRegistry;
import com.yahoo.search.query.profile.config.QueryProfilesConfig;
import com.yahoo.schema.derived.SchemaInfo;
import com.yahoo.vespa.configdefinition.IlscriptsConfig;
@@ -20,7 +18,6 @@ import com.yahoo.vespa.model.search.IndexedSearchCluster;
import com.yahoo.vespa.model.search.StreamingSearchCluster;
import java.util.Collection;
-import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -41,24 +38,24 @@ public class ContainerSearch extends ContainerSubsystem<SearchChains>
PageTemplatesConfig.Producer,
SchemaInfoConfig.Producer {
- public static final String QUERY_PROFILE_REGISTRY_CLASS = CompiledQueryProfileRegistry.class.getName();
+ public static final String QUERY_PROFILE_REGISTRY_CLASS = "com.yahoo.search.query.profile.compiled.CompiledQueryProfileRegistry";
+ private static final String SEARCH_STATUS_EXTENSION_CLASS = "com.yahoo.search.handler.observability.SearchStatusExtension";
+ private static final String SCHEMA_INFO_CLASS = "com.yahoo.search.schema.SchemaInfo";
private final ApplicationContainerCluster owningCluster;
private final List<SearchCluster> searchClusters = new LinkedList<>();
- private final Options options;
private QueryProfiles queryProfiles;
private SemanticRules semanticRules;
private PageTemplates pageTemplates;
- public ContainerSearch(ApplicationContainerCluster cluster, SearchChains chains, Options options) {
+ public ContainerSearch(ApplicationContainerCluster cluster, SearchChains chains) {
super(chains);
this.owningCluster = cluster;
- this.options = options;
owningCluster.addComponent(Component.fromClassAndBundle(QUERY_PROFILE_REGISTRY_CLASS, SEARCH_AND_DOCPROC_BUNDLE));
- owningCluster.addComponent(Component.fromClassAndBundle(com.yahoo.search.schema.SchemaInfo.class.getName(), SEARCH_AND_DOCPROC_BUNDLE));
- owningCluster.addComponent(Component.fromClassAndBundle(SearchStatusExtension.class.getName(), SEARCH_AND_DOCPROC_BUNDLE));
+ owningCluster.addComponent(Component.fromClassAndBundle(SCHEMA_INFO_CLASS, SEARCH_AND_DOCPROC_BUNDLE));
+ owningCluster.addComponent(Component.fromClassAndBundle(SEARCH_STATUS_EXTENSION_CLASS, SEARCH_AND_DOCPROC_BUNDLE));
cluster.addSearchAndDocprocBundles();
}
@@ -159,15 +156,4 @@ public class ContainerSearch extends ContainerSubsystem<SearchChains>
throw new IllegalArgumentException("No search cluster with index " + index + " exists");
}
- public Options getOptions() {
- return options;
- }
-
- /** Encapsulates qrserver options. */
- public static class Options {
-
- Map<String, QrsCache> cacheSettings = new LinkedHashMap<>();
-
- }
-
}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
index e7aaed163dc..e07b1a95e20 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
@@ -730,7 +730,7 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
SearchChains searchChains = new DomSearchChainsBuilder()
.build(deployState, containerCluster, producerSpec);
- ContainerSearch containerSearch = new ContainerSearch(containerCluster, searchChains, new ContainerSearch.Options());
+ ContainerSearch containerSearch = new ContainerSearch(containerCluster, searchChains);
applyApplicationPackageDirectoryConfigs(deployState.getApplicationPackage(), containerSearch);
containerSearch.setQueryProfiles(deployState.getQueryProfiles());
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/search/SearchCluster.java b/config-model/src/main/java/com/yahoo/vespa/model/search/SearchCluster.java
index 71f2eff8651..c5f5c9a99a5 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/search/SearchCluster.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/search/SearchCluster.java
@@ -15,7 +15,6 @@ import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.stream.Collectors;
/**
* Represents a search cluster.
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/CertificateRemovalChangeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/CertificateRemovalChangeValidatorTest.java
index 6b6621239b0..b955ada20d9 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/CertificateRemovalChangeValidatorTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/CertificateRemovalChangeValidatorTest.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.application.api.ValidationOverrides;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.security.X509CertificateUtils;
import com.yahoo.vespa.model.container.http.Client;
import org.junit.jupiter.api.Test;
@@ -38,18 +39,22 @@ public class CertificateRemovalChangeValidatorTest {
CertificateRemovalChangeValidator validator = new CertificateRemovalChangeValidator();
// Adding certs -> ok
- validator.validateClients("clusterId", List.of(c1, c2), List.of(c1, c2, c3), ValidationOverrides.empty, now);
+ validator.validateClients("clusterId", List.of(c1, c2), List.of(c1, c2, c3), new DeployState.Builder().now(now).build());
// Removing certs -> fails
assertThrows(ValidationOverrides.ValidationException.class,
- () ->validator.validateClients("clusterId", List.of(c1, c2, c3), List.of(c1, c3), ValidationOverrides.empty, now));
+ () ->validator.validateClients("clusterId", List.of(c1, c2, c3), List.of(c1, c3),
+ new DeployState.Builder().now(now).build()));
// Removing certs with validationoverrides -> ok
- validator.validateClients("clusterId", List.of(c1, c2, c3), List.of(c1, c3), ValidationOverrides.fromXml(validationOverrides), now);
+ validator.validateClients("clusterId", List.of(c1, c2, c3), List.of(c1, c3),
+ new DeployState.Builder().now(now).validationOverrides(ValidationOverrides.fromXml(validationOverrides)).build());
// Adding and removing internal certs are ok:
- validator.validateClients("clusterId", List.of(c1, c2), List.of(c1, c2, internal), ValidationOverrides.empty, now);
- validator.validateClients("clusterId", List.of(c1, c2, internal), List.of(c1, c2), ValidationOverrides.empty, now);
+ validator.validateClients("clusterId", List.of(c1, c2), List.of(c1, c2, internal),
+ new DeployState.Builder().build());
+ validator.validateClients("clusterId", List.of(c1, c2, internal), List.of(c1, c2),
+ new DeployState.Builder().now(now).build());
}
static X509Certificate certificate(String cn) {
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/CloudAccountChangeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/CloudAccountChangeValidatorTest.java
index aa16927777c..fcc8c82a6e9 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/CloudAccountChangeValidatorTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/CloudAccountChangeValidatorTest.java
@@ -1,7 +1,6 @@
package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.provision.IntRange;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.model.api.Provisioned;
import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.model.deploy.TestProperties;
@@ -14,7 +13,6 @@ import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.test.utils.VespaModelCreatorWithMockPkg;
import org.junit.jupiter.api.Test;
-import java.time.Instant;
import java.util.List;
import java.util.Optional;
@@ -33,15 +31,15 @@ class CloudAccountChangeValidatorTest {
CloudAccountChangeValidator validator = new CloudAccountChangeValidator();
try {
- validator.validate(model0, model1, ValidationOverrides.empty, Instant.now());
+ validator.validate(model0, model1, new DeployState.Builder().build());
fail("Expected exception");
} catch (IllegalArgumentException e) {
assertEquals(e.getMessage(), "Cannot change cloud account from unspecified account to " +
"account '000000000000'. The existing deployment must be removed before " +
"changing accounts");
}
- assertEquals(List.of(), validator.validate(model0, model0, ValidationOverrides.empty, Instant.now()));
- assertEquals(List.of(), validator.validate(model1, model1, ValidationOverrides.empty, Instant.now()));
+ assertEquals(List.of(), validator.validate(model0, model0, new DeployState.Builder().build()));
+ assertEquals(List.of(), validator.validate(model1, model1, new DeployState.Builder().build()));
}
private static Provisioned provisioned(Capacity... capacity) {
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ConfigValueChangeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ConfigValueChangeValidatorTest.java
index 9705bc83e2b..069bf429b41 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ConfigValueChangeValidatorTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ConfigValueChangeValidatorTest.java
@@ -1,6 +1,7 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.application.validation.change;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.test.AnotherrestartConfig;
import com.yahoo.config.ConfigInstance;
import com.yahoo.test.RestartConfig;
@@ -15,14 +16,11 @@ import com.yahoo.vespa.model.HostResource;
import com.yahoo.vespa.model.PortAllocBridge;
import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.application.validation.RestartConfigs;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.vespa.model.test.utils.DeployLoggerStub;
import com.yahoo.vespa.model.test.utils.VespaModelCreatorWithMockPkg;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import java.time.Instant;
-import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
@@ -49,7 +47,7 @@ public class ConfigValueChangeValidatorTest {
* {@link com.yahoo.vespa.model.application.validation.RestartConfigs} attribute.
* 3) That the config ids for the container services have a specific value.
*
- * This test will to a certain degree ensure that the annotations in the VespaModel is correctly applied.
+ * This test will to a certain degree ensure that the annotations in the VespaModel is correctly applied.
*/
@Test
void requireThatValidatorHandlesVespaModel() {
@@ -66,8 +64,8 @@ public class ConfigValueChangeValidatorTest {
@Test
void requireThatDocumentTypesCanBeAddedWithoutNeedForRestart() {
List<ConfigChangeAction> changes = getConfigChanges(
- createVespaModel("", Arrays.asList("foo")),
- createVespaModel("", Arrays.asList("foo", "bar")));
+ createVespaModel("", List.of("foo")),
+ createVespaModel("", List.of("foo", "bar")));
assertEquals(0, changes.size());
}
@@ -154,14 +152,14 @@ public class ConfigValueChangeValidatorTest {
}
private List<ConfigChangeAction> getConfigChanges(VespaModel currentModel, VespaModel nextModel) {
- ConfigValueChangeValidator validator = new ConfigValueChangeValidator(logger);
- return validator.validate(currentModel, nextModel, ValidationOverrides.empty, Instant.now());
+ ConfigValueChangeValidator validator = new ConfigValueChangeValidator();
+ return validator.validate(currentModel, nextModel, new DeployState.Builder().deployLogger(logger).build());
}
private List<ConfigChangeAction> getConfigChanges(AbstractConfigProducerRoot currentModel,
AbstractConfigProducerRoot nextModel) {
- ConfigValueChangeValidator validator = new ConfigValueChangeValidator(logger);
- return validator.findConfigChangesFromModels(currentModel, nextModel).toList();
+ ConfigValueChangeValidator validator = new ConfigValueChangeValidator();
+ return validator.findConfigChangesFromModels(currentModel, nextModel, logger).toList();
}
private static void assertComponentsEquals(List<ConfigChangeAction> changes, String name, int index) {
@@ -173,7 +171,7 @@ public class ConfigValueChangeValidatorTest {
}
private static VespaModel createVespaModel(String configSegment) {
- return createVespaModel(configSegment, Arrays.asList("music"));
+ return createVespaModel(configSegment, List.of("music"));
}
private static VespaModel createVespaModel(String configSegment, List<String> docTypes) {
@@ -233,7 +231,7 @@ public class ConfigValueChangeValidatorTest {
private static MockRoot createRootWithChildren(AbstractConfigProducer<?>... children) {
MockRoot root = new MockRoot();
- Arrays.asList(children).forEach(root::addChild);
+ List.of(children).forEach(root::addChild);
root.freezeModelTopology();
return root;
}
@@ -269,7 +267,7 @@ public class ConfigValueChangeValidatorTest {
}
public SimpleConfigProducer withChildren(AbstractConfigProducer<?>... producer) {
- Arrays.asList(producer).forEach(this::addChild);
+ List.of(producer).forEach(this::addChild);
return this;
}
}
@@ -323,5 +321,6 @@ public class ConfigValueChangeValidatorTest {
super(name);
}
}
+
}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidatorTest.java
index e3d6b1ac965..c034944c8ae 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidatorTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContainerRestartValidatorTest.java
@@ -2,14 +2,12 @@
package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.model.api.ConfigChangeAction;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.vespa.defaults.Defaults;
import com.yahoo.vespa.model.VespaModel;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.vespa.model.test.utils.VespaModelCreatorWithMockPkg;
import org.junit.jupiter.api.Test;
-import java.time.Instant;
-import java.util.Collections;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@@ -57,8 +55,7 @@ public class ContainerRestartValidatorTest {
}
private static List<ConfigChangeAction> validateModel(VespaModel current, VespaModel next) {
- return new ContainerRestartValidator()
- .validate(current, next, new ValidationOverrides(Collections.emptyList()), Instant.now());
+ return new ContainerRestartValidator().validate(current, next, new DeployState.Builder().build());
}
private static VespaModel createModel(boolean restartOnDeploy) {
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContentClusterRemovalValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContentClusterRemovalValidatorTest.java
index 25ce7252ea8..5c360a9343f 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContentClusterRemovalValidatorTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContentClusterRemovalValidatorTest.java
@@ -17,7 +17,7 @@ import static org.junit.jupiter.api.Assertions.fail;
*/
public class ContentClusterRemovalValidatorTest {
- private final ValidationTester tester = new ValidationTester(5);
+ private final ValidationTester tester = new ValidationTester(8);
@Test
void testContentRemovalValidation() {
@@ -42,14 +42,14 @@ public class ContentClusterRemovalValidatorTest {
private static String getServices(String contentClusterId) {
return "<services version='1.0'>" +
" <content id='" + contentClusterId + "' version='1.0'>" +
- " <redundancy>1</redundancy>" +
+ " <redundancy>2</redundancy>" +
" <engine>" +
" <proton/>" +
" </engine>" +
" <documents>" +
" <document type='music' mode='index'/>" +
" </documents>" +
- " <nodes count='1'/>" +
+ " <nodes count='2'/>" +
" </content>" +
"</services>";
}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/IndexedSchemaClusterChangeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/IndexedSchemaClusterChangeValidatorTest.java
index 309ad4094e4..027bc706067 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/IndexedSchemaClusterChangeValidatorTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/IndexedSchemaClusterChangeValidatorTest.java
@@ -4,15 +4,14 @@ package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.application.api.ValidationId;
import com.yahoo.config.model.api.ConfigChangeAction;
import com.yahoo.config.model.api.ServiceInfo;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.vespa.model.VespaModel;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.vespa.model.content.utils.ApplicationPackageBuilder;
import com.yahoo.vespa.model.content.utils.ContentClusterBuilder;
import com.yahoo.vespa.model.content.utils.SchemaBuilder;
import org.junit.jupiter.api.Test;
-import java.time.Instant;
import java.util.List;
import static com.yahoo.vespa.model.application.validation.change.ConfigChangeTestUtils.assertEqualActions;
@@ -72,7 +71,7 @@ public class IndexedSchemaClusterChangeValidatorTest {
private List<ConfigChangeAction> validate() {
return normalizeServicesInActions(validator.validate(currentModel, nextModel,
- ValidationOverrides.empty, Instant.now()));
+ new DeployState.Builder().build()));
}
public void assertValidation() {
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidatorTest.java
index d0cc4a605bc..7080a3e0f12 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidatorTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/NodeResourceChangeValidatorTest.java
@@ -1,7 +1,6 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.model.application.validation.change;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.config.model.api.ConfigChangeAction;
import com.yahoo.config.model.api.HostProvisioner;
import com.yahoo.config.model.deploy.DeployState;
@@ -15,7 +14,6 @@ import com.yahoo.vespa.model.VespaModel;
import com.yahoo.vespa.model.test.utils.VespaModelCreatorWithMockPkg;
import org.junit.jupiter.api.Test;
-import java.time.Clock;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -56,9 +54,7 @@ public class NodeResourceChangeValidatorTest {
}
private List<ConfigChangeAction> validate(VespaModel current, VespaModel next) {
- return new NodeResourceChangeValidator().validate(current, next,
- ValidationOverrides.empty,
- Clock.systemUTC().instant());
+ return new NodeResourceChangeValidator().validate(current, next, new DeployState.Builder().build());
}
private static VespaModel model(int mem1, int mem2, int mem3, int mem4) {
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RedundancyChangeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RedundancyChangeValidatorTest.java
new file mode 100644
index 00000000000..9709c975f8e
--- /dev/null
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/RedundancyChangeValidatorTest.java
@@ -0,0 +1,65 @@
+package com.yahoo.vespa.model.application.validation.change;
+
+import com.yahoo.config.provision.Environment;
+import com.yahoo.vespa.model.VespaModel;
+import com.yahoo.vespa.model.application.validation.ValidationTester;
+import com.yahoo.yolean.Exceptions;
+import org.junit.jupiter.api.Test;
+
+import static com.yahoo.test.JunitCompat.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+/**
+ * @author bratseth
+ */
+public class RedundancyChangeValidatorTest {
+
+ private static final String redundancyOverride =
+ "<validation-overrides>\n" +
+ " <allow until='2000-01-03'>redundancy-one</allow>\n" +
+ "</validation-overrides>\n";
+
+ @Test
+ public void testChangingRedundancyToOne() {
+ try {
+ var tester = new ValidationTester(6);
+ VespaModel previous = tester.deploy(null, getServices("test", 2), Environment.prod, null).getFirst();
+ tester.deploy(previous, getServices("test", 1), Environment.prod, null);
+ fail("Expected exception");
+ }
+ catch (IllegalArgumentException e) {
+ assertEquals("redundancy-one: content cluster 'test' has redundancy 1, which will cause it to lose data if a node fails. " +
+ "This requires an override on first deployment in a production zone. " +
+ "To allow this add <allow until='yyyy-mm-dd'>redundancy-one</allow> to validation-overrides.xml, " +
+ "see https://docs.vespa.ai/en/reference/validation-overrides.html",
+ Exceptions.toMessageString(e));
+ }
+
+ }
+
+ @Test
+ public void testChangingRedundancyToOneWithValidationOverride() {
+ var tester = new ValidationTester(6);
+ VespaModel previous = tester.deploy(null, getServices("test", 2), Environment.prod, null).getFirst();
+ previous = tester.deploy(previous, getServices("test", 1), Environment.prod, redundancyOverride).getFirst();
+
+ // Staying at one does not require an override
+ tester.deploy(previous, getServices("test", 1), Environment.prod, null);
+ }
+
+ private static String getServices(String contentClusterId, int redundancy) {
+ return "<services version='1.0'>" +
+ " <content id='" + contentClusterId + "' version='1.0'>" +
+ " <redundancy>" + redundancy + "</redundancy>" +
+ " <engine>" +
+ " <proton/>" +
+ " </engine>" +
+ " <documents>" +
+ " <document type='music' mode='index'/>" +
+ " </documents>" +
+ " <nodes count='2'/>" +
+ " </content>" +
+ "</services>";
+ }
+
+}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/StreamingSchemaClusterChangeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/StreamingSchemaClusterChangeValidatorTest.java
index 92f2cf61c36..5c5c86e3f3d 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/StreamingSchemaClusterChangeValidatorTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/StreamingSchemaClusterChangeValidatorTest.java
@@ -4,17 +4,15 @@ package com.yahoo.vespa.model.application.validation.change;
import com.yahoo.config.application.api.ValidationId;
import com.yahoo.config.model.api.ConfigChangeAction;
import com.yahoo.config.model.api.ServiceInfo;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.vespa.model.VespaModel;
-import com.yahoo.config.application.api.ValidationOverrides;
import com.yahoo.vespa.model.content.utils.ApplicationPackageBuilder;
import com.yahoo.vespa.model.content.utils.ContentClusterBuilder;
import com.yahoo.vespa.model.content.utils.DocType;
import com.yahoo.vespa.model.content.utils.SchemaBuilder;
import org.junit.jupiter.api.Test;
-import java.time.Instant;
-import java.util.Arrays;
import java.util.List;
import static com.yahoo.vespa.model.application.validation.change.ConfigChangeTestUtils.assertEqualActions;
@@ -40,7 +38,7 @@ public class StreamingSchemaClusterChangeValidatorTest {
public static VespaModel createOneDocModel(String sdContent) {
return new ApplicationPackageBuilder()
- .addCluster(new ContentClusterBuilder().name("foo").docTypes(Arrays.asList(DocType.streaming("d1"))))
+ .addCluster(new ContentClusterBuilder().name("foo").docTypes(List.of(DocType.streaming("d1"))))
.addSchemas(new SchemaBuilder().name("d1").content(sdContent).build())
.buildCreator().create();
}
@@ -51,7 +49,7 @@ public class StreamingSchemaClusterChangeValidatorTest {
public static VespaModel createTwoDocModel(String d1Content, String d2Content) {
return new ApplicationPackageBuilder()
- .addCluster(new ContentClusterBuilder().name("foo").docTypes(Arrays.asList(DocType.streaming("d1"), DocType.streaming("d2"))))
+ .addCluster(new ContentClusterBuilder().name("foo").docTypes(List.of(DocType.streaming("d1"), DocType.streaming("d2"))))
.addSchemas(new SchemaBuilder().name("d1").content(d1Content).build())
.addSchemas(new SchemaBuilder().name("d2").content(d2Content).build())
.buildCreator().create();
@@ -63,8 +61,8 @@ public class StreamingSchemaClusterChangeValidatorTest {
public static VespaModel createTwoClusterModel(String d1Content, String d2Content) {
return new ApplicationPackageBuilder()
- .addCluster(new ContentClusterBuilder().name("foo").docTypes(Arrays.asList(DocType.streaming("d1"))))
- .addCluster(new ContentClusterBuilder().name("bar").docTypes(Arrays.asList(DocType.streaming("d2"))))
+ .addCluster(new ContentClusterBuilder().name("foo").docTypes(List.of(DocType.streaming("d1"))))
+ .addCluster(new ContentClusterBuilder().name("bar").docTypes(List.of(DocType.streaming("d2"))))
.addSchemas(new SchemaBuilder().name("d1").content(d1Content).build())
.addSchemas(new SchemaBuilder().name("d2").content(d2Content).build())
.buildCreator().create();
@@ -72,7 +70,7 @@ public class StreamingSchemaClusterChangeValidatorTest {
public List<ConfigChangeAction> validate() {
return normalizeServicesInActions(validator.validate(currentModel, nextModel,
- ValidationOverrides.empty, Instant.now()));
+ new DeployState.Builder().build()));
}
public void assertValidation() {
@@ -80,7 +78,7 @@ public class StreamingSchemaClusterChangeValidatorTest {
}
public void assertValidation(ConfigChangeAction exp) {
- assertValidation(Arrays.asList(exp));
+ assertValidation(List.of(exp));
}
public void assertValidation(List<ConfigChangeAction> exp) {
@@ -88,14 +86,14 @@ public class StreamingSchemaClusterChangeValidatorTest {
}
}
- private static String STRING_FIELD = "field f1 type string { indexing: summary }";
- private static String INT_FIELD = "field f1 type int { indexing: summary }";
- private static String ATTRIBUTE_INT_FIELD = "field f1 type int { indexing: attribute | summary }";
- private static String ATTRIBUTE_FAST_ACCESS_INT_FIELD = "field f1 type int { indexing: attribute | summary \n attribute: fast-access }";
- private static List<ServiceInfo> FOO_SERVICE = Arrays.asList(
- new ServiceInfo("searchnode", "null", null, null, "foo/search/0", "null"));
- private static List<ServiceInfo> BAR_SERVICE = Arrays.asList(
- new ServiceInfo("searchnode2", "null", null, null, "bar/search/0", "null"));
+ private static final String STRING_FIELD = "field f1 type string { indexing: summary }";
+ private static final String INT_FIELD = "field f1 type int { indexing: summary }";
+ private static final String ATTRIBUTE_INT_FIELD = "field f1 type int { indexing: attribute | summary }";
+ private static final String ATTRIBUTE_FAST_ACCESS_INT_FIELD = "field f1 type int { indexing: attribute | summary \n attribute: fast-access }";
+ private static final List<ServiceInfo> FOO_SERVICE =
+ List.of(new ServiceInfo("searchnode", "null", null, null, "foo/search/0", "null"));
+ private static final List<ServiceInfo> BAR_SERVICE =
+ List.of(new ServiceInfo("searchnode2", "null", null, null, "bar/search/0", "null"));
@Test
void changing_field_type_requires_refeed() {
@@ -106,17 +104,15 @@ public class StreamingSchemaClusterChangeValidatorTest {
@Test
void changes_in_multiple_streaming_clusters_are_discovered() {
Fixture.withTwoClusters(STRING_FIELD, INT_FIELD)
- .assertValidation(Arrays.asList(
- createFieldTypeChangeRefeedAction("d1", FOO_SERVICE),
- createFieldTypeChangeRefeedAction("d2", BAR_SERVICE)));
+ .assertValidation(List.of(createFieldTypeChangeRefeedAction("d1", FOO_SERVICE),
+ createFieldTypeChangeRefeedAction("d2", BAR_SERVICE)));
}
@Test
void changes_in_multiple_document_types_are_discovered() {
Fixture.withTwoDocTypes(STRING_FIELD, INT_FIELD)
- .assertValidation(Arrays.asList(
- createFieldTypeChangeRefeedAction("d1", FOO_SERVICE),
- createFieldTypeChangeRefeedAction("d2", FOO_SERVICE)));
+ .assertValidation(List.of(createFieldTypeChangeRefeedAction("d1", FOO_SERVICE),
+ createFieldTypeChangeRefeedAction("d2", FOO_SERVICE)));
}
@Test
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/search/AttributeChangeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/search/AttributeChangeValidatorTest.java
index 076d78912e8..adecbf42884 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/search/AttributeChangeValidatorTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/search/AttributeChangeValidatorTest.java
@@ -3,8 +3,8 @@ package com.yahoo.vespa.model.application.validation.change.search;
import com.yahoo.config.application.api.ValidationId;
import com.yahoo.config.application.api.ValidationOverrides;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.test.ManualClock;
import com.yahoo.vespa.model.application.validation.change.VespaConfigChangeAction;
import org.junit.jupiter.api.Test;
@@ -28,8 +28,7 @@ public class AttributeChangeValidatorTest {
nextDb().getDerivedConfiguration().getAttributeFields(),
nextDb().getDerivedConfiguration().getIndexSchema(),
nextDocType(),
- new ValidationOverrides(List.of()),
- new ManualClock().instant());
+ new DeployState.Builder().build());
}
@Override
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/search/DocumentDatabaseChangeValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/search/DocumentDatabaseChangeValidatorTest.java
index 27a90c73725..689643e550d 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/search/DocumentDatabaseChangeValidatorTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/search/DocumentDatabaseChangeValidatorTest.java
@@ -2,9 +2,8 @@
package com.yahoo.vespa.model.application.validation.change.search;
import com.yahoo.config.application.api.ValidationId;
-import com.yahoo.config.application.api.ValidationOverrides;
+import com.yahoo.config.model.deploy.DeployState;
import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.test.ManualClock;
import com.yahoo.vespa.model.application.validation.change.VespaConfigChangeAction;
import org.junit.jupiter.api.Test;
@@ -28,8 +27,7 @@ public class DocumentDatabaseChangeValidatorTest {
currentDocType(),
nextDb(),
nextDocType(),
- new ValidationOverrides(List.of()),
- new ManualClock().instant());
+ new DeployState.Builder().build());
}
@Override
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java
index 500843a82a0..ce2d5ca2da5 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/ContainerClusterTest.java
@@ -41,7 +41,6 @@ import java.util.List;
import java.util.Objects;
import java.util.OptionalInt;
import java.util.Set;
-import java.util.stream.Collectors;
import static com.yahoo.config.model.api.ApplicationClusterEndpoint.RoutingMethod.exclusive;
import static com.yahoo.config.model.api.ApplicationClusterEndpoint.RoutingMethod.shared;
@@ -474,7 +473,7 @@ public class ContainerClusterTest {
cluster.getConfig(bundleBuilder);
List<String> installedBundles = bundleBuilder.build().bundlePaths();
- expectedBundleNames.forEach(b -> assertTrue(installedBundles.stream().filter(p -> p.endsWith(b)).count() > 0));
+ expectedBundleNames.forEach(b -> assertTrue(installedBundles.stream().anyMatch(p -> p.endsWith(b))));
}
private static ApplicationContainerCluster newClusterWithSearch(MockRoot root) {
@@ -486,7 +485,7 @@ public class ContainerClusterTest {
if (isCombinedCluster)
cluster.setHostClusterId("test-content-cluster");
cluster.setMemoryPercentage(memoryPercentage);
- cluster.setSearch(new ContainerSearch(cluster, new SearchChains(cluster, "search-chain"), new ContainerSearch.Options()));
+ cluster.setSearch(new ContainerSearch(cluster, new SearchChains(cluster, "search-chain")));
return cluster;
}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackage.java b/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackage.java
index 9b23037ed19..fbf14fbdb8c 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackage.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/zookeeper/ZKApplicationPackage.java
@@ -138,9 +138,11 @@ public class ZKApplicationPackage extends AbstractApplicationPackage {
@Override
public List<NamedReader> getSchemas() {
List<NamedReader> schemas = new ArrayList<>();
- for (String sd : zkApplication.getChildren(Path.fromString(USERAPP_ZK_SUBPATH).append(SCHEMAS_DIR))) {
- if (sd.endsWith(SD_NAME_SUFFIX))
- schemas.add(zkApplication.getNamedReader(sd, Path.fromString(USERAPP_ZK_SUBPATH).append(SCHEMAS_DIR).append(sd)));
+ var sdDir = Path.fromString(USERAPP_ZK_SUBPATH).append(SCHEMAS_DIR);
+ for (String sdName : zkApplication.getChildren(sdDir)) {
+ if (validSchemaFilename(sdName)) {
+ schemas.add(zkApplication.getNamedReader(sdName, sdDir.append(sdName)));
+ }
}
return schemas;
}
diff --git a/container-core/src/main/java/com/yahoo/processing/test/ProcessorLibrary.java b/container-core/src/test/java/com/yahoo/processing/test/ProcessorLibrary.java
index ee8dbd8dccb..ee8dbd8dccb 100644
--- a/container-core/src/main/java/com/yahoo/processing/test/ProcessorLibrary.java
+++ b/container-core/src/test/java/com/yahoo/processing/test/ProcessorLibrary.java
diff --git a/container-core/src/main/java/com/yahoo/processing/test/Responses.java b/container-core/src/test/java/com/yahoo/processing/test/Responses.java
index 0d54a728945..0d54a728945 100644
--- a/container-core/src/main/java/com/yahoo/processing/test/Responses.java
+++ b/container-core/src/test/java/com/yahoo/processing/test/Responses.java
diff --git a/container-search/src/main/java/com/yahoo/search/schema/SchemaInfo.java b/container-search/src/main/java/com/yahoo/search/schema/SchemaInfo.java
index 3d56dd99e30..6482070bc03 100644
--- a/container-search/src/main/java/com/yahoo/search/schema/SchemaInfo.java
+++ b/container-search/src/main/java/com/yahoo/search/schema/SchemaInfo.java
@@ -17,7 +17,6 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
-import java.util.stream.Collectors;
/**
* Information about all the schemas configured in the application this container is a part of.
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzDbMock.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzDbMock.java
index 63dfff95c03..9a9c2af2d5d 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzDbMock.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/AthenzDbMock.java
@@ -28,7 +28,11 @@ public class AthenzDbMock {
}
public Domain getOrCreateDomain(AthenzDomain domain) {
- return domains.computeIfAbsent(domain, Domain::new);
+ return this.getOrCreateDomain(domain, Map.of());
+ }
+
+ public Domain getOrCreateDomain(AthenzDomain domain, Map<String, Object> attributes) {
+ return domains.computeIfAbsent(domain, Domain::new).withAttributes(attributes);
}
public AthenzDbMock addHostedOperator(AthenzIdentity athenzIdentity) {
@@ -46,6 +50,7 @@ public class AthenzDbMock {
public final List<Role> roles = new ArrayList<>();
public final Map<String, Policy> policies = new HashMap<>();
public boolean isVespaTenant = false;
+ public final Map<String, Object> attributes = new HashMap<>();
public Domain(AthenzDomain name) {
this.name = name;
@@ -72,6 +77,11 @@ public class AthenzDbMock {
return this;
}
+ public Domain withAttributes(Map<String, Object> attributes) {
+ this.attributes.putAll(attributes);
+ return this;
+ }
+
/**
* Simulates establishing Vespa tenancy in Athens.
*/
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java
index d5e815912c5..ed185f8af32 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/athenz/ZmsClientMock.java
@@ -3,6 +3,7 @@ package com.yahoo.vespa.hosted.controller.api.integration.athenz;
import com.yahoo.vespa.athenz.api.AthenzAssertion;
import com.yahoo.vespa.athenz.api.AthenzDomain;
+import com.yahoo.vespa.athenz.api.AthenzDomainMeta;
import com.yahoo.vespa.athenz.api.AthenzGroup;
import com.yahoo.vespa.athenz.api.AthenzIdentity;
import com.yahoo.vespa.athenz.api.AthenzPolicy;
@@ -139,6 +140,25 @@ public class ZmsClientMock implements ZmsClient {
}
@Override
+ public AthenzDomainMeta getDomainMeta(AthenzDomain domain) {
+ return Optional.ofNullable(athenz.domains.get(domain))
+ .map(d -> d.attributes)
+ .map(attrs -> {
+ if (attrs.containsKey("account")) {
+ return new AthenzDomainMeta((String)attrs.get("account"), domain.getName());
+ }
+ return null;
+ })
+ .orElse(null);
+ }
+
+ @Override
+ public void updateDomain(AthenzDomain domain, Map<String, Object> attributes) {
+ if (!athenz.domains.containsKey(domain)) throw new IllegalStateException("Domain does not exist: " + domain.getName());
+ athenz.domains.get(domain).withAttributes(attributes);
+ }
+
+ @Override
public boolean hasAccess(AthenzResourceName resource, String action, AthenzIdentity identity) {
log("hasAccess(resource=%s, action=%s, identity=%s)", resource, action, identity);
if (resource.getDomain().equals(this.controllerIdentity.getDomain())) {
@@ -268,7 +288,11 @@ public class ZmsClientMock implements ZmsClient {
}
@Override
- public void createSubdomain(AthenzDomain parent, String name, Map<String, Object> attributes) {}
+ public void createSubdomain(AthenzDomain parent, String name, Map<String, Object> attributes) {
+ AthenzDomain domain = new AthenzDomain(parent, name);
+ if (athenz.domains.containsKey(domain)) throw new IllegalStateException("Subdomain already exists: %s".formatted(domain.getName()));
+ athenz.getOrCreateDomain(domain, attributes);
+ }
@Override
public AthenzRoleInformation getFullRoleInformation(AthenzRole role) {
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 5180b656670..fef29a99a47 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
@@ -126,7 +126,7 @@ enum PathGroup {
"/application/v4/tenant/{tenant}/application/{application}/instance/{ignored}/environment/{environment}/region/{region}/content/{*}",
"/application/v4/tenant/{tenant}/application/{application}/instance/{ignored}/environment/{environment}/region/{region}/logs",
"/application/v4/tenant/{tenant}/application/{application}/instance/{ignored}/environment/{environment}/region/{region}/orchestrator",
- "/application/v4/tenant/{tenant}/application/{application}/instance/{ignored}/environment/{environment}/region/{region}/private-service",
+ "/application/v4/tenant/{tenant}/application/{application}/instance/{ignored}/environment/{environment}/region/{region}/private-services",
"/application/v4/tenant/{tenant}/application/{application}/instance/{ignored}/environment/{environment}/region/{region}/suspended",
"/application/v4/tenant/{tenant}/application/{application}/instance/{ignored}/environment/{environment}/region/{region}/service/{*}",
"/application/v4/tenant/{tenant}/application/{application}/instance/{ignored}/environment/{environment}/region/{region}/access/support",
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 3f68be611eb..e92fd35025b 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
@@ -280,7 +280,7 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/clusters")) return clusters(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"));
if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/content/{*}")) return content(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), path.getRest(), request);
if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/logs")) return logs(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request.propertyMap());
- if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/private-service")) return getPrivateServiceInfo(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"));
+ if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/private-services")) return getPrivateServiceInfo(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"));
if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/access/support")) return supportAccess(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request.propertyMap());
if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/node/{node}/service-dump")) return getServiceDump(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), path.get("node"), request);
if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/scaling")) return scaling(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request);
@@ -1973,7 +1973,7 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
ZoneId.from(environment, region));
List<LoadBalancer> lbs = controller.serviceRegistry().configServer().getLoadBalancers(id.applicationId(), id.zoneId());
Slime slime = new Slime();
- Cursor lbArray = slime.setObject().setArray("loadBalancers");
+ Cursor lbArray = slime.setObject().setArray("privateServices");
for (LoadBalancer lb : lbs) {
Cursor lbObject = lbArray.addObject();
lbObject.setString("cluster", lb.cluster().value());
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 be405c7b876..95f3415095d 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
@@ -698,10 +698,10 @@ public class ApplicationApiTest extends ControllerContainerTest {
new File("suspended.json"));
// GET private service info
- tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/environment/prod/region/us-central-1/private-service", GET)
+ tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/environment/prod/region/us-central-1/private-services", GET)
.userIdentity(USER_ID),
"""
- {"loadBalancers":[{"cluster":"default","serviceId":"service","allowedUrns":[{"type":"aws-private-link","urn":"arne"}],"endpoints":[{"endpointId":"endpoint-1","state":"available"}]}]}""");
+ {"privateServices":[{"cluster":"default","serviceId":"service","allowedUrns":[{"type":"aws-private-link","urn":"arne"}],"endpoints":[{"endpointId":"endpoint-1","state":"available"}]}]}""");
// GET service/state/v1
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/environment/prod/region/us-central-1/service/storagenode/host.com/state/v1/?foo=bar", GET)
diff --git a/model-integration/src/main/java/ai/vespa/modelintegration/evaluator/OnnxEvaluatorOptions.java b/model-integration/src/main/java/ai/vespa/modelintegration/evaluator/OnnxEvaluatorOptions.java
index fceb63e6ae6..cdbce760d92 100644
--- a/model-integration/src/main/java/ai/vespa/modelintegration/evaluator/OnnxEvaluatorOptions.java
+++ b/model-integration/src/main/java/ai/vespa/modelintegration/evaluator/OnnxEvaluatorOptions.java
@@ -39,14 +39,11 @@ public class OnnxEvaluatorOptions {
return options;
}
- private void addCuda(OrtSession.SessionOptions options) throws OrtException {
+ private void addCuda(OrtSession.SessionOptions options) {
if (gpuDeviceNumber < 0) return;
try {
options.addCUDA(gpuDeviceNumber);
} catch (OrtException e) {
- if (e.getCode() != OrtException.OrtErrorCode.ORT_EP_FAIL) {
- throw e;
- }
if (gpuDeviceRequired) {
throw new IllegalArgumentException("GPU device " + gpuDeviceNumber + " is required, but CUDA backend could not be initialized", e);
}
diff --git a/searchcore/src/tests/proton/documentdb/configurer/configurer_test.cpp b/searchcore/src/tests/proton/documentdb/configurer/configurer_test.cpp
index 0bcbf1269a1..ee6edf228d9 100644
--- a/searchcore/src/tests/proton/documentdb/configurer/configurer_test.cpp
+++ b/searchcore/src/tests/proton/documentdb/configurer/configurer_test.cpp
@@ -211,7 +211,7 @@ Fixture::initViewSet(ViewSet &views)
auto matchView = std::make_shared<MatchView>(matchers, indexSearchable, attrMgr, _sessionMgr, metaStore, views._docIdLimit);
views.searchView.set(SearchView::create
(summaryMgr->createSummarySetup(SummaryConfig(),
- JuniperrcConfig(), views.repo, attrMgr),
+ JuniperrcConfig(), views.repo, attrMgr, *schema),
std::move(matchView)));
views.feedView.set(
make_shared<SearchableFeedView>(StoreOnlyFeedView::Context(summaryAdapter,
@@ -684,6 +684,33 @@ TEST("require that subdbs should change if relevant config changed")
TEST_DO(assertSubDbsShouldChange(CCR().set_alloc_config_changed(true)));
}
+void
+assertSummaryManagerShouldNotChange(DocumentDBConfig::ComparisonResult result)
+{
+ ReconfigParams params(result);
+ EXPECT_FALSE(params.configHasChanged());
+ EXPECT_FALSE(params.shouldSummaryManagerChange());
+}
+
+void
+assertSummaryManagerShouldChange(DocumentDBConfig::ComparisonResult result)
+{
+ ReconfigParams params(result);
+ EXPECT_TRUE(params.configHasChanged());
+ EXPECT_TRUE(params.shouldSummaryManagerChange());
+}
+
+TEST("require that summary manager should change if relevant config changed")
+{
+ TEST_DO(assertSummaryManagerShouldNotChange(CCR()));
+ TEST_DO(assertSummaryManagerShouldChange(CCR().setSummaryChanged(true)));
+ TEST_DO(assertSummaryManagerShouldChange(CCR().setJuniperrcChanged(true)));
+ TEST_DO(assertSummaryManagerShouldChange(CCR().setDocumenttypesChanged(true)));
+ TEST_DO(assertSummaryManagerShouldChange(CCR().setDocumentTypeRepoChanged(true)));
+ TEST_DO(assertSummaryManagerShouldChange(CCR().setStoreChanged(true)));
+ TEST_DO(assertSummaryManagerShouldChange(CCR().setSchemaChanged(true)));
+}
+
TEST_MAIN()
{
TEST_RUN_ALL();
diff --git a/searchcore/src/vespa/searchcore/proton/docsummary/isummarymanager.h b/searchcore/src/vespa/searchcore/proton/docsummary/isummarymanager.h
index d392d817105..692326721e2 100644
--- a/searchcore/src/vespa/searchcore/proton/docsummary/isummarymanager.h
+++ b/searchcore/src/vespa/searchcore/proton/docsummary/isummarymanager.h
@@ -9,6 +9,7 @@
#include <vespa/searchsummary/docsummary/resultconfig.h>
namespace document { class DocumentTypeRepo; }
+namespace search::index { class Schema; }
namespace proton {
@@ -46,7 +47,8 @@ public:
createSummarySetup(const SummaryConfig &summaryCfg,
const JuniperrcConfig &juniperCfg,
const std::shared_ptr<const document::DocumentTypeRepo> &repo,
- const std::shared_ptr<search::IAttributeManager> &attributeMgr) = 0;
+ const std::shared_ptr<search::IAttributeManager> &attributeMgr,
+ const search::index::Schema& schema) = 0;
virtual search::IDocumentStore &getBackingStore() = 0;
protected:
diff --git a/searchcore/src/vespa/searchcore/proton/docsummary/summarymanager.cpp b/searchcore/src/vespa/searchcore/proton/docsummary/summarymanager.cpp
index 34ba0e70c25..2b3a3de3b45 100644
--- a/searchcore/src/vespa/searchcore/proton/docsummary/summarymanager.cpp
+++ b/searchcore/src/vespa/searchcore/proton/docsummary/summarymanager.cpp
@@ -83,7 +83,8 @@ SummaryManager::SummarySetup::
SummarySetup(const vespalib::string & baseDir, const SummaryConfig & summaryCfg,
const JuniperrcConfig & juniperCfg,
search::IAttributeManager::SP attributeMgr, search::IDocumentStore::SP docStore,
- std::shared_ptr<const DocumentTypeRepo> repo)
+ std::shared_ptr<const DocumentTypeRepo> repo,
+ const search::index::Schema& schema)
: _docsumWriter(),
_wordFolder(std::make_unique<Fast_NormalizeWordFolder>()),
_juniperProps(juniperCfg),
@@ -94,6 +95,7 @@ SummarySetup(const vespalib::string & baseDir, const SummaryConfig & summaryCfg,
{
_juniperConfig = std::make_unique<juniper::Juniper>(&_juniperProps, _wordFolder.get());
auto resultConfig = std::make_unique<ResultConfig>();
+ (void) schema;
std::unique_ptr<IKeywordExtractorFactory> keyword_extractor_factory = std::make_unique<LegacyKeywordExtractorFactory>(std::shared_ptr<IKeywordExtractor>());
auto docsum_field_writer_factory = std::make_unique<DocsumFieldWriterFactory>(summaryCfg.usev8geopositions, *this, *keyword_extractor_factory);
if (!resultConfig->readConfig(summaryCfg, make_string("SummaryManager(%s)", baseDir.c_str()).c_str(),
@@ -120,10 +122,11 @@ SummaryManager::SummarySetup::createDocsumStore()
ISummaryManager::ISummarySetup::SP
SummaryManager::createSummarySetup(const SummaryConfig & summaryCfg,
const JuniperrcConfig & juniperCfg, const std::shared_ptr<const DocumentTypeRepo> &repo,
- const search::IAttributeManager::SP &attributeMgr)
+ const search::IAttributeManager::SP &attributeMgr,
+ const search::index::Schema& schema)
{
return std::make_shared<SummarySetup>(_baseDir, summaryCfg,
- juniperCfg, attributeMgr, _docStore, repo);
+ juniperCfg, attributeMgr, _docStore, repo, schema);
}
SummaryManager::SummaryManager(vespalib::Executor &shared_executor, const LogDocumentStore::Config & storeConfig,
diff --git a/searchcore/src/vespa/searchcore/proton/docsummary/summarymanager.h b/searchcore/src/vespa/searchcore/proton/docsummary/summarymanager.h
index bd6d8240df0..a987d40fe6d 100644
--- a/searchcore/src/vespa/searchcore/proton/docsummary/summarymanager.h
+++ b/searchcore/src/vespa/searchcore/proton/docsummary/summarymanager.h
@@ -35,7 +35,8 @@ public:
const JuniperrcConfig & juniperCfg,
search::IAttributeManager::SP attributeMgr,
search::IDocumentStore::SP docStore,
- std::shared_ptr<const document::DocumentTypeRepo> repo);
+ std::shared_ptr<const document::DocumentTypeRepo> repo,
+ const search::index::Schema& schema);
search::docsummary::IDocsumWriter & getDocsumWriter() const override { return *_docsumWriter; }
const search::docsummary::ResultConfig & getResultConfig() override { return *_docsumWriter->GetResultConfig(); }
@@ -71,7 +72,8 @@ public:
createSummarySetup(const SummaryConfig &summaryCfg,
const JuniperrcConfig &juniperCfg,
const std::shared_ptr<const document::DocumentTypeRepo> &repo,
- const search::IAttributeManager::SP &attributeMgr) override;
+ const search::IAttributeManager::SP &attributeMgr,
+ const search::index::Schema& schema) override;
search::IDocumentStore & getBackingStore() override { return *_docStore; }
void reconfigure(const search::LogDocumentStore::Config & config);
diff --git a/searchcore/src/vespa/searchcore/proton/server/reconfig_params.cpp b/searchcore/src/vespa/searchcore/proton/server/reconfig_params.cpp
index 2705ef24455..526a6fd1cd4 100644
--- a/searchcore/src/vespa/searchcore/proton/server/reconfig_params.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/reconfig_params.cpp
@@ -59,7 +59,7 @@ bool
ReconfigParams::shouldSummaryManagerChange() const
{
return _res.summaryChanged || _res.juniperrcChanged
- || _res.documentTypeRepoChanged || _res.documenttypesChanged || _res.storeChanged;
+ || _res.documentTypeRepoChanged || _res.documenttypesChanged || _res.storeChanged || _res.schemaChanged;
}
bool
diff --git a/searchcore/src/vespa/searchcore/proton/server/searchable_doc_subdb_configurer.cpp b/searchcore/src/vespa/searchcore/proton/server/searchable_doc_subdb_configurer.cpp
index 38487460b93..8ff55265a8b 100644
--- a/searchcore/src/vespa/searchcore/proton/server/searchable_doc_subdb_configurer.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/searchable_doc_subdb_configurer.cpp
@@ -221,7 +221,8 @@ SearchableDocSubDBConfigurer::reconfigure(const DocumentDBConfig &newConfig,
sumMgr->createSummarySetup(newConfig.getSummaryConfig(),
newConfig.getJuniperrcConfig(),
newConfig.getDocumentTypeRepoSP(),
- attrMgr);
+ attrMgr,
+ *newConfig.getSchemaSP());
sumSetup = newSumSetup;
shouldSearchViewChange = true;
}
diff --git a/searchcore/src/vespa/searchcore/proton/server/searchabledocsubdb.cpp b/searchcore/src/vespa/searchcore/proton/server/searchabledocsubdb.cpp
index 3d87e7dc7c3..506b541bbd3 100644
--- a/searchcore/src/vespa/searchcore/proton/server/searchabledocsubdb.cpp
+++ b/searchcore/src/vespa/searchcore/proton/server/searchabledocsubdb.cpp
@@ -203,7 +203,8 @@ SearchableDocSubDB::initViews(const DocumentDBConfig &configSnapshot)
configSnapshot.getSummaryConfig(),
configSnapshot.getJuniperrcConfig(),
configSnapshot.getDocumentTypeRepoSP(),
- attrMgr),
+ attrMgr,
+ *configSnapshot.getSchemaSP()),
std::move(matchView)));
auto attrWriter = std::make_shared<AttributeWriter>(attrMgr);
diff --git a/searchcore/src/vespa/searchcore/proton/test/dummy_summary_manager.h b/searchcore/src/vespa/searchcore/proton/test/dummy_summary_manager.h
index a40d89d6edf..d69d2dfd8eb 100644
--- a/searchcore/src/vespa/searchcore/proton/test/dummy_summary_manager.h
+++ b/searchcore/src/vespa/searchcore/proton/test/dummy_summary_manager.h
@@ -11,7 +11,8 @@ struct DummySummaryManager : public ISummaryManager
createSummarySetup(const SummaryConfig &,
const JuniperrcConfig &,
const std::shared_ptr<const document::DocumentTypeRepo> &,
- const std::shared_ptr<search::IAttributeManager> &) override {
+ const std::shared_ptr<search::IAttributeManager> &,
+ const search::index::Schema&) override {
return {};
}
};
diff --git a/searchsummary/CMakeLists.txt b/searchsummary/CMakeLists.txt
index 9c9079e6ed5..451c90c752d 100644
--- a/searchsummary/CMakeLists.txt
+++ b/searchsummary/CMakeLists.txt
@@ -20,6 +20,7 @@ vespa_define_module(
src/tests/docsummary/attribute_combiner
src/tests/docsummary/attributedfw
src/tests/docsummary/document_id_dfw
+ src/tests/docsummary/keyword_extractor_factory
src/tests/docsummary/matched_elements_filter
src/tests/docsummary/result_class
src/tests/docsummary/slime_filler
diff --git a/searchsummary/src/tests/docsummary/keyword_extractor_factory/CMakeLists.txt b/searchsummary/src/tests/docsummary/keyword_extractor_factory/CMakeLists.txt
new file mode 100644
index 00000000000..1cb555f3bd8
--- /dev/null
+++ b/searchsummary/src/tests/docsummary/keyword_extractor_factory/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(searchsummary_keyword_extractor_factory_test_app TEST
+ SOURCES
+ keyword_extractor_factory_test.cpp
+ DEPENDS
+ searchsummary
+ GTest::GTest
+)
+vespa_add_test(NAME searchsummary_keyword_extractor_factory_test_app COMMAND searchsummary_keyword_extractor_factory_test_app)
diff --git a/searchsummary/src/tests/docsummary/keyword_extractor_factory/keyword_extractor_factory_test.cpp b/searchsummary/src/tests/docsummary/keyword_extractor_factory/keyword_extractor_factory_test.cpp
new file mode 100644
index 00000000000..8ba91699ae6
--- /dev/null
+++ b/searchsummary/src/tests/docsummary/keyword_extractor_factory/keyword_extractor_factory_test.cpp
@@ -0,0 +1,73 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/searchcommon/common/schema.h>
+#include <vespa/searchsummary/docsummary/i_keyword_extractor.h>
+#include <vespa/searchsummary/docsummary/keyword_extractor_factory.h>
+#include <vespa/vespalib/gtest/gtest.h>
+
+using search::docsummary::IKeywordExtractor;
+using search::docsummary::IKeywordExtractorFactory;
+using search::docsummary::KeywordExtractorFactory;
+using search::index::Schema;
+
+using FieldSet = Schema::FieldSet;
+
+class KeywordExtractorFactoryTest : public testing::Test {
+ std::unique_ptr<IKeywordExtractorFactory> _factory;
+ Schema _schema;
+
+protected:
+ KeywordExtractorFactoryTest();
+ ~KeywordExtractorFactoryTest() override;
+
+ void make_factory() {
+ _factory = std::make_unique<KeywordExtractorFactory>(_schema);
+ }
+
+ bool check_index(const vespalib::string &index_name, const vespalib::string& summary_field) {
+ if (!_factory) {
+ make_factory();
+ }
+ auto extractor = _factory->make(summary_field);
+ return extractor->isLegalIndex(index_name);
+ }
+
+ void add_field_set(const vespalib::string& field_set_name, const std::vector<vespalib::string>& field_names) {
+ FieldSet field_set(field_set_name);
+ for (auto& field_name : field_names) {
+ field_set.addField(field_name);
+ }
+ _schema.addFieldSet(field_set);
+ _factory.reset();
+ }
+};
+
+
+KeywordExtractorFactoryTest::KeywordExtractorFactoryTest()
+ : testing::Test(),
+ _factory()
+{
+}
+
+KeywordExtractorFactoryTest::~KeywordExtractorFactoryTest() = default;
+
+TEST_F(KeywordExtractorFactoryTest, empty_schema)
+{
+ EXPECT_TRUE(check_index("foo", "foo"));
+ EXPECT_FALSE(check_index("bar", "foo"));
+ EXPECT_FALSE(check_index("foo", "bar"));
+}
+
+TEST_F(KeywordExtractorFactoryTest, field_set_is_checked)
+{
+ add_field_set("ab", {"cd", "de"});
+ add_field_set("gh", {"cd"});
+ EXPECT_TRUE(check_index("cd", "cd"));
+ EXPECT_TRUE(check_index("ab", "cd"));
+ EXPECT_TRUE(check_index("gh", "cd"));
+ EXPECT_TRUE(check_index("de", "de"));
+ EXPECT_TRUE(check_index("ab", "de"));
+ EXPECT_FALSE(check_index("gh", "de"));
+}
+
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/searchsummary/src/vespa/searchsummary/docsummary/CMakeLists.txt b/searchsummary/src/vespa/searchsummary/docsummary/CMakeLists.txt
index cfc3eb6536d..34e902461f4 100644
--- a/searchsummary/src/vespa/searchsummary/docsummary/CMakeLists.txt
+++ b/searchsummary/src/vespa/searchsummary/docsummary/CMakeLists.txt
@@ -23,6 +23,8 @@ vespa_add_library(searchsummary_docsummary OBJECT
juniper_dfw_term_visitor.cpp
juniper_query_adapter.cpp
juniperproperties.cpp
+ keyword_extractor.cpp
+ keyword_extractor_factory.cpp
legacy_keyword_extractor.cpp
legacy_keyword_extractor_factory.cpp
linguisticsannotation.cpp
diff --git a/searchsummary/src/vespa/searchsummary/docsummary/keyword_extractor.cpp b/searchsummary/src/vespa/searchsummary/docsummary/keyword_extractor.cpp
new file mode 100644
index 00000000000..71b685c6317
--- /dev/null
+++ b/searchsummary/src/vespa/searchsummary/docsummary/keyword_extractor.cpp
@@ -0,0 +1,22 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "keyword_extractor.h"
+#include <vespa/vespalib/stllike/hash_set.hpp>
+
+namespace search::docsummary {
+
+KeywordExtractor::KeywordExtractor(StringSet indexes)
+ : IKeywordExtractor(),
+ _indexes(std::move(indexes))
+{
+}
+
+KeywordExtractor::~KeywordExtractor() = default;
+
+bool
+KeywordExtractor::isLegalIndex(vespalib::stringref idx) const
+{
+ return _indexes.contains(idx);
+}
+
+}
diff --git a/searchsummary/src/vespa/searchsummary/docsummary/keyword_extractor.h b/searchsummary/src/vespa/searchsummary/docsummary/keyword_extractor.h
new file mode 100644
index 00000000000..a2b1fba96f1
--- /dev/null
+++ b/searchsummary/src/vespa/searchsummary/docsummary/keyword_extractor.h
@@ -0,0 +1,24 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include "i_keyword_extractor.h"
+#include <vespa/vespalib/stllike/hash_set.h>
+
+namespace search::docsummary {
+
+/*
+ * Class for checking if query term index name indicates that
+ * related query term is useful from the perspective of juniper.
+ */
+class KeywordExtractor : public IKeywordExtractor
+{
+ using StringSet = vespalib::hash_set<vespalib::string>;
+ StringSet _indexes;
+public:
+ KeywordExtractor(StringSet indexes);
+ ~KeywordExtractor() override;
+ bool isLegalIndex(vespalib::stringref idx) const override;
+};
+
+}
diff --git a/searchsummary/src/vespa/searchsummary/docsummary/keyword_extractor_factory.cpp b/searchsummary/src/vespa/searchsummary/docsummary/keyword_extractor_factory.cpp
new file mode 100644
index 00000000000..f749e6e42a1
--- /dev/null
+++ b/searchsummary/src/vespa/searchsummary/docsummary/keyword_extractor_factory.cpp
@@ -0,0 +1,41 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "keyword_extractor_factory.h"
+#include "keyword_extractor.h"
+#include <vespa/searchcommon/common/schema.h>
+#include <vespa/vespalib/stllike/hash_map.hpp>
+#include <vespa/vespalib/stllike/hash_set.hpp>
+
+namespace search::docsummary {
+
+KeywordExtractorFactory::KeywordExtractorFactory(const search::index::Schema& schema)
+ : IKeywordExtractorFactory(),
+ _index_map()
+{
+ for (uint32_t i = 0; i < schema.getNumFieldSets(); ++i) {
+ auto& field_set = schema.getFieldSet(i);
+ auto& fields = field_set.getFields();
+ for (auto& field : fields) {
+ auto& vec = _index_map[field];
+ vec.emplace_back(field_set.getName());
+ }
+ }
+}
+
+KeywordExtractorFactory::~KeywordExtractorFactory() = default;
+
+std::shared_ptr<const IKeywordExtractor>
+KeywordExtractorFactory::make(vespalib::stringref input_field) const
+{
+ vespalib::hash_set<vespalib::string> indexes;
+ indexes.insert(input_field);
+ auto itr = _index_map.find(input_field);
+ if (itr != _index_map.end()) {
+ for (auto& index : itr->second) {
+ indexes.insert(index);
+ }
+ }
+ return std::make_shared<KeywordExtractor>(std::move(indexes));
+}
+
+}
diff --git a/searchsummary/src/vespa/searchsummary/docsummary/keyword_extractor_factory.h b/searchsummary/src/vespa/searchsummary/docsummary/keyword_extractor_factory.h
new file mode 100644
index 00000000000..e22475eb842
--- /dev/null
+++ b/searchsummary/src/vespa/searchsummary/docsummary/keyword_extractor_factory.h
@@ -0,0 +1,26 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include "i_keyword_extractor_factory.h"
+#include <vespa/searchcommon/common/schema.h>
+#include <vespa/vespalib/stllike/hash_map.h>
+#include <vector>
+
+namespace search::index { class Schema; }
+
+namespace search::docsummary {
+
+/*
+ * Class for creating an instance of IKeywordExtractor.
+ */
+class KeywordExtractorFactory : public IKeywordExtractorFactory
+{
+ vespalib::hash_map<vespalib::string, std::vector<vespalib::string>> _index_map;
+public:
+ KeywordExtractorFactory(const search::index::Schema& schema);
+ ~KeywordExtractorFactory() override;
+ std::shared_ptr<const IKeywordExtractor> make(vespalib::stringref input_field) const override;
+};
+
+}
diff --git a/streamingvisitors/CMakeLists.txt b/streamingvisitors/CMakeLists.txt
index 0e7789a21b9..adfee1a76ae 100644
--- a/streamingvisitors/CMakeLists.txt
+++ b/streamingvisitors/CMakeLists.txt
@@ -26,6 +26,7 @@ vespa_define_module(
src/tests/charbuffer
src/tests/docsum
src/tests/document
+ src/tests/keyword_extractor_factory
src/tests/searcher
src/tests/textutil
)
diff --git a/streamingvisitors/src/tests/keyword_extractor_factory/CMakeLists.txt b/streamingvisitors/src/tests/keyword_extractor_factory/CMakeLists.txt
new file mode 100644
index 00000000000..54e2368f200
--- /dev/null
+++ b/streamingvisitors/src/tests/keyword_extractor_factory/CMakeLists.txt
@@ -0,0 +1,9 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(streamingvisitors_keyword_extractor_factory_test_app TEST
+ SOURCES
+ keyword_extractor_factory_test.cpp
+ DEPENDS
+ streamingvisitors
+ GTest::GTest
+)
+vespa_add_test(NAME streamingvisitors_keyword_extractor_factory_test_app COMMAND streamingvisitors_keyword_extractor_factory_test_app)
diff --git a/streamingvisitors/src/tests/keyword_extractor_factory/keyword_extractor_factory_test.cpp b/streamingvisitors/src/tests/keyword_extractor_factory/keyword_extractor_factory_test.cpp
new file mode 100644
index 00000000000..6ed4dfa1425
--- /dev/null
+++ b/streamingvisitors/src/tests/keyword_extractor_factory/keyword_extractor_factory_test.cpp
@@ -0,0 +1,116 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/searchsummary/docsummary/i_keyword_extractor.h>
+#include <vespa/vsm/vsm/keyword_extractor_factory.h>
+#include <vespa/vespalib/gtest/gtest.h>
+
+using search::docsummary::IKeywordExtractor;
+using search::docsummary::IKeywordExtractorFactory;
+using vespa::config::search::vsm::VsmfieldsConfig;
+using vespa::config::search::vsm::VsmfieldsConfigBuilder;
+using vespa::config::search::vsm::VsmsummaryConfig;
+using vespa::config::search::vsm::VsmsummaryConfigBuilder;
+using vsm::KeywordExtractorFactory;
+
+class KeywordExtractorFactoryTest : public testing::Test {
+ std::unique_ptr<IKeywordExtractorFactory> _factory;
+ VsmfieldsConfigBuilder _fields;
+ VsmsummaryConfigBuilder _summary;
+protected:
+ KeywordExtractorFactoryTest();
+ ~KeywordExtractorFactoryTest() override;
+
+ void make_factory() {
+ _factory = std::make_unique<KeywordExtractorFactory>(_fields, _summary);
+ }
+
+ bool check_index(const vespalib::string &index_name, const vespalib::string& summary_field) {
+ if (!_factory) {
+ make_factory();
+ }
+ auto extractor = _factory->make(summary_field);
+ return extractor->isLegalIndex(index_name);
+ }
+
+ void add_summary_field(const vespalib::string& summary_field_name, const std::vector<vespalib::string>& field_names)
+ {
+ VsmsummaryConfigBuilder::Fieldmap field_map;
+ field_map.summary = summary_field_name;
+ for (auto& field_name : field_names) {
+ VsmsummaryConfigBuilder::Fieldmap::Document document;
+ document.field = field_name;
+ field_map.document.emplace_back(document);
+ }
+ _summary.fieldmap.emplace_back(field_map);
+ _factory.reset();
+ }
+ void add_index(const vespalib::string& index_name, const std::vector<vespalib::string>& field_names)
+ {
+ if (_fields.documenttype.empty()) {
+ _fields.documenttype.resize(1);
+ _fields.documenttype.back().name = "dummy";
+ }
+ VsmfieldsConfigBuilder::Documenttype::Index index;
+ index.name = index_name;
+ for (auto& field_name : field_names) {
+ VsmfieldsConfigBuilder::Documenttype::Index::Field field;
+ field.name = field_name;
+ index.field.emplace_back(field);
+ }
+ _fields.documenttype.back().index.emplace_back(index);
+ _factory.reset();
+ }
+};
+
+
+KeywordExtractorFactoryTest::KeywordExtractorFactoryTest()
+ : testing::Test(),
+ _factory()
+{
+}
+
+KeywordExtractorFactoryTest::~KeywordExtractorFactoryTest() = default;
+
+TEST_F(KeywordExtractorFactoryTest, empty_config)
+{
+ EXPECT_FALSE(check_index("foo", "foo"));
+}
+
+TEST_F(KeywordExtractorFactoryTest, implied_identity_mapping_for_summary_field)
+{
+ add_index("foo", {"bar"});
+ EXPECT_FALSE(check_index("foo", "foo"));
+ EXPECT_TRUE(check_index("foo", "bar"));
+}
+
+TEST_F(KeywordExtractorFactoryTest, two_source_fields_for_summary_field)
+{
+ add_index("bar", {"bar"});
+ add_index("baz", {"baz"});
+ add_summary_field("foo", {"bar", "baz"});
+ EXPECT_FALSE(check_index("foo", "foo"));
+ EXPECT_TRUE(check_index("bar", "foo"));
+ EXPECT_TRUE(check_index("bar", "bar"));
+ EXPECT_TRUE(check_index("baz", "foo"));
+ EXPECT_TRUE(check_index("baz", "baz"));
+}
+
+TEST_F(KeywordExtractorFactoryTest, two_source_fields_for_summary_field_and_multiple_indexes)
+{
+ add_index("bar", {"bar"});
+ add_index("baz", {"baz"});
+ add_index("both", {"bar", "baz"});
+ add_summary_field("foo", {"bar", "baz"});
+ EXPECT_FALSE(check_index("foo", "foo"));
+ EXPECT_TRUE(check_index("both", "foo"));
+ EXPECT_TRUE(check_index("bar", "foo"));
+ EXPECT_TRUE(check_index("baz", "foo"));
+ EXPECT_TRUE(check_index("both", "bar"));
+ EXPECT_TRUE(check_index("bar", "bar"));
+ EXPECT_FALSE(check_index("baz", "bar"));
+ EXPECT_TRUE(check_index("both", "baz"));
+ EXPECT_FALSE(check_index("bar", "baz"));
+ EXPECT_TRUE(check_index("baz", "baz"));
+}
+
+GTEST_MAIN_RUN_ALL_TESTS()
diff --git a/streamingvisitors/src/vespa/vsm/vsm/CMakeLists.txt b/streamingvisitors/src/vespa/vsm/vsm/CMakeLists.txt
index cf121aead4b..67acbc1a391 100644
--- a/streamingvisitors/src/vespa/vsm/vsm/CMakeLists.txt
+++ b/streamingvisitors/src/vespa/vsm/vsm/CMakeLists.txt
@@ -6,6 +6,7 @@ vespa_add_library(vsm_vsmbase OBJECT
docsum_field_writer_factory.cpp
fieldsearchspec.cpp
flattendocsumwriter.cpp
+ keyword_extractor_factory.cpp
snippetmodifier.cpp
vsm-adapter.cpp
DEPENDS
diff --git a/streamingvisitors/src/vespa/vsm/vsm/keyword_extractor_factory.cpp b/streamingvisitors/src/vespa/vsm/vsm/keyword_extractor_factory.cpp
new file mode 100644
index 00000000000..5319f554c81
--- /dev/null
+++ b/streamingvisitors/src/vespa/vsm/vsm/keyword_extractor_factory.cpp
@@ -0,0 +1,80 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include "keyword_extractor_factory.h"
+#include <vespa/searchsummary/docsummary/keyword_extractor.h>
+#include <vespa/vespalib/stllike/hash_map.hpp>
+#include <vespa/vespalib/stllike/hash_set.hpp>
+#include <cassert>
+#include <vespa/log/log.h>
+LOG_SETUP(".vsm.keyword_extractor_factory");
+
+using search::docsummary::IKeywordExtractor;
+using search::docsummary::IKeywordExtractorFactory;
+using search::docsummary::KeywordExtractor;
+using vespa::config::search::vsm::VsmfieldsConfig;
+using vespa::config::search::vsm::VsmsummaryConfig;
+
+namespace vsm {
+
+KeywordExtractorFactory::KeywordExtractorFactory(VsmfieldsConfig& vsm_fields_config,
+ VsmsummaryConfig& vsm_summary_config)
+ : IKeywordExtractorFactory(),
+ _index_map(),
+ _field_map()
+{
+ populate_index_map(vsm_fields_config);
+ populate_field_map(vsm_summary_config);
+}
+
+KeywordExtractorFactory::~KeywordExtractorFactory() = default;
+
+void
+KeywordExtractorFactory::populate_index_map(VsmfieldsConfig& vsm_fields_config)
+{
+ for (auto& doctype : vsm_fields_config.documenttype) {
+ for (auto& index : doctype.index) {
+ for (auto& field : index.field) {
+ _index_map[field.name].insert(index.name);
+ }
+ }
+ }
+}
+
+void
+KeywordExtractorFactory::populate_field_map(VsmsummaryConfig& vsm_summary_config)
+{
+ for (auto& summary_field : vsm_summary_config.fieldmap) {
+ for (auto& document : summary_field.document) {
+ _field_map[summary_field.summary].insert(document.field);
+ }
+ }
+}
+
+void
+KeywordExtractorFactory::populate_indexes(StringSet& indexes, const vespalib::string& field) const
+{
+ auto itr = _index_map.find(field);
+ if (itr != _index_map.end()) {
+ for (auto& index : itr->second) {
+ indexes.insert(index);
+ }
+ }
+}
+
+std::shared_ptr<const IKeywordExtractor>
+KeywordExtractorFactory::make(vespalib::stringref input_field) const
+{
+ StringSet indexes;
+ auto itr = _field_map.find(input_field);
+ if (itr != _field_map.end()) {
+ for (auto& field : itr->second) {
+ populate_indexes(indexes, field);
+ }
+ } else {
+ // Assume identity mapping vsm summary field -> document field
+ populate_indexes(indexes, input_field);
+ }
+ return std::make_shared<KeywordExtractor>(std::move(indexes));
+}
+
+}
diff --git a/streamingvisitors/src/vespa/vsm/vsm/keyword_extractor_factory.h b/streamingvisitors/src/vespa/vsm/vsm/keyword_extractor_factory.h
new file mode 100644
index 00000000000..6ffcbd6f84b
--- /dev/null
+++ b/streamingvisitors/src/vespa/vsm/vsm/keyword_extractor_factory.h
@@ -0,0 +1,39 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#pragma once
+
+#include <vespa/searchsummary/docsummary/i_keyword_extractor_factory.h>
+#include <vespa/vespalib/stllike/hash_map.h>
+#include <vespa/vespalib/stllike/hash_set.h>
+#include <vespa/vsm/config/config-vsmfields.h>
+#include <vespa/vsm/config/config-vsmsummary.h>
+
+namespace vsm {
+
+/*
+ * Class for creating an instance of IKeywordExtractor for streaming search.
+ *
+ * vsm summary fields are treated as document fields by the summary framework
+ * in the searchsummary module, cf. IDocsumStoreDocument.
+ */
+class KeywordExtractorFactory : public search::docsummary::IKeywordExtractorFactory
+{
+public:
+ using VsmfieldsConfig = vespa::config::search::vsm::VsmfieldsConfig;
+ using VsmsummaryConfig = vespa::config::search::vsm::VsmsummaryConfig;
+private:
+ using StringSet = vespalib::hash_set<vespalib::string>;
+ using StringSetMap = vespalib::hash_map<vespalib::string, StringSet>;
+ StringSetMap _index_map; // document field -> indexes
+ StringSetMap _field_map; // vsm summary field -> document fields
+ void populate_index_map(VsmfieldsConfig& vsm_fields_config);
+ void populate_field_map(VsmsummaryConfig& vsm_summary_config);
+ void populate_indexes(StringSet& indexes, const vespalib::string& field) const;
+public:
+ KeywordExtractorFactory(VsmfieldsConfig& vsm_fields_config,
+ VsmsummaryConfig& vsm_summary_config);
+ ~KeywordExtractorFactory() override;
+ std::shared_ptr<const search::docsummary::IKeywordExtractor> make(vespalib::stringref input_field) const override;
+};
+
+}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AthenzDomainMeta.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AthenzDomainMeta.java
new file mode 100644
index 00000000000..7808a689982
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AthenzDomainMeta.java
@@ -0,0 +1,12 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.athenz.api;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public record AthenzDomainMeta(
+ @JsonProperty("account") String account,
+ @JsonProperty("name") String name
+) {
+}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/DefaultZmsClient.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/DefaultZmsClient.java
index 44ea5ef329f..d8d6d2c3486 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/DefaultZmsClient.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/DefaultZmsClient.java
@@ -5,6 +5,7 @@ import com.yahoo.athenz.auth.util.Crypto;
import com.yahoo.security.KeyUtils;
import com.yahoo.vespa.athenz.api.AthenzAssertion;
import com.yahoo.vespa.athenz.api.AthenzDomain;
+import com.yahoo.vespa.athenz.api.AthenzDomainMeta;
import com.yahoo.vespa.athenz.api.AthenzGroup;
import com.yahoo.vespa.athenz.api.AthenzIdentity;
import com.yahoo.vespa.athenz.api.AthenzPolicy;
@@ -33,6 +34,7 @@ import com.yahoo.vespa.athenz.utils.AthenzIdentities;
import org.apache.http.Header;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
+import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
@@ -216,6 +218,34 @@ public class DefaultZmsClient extends ClientBase implements ZmsClient {
}
@Override
+ public AthenzDomainMeta getDomainMeta(AthenzDomain domain) {
+ HttpUriRequest request = RequestBuilder.get()
+ .setUri(zmsUrl.resolve("domain/%s".formatted(domain.getName())))
+ .build();
+ return execute(request, response -> readEntity(response, AthenzDomainMeta.class));
+ }
+
+ @Override
+ public void updateDomain(AthenzDomain domain, Map<String, Object> attributes) {
+ for (String attribute : attributes.keySet()) {
+ Object attrVal = attributes.get(attribute);
+
+ String val = attrVal instanceof String ? "\"" + attrVal.toString() + "\"" : attrVal.toString();
+ String domainMeta = """
+ {
+ "%s": %s
+ }
+ """
+ .formatted(attribute, val);
+ HttpUriRequest request = RequestBuilder.put()
+ .setUri(zmsUrl.resolve("domain/%s/meta/system/%s".formatted(domain.getName(), attribute)))
+ .setEntity(new StringEntity(domainMeta, ContentType.APPLICATION_JSON))
+ .build();
+ execute(request, response -> readEntity(response, Void.class));
+ }
+ }
+
+ @Override
public boolean hasAccess(AthenzResourceName resource, String action, AthenzIdentity identity) {
URI uri = zmsUrl.resolve(String.format("access/%s/%s?principal=%s",
action, resource.toResourceNameString(), identity.getFullName()));
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/ZmsClient.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/ZmsClient.java
index 4342b32e4c8..541aa4d9c60 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/ZmsClient.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zms/ZmsClient.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.athenz.client.zms;
import com.yahoo.vespa.athenz.api.AthenzDomain;
+import com.yahoo.vespa.athenz.api.AthenzDomainMeta;
import com.yahoo.vespa.athenz.api.AthenzGroup;
import com.yahoo.vespa.athenz.api.AthenzIdentity;
import com.yahoo.vespa.athenz.api.AthenzPolicy;
@@ -52,6 +53,10 @@ public interface ZmsClient extends Closeable {
List<AthenzDomain> getDomainListByAccount(String id);
+ AthenzDomainMeta getDomainMeta(AthenzDomain domain);
+
+ void updateDomain(AthenzDomain domain, Map<String, Object> attributes);
+
boolean hasAccess(AthenzResourceName resource, String action, AthenzIdentity identity);
void createPolicy(AthenzDomain athenzDomain, String athenzPolicy);