use of io.cdap.cdap.common.BadRequestException 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.cdap.common.BadRequestException in project cdap by caskdata.
the class RuntimeServiceRoutingHandler method openConnection.
/**
* Opens a {@link HttpURLConnection} to the given service for the given program run.
*
* @throws BadRequestException if the request for service routing is not valid
*/
private HttpURLConnection openConnection(HttpRequest request, String namespace, String app, String version, String programType, String program, String run, String service) throws BadRequestException {
ApplicationId appId = new NamespaceId(namespace).app(app, version);
ProgramRunId programRunId = new ProgramRunId(appId, ProgramType.valueOfCategoryName(programType, BadRequestException::new), program, run);
requestValidator.getProgramRunStatus(programRunId, request);
Discoverable discoverable = endpointStrategyLoadingCache.getUnchecked(service).pick(2, TimeUnit.SECONDS);
if (discoverable == null) {
throw new ServiceUnavailableException(service);
}
String prefix = String.format("%s/runtime/namespaces/%s/apps/%s/versions/%s/%s/%s/runs/%s/services/%s", Constants.Gateway.INTERNAL_API_VERSION_3, namespace, app, version, programType, program, run, service);
URI uri = URIScheme.createURI(discoverable, request.uri().substring(prefix.length()));
try {
URL url = uri.toURL();
HttpURLConnection urlConn;
try {
urlConn = (HttpURLConnection) url.openConnection();
} catch (IOException e) {
// If fail to open the connection, treat it as service unavailable so that the client can retry
throw new ServiceUnavailableException(service);
}
if (urlConn instanceof HttpsURLConnection) {
new HttpsEnabler().setTrustAll(true).enable((HttpsURLConnection) urlConn);
}
for (Map.Entry<String, String> header : request.headers().entries()) {
urlConn.setRequestProperty(header.getKey(), header.getValue());
}
urlConn.setRequestMethod(request.method().name());
urlConn.setDoInput(true);
return urlConn;
} catch (MalformedURLException | ProtocolException e) {
// This can only happen if the incoming request is bad
throw new BadRequestException("Invalid request due to " + e.getMessage(), e);
}
}
use of io.cdap.cdap.common.BadRequestException 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.cdap.common.BadRequestException in project cdap by caskdata.
the class RuntimeHandler method writeMessages.
/**
* Handles call for writing to TMS from the program runtime for a given program run. The POST body is an
* avro array of bytes.
*/
@Path("/topics/{topic}")
@POST
public BodyConsumer writeMessages(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("topic") String topic) throws Exception {
if (!"avro/binary".equals(request.headers().get(HttpHeaderNames.CONTENT_TYPE))) {
throw new BadRequestException("Only avro/binary content type is supported.");
}
ApplicationId appId = new NamespaceId(namespace).app(app, version);
ProgramRunId programRunId = new ProgramRunId(appId, ProgramType.valueOfCategoryName(programType, BadRequestException::new), program, run);
ProgramRunInfo programRunInfo = requestValidator.getProgramRunStatus(programRunId, request);
if (!allowedTopics.contains(topic)) {
throw new UnauthorizedException("Access denied for topic " + topic);
}
TopicId topicId = NamespaceId.SYSTEM.topic(topic);
if (topic.startsWith(logsTopicPrefix)) {
return new MessageBodyConsumer(topicId, logProcessor::process, programRunInfo);
}
return new MessageBodyConsumer(topicId, payloads -> {
try {
messagingContext.getDirectMessagePublisher().publish(topicId.getNamespace(), topicId.getTopic(), payloads);
} catch (TopicNotFoundException e) {
throw new BadRequestException(e);
}
}, programRunInfo);
}
use of io.cdap.cdap.common.BadRequestException in project cdap by caskdata.
the class StoreHandler method createStoreRequest.
/**
* Creates a {@link StoreRequest} instance based on the given {@link HttpRequest}.
*/
private StoreRequest createStoreRequest(TopicId topicId, HttpRequest request, InputStream is) throws BadRequestException, IOException {
// Currently only support avro
if (!"avro/binary".equals(request.headers().get(HttpHeaderNames.CONTENT_TYPE))) {
throw new BadRequestException("Only avro/binary content type is supported.");
}
Decoder decoder = DecoderFactory.get().directBinaryDecoder(is, null);
DatumReader<GenericRecord> datumReader = new GenericDatumReader<>(Schemas.V1.PublishRequest.SCHEMA);
return new GenericRecordStoreRequest(topicId, datumReader.read(null, decoder));
}
Aggregations