use of io.cdap.http.BodyConsumer in project cdap by caskdata.
the class RuntimeServiceRoutingHandler method routeServiceWithBody.
/**
* Handles PUT and POST calls from program runtime to access CDAP services.
* It simply verify the request and forward the call to internal CDAP services.
*/
@Path("/services/{service}/**")
@PUT
@POST
public BodyConsumer routeServiceWithBody(HttpRequest request, HttpResponder responder, @PathParam("namespace") String namespace, @PathParam("app") String app, @PathParam("version") String version, @PathParam("program-type") String programType, @PathParam("program") String program, @PathParam("run") String run, @PathParam("service") String service) throws Exception {
HttpURLConnection urlConn = openConnection(request, namespace, app, version, programType, program, run, service);
urlConn.setDoOutput(true);
OutputStream output;
try {
output = urlConn.getOutputStream();
} catch (UnknownServiceException e) {
throw new BadRequestException(e.getMessage(), e);
} catch (IOException e) {
// If fails to get output stream, treat it as service unavailable so that the client can retry
throw new ServiceUnavailableException(service, e);
}
return new BodyConsumer() {
@Override
public void chunk(ByteBuf byteBuf, HttpResponder httpResponder) {
try {
byteBuf.readBytes(output, byteBuf.readableBytes());
} catch (IOException e) {
throw new ServiceUnavailableException(service, e);
}
}
@Override
public void finished(HttpResponder httpResponder) {
try {
output.close();
} catch (IOException e) {
throw new ServiceUnavailableException(service, e);
}
try {
ResponseInfo responseInfo = new ResponseInfo(service, urlConn);
responder.sendContent(HttpResponseStatus.valueOf(responseInfo.getResponseCode()), new RelayBodyProducer(urlConn.getURL(), responseInfo), responseInfo.getHeaders());
} catch (BadRequestException e) {
throw new ServiceException(e, HttpResponseStatus.BAD_REQUEST);
}
}
@Override
public void handleError(Throwable throwable) {
LOG.warn("Exception raised for call to {}", urlConn.getURL(), throwable);
}
};
}
use of io.cdap.http.BodyConsumer in project cdap by caskdata.
the class RuntimeHandler method writeSparkEventLogs.
/**
* Handles call for Spark event logs upload.
*/
@Path("/spark-event-logs/{id}")
@POST
public BodyConsumer writeSparkEventLogs(HttpRequest request, HttpResponder responder, @PathParam("namespace") String namespace, @PathParam("app") String app, @PathParam("version") String version, @PathParam("program-type") String programType, @PathParam("program") String program, @PathParam("run") String run, @PathParam("id") String id) throws Exception {
if (!eventLogsEnabled) {
throw new UnsupportedOperationException("Spark event logs collection is not enabled");
}
if (!MediaType.APPLICATION_OCTET_STREAM.equals(request.headers().get(HttpHeaderNames.CONTENT_TYPE))) {
throw new BadRequestException("Only application/octet-stream content type is supported.");
}
ApplicationId appId = new NamespaceId(namespace).app(app, version);
ProgramRunId programRunId = new ProgramRunId(appId, ProgramType.valueOfCategoryName(programType, BadRequestException::new), program, run);
requestValidator.getProgramRunStatus(programRunId, request);
Location location = eventLogsBaseLocation.append(String.format("%s-%s-%s-%s-%s", namespace, app, program, run, id));
if (location.exists()) {
LOG.debug("Deleting event logs location {} for program run {}", location, programRunId);
location.delete(true);
}
OutputStream os = location.getOutputStream();
return new BodyConsumer() {
@Override
public void chunk(ByteBuf request, HttpResponder responder) {
try {
request.readBytes(os, request.readableBytes());
} catch (IOException e) {
throw new RuntimeException("Failed to write spark event logs to " + location, e);
}
}
@Override
public void finished(HttpResponder responder) {
try {
os.close();
responder.sendStatus(HttpResponseStatus.OK);
} catch (IOException e) {
throw new RuntimeException("Failed to close spark event logs output stream for " + location, e);
}
}
@Override
public void handleError(Throwable cause) {
LOG.error("Failed to write spark event logs for {}", programRunId, cause);
Closeables.closeQuietly(os);
try {
location.delete();
} catch (IOException e) {
LOG.error("Failed to delete obsolete event logs location {}", location, e);
}
}
};
}
use of io.cdap.http.BodyConsumer in project cdap by caskdata.
the class AbstractHttpHandlerDelegator method wrapContentConsumer.
/**
* Returns a new instance of {@link BodyConsumer} that wraps around the given {@link HttpContentConsumer}
* and {@link DelayedHttpServiceResponder}.
*
* IMPORTANT: This method will also capture the context associated with the current thread, hence after
* this method is called, no other methods on this class should be called from the current thread.
*
* This method is called from handler class generated by {@link HttpHandlerGenerator}.
*/
@SuppressWarnings("unused")
protected final BodyConsumer wrapContentConsumer(HttpContentConsumer consumer, DelayedHttpServiceResponder responder, TransactionControl defaultTxControl) {
Preconditions.checkState(!responder.hasBufferedResponse(), "HttpContentConsumer may not be used after a response has already been sent.");
// Close the provided responder since a new one will be created for the BodyConsumerAdapter to use.
responder.close();
ServiceTaskExecutor taskExecutor = context.getServiceTaskExecutor();
Cancellable contextReleaser = context.capture();
return new BodyConsumerAdapter(new DelayedHttpServiceResponder(responder, (contentProducer, txServiceContext) -> new BodyProducerAdapter(contentProducer, txServiceContext, contextReleaser, defaultTxControl)), consumer, taskExecutor, contextReleaser, defaultTxControl);
}
use of io.cdap.http.BodyConsumer in project cdap by caskdata.
the class AppFabricClient method deployApplication.
public void deployApplication(ApplicationId appId, AppRequest appRequest) throws Exception {
HttpRequest request = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, String.format("%s/apps/%s/versions/%s/create", getNamespacePath(appId.getNamespace()), appId.getApplication(), appId.getVersion()));
request.headers().set(Constants.Gateway.API_KEY, "api-key-example");
HttpUtil.setTransferEncodingChunked(request, true);
MockResponder mockResponder = new MockResponder();
BodyConsumer bodyConsumer = appLifecycleHttpHandler.createAppVersion(request, mockResponder, appId.getNamespace(), appId.getApplication(), appId.getVersion());
Preconditions.checkNotNull(bodyConsumer, "BodyConsumer from deploy call should not be null");
bodyConsumer.chunk(Unpooled.copiedBuffer(GSON.toJson(appRequest), StandardCharsets.UTF_8), mockResponder);
bodyConsumer.finished(mockResponder);
verifyResponse(HttpResponseStatus.OK, mockResponder.getStatus(), "Failed to deploy app (" + mockResponder.getResponseContentAsString() + ")");
}
use of io.cdap.http.BodyConsumer in project cdap by caskdata.
the class AppFabricClient method deployApplication.
public Location deployApplication(Id.Namespace namespace, Class<?> applicationClz, String config, @Nullable KerberosPrincipalId ownerPrincipal, File... bundleEmbeddedJars) throws Exception {
Preconditions.checkNotNull(applicationClz, "Application cannot be null.");
Location deployedJar = AppJarHelper.createDeploymentJar(locationFactory, applicationClz, bundleEmbeddedJars);
LOG.info("Created deployedJar at {}", deployedJar);
String archiveName = String.format("%s-1.0.%d.jar", applicationClz.getSimpleName(), System.currentTimeMillis());
FullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.POST, String.format("/v3/namespaces/%s/apps", namespace.getId()));
request.headers().set(Constants.Gateway.API_KEY, "api-key-example");
request.headers().set(AbstractAppFabricHttpHandler.ARCHIVE_NAME_HEADER, archiveName);
if (config != null) {
request.headers().set(AbstractAppFabricHttpHandler.APP_CONFIG_HEADER, config);
}
String owner = null;
if (ownerPrincipal != null) {
owner = GSON.toJson(ownerPrincipal, KerberosPrincipalId.class);
request.headers().set(AbstractAppFabricHttpHandler.PRINCIPAL_HEADER, owner);
}
MockResponder mockResponder = new MockResponder();
BodyConsumer bodyConsumer = appLifecycleHttpHandler.deploy(request, mockResponder, namespace.getId(), archiveName, config, owner, true);
Preconditions.checkNotNull(bodyConsumer, "BodyConsumer from deploy call should not be null");
try (BufferFileInputStream is = new BufferFileInputStream(deployedJar.getInputStream(), 100 * 1024)) {
byte[] chunk = is.read();
while (chunk.length > 0) {
mockResponder = new MockResponder();
bodyConsumer.chunk(Unpooled.wrappedBuffer(chunk), mockResponder);
Preconditions.checkState(mockResponder.getStatus() == null, "failed to deploy app");
chunk = is.read();
}
mockResponder = new MockResponder();
bodyConsumer.finished(mockResponder);
verifyResponse(HttpResponseStatus.OK, mockResponder.getStatus(), "Failed to deploy app (" + mockResponder.getResponseContentAsString() + ")");
}
return deployedJar;
}
Aggregations