use of akka.http.javadsl.model.Uri in project mantis by Netflix.
the class JobClusterRoute method createCache.
private Cache<Uri, RouteResult> createCache(ActorSystem actorSystem) {
final CachingSettings defaultCachingSettings = CachingSettings.create(actorSystem);
final LfuCacheSettings lfuCacheSettings = defaultCachingSettings.lfuCacheSettings().withInitialCapacity(5).withMaxCapacity(50).withTimeToLive(Duration.create(1, TimeUnit.SECONDS));
final CachingSettings cachingSettings = defaultCachingSettings.withLfuCacheSettings(lfuCacheSettings);
// Created outside the route to potentially allow using
// the same cache across multiple calls
final Cache<Uri, RouteResult> jobClustersListCache = LfuCache.create(cachingSettings);
return jobClustersListCache;
}
use of akka.http.javadsl.model.Uri in project mantis by Netflix.
the class JobRoute method getJobRoutes.
private Route getJobRoutes() {
return route(path(STATUS_ENDPOINT, () -> post(() -> decodeRequest(() -> entity(Unmarshaller.entityToString(), req -> {
if (logger.isDebugEnabled()) {
logger.debug("/api/postjobstatus called {}", req);
}
try {
workerHeartbeatStatusPOST.increment();
PostJobStatusRequest postJobStatusRequest = Jackson.fromJSON(req, PostJobStatusRequest.class);
WorkerEvent workerStatusRequest = createWorkerStatusRequest(postJobStatusRequest);
if (workerStatusRequest instanceof WorkerHeartbeat) {
if (!ConfigurationProvider.getConfig().isHeartbeatProcessingEnabled()) {
// skip heartbeat processing
if (logger.isTraceEnabled()) {
logger.trace("skipped heartbeat event {}", workerStatusRequest);
}
workerHeartbeatSkipped.increment();
return complete(StatusCodes.OK);
}
}
return completeWithFuture(jobRouteHandler.workerStatus(workerStatusRequest).thenApply(this::toHttpResponse));
} catch (IOException e) {
logger.warn("Error handling job status {}", req, e);
return complete(StatusCodes.BAD_REQUEST, "{\"error\": \"invalid JSON payload to post job status\"}");
}
})))), pathPrefix(API_JOBS, () -> route(post(() -> route(path(KILL_ENDPOINT, () -> decodeRequest(() -> entity(Unmarshaller.entityToString(), req -> {
logger.debug("/api/jobs/kill called {}", req);
try {
final KillJobRequest killJobRequest = Jackson.fromJSON(req, KillJobRequest.class);
return completeWithFuture(jobRouteHandler.kill(killJobRequest).thenApply(resp -> {
if (resp.responseCode == BaseResponse.ResponseCode.SUCCESS) {
return new JobClusterManagerProto.KillJobResponse(resp.requestId, resp.responseCode, resp.getState(), "[\"" + resp.getJobId().getId() + " Killed\"]", resp.getJobId(), resp.getUser());
} else if (resp.responseCode == BaseResponse.ResponseCode.CLIENT_ERROR) {
// for backwards compatibility with old master
return new JobClusterManagerProto.KillJobResponse(resp.requestId, BaseResponse.ResponseCode.SUCCESS, resp.getState(), "[\"" + resp.message + " \"]", resp.getJobId(), resp.getUser());
}
return resp;
}).thenApply(this::toHttpResponse));
} catch (IOException e) {
logger.warn("Error on job kill {}", req, e);
return complete(StatusCodes.BAD_REQUEST, "{\"error\": \"invalid json payload to kill job\"}");
}
}))), path(RESUBMIT_WORKER_ENDPOINT, () -> decodeRequest(() -> entity(Unmarshaller.entityToString(), req -> {
logger.debug("/api/jobs/resubmitWorker called {}", req);
try {
final ResubmitWorkerRequest resubmitWorkerRequest = Jackson.fromJSON(req, ResubmitWorkerRequest.class);
return completeWithFuture(jobRouteHandler.resubmitWorker(resubmitWorkerRequest).thenApply(this::toHttpResponse));
} catch (IOException e) {
logger.warn("Error on worker resubmit {}", req, e);
return complete(StatusCodes.BAD_REQUEST, "{\"error\": \"invalid json payload to resubmit worker\"}");
}
}))), path(SCALE_STAGE_ENDPOINT, () -> decodeRequest(() -> entity(Unmarshaller.entityToString(), req -> {
logger.debug("/api/jobs/scaleStage called {}", req);
try {
ScaleStageRequest scaleStageRequest = Jackson.fromJSON(req, ScaleStageRequest.class);
int numWorkers = scaleStageRequest.getNumWorkers();
int maxWorkersPerStage = ConfigurationProvider.getConfig().getMaxWorkersPerStage();
if (numWorkers > maxWorkersPerStage) {
logger.warn("rejecting ScaleStageRequest {} with invalid num workers", scaleStageRequest);
return complete(StatusCodes.BAD_REQUEST, "{\"error\": \"num workers must be less than " + maxWorkersPerStage + "\"}");
}
return completeWithFuture(jobRouteHandler.scaleStage(scaleStageRequest).thenApply(this::toHttpResponse));
} catch (IOException e) {
logger.warn("Error scaling stage {}", req, e);
return complete(StatusCodes.BAD_REQUEST, "{\"error\": \"invalid json payload to scale stage " + e.getMessage() + "\"}");
}
}))))), get(() -> route(// - optional labels.op query param - default value is 'or' if not specified (other possible value is 'and'
path(segment("list"), () -> {
jobListGET.increment();
return jobListRoute(Optional.empty());
}), path(segment("list").slash("matchinglabels"), () -> {
jobListLabelMatchGET.increment();
return jobListRoute(Optional.empty());
}), path(segment("list").slash(PathMatchers.segment()), (jobId) -> {
logger.debug("/api/jobs/list/{} called", jobId);
jobListJobIdGET.increment();
return completeAsync(jobRouteHandler.getJobDetails(new JobClusterManagerProto.GetJobDetailsRequest("masterAPI", jobId)), resp -> {
Optional<MantisJobMetadataView> mantisJobMetadataView = resp.getJobMetadata().map(metaData -> new MantisJobMetadataView(metaData, Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), Collections.emptyList(), false));
return completeOK(mantisJobMetadataView, Jackson.marshaller());
});
}), path(segment("list").slash("matching").slash(PathMatchers.segment()), (regex) -> {
jobListRegexGET.increment();
return jobListRoute(Optional.ofNullable(regex).filter(r -> !r.isEmpty()));
}), path(segment("archived").slash(PathMatchers.segment()), (jobId) -> parameterOptional(StringUnmarshallers.INTEGER, "limit", (limit) -> {
jobArchivedWorkersGET.increment();
Optional<JobId> jobIdO = JobId.fromId(jobId);
if (jobIdO.isPresent()) {
ListArchivedWorkersRequest req = new ListArchivedWorkersRequest(jobIdO.get(), limit.orElse(DEFAULT_LIST_ARCHIVED_WORKERS_LIMIT));
return alwaysCache(cache, requestUriKeyer, () -> extractUri(uri -> completeAsync(jobRouteHandler.listArchivedWorkers(req), resp -> {
List<MantisWorkerMetadataWritable> workers = resp.getWorkerMetadata().stream().map(wm -> DataFormatAdapter.convertMantisWorkerMetadataToMantisWorkerMetadataWritable(wm)).collect(Collectors.toList());
return completeOK(workers, Jackson.marshaller());
})));
} else {
return complete(StatusCodes.BAD_REQUEST, "error: 'archived/<jobId>' request must include a valid jobId");
}
})), path(segment("archived"), () -> {
jobArchivedWorkersGETInvalid.increment();
return complete(StatusCodes.BAD_REQUEST, "error: 'archived' Request must include jobId");
}))))));
}
use of akka.http.javadsl.model.Uri in project mantis by Netflix.
the class JobClusterRoute method getJobClusterRoutes.
private Route getJobClusterRoutes() {
return route(path(segment("api").slash("submit"), () -> decodeRequest(() -> entity(Unmarshaller.entityToString(), request -> {
logger.debug("/api/submit called {}", request);
try {
MantisJobDefinition mjd = Jackson.fromJSON(request, MantisJobDefinition.class);
logger.debug("job submit request {}", mjd);
mjd.validate(true);
Pair<Boolean, String> validationResult = validateSubmitJobRequest(mjd);
if (!validationResult.first()) {
jobClusterSubmitError.increment();
return complete(StatusCodes.BAD_REQUEST, "{\"error\": \"" + validationResult.second() + "\"}");
}
jobClusterSubmit.increment();
return completeWithFuture(jobClusterRouteHandler.submit(JobClusterProtoAdapter.toSubmitJobClusterRequest(mjd)).thenApply(this::toHttpResponse));
} catch (Exception e) {
logger.warn("exception in submit job request {}", request, e);
jobClusterSubmitError.increment();
return complete(StatusCodes.INTERNAL_SERVER_ERROR, "{\"error\": \"" + e.getMessage() + "\"}");
}
}))), pathPrefix(API_V0_JOBCLUSTER, () -> route(post(() -> route(path("create", () -> decodeRequest(() -> entity(Unmarshaller.entityToString(), jobClusterDefn -> {
logger.debug("/api/namedjob/create called {}", jobClusterDefn);
try {
final NamedJobDefinition namedJobDefinition = Jackson.fromJSON(jobClusterDefn, NamedJobDefinition.class);
if (namedJobDefinition == null || namedJobDefinition.getJobDefinition() == null || namedJobDefinition.getJobDefinition().getJobJarFileLocation() == null || namedJobDefinition.getJobDefinition().getName() == null || namedJobDefinition.getJobDefinition().getName().isEmpty()) {
logger.warn("JobCluster create request must include name and URL {}", jobClusterDefn);
return complete(StatusCodes.BAD_REQUEST, "{\"error\": \"Job definition must include name and URL\"}");
}
final CompletionStage<CreateJobClusterResponse> response = jobClusterRouteHandler.create(JobClusterProtoAdapter.toCreateJobClusterRequest(namedJobDefinition));
jobClusterCreate.increment();
return completeWithFuture(response.thenApply(r -> {
if ((r.responseCode == CLIENT_ERROR || r.responseCode == CLIENT_ERROR_CONFLICT) && r.message.contains("already exists")) {
return new CreateJobClusterResponse(r.requestId, SERVER_ERROR, r.message, r.getJobClusterName());
}
return r;
}).thenApply(this::toHttpResponse));
} catch (IOException e) {
logger.warn("Error creating JobCluster {}", jobClusterDefn, e);
jobClusterCreateError.increment();
return complete(StatusCodes.BAD_REQUEST, "Can't read valid json in request: " + e.getMessage());
} catch (Exception e) {
logger.warn("Error creating JobCluster {}", jobClusterDefn, e);
jobClusterCreateError.increment();
return complete(StatusCodes.INTERNAL_SERVER_ERROR, "{\"error\": " + e.getMessage() + "}");
}
}))), path("update", () -> decodeRequest(() -> entity(Unmarshaller.entityToString(), jobClusterDefn -> {
logger.debug("/api/namedjob/update called {}", jobClusterDefn);
try {
final NamedJobDefinition namedJobDefinition = Jackson.fromJSON(jobClusterDefn, NamedJobDefinition.class);
if (namedJobDefinition == null || namedJobDefinition.getJobDefinition() == null || namedJobDefinition.getJobDefinition().getJobJarFileLocation() == null || namedJobDefinition.getJobDefinition().getName() == null || namedJobDefinition.getJobDefinition().getName().isEmpty()) {
logger.warn("JobCluster update request must include name and URL {}", jobClusterDefn);
jobClusterCreateUpdateError.increment();
return complete(StatusCodes.BAD_REQUEST, "{\"error\": \"Job definition must include name and URL\"}");
}
final CompletionStage<UpdateJobClusterResponse> response = jobClusterRouteHandler.update(JobClusterProtoAdapter.toUpdateJobClusterRequest(namedJobDefinition));
jobClusterCreateUpdate.increment();
return completeWithFuture(response.thenApply(this::toHttpResponse));
} catch (IOException e) {
logger.warn("Error updating JobCluster {}", jobClusterDefn, e);
jobClusterCreateUpdateError.increment();
return complete(StatusCodes.BAD_REQUEST, "Can't read valid json in request: " + e.getMessage());
} catch (Exception e) {
logger.warn("Error updating JobCluster {}", jobClusterDefn, e);
jobClusterCreateUpdateError.increment();
return complete(StatusCodes.INTERNAL_SERVER_ERROR, "{\"error\": " + e.getMessage() + "}");
}
}))), path("delete", () -> decodeRequest(() -> entity(Unmarshaller.entityToString(), deleteReq -> {
logger.debug("/api/namedjob/delete called {}", deleteReq);
try {
final DeleteJobClusterRequest deleteJobClusterRequest = Jackson.fromJSON(deleteReq, DeleteJobClusterRequest.class);
final CompletionStage<DeleteJobClusterResponse> response = jobClusterRouteHandler.delete(deleteJobClusterRequest);
jobClusterDelete.increment();
return completeWithFuture(response.thenApply(this::toHttpResponse));
} catch (IOException e) {
logger.warn("Error deleting JobCluster {}", deleteReq, e);
jobClusterDeleteError.increment();
return complete(StatusCodes.BAD_REQUEST, "Can't find valid json in request: " + e.getMessage());
}
}))), path("disable", () -> decodeRequest(() -> entity(Unmarshaller.entityToString(), request -> {
logger.debug("/api/namedjob/disable called {}", request);
try {
final DisableJobClusterRequest disableJobClusterRequest = Jackson.fromJSON(request, DisableJobClusterRequest.class);
final CompletionStage<DisableJobClusterResponse> response = jobClusterRouteHandler.disable(disableJobClusterRequest);
jobClusterDisable.increment();
return completeWithFuture(response.thenApply(this::toHttpResponse));
} catch (IOException e) {
logger.warn("Error disabling JobCluster {}", request, e);
jobClusterDisableError.increment();
return complete(StatusCodes.BAD_REQUEST, "Can't find valid json in request: " + e.getMessage());
}
}))), path("enable", () -> decodeRequest(() -> entity(Unmarshaller.entityToString(), request -> {
logger.debug("/api/namedjob/enable called {}", request);
try {
final EnableJobClusterRequest enableJobClusterRequest = Jackson.fromJSON(request, EnableJobClusterRequest.class);
final CompletionStage<EnableJobClusterResponse> response = jobClusterRouteHandler.enable(enableJobClusterRequest);
jobClusterEnable.increment();
return completeWithFuture(response.thenApply(this::toHttpResponse));
} catch (IOException e) {
logger.warn("Error enabling JobCluster {}", request, e);
jobClusterEnableError.increment();
return complete(StatusCodes.BAD_REQUEST, "Can't find valid json in request: " + e.getMessage());
}
}))), path("quickupdate", () -> decodeRequest(() -> entity(Unmarshaller.entityToString(), request -> {
logger.debug("/api/namedjob/quickupdate called {}", request);
try {
final UpdateJobClusterArtifactRequest updateJobClusterArtifactRequest = Jackson.fromJSON(request, UpdateJobClusterArtifactRequest.class);
final CompletionStage<UpdateJobClusterArtifactResponse> response = jobClusterRouteHandler.updateArtifact(updateJobClusterArtifactRequest);
jobClusterQuickupdate.increment();
return completeWithFuture(response.thenApply(this::toHttpResponse));
} catch (IOException e) {
logger.warn("Error on quickupdate for JobCluster {}", request, e);
jobClusterQuickupdateError.increment();
return complete(StatusCodes.BAD_REQUEST, "Can't find valid json in request: " + e.getMessage());
}
}))), path("updatelabels", () -> decodeRequest(() -> entity(Unmarshaller.entityToString(), request -> {
logger.debug("/api/namedjob/updatelabels called {}", request);
try {
final UpdateJobClusterLabelsRequest updateJobClusterLabelsRequest = Jackson.fromJSON(request, UpdateJobClusterLabelsRequest.class);
jobClusterUpdateLabel.increment();
return completeWithFuture(jobClusterRouteHandler.updateLabels(updateJobClusterLabelsRequest).thenApply(this::toHttpResponse));
} catch (IOException e) {
logger.warn("Error updating labels for JobCluster {}", request, e);
jobClusterUpdateLabelError.increment();
return complete(StatusCodes.BAD_REQUEST, "Can't find valid json in request: " + e.getMessage());
}
}))), path("updatesla", () -> decodeRequest(() -> entity(Unmarshaller.entityToString(), request -> {
logger.debug("/api/namedjob/updatesla called {}", request);
jobClusterUpdateSla.increment();
try {
final UpdateJobClusterSLARequest updateJobClusterSLARequest = Jackson.fromJSON(request, UpdateJobClusterSLARequest.class);
return completeWithFuture(jobClusterRouteHandler.updateSLA(updateJobClusterSLARequest).thenApply(this::toHttpResponse));
} catch (IOException e) {
logger.warn("Error updating SLA for JobCluster {}", request, e);
jobClusterUpdateSlaError.increment();
return complete(StatusCodes.BAD_REQUEST, "Can't find valid json in request: " + e.getMessage());
}
}))), path("migratestrategy", () -> decodeRequest(() -> entity(Unmarshaller.entityToString(), request -> {
logger.debug("/api/namedjob/migratestrategy called {}", request);
try {
final UpdateJobClusterWorkerMigrationStrategyRequest updateMigrateStrategyReq = Jackson.fromJSON(request, UpdateJobClusterWorkerMigrationStrategyRequest.class);
return completeWithFuture(jobClusterRouteHandler.updateWorkerMigrateStrategy(updateMigrateStrategyReq).thenApply(this::toHttpResponse));
} catch (IOException e) {
logger.warn("Error updating migrate strategy for JobCluster {}", request, e);
return complete(StatusCodes.BAD_REQUEST, "Can't find valid json in request: " + e.getMessage());
}
}))), path("quicksubmit", () -> decodeRequest(() -> entity(Unmarshaller.entityToString(), request -> {
logger.debug("/api/namedjob/quicksubmit called {}", request);
try {
final JobClusterManagerProto.SubmitJobRequest submitJobRequest = Jackson.fromJSON(request, JobClusterManagerProto.SubmitJobRequest.class);
return completeWithFuture(jobClusterRouteHandler.submit(submitJobRequest).thenApply(this::toHttpResponse));
} catch (IOException e) {
logger.warn("Error on quick submit for JobCluster {}", request, e);
return complete(StatusCodes.BAD_REQUEST, "Can't find valid json in request: " + e.getMessage());
}
}))))), get(() -> route(pathPrefix("list", () -> route(pathEndOrSingleSlash(() -> {
logger.debug("/api/namedjob/list called");
jobClusterListGET.increment();
return alwaysCache(cache, requestUriKeyer, () -> extractUri(uri -> completeAsync(jobClusterRouteHandler.getAllJobClusters(new ListJobClustersRequest()), resp -> completeOK(resp.getJobClusters().stream().map(jobClusterMetadataView -> JobClusterProtoAdapter.toJobClusterInfo(jobClusterMetadataView)).collect(Collectors.toList()), Jackson.marshaller()), resp -> completeOK(Collections.emptyList(), Jackson.marshaller()))));
}), path(PathMatchers.segment(), (jobCluster) -> {
if (logger.isDebugEnabled()) {
logger.debug("/api/namedjob/list/{} called", jobCluster);
}
jobClusterListClusterGET.increment();
return completeAsync(jobClusterRouteHandler.getJobClusterDetails(new JobClusterManagerProto.GetJobClusterRequest(jobCluster)), resp -> completeOK(resp.getJobCluster().map(jc -> Arrays.asList(jc)).orElse(Collections.emptyList()), Jackson.marshaller()), resp -> completeOK(Collections.emptyList(), Jackson.marshaller()));
}))), path(segment("listJobIds").slash(PathMatchers.segment()), (jobCluster) -> {
logger.debug("/api/namedjob/listJobIds/{} called", jobCluster);
jobClusterListJobIdGET.increment();
return jobClusterListRoute(jobCluster);
}), path("listJobIds", () -> {
logger.debug("/api/namedjob/listJobIds called");
return complete(StatusCodes.BAD_REQUEST, "Specify the Job cluster name '/api/namedjob/listJobIds/<JobClusterName>' to list the job Ids");
}))))));
}
use of akka.http.javadsl.model.Uri in project mantis by Netflix.
the class LeaderRedirectionFilter method redirectIfNotLeader.
public Route redirectIfNotLeader(final Route leaderRoute) {
MasterDescription latestMaster = masterMonitor.getLatestMaster();
if (leadershipManager.isLeader() || isLocalHost(latestMaster)) {
if (leadershipManager.isReady()) {
return leaderRoute;
} else {
return extractUri(uri -> {
logger.info("leader is not ready, returning 503 for {}", uri);
api503MasterNotReady.increment();
return complete(StatusCodes.SERVICE_UNAVAILABLE, "Mantis master awaiting to be ready");
});
}
} else {
String hostname = latestMaster.getHostname();
int apiPort = latestMaster.getApiPort();
return extractUri(uri -> {
Uri redirectUri = uri.host(hostname).port(apiPort);
apiRedirectsToLeader.increment();
logger.info("redirecting request {} to leader", redirectUri.toString());
return redirect(redirectUri, StatusCodes.FOUND);
});
}
}
Aggregations