com.yahoo.vespa.hosted.controller.persistence.CuratorDb Maven / Gradle / Ivy
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.persistence;
import com.google.inject.Inject;
import com.yahoo.collections.Pair;
import com.yahoo.component.Version;
import com.yahoo.concurrent.UncheckedTimeoutException;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.zone.ZoneId;
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.Lock;
import com.yahoo.vespa.hosted.controller.Application;
import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId;
import com.yahoo.vespa.hosted.controller.api.integration.archive.ArchiveBucket;
import com.yahoo.vespa.hosted.controller.api.integration.certificates.EndpointCertificateMetadata;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId;
import com.yahoo.vespa.hosted.controller.api.integration.vcmr.VespaChangeRequest;
import com.yahoo.vespa.hosted.controller.application.TenantAndApplicationId;
import com.yahoo.vespa.hosted.controller.auditlog.AuditLog;
import com.yahoo.vespa.hosted.controller.deployment.RetriggerEntry;
import com.yahoo.vespa.hosted.controller.deployment.RetriggerEntrySerializer;
import com.yahoo.vespa.hosted.controller.deployment.Run;
import com.yahoo.vespa.hosted.controller.deployment.Step;
import com.yahoo.vespa.hosted.controller.dns.NameServiceQueue;
import com.yahoo.vespa.hosted.controller.notification.Notification;
import com.yahoo.vespa.hosted.controller.routing.RoutingPolicy;
import com.yahoo.vespa.hosted.controller.routing.RoutingStatus;
import com.yahoo.vespa.hosted.controller.routing.ZoneRoutingPolicy;
import com.yahoo.vespa.hosted.controller.support.access.SupportAccess;
import com.yahoo.vespa.hosted.controller.tenant.Tenant;
import com.yahoo.vespa.hosted.controller.versions.ControllerVersion;
import com.yahoo.vespa.hosted.controller.versions.OsVersionStatus;
import com.yahoo.vespa.hosted.controller.versions.OsVersionTarget;
import com.yahoo.vespa.hosted.controller.versions.VersionStatus;
import com.yahoo.vespa.hosted.controller.versions.VespaVersion;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.ByteBuffer;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toUnmodifiableList;
/**
* Curator backed database for storing the persistence state of controllers. This maps controller specific operations
* to general curator operations.
*
* @author bratseth
* @author mpolden
* @author jonmv
*/
public class CuratorDb {
private static final Logger log = Logger.getLogger(CuratorDb.class.getName());
private static final Duration deployLockTimeout = Duration.ofMinutes(30);
private static final Duration defaultLockTimeout = Duration.ofMinutes(5);
private static final Duration defaultTryLockTimeout = Duration.ofSeconds(1);
private static final Path root = Path.fromString("/controller/v1");
private static final Path lockRoot = root.append("locks");
private static final Path tenantRoot = root.append("tenants");
private static final Path applicationRoot = root.append("applications");
private static final Path jobRoot = root.append("jobs");
private static final Path controllerRoot = root.append("controllers");
private static final Path routingPoliciesRoot = root.append("routingPolicies");
private static final Path zoneRoutingPoliciesRoot = root.append("zoneRoutingPolicies");
private static final Path endpointCertificateRoot = root.append("applicationCertificates");
private static final Path archiveBucketsRoot = root.append("archiveBuckets");
private static final Path changeRequestsRoot = root.append("changeRequests");
private static final Path notificationsRoot = root.append("notifications");
private static final Path supportAccessRoot = root.append("supportAccess");
private final NodeVersionSerializer nodeVersionSerializer = new NodeVersionSerializer();
private final VersionStatusSerializer versionStatusSerializer = new VersionStatusSerializer(nodeVersionSerializer);
private final ControllerVersionSerializer controllerVersionSerializer = new ControllerVersionSerializer();
private final ConfidenceOverrideSerializer confidenceOverrideSerializer = new ConfidenceOverrideSerializer();
private final TenantSerializer tenantSerializer = new TenantSerializer();
private final ApplicationSerializer applicationSerializer = new ApplicationSerializer();
private final RunSerializer runSerializer = new RunSerializer();
private final OsVersionSerializer osVersionSerializer = new OsVersionSerializer();
private final OsVersionTargetSerializer osVersionTargetSerializer = new OsVersionTargetSerializer(osVersionSerializer);
private final OsVersionStatusSerializer osVersionStatusSerializer = new OsVersionStatusSerializer(osVersionSerializer, nodeVersionSerializer);
private final RoutingPolicySerializer routingPolicySerializer = new RoutingPolicySerializer();
private final ZoneRoutingPolicySerializer zoneRoutingPolicySerializer = new ZoneRoutingPolicySerializer(routingPolicySerializer);
private final AuditLogSerializer auditLogSerializer = new AuditLogSerializer();
private final NameServiceQueueSerializer nameServiceQueueSerializer = new NameServiceQueueSerializer();
private final Curator curator;
private final Duration tryLockTimeout;
// For each application id (path), store the ZK node version and its deserialised data - update when version changes.
// This will grow to keep all applications in memory, but this should be OK
private final Map> cachedApplications = new ConcurrentHashMap<>();
// For each job id (path), store the ZK node version and its deserialised data - update when version changes.
private final Map>> cachedHistoricRuns = new ConcurrentHashMap<>();
@Inject
public CuratorDb(Curator curator) {
this(curator, defaultTryLockTimeout);
}
CuratorDb(Curator curator, Duration tryLockTimeout) {
this.curator = curator;
this.tryLockTimeout = tryLockTimeout;
}
/** Returns all hostnames configured to be part of this ZooKeeper cluster */
public List cluster() {
return Arrays.stream(curator.zooKeeperEnsembleConnectionSpec().split(","))
.filter(hostAndPort -> !hostAndPort.isEmpty())
.map(hostAndPort -> hostAndPort.split(":")[0])
.collect(Collectors.toUnmodifiableList());
}
// -------------- Locks ---------------------------------------------------
public Lock lock(TenantName name) {
return curator.lock(lockPath(name), defaultLockTimeout.multipliedBy(2));
}
public Lock lock(TenantAndApplicationId id) {
return curator.lock(lockPath(id), defaultLockTimeout.multipliedBy(2));
}
public Lock lockForDeployment(ApplicationId id, ZoneId zone) {
return curator.lock(lockPath(id, zone), deployLockTimeout);
}
public Lock lock(ApplicationId id, JobType type) {
return curator.lock(lockPath(id, type), defaultLockTimeout);
}
public Lock lock(ApplicationId id, JobType type, Step step) throws TimeoutException {
return tryLock(lockPath(id, type, step));
}
public Lock lockRotations() {
return curator.lock(lockRoot.append("rotations"), defaultLockTimeout);
}
public Lock lockConfidenceOverrides() {
return curator.lock(lockRoot.append("confidenceOverrides"), defaultLockTimeout);
}
public Lock lockMaintenanceJob(String jobName) {
try {
return tryLock(lockRoot.append("maintenanceJobLocks").append(jobName));
} catch (TimeoutException e) {
throw new UncheckedTimeoutException(e);
}
}
@SuppressWarnings("unused") // Called by internal code
public Lock lockProvisionState(String provisionStateId) {
return curator.lock(lockPath(provisionStateId), Duration.ofSeconds(1));
}
public Lock lockOsVersions() {
return curator.lock(lockRoot.append("osTargetVersion"), defaultLockTimeout);
}
public Lock lockOsVersionStatus() {
return curator.lock(lockRoot.append("osVersionStatus"), defaultLockTimeout);
}
public Lock lockRoutingPolicies() {
return curator.lock(lockRoot.append("routingPolicies"), defaultLockTimeout);
}
public Lock lockAuditLog() {
return curator.lock(lockRoot.append("auditLog"), defaultLockTimeout);
}
public Lock lockNameServiceQueue() {
return curator.lock(lockRoot.append("nameServiceQueue"), defaultLockTimeout);
}
public Lock lockMeteringRefreshTime() throws TimeoutException {
return tryLock(lockRoot.append("meteringRefreshTime"));
}
public Lock lockArchiveBuckets(ZoneId zoneId) {
return curator.lock(lockRoot.append("archiveBuckets").append(zoneId.value()), defaultLockTimeout);
}
public Lock lockChangeRequests() {
return curator.lock(lockRoot.append("changeRequests"), defaultLockTimeout);
}
public Lock lockNotifications(TenantName tenantName) {
return curator.lock(lockRoot.append("notifications").append(tenantName.value()), defaultLockTimeout);
}
public Lock lockSupportAccess(DeploymentId deploymentId) {
return curator.lock(lockRoot.append("supportAccess").append(deploymentId.dottedString()), defaultLockTimeout);
}
public Lock lockDeploymentRetriggerQueue() {
return curator.lock(lockRoot.append("deploymentRetriggerQueue"), defaultLockTimeout);
}
// -------------- Helpers ------------------------------------------
/** Try locking with a low timeout, meaning it is OK to fail lock acquisition.
*
* Useful for maintenance jobs, where there is no point in running the jobs back to back.
*/
private Lock tryLock(Path path) throws TimeoutException {
try {
return curator.lock(path, tryLockTimeout);
}
catch (UncheckedTimeoutException e) {
throw new TimeoutException(e.getMessage());
}
}
private Optional read(Path path, Function mapper) {
return curator.getData(path).filter(data -> data.length > 0).map(mapper);
}
private Optional readSlime(Path path) {
return read(path, SlimeUtils::jsonToSlime);
}
private static byte[] asJson(Slime slime) {
try {
return SlimeUtils.toJsonBytes(slime);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
// -------------- Deployment orchestration --------------------------------
public double readUpgradesPerMinute() {
return read(upgradesPerMinutePath(), ByteBuffer::wrap).map(ByteBuffer::getDouble).orElse(0.125);
}
public void writeUpgradesPerMinute(double n) {
curator.set(upgradesPerMinutePath(), ByteBuffer.allocate(Double.BYTES).putDouble(n).array());
}
public Optional readTargetMajorVersion() {
return read(targetMajorVersionPath(), ByteBuffer::wrap).map(ByteBuffer::getInt);
}
public void writeTargetMajorVersion(Optional targetMajorVersion) {
if (targetMajorVersion.isPresent())
curator.set(targetMajorVersionPath(), ByteBuffer.allocate(Integer.BYTES).putInt(targetMajorVersion.get()).array());
else
curator.delete(targetMajorVersionPath());
}
public void writeVersionStatus(VersionStatus status) {
curator.set(versionStatusPath(), asJson(versionStatusSerializer.toSlime(status)));
}
public VersionStatus readVersionStatus() {
return readSlime(versionStatusPath()).map(versionStatusSerializer::fromSlime).orElseGet(VersionStatus::empty);
}
public void writeConfidenceOverrides(Map overrides) {
curator.set(confidenceOverridesPath(), asJson(confidenceOverrideSerializer.toSlime(overrides)));
}
public Map readConfidenceOverrides() {
return readSlime(confidenceOverridesPath()).map(confidenceOverrideSerializer::fromSlime)
.orElseGet(Collections::emptyMap);
}
public void writeControllerVersion(HostName hostname, ControllerVersion version) {
curator.set(controllerPath(hostname.value()), asJson(controllerVersionSerializer.toSlime(version)));
}
public ControllerVersion readControllerVersion(HostName hostname) {
return readSlime(controllerPath(hostname.value()))
.map(controllerVersionSerializer::fromSlime)
.orElse(ControllerVersion.CURRENT);
}
// Infrastructure upgrades
public void writeOsVersionTargets(Set versions) {
curator.set(osVersionTargetsPath(), asJson(osVersionTargetSerializer.toSlime(versions)));
}
public Set readOsVersionTargets() {
return readSlime(osVersionTargetsPath()).map(osVersionTargetSerializer::fromSlime).orElseGet(Collections::emptySet);
}
public void writeOsVersionStatus(OsVersionStatus status) {
curator.set(osVersionStatusPath(), asJson(osVersionStatusSerializer.toSlime(status)));
}
public OsVersionStatus readOsVersionStatus() {
return readSlime(osVersionStatusPath()).map(osVersionStatusSerializer::fromSlime).orElse(OsVersionStatus.empty);
}
// -------------- Tenant --------------------------------------------------
public void writeTenant(Tenant tenant) {
curator.set(tenantPath(tenant.name()), asJson(tenantSerializer.toSlime(tenant)));
}
public Optional readTenant(TenantName name) {
return readSlime(tenantPath(name)).map(bytes -> tenantSerializer.tenantFrom(bytes));
}
public List readTenants() {
return readTenantNames().stream()
.map(this::readTenant)
.flatMap(Optional::stream)
.collect(collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
}
public List readTenantNames() {
return curator.getChildren(tenantRoot).stream()
.map(TenantName::from)
.collect(Collectors.toList());
}
public void removeTenant(TenantName name) {
curator.delete(tenantPath(name));
}
// -------------- Applications ---------------------------------------------
public void writeApplication(Application application) {
curator.set(applicationPath(application.id()), asJson(applicationSerializer.toSlime(application)));
}
public Optional readApplication(TenantAndApplicationId application) {
Path path = applicationPath(application);
return curator.getStat(path)
.map(stat -> cachedApplications.compute(path, (__, old) ->
old != null && old.getFirst() == stat.getVersion()
? old
: new Pair<>(stat.getVersion(), read(path, applicationSerializer::fromSlime).get())).getSecond());
}
public List readApplications(boolean canFail) {
return readApplications(ignored -> true, canFail);
}
public List readApplications(TenantName name) {
return readApplications(application -> application.tenant().equals(name), false);
}
private List readApplications(Predicate applicationFilter, boolean canFail) {
var applicationIds = readApplicationIds();
var applications = new ArrayList(applicationIds.size());
for (var id : applicationIds) {
if (!applicationFilter.test(id)) continue;
try {
readApplication(id).ifPresent(applications::add);
} catch (Exception e) {
if (canFail) {
log.log(Level.SEVERE, "Failed to read application '" + id + "', this must be fixed through " +
"manual intervention", e);
} else {
throw e;
}
}
}
return Collections.unmodifiableList(applications);
}
public List readApplicationIds() {
return curator.getChildren(applicationRoot).stream()
.map(TenantAndApplicationId::fromSerialized)
.sorted()
.collect(toUnmodifiableList());
}
public void removeApplication(TenantAndApplicationId id) {
curator.delete(applicationPath(id));
}
// -------------- Job Runs ------------------------------------------------
public void writeLastRun(Run run) {
curator.set(lastRunPath(run.id().application(), run.id().type()), asJson(runSerializer.toSlime(run)));
}
public void writeHistoricRuns(ApplicationId id, JobType type, Iterable runs) {
Path path = runsPath(id, type);
curator.set(path, asJson(runSerializer.toSlime(runs)));
}
public Optional readLastRun(ApplicationId id, JobType type) {
return readSlime(lastRunPath(id, type)).map(runSerializer::runFromSlime);
}
public NavigableMap readHistoricRuns(ApplicationId id, JobType type) {
Path path = runsPath(id, type);
return curator.getStat(path)
.map(stat -> cachedHistoricRuns.compute(path, (__, old) ->
old != null && old.getFirst() == stat.getVersion()
? old
: new Pair<>(stat.getVersion(), runSerializer.runsFromSlime(readSlime(path).get()))).getSecond())
.orElseGet(Collections::emptyNavigableMap);
}
public void deleteRunData(ApplicationId id, JobType type) {
curator.delete(runsPath(id, type));
curator.delete(lastRunPath(id, type));
}
public void deleteRunData(ApplicationId id) {
curator.delete(jobRoot.append(id.serializedForm()));
}
public List applicationsWithJobs() {
return curator.getChildren(jobRoot).stream()
.map(ApplicationId::fromSerializedForm)
.collect(Collectors.toList());
}
public Optional readLog(ApplicationId id, JobType type, long chunkId) {
return curator.getData(logPath(id, type, chunkId));
}
public void writeLog(ApplicationId id, JobType type, long chunkId, byte[] log) {
curator.set(logPath(id, type, chunkId), log);
}
public void deleteLog(ApplicationId id, JobType type) {
curator.delete(runsPath(id, type).append("logs"));
}
public Optional readLastLogEntryId(ApplicationId id, JobType type) {
return curator.getData(lastLogPath(id, type))
.map(String::new).map(Long::parseLong);
}
public void writeLastLogEntryId(ApplicationId id, JobType type, long lastId) {
curator.set(lastLogPath(id, type), Long.toString(lastId).getBytes());
}
public LongStream getLogChunkIds(ApplicationId id, JobType type) {
return curator.getChildren(runsPath(id, type).append("logs")).stream()
.mapToLong(Long::parseLong)
.sorted();
}
// -------------- Audit log -----------------------------------------------
public AuditLog readAuditLog() {
return readSlime(auditLogPath()).map(auditLogSerializer::fromSlime)
.orElse(AuditLog.empty);
}
public void writeAuditLog(AuditLog log) {
curator.set(auditLogPath(), asJson(auditLogSerializer.toSlime(log)));
}
// -------------- Name service log ----------------------------------------
public NameServiceQueue readNameServiceQueue() {
return readSlime(nameServiceQueuePath()).map(nameServiceQueueSerializer::fromSlime)
.orElse(NameServiceQueue.EMPTY);
}
public void writeNameServiceQueue(NameServiceQueue queue) {
curator.set(nameServiceQueuePath(), asJson(nameServiceQueueSerializer.toSlime(queue)));
}
// -------------- Provisioning (called by internal code) ------------------
@SuppressWarnings("unused")
public Optional readProvisionState(String provisionId) {
return curator.getData(provisionStatePath(provisionId));
}
@SuppressWarnings("unused")
public void writeProvisionState(String provisionId, byte[] data) {
curator.set(provisionStatePath(provisionId), data);
}
@SuppressWarnings("unused")
public List readProvisionStateIds() {
return curator.getChildren(provisionStatePath());
}
// -------------- Routing policies ----------------------------------------
public void writeRoutingPolicies(ApplicationId application, List policies) {
for (var policy : policies) {
if (!policy.id().owner().equals(application)) {
throw new IllegalArgumentException(policy.id() + " does not belong to the application being written: " +
application.toShortString());
}
}
curator.set(routingPolicyPath(application), asJson(routingPolicySerializer.toSlime(policies)));
}
public Map> readRoutingPolicies() {
return readRoutingPolicies((instance) -> true);
}
public Map> readRoutingPolicies(Predicate filter) {
return curator.getChildren(routingPoliciesRoot).stream()
.map(ApplicationId::fromSerializedForm)
.filter(filter)
.collect(Collectors.toUnmodifiableMap(Function.identity(),
this::readRoutingPolicies));
}
public List readRoutingPolicies(ApplicationId application) {
return readSlime(routingPolicyPath(application)).map(slime -> routingPolicySerializer.fromSlime(application, slime))
.orElseGet(List::of);
}
public void writeZoneRoutingPolicy(ZoneRoutingPolicy policy) {
curator.set(zoneRoutingPolicyPath(policy.zone()), asJson(zoneRoutingPolicySerializer.toSlime(policy)));
}
public ZoneRoutingPolicy readZoneRoutingPolicy(ZoneId zone) {
return readSlime(zoneRoutingPolicyPath(zone)).map(data -> zoneRoutingPolicySerializer.fromSlime(zone, data))
.orElseGet(() -> new ZoneRoutingPolicy(zone, RoutingStatus.DEFAULT));
}
// -------------- Application endpoint certificates ----------------------------
public void writeEndpointCertificateMetadata(ApplicationId applicationId, EndpointCertificateMetadata endpointCertificateMetadata) {
curator.set(endpointCertificatePath(applicationId), asJson(EndpointCertificateMetadataSerializer.toSlime(endpointCertificateMetadata)));
}
public void deleteEndpointCertificateMetadata(ApplicationId applicationId) {
curator.delete(endpointCertificatePath(applicationId));
}
public Optional readEndpointCertificateMetadata(ApplicationId applicationId) {
return curator.getData(endpointCertificatePath(applicationId)).map(String::new).map(EndpointCertificateMetadataSerializer::fromJsonString);
}
public Map readAllEndpointCertificateMetadata() {
Map allEndpointCertificateMetadata = new HashMap<>();
for (String appIdString : curator.getChildren(endpointCertificateRoot)) {
ApplicationId applicationId = ApplicationId.fromSerializedForm(appIdString);
Optional endpointCertificateMetadata = readEndpointCertificateMetadata(applicationId);
allEndpointCertificateMetadata.put(applicationId, endpointCertificateMetadata.orElseThrow());
}
return allEndpointCertificateMetadata;
}
// -------------- Metering view refresh times ----------------------------
public void writeMeteringRefreshTime(long timestamp) {
curator.set(meteringRefreshPath(), Long.toString(timestamp).getBytes());
}
public long readMeteringRefreshTime() {
return curator.getData(meteringRefreshPath())
.map(String::new).map(Long::parseLong)
.orElse(0L);
}
// -------------- Archive buckets -----------------------------------------
public Set readArchiveBuckets(ZoneId zoneId) {
return curator.getData(archiveBucketsPath(zoneId)).map(String::new).map(ArchiveBucketsSerializer::fromJsonString)
.orElseGet(Set::of);
}
public void writeArchiveBuckets(ZoneId zoneid, Set archiveBuckets) {
curator.set(archiveBucketsPath(zoneid), asJson(ArchiveBucketsSerializer.toSlime(archiveBuckets)));
}
// -------------- VCMRs ---------------------------------------------------
public Optional readChangeRequest(String changeRequestId) {
return readSlime(changeRequestPath(changeRequestId)).map(ChangeRequestSerializer::fromSlime);
}
public List readChangeRequests() {
return curator.getChildren(changeRequestsRoot)
.stream()
.map(this::readChangeRequest)
.flatMap(Optional::stream)
.collect(Collectors.toList());
}
public void writeChangeRequest(VespaChangeRequest changeRequest) {
curator.set(changeRequestPath(changeRequest.getId()), asJson(ChangeRequestSerializer.toSlime(changeRequest)));
}
public void deleteChangeRequest(VespaChangeRequest changeRequest) {
curator.delete(changeRequestPath(changeRequest.getId()));
}
// -------------- Notifications -------------------------------------------
public List readNotifications(TenantName tenantName) {
return readSlime(notificationsPath(tenantName))
.map(slime -> NotificationsSerializer.fromSlime(tenantName, slime)).orElseGet(List::of);
}
public List listNotifications() {
return curator.getChildren(notificationsRoot).stream()
.map(TenantName::from)
.collect(Collectors.toUnmodifiableList());
}
public void writeNotifications(TenantName tenantName, List notifications) {
curator.set(notificationsPath(tenantName), asJson(NotificationsSerializer.toSlime(notifications)));
}
public void deleteNotifications(TenantName tenantName) {
curator.delete(notificationsPath(tenantName));
}
// -------------- Endpoint Support Access ---------------------------------
public SupportAccess readSupportAccess(DeploymentId deploymentId) {
return readSlime(supportAccessPath(deploymentId)).map(SupportAccessSerializer::fromSlime).orElse(SupportAccess.DISALLOWED_NO_HISTORY);
}
/** Take lock before reading before writing */
public void writeSupportAccess(DeploymentId deploymentId, SupportAccess supportAccess) {
curator.set(supportAccessPath(deploymentId), asJson(SupportAccessSerializer.toSlime(supportAccess)));
}
// -------------- Job Retrigger entries -----------------------------------
public List readRetriggerEntries() {
return readSlime(deploymentRetriggerPath()).map(RetriggerEntrySerializer::fromSlime).orElseGet(List::of);
}
public void writeRetriggerEntries(List retriggerEntries) {
curator.set(deploymentRetriggerPath(), asJson(RetriggerEntrySerializer.toSlime(retriggerEntries)));
}
// -------------- Paths ---------------------------------------------------
private Path lockPath(TenantName tenant) {
return lockRoot
.append(tenant.value());
}
private Path lockPath(TenantAndApplicationId application) {
return lockPath(application.tenant())
.append(application.application().value());
}
private Path lockPath(ApplicationId instance) {
return lockPath(TenantAndApplicationId.from(instance))
.append(instance.instance().value());
}
private Path lockPath(ApplicationId instance, ZoneId zone) {
return lockPath(instance)
.append(zone.environment().value())
.append(zone.region().value());
}
private Path lockPath(ApplicationId instance, JobType type) {
return lockPath(instance)
.append(type.jobName());
}
private Path lockPath(ApplicationId instance, JobType type, Step step) {
return lockPath(instance, type)
.append(step.name());
}
private Path lockPath(String provisionId) {
return lockRoot
.append(provisionStatePath())
.append(provisionId);
}
private static Path upgradesPerMinutePath() {
return root.append("upgrader").append("upgradesPerMinute");
}
private static Path targetMajorVersionPath() {
return root.append("upgrader").append("targetMajorVersion");
}
private static Path confidenceOverridesPath() {
return root.append("upgrader").append("confidenceOverrides");
}
private static Path osVersionTargetsPath() {
return root.append("osUpgrader").append("targetVersion");
}
private static Path osVersionStatusPath() {
return root.append("osVersionStatus");
}
private static Path versionStatusPath() {
return root.append("versionStatus");
}
private static Path routingPolicyPath(ApplicationId application) {
return routingPoliciesRoot.append(application.serializedForm());
}
private static Path zoneRoutingPolicyPath(ZoneId zone) { return zoneRoutingPoliciesRoot.append(zone.value()); }
private static Path nameServiceQueuePath() {
return root.append("nameServiceQueue");
}
private static Path auditLogPath() {
return root.append("auditLog");
}
private static Path provisionStatePath() {
return root.append("provisioning").append("states");
}
private static Path provisionStatePath(String provisionId) {
return provisionStatePath().append(provisionId);
}
private static Path tenantPath(TenantName name) {
return tenantRoot.append(name.value());
}
private static Path applicationPath(TenantAndApplicationId id) {
return applicationRoot.append(id.serialized());
}
private static Path runsPath(ApplicationId id, JobType type) {
return jobRoot.append(id.serializedForm()).append(type.jobName());
}
private static Path lastRunPath(ApplicationId id, JobType type) {
return runsPath(id, type).append("last");
}
private static Path logPath(ApplicationId id, JobType type, long first) {
return runsPath(id, type).append("logs").append(Long.toString(first));
}
private static Path lastLogPath(ApplicationId id, JobType type) {
return runsPath(id, type).append("logs");
}
private static Path controllerPath(String hostname) {
return controllerRoot.append(hostname);
}
private static Path endpointCertificatePath(ApplicationId id) {
return endpointCertificateRoot.append(id.serializedForm());
}
private static Path meteringRefreshPath() {
return root.append("meteringRefreshTime");
}
private static Path archiveBucketsPath(ZoneId zoneId) {
return archiveBucketsRoot.append(zoneId.value());
}
private static Path changeRequestPath(String id) {
return changeRequestsRoot.append(id);
}
private static Path notificationsPath(TenantName tenantName) {
return notificationsRoot.append(tenantName.value());
}
private static Path supportAccessPath(DeploymentId deploymentId) {
return supportAccessRoot.append(deploymentId.dottedString());
}
private static Path deploymentRetriggerPath() {
return root.append("deploymentRetriggerQueue");
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy