/*
* Copyright 2015-2016 OpenCB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.opencb.opencga.server.rest;
import io.swagger.annotations.*;
import org.apache.commons.lang3.StringUtils;
import org.opencb.commons.datastore.core.QueryOptions;
import org.opencb.commons.datastore.core.QueryResult;
import org.opencb.opencga.catalog.db.api.JobDBAdaptor;
import org.opencb.opencga.catalog.exceptions.CatalogException;
import org.opencb.opencga.catalog.models.File;
import org.opencb.opencga.catalog.models.Job;
import org.opencb.opencga.core.exception.VersionException;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.*;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
import java.io.IOException;
import java.util.List;
import java.util.Map;
///opencga/rest/v1/jobs/create?analysisId=23&tool=samtools
@Path("/{version}/jobs")
@Produces(MediaType.APPLICATION_JSON)
@Api(value = "Jobs", position = 5, description = "Methods for working with 'jobs' endpoint")
public class JobWSServer extends OpenCGAWSServer {
public JobWSServer(@Context UriInfo uriInfo, @Context HttpServletRequest httpServletRequest) throws IOException, VersionException {
super(uriInfo, httpServletRequest);
}
public static class InputJob {
public InputJob() {
}
public InputJob(String name, String toolName, String description, long startTime, long endTime, String commandLine, Status status,
String outDirId, List<Long> input, Map<String, Object> attributes, Map<String, Object> resourceManagerAttributes) {
this.name = name;
this.toolName = toolName;
this.description = description;
this.startTime = startTime;
this.endTime = endTime;
this.commandLine = commandLine;
this.status = status;
this.outDirId = outDirId;
this.input = input;
this.attributes = attributes;
this.resourceManagerAttributes = resourceManagerAttributes;
}
enum Status{READY, ERROR}
@ApiModelProperty(required = true)
public String name;
@ApiModelProperty(required = true)
public String toolName;
public String description;
public String execution;
public Map<String, String> params;
public long startTime;
public long endTime;
@ApiModelProperty(required = true)
public String commandLine;
public Status status = Status.READY;
public String statusMessage;
@ApiModelProperty(required = true)
public String outDirId;
public List<Long> input;
public List<Long> output;
public Map<String, Object> attributes;
public Map<String, Object> resourceManagerAttributes;
}
// TODO: Change the name for register. We are not "creating" a job, meaning that it will be put into execution, we are just registering
// TODO: it, so it would be necessary changing the path name "create" per "register"
@POST
@Path("/create")
@Consumes(MediaType.APPLICATION_JSON)
@ApiOperation(value = "Register an executed job with POST method", position = 1,
notes = "Registers a job that has been previously run outside catalog into catalog. <br>"
+ "Required values: [name, toolName, commandLine, outDirId]", response = Job.class)
public Response createJobPOST(@ApiParam(value = "DEPRECATED: studyId", hidden = true) @QueryParam("studyId") String studyIdStr,
@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias")
@QueryParam("study") String studyStr,
@ApiParam(value = "job", required = true) InputJob job) {
try {
if (StringUtils.isNotEmpty(studyIdStr)) {
studyStr = studyIdStr;
}
long studyId = catalogManager.getStudyId(studyStr, sessionId);
Job.JobStatus jobStatus;
if (Job.JobStatus.isValid(job.status.toString())) {
jobStatus = new Job.JobStatus(job.status.toString(), job.statusMessage);
} else {
jobStatus = new Job.JobStatus();
jobStatus.setMessage(job.statusMessage);
}
long outDir = catalogManager.getFileId(job.outDirId, Long.toString(studyId), sessionId);
QueryResult<Job> result = catalogManager.createJob(studyId, job.name, job.toolName, job.description, job.execution, job.params,
job.commandLine, null, outDir, job.input, job.output, job.attributes, job.resourceManagerAttributes, jobStatus,
job.startTime, job.endTime, queryOptions, sessionId);
return createOkResponse(result);
} catch (Exception e) {
return createErrorResponse(e);
}
}
@GET
@Path("/{jobId}/info")
@ApiOperation(value = "Get job information", position = 2, response = Job[].class)
@ApiImplicitParams({
@ApiImplicitParam(name = "include", value = "Fields included in the response, whole JSON path must be provided",
example = "name,attributes", dataType = "string", paramType = "query"),
@ApiImplicitParam(name = "exclude", value = "Fields excluded in the response, whole JSON path must be provided",
example = "id,status", dataType = "string", paramType = "query"),
})
public Response info(@ApiParam(value = "jobId", required = true) @PathParam("jobId") long jobId) {
try {
return createOkResponse(catalogManager.getJob(jobId, queryOptions, sessionId));
} catch (CatalogException e) {
return createErrorResponse(e);
}
}
// FIXME: Implement and change parameters
@GET
@Path("/search")
@ApiOperation(value = "Filter jobs [PENDING]", position = 12, response = Job[].class)
@ApiImplicitParams({
@ApiImplicitParam(name = "include", value = "Fields included in the response, whole JSON path must be provided", example = "name,attributes", dataType = "string", paramType = "query"),
@ApiImplicitParam(name = "exclude", value = "Fields excluded in the response, whole JSON path must be provided", example = "id,status", dataType = "string", paramType = "query"),
@ApiImplicitParam(name = "limit", value = "Number of results to be returned in the queries", dataType = "integer", paramType = "query"),
@ApiImplicitParam(name = "skip", value = "Number of results to skip in the queries", dataType = "integer", paramType = "query"),
@ApiImplicitParam(name = "count", value = "Total number of results", dataType = "boolean", paramType = "query")
})
public Response search(@ApiParam(value = "DEPRECATED: studyId", hidden = true) @QueryParam("studyId") String studyId,
@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias")
@QueryParam("study") String studyStr,
@ApiParam(value = "name", required = false) @DefaultValue("") @QueryParam("name") String name,
@ApiParam(value = "tool name", required = false) @DefaultValue("") @QueryParam("toolName") String tool,
@ApiParam(value = "status", required = false) @DefaultValue("") @QueryParam("status") String status,
@ApiParam(value = "ownerId", required = false) @DefaultValue("") @QueryParam("ownerId") String ownerId,
@ApiParam(value = "date", required = false) @DefaultValue("") @QueryParam("date") String date,
@ApiParam(value = "Comma separated list of input file ids", required = false) @DefaultValue("") @QueryParam("inputFiles") String inputFiles,
@ApiParam(value = "Comma separated list of output file ids", required = false) @DefaultValue("")
@QueryParam ("outputFiles") String outputFiles,
@ApiParam(value = "Skip count", defaultValue = "false") @QueryParam("skipCount") boolean skipCount) {
try {
queryOptions.put(QueryOptions.SKIP_COUNT, skipCount);
if (StringUtils.isNotEmpty(studyId)) {
studyStr = studyId;
}
long studyIdNum = catalogManager.getStudyId(studyStr, sessionId);
// TODO this must be changed: only one queryOptions need to be passed
if (query.containsKey(JobDBAdaptor.QueryParams.NAME.key())
&& (query.get(JobDBAdaptor.QueryParams.NAME.key()) == null
|| query.getString(JobDBAdaptor.QueryParams.NAME.key()).isEmpty())) {
query.remove(JobDBAdaptor.QueryParams.NAME.key());
logger.debug("Name attribute empty, it's been removed");
}
QueryResult<Job> result = catalogManager.getAllJobs(studyIdNum, query, queryOptions, sessionId);
return createOkResponse(result);
} catch (Exception e) {
return createErrorResponse(e);
}
}
@GET
@Path("/{jobId}/visit")
@ApiOperation(value = "Increment job visits", position = 3)
public Response visit(@ApiParam(value = "jobId", required = true) @PathParam("jobId") long jobId) {
try {
return createOkResponse(catalogManager.incJobVisites(jobId, sessionId));
} catch (CatalogException e) {
return createErrorResponse(e);
}
}
@GET
@Path("/{jobIds}/delete")
@ApiOperation(value = "Delete job", position = 4)
public Response delete(@ApiParam(value = "Comma separated list of job ids or names", required = true) @PathParam("jobIds")
String jobIds,
@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias")
@QueryParam("study") String studyStr) {
// @ApiParam(value = "deleteFiles", required = false) @DefaultValue("true")
// @QueryParam("deleteFiles") boolean deleteFiles) {
try {
// QueryOptions options = new QueryOptions(JobManager.DELETE_FILES, deleteFiles);
List<QueryResult<Job>> delete = catalogManager.getJobManager().delete(jobIds, studyStr, queryOptions, sessionId);
return createOkResponse(delete);
} catch (CatalogException | IOException e) {
return createErrorResponse(e);
}
}
@GET
@Path("/groupBy")
@ApiOperation(value = "Group jobs by several fields", position = 10)
public Response groupBy(@ApiParam(value = "Comma separated list of fields by which to group by.", required = true) @DefaultValue("")
@QueryParam("fields") String fields,
@ApiParam(value = "id", required = false) @DefaultValue("") @QueryParam("id") String id,
@ApiParam(value = "DEPRECATED: studyId", hidden = true) @DefaultValue("") @QueryParam("studyId") String studyId,
@ApiParam(value = "Study [[user@]project:]study where study and project can be either the id or alias")
@QueryParam("study") String studyStr,
@ApiParam(value = "name", required = false) @DefaultValue("") @QueryParam("name") String name,
@ApiParam(value = "path", required = false) @DefaultValue("") @QueryParam("path") String path,
@ApiParam(value = "status", required = false) @DefaultValue("") @QueryParam("status") File.FileStatus status,
@ApiParam(value = "ownerId", required = false) @DefaultValue("") @QueryParam("ownerId") String ownerId,
@ApiParam(value = "creationDate", required = false) @DefaultValue("")
@QueryParam("creationDate") String creationDate,
// @ApiParam(value = "modificationDate", required = false) @DefaultValue("")
// @QueryParam("modificationDate") String modificationDate,
@ApiParam(value = "description", required = false) @DefaultValue("")
@QueryParam("description") String description,
@ApiParam(value = "attributes", required = false) @DefaultValue("")
@QueryParam("attributes") String attributes) {
try {
QueryResult result = catalogManager.jobGroupBy(studyStr, query, queryOptions, fields, sessionId);
return createOkResponse(result);
} catch (Exception e) {
return createErrorResponse(e);
}
}
@GET
@Path("/{jobIds}/acl")
@ApiOperation(value = "Return the acl of the job", position = 18)
public Response getAcls(@ApiParam(value = "Comma separated list of job ids", required = true) @PathParam("jobIds") String jobIdsStr) {
try {
return createOkResponse(catalogManager.getAllJobAcls(jobIdsStr, sessionId));
} catch (Exception e) {
return createErrorResponse(e);
}
}
@GET
@Path("/{jobIds}/acl/create")
@ApiOperation(value = "Define a set of permissions for a list of members", hidden = true, position = 19)
public Response createRole(@ApiParam(value = "Comma separated list of job ids", required = true) @PathParam("jobIds") String jobIdsStr,
@ApiParam(value = "Comma separated list of permissions that will be granted to the member list",
required = false) @DefaultValue("") @QueryParam("permissions") String permissions,
@ApiParam(value = "Comma separated list of members. Accepts: '{userId}', '@{groupId}' or '*'",
required = true) @DefaultValue("") @QueryParam("members") String members) {
try {
return createOkResponse(catalogManager.createJobAcls(jobIdsStr, members, permissions, sessionId));
} catch (Exception e) {
return createErrorResponse(e);
}
}
@POST
@Path("/{jobIds}/acl/create")
@ApiOperation(value = "Define a set of permissions for a list of members", position = 19)
public Response createRolePOST(
@ApiParam(value = "Comma separated list of job ids", required = true) @PathParam("jobIds") String jobIdsStr,
@ApiParam(value="JSON containing the parameters defined in GET. Mandatory keys: 'members'", required = true)
StudyWSServer.CreateAclCommands params) {
try {
return createOkResponse(catalogManager.createJobAcls(jobIdsStr, params.members, params.permissions, sessionId));
} catch (Exception e) {
return createErrorResponse(e);
}
}
@GET
@Path("/{jobId}/acl/{memberId}/info")
@ApiOperation(value = "Return the set of permissions granted for the member", position = 20)
public Response getAcl(@ApiParam(value = "jobId", required = true) @PathParam("jobId") String jobIdStr,
@ApiParam(value = "Member id", required = true) @PathParam("memberId") String memberId) {
try {
return createOkResponse(catalogManager.getJobAcl(jobIdStr, memberId, sessionId));
} catch (Exception e) {
return createErrorResponse(e);
}
}
@GET
@Path("/{jobId}/acl/{memberId}/update")
@ApiOperation(value = "Update the set of permissions granted for the member", hidden = true, position = 21)
public Response updateAcl(@ApiParam(value = "jobId", required = true) @PathParam("jobId") String jobIdStr,
@ApiParam(value = "Member id", required = true) @PathParam("memberId") String memberId,
@ApiParam(value = "Comma separated list of permissions to add", required = false)
@QueryParam("add") String addPermissions,
@ApiParam(value = "Comma separated list of permissions to remove", required = false)
@QueryParam("remove") String removePermissions,
@ApiParam(value = "Comma separated list of permissions to set", required = false)
@QueryParam("set") String setPermissions) {
try {
return createOkResponse(catalogManager.updateJobAcl(jobIdStr, memberId, addPermissions, removePermissions, setPermissions,
sessionId));
} catch (Exception e) {
return createErrorResponse(e);
}
}
@POST
@Path("/{jobId}/acl/{memberId}/update")
@ApiOperation(value = "Update the set of permissions granted for the member", position = 21)
public Response updateAclPOST(
@ApiParam(value = "jobId", required = true) @PathParam("jobId") String jobIdStr,
@ApiParam(value = "Member id", required = true) @PathParam("memberId") String memberId,
@ApiParam(value="JSON containing one of the keys 'add', 'set' or 'remove'", required = true)
StudyWSServer.MemberAclUpdate params) {
try {
return createOkResponse(catalogManager.updateJobAcl(jobIdStr, memberId, params.add, params.remove, params.set, sessionId));
} catch (Exception e) {
return createErrorResponse(e);
}
}
@GET
@Path("/{jobIds}/acl/{memberId}/delete")
@ApiOperation(value = "Remove all the permissions granted for the member", position = 22)
public Response deleteAcl(@ApiParam(value = "Comma separated list of job ids", required = true) @PathParam("jobIds") String jobIdsStr,
@ApiParam(value = "Member id", required = true) @PathParam("memberId") String memberId) {
try {
return createOkResponse(catalogManager.removeJobAcl(jobIdsStr, memberId, sessionId));
} catch (Exception e) {
return createErrorResponse(e);
}
}
}