aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgradeScheduler.java61
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgradeSchedulerTest.java33
2 files changed, 67 insertions, 27 deletions
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 3a1f57c43e4..5e4d6d71ff6 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;
@@ -116,18 +118,18 @@ public class OsUpgradeScheduler extends ControllerMaintainer {
}
/** OS release based on calendar-versioning */
- private record CalendarVersionedRelease(SystemName system) 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(45);
+
+ /** The day of week new releases are published */
+ private static final DayOfWeek RELEASE_DAY = DayOfWeek.MONDAY;
private static final DateTimeFormatter CALENDAR_VERSION_PATTERN = DateTimeFormatter.ofPattern("yyyyMMdd");
@@ -137,18 +139,9 @@ public class OsUpgradeScheduler extends ControllerMaintainer {
@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
@@ -156,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/test/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgradeSchedulerTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgradeSchedulerTest.java
index 300aa86b5ea..478bb943eba 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgradeSchedulerTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/maintenance/OsUpgradeSchedulerTest.java
@@ -13,7 +13,10 @@ import org.junit.Test;
import java.time.Duration;
import java.time.Instant;
+import java.time.LocalDate;
+import java.time.ZoneOffset;
import java.util.List;
+import java.util.Map;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -27,7 +30,7 @@ public class OsUpgradeSchedulerTest {
public void schedule_calendar_versioned_release() {
ControllerTester tester = new ControllerTester();
OsUpgradeScheduler scheduler = new OsUpgradeScheduler(tester.controller(), Duration.ofDays(1));
- Instant t0 = Instant.parse("2021-01-23T00:00:00.00Z"); // Outside trigger period
+ Instant t0 = Instant.parse("2022-01-16T00:00:00.00Z"); // Outside trigger period
tester.clock().setInstant(t0);
CloudName cloud = CloudName.from("cloud");
@@ -38,8 +41,8 @@ public class OsUpgradeSchedulerTest {
scheduler.maintain();
assertTrue("No target set", tester.controller().osVersionTarget(cloud).isEmpty());
- // Target is set
- Version version0 = Version.fromString("7.0.0.20210123190005");
+ // Target is set manually
+ Version version0 = Version.fromString("7.0.0.20220101");
tester.controller().upgradeOsIn(cloud, version0, Duration.ofDays(1), false);
// Target remains unchanged as it hasn't expired yet
@@ -49,8 +52,8 @@ public class OsUpgradeSchedulerTest {
assertEquals(version0, tester.controller().osVersionTarget(cloud).get().osVersion().version());
}
- // Just over 45 days pass, and a new target replaces the expired one
- Version version1 = Version.fromString("7.0.0.20210302");
+ // Enough days pass that the next release is triggered
+ Version version1 = Version.fromString("7.0.0.20220214");
tester.clock().advance(Duration.ofDays(15).plus(Duration.ofSeconds(1)));
scheduler.maintain();
assertEquals("Target is unchanged because we're outside trigger period", version0,
@@ -60,7 +63,7 @@ public class OsUpgradeSchedulerTest {
assertEquals("New target set", version1,
tester.controller().osVersionTarget(cloud).get().osVersion().version());
- // A few days pass and target remains unchanged
+ // A few more days pass and target remains unchanged
tester.clock().advance(Duration.ofDays(2));
scheduler.maintain();
assertEquals(version1, tester.controller().osVersionTarget(cloud).get().osVersion().version());
@@ -112,6 +115,24 @@ public class OsUpgradeSchedulerTest {
scheduleUpgradeAfter(Duration.ofDays(1), version1, tester);
}
+ @Test
+ public void schedule_of_calender_versioned_releases() {
+ Map<String, String> tests = Map.of("2022-01-01", "2021-12-27",
+ "2022-02-14", "2021-12-27",
+ "2022-02-15", "2022-02-14",
+ "2022-03-31", "2022-02-14",
+ "2022-04-01", "2022-03-28",
+ "2022-05-15", "2022-03-28",
+ "2022-05-16", "2022-05-16",
+ "2022-06-29", "2022-05-16",
+ "2022-06-30", "2022-06-27");
+ tests.forEach((now, expected) -> {
+ Instant instant = LocalDate.parse(now).atStartOfDay().toInstant(ZoneOffset.UTC);
+ LocalDate dateOfWantedVersion = OsUpgradeScheduler.CalendarVersionedRelease.dateOfWantedVersion(instant);
+ assertEquals("scheduled wanted version at " + now, LocalDate.parse(expected), dateOfWantedVersion);
+ });
+ }
+
private void scheduleUpgradeAfter(Duration duration, Version version, ControllerTester tester) {
tester.clock().advance(duration);
new OsUpgradeScheduler(tester.controller(), Duration.ofDays(1)).maintain();