use of io.cdap.cdap.common.ServiceException in project cdap by caskdata.
the class AppLifecycleHttpHandler method upgradeApplications.
/**
* Upgrades a lis of existing application to use latest version of application artifact and plugin artifacts.
*
* <pre>
* {@code
* [
* {"name":"XYZ"},
* {"name":"ABC"},
* {"name":"FOO"},
* ]
* }
* </pre>
* The response will be an array of {@link ApplicationUpdateDetail} object, which either indicates a success (200) or
* failure for each of the requested application in the same order as the request. The failure also indicates reason
* for the error. The response will be sent via ChunkResponder to continuously stream upgrade result per application.
*/
@POST
@Path("/upgrade")
@AuditPolicy(AuditDetail.REQUEST_BODY)
public void upgradeApplications(FullHttpRequest request, HttpResponder responder, @PathParam("namespace-id") String namespaceId, @QueryParam("artifactScope") Set<String> artifactScopes, @QueryParam("allowSnapshot") boolean allowSnapshot) throws Exception {
// TODO: (CDAP-16910) Improve batch API performance as each application upgrade is an event independent of each
// other.
List<ApplicationId> appIds = decodeAndValidateBatchApplicationRecord(validateNamespace(namespaceId), request);
Set<ArtifactScope> allowedArtifactScopes = getArtifactScopes(artifactScopes);
try (ChunkResponder chunkResponder = responder.sendChunkStart(HttpResponseStatus.OK)) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try (JsonWriter jsonWriter = new JsonWriter(new OutputStreamWriter(outputStream, StandardCharsets.UTF_8))) {
jsonWriter.beginArray();
for (ApplicationId appId : appIds) {
ApplicationUpdateDetail updateDetail;
try {
applicationLifecycleService.upgradeApplication(appId, allowedArtifactScopes, allowSnapshot);
updateDetail = new ApplicationUpdateDetail(appId);
} catch (UnsupportedOperationException e) {
String errorMessage = String.format("Application %s does not support upgrade.", appId);
updateDetail = new ApplicationUpdateDetail(appId, new NotImplementedException(errorMessage));
} catch (InvalidArtifactException | NotFoundException e) {
updateDetail = new ApplicationUpdateDetail(appId, e);
} catch (Exception e) {
updateDetail = new ApplicationUpdateDetail(appId, new ServiceException("Upgrade failed due to internal error.", e, HttpResponseStatus.INTERNAL_SERVER_ERROR));
LOG.error("Application upgrade failed with exception", e);
}
GSON.toJson(updateDetail, ApplicationUpdateDetail.class, jsonWriter);
jsonWriter.flush();
chunkResponder.sendChunk(Unpooled.wrappedBuffer(outputStream.toByteArray()));
outputStream.reset();
chunkResponder.flush();
}
jsonWriter.endArray();
}
chunkResponder.sendChunk(Unpooled.wrappedBuffer(outputStream.toByteArray()));
}
}
use of io.cdap.cdap.common.ServiceException 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.ServiceException in project cdap by caskdata.
the class ImpersonationHandler method getCredentials.
@POST
@Path("/credentials")
public void getCredentials(FullHttpRequest request, HttpResponder responder) throws Exception {
String requestContent = request.content().toString(StandardCharsets.UTF_8);
if (requestContent == null) {
throw new BadRequestException("Request body is empty.");
}
ImpersonationRequest impersonationRequest = GSON.fromJson(requestContent, ImpersonationRequest.class);
LOG.debug("Fetching credentials for {}", impersonationRequest);
UGIWithPrincipal ugiWithPrincipal;
try {
ugiWithPrincipal = ugiProvider.getConfiguredUGI(impersonationRequest);
} catch (AccessException e) {
throw new ServiceException(e, HttpResponseStatus.INTERNAL_SERVER_ERROR);
}
Credentials credentials = ImpersonationUtils.doAs(ugiWithPrincipal.getUGI(), new Callable<Credentials>() {
@Override
public Credentials call() throws Exception {
return tokenSecureStoreRenewer.createCredentials();
}
});
// example: hdfs:///cdap/credentials
Location credentialsDir = locationFactory.create("credentials");
if (credentialsDir.isDirectory() || credentialsDir.mkdirs() || credentialsDir.isDirectory()) {
// the getTempFile() doesn't create the file within the directory that you call it on. It simply appends the path
// without a separator, which is why we manually append the "tmp"
// example: hdfs:///cdap/credentials/tmp.5960fe60-6fd8-4f3e-8e92-3fb6d4726006.credentials
Location credentialsFile = credentialsDir.append("tmp").getTempFile(".credentials");
// 600 is owner-only READ_WRITE
try (DataOutputStream os = new DataOutputStream(new BufferedOutputStream(credentialsFile.getOutputStream("600")))) {
credentials.writeTokenStorageToStream(os);
}
LOG.debug("Wrote credentials for user {} to {}", ugiWithPrincipal.getPrincipal(), credentialsFile);
PrincipalCredentials principalCredentials = new PrincipalCredentials(ugiWithPrincipal.getPrincipal(), credentialsFile.toURI().toString());
responder.sendJson(HttpResponseStatus.OK, GSON.toJson(principalCredentials));
} else {
throw new IllegalStateException("Unable to create credentials directory.");
}
}
Aggregations