summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Eriksen <andreer@verizonmedia.com>2019-06-27 10:25:51 +0200
committerGitHub <noreply@github.com>2019-06-27 10:25:51 +0200
commit70a894e986198368909f4d3ad39678224df1567c (patch)
treeb07993bf21612f94170c216b6fbe13a4cc96def3
parent835688ddc6f02b256dfe12a31b57d761ce66c234 (diff)
parent6b330dbe13745eed26c60cab48b6121527266f7c (diff)
Merge pull request #9885 from vespa-engine/andreer/retry-deploy-on-missing-certificate
retry deployment on missing certificate
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/TlsSecretsValidator.java17
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/application/validation/Validation.java1
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/application/validation/TlsSecretsValidatorTest.java88
-rw-r--r--config-provisioning/abi-spec.json11
-rw-r--r--config-provisioning/src/main/java/com/yahoo/config/provision/CertificateNotReadyException.java17
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/HttpErrorResponse.java7
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/HttpHandler.java3
7 files changed, 143 insertions, 1 deletions
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/application/validation/TlsSecretsValidator.java b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/TlsSecretsValidator.java
new file mode 100644
index 00000000000..1018099cf05
--- /dev/null
+++ b/config-model/src/main/java/com/yahoo/vespa/model/application/validation/TlsSecretsValidator.java
@@ -0,0 +1,17 @@
+package com.yahoo.vespa.model.application.validation;
+
+import com.yahoo.config.model.api.TlsSecrets;
+import com.yahoo.config.model.deploy.DeployState;
+import com.yahoo.config.provision.CertificateNotReadyException;
+import com.yahoo.vespa.model.VespaModel;
+
+public class TlsSecretsValidator extends Validator {
+
+ /** This check is delayed until validation to allow node provisioning to complete while we are waiting for cert */
+ @Override
+ public void validate(VespaModel model, DeployState deployState) {
+ if (deployState.tlsSecrets().isPresent() && deployState.tlsSecrets().get() == TlsSecrets.MISSING) {
+ throw new CertificateNotReadyException("TLS enabled, but could not retrieve certificate yet");
+ }
+ }
+}
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 e44acf61466..042c7cc867c 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
@@ -56,6 +56,7 @@ public class Validation {
new DeploymentFileValidator().validate(model, deployState);
new RankingConstantsValidator().validate(model, deployState);
new SecretStoreValidator().validate(model, deployState);
+ new TlsSecretsValidator().validate(model, deployState);
List<ConfigChangeAction> result = Collections.emptyList();
if (deployState.getProperties().isFirstTimeDeployment()) {
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/application/validation/TlsSecretsValidatorTest.java b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/TlsSecretsValidatorTest.java
new file mode 100644
index 00000000000..cdb4ce955e2
--- /dev/null
+++ b/config-model/src/test/java/com/yahoo/vespa/model/application/validation/TlsSecretsValidatorTest.java
@@ -0,0 +1,88 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.model.application.validation;
+
+import com.yahoo.config.application.api.ApplicationPackage;
+import com.yahoo.config.model.NullConfigModelRegistry;
+import com.yahoo.config.model.api.TlsSecrets;
+import com.yahoo.config.model.deploy.DeployState;
+import com.yahoo.config.model.deploy.TestProperties;
+import com.yahoo.config.model.test.MockApplicationPackage;
+import com.yahoo.config.provision.CertificateNotReadyException;
+import com.yahoo.config.provision.Environment;
+import com.yahoo.config.provision.RegionName;
+import com.yahoo.config.provision.Zone;
+import com.yahoo.vespa.model.VespaModel;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import java.util.Optional;
+
+import static com.yahoo.config.model.test.TestUtil.joinLines;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author andreer
+ */
+public class TlsSecretsValidatorTest {
+ @Rule
+ public final ExpectedException exceptionRule = ExpectedException.none();
+
+ private static String servicesXml() {
+ return joinLines("<services version='1.0'>",
+ " <container id='default' version='1.0'>",
+ " </container>",
+ "</services>");
+ }
+
+ private static String deploymentXml() {
+ return joinLines("<deployment version='1.0' >",
+ " <prod />",
+ "</deployment>");
+ }
+
+ @Test
+ public void missing_certificate_fails_validation() throws Exception {
+ DeployState deployState = deployState(servicesXml(), deploymentXml(), Optional.of(TlsSecrets.MISSING));
+ VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState);
+
+ exceptionRule.expect(CertificateNotReadyException.class);
+ exceptionRule.expectMessage("TLS enabled, but could not retrieve certificate yet");
+
+ new TlsSecretsValidator().validate(model, deployState);
+ }
+
+ @Test
+ public void validation_succeeds_with_certificate() throws Exception {
+ DeployState deployState = deployState(servicesXml(), deploymentXml(), Optional.of(new TlsSecrets("cert", "key")));
+ VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState);
+
+ new TlsSecretsValidator().validate(model, deployState);
+ }
+
+ @Test
+ public void validation_succeeds_without_certificate() throws Exception {
+ DeployState deployState = deployState(servicesXml(), deploymentXml(), Optional.empty());
+ VespaModel model = new VespaModel(new NullConfigModelRegistry(), deployState);
+
+ new TlsSecretsValidator().validate(model, deployState);
+ }
+
+ private static DeployState deployState(String servicesXml, String deploymentXml, Optional<TlsSecrets> tlsSecrets) {
+ ApplicationPackage app = new MockApplicationPackage.Builder()
+ .withServices(servicesXml)
+ .withDeploymentSpec(deploymentXml)
+ .build();
+ DeployState.Builder builder = new DeployState.Builder()
+ .applicationPackage(app)
+ .zone(new Zone(Environment.prod, RegionName.from("foo")))
+ .properties(
+ new TestProperties()
+ .setHostedVespa(true)
+ .setTlsSecrets(tlsSecrets));
+ final DeployState deployState = builder.build();
+
+ assertTrue("Test must emulate a hosted deployment.", deployState.isHosted());
+ return deployState;
+ }
+}
diff --git a/config-provisioning/abi-spec.json b/config-provisioning/abi-spec.json
index ffeb5dce112..a9b45fe6bb4 100644
--- a/config-provisioning/abi-spec.json
+++ b/config-provisioning/abi-spec.json
@@ -149,6 +149,17 @@
],
"fields": []
},
+ "com.yahoo.config.provision.CertificateNotReadyException": {
+ "superClass": "com.yahoo.config.provision.TransientException",
+ "interfaces": [],
+ "attributes": [
+ "public"
+ ],
+ "methods": [
+ "public void <init>(java.lang.String)"
+ ],
+ "fields": []
+ },
"com.yahoo.config.provision.CloudName": {
"superClass": "java.lang.Object",
"interfaces": [
diff --git a/config-provisioning/src/main/java/com/yahoo/config/provision/CertificateNotReadyException.java b/config-provisioning/src/main/java/com/yahoo/config/provision/CertificateNotReadyException.java
new file mode 100644
index 00000000000..0d88a7aa435
--- /dev/null
+++ b/config-provisioning/src/main/java/com/yahoo/config/provision/CertificateNotReadyException.java
@@ -0,0 +1,17 @@
+// Copyright 2019 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.config.provision;
+
+/**
+ * Exception thrown when trying to validate an application which is configured
+ * with a certificate that is not yet retrievable
+ *
+ * @author andreer
+ *
+ */
+public class CertificateNotReadyException extends TransientException {
+
+ public CertificateNotReadyException(String message) {
+ super(message);
+ }
+
+}
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/HttpErrorResponse.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/HttpErrorResponse.java
index a29891ae764..3d2ecd4a2ca 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/HttpErrorResponse.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/HttpErrorResponse.java
@@ -48,7 +48,8 @@ public class HttpErrorResponse extends HttpResponse {
OUT_OF_CAPACITY,
REQUEST_TIMEOUT,
UNKNOWN_VESPA_VERSION,
- PARENT_HOST_NOT_READY
+ PARENT_HOST_NOT_READY,
+ CERTIFICATE_NOT_READY
}
public static HttpErrorResponse notFoundError(String msg) {
@@ -95,6 +96,10 @@ public class HttpErrorResponse extends HttpResponse {
return new HttpErrorResponse(CONFLICT, errorCodes.PARENT_HOST_NOT_READY.name(), msg);
}
+ public static HttpErrorResponse certificateNotReady(String msg) {
+ return new HttpErrorResponse(CONFLICT, errorCodes.CERTIFICATE_NOT_READY.name(), msg);
+ }
+
@Override
public void render(OutputStream stream) throws IOException {
new JsonFormat(true).encode(stream, slime);
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/HttpHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/HttpHandler.java
index cd2052653ed..20ee77be9fe 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/HttpHandler.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/HttpHandler.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.config.server.http;
import com.yahoo.config.provision.ApplicationLockException;
+import com.yahoo.config.provision.CertificateNotReadyException;
import com.yahoo.config.provision.ParentHostUnavailableException;
import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.container.jdisc.HttpResponse;
@@ -64,6 +65,8 @@ public class HttpHandler extends LoggingRequestHandler {
return HttpErrorResponse.applicationLockFailure(getMessage(e, request));
} catch (ParentHostUnavailableException e) {
return HttpErrorResponse.parentHostNotReady(getMessage(e, request));
+ } catch (CertificateNotReadyException e) {
+ return HttpErrorResponse.certificateNotReady(getMessage(e, request));
} catch (Exception e) {
log.log(LogLevel.WARNING, "Unexpected exception handling a config server request", e);
return HttpErrorResponse.internalServerError(getMessage(e, request));