diff options
author | Morten Tokle <mortent@yahooinc.com> | 2023-06-09 08:34:31 +0200 |
---|---|---|
committer | Morten Tokle <mortent@yahooinc.com> | 2023-06-12 22:53:33 +0200 |
commit | e4a5a20eb19ff2e2d5759f6fef83da5611d1a94e (patch) | |
tree | 1cef0d16766e852e36d9f44b7b2e788b17d9d8b2 | |
parent | 5f25e0ba346c04ccc27c60cc410c0ed2fdb6b06b (diff) |
Persist tokens on deploy
13 files changed, 237 insertions, 9 deletions
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 a9cbe82895f..f84d42eab7c 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 @@ -9,6 +9,7 @@ import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.AthenzDomain; import com.yahoo.config.provision.CloudAccount; import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.DataplaneToken; import com.yahoo.config.provision.DockerImage; import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.Zone; @@ -191,6 +192,8 @@ public interface ModelContext { default Duration endpointConnectionTtl() { return Duration.ZERO; } + default List<DataplaneToken> dataplaneTokens() { return List.of(); } + } @Retention(RetentionPolicy.RUNTIME) diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/DataplaneToken.java b/config-provisioning/src/main/java/com/yahoo/config/provision/DataplaneToken.java new file mode 100644 index 00000000000..422c8bf3a08 --- /dev/null +++ b/config-provisioning/src/main/java/com/yahoo/config/provision/DataplaneToken.java @@ -0,0 +1,54 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.config.provision; + +import java.util.List; +import java.util.Objects; + +/** + * Id, fingerprints and check access hashes of a data plane token + * + * @author mortent + */ +public class DataplaneToken { + + private final String tokenId; + private final List<TokenValue> tokenValues; + + + public DataplaneToken(String tokenId, List<TokenValue> tokenValues) { + this.tokenId = tokenId; + this.tokenValues = List.copyOf(tokenValues); + } + + public String tokenId() { + return tokenId; + } + + public List<TokenValue> tokenValues() { + return tokenValues; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DataplaneToken that = (DataplaneToken) o; + return Objects.equals(tokenId, that.tokenId) && Objects.equals(tokenValues, that.tokenValues); + } + + @Override + public int hashCode() { + return Objects.hash(tokenId, tokenValues); + } + + @Override + public String toString() { + return "DataplaneToken{" + + "tokenId='" + tokenId + '\'' + + ", tokenValues=" + tokenValues + + '}'; + } + + public record TokenValue (String fingerprint, String checkAccessHash){ + } +} 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 efdcaeec3aa..36f09f989a7 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 @@ -21,6 +21,7 @@ import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.AthenzDomain; import com.yahoo.config.provision.CloudAccount; import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.DataplaneToken; import com.yahoo.config.provision.DockerImage; import com.yahoo.config.provision.HostName; import com.yahoo.config.provision.TenantName; @@ -385,6 +386,7 @@ public class ModelContextImpl implements ModelContext { private final List<String> zoneDnsSuffixes; private final List<String> environmentVariables; private final Optional<CloudAccount> cloudAccount; + private final List<DataplaneToken> dataplaneTokens; private final boolean allowUserFilters; private final Duration endpointConnectionTtl; @@ -402,7 +404,8 @@ public class ModelContextImpl implements ModelContext { List<TenantSecretStore> tenantSecretStores, SecretStore secretStore, List<X509Certificate> operatorCertificates, - Optional<CloudAccount> cloudAccount) { + Optional<CloudAccount> cloudAccount, + List<DataplaneToken> dataplaneTokens) { this.featureFlags = new FeatureFlags(flagSource, applicationId, modelVersion); this.applicationId = applicationId; this.multitenant = configserverConfig.multitenant() || configserverConfig.hostedVespa() || Boolean.getBoolean("multitenant"); @@ -436,6 +439,7 @@ public class ModelContextImpl implements ModelContext { this.endpointConnectionTtl = Duration.ofSeconds( PermanentFlags.ENDPOINT_CONNECTION_TTL.bindTo(flagSource) .with(FetchVector.Dimension.APPLICATION_ID, applicationId.serializedForm()).value()); + this.dataplaneTokens = dataplaneTokens; } @Override public ModelContext.FeatureFlags featureFlags() { return featureFlags; } @@ -525,6 +529,11 @@ public class ModelContextImpl implements ModelContext { return cloudAccount; } + @Override + public List<DataplaneToken> dataplaneTokens() { + return dataplaneTokens; + } + @Override public boolean allowUserFilters() { return allowUserFilters; } @Override public Duration endpointConnectionTtl() { return endpointConnectionTtl; } 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 9497a298a33..0e45d42efcf 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 @@ -156,7 +156,8 @@ public class ActivatedModelsBuilder extends ModelsBuilder<Application> { zkClient.readTenantSecretStores(), secretStore, zkClient.readOperatorCertificates(), - zkClient.readCloudAccount()); + zkClient.readCloudAccount(), + zkClient.readDataplaneTokens()); } } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java index 1bfa94a1355..fc86629125f 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/PreparedModelsBuilder.java @@ -209,7 +209,8 @@ public class PreparedModelsBuilder extends ModelsBuilder<PreparedModelsBuilder.P params.tenantSecretStores(), secretStore, params.operatorCertificates(), - params.cloudAccount()); + params.cloudAccount(), + params.dataplaneTokens()); } /** The result of preparing a single model version */ 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 239026249e5..f00e37e0ee8 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 @@ -9,6 +9,7 @@ import com.yahoo.config.model.api.TenantSecretStore; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.AthenzDomain; import com.yahoo.config.provision.CloudAccount; +import com.yahoo.config.provision.DataplaneToken; import com.yahoo.config.provision.DockerImage; import com.yahoo.config.provision.TenantName; import com.yahoo.container.jdisc.HttpRequest; @@ -20,6 +21,7 @@ import com.yahoo.vespa.config.server.TimeoutBudget; import com.yahoo.vespa.config.server.http.SessionHandler; import com.yahoo.vespa.config.server.tenant.CloudAccountSerializer; import com.yahoo.vespa.config.server.tenant.ContainerEndpointSerializer; +import com.yahoo.vespa.config.server.tenant.DataplaneTokenSerializer; import com.yahoo.vespa.config.server.tenant.EndpointCertificateMetadataSerializer; import com.yahoo.vespa.config.server.tenant.TenantSecretStoreSerializer; @@ -55,6 +57,7 @@ public final class PrepareParams { static final String WAIT_FOR_RESOURCES_IN_PREPARE = "waitForResourcesInPrepare"; static final String OPERATOR_CERTIFICATES = "operatorCertificates"; static final String CLOUD_ACCOUNT = "cloudAccount"; + static final String DATAPLANE_TOKENS = "dataplaneTokens"; private final ApplicationId applicationId; private final TimeoutBudget timeoutBudget; @@ -73,6 +76,7 @@ public final class PrepareParams { private final List<TenantSecretStore> tenantSecretStores; private final List<X509Certificate> operatorCertificates; private final Optional<CloudAccount> cloudAccount; + private final List<DataplaneToken> dataplaneTokens; private PrepareParams(ApplicationId applicationId, TimeoutBudget timeoutBudget, @@ -90,7 +94,8 @@ public final class PrepareParams { boolean force, boolean waitForResourcesInPrepare, List<X509Certificate> operatorCertificates, - Optional<CloudAccount> cloudAccount) { + Optional<CloudAccount> cloudAccount, + List<DataplaneToken> dataplaneTokens) { this.timeoutBudget = timeoutBudget; this.applicationId = Objects.requireNonNull(applicationId); this.ignoreValidationErrors = ignoreValidationErrors; @@ -108,6 +113,7 @@ public final class PrepareParams { this.waitForResourcesInPrepare = waitForResourcesInPrepare; this.operatorCertificates = operatorCertificates; this.cloudAccount = Objects.requireNonNull(cloudAccount); + this.dataplaneTokens = dataplaneTokens; } public static class Builder { @@ -129,6 +135,7 @@ public final class PrepareParams { private List<TenantSecretStore> tenantSecretStores = List.of(); private List<X509Certificate> operatorCertificates = List.of(); private Optional<CloudAccount> cloudAccount = Optional.empty(); + private List<DataplaneToken> dataplaneTokens = List.of(); public Builder() { } @@ -266,6 +273,11 @@ public final class PrepareParams { return this; } + public Builder dataplaneTokens(List<DataplaneToken> dataplaneTokens) { + this.dataplaneTokens = List.copyOf(dataplaneTokens); + return this; + } + public PrepareParams build() { return new PrepareParams(applicationId, timeoutBudget, @@ -283,7 +295,8 @@ public final class PrepareParams { force, waitForResourcesInPrepare, operatorCertificates, - cloudAccount); + cloudAccount, + dataplaneTokens); } } @@ -327,6 +340,7 @@ public final class PrepareParams { .waitForResourcesInPrepare(booleanValue(params, WAIT_FOR_RESOURCES_IN_PREPARE)) .operatorCertificates(deserialize(params.field(OPERATOR_CERTIFICATES), PrepareParams::readOperatorCertificates, List.of())) .cloudAccount(deserialize(params.field(CLOUD_ACCOUNT), CloudAccountSerializer::fromSlime, null)) + .dataplaneTokens(deserialize(params.field(DATAPLANE_TOKENS), DataplaneTokenSerializer::fromSlime, List.of())) .build(); } @@ -444,4 +458,7 @@ public final class PrepareParams { return cloudAccount; } + public List<DataplaneToken> dataplaneTokens() { + return dataplaneTokens; + } } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/Session.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/Session.java index 94b3bd96620..b627fe9ba3b 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/Session.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/Session.java @@ -12,6 +12,7 @@ import com.yahoo.config.provision.AllocatedHosts; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.AthenzDomain; import com.yahoo.config.provision.CloudAccount; +import com.yahoo.config.provision.DataplaneToken; import com.yahoo.config.provision.DockerImage; import com.yahoo.config.provision.TenantName; import com.yahoo.path.Path; @@ -151,6 +152,10 @@ public abstract class Session implements Comparable<Session> { sessionZooKeeperClient.writeCloudAccount(cloudAccount); } + public void setDataplaneTokens(List<DataplaneToken> dataplaneTokens) { + sessionZooKeeperClient.writeDataplaneTokens(dataplaneTokens); + } + /** Returns application id read from ZooKeeper. Will throw RuntimeException if not found */ public ApplicationId getApplicationId() { return sessionZooKeeperClient.readApplicationId(); } @@ -193,6 +198,10 @@ public abstract class Session implements Comparable<Session> { return sessionZooKeeperClient.readCloudAccount(); } + public List<DataplaneToken> getDataplaneTokens() { + return sessionZooKeeperClient.readDataplaneTokens(); + } + private Transaction createSetStatusTransaction(Status status) { return sessionZooKeeperClient.createWriteStatusTransaction(status); } 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 d33dcea5c69..ae87a0dd182 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 @@ -24,6 +24,7 @@ import com.yahoo.config.provision.AllocatedHosts; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.AthenzDomain; import com.yahoo.config.provision.CloudAccount; +import com.yahoo.config.provision.DataplaneToken; import com.yahoo.config.provision.DockerImage; import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.Tags; @@ -344,7 +345,8 @@ public class SessionPreparer { params.quota(), params.tenantSecretStores(), params.operatorCertificates(), - params.cloudAccount()); + params.cloudAccount(), + params.dataplaneTokens()); checkTimeout("write state to zookeeper"); } @@ -385,7 +387,8 @@ public class SessionPreparer { Optional<Quota> quota, List<TenantSecretStore> tenantSecretStores, List<X509Certificate> operatorCertificates, - Optional<CloudAccount> cloudAccount) { + Optional<CloudAccount> cloudAccount, + List<DataplaneToken> dataplaneTokens) { ZooKeeperDeployer zkDeployer = zooKeeperClient.createDeployer(deployLogger); try { zkDeployer.deploy(applicationPackage, fileRegistryMap, allocatedHosts); @@ -399,6 +402,7 @@ public class SessionPreparer { zooKeeperClient.writeTenantSecretStores(tenantSecretStores); zooKeeperClient.writeOperatorCertificates(operatorCertificates); zooKeeperClient.writeCloudAccount(cloudAccount); + zooKeeperClient.writeDataplaneTokens(dataplaneTokens); } catch (RuntimeException | IOException e) { zkDeployer.cleanup(); throw new RuntimeException("Error preparing session", e); diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java index 6284ecad33e..23b6fe075fa 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClient.java @@ -14,6 +14,7 @@ import com.yahoo.config.provision.AllocatedHosts; import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.AthenzDomain; import com.yahoo.config.provision.CloudAccount; +import com.yahoo.config.provision.DataplaneToken; import com.yahoo.config.provision.DockerImage; import com.yahoo.config.provision.TenantName; import com.yahoo.path.Path; @@ -27,6 +28,7 @@ import com.yahoo.vespa.config.server.deploy.ZooKeeperDeployer; import com.yahoo.vespa.config.server.filedistribution.AddFileInterface; import com.yahoo.vespa.config.server.filedistribution.MockFileManager; import com.yahoo.vespa.config.server.tenant.CloudAccountSerializer; +import com.yahoo.vespa.config.server.tenant.DataplaneTokenSerializer; import com.yahoo.vespa.config.server.tenant.OperatorCertificateSerializer; import com.yahoo.vespa.config.server.tenant.TenantRepository; import com.yahoo.vespa.config.server.tenant.TenantSecretStoreSerializer; @@ -69,6 +71,7 @@ public class SessionZooKeeperClient { private static final String TENANT_SECRET_STORES_PATH = "tenantSecretStores"; private static final String OPERATOR_CERTIFICATES_PATH = "operatorCertificates"; private static final String CLOUD_ACCOUNT_PATH = "cloudAccount"; + private static final String DATAPLANE_TOKENS_PATH = "dataplaneTokens"; private final Curator curator; private final TenantName tenantName; @@ -216,6 +219,10 @@ public class SessionZooKeeperClient { return sessionPath.append(CLOUD_ACCOUNT_PATH); } + private Path dataplaneTokensPath() { + return sessionPath.append(DATAPLANE_TOKENS_PATH); + } + public void writeVespaVersion(Version version) { curator.set(versionPath(), Utf8.toBytes(version.toString())); } @@ -335,6 +342,18 @@ public class SessionZooKeeperClient { return curator.getData(cloudAccountPath()).map(SlimeUtils::jsonToSlime).map(slime -> CloudAccountSerializer.fromSlime(slime.get())); } + public void writeDataplaneTokens(List<DataplaneToken> dataplaneTokens) { + byte[] data = uncheck(() -> SlimeUtils.toJsonBytes(DataplaneTokenSerializer.toSlime(dataplaneTokens))); + curator.set(dataplaneTokensPath(), data); + } + + public List<DataplaneToken> readDataplaneTokens() { + return curator.getData(dataplaneTokensPath()) + .map(SlimeUtils::jsonToSlime) + .map(slime -> DataplaneTokenSerializer.fromSlime(slime.get())) + .orElse(List.of()); + } + /** * Create necessary paths atomically for a new session. * @@ -352,5 +371,4 @@ public class SessionZooKeeperClient { private static Path getSessionPath(TenantName tenantName, long sessionId) { return TenantRepository.getSessionsPath(tenantName).append(String.valueOf(sessionId)); } - } diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/DataplaneTokenSerializer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/DataplaneTokenSerializer.java new file mode 100644 index 00000000000..be6bf7164ad --- /dev/null +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/DataplaneTokenSerializer.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.config.server.tenant; + +import com.yahoo.config.provision.DataplaneToken; +import com.yahoo.slime.Cursor; +import com.yahoo.slime.Inspector; +import com.yahoo.slime.Slime; +import com.yahoo.slime.SlimeUtils; + +import java.util.List; + +/** + * Serialize/deserialize dataplane tokens + * + * @author mortent + */ +public class DataplaneTokenSerializer { + + private static final String ID_FIELD = "id"; + private static final String VALUES_FIELD = "values"; + private static final String FINGERPRINT_FIELD = "fingerPrint"; + private static final String CHECKACCESSHASH_FIELD = "checkAccessHash"; + + private DataplaneTokenSerializer() {} + + public static List<DataplaneToken> fromSlime(Inspector object) { + return SlimeUtils.entriesStream(object) + .map(DataplaneTokenSerializer::tokenFromSlime) + .toList(); + } + + private static DataplaneToken tokenFromSlime(Inspector object) { + String id = object.field(ID_FIELD).asString(); + List<DataplaneToken.TokenValue> values = SlimeUtils.entriesStream(object.field(VALUES_FIELD)) + .filter(Inspector::valid) + .map(DataplaneTokenSerializer::tokenValue) + .toList(); + return new DataplaneToken(id, values); + } + + private static DataplaneToken.TokenValue tokenValue(Inspector inspector) { + return new DataplaneToken.TokenValue( + inspector.field(FINGERPRINT_FIELD).asString(), + inspector.field(CHECKACCESSHASH_FIELD).asString()); + } + + public static Slime toSlime(List<DataplaneToken> dataplaneTokens) { + Slime slime = new Slime(); + Cursor root = slime.setArray(); + for (DataplaneToken token : dataplaneTokens) { + Cursor cursor = root.addObject(); + cursor.setString(ID_FIELD, token.tokenId()); + Cursor values = cursor.setArray(VALUES_FIELD); + token.tokenValues().forEach(v -> { + Cursor val = values.addObject(); + val.setString(FINGERPRINT_FIELD, v.fingerprint()); + val.setString(CHECKACCESSHASH_FIELD, v.checkAccessHash()); + }); + } + return slime; + } +} 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 2ef9a41a967..f5cd56707b3 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 @@ -75,7 +75,8 @@ public class ModelContextImplTest { List.of(), new SecretStoreProvider().get(), List.of(), - Optional.empty()), + Optional.empty(), + List.of()), Optional.empty(), Optional.empty(), new Version(7), diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionPreparerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionPreparerTest.java index 4af0881e200..19f24f8e817 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionPreparerTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionPreparerTest.java @@ -16,6 +16,7 @@ import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.ApplicationName; import com.yahoo.config.provision.CertificateNotReadyException; import com.yahoo.config.provision.CloudAccount; +import com.yahoo.config.provision.DataplaneToken; import com.yahoo.config.provision.InstanceName; import com.yahoo.config.provision.TenantName; import com.yahoo.config.provision.Zone; @@ -360,6 +361,25 @@ public class SessionPreparerTest { assertEquals(Optional.of(expected), accountFromModel); } + @Test + public void require_that_dataplane_tokens_are_written() throws Exception { + TestModelFactory modelFactory = new TestModelFactory(version123); + preparer = createPreparer(new ModelFactoryRegistry(List.of(modelFactory)), HostProvisionerProvider.empty()); + ApplicationId applicationId = applicationId("test"); + List<DataplaneToken> expected = List.of(new DataplaneToken("id", List.of(new DataplaneToken.TokenValue("f1", "ch1")))); + PrepareParams params = new PrepareParams.Builder().applicationId(applicationId) + .dataplaneTokens(expected) + .build(); + prepare(new File("src/test/resources/deploy/hosted-app"), params); + + SessionZooKeeperClient zkClient = createSessionZooKeeperClient(); + assertEquals(expected, zkClient.readDataplaneTokens()); + + ModelContext modelContext = modelFactory.getModelContext(); + List<DataplaneToken> tokensFromModel = modelContext.properties().dataplaneTokens(); + assertEquals(expected, tokensFromModel); + } + private List<ContainerEndpoint> readContainerEndpoints(ApplicationId applicationId) { Path tenantPath = TenantRepository.getTenantPath(applicationId.tenant()); return new ContainerEndpointsCache(tenantPath, curator).read(applicationId); diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/DataplaneTokenSerializerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/DataplaneTokenSerializerTest.java new file mode 100644 index 00000000000..cb9e29e6517 --- /dev/null +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/tenant/DataplaneTokenSerializerTest.java @@ -0,0 +1,29 @@ +// Copyright Yahoo. 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.provision.DataplaneToken; +import com.yahoo.slime.Slime; +import org.junit.Test; + +import java.util.List; + +import static org.junit.Assert.assertEquals; + +/** + * @author mortent + */ +public class DataplaneTokenSerializerTest { + + @Test + public void testSerialization() { + List<DataplaneToken> tokens = List.of( + new DataplaneToken("id1", + List.of(new DataplaneToken.TokenValue("id1_fingerPrint1", "id1_checkaccesshash1"))), + new DataplaneToken("id2", + List.of(new DataplaneToken.TokenValue("id2_fingerPrint1", "id2_checkaccesshash1"), + new DataplaneToken.TokenValue("id3_fingerPrint1", "id3_checkaccesshash1")))); + Slime slime = DataplaneTokenSerializer.toSlime(tokens); + List<DataplaneToken> deserialized = DataplaneTokenSerializer.fromSlime(slime.get()); + assertEquals(tokens, deserialized); + } +} |