diff options
41 files changed, 289 insertions, 164 deletions
diff --git a/cloud-tenant-base-dependencies-enforcer/pom.xml b/cloud-tenant-base-dependencies-enforcer/pom.xml index 16045d5dc75..340123ae659 100644 --- a/cloud-tenant-base-dependencies-enforcer/pom.xml +++ b/cloud-tenant-base-dependencies-enforcer/pom.xml @@ -34,7 +34,7 @@ <jetty-alpn.version>1.1.3.v20160715</jetty-alpn.version> <junit5.version>5.7.0</junit5.version> <junit5.platform.version>1.7.0</junit5.platform.version> - <onnxruntime.version>1.7.0</onnxruntime.version> + <onnxruntime.version>1.8.0</onnxruntime.version> <org.lz4.version>1.7.1</org.lz4.version> <org.json.version>20090211</org.json.version><!-- TODO Vespa 8: remove as provided dependency --> <slf4j.version>1.7.30</slf4j.version> diff --git a/config-model-api/abi-spec.json b/config-model-api/abi-spec.json index 1ffa5c00426..9de674ca820 100644 --- a/config-model-api/abi-spec.json +++ b/config-model-api/abi-spec.json @@ -539,7 +539,8 @@ "public static final enum com.yahoo.config.application.api.ValidationId skipOldConfigModels", "public static final enum com.yahoo.config.application.api.ValidationId accessControl", "public static final enum com.yahoo.config.application.api.ValidationId globalEndpointChange", - "public static final enum com.yahoo.config.application.api.ValidationId redundancyIncrease" + "public static final enum com.yahoo.config.application.api.ValidationId redundancyIncrease", + "public static final enum com.yahoo.config.application.api.ValidationId redundancyOne" ] }, "com.yahoo.config.application.api.ValidationOverrides$Allow": { diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/ValidationId.java b/config-model-api/src/main/java/com/yahoo/config/application/api/ValidationId.java index 24730ada3ab..7aa6788b86d 100644 --- a/config-model-api/src/main/java/com/yahoo/config/application/api/ValidationId.java +++ b/config-model-api/src/main/java/com/yahoo/config/application/api/ValidationId.java @@ -24,7 +24,8 @@ public enum ValidationId { skipOldConfigModels("skip-old-config-models"), // Internal use accessControl("access-control"), // Internal use, used in zones where there should be no access-control globalEndpointChange("global-endpoint-change"), // Changing global endpoints - redundancyIncrease("redundancy-increase"); // Increasing redundancy - may easily cause feed blocked + redundancyIncrease("redundancy-increase"), // Increasing redundancy - may easily cause feed blocked + redundancyOne("redundancy-one"); // redundancy=1 requires a validation override on first deployment private final String id; diff --git a/config-model-api/src/main/java/com/yahoo/config/application/api/ValidationOverrides.java b/config-model-api/src/main/java/com/yahoo/config/application/api/ValidationOverrides.java index ea27b7f70d8..3221df38d4f 100644 --- a/config-model-api/src/main/java/com/yahoo/config/application/api/ValidationOverrides.java +++ b/config-model-api/src/main/java/com/yahoo/config/application/api/ValidationOverrides.java @@ -177,6 +177,7 @@ public class ValidationOverrides { } + // TODO: Remove this class after June 2021 public static class AllowAllValidationOverrides extends ValidationOverrides { private final DeployLogger logger; diff --git a/config-model-api/src/test/java/com/yahoo/config/application/api/ValidationOverrideTest.java b/config-model-api/src/test/java/com/yahoo/config/application/api/ValidationOverrideTest.java index 2943b0bab34..f7ef059c5f2 100644 --- a/config-model-api/src/test/java/com/yahoo/config/application/api/ValidationOverrideTest.java +++ b/config-model-api/src/test/java/com/yahoo/config/application/api/ValidationOverrideTest.java @@ -4,16 +4,10 @@ package com.yahoo.config.application.api; import com.yahoo.test.ManualClock; import org.junit.Assert; import org.junit.Test; -import org.xml.sax.SAXException; - -import java.io.IOException; import java.io.StringReader; -import java.time.Clock; import java.time.Instant; -import java.util.Optional; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; /** * @author bratseth @@ -82,15 +76,6 @@ public class ValidationOverrideTest { assertEquals(empty.xmlForm(), emptyReserialized.xmlForm()); } - @Test - public void testAll() { - ValidationOverrides all = ValidationOverrides.all; - assertTrue(all.allows(ValidationId.deploymentRemoval, Clock.systemUTC().instant())); - assertTrue(all.allows(ValidationId.contentClusterRemoval, Clock.systemUTC().instant())); - assertTrue(all.allows(ValidationId.indexModeChange, Clock.systemUTC().instant())); - assertTrue(all.allows(ValidationId.fieldTypeChange, Clock.systemUTC().instant())); - } - private void assertOverridden(String validationId, ValidationOverrides overrides, Instant now) { overrides.invalid(ValidationId.from(validationId).get(), "message", now); // should not throw exception } diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java b/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java index 68924dde3e1..dd66861f2ce 100644 --- a/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java +++ b/config-model/src/main/java/com/yahoo/config/model/deploy/DeployState.java @@ -142,12 +142,8 @@ public class DeployState implements ConfigDefinitionStore { this.semanticRules = semanticRules; // TODO: Remove this by seeing how pagetemplates are propagated this.importedModels = importMlModels(applicationPackage, modelImporters, deployLogger); - ValidationOverrides suppliedValidationOverrides = applicationPackage.getValidationOverrides().map(ValidationOverrides::fromXml) - .orElse(ValidationOverrides.empty); - this.validationOverrides = - zone.environment().isManuallyDeployed() // // Warn but allow in manually deployed zones - ? new ValidationOverrides.AllowAllValidationOverrides(suppliedValidationOverrides, deployLogger) - : suppliedValidationOverrides; + this.validationOverrides = applicationPackage.getValidationOverrides().map(ValidationOverrides::fromXml) + .orElse(ValidationOverrides.empty); this.wantedNodeVespaVersion = wantedNodeVespaVersion; this.now = now; diff --git a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java index 2927df57bc1..e08c57a6fb4 100644 --- a/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java +++ b/config-model/src/main/java/com/yahoo/config/model/deploy/TestProperties.java @@ -42,6 +42,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea private double defaultTermwiseLimit = 1.0; private String jvmGCOptions = null; private String sequencerType = "LATENCY"; + private boolean firstTimeDeployment = false; private String responseSequencerType = "ADAPTIVE"; private int responseNumThreads = 2; private Optional<EndpointCertificateSecrets> endpointCertificateSecrets = Optional.empty(); @@ -77,7 +78,7 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea @Override public String jvmGCOptions(Optional<ClusterSpec.Type> clusterType) { return jvmGCOptions; } @Override public String feedSequencerType() { return sequencerType; } @Override public boolean isBootstrap() { return false; } - @Override public boolean isFirstTimeDeployment() { return false; } + @Override public boolean isFirstTimeDeployment() { return firstTimeDeployment; } @Override public boolean useDedicatedNodeForLogserver() { return useDedicatedNodeForLogserver; } @Override public Optional<EndpointCertificateSecrets> endpointCertificateSecrets() { return endpointCertificateSecrets; } @Override public double defaultTermwiseLimit() { return defaultTermwiseLimit; } @@ -133,6 +134,10 @@ public class TestProperties implements ModelContext.Properties, ModelContext.Fea responseSequencerType = type; return this; } + public TestProperties setFirstTimeDeployment(boolean firstTimeDeployment) { + this.firstTimeDeployment = firstTimeDeployment; + return this; + } public TestProperties setResponseNumThreads(int numThreads) { responseNumThreads = numThreads; return this; diff --git a/config-model/src/main/java/com/yahoo/vespa/model/VespaModelFactory.java b/config-model/src/main/java/com/yahoo/vespa/model/VespaModelFactory.java index d6673cd49e9..b576d1cb5d2 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/VespaModelFactory.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/VespaModelFactory.java @@ -6,6 +6,7 @@ import com.google.inject.Inject; import com.yahoo.component.Version; import com.yahoo.component.provider.ComponentRegistry; import com.yahoo.config.application.api.ApplicationPackage; +import com.yahoo.config.application.api.ValidationOverrides; import com.yahoo.config.model.ConfigModelRegistry; import com.yahoo.config.model.MapConfigModelRegistry; import com.yahoo.config.model.NullConfigModelRegistry; @@ -23,6 +24,7 @@ import com.yahoo.config.provision.TransientException; import com.yahoo.config.provision.Zone; import com.yahoo.vespa.config.VespaVersion; import com.yahoo.vespa.model.application.validation.Validation; +import com.yahoo.yolean.Exceptions; import org.xml.sax.SAXException; import java.io.IOException; @@ -31,6 +33,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.logging.Level; import java.util.logging.Logger; /** @@ -170,6 +173,13 @@ public class VespaModelFactory implements ModelFactory { private List<ConfigChangeAction> validateModel(VespaModel model, DeployState deployState, ValidationParameters validationParameters) { try { return Validation.validate(model, validationParameters, deployState); + } catch (ValidationOverrides.ValidationException e) { + if (deployState.isHosted() && zone.environment().isManuallyDeployed()) + deployState.getDeployLogger().logApplicationPackage(Level.WARNING, + "Auto-overriding validation which would be disallowed in production: " + + Exceptions.toMessageString(e)); + else + rethrowUnlessIgnoreErrors(e, validationParameters.ignoreValidationErrors()); } catch (IllegalArgumentException | TransientException e) { rethrowUnlessIgnoreErrors(e, validationParameters.ignoreValidationErrors()); } catch (Exception e) { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java index eccb54780d6..84c7a48a998 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java @@ -25,6 +25,7 @@ import com.yahoo.vespa.model.application.validation.change.ResourcesReductionVal import com.yahoo.vespa.model.application.validation.change.StartupCommandChangeValidator; import com.yahoo.vespa.model.application.validation.change.StreamingSearchClusterChangeValidator; import com.yahoo.vespa.model.application.validation.first.AccessControlOnFirstDeploymentValidator; +import com.yahoo.vespa.model.application.validation.first.RedundancyOnFirstDeploymentValidator; import java.time.Instant; import java.util.Arrays; @@ -54,6 +55,7 @@ public class Validation { * between the previous and current model * * @return a list of required changes needed to make this configuration live + * @throws ValidationOverrides.ValidationException if the change fails validation */ public static List<ConfigChangeAction> validate(VespaModel model, ValidationParameters validationParameters, DeployState deployState) { if (validationParameters.checkRouting()) { @@ -124,6 +126,7 @@ public class Validation { private static void validateFirstTimeDeployment(VespaModel model, DeployState deployState) { new AccessControlOnFirstDeploymentValidator().validate(model, deployState); + new RedundancyOnFirstDeploymentValidator().validate(model, deployState); } private static void deferConfigChangesForClustersToBeRestarted(List<ConfigChangeAction> actions, VespaModel model) { diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ChangeValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ChangeValidator.java index b720cc13f42..4222d22563d 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ChangeValidator.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/change/ChangeValidator.java @@ -25,6 +25,7 @@ public interface ChangeValidator { * @param now the instant to use as now * @return a list of actions specifying what needs to be done in order to activate the new model. * Return an empty list if nothing needs to be done + * @throws IllegalArgumentException if the change fails validation */ List<ConfigChangeAction> validate(VespaModel current, VespaModel next, ValidationOverrides overrides, Instant now); diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/first/RedundancyOnFirstDeploymentValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/first/RedundancyOnFirstDeploymentValidator.java new file mode 100644 index 00000000000..e6117299269 --- /dev/null +++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/first/RedundancyOnFirstDeploymentValidator.java @@ -0,0 +1,44 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.model.application.validation.first; + +import com.yahoo.config.application.api.ValidationId; +import com.yahoo.config.model.ConfigModelContext.ApplicationType; +import com.yahoo.config.model.deploy.DeployState; +import com.yahoo.vespa.model.VespaModel; +import com.yahoo.vespa.model.application.validation.Validator; +import com.yahoo.vespa.model.container.ApplicationContainerCluster; +import com.yahoo.vespa.model.container.Container; +import com.yahoo.vespa.model.container.ContainerCluster; +import com.yahoo.vespa.model.content.cluster.ContentCluster; + +import java.util.ArrayList; +import java.util.List; + +import static com.yahoo.collections.CollectionUtil.mkString; +import static com.yahoo.config.provision.InstanceName.defaultName; +import static com.yahoo.vespa.model.container.http.AccessControl.hasHandlerThatNeedsProtection; + +/** + * Validates that applications in prod zones do not have redundancy 1 (without a validation override). + * + * @author bratseth + */ +public class RedundancyOnFirstDeploymentValidator extends Validator { + + @Override + public void validate(VespaModel model, DeployState deployState) { + if ( ! deployState.isHosted()) return; + if ( ! deployState.zone().environment().isProduction()) return; + + for (ContentCluster cluster : model.getContentClusters().values()) { + if (cluster.redundancy().finalRedundancy() == 1 + && cluster.redundancy().totalNodes() > cluster.redundancy().groups()) + deployState.validationOverrides().invalid(ValidationId.redundancyOne, + cluster + " has redundancy 1, which will cause it to lose data " + + "if a node fails. This requires an override on first deployment " + + "in a production zone", + deployState.now()); + } + } + +} diff --git a/config-model/src/test/java/com/yahoo/config/model/MockModelContext.java b/config-model/src/test/java/com/yahoo/config/model/MockModelContext.java index f8469aa6fa1..59af3193b79 100644 --- a/config-model/src/test/java/com/yahoo/config/model/MockModelContext.java +++ b/config-model/src/test/java/com/yahoo/config/model/MockModelContext.java @@ -20,8 +20,8 @@ import com.yahoo.config.model.test.MockApplicationPackage; import java.util.Optional; /** -* @author hmusum -*/ + * @author hmusum + */ public class MockModelContext implements ModelContext { private final ApplicationPackage applicationPackage; @@ -82,4 +82,5 @@ public class MockModelContext implements ModelContext { public Properties properties() { return new TestProperties(); } + } diff --git a/config-model/src/test/java/com/yahoo/vespa/model/VespaModelFactoryTest.java b/config-model/src/test/java/com/yahoo/vespa/model/VespaModelFactoryTest.java index e3e0edd7896..a3e3a768b05 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/VespaModelFactoryTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/VespaModelFactoryTest.java @@ -19,7 +19,6 @@ import com.yahoo.config.provision.ClusterSpec; import com.yahoo.config.provision.HostSpec; import com.yahoo.config.provision.NodeResources; import com.yahoo.config.provision.ProvisionLogger; -import com.yahoo.vespa.model.builder.xml.dom.NodesSpecification; import org.junit.Before; import org.junit.Test; diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContentTypeRemovalValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContentTypeRemovalValidatorTest.java index c8fdb8348c3..45f3b0fcf60 100644 --- a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContentTypeRemovalValidatorTest.java +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/change/ContentTypeRemovalValidatorTest.java @@ -45,14 +45,6 @@ public class ContentTypeRemovalValidatorTest { tester.deploy(previous, getServices("book"), Environment.prod, removalOverride); // Allowed due to override } - @Test - public void testNoOverrideNeededinDev() { - ValidationTester tester = new ValidationTester(); - - VespaModel previous = tester.deploy(null, getServices("music"), Environment.prod, null).getFirst(); - tester.deploy(previous, getServices("book"), Environment.dev, null); - } - private static String getServices(String documentType) { return "<services version='1.0'>" + " <content id='test' version='1.0'>" + diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/first/RedundancyOnFirstDeploymentValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/first/RedundancyOnFirstDeploymentValidatorTest.java new file mode 100644 index 00000000000..d59b2f7227c --- /dev/null +++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/first/RedundancyOnFirstDeploymentValidatorTest.java @@ -0,0 +1,64 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.model.application.validation.first; + +import com.yahoo.config.application.api.ValidationId; +import com.yahoo.config.application.api.ValidationOverrides; +import com.yahoo.config.model.deploy.TestProperties; +import com.yahoo.config.provision.Environment; +import com.yahoo.vespa.model.application.validation.ValidationTester; +import com.yahoo.yolean.Exceptions; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * @author bratseth + */ +public class RedundancyOnFirstDeploymentValidatorTest { + + private final ValidationTester tester = new ValidationTester(7, false, + new TestProperties().setFirstTimeDeployment(true) + .setHostedVespa(true)); + + @Test + public void testRedundancyOnFirstDeploymentValidation() { + try { + tester.deploy(null, getServices(1), Environment.prod, null); + fail("Expected exception due to redundancy 1"); + } + catch (IllegalArgumentException expected) { + assertEquals("redundancy-one: " + + "content cluster 'contentClusterId' has redundancy 1, which will cause it to lose data if a node fails. " + + "This requires an override on first deployment in a production zone. " + + ValidationOverrides.toAllowMessage(ValidationId.redundancyOne), + Exceptions.toMessageString(expected)); + } + } + + @Test + public void testOverridingRedundancyOnFirstDeploymentValidation() { + tester.deploy(null, getServices(1), Environment.prod, redundancyOneOverride); // Allowed due to override + } + + private static String getServices(int redundancy) { + return "<services version='1.0'>" + + " <content id='contentClusterId' version='1.0'>" + + " <redundancy>" + redundancy + "</redundancy>" + + " <engine>" + + " <proton/>" + + " </engine>" + + " <documents>" + + " <document type='music' mode='index'/>" + + " </documents>" + + " <nodes count='3'/>" + + " </content>" + + "</services>"; + } + + private static final String redundancyOneOverride = + "<validation-overrides>\n" + + " <allow until='2000-01-03'>redundancy-one</allow>\n" + + "</validation-overrides>\n"; + +} diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/ApplicationLockException.java b/config-provisioning/src/main/java/com/yahoo/config/provision/ApplicationLockException.java index e9fe669269c..8f71d4f5061 100644 --- a/config-provisioning/src/main/java/com/yahoo/config/provision/ApplicationLockException.java +++ b/config-provisioning/src/main/java/com/yahoo/config/provision/ApplicationLockException.java @@ -1,4 +1,4 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.config.provision; /** @@ -13,4 +13,8 @@ public class ApplicationLockException extends RuntimeException { super(e); } + public ApplicationLockException(String message) { + super(message); + } + } diff --git a/configd/src/apps/sentinel/connectivity.cpp b/configd/src/apps/sentinel/connectivity.cpp index 9cced1d3475..132b57fc884 100644 --- a/configd/src/apps/sentinel/connectivity.cpp +++ b/configd/src/apps/sentinel/connectivity.cpp @@ -1,5 +1,6 @@ // Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +#include "config-owner.h" #include "connectivity.h" #include "outward-check.h" #include <vespa/defaults.h> @@ -16,19 +17,14 @@ using namespace std::chrono_literals; namespace config::sentinel { -Connectivity::Connectivity(const SentinelConfig::Connectivity & config, RpcServer &rpcServer) - : _config(config), - _rpcServer(rpcServer) -{ - LOG(config, "connectivity.maxBadReverseCount = %d", _config.maxBadReverseCount); - LOG(config, "connectivity.maxBadOutPercent = %d", _config.maxBadOutPercent); -} +constexpr std::chrono::milliseconds MODEL_TIMEOUT_MS = 60s; +Connectivity::Connectivity() = default; Connectivity::~Connectivity() = default; namespace { -const char *toString(CcResult value) { +std::string toString(CcResult value) { switch (value) { case CcResult::UNKNOWN: return "BAD: missing result"; // very very bad case CcResult::REVERSE_FAIL: return "connect OK, but reverse check FAILED"; // very bad @@ -65,16 +61,28 @@ std::map<std::string, std::string> specsFrom(const ModelConfig &model) { } -Connectivity::CheckResult -Connectivity::checkConnectivity(const ModelConfig &model) { - const auto checkSpecs = specsFrom(model); - size_t clusterSize = checkSpecs.size(); +void Connectivity::configure(const SentinelConfig::Connectivity &config) { + _config = config; + LOG(config, "connectivity.maxBadReverseCount = %d", _config.maxBadReverseCount); + LOG(config, "connectivity.maxBadOutPercent = %d", _config.maxBadOutPercent); + if (auto up = ConfigOwner::fetchModelConfig(MODEL_TIMEOUT_MS)) { + _checkSpecs = specsFrom(*up); + } +} + +bool +Connectivity::checkConnectivity(RpcServer &rpcServer) { + size_t clusterSize = _checkSpecs.size(); + if (clusterSize == 0) { + LOG(warning, "could not get model config, skipping connectivity checks"); + return true; + } OutwardCheckContext checkContext(clusterSize, vespa::Defaults::vespaHostname(), - _rpcServer.getPort(), - _rpcServer.orb()); + rpcServer.getPort(), + rpcServer.orb()); std::map<std::string, OutwardCheck> connectivityMap; - for (const auto & [ hn, spec ] : checkSpecs) { + for (const auto & [ hn, spec ] : _checkSpecs) { connectivityMap.try_emplace(hn, spec, checkContext); } checkContext.latch.await(); @@ -82,6 +90,12 @@ Connectivity::checkConnectivity(const ModelConfig &model) { size_t numFailedReverse = 0; bool allChecksOk = true; for (const auto & [hostname, check] : connectivityMap) { + std::string detail = toString(check.result()); + std::string prev = _detailsPerHost[hostname]; + if (prev != detail) { + LOG(info, "Connectivity check details: %s -> %s", hostname.c_str(), detail.c_str()); + } + _detailsPerHost[hostname] = detail; LOG_ASSERT(check.result() != CcResult::UNKNOWN); if (check.result() == CcResult::CONN_FAIL) ++numFailedConns; if (check.result() == CcResult::REVERSE_FAIL) ++numFailedReverse; @@ -97,16 +111,12 @@ Connectivity::checkConnectivity(const ModelConfig &model) { numFailedConns, clusterSize, pct, _config.maxBadOutPercent); allChecksOk = false; } - std::vector<std::string> details; - for (const auto & [hostname, check] : connectivityMap) { - std::string detail = fmt("%s -> %s", hostname.c_str(), toString(check.result())); - details.push_back(detail); + if (allChecksOk && (numFailedConns == 0) && (numFailedReverse == 0)) { + LOG(info, "All connectivity checks OK, proceeding with service startup"); + } else if (allChecksOk) { + LOG(info, "Enough connectivity checks OK, proceeding with service startup"); } - CheckResult result{false, false, {}}; - result.enoughOk = allChecksOk; - result.allOk = (numFailedConns == 0) && (numFailedReverse == 0); - result.details = std::move(details); - return result; + return allChecksOk; } } diff --git a/configd/src/apps/sentinel/connectivity.h b/configd/src/apps/sentinel/connectivity.h index 0e32b5243e0..1c7ee8ddc57 100644 --- a/configd/src/apps/sentinel/connectivity.h +++ b/configd/src/apps/sentinel/connectivity.h @@ -6,7 +6,7 @@ #include <vespa/config-sentinel.h> #include <vespa/config-model.h> #include <string> -#include <vector> +#include <map> using cloud::config::SentinelConfig; using cloud::config::ModelConfig; @@ -18,19 +18,14 @@ namespace config::sentinel { **/ class Connectivity { public: - Connectivity(const SentinelConfig::Connectivity & config, RpcServer &rpcServer); + Connectivity(); ~Connectivity(); - - struct CheckResult { - bool enoughOk; - bool allOk; - std::vector<std::string> details; - }; - - CheckResult checkConnectivity(const ModelConfig &model); + void configure(const SentinelConfig::Connectivity &config); + bool checkConnectivity(RpcServer &rpcServer); private: - const SentinelConfig::Connectivity _config; - RpcServer &_rpcServer; + SentinelConfig::Connectivity _config; + std::map<std::string, std::string> _checkSpecs; + std::map<std::string, std::string> _detailsPerHost; }; } diff --git a/configd/src/apps/sentinel/env.cpp b/configd/src/apps/sentinel/env.cpp index e4174ee450d..5bbbfd8f0bd 100644 --- a/configd/src/apps/sentinel/env.cpp +++ b/configd/src/apps/sentinel/env.cpp @@ -2,11 +2,12 @@ #include "env.h" #include "check-completion-handler.h" -#include "outward-check.h" +#include "connectivity.h" #include <vespa/defaults.h> #include <vespa/log/log.h> #include <vespa/config/common/exceptions.h> #include <vespa/vespalib/util/exceptions.h> +#include <vespa/vespalib/util/signalhandler.h> #include <vespa/vespalib/util/stringfmt.h> #include <thread> #include <chrono> @@ -18,8 +19,20 @@ using namespace std::chrono_literals; namespace config::sentinel { +namespace { + +void maybeStopNow() { + if (vespalib::SignalHandler::INT.check() || + vespalib::SignalHandler::TERM.check()) + { + throw vespalib::FatalException("got signal during boot()"); + } +} + constexpr std::chrono::milliseconds CONFIG_TIMEOUT_MS = 3min; -constexpr std::chrono::milliseconds MODEL_TIMEOUT_MS = 1500ms; +constexpr int maxConnectivityRetries = 100; + +} // namespace <unnamed> Env::Env() : _cfgOwner(), @@ -31,6 +44,7 @@ Env::Env() _statePort(0) { _startMetrics.startedTime = vespalib::steady_clock::now(); + _stateApi.myHealth.setFailed("initializing..."); } Env::~Env() = default; @@ -38,17 +52,36 @@ Env::~Env() = default; void Env::boot(const std::string &configId) { LOG(debug, "Reading configuration for ID: %s", configId.c_str()); _cfgOwner.subscribe(configId, CONFIG_TIMEOUT_MS); - bool ok = _cfgOwner.checkForConfigUpdate(); // subscribe() should throw if something is not OK - LOG_ASSERT(ok && _cfgOwner.hasConfig()); - const auto & cfg = _cfgOwner.getConfig(); - LOG(config, "Booting sentinel '%s' with [stateserver port %d] and [rpc port %d]", - configId.c_str(), cfg.port.telnet, cfg.port.rpc); - rpcPort(cfg.port.rpc); - statePort(cfg.port.telnet); - if (auto up = ConfigOwner::fetchModelConfig(MODEL_TIMEOUT_MS)) { - waitForConnectivity(*up); + Connectivity checker; + for (int retry = 0; retry < maxConnectivityRetries; ++retry) { + bool changed = _cfgOwner.checkForConfigUpdate(); + LOG_ASSERT(changed || retry > 0); + if (changed) { + LOG_ASSERT(_cfgOwner.hasConfig()); + const auto & cfg = _cfgOwner.getConfig(); + LOG(config, "Booting sentinel '%s' with [stateserver port %d] and [rpc port %d]", + configId.c_str(), cfg.port.telnet, cfg.port.rpc); + rpcPort(cfg.port.rpc); + statePort(cfg.port.telnet); + checker.configure(cfg.connectivity); + } + if (checker.checkConnectivity(*_rpcServer)) { + _stateApi.myHealth.setOk(); + return; + } else { + _stateApi.myHealth.setFailed("FAILED connectivity check"); + if ((retry % 10) == 0) { + LOG(warning, "Bad network connectivity (try %d)", 1+retry); + } + for (int i = 0; i < 5; ++i) { + respondAsEmpty(); + maybeStopNow(); + std::this_thread::sleep_for(600ms); + } + } } + throw vespalib::FatalException("Giving up - too many connectivity check failures"); } void Env::rpcPort(int port) { @@ -93,60 +126,4 @@ void Env::respondAsEmpty() { } } -namespace { - -const char *toString(CcResult value) { - switch (value) { - case CcResult::UNKNOWN: return "unknown"; - case CcResult::CONN_FAIL: return "failed to connect"; - case CcResult::REVERSE_FAIL: return "connect OK, but reverse check FAILED"; - case CcResult::REVERSE_UNAVAIL: return "connect OK, but reverse check unavailable"; - case CcResult::ALL_OK: return "both ways connectivity OK"; - } - LOG(error, "Unknown CcResult enum value: %d", (int)value); - LOG_ABORT("Unknown CcResult enum value"); -} - -std::map<std::string, std::string> specsFrom(const ModelConfig &model) { - std::map<std::string, std::string> checkSpecs; - for (const auto & h : model.hosts) { - bool foundSentinelPort = false; - for (const auto & s : h.services) { - if (s.name == "config-sentinel") { - for (const auto & p : s.ports) { - if (p.tags.find("rpc") != p.tags.npos) { - auto spec = fmt("tcp/%s:%d", h.name.c_str(), p.number); - checkSpecs[h.name] = spec; - foundSentinelPort = true; - } - } - } - } - if (! foundSentinelPort) { - LOG(warning, "Did not find 'config-sentinel' RPC port in model for host %s [%zd services]", - h.name.c_str(), h.services.size()); - } - } - return checkSpecs; -} - -} - -void Env::waitForConnectivity(const ModelConfig &model) { - auto checkSpecs = specsFrom(model); - OutwardCheckContext checkContext(checkSpecs.size(), - vespa::Defaults::vespaHostname(), - _rpcServer->getPort(), - _rpcServer->orb()); - std::map<std::string, OutwardCheck> connectivityMap; - for (const auto & [ hn, spec ] : checkSpecs) { - connectivityMap.try_emplace(hn, spec, checkContext); - } - checkContext.latch.await(); - for (const auto & [hostname, check] : connectivityMap) { - LOG(info, "outward check status for host %s is: %s", - hostname.c_str(), toString(check.result())); - } -} - } diff --git a/configd/src/apps/sentinel/env.h b/configd/src/apps/sentinel/env.h index f117854f006..f71fb537068 100644 --- a/configd/src/apps/sentinel/env.h +++ b/configd/src/apps/sentinel/env.h @@ -32,7 +32,6 @@ public: void notifyConfigUpdated(); private: void respondAsEmpty(); - void waitForConnectivity(const ModelConfig &model); ConfigOwner _cfgOwner; CommandQueue _rpcCommandQueue; std::unique_ptr<RpcServer> _rpcServer; diff --git a/configd/src/apps/sentinel/sentinel.cpp b/configd/src/apps/sentinel/sentinel.cpp index 7f3ddcc5882..ebed1549106 100644 --- a/configd/src/apps/sentinel/sentinel.cpp +++ b/configd/src/apps/sentinel/sentinel.cpp @@ -63,16 +63,20 @@ main(int argc, char **argv) LOG(debug, "Reading configuration"); try { environment.boot(configId); + } catch (vespalib::FatalException& ex) { + LOG(error, "Stopping before boot complete: %s", ex.message()); + EV_STOPPING("config-sentinel", ex.message()); + return EXIT_FAILURE; } catch (ConfigTimeoutException & ex) { - LOG(warning, "Timeout getting config, please check your setup. Will exit and restart: %s", ex.getMessage().c_str()); - EV_STOPPING("config-sentinel", ex.what()); + LOG(warning, "Timeout getting config, please check your setup. Will exit and restart: %s", ex.message()); + EV_STOPPING("config-sentinel", ex.message()); return EXIT_FAILURE; } catch (InvalidConfigException& ex) { - LOG(error, "Fatal: Invalid configuration, please check your setup: %s", ex.getMessage().c_str()); - EV_STOPPING("config-sentinel", ex.what()); + LOG(error, "Fatal: Invalid configuration, please check your setup: %s", ex.message()); + EV_STOPPING("config-sentinel", ex.message()); return EXIT_FAILURE; } catch (ConfigRuntimeException& ex) { - LOG(error, "Fatal: Could not get config, please check your setup: %s", ex.getMessage().c_str()); + LOG(error, "Fatal: Could not get config, please check your setup: %s", ex.message()); EV_STOPPING("config-sentinel", ex.what()); return EXIT_FAILURE; } @@ -84,13 +88,13 @@ main(int argc, char **argv) vespalib::SignalHandler::CHLD.clear(); manager.doWork(); // Check for child procs & commands } catch (InvalidConfigException& ex) { - LOG(warning, "Configuration problem: (ignoring): %s", ex.what()); + LOG(warning, "Configuration problem: (ignoring): %s", ex.message()); } catch (vespalib::PortListenException& ex) { - LOG(error, "Fatal: %s", ex.getMessage().c_str()); + LOG(error, "Fatal: %s", ex.message()); EV_STOPPING("config-sentinel", ex.what()); return EXIT_FAILURE; } catch (vespalib::FatalException& ex) { - LOG(error, "Fatal: %s", ex.getMessage().c_str()); + LOG(error, "Fatal: %s", ex.message()); EV_STOPPING("config-sentinel", ex.what()); return EXIT_FAILURE; } 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 2d4aa78bcf6..4c25708dca2 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 @@ -208,10 +208,11 @@ public abstract class ModelsBuilder<MODELRESULT extends ModelResult> { builtModelVersions.add(modelVersion); } catch (RuntimeException e) { // allow failure to create old config models if there is a validation override that allow skipping old - // config models (which is always true for manually deployed zones) - if (builtModelVersions.size() > 0 && builtModelVersions.get(0).getModel().skipOldConfigModels(now)) + // config models or we're manually deploying + if (builtModelVersions.size() > 0 && + ( builtModelVersions.get(0).getModel().skipOldConfigModels(now) || zone().environment().isManuallyDeployed())) log.log(Level.INFO, applicationId + ": Failed to build version " + version + - ", but allow failure due to validation override ´skipOldConfigModels´"); + ", but allow failure due to validation override or manual deployment"); else { log.log(Level.SEVERE, applicationId + ": Failed to build version " + version); throw e; diff --git a/configserver/src/test/apps/app_sdbundles/services.xml b/configserver/src/test/apps/app_sdbundles/services.xml index f1eabb7d1ef..29c736fb41b 100644 --- a/configserver/src/test/apps/app_sdbundles/services.xml +++ b/configserver/src/test/apps/app_sdbundles/services.xml @@ -11,7 +11,7 @@ </admin> <content version="1.0"> - <redundancy>1</redundancy> + <redundancy>2</redundancy> <documents> <document type="music" mode="index"/> </documents> diff --git a/configserver/src/test/apps/hosted-no-write-access-control/services.xml b/configserver/src/test/apps/hosted-no-write-access-control/services.xml index b12f630ef80..429995c03a4 100644 --- a/configserver/src/test/apps/hosted-no-write-access-control/services.xml +++ b/configserver/src/test/apps/hosted-no-write-access-control/services.xml @@ -15,7 +15,7 @@ </container> <content id="music" version="1.0"> - <redundancy>1</redundancy> + <redundancy>2</redundancy> <documents> <document type="music" mode="index" /> </documents> diff --git a/configserver/src/test/apps/hosted/services.xml b/configserver/src/test/apps/hosted/services.xml index a5c8fa1d26f..456a41c6994 100644 --- a/configserver/src/test/apps/hosted/services.xml +++ b/configserver/src/test/apps/hosted/services.xml @@ -18,7 +18,7 @@ </container> <content id="music" version="1.0"> - <redundancy>1</redundancy> + <redundancy>2</redundancy> <documents> <document type="music" mode="index" /> </documents> diff --git a/configserver/src/test/apps/zkapp/services.xml b/configserver/src/test/apps/zkapp/services.xml index 58ecf41707d..037c8e75677 100644 --- a/configserver/src/test/apps/zkapp/services.xml +++ b/configserver/src/test/apps/zkapp/services.xml @@ -19,7 +19,7 @@ </container> <content version="1.0"> - <redundancy>1</redundancy> + <redundancy>2</redundancy> <documents> <document type="music" mode="index"/> </documents> diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java index f2722fb49e1..cca26cbb4f1 100644 --- a/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java +++ b/configserver/src/test/java/com/yahoo/vespa/config/server/deploy/DeployTester.java @@ -209,7 +209,7 @@ public class DeployTester { @Override public ModelCreateResult createAndValidateModel(ModelContext modelContext, ValidationParameters validationParameters) { if ( ! validationParameters.ignoreValidationErrors()) - throw new IllegalArgumentException("Validation fails"); + throw new IllegalArgumentException("Model building fails"); return new ModelCreateResult(createModel(modelContext), Collections.emptyList()); } diff --git a/configserver/src/test/resources/deploy/advancedapp/services.xml b/configserver/src/test/resources/deploy/advancedapp/services.xml index b8e93b14317..77fa426041f 100644 --- a/configserver/src/test/resources/deploy/advancedapp/services.xml +++ b/configserver/src/test/resources/deploy/advancedapp/services.xml @@ -18,7 +18,7 @@ </container> <content version="1.0"> - <redundancy>1</redundancy> + <redundancy>2</redundancy> <documents> <document type="keyvalue" mode="index"/> </documents> diff --git a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java index 4ad39f91a83..ad682273d0d 100644 --- a/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java +++ b/container-core/src/main/java/com/yahoo/jdisc/http/server/jetty/ConnectorFactory.java @@ -75,7 +75,7 @@ public class ConnectorFactory { connector.setName(connectorConfig.name()); connector.setAcceptQueueSize(connectorConfig.acceptQueueSize()); connector.setReuseAddress(connectorConfig.reuseAddress()); - connector.setIdleTimeout(toMillis(connector.getIdleTimeout())); + connector.setIdleTimeout(toMillis(connectorConfig.idleTimeout())); return connector; } diff --git a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java index 9904ef77513..136f64abec6 100644 --- a/flags/src/main/java/com/yahoo/vespa/flags/Flags.java +++ b/flags/src/main/java/com/yahoo/vespa/flags/Flags.java @@ -268,7 +268,7 @@ public class Flags { public static final UnboundBooleanFlag THROW_EXCEPTION_IF_RESOURCE_LIMITS_SPECIFIED = defineFeatureFlag( "throw-exception-if-resource-limits-specified", false, - List.of("mpolden"), "2021-06-07", "2021-07-07", + List.of("hmusum"), "2021-06-07", "2021-08-07", "Whether to throw an exception in hosted Vespa if the application specifies resource limits in services.xml", "Takes effect on next deployment through controller", APPLICATION_ID); diff --git a/fnet/src/vespa/fnet/frt/supervisor.cpp b/fnet/src/vespa/fnet/frt/supervisor.cpp index 388d754ece4..d992567f776 100644 --- a/fnet/src/vespa/fnet/frt/supervisor.cpp +++ b/fnet/src/vespa/fnet/frt/supervisor.cpp @@ -430,4 +430,8 @@ StandaloneFRT::~StandaloneFRT() _transport->ShutDown(true); } +void StandaloneFRT::shutdown() { + _transport->ShutDown(true); +} + } diff --git a/fnet/src/vespa/fnet/frt/supervisor.h b/fnet/src/vespa/fnet/frt/supervisor.h index 1332bbe3ddb..2743cafae26 100644 --- a/fnet/src/vespa/fnet/frt/supervisor.h +++ b/fnet/src/vespa/fnet/frt/supervisor.h @@ -133,6 +133,7 @@ public: explicit StandaloneFRT(std::shared_ptr<vespalib::CryptoEngine> crypto); ~StandaloneFRT(); FRT_Supervisor & supervisor() { return *_supervisor; } + void shutdown(); private: std::unique_ptr<FastOS_ThreadPool> _threadPool; std::unique_ptr<FNET_Transport> _transport; diff --git a/model-integration/src/test/java/ai/vespa/modelintegration/evaluator/OnnxEvaluatorTest.java b/model-integration/src/test/java/ai/vespa/modelintegration/evaluator/OnnxEvaluatorTest.java index 4b42e18d75e..a7186aae5fe 100644 --- a/model-integration/src/test/java/ai/vespa/modelintegration/evaluator/OnnxEvaluatorTest.java +++ b/model-integration/src/test/java/ai/vespa/modelintegration/evaluator/OnnxEvaluatorTest.java @@ -74,7 +74,7 @@ public class OnnxEvaluatorTest { assertEvaluate("cast_int8_float.onnx", "tensor<float>(d0[1]):[-128]", "tensor<int8>(d0[1]):[128]"); assertEvaluate("cast_float_int8.onnx", "tensor<int8>(d0[1]):[-1]", "tensor<float>(d0[1]):[255]"); - // ONNX Runtime 1.7.0 does not support much of bfloat16 yet + // ONNX Runtime 1.8.0 does not support much of bfloat16 yet // assertEvaluate("cast_bfloat16_float.onnx", "tensor<float>(d0[1]):[1]", "tensor<bfloat16>(d0[1]):[1]"); } diff --git a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/NodeReports.java b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/NodeReports.java index 70ce548916a..ad9ce84f590 100644 --- a/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/NodeReports.java +++ b/node-admin/src/main/java/com/yahoo/vespa/hosted/node/admin/configserver/noderepository/NodeReports.java @@ -42,6 +42,8 @@ public class NodeReports { reports.put(reportId, jsonNode); } + public boolean hasReport(String reportId) { return reports.containsKey(reportId); } + public <T> Optional<T> getReport(String reportId, Class<T> jacksonClass) { return Optional.ofNullable(reports.get(reportId)).map(r -> uncheck(() -> mapper.treeToValue(r, jacksonClass))); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/Applications.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/Applications.java index ccd5af1cb64..fe363bf3786 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/Applications.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/applications/Applications.java @@ -2,8 +2,8 @@ package com.yahoo.vespa.hosted.provision.applications; import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.ApplicationLockException; import com.yahoo.config.provision.ApplicationTransaction; -import com.yahoo.config.provision.ProvisionLock; import com.yahoo.transaction.Mutex; import com.yahoo.transaction.NestedTransaction; import com.yahoo.vespa.hosted.provision.persistence.CuratorDatabaseClient; @@ -28,6 +28,8 @@ public class Applications { for (ApplicationId id : ids()) { try (Mutex lock = db.lock(id)) { get(id).ifPresent(application -> put(application, lock)); + } catch (ApplicationLockException e) { + throw new ApplicationLockException(e.getMessage()); // No need for stack trace here } } } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java index 3afe5824af5..ec1bfba6996 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/node/Nodes.java @@ -161,6 +161,14 @@ public class Nodes { node = node.with(node.status().withFailCount(existing.get().status().failCount())); if (existing.get().status().firmwareVerifiedAt().isPresent()) node = node.with(node.status().withFirmwareVerifiedAt(existing.get().status().firmwareVerifiedAt().get())); + // Preserve wantToRebuild/wantToRetire when rebuilding as the fields shouldn't be cleared until the + // host is readied (i.e. we know it is up and rebuild completed) + boolean rebuilding = existing.get().status().wantToRebuild(); + if (rebuilding) { + node = node.with(node.status().withWantToRetire(existing.get().status().wantToRetire(), + false, + rebuilding)); + } nodesToRemove.add(existing.get()); } diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java index fb4799be29c..364af6308a1 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/persistence/CuratorDatabaseClient.java @@ -71,7 +71,7 @@ public class CuratorDatabaseClient { private static final Path firmwareCheckPath = root.append("firmwareCheck"); private static final Path archiveUrisPath = root.append("archiveUris"); - private static final Duration defaultLockTimeout = Duration.ofMinutes(6); + private static final Duration defaultLockTimeout = Duration.ofMinutes(10); private final NodeSerializer nodeSerializer; private final CuratorDatabase db; diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTest.java index 351f9fe44ee..4bfe01375c1 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/NodeRepositoryTest.java @@ -197,8 +197,16 @@ public class NodeRepositoryTest { } tester.nodeRepository().nodes().removeRecursively("host1"); + // Set host 2 properties and deprovision it + try (var lock = tester.nodeRepository().nodes().lockAndGetRequired("host2")) { + Node host2 = lock.node().withWantToRetire(true, false, true, Agent.system, tester.nodeRepository().clock().instant()); + tester.nodeRepository().nodes().write(host2, lock); + } + tester.nodeRepository().nodes().removeRecursively("host2"); + // Host 1 is deprovisioned and unwanted properties are cleared Node host1 = tester.nodeRepository().nodes().node("host1").get(); + Node host2 = tester.nodeRepository().nodes().node("host2").get(); assertEquals(Node.State.deprovisioned, host1.state()); assertTrue(host1.history().hasEventAfter(History.Event.Type.deprovisioned, testStart)); @@ -214,6 +222,8 @@ public class NodeRepositoryTest { assertTrue("Transferred from deprovisioned host", host1.status().firmwareVerifiedAt().isPresent()); assertEquals("Transferred from deprovisioned host", 1, host1.status().failCount()); assertEquals("Transferred from deprovisioned host", 1, host1.reports().getReports().size()); + assertTrue("Transferred from rebuilt host", host2.status().wantToRetire()); + assertTrue("Transferred from rebuilt host", host2.status().wantToRebuild()); } @Test diff --git a/parent/pom.xml b/parent/pom.xml index 6f1d6f23f51..2a763dcc6ac 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -885,7 +885,7 @@ <maven-site-plugin.version>3.3</maven-site-plugin.version> <maven-source-plugin.version>3.0.1</maven-source-plugin.version> <prometheus.client.version>0.6.0</prometheus.client.version> - <onnxruntime.version>1.7.0</onnxruntime.version> + <onnxruntime.version>1.8.0</onnxruntime.version> <protobuf.version>3.11.4</protobuf.version> <spifly.version>1.3.3</spifly.version> <surefire.version>2.22.0</surefire.version> diff --git a/slobrok/src/tests/registerapi/registerapi.cpp b/slobrok/src/tests/registerapi/registerapi.cpp index 59bc4690985..696812e2a3d 100644 --- a/slobrok/src/tests/registerapi/registerapi.cpp +++ b/slobrok/src/tests/registerapi/registerapi.cpp @@ -6,6 +6,7 @@ #include <vespa/slobrok/sbregister.h> #include <vespa/slobrok/server/slobrokserver.h> #include <vespa/fnet/frt/supervisor.h> +#include <vespa/fnet/transport.h> #include <sstream> #include <algorithm> #include <thread> @@ -217,5 +218,6 @@ Test::Main() .add("F/y/w", myspec.c_str()))); mock.stop(); + server.shutdown(); TEST_DONE(); } diff --git a/vespalib/src/vespa/vespalib/util/exception.h b/vespalib/src/vespa/vespalib/util/exception.h index 097ecc131c7..6fb53c035eb 100644 --- a/vespalib/src/vespa/vespalib/util/exception.h +++ b/vespalib/src/vespa/vespalib/util/exception.h @@ -216,6 +216,9 @@ public: /** @brief Returns the msg parameter that this Exception was constructed with */ const string &getMessage() const { return _msg; } + /** @brief Returns the message string */ + const char *message() const { return _msg.c_str(); } + /** @brief Returns the location parameter that this Exception was constructed with */ const string &getLocation() const { return _location; } |