diff options
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); |