summaryrefslogtreecommitdiffstats
path: root/configserver
diff options
context:
space:
mode:
authorHenning Baldersheim <balder@yahoo-inc.com>2023-03-07 13:39:11 +0100
committerGitHub <noreply@github.com>2023-03-07 13:39:11 +0100
commit251964b9450ed3eadbb9e95be4a52431a22b4df3 (patch)
treef686846078d811a3a8dc9ab2fc6aba1b7e4389e2 /configserver
parentc1285a18fc5629e4ded7d189401cb0fea5a646b7 (diff)
parentc49fb0a11c12fad7d87a1d949e1c128767922c61 (diff)
Merge pull request #26336 from vespa-engine/hmusum/add-property-requiredGeneration-to-config-requests
Add request property requiredGeneration to http get config requests
Diffstat (limited to 'configserver')
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/HttpConfigRequest.java33
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/HttpErrorResponse.java8
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/HttpHandler.java2
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/NotFoundException.java1
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/PreconditionFailedException.java16
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/HttpGetConfigHandler.java14
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/HttpGetConfigHandlerTest.java15
7 files changed, 73 insertions, 16 deletions
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/HttpConfigRequest.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/HttpConfigRequest.java
index 3baa57b2b01..e043afdbf43 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/HttpConfigRequest.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/HttpConfigRequest.java
@@ -30,15 +30,18 @@ import java.util.Set;
*/
public class HttpConfigRequest implements GetConfigRequest, TenantRequest {
- private static final String HTTP_PROPERTY_NOCACHE = "noCache";
+ private static final String NOCACHE = "noCache";
+ private static final String REQUIRED_GENERATION = "requiredGeneration";
private final ConfigKey<?> key;
private final ApplicationId appId;
private final boolean noCache;
+ private final Optional<Long> requiredGeneration;
- private HttpConfigRequest(ConfigKey<?> key, ApplicationId appId, boolean noCache) {
+ private HttpConfigRequest(ConfigKey<?> key, ApplicationId appId, boolean noCache, Optional<Long> requiredGeneration) {
this.key = key;
this.appId = appId;
this.noCache = noCache;
+ this.requiredGeneration = requiredGeneration;
}
private static ConfigKey<?> fromRequestV1(HttpRequest req) {
@@ -59,7 +62,10 @@ public class HttpConfigRequest implements GetConfigRequest, TenantRequest {
}
public static HttpConfigRequest createFromRequestV1(HttpRequest req) {
- return new HttpConfigRequest(fromRequestV1(req), ApplicationId.defaultId(), req.getBooleanProperty(HTTP_PROPERTY_NOCACHE));
+ return new HttpConfigRequest(fromRequestV1(req),
+ ApplicationId.defaultId(),
+ req.getBooleanProperty(NOCACHE),
+ requiredGeneration(req));
}
public static HttpConfigRequest createFromRequestV2(HttpRequest req) {
@@ -89,7 +95,8 @@ public class HttpConfigRequest implements GetConfigRequest, TenantRequest {
cNamespace = nns.second;
return new HttpConfigRequest(new ConfigKey<>(cName, cId, cNamespace),
new ApplicationId.Builder().applicationName(application).tenant(tenant).build(),
- req.getBooleanProperty(HTTP_PROPERTY_NOCACHE));
+ req.getBooleanProperty(NOCACHE),
+ requiredGeneration(req));
}
// The URL pattern with full app id given
@@ -117,7 +124,10 @@ public class HttpConfigRequest implements GetConfigRequest, TenantRequest {
.applicationName(application)
.instanceName(instance)
.build();
- return new HttpConfigRequest(new ConfigKey<>(cName, cId, cNamespace), appId, req.getBooleanProperty(HTTP_PROPERTY_NOCACHE));
+ return new HttpConfigRequest(new ConfigKey<>(cName, cId, cNamespace),
+ appId,
+ req.getBooleanProperty(NOCACHE),
+ requiredGeneration(req));
}
/**
@@ -144,7 +154,11 @@ public class HttpConfigRequest implements GetConfigRequest, TenantRequest {
public static void throwModelNotReady() {
throw new NotFoundException("Config not available, verify that an application package has been deployed and activated.");
}
-
+
+ public static void throwPreconditionFailed(long requiredGeneration) {
+ throw new PreconditionFailedException("Config for required generation " + requiredGeneration + " could not be found.");
+ }
+
/**
* If the given config is produced by the model at all
*
@@ -199,4 +213,11 @@ public class HttpConfigRequest implements GetConfigRequest, TenantRequest {
@Override
public PayloadChecksums configPayloadChecksums() { return PayloadChecksums.empty(); }
+ public Optional<Long> requiredGeneration() { return requiredGeneration; }
+
+ static Optional<Long> requiredGeneration(HttpRequest req) {
+ Optional<String> requiredGeneration = Optional.ofNullable(req.getProperty(REQUIRED_GENERATION));
+ return requiredGeneration.map(Long::parseLong);
+ }
+
}
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 40ce16145e7..3b5269cdf11 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
@@ -16,6 +16,7 @@ import static com.yahoo.jdisc.Response.Status.CONFLICT;
import static com.yahoo.jdisc.Response.Status.INTERNAL_SERVER_ERROR;
import static com.yahoo.jdisc.Response.Status.METHOD_NOT_ALLOWED;
import static com.yahoo.jdisc.Response.Status.NOT_FOUND;
+import static com.yahoo.jdisc.Response.Status.PRECONDITION_FAILED;
import static com.yahoo.jdisc.Response.Status.REQUEST_TIMEOUT;
/**
@@ -51,7 +52,8 @@ public class HttpErrorResponse extends HttpResponse {
CERTIFICATE_NOT_READY,
LOAD_BALANCER_NOT_READY,
CONFIG_NOT_CONVERGED,
- REINDEXING_STATUS_UNAVAILABLE
+ REINDEXING_STATUS_UNAVAILABLE,
+ PRECONDITION_FAILED
}
public static HttpErrorResponse notFoundError(String msg) {
@@ -114,6 +116,10 @@ public class HttpErrorResponse extends HttpResponse {
return new HttpErrorResponse(CONFLICT, ErrorCode.REINDEXING_STATUS_UNAVAILABLE.name(), msg);
}
+ public static HttpResponse preconditionFailed(String msg) {
+ return new HttpErrorResponse(PRECONDITION_FAILED, ErrorCode.PRECONDITION_FAILED.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 dc3a05e65f9..a0e814f32d8 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
@@ -71,6 +71,8 @@ public class HttpHandler extends ThreadedHttpRequestHandler {
return HttpErrorResponse.loadBalancerNotReady(getMessage(e, request));
} catch (ReindexingStatusException e) {
return HttpErrorResponse.reindexingStatusUnavailable(getMessage(e, request));
+ } catch (PreconditionFailedException e) {
+ return HttpErrorResponse.preconditionFailed(getMessage(e, request));
} catch (Exception e) {
log.log(Level.WARNING, "Unexpected exception handling a config server request", e);
return HttpErrorResponse.internalServerError(getMessage(e, request));
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/NotFoundException.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/NotFoundException.java
index eb008de6ee5..688890c75b2 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/NotFoundException.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/NotFoundException.java
@@ -5,7 +5,6 @@ package com.yahoo.vespa.config.server.http;
* Exception that will create a http response with NOT_FOUND response code (404)
*
* @author hmusum
- * @since 5.1.17
*/
public class NotFoundException extends RuntimeException {
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/PreconditionFailedException.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/PreconditionFailedException.java
new file mode 100644
index 00000000000..ef3924425c2
--- /dev/null
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/PreconditionFailedException.java
@@ -0,0 +1,16 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.config.server.http;
+
+/**
+ * Exception that will create a http response with NOT_FOUND response code (404)
+ *
+ * @author hmusum
+ */
+public class PreconditionFailedException extends RuntimeException {
+
+ public PreconditionFailedException(String message) {
+ super(message);
+ }
+
+}
+
diff --git a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/HttpGetConfigHandler.java b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/HttpGetConfigHandler.java
index 3ab3df99a10..0389b2a6c98 100644
--- a/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/HttpGetConfigHandler.java
+++ b/configserver/src/main/java/com/yahoo/vespa/config/server/http/v2/HttpGetConfigHandler.java
@@ -4,31 +4,27 @@ package com.yahoo.vespa.config.server.http.v2;
import com.yahoo.component.annotation.Inject;
import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.container.jdisc.HttpResponse;
-import java.util.logging.Level;
import com.yahoo.vespa.config.protocol.ConfigResponse;
import com.yahoo.vespa.config.server.RequestHandler;
-import com.yahoo.vespa.config.server.http.v2.request.HttpConfigRequests;
-import com.yahoo.vespa.config.server.tenant.TenantRepository;
import com.yahoo.vespa.config.server.http.HttpConfigRequest;
import com.yahoo.vespa.config.server.http.HttpConfigResponse;
import com.yahoo.vespa.config.server.http.HttpHandler;
-
+import com.yahoo.vespa.config.server.http.v2.request.HttpConfigRequests;
+import com.yahoo.vespa.config.server.tenant.TenantRepository;
import java.util.Optional;
+import java.util.logging.Level;
/**
* HTTP handler for a getConfig operation
*
* @author Ulf Lilleengen
- * @since 5.1
*/
public class HttpGetConfigHandler extends HttpHandler {
private final TenantRepository tenantRepository;
@Inject
- public HttpGetConfigHandler(HttpHandler.Context ctx,
- TenantRepository tenantRepository)
- {
+ public HttpGetConfigHandler(HttpHandler.Context ctx, TenantRepository tenantRepository) {
super(ctx);
this.tenantRepository = tenantRepository;
}
@@ -45,6 +41,8 @@ public class HttpGetConfigHandler extends HttpHandler {
log.log(Level.FINE, () -> "nocache=" + request.noCache());
ConfigResponse config = requestHandler.resolveConfig(request.getApplicationId(), request, Optional.empty());
if (config == null) HttpConfigRequest.throwModelNotReady();
+ if (request.requiredGeneration().isPresent() && request.requiredGeneration().get() != config.getGeneration())
+ HttpConfigRequest.throwPreconditionFailed(request.requiredGeneration().get());
return config;
}
}
diff --git a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/HttpGetConfigHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/HttpGetConfigHandlerTest.java
index a0b5b879e45..401bd1ae55b 100644
--- a/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/HttpGetConfigHandlerTest.java
+++ b/configserver/src/test/java/com/yahoo/vespa/config/server/http/v2/HttpGetConfigHandlerTest.java
@@ -25,6 +25,7 @@ import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
+import java.util.Map;
import static com.yahoo.jdisc.Response.Status.BAD_REQUEST;
import static com.yahoo.jdisc.Response.Status.NOT_FOUND;
@@ -131,6 +132,20 @@ public class HttpGetConfigHandlerTest {
assertTrue(renderedString, renderedString.startsWith(expected));
}
+ @Test
+ public void require_that_required_generation_property_works() throws IOException {
+ HttpRequest request = HttpRequest.createTestRequest(configUri, GET, null, Map.of("requiredGeneration", "2"));
+ HttpResponse response = handler.handle(request);
+ String renderedString = SessionHandlerTest.getRenderedString(response);
+ assertTrue(renderedString, renderedString.startsWith(expected));
+
+ request = HttpRequest.createTestRequest(configUri, GET, null, Map.of("requiredGeneration", "3"));
+ response = handler.handle(request);
+ assertEquals(412, response.getStatus());
+ renderedString = SessionHandlerTest.getRenderedString(response);
+ assertEquals("{\"error-code\":\"PRECONDITION_FAILED\",\"message\":\"Config for required generation 3 could not be found.\"}", renderedString);
+ }
+
private PrepareParams prepareParams() {
return new PrepareParams.Builder().applicationId(applicationId).build();
}