com.yahoo.vespa.config.server.http.v2.SessionCreateHandler Maven / Gradle / Ivy
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.config.server.http.v2;
import com.yahoo.component.annotation.Inject;
import com.yahoo.cloud.config.ConfigserverConfig;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.ApplicationName;
import com.yahoo.config.provision.InstanceName;
import com.yahoo.config.provision.TenantName;
import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.container.jdisc.HttpResponse;
import com.yahoo.jdisc.application.UriPattern;
import com.yahoo.vespa.config.server.ApplicationRepository;
import com.yahoo.vespa.config.server.deploy.DeployHandlerLogger;
import com.yahoo.vespa.config.server.TimeoutBudget;
import com.yahoo.vespa.config.server.http.BadRequestException;
import com.yahoo.vespa.config.server.http.SessionHandler;
import com.yahoo.vespa.config.server.http.Utils;
import com.yahoo.vespa.config.server.http.v2.response.SessionCreateResponse;
import org.apache.hc.core5.http.ContentType;
import java.net.URI;
import java.time.Duration;
import java.util.List;
/**
* A handler that is able to create a session from an application package,
* or create a new session from a previous session (with id or the "active" session).
* Handles /application/v2/ requests
*
* @author hmusum
*/
public class SessionCreateHandler extends SessionHandler {
private static final String fromPattern = "http://*/application/v2/tenant/*/application/*/environment/*/region/*/instance/*";
private final Duration zookeeperBarrierTimeout;
@Inject
public SessionCreateHandler(Context ctx,
ApplicationRepository applicationRepository,
ConfigserverConfig configserverConfig) {
super(ctx, applicationRepository);
this.zookeeperBarrierTimeout = Duration.ofSeconds(configserverConfig.zookeeper().barrierTimeout());
}
@Override
protected HttpResponse handlePOST(HttpRequest request) {
TenantName tenantName = Utils.getTenantNameFromSessionRequest(request);
Utils.checkThatTenantExists(applicationRepository.tenantRepository(), tenantName);
TimeoutBudget timeoutBudget = SessionHandler.getTimeoutBudget(request, zookeeperBarrierTimeout);
boolean verbose = request.getBooleanProperty("verbose");
DeployHandlerLogger logger;
long sessionId;
if (request.hasProperty("from")) {
ApplicationId applicationId = getFromApplicationId(request);
logger = DeployHandlerLogger.forApplication(applicationId, verbose);
sessionId = applicationRepository.createSessionFromExisting(applicationId, false, timeoutBudget, logger);
} else {
validateDataAndHeader(request, List.of(ApplicationApiHandler.APPLICATION_ZIP, ApplicationApiHandler.APPLICATION_X_GZIP));
logger = DeployHandlerLogger.forTenant(tenantName, verbose);
// TODO: Avoid using application id here at all
ApplicationId applicationId = ApplicationId.from(tenantName, ApplicationName.defaultName(), InstanceName.defaultName());
sessionId = applicationRepository.createSession(applicationId,
timeoutBudget,
request.getData(),
request.getHeader(ApplicationApiHandler.contentTypeHeader),
logger);
}
return new SessionCreateResponse(logger.slime(), tenantName, request.getHost(), request.getPort(), sessionId);
}
static ApplicationId getFromApplicationId(HttpRequest request) {
String from = request.getProperty("from");
if (from == null || "".equals(from))
throw new BadRequestException("Parameter 'from' has illegal value '" + from + "'");
return getAndValidateFromParameter(URI.create(from));
}
private static ApplicationId getAndValidateFromParameter(URI from) {
UriPattern.Match match = new UriPattern(fromPattern).match(from);
if (match == null || match.groupCount() < 7)
throw new BadRequestException("Parameter 'from' has illegal value '" + from + "'");
return new ApplicationId.Builder()
.tenant(match.group(2))
.applicationName(match.group(3))
.instanceName(match.group(6)).build();
}
static void validateDataAndHeader(HttpRequest request, List supportedContentTypes) {
if (request.getData() == null)
throw new BadRequestException("Request contains no data");
String header = request.getHeader(ApplicationApiHandler.contentTypeHeader);
if (header == null)
throw new BadRequestException("Request contains no " + ApplicationApiHandler.contentTypeHeader + " header");
ContentType contentType = ContentType.parse(header);
if ( ! supportedContentTypes.contains(contentType.getMimeType()))
throw new BadRequestException("Request contains invalid " + ApplicationApiHandler.contentTypeHeader +
" header (" + contentType.getMimeType() + "), only '[" +
String.join(", ", supportedContentTypes) + "]' are supported");
}
}