diff options
12 files changed, 255 insertions, 9 deletions
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ApplicationRoles.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ApplicationRoles.java new file mode 100644 index 00000000000..8492603e2e3 --- /dev/null +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ApplicationRoles.java @@ -0,0 +1,51 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.model.api; + +import com.google.common.base.Strings; + +/** + * @author mortent + */ +public class ApplicationRoles { + private final String applicationHostRole; + private final String applicationContainerRole; + + public ApplicationRoles(String applicationHostRole, String applicationContainerRole) { + this.applicationHostRole = applicationHostRole; + this.applicationContainerRole = applicationContainerRole; + } + + /** + * @return an ApplicationRoles instance if both hostRole and containerRole is non-empty, <code>null</code> otherwise + */ + public static ApplicationRoles fromString(String hostRole, String containerRole) { + if(Strings.isNullOrEmpty(hostRole) || Strings.isNullOrEmpty(containerRole)) { + return null; + } + return new ApplicationRoles(hostRole, containerRole); + } + + public String applicationContainerRole() { + return applicationContainerRole; + } + + public String applicationHostRole() { + return applicationHostRole; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ApplicationRoles that = (ApplicationRoles) o; + if (!applicationHostRole.equals(that.applicationHostRole)) return false; + return applicationContainerRole.equals(that.applicationContainerRole); + } + + @Override + public int hashCode() { + int result = applicationHostRole.hashCode(); + result = 31 * result + applicationContainerRole.hashCode(); + return result; + } +} diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java index 7641f14b007..33369727703 100644 --- a/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java +++ b/config-model-api/src/main/java/com/yahoo/config/model/api/ModelContext.java @@ -93,6 +93,8 @@ public interface ModelContext { // TODO(mpolden): Remove after May 2020 default boolean useDedicatedNodesWhenUnspecified() { return true; } + + Optional<ApplicationRoles> applicationRoles(); } } diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java index 4dbfc8f7a8f..54630426cb8 100644 --- a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java +++ b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java @@ -2,6 +2,7 @@ package com.yahoo.config.model.deploy; import com.google.common.collect.ImmutableList; +import com.yahoo.config.model.api.ApplicationRoles; import com.yahoo.config.model.api.ConfigServerSpec; import com.yahoo.config.model.api.ContainerEndpoint; import com.yahoo.config.model.api.EndpointCertificateSecrets; @@ -49,6 +50,7 @@ public class TestProperties implements ModelContext.Properties { private int defaultNumResponseThreads = 0; private Optional<EndpointCertificateSecrets> endpointCertificateSecrets = Optional.empty(); private AthenzDomain athenzDomain; + private ApplicationRoles applicationRoles; @Override public boolean multitenant() { return multitenant; } @Override public ApplicationId applicationId() { return applicationId; } @@ -90,6 +92,7 @@ public class TestProperties implements ModelContext.Properties { @Override public boolean useDistributorBtreeDb() { return useDistributorBtreeDb; } @Override public boolean useThreePhaseUpdates() { return useThreePhaseUpdates; } @Override public Optional<AthenzDomain> athenzDomain() { return Optional.ofNullable(athenzDomain); } + @Override public Optional<ApplicationRoles> applicationRoles() { return Optional.ofNullable(applicationRoles); } public TestProperties setDefaultTermwiseLimit(double limit) { defaultTermwiseLimit = limit; @@ -174,6 +177,11 @@ public class TestProperties implements ModelContext.Properties { return this; } + public TestProperties setApplicationRoles(ApplicationRoles applicationRoles) { + this.applicationRoles = applicationRoles; + return this; + } + public static class Spec implements ConfigServerSpec { private final String hostName; diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java index fa7a107f953..0ecb608fe0c 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/deploy/ModelContextImpl.java @@ -5,6 +5,7 @@ import com.yahoo.component.Version; 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.ApplicationRoles; import com.yahoo.config.model.api.ConfigDefinitionRepo; import com.yahoo.config.model.api.ConfigServerSpec; import com.yahoo.config.model.api.ContainerEndpoint; @@ -156,6 +157,7 @@ public class ModelContextImpl implements ModelContext { private final double queueSizefactor; private final int defaultNumResponseThreads; private final Optional<AthenzDomain> athenzDomain; + private final Optional<ApplicationRoles> applicationRoles; public Properties(ApplicationId applicationId, boolean multitenantFromConfig, @@ -170,7 +172,8 @@ public class ModelContextImpl implements ModelContext { boolean isFirstTimeDeployment, FlagSource flagSource, Optional<EndpointCertificateSecrets> endpointCertificateSecrets, - Optional<AthenzDomain> athenzDomain) { + Optional<AthenzDomain> athenzDomain, + Optional<ApplicationRoles> applicationRoles) { this.applicationId = applicationId; this.multitenant = multitenantFromConfig || hostedVespa || Boolean.getBoolean("multitenant"); this.configServerSpecs = configServerSpecs; @@ -202,6 +205,7 @@ public class ModelContextImpl implements ModelContext { defaultNumResponseThreads = Flags.DEFAULT_NUM_RESPONSE_THREADS.bindTo(flagSource) .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value(); this.athenzDomain = athenzDomain; + this.applicationRoles = applicationRoles; } @Override @@ -287,6 +291,10 @@ public class ModelContextImpl implements ModelContext { @Override public Optional<AthenzDomain> athenzDomain() { return athenzDomain; } + @Override + public Optional<ApplicationRoles> applicationRoles() { + return applicationRoles; + } } } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java index 0b83e927c39..7828ce8963f 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ActivatedModelsBuilder.java @@ -16,7 +16,6 @@ import com.yahoo.config.provision.DockerImage; import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.TenantName; import com.yahoo.container.jdisc.secretstore.SecretStore; -import java.util.logging.Level; import com.yahoo.vespa.config.server.ConfigServerSpec; import com.yahoo.vespa.config.server.GlobalComponentRegistry; import com.yahoo.vespa.config.server.ServerCache; @@ -28,10 +27,11 @@ import com.yahoo.vespa.config.server.monitoring.Metrics; import com.yahoo.vespa.config.server.provision.HostProvisionerProvider; import com.yahoo.vespa.config.server.session.SessionZooKeeperClient; import com.yahoo.vespa.config.server.session.SilentDeployLogger; +import com.yahoo.vespa.config.server.tenant.ApplicationRolesStore; import com.yahoo.vespa.config.server.tenant.ContainerEndpointsCache; +import com.yahoo.vespa.config.server.tenant.EndpointCertificateMetadataStore; import com.yahoo.vespa.config.server.tenant.EndpointCertificateRetriever; import com.yahoo.vespa.config.server.tenant.TenantRepository; -import com.yahoo.vespa.config.server.tenant.EndpointCertificateMetadataStore; import com.yahoo.vespa.curator.Curator; import com.yahoo.vespa.flags.FlagSource; @@ -39,6 +39,7 @@ import java.net.URI; import java.time.Instant; import java.util.Map; import java.util.Optional; +import java.util.logging.Level; import java.util.logging.Logger; /** @@ -147,7 +148,9 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> { new EndpointCertificateMetadataStore(curator, TenantRepository.getTenantPath(tenant)) .readEndpointCertificateMetadata(applicationId) .flatMap(new EndpointCertificateRetriever(secretStore)::readEndpointCertificateSecrets), - zkClient.readAthenzDomain()); + zkClient.readAthenzDomain(), + new ApplicationRolesStore(curator, TenantRepository.getTenantPath(tenant)) + .readApplicationRoles(applicationId)); } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/PrepareParams.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/PrepareParams.java index ea84dee9fe7..a29b105f43f 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/PrepareParams.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/PrepareParams.java @@ -2,6 +2,7 @@ package com.yahoo.vespa.config.server.session; import com.yahoo.component.Version; +import com.yahoo.config.model.api.ApplicationRoles; import com.yahoo.config.model.api.ContainerEndpoint; import com.yahoo.config.model.api.EndpointCertificateMetadata; import com.yahoo.config.provision.ApplicationId; @@ -38,6 +39,8 @@ public final class PrepareParams { static final String ENDPOINT_CERTIFICATE_METADATA_PARAM_NAME = "endpointCertificateMetadata"; static final String DOCKER_IMAGE_REPOSITORY = "dockerImageRepository"; static final String ATHENZ_DOMAIN = "athenzDomain"; + static final String APPLICATION_HOST_ROLE = "applicationHostRole"; + static final String APPLICATION_CONTAINER_ROLE = "applicationContainerRole"; private final ApplicationId applicationId; private final TimeoutBudget timeoutBudget; @@ -51,12 +54,14 @@ public final class PrepareParams { private final Optional<EndpointCertificateMetadata> endpointCertificateMetadata; private final Optional<DockerImage> dockerImageRepository; private final Optional<AthenzDomain> athenzDomain; + private final Optional<ApplicationRoles> applicationRoles; private PrepareParams(ApplicationId applicationId, TimeoutBudget timeoutBudget, boolean ignoreValidationErrors, boolean dryRun, boolean verbose, boolean isBootstrap, Optional<Version> vespaVersion, List<ContainerEndpoint> containerEndpoints, Optional<String> tlsSecretsKeyName, Optional<EndpointCertificateMetadata> endpointCertificateMetadata, - Optional<DockerImage> dockerImageRepository, Optional<AthenzDomain> athenzDomain) { + Optional<DockerImage> dockerImageRepository, Optional<AthenzDomain> athenzDomain, + Optional<ApplicationRoles> applicationRoles) { this.timeoutBudget = timeoutBudget; this.applicationId = applicationId; this.ignoreValidationErrors = ignoreValidationErrors; @@ -69,6 +74,7 @@ public final class PrepareParams { this.endpointCertificateMetadata = endpointCertificateMetadata; this.dockerImageRepository = dockerImageRepository; this.athenzDomain = athenzDomain; + this.applicationRoles = applicationRoles; } public static class Builder { @@ -85,6 +91,7 @@ public final class PrepareParams { private Optional<EndpointCertificateMetadata> endpointCertificateMetadata = Optional.empty(); private Optional<DockerImage> dockerImageRepository = Optional.empty(); private Optional<AthenzDomain> athenzDomain = Optional.empty(); + private Optional<ApplicationRoles> applicationRoles = Optional.empty(); public Builder() { } @@ -174,12 +181,17 @@ public final class PrepareParams { return this; } + public Builder applicationRoles(ApplicationRoles applicationRoles) { + this.applicationRoles = Optional.ofNullable(applicationRoles); + return this; + } + public PrepareParams build() { return new PrepareParams(applicationId, timeoutBudget, ignoreValidationErrors, dryRun, verbose, isBootstrap, vespaVersion, containerEndpoints, tlsSecretsKeyName, - endpointCertificateMetadata, dockerImageRepository, athenzDomain); + endpointCertificateMetadata, dockerImageRepository, athenzDomain, + applicationRoles); } - } public static PrepareParams fromHttpRequest(HttpRequest request, TenantName tenant, Duration barrierTimeout) { @@ -194,6 +206,7 @@ public final class PrepareParams { .endpointCertificateMetadata(request.getProperty(ENDPOINT_CERTIFICATE_METADATA_PARAM_NAME)) .dockerImageRepository(request.getProperty(DOCKER_IMAGE_REPOSITORY)) .athenzDomain(request.getProperty(ATHENZ_DOMAIN)) + .applicationRoles(ApplicationRoles.fromString(request.getProperty(APPLICATION_HOST_ROLE), request.getProperty(APPLICATION_CONTAINER_ROLE))) .build(); } @@ -261,4 +274,7 @@ public final class PrepareParams { public Optional<AthenzDomain> athenzDomain() { return athenzDomain; } + public Optional<ApplicationRoles> applicationRoles() { + return applicationRoles; + } } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java index 54d4cc8654b..e63244cd57b 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java @@ -10,6 +10,7 @@ import com.yahoo.config.FileReference; 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.ApplicationRoles; import com.yahoo.config.model.api.ConfigDefinitionRepo; import com.yahoo.config.model.api.ContainerEndpoint; import com.yahoo.config.model.api.EndpointCertificateMetadata; @@ -36,6 +37,7 @@ import com.yahoo.vespa.config.server.http.InvalidApplicationException; import com.yahoo.vespa.config.server.modelfactory.ModelFactoryRegistry; import com.yahoo.vespa.config.server.modelfactory.PreparedModelsBuilder; import com.yahoo.vespa.config.server.provision.HostProvisionerProvider; +import com.yahoo.vespa.config.server.tenant.ApplicationRolesStore; import com.yahoo.vespa.config.server.tenant.ContainerEndpointsCache; import com.yahoo.vespa.config.server.tenant.EndpointCertificateMetadataSerializer; import com.yahoo.vespa.config.server.tenant.EndpointCertificateMetadataStore; @@ -135,6 +137,7 @@ public class SessionPreparer { } else { preparation.legacyWriteContainerEndpointsZK(); } + preparation.writeApplicationRoles(); preparation.distribute(); } log.log(Level.FINE, () -> "time used " + params.getTimeoutBudget().timesUsed() + @@ -170,6 +173,8 @@ public class SessionPreparer { private final Optional<EndpointCertificateMetadata> endpointCertificateMetadata; private final Optional<EndpointCertificateSecrets> endpointCertificateSecrets; private final Optional<AthenzDomain> athenzDomain; + private final ApplicationRolesStore applicationRolesStore; + private final Optional<ApplicationRoles> applicationRoles; private ApplicationPackage applicationPackage; private List<PreparedModelsBuilder.PreparedModelResult> modelResultList; @@ -203,6 +208,9 @@ public class SessionPreparer { this.containerEndpoints = getEndpoints(params.containerEndpoints()); } this.athenzDomain = params.athenzDomain(); + this.applicationRolesStore = new ApplicationRolesStore(curator, tenantPath); + this.applicationRoles = params.applicationRoles() + .or(() -> applicationRolesStore.readApplicationRoles(applicationId)); this.properties = new ModelContextImpl.Properties(params.getApplicationId(), configserverConfig.multitenant(), ConfigServerSpec.fromConfig(configserverConfig), @@ -216,7 +224,7 @@ public class SessionPreparer { currentActiveApplicationSet.isEmpty(), context.getFlagSource(), endpointCertificateSecrets, - athenzDomain); + athenzDomain, applicationRoles); this.fileDistributionProvider = fileDistributionFactory.createProvider(context.getServerDBSessionDir()); this.preparedModelsBuilder = new PreparedModelsBuilder(modelFactoryRegistry, permanentApplicationPackage, @@ -303,6 +311,12 @@ public class SessionPreparer { } } + void writeApplicationRoles() { + applicationRoles.ifPresent(roles -> + applicationRolesStore.writeApplicationRoles(applicationId, roles)); + checkTimeout("write application roles to zookeeper"); + } + void distribute() { prepareResult.asList().forEach(modelResult -> modelResult.model .distributeFiles(modelResult.fileDistributionProvider.getFileDistribution())); @@ -326,7 +340,6 @@ public class SessionPreparer { } return List.copyOf(endpoints); } - } private void writeStateToZooKeeper(SessionZooKeeperClient zooKeeperClient, diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/ApplicationRolesSerializer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/ApplicationRolesSerializer.java new file mode 100644 index 00000000000..132828de7b4 --- /dev/null +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/ApplicationRolesSerializer.java @@ -0,0 +1,27 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.config.server.tenant; + +import com.yahoo.config.model.api.ApplicationRoles; +import com.yahoo.slime.Cursor; +import com.yahoo.slime.Inspector; + +/** + * @author mortent + */ +public class ApplicationRolesSerializer { + + private final static String hostRoleField = "applicationHostRole"; + private final static String containerRoleField = "applicationContainerRole"; + + + public static void toSlime(ApplicationRoles applicationRoles, Cursor object) { + object.setString(hostRoleField, applicationRoles.applicationHostRole()); + object.setString(containerRoleField, applicationRoles.applicationContainerRole()); + } + + public static ApplicationRoles fromSlime(Inspector inspector) { + return new ApplicationRoles(inspector.field(hostRoleField).asString(), + inspector.field(containerRoleField).asString()); + + } +} diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/ApplicationRolesStore.java b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/ApplicationRolesStore.java new file mode 100644 index 00000000000..a41e5465509 --- /dev/null +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/ApplicationRolesStore.java @@ -0,0 +1,64 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.config.server.tenant; + +import com.yahoo.config.model.api.ApplicationRoles; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.path.Path; +import com.yahoo.slime.Slime; +import com.yahoo.slime.SlimeUtils; +import com.yahoo.vespa.curator.Curator; +import com.yahoo.vespa.curator.transaction.CuratorOperations; +import com.yahoo.vespa.curator.transaction.CuratorTransaction; + +import java.util.Optional; + +/** + * Stores application roles for an application. + * + * @author mortent + */ +public class ApplicationRolesStore { + + private final Path path; + private final Curator curator; + + public ApplicationRolesStore(Curator curator, Path tenantPath) { + this.curator = curator; + this.path = tenantPath.append("applicationRoles/"); + } + + /** Reads the application roles from ZooKeeper, if it exists */ + public Optional<ApplicationRoles> readApplicationRoles(ApplicationId application) { + try { + Optional<byte[]> data = curator.getData(applicationRolesPath(application)); + if (data.isEmpty() || data.get().length == 0) return Optional.empty(); + Slime slime = SlimeUtils.jsonToSlime(data.get()); + ApplicationRoles applicationRoles = ApplicationRolesSerializer.fromSlime(slime.get()); + return Optional.of(applicationRoles); + } catch (Exception e) { + throw new RuntimeException("Error reading application roles of " + application, e); + } + } + + /** Writes the application roles to ZooKeeper */ + public void writeApplicationRoles(ApplicationId application, ApplicationRoles applicationRoles) { + try { + Slime slime = new Slime(); + ApplicationRolesSerializer.toSlime(applicationRoles, slime.setObject()); + curator.set(applicationRolesPath(application), SlimeUtils.toJsonBytes(slime)); + } catch (Exception e) { + throw new RuntimeException("Could not write application roles of " + application, e); + } + } + + /** Returns a transaction which deletes application roles if they exist */ + public CuratorTransaction delete(ApplicationId application) { + if (!curator.exists(applicationRolesPath(application))) return CuratorTransaction.empty(curator); + return CuratorTransaction.from(CuratorOperations.delete(applicationRolesPath(application).getAbsolute()), curator); + } + + /** Returns the path storing the application roles for an application */ + private Path applicationRolesPath(ApplicationId application) { + return path.append(application.serializedForm()); + } +} diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java index 20e8524b9b8..3b8343fc6a4 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/ModelContextImplTest.java @@ -62,6 +62,7 @@ public class ModelContextImplTest { false, flagSource, null, + Optional.empty(), Optional.empty()), Optional.empty(), Optional.empty(), diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/session/PrepareParamsTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/session/PrepareParamsTest.java index 3f5d06b7071..bf21f800815 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/session/PrepareParamsTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/session/PrepareParamsTest.java @@ -1,6 +1,7 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.config.server.session; +import com.yahoo.config.model.api.ApplicationRoles; import com.yahoo.config.model.api.ContainerEndpoint; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.TenantName; @@ -70,6 +71,19 @@ public class PrepareParamsTest { assertEquals(endpoints, prepareParams.containerEndpoints()); } + @Test + public void testCorrectParsingWithApplicationRoles() { + String req = request + "&" + + PrepareParams.APPLICATION_HOST_ROLE + "=hostRole&" + + PrepareParams.APPLICATION_CONTAINER_ROLE + "=containerRole"; + var prepareParams = createParams(req, TenantName.from("foo")); + + Optional<ApplicationRoles> applicationRoles = prepareParams.applicationRoles(); + assertTrue(applicationRoles.isPresent()); + assertEquals("hostRole", applicationRoles.get().applicationHostRole()); + assertEquals("containerRole", applicationRoles.get().applicationContainerRole()); + } + // Create PrepareParams from a request (based on uri and tenant name) private static PrepareParams createParams(String uri, TenantName tenantName) { return PrepareParams.fromHttpRequest( diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/ApplicationRolesStoreTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/ApplicationRolesStoreTest.java new file mode 100644 index 00000000000..a03ea61ec54 --- /dev/null +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/ApplicationRolesStoreTest.java @@ -0,0 +1,39 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.config.server.tenant; + +import com.yahoo.config.model.api.ApplicationRoles; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.path.Path; +import com.yahoo.vespa.curator.mock.MockCurator; +import org.junit.Test; + +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author mortent + */ +public class ApplicationRolesStoreTest { + @Test + public void persists_entry_correctly() { + // Persist + var applicationRolesStore = new ApplicationRolesStore(new MockCurator(), Path.createRoot()); + var roles = new ApplicationRoles("hostRole", "containerRole"); + applicationRolesStore.writeApplicationRoles(ApplicationId.defaultId(), roles); + + // Read + Optional<ApplicationRoles> deserialized = applicationRolesStore.readApplicationRoles(ApplicationId.defaultId()); + assertTrue(deserialized.isPresent()); + assertEquals(roles, deserialized.get()); + } + + @Test + public void read_non_existent() { + var applicationRolesStore = new ApplicationRolesStore(new MockCurator(), Path.createRoot()); + Optional<ApplicationRoles> applicationRoles = applicationRolesStore.readApplicationRoles(ApplicationId.defaultId()); + assertTrue(applicationRoles.isEmpty()); + } + +} |