summaryrefslogtreecommitdiffstats
path: root/controller-server/src/main/java/com/yahoo
diff options
context:
space:
mode:
Diffstat (limited to 'controller-server/src/main/java/com/yahoo')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java20
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java6
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationMetaDataGarbageCollector.java5
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgradeScheduler.java78
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgrader.java10
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Upgrader.java3
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainer.java21
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/BufferedLogStore.java12
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java8
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java10
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelper.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/controller/ControllerApiHandler.java19
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VespaVersion.java8
15 files changed, 131 insertions, 75 deletions
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
index 045e43f532c..b9432fdc375 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/ApplicationController.java
@@ -237,7 +237,7 @@ public class ApplicationController {
}
/** Sets the default target major version. Set to empty to determine target version normally (by confidence) */
- public void setTargetMajorVersion(Optional<Integer> targetMajorVersion) {
+ public void setTargetMajorVersion(OptionalInt targetMajorVersion) {
curator.writeTargetMajorVersion(targetMajorVersion);
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java
index 7ceeda08d3a..d83f552ab25 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/DeploymentTrigger.java
@@ -228,10 +228,9 @@ public class DeploymentTrigger {
Instance instance = application.require(applicationId.instance());
JobId job = new JobId(instance.id(), jobType);
JobStatus jobStatus = jobs.jobStatus(new JobId(applicationId, jobType));
- Versions versions = jobStatus.lastTriggered()
- .orElseThrow(() -> new IllegalArgumentException(job + " has never been triggered"))
- .versions();
- trigger(deploymentJob(instance, versions, jobType, jobStatus, clock.instant()), reason);
+ Run last = jobStatus.lastTriggered()
+ .orElseThrow(() -> new IllegalArgumentException(job + " has never been triggered"));
+ trigger(deploymentJob(instance, last.versions(), last.id().type(), jobStatus.isNodeAllocationFailure(), clock.instant()), reason);
return job;
}
@@ -259,7 +258,12 @@ public class DeploymentTrigger {
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
jobs.forEach((jobId, versionsList) -> {
- trigger(deploymentJob(application.require(job.application().instance()), versionsList.get(0).versions(), jobId.type(), status.jobs().get(jobId).get(), clock.instant()), reason);
+ trigger(deploymentJob(application.require(job.application().instance()),
+ versionsList.get(0).versions(),
+ jobId.type(),
+ status.jobs().get(jobId).get().isNodeAllocationFailure(),
+ clock.instant()),
+ reason);
});
return List.copyOf(jobs.keySet());
}
@@ -388,7 +392,7 @@ public class DeploymentTrigger {
jobs.add(deploymentJob(status.application().require(jobId.application().instance()),
job.versions(),
job.type(),
- status.instanceJobs(jobId.application().instance()).get(jobId.type()),
+ status.instanceJobs(jobId.application().instance()).get(jobId.type()).isNodeAllocationFailure(),
job.readyAt().get()));
});
return Collections.unmodifiableList(jobs);
@@ -475,8 +479,8 @@ public class DeploymentTrigger {
// ---------- Version and job helpers ----------
- private Job deploymentJob(Instance instance, Versions versions, JobType jobType, JobStatus jobStatus, Instant availableSince) {
- return new Job(instance, versions, jobType, availableSince, jobStatus.isNodeAllocationFailure(), instance.change().revision().isPresent());
+ private Job deploymentJob(Instance instance, Versions versions, JobType jobType, boolean isNodeAllocationFailure, Instant availableSince) {
+ return new Job(instance, versions, jobType, availableSince, isNodeAllocationFailure, instance.change().revision().isPresent());
}
// ---------- Data containers ----------
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
index 19b2afb3af9..881107fa0f9 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/JobController.java
@@ -158,7 +158,7 @@ public class JobController {
/** Stores the given log entries for the given run and step. */
public void log(RunId id, Step step, List<LogEntry> entries) {
locked(id, __ -> {
- logs.append(id.application(), id.type(), step, entries);
+ logs.append(id.application(), id.type(), step, entries, true);
return __;
});
}
@@ -211,7 +211,7 @@ public class JobController {
if (log.isEmpty())
return run;
- logs.append(id.application(), id.type(), Step.copyVespaLogs, log);
+ logs.append(id.application(), id.type(), Step.copyVespaLogs, log, false);
return run.with(log.get(log.size() - 1).at());
});
}
@@ -230,7 +230,7 @@ public class JobController {
if (entries.isEmpty())
return run;
- logs.append(id.application(), id.type(), step.get(), entries);
+ logs.append(id.application(), id.type(), step.get(), entries, false);
return run.with(entries.stream().mapToLong(LogEntry::id).max().getAsLong());
});
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationMetaDataGarbageCollector.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationMetaDataGarbageCollector.java
index 09e0fec41d1..c8c5a1834c7 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationMetaDataGarbageCollector.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ApplicationMetaDataGarbageCollector.java
@@ -14,14 +14,17 @@ public class ApplicationMetaDataGarbageCollector extends ControllerMaintainer {
private static final Logger log = Logger.getLogger(ApplicationMetaDataGarbageCollector.class.getName());
+ private final Duration timeToLive;
+
public ApplicationMetaDataGarbageCollector(Controller controller, Duration interval) {
super(controller, interval);
+ this.timeToLive = controller.system().isCd() ? Duration.ofDays(7) : Duration.ofDays(365);
}
@Override
protected double maintain() {
try {
- controller().applications().applicationStore().pruneMeta(controller().clock().instant().minus(Duration.ofDays(365)));
+ controller().applications().applicationStore().pruneMeta(controller().clock().instant().minus(timeToLive));
return 1.0;
}
catch (Exception e) {
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java
index 4aeecdcd4ff..9793cded918 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/ControllerMaintenance.java
@@ -70,7 +70,7 @@ public class ControllerMaintenance extends AbstractComponent {
maintainers.add(new ArchiveAccessMaintainer(controller, metric, intervals.archiveAccessMaintainer));
maintainers.add(new TenantRoleMaintainer(controller, intervals.tenantRoleMaintainer));
maintainers.add(new ChangeRequestMaintainer(controller, intervals.changeRequestMaintainer));
- maintainers.add(new VcmrMaintainer(controller, intervals.vcmrMaintainer));
+ maintainers.add(new VcmrMaintainer(controller, intervals.vcmrMaintainer, metric));
maintainers.add(new CloudTrialExpirer(controller, intervals.defaultInterval));
maintainers.add(new RetriggerMaintainer(controller, intervals.retriggerMaintainer));
maintainers.add(new UserManagementMaintainer(controller, intervals.userManagementMaintainer, controller.serviceRegistry().roleMaintainer()));
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgradeScheduler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgradeScheduler.java
index 3bd1c7bb358..111931b638b 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgradeScheduler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgradeScheduler.java
@@ -9,8 +9,10 @@ import com.yahoo.vespa.hosted.controller.api.integration.deployment.ArtifactRepo
import com.yahoo.vespa.hosted.controller.api.integration.deployment.OsRelease;
import com.yahoo.vespa.hosted.controller.versions.OsVersionTarget;
+import java.time.DayOfWeek;
import java.time.Duration;
import java.time.Instant;
+import java.time.LocalDate;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
@@ -84,14 +86,11 @@ public class OsUpgradeScheduler extends ControllerMaintainer {
}
/** OS release based on a tag */
- private static class TaggedRelease implements Release {
+ private record TaggedRelease(SystemName system, ArtifactRepository artifactRepository) implements Release {
- private final SystemName system;
- private final ArtifactRepository artifactRepository;
-
- private TaggedRelease(SystemName system, ArtifactRepository artifactRepository) {
- this.system = Objects.requireNonNull(system);
- this.artifactRepository = Objects.requireNonNull(artifactRepository);
+ public TaggedRelease {
+ Objects.requireNonNull(system);
+ Objects.requireNonNull(artifactRepository);
}
@Override
@@ -119,41 +118,30 @@ public class OsUpgradeScheduler extends ControllerMaintainer {
}
/** OS release based on calendar-versioning */
- private static class CalendarVersionedRelease implements Release {
+ record CalendarVersionedRelease(SystemName system) implements Release {
- /** The time to wait before scheduling upgrade to next version */
- private static final Duration SCHEDULING_INTERVAL = Duration.ofDays(45);
+ /** A fixed point in time which the release schedule is calculated from */
+ private static final Instant START_OF_SCHEDULE = LocalDate.of(2022, 1, 1)
+ .atStartOfDay()
+ .toInstant(ZoneOffset.UTC);
- /**
- * The interval at which new versions become available. We use this to avoid scheduling upgrades to a version
- * that has not been released yet. Example: Version N is the latest one and target is set to N+1. If N+1 does
- * not exist the zone will not converge until N+1 has been released and we may end up triggering multiple
- * rounds of upgrades.
- */
- private static final Duration AVAILABILITY_INTERVAL = Duration.ofDays(7);
+ /** The time that should elapse between versions */
+ private static final Duration SCHEDULING_STEP = Duration.ofDays(60);
- private static final DateTimeFormatter CALENDAR_VERSION_PATTERN = DateTimeFormatter.ofPattern("yyyyMMdd");
+ /** The day of week new releases are published */
+ private static final DayOfWeek RELEASE_DAY = DayOfWeek.MONDAY;
- private final SystemName system;
+ private static final DateTimeFormatter CALENDAR_VERSION_PATTERN = DateTimeFormatter.ofPattern("yyyyMMdd");
- public CalendarVersionedRelease(SystemName system) {
- this.system = Objects.requireNonNull(system);
+ public CalendarVersionedRelease {
+ Objects.requireNonNull(system);
}
@Override
public Version version(OsVersionTarget currentTarget, Instant now) {
- Instant scheduledAt = currentTarget.scheduledAt();
Version currentVersion = currentTarget.osVersion().version();
- if (scheduledAt.isBefore(now.minus(SCHEDULING_INTERVAL))) {
- String calendarVersion = now.minus(AVAILABILITY_INTERVAL)
- .atZone(ZoneOffset.UTC)
- .format(CALENDAR_VERSION_PATTERN);
- return new Version(currentVersion.getMajor(),
- currentVersion.getMinor(),
- currentVersion.getMicro(),
- calendarVersion);
- }
- return currentVersion; // New version should not be scheduled yet
+ Version wantedVersion = asVersion(dateOfWantedVersion(now), currentVersion);
+ return wantedVersion.isAfter(currentVersion) ? wantedVersion : currentVersion;
}
@Override
@@ -161,6 +149,32 @@ public class OsUpgradeScheduler extends ControllerMaintainer {
return system.isCd() ? Duration.ZERO : Duration.ofDays(14);
}
+ /**
+ * Calculate the date of the wanted version relative to now. A given zone will choose the oldest release
+ * available which is not older than this date.
+ */
+ static LocalDate dateOfWantedVersion(Instant now) {
+ Instant candidate = START_OF_SCHEDULE;
+ while (!candidate.plus(SCHEDULING_STEP).isAfter(now)) {
+ candidate = candidate.plus(SCHEDULING_STEP);
+ }
+ LocalDate date = LocalDate.ofInstant(candidate, ZoneOffset.UTC);
+ return releaseDayOf(date);
+ }
+
+ private static LocalDate releaseDayOf(LocalDate date) {
+ int releaseDayDelta = RELEASE_DAY.getValue() - date.getDayOfWeek().getValue();
+ return date.plusDays(releaseDayDelta);
+ }
+
+ private static Version asVersion(LocalDate dateOfVersion, Version currentVersion) {
+ String calendarVersion = dateOfVersion.format(CALENDAR_VERSION_PATTERN);
+ return new Version(currentVersion.getMajor(),
+ currentVersion.getMinor(),
+ currentVersion.getMicro(),
+ calendarVersion);
+ }
+
}
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgrader.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgrader.java
index fa64a2677f4..8155476f139 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgrader.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgrader.java
@@ -62,7 +62,7 @@ public class OsUpgrader extends InfrastructureUpgrader<OsVersionTarget> {
protected boolean expectUpgradeOf(Node node, SystemApplication application, ZoneApi zone) {
return cloud.equals(zone.getCloudName()) && // Cloud is managed by this upgrader
application.shouldUpgradeOs() && // Application should upgrade in this cloud
- canUpgrade(node); // Node is in an upgradable state
+ canUpgrade(node);
}
@Override
@@ -98,14 +98,12 @@ public class OsUpgrader extends InfrastructureUpgrader<OsVersionTarget> {
/** Returns whether to spend upgrade budget on given zone */
private boolean spendBudgetOn(ZoneApi zone) {
- if (!zone.getEnvironment().isProduction()) return false;
- if (controller().zoneRegistry().systemZone().getVirtualId().equals(zone.getVirtualId())) return false; // Controller zone
- return true;
+ return !controller().zoneRegistry().systemZone().getVirtualId().equals(zone.getVirtualId()); // Do not spend budget on controller zone
}
- /** Returns whether node is in a state where it can be upgraded */
+ /** Returns whether node currently allows upgrades */
public static boolean canUpgrade(Node node) {
- return upgradableNodeStates.contains(node.state());
+ return !node.deferOsUpgrade() && upgradableNodeStates.contains(node.state());
}
private static String name(CloudName cloud) {
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Upgrader.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Upgrader.java
index a2fb0df626f..1932dc65657 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Upgrader.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/Upgrader.java
@@ -23,7 +23,6 @@ import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-import java.util.Optional;
import java.util.OptionalInt;
import java.util.Random;
import java.util.Set;
@@ -182,7 +181,7 @@ public class Upgrader extends ControllerMaintainer {
}
/** Sets the default target major version. Set to empty to determine target version normally (by confidence) */
- public void setTargetMajorVersion(Optional<Integer> targetMajorVersion) {
+ public void setTargetMajorVersion(OptionalInt targetMajorVersion) {
controller().applications().setTargetMajorVersion(targetMajorVersion);
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainer.java
index 551f803f368..daba7e74f34 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainer.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/VcmrMaintainer.java
@@ -5,6 +5,7 @@ import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.NodeType;
import com.yahoo.config.provision.SystemName;
import com.yahoo.config.provision.zone.ZoneId;
+import com.yahoo.jdisc.Metric;
import com.yahoo.text.Text;
import com.yahoo.vespa.hosted.controller.Controller;
import com.yahoo.vespa.hosted.controller.api.integration.configserver.Node;
@@ -46,26 +47,28 @@ public class VcmrMaintainer extends ControllerMaintainer {
private static final Logger LOG = Logger.getLogger(VcmrMaintainer.class.getName());
private static final int DAYS_TO_RETIRE = 2;
private static final Duration ALLOWED_POSTPONEMENT_TIME = Duration.ofDays(7);
+ protected static final String TRACKED_CMRS_METRIC = "cmr.tracked";
private final CuratorDb curator;
private final NodeRepository nodeRepository;
private final ChangeRequestClient changeRequestClient;
private final SystemName system;
+ private final Metric metric;
- public VcmrMaintainer(Controller controller, Duration interval) {
+ public VcmrMaintainer(Controller controller, Duration interval, Metric metric) {
super(controller, interval, null, SystemName.allOf(Predicate.not(SystemName::isPublic)));
this.curator = controller.curator();
this.nodeRepository = controller.serviceRegistry().configServer().nodeRepository();
this.changeRequestClient = controller.serviceRegistry().changeRequestClient();
this.system = controller.system();
+ this.metric = metric;
}
@Override
protected double maintain() {
var changeRequests = curator.readChangeRequests()
.stream()
- .filter(shouldUpdate())
- .collect(Collectors.toList());
+ .filter(shouldUpdate()).toList();
var nodesByZone = nodesByZone();
@@ -86,6 +89,7 @@ public class VcmrMaintainer extends ControllerMaintainer {
});
}
});
+ updateMetrics();
return 1.0;
}
@@ -357,4 +361,15 @@ public class VcmrMaintainer extends ControllerMaintainer {
return time;
}
+ private void updateMetrics() {
+ var cmrsByStatus = curator.readChangeRequests()
+ .stream()
+ .collect(Collectors.groupingBy(VespaChangeRequest::getStatus));
+
+ for (var status : Status.values()) {
+ var count = cmrsByStatus.getOrDefault(status, List.of()).size();
+ metric.set(TRACKED_CMRS_METRIC, count, metric.createContext(Map.of("status", status.name())));
+ }
+ }
+
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/BufferedLogStore.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/BufferedLogStore.java
index 9721026c628..ecb9db8195f 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/BufferedLogStore.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/BufferedLogStore.java
@@ -49,7 +49,7 @@ public class BufferedLogStore {
}
/** Appends to the log of the given, active run, reassigning IDs as counted here, and converting to Vespa log levels. */
- public void append(ApplicationId id, JobType type, Step step, List<LogEntry> entries) {
+ public void append(ApplicationId id, JobType type, Step step, List<LogEntry> entries, boolean forceLog) {
if (entries.isEmpty())
return;
@@ -58,7 +58,7 @@ public class BufferedLogStore {
long lastEntryId = buffer.readLastLogEntryId(id, type).orElse(-1L);
long lastChunkId = buffer.getLogChunkIds(id, type).max().orElse(0);
long numberOfChunks = Math.max(1, buffer.getLogChunkIds(id, type).count());
- if (numberOfChunks > maxLogSize / chunkSize)
+ if (numberOfChunks > maxLogSize / chunkSize && ! forceLog)
return; // Max size exceeded — store no more.
byte[] emptyChunk = "[]".getBytes();
@@ -72,8 +72,12 @@ public class BufferedLogStore {
buffer.writeLastLogEntryId(id, type, lastEntryId);
buffer.writeLog(id, type, lastChunkId, logSerializer.toJson(log));
lastChunkId = lastEntryId + 1;
- if (++numberOfChunks > maxLogSize / chunkSize) {
- log = Map.of(step, List.of(new LogEntry(++lastEntryId, entry.at(), LogEntry.Type.warning, "Max log size of " + (maxLogSize >> 20) + "Mb exceeded; further entries are discarded.")));
+ if (++numberOfChunks > maxLogSize / chunkSize && ! forceLog) {
+ log = Map.of(step, List.of(new LogEntry(++lastEntryId,
+ entry.at(),
+ LogEntry.Type.warning,
+ "Max log size of " + (maxLogSize >> 20) +
+ "Mb exceeded; further user entries are discarded.")));
break;
}
log = new HashMap<>();
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java
index f02f49e7114..54e98877ba3 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/persistence/CuratorDb.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.hosted.controller.persistence;
-import com.yahoo.component.annotation.Inject;
import com.yahoo.collections.Pair;
import com.yahoo.component.Version;
+import com.yahoo.component.annotation.Inject;
import com.yahoo.concurrent.UncheckedTimeoutException;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.HostName;
@@ -41,6 +41,7 @@ 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;
@@ -53,6 +54,7 @@ import java.util.List;
import java.util.Map;
import java.util.NavigableMap;
import java.util.Optional;
+import java.util.OptionalInt;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeoutException;
@@ -271,9 +273,9 @@ public class CuratorDb {
return read(targetMajorVersionPath(), ByteBuffer::wrap).map(ByteBuffer::getInt);
}
- public void writeTargetMajorVersion(Optional<Integer> targetMajorVersion) {
+ public void writeTargetMajorVersion(OptionalInt targetMajorVersion) {
if (targetMajorVersion.isPresent())
- curator.set(targetMajorVersionPath(), ByteBuffer.allocate(Integer.BYTES).putInt(targetMajorVersion.get()).array());
+ curator.set(targetMajorVersionPath(), ByteBuffer.allocate(Integer.BYTES).putInt(targetMajorVersion.getAsInt()).array());
else
curator.delete(targetMajorVersionPath());
}
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 cfb00db7b63..56eaf2f3a2e 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
@@ -75,6 +75,7 @@ import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId;
import com.yahoo.vespa.hosted.controller.api.integration.deployment.SourceRevision;
import com.yahoo.vespa.hosted.controller.api.integration.noderepository.RestartFilter;
import com.yahoo.vespa.hosted.controller.api.integration.secrets.TenantSecretStore;
+import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneRegistry;
import com.yahoo.vespa.hosted.controller.api.role.Role;
import com.yahoo.vespa.hosted.controller.api.role.RoleDefinition;
import com.yahoo.vespa.hosted.controller.api.role.SecurityContext;
@@ -1473,6 +1474,15 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler {
private HttpResponse trigger(ApplicationId id, JobType type, HttpRequest request) {
+ // JobType.fromJobName doesn't properly initiate test jobs. Triggering these without context isn't _really_
+ // necessary, but triggering a test in the default cloud is better than failing with a weird error.
+ ZoneRegistry zones = controller.zoneRegistry();
+ type = switch (type.environment()) {
+ case test -> JobType.systemTest(zones, zones.systemZone().getCloudName());
+ case staging -> JobType.stagingTest(zones, zones.systemZone().getCloudName());
+ default -> type;
+ };
+
Inspector requestObject = toSlime(request.getData()).get();
boolean requireTests = ! requestObject.field("skipTests").asBool();
boolean reTrigger = requestObject.field("reTrigger").asBool();
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelper.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelper.java
index 9c016eccd27..25953c16bf0 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelper.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/JobControllerApiHandlerHelper.java
@@ -115,6 +115,7 @@ class JobControllerApiHandlerHelper {
Run run = jobController.run(runId);
detailsObject.setBool("active", ! run.hasEnded());
detailsObject.setString("status", nameOf(run.status()));
+ run.reason().ifPresent(reason -> detailsObject.setString("reason", reason));
try {
jobController.updateTestLog(runId);
jobController.updateVespaLog(runId);
@@ -421,6 +422,7 @@ class JobControllerApiHandlerHelper {
runObject.setLong("start", run.start().toEpochMilli());
run.end().ifPresent(end -> runObject.setLong("end", end.toEpochMilli()));
runObject.setString("status", run.status().name());
+ run.reason().ifPresent(reason -> runObject.setString("reason", reason));
toSlime(runObject.setObject("versions"), run.versions(), application);
Cursor runStepsArray = runObject.setArray("steps");
run.steps().forEach((step, info) -> {
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/controller/ControllerApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/controller/ControllerApiHandler.java
index 25ac90ac0ea..776fcbfd03b 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/controller/ControllerApiHandler.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/controller/ControllerApiHandler.java
@@ -35,6 +35,7 @@ import java.security.Principal;
import java.security.cert.X509Certificate;
import java.time.Instant;
import java.util.Optional;
+import java.util.OptionalInt;
import java.util.Scanner;
import java.util.function.Function;
import java.util.logging.Level;
@@ -60,13 +61,13 @@ public class ControllerApiHandler extends AuditLoggingRequestHandler {
@Override
public HttpResponse auditAndHandle(HttpRequest request) {
try {
- switch (request.getMethod()) {
- case GET: return get(request);
- case POST: return post(request);
- case DELETE: return delete(request);
- case PATCH: return patch(request);
- default: return ErrorResponse.methodNotAllowed("Method '" + request.getMethod() + "' is not supported");
- }
+ return switch (request.getMethod()) {
+ case GET -> get(request);
+ case POST -> post(request);
+ case DELETE -> delete(request);
+ case PATCH -> patch(request);
+ default -> ErrorResponse.methodNotAllowed("Method '" + request.getMethod() + "' is not supported");
+ };
}
catch (IllegalArgumentException e) {
return ErrorResponse.badRequest(Exceptions.toMessageString(e));
@@ -165,8 +166,8 @@ public class ControllerApiHandler extends AuditLoggingRequestHandler {
if (inspect.field(upgradesPerMinuteField).valid()) {
upgrader.setUpgradesPerMinute(inspect.field(upgradesPerMinuteField).asDouble());
} else if (inspect.field(targetMajorVersionField).valid()) {
- int target = (int)inspect.field(targetMajorVersionField).asLong();
- upgrader.setTargetMajorVersion(Optional.ofNullable(target == 0 ? null : target)); // 0 is the default value
+ int target = (int) inspect.field(targetMajorVersionField).asLong();
+ upgrader.setTargetMajorVersion(target == 0 ? OptionalInt.empty() : OptionalInt.of(target)); // 0 is the default value
} else {
return ErrorResponse.badRequest("No such modifiable field(s)");
}
diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VespaVersion.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VespaVersion.java
index 7f33f612cd0..e078df0267f 100644
--- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VespaVersion.java
+++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/versions/VespaVersion.java
@@ -15,7 +15,8 @@ import static com.yahoo.config.application.api.DeploymentSpec.UpgradePolicy;
/**
* Information about a particular Vespa version.
- * VespaVersions are identified by their version number and ordered by increasing version numbers.
+ *
+ * Vespa versions are identified by their version number and ordered by increasing version numbers.
*
* @author bratseth
*/
@@ -29,8 +30,11 @@ public record VespaVersion(Version version,
Confidence confidence) implements Comparable<VespaVersion> {
public static Confidence confidenceFrom(DeploymentStatistics statistics, Controller controller) {
+ int thisMajorVersion = statistics.version().getMajor();
+ int defaultMajorVersion = controller.applications().targetMajorVersion().orElse(thisMajorVersion);
InstanceList all = InstanceList.from(controller.jobController().deploymentStatuses(ApplicationList.from(controller.applications().asList())
- .withProductionDeployment()));
+ .withProductionDeployment()))
+ .allowingMajorVersion(thisMajorVersion, defaultMajorVersion);
// 'production on this': All production deployment jobs upgrading to this version have completed without failure
InstanceList productionOnThis = all.matching(instance -> statistics.productionSuccesses().stream().anyMatch(run -> run.id().application().equals(instance)))
.not().failingUpgrade()