aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--client/go/.gitignore1
-rw-r--r--client/go/jvm/application_container.go9
-rw-r--r--client/go/jvm/container.go18
-rw-r--r--client/go/jvm/env.go9
-rw-r--r--client/go/jvm/jdisc_options.go2
-rw-r--r--client/go/jvm/options_test.go4
-rw-r--r--client/go/jvm/standalone_container.go12
-rw-r--r--client/go/script-utils/main.go3
-rw-r--r--client/go/script-utils/standalone/start.go52
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/QuotaValidator.java8
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/QuotaValidatorTest.java10
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java6
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java2
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java2
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/session/SessionPreparer.java2
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java2
-rw-r--r--controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServerException.java6
-rw-r--r--controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java2
-rw-r--r--dist/vespa.spec71
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java9
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java8
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java3
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java44
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Limits.java2
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/OsUpgrader.java10
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/OsVersionChange.java24
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/RebuildingOsUpgrader.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/RetiringOsUpgrader.java11
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/OsVersionChangeSerializer.java4
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java29
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java27
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeResourceLimits.java40
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java8
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java32
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java14
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModelTest.java5
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Fixture.java23
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/awsnodes/AwsHostResourcesCalculatorImpl.java41
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OsUpgradeActivatorTest.java1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/os/OsVersionsTest.java3
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/OsVersionChangeSerializerTest.java5
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-os-upgrade-complete.json3
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-2.json2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-3.json2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-4.json2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports.json2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1.json2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node2.json2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node3.json2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node4.json2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node5.json2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/dockerhost1-with-firmware-data.json2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/dockerhost6.json2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node8.json2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node9.json2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/parent2.json2
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/equiv_blueprint.h2
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/field_spec.cpp4
-rw-r--r--searchlib/src/vespa/searchlib/queryeval/field_spec.h2
59 files changed, 362 insertions, 245 deletions
diff --git a/client/go/.gitignore b/client/go/.gitignore
index baab7c638c6..1d2f5a949a6 100644
--- a/client/go/.gitignore
+++ b/client/go/.gitignore
@@ -1,7 +1,6 @@
bin/
dist/
share/
-!Makefile
!build/
!target/
mytestapp/
diff --git a/client/go/jvm/application_container.go b/client/go/jvm/application_container.go
index 924a47f1997..e1ce45f890c 100644
--- a/client/go/jvm/application_container.go
+++ b/client/go/jvm/application_container.go
@@ -9,6 +9,7 @@ import (
"github.com/vespa-engine/vespa/client/go/defaults"
"github.com/vespa-engine/vespa/client/go/envvars"
+ "github.com/vespa-engine/vespa/client/go/prog"
"github.com/vespa-engine/vespa/client/go/trace"
"github.com/vespa-engine/vespa/client/go/util"
)
@@ -166,3 +167,11 @@ func (a *ApplicationContainer) configureOptions() {
opts.AddOption("-Dzookeeper_log_file_prefix=" + zkLogFile)
}
}
+
+func (c *ApplicationContainer) exportExtraEnv(ps *prog.Spec) {
+ if c.ConfigId() != "" {
+ ps.Setenv(envvars.VESPA_CONFIG_ID, c.ConfigId())
+ } else {
+ util.JustExitMsg("application container requires a config id")
+ }
+}
diff --git a/client/go/jvm/container.go b/client/go/jvm/container.go
index 384384da137..3a66a2d37c4 100644
--- a/client/go/jvm/container.go
+++ b/client/go/jvm/container.go
@@ -5,6 +5,7 @@ package jvm
import (
"fmt"
+ "sort"
"strings"
"github.com/vespa-engine/vespa/client/go/prog"
@@ -18,6 +19,7 @@ type Container interface {
ArgForMain() string
JvmOptions() *Options
Exec()
+ exportExtraEnv(ps *prog.Spec)
}
type containerBase struct {
@@ -38,10 +40,20 @@ func (cb *containerBase) ConfigId() string {
return cb.configId
}
+func keysOfMap(m map[string]string) []string {
+ keys := make([]string, 0, len(m))
+ for k, _ := range m {
+ keys = append(keys, k)
+ }
+ return keys
+}
+
func readableEnv(env map[string]string) string {
+ keys := keysOfMap(env)
+ sort.Strings(keys)
var buf strings.Builder
- for k, v := range env {
- fmt.Fprintf(&buf, " %s=%s", k, v)
+ for _, k := range keys {
+ fmt.Fprintf(&buf, " %s=%s", k, env[k])
}
return buf.String()
}
@@ -54,7 +66,7 @@ func (cb *containerBase) Exec() {
}
p := prog.NewSpec(argv)
p.ConfigureNumaCtl()
- cb.exportEnvSettings(p)
+ cb.JvmOptions().exportEnvSettings(p)
trace.Info("starting container; env:", readableEnv(p.Env))
trace.Info("starting container; exec:", argv)
err := p.Run()
diff --git a/client/go/jvm/env.go b/client/go/jvm/env.go
index 97050bcca7c..a23606e6d0d 100644
--- a/client/go/jvm/env.go
+++ b/client/go/jvm/env.go
@@ -12,13 +12,16 @@ import (
"github.com/vespa-engine/vespa/client/go/util"
)
-func (c *containerBase) exportEnvSettings(ps *prog.Spec) {
+func (opts *Options) exportEnvSettings(ps *prog.Spec) {
+ c := opts.container
vespaHome := defaults.VespaHome()
vlt := fmt.Sprintf("file:%s/logs/vespa/vespa.log", vespaHome)
lcd := fmt.Sprintf("%s/var/db/vespa/logcontrol", vespaHome)
+ lcf := fmt.Sprintf("%s/%s.logcontrol", lcd, c.ServiceName())
dlp := fmt.Sprintf("%s/lib64", vespaHome)
ps.Setenv(envvars.VESPA_LOG_TARGET, vlt)
ps.Setenv(envvars.VESPA_LOG_CONTROL_DIR, lcd)
+ ps.Setenv(envvars.VESPA_LOG_CONTROL_FILE, lcf)
ps.Setenv(envvars.VESPA_SERVICE_NAME, c.ServiceName())
ps.Setenv(envvars.LD_LIBRARY_PATH, dlp)
ps.Setenv(envvars.MALLOC_ARENA_MAX, "1")
@@ -26,8 +29,6 @@ func (c *containerBase) exportEnvSettings(ps *prog.Spec) {
ps.Setenv(envvars.JAVAVM_LD_PRELOAD, preload)
ps.Setenv(envvars.LD_PRELOAD, preload)
}
- if c.ConfigId() != "" {
- ps.Setenv(envvars.VESPA_CONFIG_ID, c.ConfigId())
- }
util.OptionallyReduceTimerFrequency()
+ c.exportExtraEnv(ps)
}
diff --git a/client/go/jvm/jdisc_options.go b/client/go/jvm/jdisc_options.go
index f218ae7e28f..32cfb840336 100644
--- a/client/go/jvm/jdisc_options.go
+++ b/client/go/jvm/jdisc_options.go
@@ -20,7 +20,7 @@ func selectedEnv() []byte {
var buf bytes.Buffer
for _, vv := range os.Environ() {
varName := strings.Split(vv, "=")[0]
- if strings.Contains(vv, "\n") || strings.Contains(varName, "%%") {
+ if strings.Contains(vv, "\\u") || strings.Contains(vv, "\n") || strings.Contains(varName, "%%") {
continue
}
buf.WriteString(vv)
diff --git a/client/go/jvm/options_test.go b/client/go/jvm/options_test.go
index 9ccecf5ae6b..cfb4e90d5e5 100644
--- a/client/go/jvm/options_test.go
+++ b/client/go/jvm/options_test.go
@@ -5,11 +5,13 @@ import (
"testing"
"github.com/stretchr/testify/assert"
+ "github.com/vespa-engine/vespa/client/go/prog"
)
type dummyContainer struct{ containerBase }
-func (*dummyContainer) ArgForMain() string { return "arg-for-main" }
+func (*dummyContainer) ArgForMain() string { return "arg-for-main" }
+func (*dummyContainer) exportExtraEnv(ps *prog.Spec) {}
func newDummyContainer() Container {
var dc dummyContainer
dc.serviceName = "foo"
diff --git a/client/go/jvm/standalone_container.go b/client/go/jvm/standalone_container.go
index a2181ed7c3e..edaea346889 100644
--- a/client/go/jvm/standalone_container.go
+++ b/client/go/jvm/standalone_container.go
@@ -8,6 +8,8 @@ import (
"os"
"github.com/vespa-engine/vespa/client/go/defaults"
+ "github.com/vespa-engine/vespa/client/go/envvars"
+ "github.com/vespa-engine/vespa/client/go/prog"
"github.com/vespa-engine/vespa/client/go/trace"
"github.com/vespa-engine/vespa/client/go/util"
)
@@ -78,3 +80,13 @@ func (a *StandaloneContainer) addJdiscProperties() {
opts.AddOption("-Djdisc.cache.path=" + bCacheDir)
opts.AddOption("-Djdisc.logger.tag=" + svcName)
}
+
+func (c *StandaloneContainer) exportExtraEnv(ps *prog.Spec) {
+ vespaHome := defaults.VespaHome()
+ app := fmt.Sprintf("%s/conf/%s-app", vespaHome, c.ServiceName())
+ if util.IsDirectory(app) {
+ ps.Setenv(envvars.STANDALONE_JDISC_APP_LOCATION, app)
+ } else {
+ util.JustExitMsg("standalone container requires an application directory, missing: " + app)
+ }
+}
diff --git a/client/go/script-utils/main.go b/client/go/script-utils/main.go
index 9d35cb46e1c..97f31957b36 100644
--- a/client/go/script-utils/main.go
+++ b/client/go/script-utils/main.go
@@ -13,6 +13,7 @@ import (
"github.com/vespa-engine/vespa/client/go/cmd/logfmt"
"github.com/vespa-engine/vespa/client/go/jvm"
"github.com/vespa-engine/vespa/client/go/script-utils/configserver"
+ "github.com/vespa-engine/vespa/client/go/script-utils/standalone"
"github.com/vespa-engine/vespa/client/go/script-utils/startcbinary"
"github.com/vespa-engine/vespa/client/go/util"
"github.com/vespa-engine/vespa/client/go/vespa"
@@ -38,6 +39,8 @@ func main() {
os.Exit(configserver.JustStartConfigserver())
case "vespa-start-container-daemon":
os.Exit(jvm.RunApplicationContainer(os.Args[1:]))
+ case "run-standalone-container":
+ os.Exit(standalone.StartStandaloneContainer(os.Args[1:]))
case "start-c-binary":
os.Exit(startcbinary.Run(os.Args[1:]))
case "export-env":
diff --git a/client/go/script-utils/standalone/start.go b/client/go/script-utils/standalone/start.go
new file mode 100644
index 00000000000..7b929730f5a
--- /dev/null
+++ b/client/go/script-utils/standalone/start.go
@@ -0,0 +1,52 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+// Author: arnej
+
+// for starting standalone jdisc containers
+package standalone
+
+import (
+ "os"
+
+ "github.com/vespa-engine/vespa/client/go/jvm"
+ "github.com/vespa-engine/vespa/client/go/trace"
+ "github.com/vespa-engine/vespa/client/go/util"
+ "github.com/vespa-engine/vespa/client/go/vespa"
+)
+
+func commonPreChecks() {
+ if doTrace := os.Getenv("TRACE_JVM_STARTUP"); doTrace != "" {
+ trace.AdjustVerbosity(1)
+ }
+ if doDebug := os.Getenv("DEBUG_JVM_STARTUP"); doDebug != "" {
+ trace.AdjustVerbosity(2)
+ }
+ veHome := vespa.FindAndVerifyVespaHome()
+ err := os.Chdir(veHome)
+ if err != nil {
+ util.JustExitWith(err)
+ }
+ err = vespa.LoadDefaultEnv()
+ if err != nil {
+ util.JustExitWith(err)
+ }
+}
+
+func StartStandaloneContainer(extraArgs []string) int {
+ commonPreChecks()
+ util.TuneResourceLimits()
+ serviceName := os.Getenv("VESPA_SERVICE_NAME")
+ if serviceName == "" {
+ util.JustExitMsg("Missing service name, ensure VESPA_SERVICE_NAME is set in the environment")
+ }
+ c := jvm.NewStandaloneContainer(serviceName)
+ jvmOpts := c.JvmOptions()
+ for _, extra := range extraArgs {
+ jvmOpts.AddOption(extra)
+ }
+ minFallback := jvm.MegaBytesOfMemory(128)
+ maxFallback := jvm.MegaBytesOfMemory(2048)
+ jvmOpts.AddDefaultHeapSizeArgs(minFallback, maxFallback)
+ c.Exec()
+ // unreachable:
+ return 1
+}
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/QuotaValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/QuotaValidator.java
index 7ea582b99e6..da470f804d9 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/QuotaValidator.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/QuotaValidator.java
@@ -86,19 +86,19 @@ public class QuotaValidator extends Validator {
private static void throwIfBudgetNegative(double spend, BigDecimal budget, SystemName systemName) {
if (budget.doubleValue() < 0) {
- throw new IllegalArgumentException(quotaMessage("Please free up some capacity", systemName, spend, budget));
+ throw new IllegalArgumentException(quotaMessage("Please free up some capacity.", systemName, spend, budget));
}
}
private static void throwIfBudgetExceeded(double spend, BigDecimal budget, SystemName systemName) {
if (budget.doubleValue() < spend) {
- throw new IllegalArgumentException(quotaMessage("Deployment exceeds its quota and has been blocked! Please contact support to update your plan", systemName, spend, budget));
+ throw new IllegalArgumentException(quotaMessage("Contact support to upgrade your plan.", systemName, spend, budget));
}
}
private static String quotaMessage(String message, SystemName system, double spend, BigDecimal budget) {
- String quotaDescription = String.format(Locale.ENGLISH, "Quota is $%.2f, but at least $%.2f is required", budget, spend);
- return (system == SystemName.Public ? "" : system.value() + ": ") + message + ": " + quotaDescription;
+ String quotaDescription = String.format(Locale.ENGLISH, "The max resources specified cost $%.2f but your quota is $%.2f", spend, budget);
+ return (system == SystemName.Public ? "" : system.value() + ": ") + quotaDescription + ": " + message;
}
}
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/QuotaValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/QuotaValidatorTest.java
index ef22f0b2770..1a7b3d62cb7 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/QuotaValidatorTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/QuotaValidatorTest.java
@@ -47,7 +47,7 @@ public class QuotaValidatorTest {
tester.deploy(null, getServices("testCluster", 10), Environment.prod, null);
fail();
} catch (RuntimeException e) {
- assertEquals("Deployment exceeds its quota and has been blocked! Please contact support to update your plan: Quota is $1.25, but at least $1.63 is required", e.getMessage());
+ assertEquals("The max resources specified cost $1.63 but your quota is $1.25: Contact support to upgrade your plan.", e.getMessage());
}
}
@@ -58,7 +58,7 @@ public class QuotaValidatorTest {
tester.deploy(null, getServices("testCluster", 10), Environment.prod, null);
fail();
} catch (RuntimeException e) {
- assertEquals("publiccd: Deployment exceeds its quota and has been blocked! Please contact support to update your plan: Quota is $1.00, but at least $1.63 is required", e.getMessage());
+ assertEquals("publiccd: The max resources specified cost $1.63 but your quota is $1.00: Contact support to upgrade your plan.", e.getMessage());
}
}
@@ -69,7 +69,7 @@ public class QuotaValidatorTest {
tester.deploy(null, getServices("testCluster", 10), Environment.prod, null);
fail();
} catch (RuntimeException e) {
- assertEquals("publiccd: Deployment exceeds its quota and has been blocked! Please contact support to update your plan: Quota is $1.25, but at least $1.63 is required", e.getMessage());
+ assertEquals("publiccd: The max resources specified cost $1.63 but your quota is $1.25: Contact support to upgrade your plan.", e.getMessage());
}
}
@@ -82,8 +82,8 @@ public class QuotaValidatorTest {
tester.deploy(null, getServices("testCluster", 10), Environment.prod, null);
fail();
} catch (RuntimeException e) {
- assertEquals("Please free up some capacity: Quota is $--.--, but at least $-.-- is required",
- ValidationTester.censorNumbers(e.getMessage()));
+ assertEquals("The max resources specified cost $-.-- but your quota is $--.--: Please free up some capacity.",
+ ValidationTester.censorNumbers(e.getMessage()));
}
}
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java
index 22c9234b0c5..2dba42ce0d6 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/ClusterSpec.java
@@ -31,7 +31,7 @@ public final class ClusterSpec {
this.type = type;
this.id = id;
this.groupId = groupId;
- this.vespaVersion = Objects.requireNonNull(vespaVersion);
+ this.vespaVersion = Objects.requireNonNull(vespaVersion, "vespaVersion cannot be null");
this.exclusive = exclusive;
if (type == Type.combined) {
if (combinedId.isEmpty()) throw new IllegalArgumentException("combinedId must be set for cluster of type " + type);
@@ -84,6 +84,10 @@ public final class ClusterSpec {
return new ClusterSpec(type, id, newGroup, vespaVersion, exclusive, combinedId, dockerImageRepo, stateful);
}
+ public ClusterSpec withExclusivity(boolean exclusive) {
+ return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, stateful);
+ }
+
public ClusterSpec exclusive(boolean exclusive) {
return new ClusterSpec(type, id, groupId, vespaVersion, exclusive, combinedId, dockerImageRepo, stateful);
}
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java b/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java
index d4827f07a80..7b1eb945247 100644
--- a/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/NodeResources.java
@@ -407,7 +407,7 @@ public class NodeResources {
public boolean compatibleWith(NodeResources requested) {
if ( ! equal(this.vcpu, requested.vcpu)) return false;
if ( ! equal(this.memoryGb, requested.memoryGb)) return false;
- if (requested.storageType == StorageType.local) {
+ if (this.storageType == StorageType.local || requested.storageType == StorageType.local) {
if ( ! equal(this.diskGb, requested.diskGb)) return false;
}
else {
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java
index 8a541abf4ae..d32d1a4e000 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/modelfactory/ModelsBuilder.java
@@ -134,7 +134,7 @@ public abstract class ModelsBuilder<MODELRESULT extends ModelResult> {
}
else {
if (e instanceof IllegalArgumentException) {
- var wrapped = new InvalidApplicationException("Error loading " + applicationId, e);
+ var wrapped = new InvalidApplicationException("Invalid application", e);
deployLogger.logApplicationPackage(Level.SEVERE, Exceptions.toMessageString(wrapped));
throw wrapped;
}
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 8d023cac88a..4928af488e1 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
@@ -148,6 +148,8 @@ public class SessionPreparer {
return preparation.result();
}
catch (IllegalArgumentException e) {
+ if (e instanceof InvalidApplicationException)
+ throw e;
throw new InvalidApplicationException("Invalid application package", e);
}
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java
index 95f44bf09a1..39b1a588a17 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/HostedDeployTest.java
@@ -294,7 +294,7 @@ public class HostedDeployTest {
DeployTester tester = createTester(hosts, modelFactories, prodZone);
// Not OK when failing version is requested.
- assertEquals("Invalid application package",
+ assertEquals("Invalid application",
assertThrows(IllegalArgumentException.class,
() -> tester.deployApp("src/test/apps/hosted/", wantedVersion.toFullString()))
.getMessage());
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServerException.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServerException.java
index 47373413a0d..99b2968a43f 100644
--- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServerException.java
+++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServerException.java
@@ -16,6 +16,12 @@ public class ConfigServerException extends RuntimeException {
private final ErrorCode code;
private final String message;
+ public ConfigServerException(ErrorCode code, String message) {
+ super(message);
+ this.code = code;
+ this.message = message;
+ }
+
public ConfigServerException(ErrorCode code, String message, String context) {
super(context + ": " + message);
this.code = code;
diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
index d6da677cb27..ee1094ac32e 100644
--- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
+++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java
@@ -1208,7 +1208,7 @@ public class ApplicationApiTest extends ControllerContainerTest {
400);
ConfigServerMock configServer = tester.serviceRegistry().configServerMock();
- configServer.throwOnNextPrepare(new ConfigServerException(ConfigServerException.ErrorCode.INVALID_APPLICATION_PACKAGE, "Failed to prepare application", "Invalid application package"));
+ configServer.throwOnNextPrepare(new ConfigServerException(ConfigServerException.ErrorCode.INVALID_APPLICATION_PACKAGE, "Deployment failed", "Invalid application package"));
// GET non-existent application package
tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/package", GET).userIdentity(HOSTED_VESPA_OPERATOR),
diff --git a/dist/vespa.spec b/dist/vespa.spec
index 2592e769359..4a1946824a6 100644
--- a/dist/vespa.spec
+++ b/dist/vespa.spec
@@ -94,14 +94,8 @@ BuildRequires: cmake >= 3.11.4-3
BuildRequires: libarchive
%endif
%define _command_cmake cmake
-%if 0%{?_centos_stream}
-BuildRequires: (llvm-devel >= 14.0.0 and llvm-devel < 15)
-%else
-BuildRequires: (llvm-devel >= 13.0.1 and llvm-devel < 14)
-%endif
-%else
-BuildRequires: (llvm-devel >= 13.0.1 and llvm-devel < 14)
%endif
+BuildRequires: llvm-devel
BuildRequires: vespa-boost-devel >= 1.76.0-1
BuildRequires: vespa-openssl-devel >= 1.1.1o-1
%define _use_vespa_openssl 1
@@ -121,11 +115,7 @@ BuildRequires: vespa-lz4-devel >= 1.9.4-1
BuildRequires: vespa-onnxruntime-devel = 1.12.1
BuildRequires: vespa-libzstd-devel >= 1.5.2-1
BuildRequires: protobuf-devel
-%if 0%{?_centos_stream}
-BuildRequires: (llvm-devel >= 14.0.0 and llvm-devel < 15)
-%else
-BuildRequires: (llvm-devel >= 13.0.0 and llvm-devel < 14)
-%endif
+BuildRequires: llvm-devel
BuildRequires: boost-devel >= 1.75
BuildRequires: gtest-devel
BuildRequires: gmock-devel
@@ -145,35 +135,12 @@ BuildRequires: openssl-devel
BuildRequires: vespa-lz4-devel >= 1.9.4-1
BuildRequires: vespa-onnxruntime-devel = 1.12.1
BuildRequires: vespa-libzstd-devel >= 1.5.2-1
-%if 0%{?amzn2022}
-BuildRequires: protobuf-devel
-BuildRequires: llvm-devel >= 14.0.5
-BuildRequires: boost-devel >= 1.75
-BuildRequires: gtest-devel
-BuildRequires: gmock-devel
-%endif
-%if 0%{?fc36}
-BuildRequires: protobuf-devel
-BuildRequires: llvm-devel >= 14.0.0
-BuildRequires: boost-devel >= 1.76
-BuildRequires: gtest-devel
-BuildRequires: gmock-devel
-%endif
-%if 0%{?fc37}
-BuildRequires: protobuf-devel
-BuildRequires: llvm-devel >= 15.0.0
-BuildRequires: boost-devel >= 1.78
-BuildRequires: gtest-devel
-BuildRequires: gmock-devel
-%endif
-%if 0%{?fc38}
BuildRequires: protobuf-devel
-BuildRequires: llvm-devel >= 15.0.0
-BuildRequires: boost-devel >= 1.78
+BuildRequires: llvm-devel
+BuildRequires: boost-devel
BuildRequires: gtest-devel
BuildRequires: gmock-devel
%endif
-%endif
%if 0%{?amzn2022}
BuildRequires: vespa-xxhash-devel >= 0.8.1
%define _use_vespa_xxhash 1
@@ -238,7 +205,6 @@ BuildRequires: perf
%if 0%{?amzn2022}
Requires: vespa-xxhash >= 0.8.1
%else
-Requires: xxhash
Requires: xxhash-libs >= 0.8.1
%endif
Requires: gdb
@@ -344,39 +310,16 @@ Requires: vespa-openssl >= 1.1.1o-1
Requires: openssl-libs
%endif
%if 0%{?el8}
-%if 0%{?centos} || 0%{?rocky} || 0%{?oraclelinux}
-%if 0%{?_centos_stream}
-Requires: (llvm-libs >= 14.0.0 and llvm-libs < 15)
-%else
-Requires: (llvm-libs >= 13.0.1 and llvm-libs < 14)
-%endif
-%else
-Requires: (llvm-libs >= 13.0.1 and llvm-libs < 14)
-%endif
+Requires: llvm-libs
Requires: vespa-protobuf = 3.21.7
%endif
%if 0%{?el9}
-%if 0%{?_centos_stream}
-Requires: (llvm-libs >= 14.0.0 and llvm-libs < 15)
-%else
-Requires: (llvm-libs >= 13.0.0 and llvm-libs < 14)
-%endif
+Requires: llvm-libs
Requires: protobuf
%endif
%if 0%{?fedora}
Requires: protobuf
-%if 0%{?amzn2022}
-Requires: llvm-libs >= 14.0.5
-%endif
-%if 0%{?fc36}
-Requires: llvm-libs >= 14.0.0
-%endif
-%if 0%{?fc37}
-Requires: llvm-libs >= 15.0.0
-%endif
-%if 0%{?fc38}
-Requires: llvm-libs >= 15.0.0
-%endif
+Requires: llvm-libs
%endif
Requires: vespa-onnxruntime = 1.12.1
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java
index 0bf32e534b7..fb21b009a30 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/NodeRepository.java
@@ -7,11 +7,15 @@ import com.yahoo.concurrent.maintenance.JobControl;
import com.yahoo.config.provision.ApplicationTransaction;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.DockerImage;
+import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.NodeFlavors;
import com.yahoo.config.provision.Zone;
import com.yahoo.config.provisioning.NodeRepositoryConfig;
import com.yahoo.vespa.curator.Curator;
import com.yahoo.vespa.flags.FlagSource;
+import com.yahoo.vespa.flags.JacksonFlag;
+import com.yahoo.vespa.flags.PermanentFlags;
+import com.yahoo.vespa.flags.custom.SharedHost;
import com.yahoo.vespa.hosted.provision.Node.State;
import com.yahoo.vespa.hosted.provision.applications.Applications;
import com.yahoo.vespa.hosted.provision.autoscale.MetricsDb;
@@ -62,6 +66,7 @@ public class NodeRepository extends AbstractComponent {
private final MetricsDb metricsDb;
private final Orchestrator orchestrator;
private final int spareCount;
+ private final JacksonFlag<SharedHost> sharedHosts;
/**
* Creates a node repository from a zookeeper provider.
@@ -134,6 +139,7 @@ public class NodeRepository extends AbstractComponent {
this.metricsDb = metricsDb;
this.orchestrator = orchestrator;
this.spareCount = spareCount;
+ this.sharedHosts = PermanentFlags.SHARED_HOST.bindTo(flagSource());
nodes.rewrite();
}
@@ -197,7 +203,8 @@ public class NodeRepository extends AbstractComponent {
* perfectly.
*/
public boolean exclusiveAllocation(ClusterSpec clusterSpec) {
- return clusterSpec.isExclusive() || ! zone().cloud().allowHostSharing();
+ return clusterSpec.isExclusive() ||
+ ( !zone().cloud().allowHostSharing() && !sharedHosts.value().isEnabled(clusterSpec.type().name()));
}
/**
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java
index 389be5b6652..3d76c8e3f94 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/AllocatableClusterResources.java
@@ -164,10 +164,10 @@ public class AllocatableClusterResources {
if (! exclusive) {
// We decide resources: Add overhead to what we'll request (advertised) to make sure real becomes (at least) cappedNodeResources
var advertisedResources = nodeRepository.resourcesCalculator().realToRequest(wantedResources.nodeResources(), exclusive);
- advertisedResources = systemLimits.enlargeToLegal(advertisedResources, clusterSpec.type(), exclusive); // Ask for something legal
+ advertisedResources = systemLimits.enlargeToLegal(advertisedResources, clusterSpec, exclusive); // Ask for something legal
advertisedResources = applicationLimits.cap(advertisedResources); // Overrides other conditions, even if it will then fail
var realResources = nodeRepository.resourcesCalculator().requestToReal(advertisedResources, exclusive); // What we'll really get
- if ( ! systemLimits.isWithinRealLimits(realResources, clusterSpec.type()))
+ if ( ! systemLimits.isWithinRealLimits(realResources, clusterSpec))
return Optional.empty();
if (anySatisfies(realResources, availableRealHostResources))
return Optional.of(new AllocatableClusterResources(wantedResources.with(realResources),
@@ -187,7 +187,7 @@ public class AllocatableClusterResources {
// Adjust where we don't need exact match to the flavor
if (flavor.resources().storageType() == NodeResources.StorageType.remote) {
- double diskGb = systemLimits.enlargeToLegal(cappedWantedResources, clusterSpec.type(), exclusive).diskGb();
+ double diskGb = systemLimits.enlargeToLegal(cappedWantedResources, clusterSpec, exclusive).diskGb();
advertisedResources = advertisedResources.withDiskGb(diskGb);
realResources = realResources.withDiskGb(diskGb);
}
@@ -197,7 +197,7 @@ public class AllocatableClusterResources {
}
if ( ! between(applicationLimits.min().nodeResources(), applicationLimits.max().nodeResources(), advertisedResources)) continue;
- if ( ! systemLimits.isWithinRealLimits(realResources, clusterSpec.type())) continue;
+ if ( ! systemLimits.isWithinRealLimits(realResources, clusterSpec)) continue;
var candidate = new AllocatableClusterResources(wantedResources.with(realResources),
advertisedResources,
wantedResources,
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java
index 689b5a9a950..c816abc060c 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Autoscaler.java
@@ -58,7 +58,8 @@ public class Autoscaler {
}
private Advice autoscale(Application application, Cluster cluster, NodeList clusterNodes, Limits limits) {
- ClusterModel clusterModel = new ClusterModel(application,
+ ClusterModel clusterModel = new ClusterModel(nodeRepository.zone(),
+ application,
clusterNodes.clusterSpec(),
cluster,
clusterNodes,
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java
index c9167c3a87b..80ff22eae91 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModel.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.hosted.provision.autoscale;
import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.Zone;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.applications.Application;
import com.yahoo.vespa.hosted.provision.applications.Cluster;
@@ -39,6 +40,7 @@ public class ClusterModel {
// TODO: Measure this, and only take it into account with queries
private static final double fixedCpuCostFraction = 0.1;
+ private final Zone zone;
private final Application application;
private final ClusterSpec clusterSpec;
private final Cluster cluster;
@@ -53,12 +55,14 @@ public class ClusterModel {
private Double queryFractionOfMax = null;
private Double maxQueryGrowthRate = null;
- public ClusterModel(Application application,
+ public ClusterModel(Zone zone,
+ Application application,
ClusterSpec clusterSpec,
Cluster cluster,
NodeList clusterNodes,
MetricsDb metricsDb,
Clock clock) {
+ this.zone = zone;
this.application = application;
this.clusterSpec = clusterSpec;
this.cluster = cluster;
@@ -69,14 +73,15 @@ public class ClusterModel {
this.nodeTimeseries = new ClusterNodesTimeseries(scalingDuration(), cluster, nodes, metricsDb);
}
- /** For testing */
- ClusterModel(Application application,
+ ClusterModel(Zone zone,
+ Application application,
ClusterSpec clusterSpec,
Cluster cluster,
Clock clock,
Duration scalingDuration,
ClusterTimeseries clusterTimeseries,
ClusterNodesTimeseries nodeTimeseries) {
+ this.zone = zone;
this.application = application;
this.clusterSpec = clusterSpec;
this.cluster = cluster;
@@ -218,13 +223,29 @@ public class ClusterModel {
private double idealCpuLoad() {
double queryCpuFraction = queryCpuFraction();
- // What's needed to have headroom for growth during scale-up as a fraction of current resources?
+ // Assumptions: 1) Write load is not organic so we should not grow to handle more.
+ // (TODO: But allow applications to set their target write rate and size for that)
+ // 2) Write load does not change in BCP scenarios.
+ return queryCpuFraction * 1/growthRateHeadroom() * 1/trafficShiftHeadroom() * idealQueryCpuLoad +
+ (1 - queryCpuFraction) * idealWriteCpuLoad;
+ }
+
+ /** Returns the headroom for growth during organic traffic growth as a multiple of current resources. */
+ private double growthRateHeadroom() {
+ if ( ! zone.environment().isProduction()) return 1;
double growthRateHeadroom = 1 + maxQueryGrowthRate() * scalingDuration().toMinutes();
// Cap headroom at 10% above the historical observed peak
if (queryFractionOfMax() != 0)
growthRateHeadroom = Math.min(growthRateHeadroom, 1 / queryFractionOfMax() + 0.1);
+ return growthRateHeadroom;
+ }
- // How much headroom is needed to handle sudden arrival of additional traffic due to another zone going down?
+ /**
+ * Returns the headroom is needed to handle sudden arrival of additional traffic due to another zone going down
+ * as a multiple of current resources.
+ */
+ private double trafficShiftHeadroom() {
+ if ( ! zone.environment().isProduction()) return 1;
double trafficShiftHeadroom;
if (application.status().maxReadShare() == 0) // No traffic fraction data
trafficShiftHeadroom = 2.0; // assume we currently get half of the global share of traffic
@@ -232,13 +253,7 @@ public class ClusterModel {
trafficShiftHeadroom = 1/application.status().maxReadShare();
else
trafficShiftHeadroom = application.status().maxReadShare() / application.status().currentReadShare();
- trafficShiftHeadroom = Math.min(trafficShiftHeadroom, 1/application.status().maxReadShare());
-
- // Assumptions: 1) Write load is not organic so we should not grow to handle more.
- // (TODO: But allow applications to set their target write rate and size for that)
- // 2) Write load does not change in BCP scenarios.
- return queryCpuFraction * 1/growthRateHeadroom * 1/trafficShiftHeadroom * idealQueryCpuLoad +
- (1 - queryCpuFraction) * idealWriteCpuLoad;
+ return Math.min(trafficShiftHeadroom, 1/application.status().maxReadShare());
}
/** The estimated fraction of cpu usage which goes to processing queries vs. writes */
@@ -303,14 +318,15 @@ public class ClusterModel {
* This is useful in cases where it's possible to continue without the cluser model,
* as QuestDb is known to temporarily fail during reading of data.
*/
- public static Optional<ClusterModel> create(Application application,
+ public static Optional<ClusterModel> create(Zone zone,
+ Application application,
ClusterSpec clusterSpec,
Cluster cluster,
NodeList clusterNodes,
MetricsDb metricsDb,
Clock clock) {
try {
- return Optional.of(new ClusterModel(application, clusterSpec, cluster, clusterNodes, metricsDb, clock));
+ return Optional.of(new ClusterModel(zone, application, clusterSpec, cluster, clusterNodes, metricsDb, clock));
}
catch (Exception e) {
log.log(Level.WARNING, "Failed creating a cluster model for " + application + " " + cluster, e);
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Limits.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Limits.java
index 36b32f0b099..cb5d8dd5042 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Limits.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/Limits.java
@@ -63,7 +63,7 @@ public class Limits {
public Limits fullySpecified(ClusterSpec clusterSpec, NodeRepository nodeRepository, ApplicationId applicationId) {
if (this.isEmpty()) throw new IllegalStateException("Unspecified limits can not be made fully specified");
- var defaultResources = new CapacityPolicies(nodeRepository).defaultNodeResources(clusterSpec, applicationId, clusterSpec.isExclusive());
+ var defaultResources = new CapacityPolicies(nodeRepository).defaultNodeResources(clusterSpec, applicationId);
var specifiedMin = min.nodeResources().isUnspecified() ? min.with(defaultResources) : min;
var specifiedMax = max.nodeResources().isUnspecified() ? max.with(defaultResources) : max;
return new Limits(specifiedMin, specifiedMax);
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/OsUpgrader.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/OsUpgrader.java
index 258609f043e..120b7f00b38 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/OsUpgrader.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/OsUpgrader.java
@@ -8,6 +8,7 @@ import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeList;
import com.yahoo.vespa.hosted.provision.NodeRepository;
+import java.time.Duration;
import java.time.Instant;
/**
@@ -43,8 +44,13 @@ public abstract class OsUpgrader {
}
/** Returns whether node can upgrade at given instant */
- boolean canUpgradeAt(Instant instant, Node node) {
- return true;
+ final boolean canUpgradeAt(Instant instant, Node node) {
+ return node.history().age(instant).compareTo(gracePeriod()) > 0;
+ }
+
+ /** The duration this leaves new nodes alone before scheduling any upgrade */
+ private Duration gracePeriod() {
+ return Duration.ofDays(1);
}
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/OsVersionChange.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/OsVersionChange.java
index bdc40742ea4..a21c8aa539b 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/OsVersionChange.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/OsVersionChange.java
@@ -1,42 +1,36 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.provision.os;
-import com.google.common.collect.ImmutableSortedMap;
import com.yahoo.component.Version;
import com.yahoo.config.provision.NodeType;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
+import java.util.Collections;
+import java.util.SortedMap;
+import java.util.TreeMap;
/**
* The OS version change being deployed in a {@link com.yahoo.vespa.hosted.provision.NodeRepository}.
*
* @author mpolden
*/
-public record OsVersionChange(Map<NodeType, OsVersionTarget> targets) {
+public record OsVersionChange(SortedMap<NodeType, OsVersionTarget> targets) {
- public static final OsVersionChange NONE = new OsVersionChange(Map.of());
+ public static final OsVersionChange NONE = new OsVersionChange(new TreeMap<>());
- public OsVersionChange(Map<NodeType, OsVersionTarget> targets) {
- this.targets = ImmutableSortedMap.copyOf(Objects.requireNonNull(targets));
- }
-
- /** Version targets in this */
- public Map<NodeType, OsVersionTarget> targets() {
- return targets;
+ public OsVersionChange(SortedMap<NodeType, OsVersionTarget> targets) {
+ this.targets = Collections.unmodifiableSortedMap(new TreeMap<>(targets));
}
/** Returns a copy of this with target for given node type removed */
public OsVersionChange withoutTarget(NodeType nodeType) {
- var targets = new HashMap<>(this.targets);
+ var targets = new TreeMap<>(this.targets);
targets.remove(nodeType);
return new OsVersionChange(targets);
}
/** Returns a copy of this with given target added */
public OsVersionChange withTarget(Version version, NodeType nodeType) {
- var copy = new HashMap<>(this.targets);
+ var copy = new TreeMap<>(this.targets);
copy.compute(nodeType, (key, prevTarget) -> new OsVersionTarget(nodeType, version));
return new OsVersionChange(copy);
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/RebuildingOsUpgrader.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/RebuildingOsUpgrader.java
index f329c4cb695..f6779d08fd7 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/RebuildingOsUpgrader.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/RebuildingOsUpgrader.java
@@ -93,8 +93,4 @@ public class RebuildingOsUpgrader extends OsUpgrader {
nodeRepository.nodes().upgradeOs(NodeListFilter.from(host), Optional.of(target));
}
- private static void illegal(String msg) {
- throw new IllegalArgumentException(msg);
- }
-
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/RetiringOsUpgrader.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/RetiringOsUpgrader.java
index de0ef085bc6..4d98885b72c 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/RetiringOsUpgrader.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/os/RetiringOsUpgrader.java
@@ -9,7 +9,6 @@ import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.node.filter.NodeListFilter;
-import java.time.Duration;
import java.time.Instant;
import java.util.Optional;
import java.util.logging.Logger;
@@ -46,11 +45,6 @@ public class RetiringOsUpgrader extends OsUpgrader {
// No action needed in this implementation.
}
- @Override
- public boolean canUpgradeAt(Instant instant, Node node) {
- return node.history().age(instant).compareTo(gracePeriod()) > 0;
- }
-
/** Returns nodes that are candidates for upgrade */
private NodeList candidates(Instant instant, OsVersionTarget target, NodeList allNodes) {
NodeList activeNodes = allNodes.state(Node.State.active).nodeType(target.nodeType());
@@ -74,9 +68,4 @@ public class RetiringOsUpgrader extends OsUpgrader {
nodeRepository.nodes().upgradeOs(NodeListFilter.from(host), Optional.of(target));
}
- /** The duration this leaves new nodes alone before scheduling any upgrade */
- private Duration gracePeriod() {
- return Duration.ofDays(1);
- }
-
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/OsVersionChangeSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/OsVersionChangeSerializer.java
index 1f05e807a69..fd9e5eb34a9 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/OsVersionChangeSerializer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/OsVersionChangeSerializer.java
@@ -11,7 +11,7 @@ import com.yahoo.vespa.hosted.provision.os.OsVersionTarget;
import java.io.IOException;
import java.io.UncheckedIOException;
-import java.util.HashMap;
+import java.util.TreeMap;
/**
* Serializer for {@link OsVersionChange}.
@@ -43,7 +43,7 @@ public class OsVersionChangeSerializer {
}
public static OsVersionChange fromJson(byte[] data) {
- var targets = new HashMap<NodeType, OsVersionTarget>();
+ var targets = new TreeMap<NodeType, OsVersionTarget>();
var inspector = SlimeUtils.jsonToSlime(data).get();
inspector.field(TARGETS_FIELD).traverse((ArrayTraverser) (idx, arrayInspector) -> {
var version = Version.fromString(arrayInspector.field(VERSION_FIELD).asString());
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java
index 8d6c6b4bb62..a1400626658 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/CapacityPolicies.java
@@ -10,10 +10,8 @@ import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.NodeResources;
import com.yahoo.config.provision.Zone;
-import com.yahoo.vespa.flags.JacksonFlag;
import com.yahoo.vespa.flags.PermanentFlags;
import com.yahoo.vespa.flags.StringFlag;
-import com.yahoo.vespa.flags.custom.SharedHost;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import java.util.Map;
import java.util.TreeMap;
@@ -30,13 +28,13 @@ import static java.util.Objects.requireNonNull;
*/
public class CapacityPolicies {
+ private final NodeRepository nodeRepository;
private final Zone zone;
- private final JacksonFlag<SharedHost> sharedHosts;
private final StringFlag adminClusterNodeArchitecture;
public CapacityPolicies(NodeRepository nodeRepository) {
+ this.nodeRepository = nodeRepository;
this.zone = nodeRepository.zone();
- this.sharedHosts = PermanentFlags.SHARED_HOST.bindTo(nodeRepository.flagSource());
this.adminClusterNodeArchitecture = PermanentFlags.ADMIN_CLUSTER_NODE_ARCHITECTURE.bindTo(nodeRepository.flagSource());
}
@@ -79,16 +77,15 @@ public class CapacityPolicies {
return target;
}
- public NodeResources defaultNodeResources(ClusterSpec clusterSpec, ApplicationId applicationId, boolean exclusive) {
+ public NodeResources defaultNodeResources(ClusterSpec clusterSpec, ApplicationId applicationId) {
if (clusterSpec.type() == ClusterSpec.Type.admin) {
Architecture architecture = adminClusterArchitecture(applicationId);
if (clusterSpec.id().value().equals("cluster-controllers")) {
- return clusterControllerResources(clusterSpec, exclusive)
- .with(architecture);
+ return clusterControllerResources(clusterSpec).with(architecture);
}
- return (requiresExclusiveHost(clusterSpec.type(), exclusive)
+ return (nodeRepository.exclusiveAllocation(clusterSpec)
? versioned(clusterSpec, Map.of(new Version(0), smallestExclusiveResources()))
: versioned(clusterSpec, Map.of(new Version(0), smallestSharedResources())))
.with(architecture);
@@ -107,8 +104,8 @@ public class CapacityPolicies {
}
}
- private NodeResources clusterControllerResources(ClusterSpec clusterSpec, boolean exclusive) {
- if (requiresExclusiveHost(clusterSpec.type(), exclusive)) {
+ private NodeResources clusterControllerResources(ClusterSpec clusterSpec) {
+ if (nodeRepository.exclusiveAllocation(clusterSpec)) {
return versioned(clusterSpec, Map.of(new Version(0), smallestExclusiveResources()));
}
return versioned(clusterSpec, Map.of(new Version(0), new NodeResources(0.25, 1.14, 10, 0.3)));
@@ -118,11 +115,6 @@ public class CapacityPolicies {
return Architecture.valueOf(adminClusterNodeArchitecture.with(APPLICATION_ID, instance.serializedForm()).value());
}
- /** Returns whether an exclusive host is required for given cluster type and exclusivity requirement */
- private boolean requiresExclusiveHost(ClusterSpec.Type type, boolean exclusive) {
- return ! zone.cloud().allowHostSharing() && (exclusive || !sharedHosts.value().isEnabled(type.name()));
- }
-
/** Returns the resources for the newest version not newer than that requested in the cluster spec. */
static NodeResources versioned(ClusterSpec spec, Map<Version, NodeResources> resources) {
return requireNonNull(new TreeMap<>(resources).floorEntry(spec.vespaVersion()),
@@ -145,9 +137,10 @@ public class CapacityPolicies {
}
/** Returns whether the nodes requested can share physical host with other applications */
- public boolean decideExclusivity(Capacity capacity, boolean requestedExclusivity) {
- if (capacity.cloudAccount().isPresent()) return true; // Implicit exclusive when using custom cloud account
- return requestedExclusivity && (capacity.isRequired() || zone.environment() == Environment.prod);
+ public ClusterSpec decideExclusivity(Capacity capacity, ClusterSpec requestedCluster) {
+ if (capacity.cloudAccount().isPresent()) return requestedCluster.withExclusivity(true); // Implicit exclusive
+ boolean exclusive = requestedCluster.isExclusive() && (capacity.isRequired() || zone.environment() == Environment.prod);
+ return requestedCluster.withExclusivity(exclusive);
}
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
index b4c01267d3b..c425c235d11 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeRepositoryProvisioner.java
@@ -95,28 +95,29 @@ public class NodeRepositoryProvisioner implements Provisioner {
NodeResources resources;
NodeSpec nodeSpec;
if (requested.type() == NodeType.tenant) {
- boolean exclusive = capacityPolicies.decideExclusivity(requested, cluster.isExclusive());
- Capacity actual = capacityPolicies.applyOn(requested, application, exclusive);
+ cluster = capacityPolicies.decideExclusivity(requested, cluster);
+ Capacity actual = capacityPolicies.applyOn(requested, application, cluster.isExclusive());
ClusterResources target = decideTargetResources(application, cluster, actual);
ensureRedundancy(target.nodes(), cluster, actual.canFail(), application);
logIfDownscaled(requested.minResources().nodes(), actual.minResources().nodes(), cluster, logger);
groups = target.groups();
- resources = getNodeResources(cluster, target.nodeResources(), application, exclusive);
- nodeSpec = NodeSpec.from(target.nodes(), resources, exclusive, actual.canFail(),
+ resources = getNodeResources(cluster, target.nodeResources(), application);
+ nodeSpec = NodeSpec.from(target.nodes(), resources, cluster.isExclusive(), actual.canFail(),
requested.cloudAccount().orElse(nodeRepository.zone().cloud().account()));
}
else {
groups = 1; // type request with multiple groups is not supported
- resources = getNodeResources(cluster, requested.minResources().nodeResources(), application, true);
+ cluster = cluster.withExclusivity(true);
+ resources = getNodeResources(cluster, requested.minResources().nodeResources(), application);
nodeSpec = NodeSpec.from(requested.type(), nodeRepository.zone().cloud().account());
}
return asSortedHosts(preparer.prepare(application, cluster, nodeSpec, groups), resources);
}
- private NodeResources getNodeResources(ClusterSpec cluster, NodeResources nodeResources, ApplicationId applicationId, boolean exclusive) {
+ private NodeResources getNodeResources(ClusterSpec cluster, NodeResources nodeResources, ApplicationId applicationId) {
return nodeResources.isUnspecified()
- ? capacityPolicies.defaultNodeResources(cluster, applicationId, exclusive)
+ ? capacityPolicies.defaultNodeResources(cluster, applicationId)
: nodeResources;
}
@@ -170,15 +171,14 @@ public class NodeRepositoryProvisioner implements Provisioner {
firstDeployment // start at min, preserve current resources otherwise
? new AllocatableClusterResources(initialResourcesFrom(requested, clusterSpec, application.id()), clusterSpec, nodeRepository)
: new AllocatableClusterResources(nodes, nodeRepository);
- var clusterModel = new ClusterModel(application, clusterSpec, cluster, nodes, nodeRepository.metricsDb(), nodeRepository.clock());
+ var clusterModel = new ClusterModel(zone, application, clusterSpec, cluster, nodes, nodeRepository.metricsDb(), nodeRepository.clock());
return within(Limits.of(requested), currentResources, firstDeployment, clusterModel);
}
private ClusterResources initialResourcesFrom(Capacity requested, ClusterSpec clusterSpec, ApplicationId applicationId) {
var initial = requested.minResources();
if (initial.nodeResources().isUnspecified())
- initial = initial.with(capacityPolicies.defaultNodeResources(clusterSpec, applicationId,
- capacityPolicies.decideExclusivity(requested, clusterSpec.isExclusive())));
+ initial = initial.with(capacityPolicies.defaultNodeResources(clusterSpec, applicationId));
return initial;
}
@@ -191,8 +191,8 @@ public class NodeRepositoryProvisioner implements Provisioner {
if (limits.min().equals(limits.max())) return limits.min();
// Don't change current deployments that are still legal
- var currentAsAdvertised = current.advertisedResources();
- if (! firstDeployment && currentAsAdvertised.isWithin(limits.min(), limits.max())) return currentAsAdvertised;
+ if (! firstDeployment && current.advertisedResources().isWithin(limits.min(), limits.max()))
+ return current.advertisedResources();
// Otherwise, find an allocation that preserves the current resources as well as possible
return allocationOptimizer.findBestAllocation(Load.one(),
@@ -260,8 +260,7 @@ public class NodeRepositoryProvisioner implements Provisioner {
private IllegalArgumentException newNoAllocationPossible(ClusterSpec spec, Limits limits) {
StringBuilder message = new StringBuilder("No allocation possible within ").append(limits);
- boolean exclusiveHosts = spec.isExclusive() || ! nodeRepository.zone().cloud().allowHostSharing();
- if (exclusiveHosts)
+ if (nodeRepository.exclusiveAllocation(spec))
message.append(". Nearest allowed node resources: ").append(findNearestNodeResources(limits));
return new IllegalArgumentException(message.toString());
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeResourceLimits.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeResourceLimits.java
index 81dd852e2a1..66895867623 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeResourceLimits.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/provisioning/NodeResourceLimits.java
@@ -28,10 +28,10 @@ public class NodeResourceLimits {
public void ensureWithinAdvertisedLimits(String type, NodeResources requested, ClusterSpec cluster) {
if (requested.isUnspecified()) return;
- if (requested.vcpu() < minAdvertisedVcpu(cluster.type()))
- illegal(type, "vcpu", "", cluster, requested.vcpu(), minAdvertisedVcpu(cluster.type()));
- if (requested.memoryGb() < minAdvertisedMemoryGb(cluster.type()))
- illegal(type, "memoryGb", "Gb", cluster, requested.memoryGb(), minAdvertisedMemoryGb(cluster.type()));
+ if (requested.vcpu() < minAdvertisedVcpu(cluster))
+ illegal(type, "vcpu", "", cluster, requested.vcpu(), minAdvertisedVcpu(cluster));
+ if (requested.memoryGb() < minAdvertisedMemoryGb(cluster))
+ illegal(type, "memoryGb", "Gb", cluster, requested.memoryGb(), minAdvertisedMemoryGb(cluster));
if (requested.diskGb() < minAdvertisedDiskGb(requested, cluster.isExclusive()))
illegal(type, "diskGb", "Gb", cluster, requested.diskGb(), minAdvertisedDiskGb(requested, cluster.isExclusive()));
}
@@ -40,36 +40,36 @@ public class NodeResourceLimits {
public boolean isWithinRealLimits(NodeCandidate candidateNode, ClusterSpec cluster) {
if (candidateNode.type() != NodeType.tenant) return true; // Resource limits only apply to tenant nodes
return isWithinRealLimits(nodeRepository.resourcesCalculator().realResourcesOf(candidateNode, nodeRepository),
- cluster.type());
+ cluster);
}
/** Returns whether the real resources we'll end up with on a given tenant node are within limits */
- public boolean isWithinRealLimits(NodeResources realResources, ClusterSpec.Type clusterType) {
+ public boolean isWithinRealLimits(NodeResources realResources, ClusterSpec cluster) {
if (realResources.isUnspecified()) return true;
- if (realResources.vcpu() < minRealVcpu(clusterType)) return false;
- if (realResources.memoryGb() < minRealMemoryGb(clusterType)) return false;
+ if (realResources.vcpu() < minRealVcpu(cluster)) return false;
+ if (realResources.memoryGb() < minRealMemoryGb(cluster)) return false;
if (realResources.diskGb() < minRealDiskGb()) return false;
return true;
}
- public NodeResources enlargeToLegal(NodeResources requested, ClusterSpec.Type clusterType, boolean exclusive) {
+ public NodeResources enlargeToLegal(NodeResources requested, ClusterSpec cluster, boolean exclusive) {
if (requested.isUnspecified()) return requested;
- return requested.withVcpu(Math.max(minAdvertisedVcpu(clusterType), requested.vcpu()))
- .withMemoryGb(Math.max(minAdvertisedMemoryGb(clusterType), requested.memoryGb()))
+ return requested.withVcpu(Math.max(minAdvertisedVcpu(cluster), requested.vcpu()))
+ .withMemoryGb(Math.max(minAdvertisedMemoryGb(cluster), requested.memoryGb()))
.withDiskGb(Math.max(minAdvertisedDiskGb(requested, exclusive), requested.diskGb()));
}
- private double minAdvertisedVcpu(ClusterSpec.Type clusterType) {
- if (zone().environment() == Environment.dev && zone().cloud().allowHostSharing()) return 0.1;
- if (clusterType.isContent() && zone().environment().isProduction()) return 1.0;
- if (clusterType == ClusterSpec.Type.admin) return 0.1;
+ private double minAdvertisedVcpu(ClusterSpec cluster) {
+ if (zone().environment() == Environment.dev && ! nodeRepository.exclusiveAllocation(cluster)) return 0.1;
+ if (cluster.type().isContent() && zone().environment().isProduction()) return 1.0;
+ if (cluster.type() == ClusterSpec.Type.admin) return 0.1;
return 0.5;
}
- private double minAdvertisedMemoryGb(ClusterSpec.Type clusterType) {
- if (clusterType == ClusterSpec.Type.admin) return 1;
+ private double minAdvertisedMemoryGb(ClusterSpec cluster) {
+ if (cluster.type() == ClusterSpec.Type.admin) return 1;
return 4;
}
@@ -85,10 +85,10 @@ public class NodeResourceLimits {
return 4;
}
- private double minRealVcpu(ClusterSpec.Type clusterType) { return minAdvertisedVcpu(clusterType); }
+ private double minRealVcpu(ClusterSpec cluster) { return minAdvertisedVcpu(cluster); }
- private double minRealMemoryGb(ClusterSpec.Type clusterType) {
- return minAdvertisedMemoryGb(clusterType) - 1.7;
+ private double minRealMemoryGb(ClusterSpec cluster) {
+ return minAdvertisedMemoryGb(cluster) - 1.7;
}
private double minRealDiskGb() { return 6; }
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java
index c5e4654c568..0603eb97cca 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/ApplicationSerializer.java
@@ -63,7 +63,13 @@ public class ApplicationSerializer {
NodeList nodes = applicationNodes.not().retired().cluster(cluster.id());
if (nodes.isEmpty()) return;
ClusterResources currentResources = nodes.toResources();
- Optional<ClusterModel> clusterModel = ClusterModel.create(application, nodes.clusterSpec(), cluster, nodes, metricsDb, nodeRepository.clock());
+ Optional<ClusterModel> clusterModel = ClusterModel.create(nodeRepository.zone(),
+ application,
+ nodes.clusterSpec(),
+ cluster,
+ nodes,
+ metricsDb,
+ nodeRepository.clock());
Cursor clusterObject = clustersObject.setObject(cluster.id().value());
clusterObject.setString("type", nodes.clusterSpec().type().name());
Limits limits = Limits.of(cluster).fullySpecified(nodes.clusterSpec(), nodeRepository, application.id());
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java
index f833348b8dc..d0232f6f62f 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTest.java
@@ -272,7 +272,7 @@ public class AutoscalingTest {
.build();
NodeResources defaultResources =
- new CapacityPolicies(fixture.tester().nodeRepository()).defaultNodeResources(fixture.clusterSpec, fixture.applicationId, false);
+ new CapacityPolicies(fixture.tester().nodeRepository()).defaultNodeResources(fixture.clusterSpec, fixture.applicationId);
fixture.tester().assertResources("Min number of nodes and default resources",
2, 1, defaultResources,
@@ -649,4 +649,34 @@ public class AutoscalingTest {
fixture.autoscale());
}
+ @Test
+ public void test_changing_exclusivity() {
+ var fixture = AutoscalingTester.fixture()
+ .awsProdSetup(true)
+ .cluster(clusterSpec(true))
+ .initialResources(Optional.empty())
+ .build();
+ fixture.tester().assertResources("Initial deployment at minimum",
+ 2, 1, 2, 4, 10,
+ fixture.currentResources().advertisedResources());
+
+ fixture.tester().deploy(fixture.applicationId(), clusterSpec(false), fixture.capacity());
+ fixture.tester().assertResources("With non-exclusive nodes, a better solution is " +
+ "50% more nodes with half the cpu",
+ 3, 1, 1, 4, 10.2,
+ fixture.autoscale());
+
+ fixture.tester().deploy(fixture.applicationId(), clusterSpec(true), fixture.capacity());
+ fixture.tester().assertResources("Reverts to the initial resources",
+ 2, 1, 2, 4, 10,
+ fixture.currentResources().advertisedResources());
+ }
+
+ private ClusterSpec clusterSpec(boolean exclusive) {
+ return ClusterSpec.request(ClusterSpec.Type.container,
+ ClusterSpec.Id.from("test")).vespaVersion("8.1.2")
+ .exclusive(exclusive)
+ .build();
+ }
+
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java
index 56f23e62f90..00797cd6305 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/AutoscalingTester.java
@@ -142,7 +142,7 @@ class AutoscalingTester {
}
public Autoscaler.Advice autoscale(ApplicationId applicationId, ClusterSpec cluster, Capacity capacity) {
- capacity = capacityPolicies.applyOn(capacity, applicationId, capacityPolicies.decideExclusivity(capacity, cluster.isExclusive()));
+ capacity = capacityPolicies.applyOn(capacity, applicationId, capacityPolicies.decideExclusivity(capacity, cluster).isExclusive());
Application application = nodeRepository().applications().get(applicationId).orElse(Application.empty(applicationId))
.withCluster(cluster.id(), false, capacity);
try (Mutex lock = nodeRepository().applications().lock(applicationId)) {
@@ -210,17 +210,15 @@ class AutoscalingTester {
public static class MockHostResourcesCalculator implements HostResourcesCalculator {
private final Zone zone;
- private double memoryTax;
- public MockHostResourcesCalculator(Zone zone, double memoryTax) {
+ public MockHostResourcesCalculator(Zone zone) {
this.zone = zone;
- this.memoryTax = memoryTax;
}
@Override
public NodeResources realResourcesOf(Nodelike node, NodeRepository nodeRepository) {
if (zone.cloud().dynamicProvisioning())
- return node.resources().withMemoryGb(node.resources().memoryGb() - memoryTax);
+ return node.resources().withMemoryGb(node.resources().memoryGb());
else
return node.resources();
}
@@ -228,19 +226,19 @@ class AutoscalingTester {
@Override
public NodeResources advertisedResourcesOf(Flavor flavor) {
if (zone.cloud().dynamicProvisioning())
- return flavor.resources().withMemoryGb(flavor.resources().memoryGb() + memoryTax);
+ return flavor.resources().withMemoryGb(flavor.resources().memoryGb());
else
return flavor.resources();
}
@Override
public NodeResources requestToReal(NodeResources resources, boolean exclusive) {
- return resources.withMemoryGb(resources.memoryGb() - memoryTax);
+ return resources.withMemoryGb(resources.memoryGb());
}
@Override
public NodeResources realToRequest(NodeResources resources, boolean exclusive) {
- return resources.withMemoryGb(resources.memoryGb() + memoryTax);
+ return resources.withMemoryGb(resources.memoryGb());
}
@Override
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModelTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModelTest.java
index f31ad191637..b38dbfc55ae 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModelTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/ClusterModelTest.java
@@ -6,6 +6,7 @@ import com.yahoo.config.provision.Capacity;
import com.yahoo.config.provision.ClusterResources;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.NodeResources;
+import com.yahoo.config.provision.Zone;
import com.yahoo.test.ManualClock;
import com.yahoo.vespa.hosted.provision.applications.Application;
import com.yahoo.vespa.hosted.provision.applications.Cluster;
@@ -73,11 +74,13 @@ public class ClusterModelTest {
private ClusterModel clusterModel(Status status, IntFunction<Double> queryRate, IntFunction<Double> writeRate) {
ManualClock clock = new ManualClock();
+ Zone zone = Zone.defaultZone();
Application application = Application.empty(ApplicationId.from("t1", "a1", "i1"));
ClusterSpec clusterSpec = clusterSpec();
Cluster cluster = cluster(resources());
application = application.with(cluster);
- return new ClusterModel(application.with(status),
+ return new ClusterModel(zone,
+ application.with(status),
clusterSpec, cluster, clock, Duration.ofMinutes(10),
timeseries(cluster,100, queryRate, writeRate, clock),
ClusterNodesTimeseries.empty());
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Fixture.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Fixture.java
index d348df00b78..4828db4dfc8 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Fixture.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/Fixture.java
@@ -35,12 +35,14 @@ import java.util.stream.Collectors;
public class Fixture {
final AutoscalingTester tester;
+ final Zone zone;
final ApplicationId applicationId;
final ClusterSpec clusterSpec;
final Capacity capacity;
final Loader loader;
public Fixture(Fixture.Builder builder, Optional<ClusterResources> initialResources, int hostCount) {
+ zone = builder.zone;
applicationId = builder.application;
clusterSpec = builder.cluster;
capacity = builder.capacity;
@@ -60,12 +62,20 @@ public class Fixture {
return tester().nodeRepository().applications().get(applicationId).orElse(Application.empty(applicationId));
}
+ public AllocatableClusterResources currentResources() {
+ return new AllocatableClusterResources(tester.nodeRepository().nodes().list(Node.State.active).owner(applicationId).cluster(clusterId()),
+ tester.nodeRepository());
+ }
+
public Cluster cluster() {
return application().cluster(clusterId()).get();
}
+ public Capacity capacity() { return capacity; }
+
public ClusterModel clusterModel() {
- return new ClusterModel(application(),
+ return new ClusterModel(zone,
+ application(),
clusterSpec,
cluster(),
nodes(),
@@ -128,10 +138,10 @@ public class Fixture {
List<Flavor> hostFlavors = List.of(new Flavor(new NodeResources(100, 100, 100, 1)));
Optional<ClusterResources> initialResources = Optional.of(new ClusterResources(5, 1, new NodeResources(2, 16, 75, 1)));
Capacity capacity = Capacity.from(new ClusterResources(2, 1,
- new NodeResources(1, 1, 1, 1, NodeResources.DiskSpeed.any)),
+ new NodeResources(1, 4, 10, 1, NodeResources.DiskSpeed.any)),
new ClusterResources(20, 1,
new NodeResources(100, 1000, 1000, 1, NodeResources.DiskSpeed.any)));
- HostResourcesCalculator resourceCalculator = new AutoscalingTester.MockHostResourcesCalculator(zone, 0);
+ HostResourcesCalculator resourceCalculator = new AutoscalingTester.MockHostResourcesCalculator(zone);
int hostCount = 0;
public Fixture.Builder zone(Zone zone) {
@@ -168,6 +178,11 @@ public class Fixture {
return this;
}
+ public Fixture.Builder cluster(ClusterSpec cluster) {
+ this.cluster = cluster;
+ return this;
+ }
+
public Fixture.Builder awsProdSetup(boolean allowHostSharing) {
return this.awsHostFlavors()
.awsResourceCalculator()
@@ -215,7 +230,7 @@ public class Fixture {
return this;
}
- public Fixture.Builder hostCount(int hostCount) { // TODO: Remove all usage of this
+ public Fixture.Builder hostCount(int hostCount) {
this.hostCount = hostCount;
return this;
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/awsnodes/AwsHostResourcesCalculatorImpl.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/awsnodes/AwsHostResourcesCalculatorImpl.java
index 4609c0a4023..d148f6d3cc7 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/awsnodes/AwsHostResourcesCalculatorImpl.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/awsnodes/AwsHostResourcesCalculatorImpl.java
@@ -12,7 +12,6 @@ import com.yahoo.vespa.hosted.provision.provisioning.HostResourcesCalculator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
/**
* @author valerijf
@@ -45,19 +44,32 @@ public class AwsHostResourcesCalculatorImpl implements HostResourcesCalculator {
@Override
public NodeResources requestToReal(NodeResources advertisedResources, boolean exclusive) {
- double memoryOverhead = flavorsCompatibleWithAdvertised(advertisedResources, exclusive)
- .mapToDouble(flavor -> resourcesCalculator.memoryOverhead(flavor, advertisedResources, false)).max().orElse(0);
- double diskOverhead = flavorsCompatibleWithAdvertised(advertisedResources, exclusive)
- .mapToDouble(flavor -> resourcesCalculator.diskOverhead(flavor, advertisedResources, false, exclusive)).max().orElse(0);
+ // Only consider exactly matched flavors if any to avoid concluding we have slightly too little resources
+ // on an exactly matched flavor if we move from exclusive to shared hosts
+ List<VespaFlavor> consideredFlavors = flavorsCompatibleWithAdvertised(advertisedResources, true);
+ if (consideredFlavors.isEmpty())
+ consideredFlavors = flavorsCompatibleWithAdvertised(advertisedResources, false);
+
+ double memoryOverhead = consideredFlavors.stream()
+ .mapToDouble(flavor -> resourcesCalculator.memoryOverhead(flavor, advertisedResources, false))
+ .max().orElse(0);
+ double diskOverhead = consideredFlavors.stream()
+ .mapToDouble(flavor -> resourcesCalculator.diskOverhead(flavor, advertisedResources, false, exclusive))
+ .max().orElse(0);
return advertisedResources.withMemoryGb(advertisedResources.memoryGb() - memoryOverhead)
.withDiskGb(advertisedResources.diskGb() - diskOverhead);
}
@Override
public NodeResources realToRequest(NodeResources realResources, boolean exclusive) {
+ // Only consider exactly matched flavors if any to avoid concluding we have slightly too little resources
+ // on an exactly matched flavor if we move from exclusive to shared hosts
+ List<VespaFlavor> consideredFlavors = flavorsCompatibleWithReal(realResources, true);
+ if (consideredFlavors.isEmpty())
+ consideredFlavors = flavorsCompatibleWithReal(realResources, false);
double worstMemoryOverhead = 0;
double worstDiskOverhead = 0;
- for (VespaFlavor flavor : flavorsCompatibleWithReal(realResources, exclusive)) {
+ for (VespaFlavor flavor : consideredFlavors) {
double memoryOverhead = resourcesCalculator.memoryOverhead(flavor, realResources, true);
double diskOverhead = resourcesCalculator.diskOverhead(flavor, realResources, true, exclusive);
NodeResources advertised = realResources.withMemoryGb(realResources.memoryGb() + memoryOverhead)
@@ -78,20 +90,21 @@ public class AwsHostResourcesCalculatorImpl implements HostResourcesCalculator {
}
/** Returns the flavors of hosts which are eligible and matches the given advertised resources */
- private Stream<VespaFlavor> flavorsCompatibleWithAdvertised(NodeResources advertisedResources, boolean exclusive) {
+ private List<VespaFlavor> flavorsCompatibleWithAdvertised(NodeResources advertisedResources, boolean exactOnly) {
return flavors.values().stream()
- .filter(flavor -> exclusive
- ? flavor.advertisedResources().compatibleWith(advertisedResources)
- : flavor.advertisedResources().satisfies(advertisedResources));
+ .filter(flavor -> exactOnly
+ ? flavor.advertisedResources().equalsWhereSpecified(advertisedResources)
+ : flavor.advertisedResources().satisfies(advertisedResources))
+ .toList();
}
/** Returns the flavors of hosts which are eligible and matches the given real resources */
- private List<VespaFlavor> flavorsCompatibleWithReal(NodeResources realResources, boolean exclusive) {
+ private List<VespaFlavor> flavorsCompatibleWithReal(NodeResources realResources, boolean exactOnly) {
return flavors.values().stream()
- .filter(flavor -> exclusive
- ? flavor.realResources().compatibleWith(realResources)
+ .filter(flavor -> exactOnly
+ ? resourcesCalculator.realResourcesOfChildContainer(flavor.advertisedResources(), flavor).compatibleWith(realResources)
: flavor.realResources().satisfies(realResources))
- .collect(Collectors.toList());
+ .toList();
}
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OsUpgradeActivatorTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OsUpgradeActivatorTest.java
index a0c9e2fc530..be43d39cdeb 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OsUpgradeActivatorTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/OsUpgradeActivatorTest.java
@@ -45,6 +45,7 @@ public class OsUpgradeActivatorTest {
var tenantHostApplication = ApplicationId.from("hosted-vespa", "tenant-host", "default");
var tenantHostNodes = tester.makeReadyNodes(3, "default", NodeType.host, 1);
tester.prepareAndActivateInfraApplication(tenantHostApplication, NodeType.host, version0);
+ tester.clock().advance(Duration.ofDays(1).plusSeconds(1)); // Let grace period pass
var allNodes = new ArrayList<>(configHostNodes);
allNodes.addAll(tenantHostNodes);
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/os/OsVersionsTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/os/OsVersionsTest.java
index f9cc41cd8d0..1741dbdb749 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/os/OsVersionsTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/os/OsVersionsTest.java
@@ -175,7 +175,6 @@ public class OsVersionsTest {
Supplier<NodeList> hostNodes = () -> tester.nodeRepository().nodes().list()
.hosts()
.not().state(Node.State.deprovisioned);
- tester.clock().advance(Duration.ofDays(2)); // Let grace period pass
// Target is set and upgrade started
var version1 = Version.fromString("7.1");
@@ -219,7 +218,6 @@ public class OsVersionsTest {
Supplier<NodeList> hostNodes = () -> tester.nodeRepository().nodes().list()
.nodeType(NodeType.host)
.not().state(Node.State.deprovisioned);
- tester.clock().advance(Duration.ofDays(2)); // Let grace period pass
// Target is set and upgrade started
var version1 = Version.fromString("7.1");
@@ -541,6 +539,7 @@ public class OsVersionsTest {
NodeResources.DiskSpeed.fast, storageType),
nodeType, 10);
tester.prepareAndActivateInfraApplication(application, nodeType);
+ tester.clock().advance(Duration.ofDays(1).plusSeconds(1)); // Let grace period pass
return nodes.stream()
.map(Node::hostname)
.flatMap(hostname -> tester.nodeRepository().nodes().node(hostname).stream())
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/OsVersionChangeSerializerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/OsVersionChangeSerializerTest.java
index b68df92cf3e..e61e433b2bd 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/OsVersionChangeSerializerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/persistence/OsVersionChangeSerializerTest.java
@@ -8,6 +8,7 @@ import com.yahoo.vespa.hosted.provision.os.OsVersionTarget;
import org.junit.Test;
import java.util.Map;
+import java.util.TreeMap;
import static org.junit.Assert.assertEquals;
@@ -18,11 +19,11 @@ public class OsVersionChangeSerializerTest {
@Test
public void serialization() {
- var change = new OsVersionChange(Map.of(
+ var change = new OsVersionChange(new TreeMap<>(Map.of(
NodeType.host, new OsVersionTarget(NodeType.host, Version.fromString("1.2.3")),
NodeType.proxyhost, new OsVersionTarget(NodeType.proxyhost, Version.fromString("4.5.6")),
NodeType.confighost, new OsVersionTarget(NodeType.confighost, Version.fromString("7.8.9"))
- ));
+ )));
var serialized = OsVersionChangeSerializer.fromJson(OsVersionChangeSerializer.toJson(change));
assertEquals(serialized, change);
}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-os-upgrade-complete.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-os-upgrade-complete.json
index 0290aba4118..b5e8a040c30 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-os-upgrade-complete.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-os-upgrade-complete.json
@@ -29,8 +29,7 @@
"rebootGeneration": 0,
"currentRebootGeneration": 0,
"currentOsVersion": "7.5.2",
- "wantedOsVersion": "7.5.2",
- "deferOsUpgrade": false,
+ "deferOsUpgrade": true,
"failCount": 0,
"wantToRetire": false,
"preferToRetire": false,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-2.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-2.json
index dc68af4b602..afed3b4e17e 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-2.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-2.json
@@ -36,7 +36,7 @@
},
"rebootGeneration": 0,
"currentRebootGeneration": 0,
- "deferOsUpgrade": false,
+ "deferOsUpgrade": true,
"failCount": 0,
"wantToRetire": true,
"preferToRetire": false,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-3.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-3.json
index 94eb5a6015f..1c366d634cc 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-3.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-3.json
@@ -36,7 +36,7 @@
},
"rebootGeneration": 0,
"currentRebootGeneration": 0,
- "deferOsUpgrade": false,
+ "deferOsUpgrade": true,
"failCount": 0,
"wantToRetire": false,
"preferToRetire": false,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-4.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-4.json
index db6ac0040af..98e3920b910 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-4.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports-4.json
@@ -36,7 +36,7 @@
},
"rebootGeneration": 0,
"currentRebootGeneration": 0,
- "deferOsUpgrade": false,
+ "deferOsUpgrade": true,
"failCount": 0,
"wantToRetire": false,
"preferToRetire": false,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports.json
index bbf1c7b52ea..dbe0222a848 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1-reports.json
@@ -36,7 +36,7 @@
},
"rebootGeneration": 0,
"currentRebootGeneration": 0,
- "deferOsUpgrade": false,
+ "deferOsUpgrade": true,
"failCount": 0,
"wantToRetire": true,
"preferToRetire": false,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1.json
index 70eac6a33db..b5c61780c51 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node1.json
@@ -28,7 +28,7 @@
"requestedResources": { "vcpu":4.0, "memoryGb":32.0, "diskGb":1600.0, "bandwidthGbps":20.0, "diskSpeed":"fast", "storageType":"remote","architecture":"x86_64" },
"rebootGeneration": 0,
"currentRebootGeneration": 0,
- "deferOsUpgrade": false,
+ "deferOsUpgrade": true,
"failCount": 0,
"wantToRetire": false,
"preferToRetire": false,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node2.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node2.json
index bf12fc18b03..b39aba199b7 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node2.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node2.json
@@ -28,7 +28,7 @@
"requestedResources": { "vcpu":4.0, "memoryGb":32.0, "diskGb":1600.0, "bandwidthGbps":20.0, "diskSpeed":"fast", "storageType":"remote","architecture":"x86_64" },
"rebootGeneration": 0,
"currentRebootGeneration": 0,
- "deferOsUpgrade": false,
+ "deferOsUpgrade": true,
"failCount": 0,
"wantToRetire": false,
"preferToRetire": false,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node3.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node3.json
index 67f42d73776..480e8f7f910 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node3.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node3.json
@@ -28,7 +28,7 @@
"requestedResources": { "vcpu":4.0, "memoryGb":32.0, "diskGb":1600.0, "bandwidthGbps":20.0, "diskSpeed":"fast", "storageType":"remote","architecture":"x86_64" },
"rebootGeneration": 0,
"currentRebootGeneration": 0,
- "deferOsUpgrade": false,
+ "deferOsUpgrade": true,
"failCount": 0,
"wantToRetire": false,
"preferToRetire": false,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node4.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node4.json
index ac9019a2d82..163a3d7c244 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node4.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node4.json
@@ -28,7 +28,7 @@
"requestedResources": { "vcpu":4.0, "memoryGb":32.0, "diskGb":1600.0, "bandwidthGbps":20.0, "diskSpeed":"fast", "storageType":"remote","architecture":"x86_64" },
"rebootGeneration": 0,
"currentRebootGeneration": 0,
- "deferOsUpgrade": false,
+ "deferOsUpgrade": true,
"failCount": 0,
"wantToRetire": false,
"preferToRetire": false,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node5.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node5.json
index cff37c43655..c160c5dcdfe 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node5.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/docker-node5.json
@@ -28,7 +28,7 @@
"requestedResources": { "vcpu":4.0, "memoryGb":32.0, "diskGb":1600.0, "bandwidthGbps":20.0, "diskSpeed":"fast", "storageType":"remote","architecture":"x86_64" },
"rebootGeneration": 0,
"currentRebootGeneration": 0,
- "deferOsUpgrade": false,
+ "deferOsUpgrade": true,
"failCount": 0,
"wantToRetire": false,
"preferToRetire": false,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/dockerhost1-with-firmware-data.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/dockerhost1-with-firmware-data.json
index 5124560b3bc..6d62c31ce56 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/dockerhost1-with-firmware-data.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/dockerhost1-with-firmware-data.json
@@ -28,7 +28,7 @@
"requestedResources": { "vcpu":4.0, "memoryGb":32.0, "diskGb":1600.0, "bandwidthGbps":20.0, "diskSpeed":"fast", "storageType":"remote","architecture":"x86_64" },
"rebootGeneration": 0,
"currentRebootGeneration": 0,
- "deferOsUpgrade": false,
+ "deferOsUpgrade": true,
"currentFirmwareCheck": 100,
"wantedFirmwareCheck": 123,
"failCount": 0,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/dockerhost6.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/dockerhost6.json
index 4b3a1448d4c..add2fcf87a8 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/dockerhost6.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/dockerhost6.json
@@ -11,7 +11,7 @@
"environment": "BARE_METAL",
"rebootGeneration": 0,
"currentRebootGeneration": 0,
- "deferOsUpgrade": false,
+ "deferOsUpgrade": true,
"failCount": 1,
"wantToRetire": false,
"preferToRetire": false,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node8.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node8.json
index f6d7a9e201c..3c70371cdc6 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node8.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node8.json
@@ -27,7 +27,7 @@
"environment": "BARE_METAL",
"rebootGeneration": 0,
"currentRebootGeneration": 0,
- "deferOsUpgrade": false,
+ "deferOsUpgrade": true,
"failCount": 0,
"wantToRetire": false,
"preferToRetire": false,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node9.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node9.json
index e76a364e1bb..2cb3213add1 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node9.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/node9.json
@@ -11,7 +11,7 @@
"environment": "BARE_METAL",
"rebootGeneration": 0,
"currentRebootGeneration": 0,
- "deferOsUpgrade": false,
+ "deferOsUpgrade": true,
"failCount": 0,
"wantToRetire": false,
"preferToRetire": false,
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/parent2.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/parent2.json
index 58b96b51efa..03227335019 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/parent2.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/responses/parent2.json
@@ -13,7 +13,7 @@
"environment": "BARE_METAL",
"rebootGeneration": 0,
"currentRebootGeneration": 0,
- "deferOsUpgrade": false,
+ "deferOsUpgrade": true,
"failCount": 0,
"wantToRetire": false,
"preferToRetire": false,
diff --git a/searchlib/src/vespa/searchlib/queryeval/equiv_blueprint.h b/searchlib/src/vespa/searchlib/queryeval/equiv_blueprint.h
index 706e05f0156..86bd4f09cd4 100644
--- a/searchlib/src/vespa/searchlib/queryeval/equiv_blueprint.h
+++ b/searchlib/src/vespa/searchlib/queryeval/equiv_blueprint.h
@@ -18,7 +18,7 @@ private:
public:
EquivBlueprint(const FieldSpecBaseList &fields, fef::MatchDataLayout subtree_mdl);
- virtual ~EquivBlueprint();
+ ~EquivBlueprint() override;
// used by create visitor
EquivBlueprint& addTerm(Blueprint::UP term, double exactness);
diff --git a/searchlib/src/vespa/searchlib/queryeval/field_spec.cpp b/searchlib/src/vespa/searchlib/queryeval/field_spec.cpp
index 138b4e6865d..ebda61dd820 100644
--- a/searchlib/src/vespa/searchlib/queryeval/field_spec.cpp
+++ b/searchlib/src/vespa/searchlib/queryeval/field_spec.cpp
@@ -12,4 +12,8 @@ FieldSpecBase::FieldSpecBase(uint32_t fieldId, fef::TermFieldHandle handle, bool
assert(fieldId < 0x1000000); // Can be represented by 24 bits
}
+FieldSpecBaseList::~FieldSpecBaseList() = default;
+
+FieldSpecList::~FieldSpecList() = default;
+
}
diff --git a/searchlib/src/vespa/searchlib/queryeval/field_spec.h b/searchlib/src/vespa/searchlib/queryeval/field_spec.h
index be151e1fa28..0d66de954ad 100644
--- a/searchlib/src/vespa/searchlib/queryeval/field_spec.h
+++ b/searchlib/src/vespa/searchlib/queryeval/field_spec.h
@@ -59,6 +59,7 @@ private:
List _list;
public:
+ ~FieldSpecBaseList();
using const_iterator = List::const_iterator;
FieldSpecBaseList &add(const FieldSpecBase &spec) {
_list.push_back(spec);
@@ -82,6 +83,7 @@ private:
std::vector<FieldSpec> _list;
public:
+ ~FieldSpecList();
FieldSpecList &add(const FieldSpec &spec) {
_list.push_back(spec);
return *this;