From 1ce6497f35188ea45e0e7fb74f8a730ac39376ae Mon Sep 17 00:00:00 2001 From: Harald Musum Date: Mon, 21 Aug 2023 11:17:17 +0200 Subject: Write time when session was created, add support for reading sessiond data --- .../vespa/config/server/session/SessionData.java | 23 +++++++++++++++++++++- .../config/server/session/SessionPreparer.java | 3 +++ .../config/server/session/SessionRepository.java | 17 ++++++++++------ .../config/server/session/SessionSerializer.java | 23 ++++++++++++++++++++-- .../server/session/SessionZooKeeperClient.java | 4 ++++ .../server/tenant/TenantSecretStoreSerializer.java | 1 + .../server/session/SessionZooKeeperClientTest.java | 1 + 7 files changed, 63 insertions(+), 9 deletions(-) diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionData.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionData.java index 1fb72e1253e..1d5a560fc8b 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionData.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionData.java @@ -18,9 +18,12 @@ import com.yahoo.vespa.config.server.tenant.TenantSecretStoreSerializer; import java.io.IOException; import java.security.cert.X509Certificate; +import java.time.Instant; import java.util.List; import java.util.Optional; +import static com.yahoo.slime.SlimeUtils.optionalString; + /** * Data class for session information, typically parameters supplied in a deployment request that needs * to be persisted in ZooKeeper. These will be used when creating a new session based on an existing one. @@ -30,6 +33,7 @@ import java.util.Optional; public record SessionData(ApplicationId applicationId, Optional applicationPackageReference, Version version, + Instant created, Optional dockerImageRepository, Optional athenzDomain, Optional quota, @@ -67,7 +71,7 @@ public record SessionData(ApplicationId applicationId, object.setString(APPLICATION_ID_PATH, applicationId.serializedForm()); applicationPackageReference.ifPresent(ref -> object.setString(APPLICATION_PACKAGE_REFERENCE_PATH, ref.value())); object.setString(VERSION_PATH, version.toString()); - object.setLong(CREATE_TIME_PATH, System.currentTimeMillis()); + object.setLong(CREATE_TIME_PATH, created.toEpochMilli()); dockerImageRepository.ifPresent(image -> object.setString(DOCKER_IMAGE_REPOSITORY_PATH, image.asString())); athenzDomain.ifPresent(domain -> object.setString(ATHENZ_DOMAIN, domain.value())); quota.ifPresent(q -> q.toSlime(object.setObject(QUOTA_PATH))); @@ -84,4 +88,21 @@ public record SessionData(ApplicationId applicationId, DataplaneTokenSerializer.toSlime(dataplaneTokens, dataplaneTokensArray); } + static SessionData fromSlime(Slime slime) { + Cursor cursor = slime.get(); + return new SessionData(ApplicationId.fromSerializedForm(cursor.field(APPLICATION_ID_PATH).asString()), + optionalString(cursor.field(APPLICATION_PACKAGE_REFERENCE_PATH)).map(FileReference::new), + Version.fromString(cursor.field(VERSION_PATH).asString()), + Instant.ofEpochMilli(cursor.field(CREATE_TIME_PATH).asLong()), + optionalString(cursor.field(DOCKER_IMAGE_REPOSITORY_PATH)).map(DockerImage::fromString), + optionalString(cursor.field(ATHENZ_DOMAIN)).map(AthenzDomain::from), + SlimeUtils.isPresent(cursor.field(QUOTA_PATH)) + ? Optional.of(Quota.fromSlime(cursor.field(QUOTA_PATH))) + : Optional.empty(), + TenantSecretStoreSerializer.listFromSlime(cursor.field(TENANT_SECRET_STORES_PATH)), + OperatorCertificateSerializer.fromSlime(cursor.field(OPERATOR_CERTIFICATES_PATH)), + optionalString(cursor.field(CLOUD_ACCOUNT_PATH)).map(CloudAccount::from), + DataplaneTokenSerializer.fromSlime(cursor.field(DATAPLANE_TOKENS_PATH))); + } + } 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 60b8b4d1ea8..6c0120eb337 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 @@ -339,6 +339,7 @@ public class SessionPreparer { writeStateToZooKeeper(sessionZooKeeperClient, preprocessedApplicationPackage, applicationId, + sessionZooKeeperClient.readCreateTime(), Optional.of(filereference), dockerImageRepository, vespaVersion, @@ -381,6 +382,7 @@ public class SessionPreparer { private void writeStateToZooKeeper(SessionZooKeeperClient zooKeeperClient, ApplicationPackage applicationPackage, ApplicationId applicationId, + Instant created, Optional fileReference, Optional dockerImageRepository, Version vespaVersion, @@ -398,6 +400,7 @@ public class SessionPreparer { zooKeeperDeplyer.deploy(applicationPackage, fileRegistryMap, allocatedHosts); new SessionSerializer().write(zooKeeperClient, applicationId, + created, fileReference, dockerImageRepository, vespaVersion, diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java index 1af728919d9..eb8f78036ef 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionRepository.java @@ -270,12 +270,14 @@ public class SessionRepository { DeployLogger deployLogger) { ApplicationId applicationId = existingSession.getApplicationId(); File existingApp = getSessionAppDir(existingSession.getSessionId()); + Instant created = clock.instant(); LocalSession session = createSessionFromApplication(existingApp, applicationId, internalRedeploy, timeoutBudget, - deployLogger); - write(existingSession, session, applicationId); + deployLogger, + created); + write(existingSession, session, applicationId, created); return session; } @@ -292,7 +294,8 @@ public class SessionRepository { TimeoutBudget timeoutBudget, DeployLogger deployLogger) { applicationRepo.createApplication(applicationId); - return createSessionFromApplication(applicationDirectory, applicationId, false, timeoutBudget, deployLogger); + return createSessionFromApplication(applicationDirectory, applicationId, false, timeoutBudget, + deployLogger, clock.instant()); } /** @@ -571,10 +574,11 @@ public class SessionRepository { // ---------------- Serialization ---------------------------------------------------------------- - private void write(Session existingSession, LocalSession session, ApplicationId applicationId) { + private void write(Session existingSession, LocalSession session, ApplicationId applicationId, Instant created) { SessionSerializer sessionSerializer = new SessionSerializer(); sessionSerializer.write(session.getSessionZooKeeperClient(), applicationId, + created, existingSession.getApplicationPackageReference(), existingSession.getDockerImageRepository(), existingSession.getVespaVersion(), @@ -729,14 +733,15 @@ public class SessionRepository { ApplicationId applicationId, boolean internalRedeploy, TimeoutBudget timeoutBudget, - DeployLogger deployLogger) { + DeployLogger deployLogger, + Instant created) { long sessionId = getNextSessionId(); try { ensureSessionPathDoesNotExist(sessionId); ApplicationPackage app = createApplicationPackage(applicationDirectory, applicationId, sessionId, internalRedeploy, Optional.of(deployLogger)); log.log(Level.FINE, () -> TenantRepository.logPre(tenantName) + "Creating session " + sessionId + " in ZooKeeper"); SessionZooKeeperClient sessionZKClient = createSessionZooKeeperClient(sessionId); - sessionZKClient.createNewSession(clock.instant()); + sessionZKClient.createNewSession(created); CompletionWaiter waiter = sessionZKClient.getUploadWaiter(); LocalSession session = new LocalSession(tenantName, sessionId, app, sessionZKClient); waiter.awaitCompletion(Duration.ofSeconds(Math.min(120, timeoutBudget.timeLeft().getSeconds()))); diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionSerializer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionSerializer.java index 1202b2bd08b..46acb8c7ef1 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionSerializer.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionSerializer.java @@ -12,6 +12,7 @@ import com.yahoo.config.provision.DockerImage; import com.yahoo.vespa.flags.BooleanFlag; import java.security.cert.X509Certificate; +import java.time.Instant; import java.util.List; import java.util.Optional; @@ -22,7 +23,7 @@ import java.util.Optional; public class SessionSerializer { void write(SessionZooKeeperClient zooKeeperClient, ApplicationId applicationId, - Optional fileReference, Optional dockerImageRepository, + Instant created, Optional fileReference, Optional dockerImageRepository, Version vespaVersion, Optional athenzDomain, Optional quota, List tenantSecretStores, List operatorCertificates, Optional cloudAccount, List dataplaneTokens, @@ -41,6 +42,7 @@ public class SessionSerializer { zooKeeperClient.writeSessionData(new SessionData(applicationId, fileReference, vespaVersion, + created, dockerImageRepository, athenzDomain, quota, @@ -50,4 +52,21 @@ public class SessionSerializer { dataplaneTokens)); } -} \ No newline at end of file + SessionData read(SessionZooKeeperClient zooKeeperClient, BooleanFlag readSessionData) { + if (readSessionData.value()) + return zooKeeperClient.readSessionData(); + else + return new SessionData(zooKeeperClient.readApplicationId(), + zooKeeperClient.readApplicationPackageReference(), + zooKeeperClient.readVespaVersion(), + zooKeeperClient.readCreateTime(), + zooKeeperClient.readDockerImageRepository(), + zooKeeperClient.readAthenzDomain(), + zooKeeperClient.readQuota(), + zooKeeperClient.readTenantSecretStores(), + zooKeeperClient.readOperatorCertificates(), + zooKeeperClient.readCloudAccount(), + zooKeeperClient.readDataplaneTokens()); + } + +} 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 04856f0b5c4..85abd937ac0 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 @@ -225,6 +225,10 @@ public class SessionZooKeeperClient { curator.set(sessionPath.append(SESSION_DATA_PATH), sessionData.toJson()); } + public SessionData readSessionData() { + return SessionData.fromSlime(SlimeUtils.jsonToSlime(curator.getData(sessionPath.append(SESSION_DATA_PATH)).orElseThrow())); + } + public Version readVespaVersion() { Optional data = curator.getData(versionPath()); // TODO: Empty version should not be possible any more - verify and remove diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantSecretStoreSerializer.java b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantSecretStoreSerializer.java index b8df5073a3e..1980fea3ae5 100644 --- a/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantSecretStoreSerializer.java +++ b/configserver/src/main/java/com/yahoo/vespa/config/server/tenant/TenantSecretStoreSerializer.java @@ -60,4 +60,5 @@ public class TenantSecretStoreSerializer { inspector.traverse(((ArrayTraverser)(idx, store) -> tenantSecretStores.add(fromSlime(store)))); return tenantSecretStores; } + } diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClientTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClientTest.java index 569b6624815..5365cbd84f1 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClientTest.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/session/SessionZooKeeperClientTest.java @@ -168,6 +168,7 @@ public class SessionZooKeeperClientTest { zkc.writeSessionData(new SessionData(ApplicationId.defaultId(), Optional.of(new FileReference("foo")), Version.fromString("8.195.1"), + Instant.now(), Optional.empty(), Optional.empty(), Optional.empty(), -- cgit v1.2.3