Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
bba6292
core: rename type to scope, #TASK-7610
pfurio Apr 15, 2025
3239350
core: rename Workflow for ExternalTool, #TASK-7610
pfurio Apr 15, 2025
faf3818
wip
pfurio Apr 16, 2025
cdff2b5
catalog: external tool changes compile, #TASK-7610
pfurio Apr 16, 2025
d418ccb
app: add external tool data model migration, #TASK-7610
pfurio May 7, 2025
d55159d
Merge branch 'TASK-7610' of github.com:opencb/opencga into TASK-7610
pfurio May 12, 2025
f7e6e3c
catalog: last changes to ExternalTool, #TASK-7610
pfurio May 15, 2025
4d15716
app: deprecate old migrations, #TASK-7610
pfurio May 15, 2025
b264089
analysis: implement new options from CustomToolExecutor, #TASK-7610
pfurio May 21, 2025
2f47ee8
server: fix generator to support special naming for WS method, #TASK-…
pfurio May 21, 2025
4bab571
server: remove system out print, #TASK-7610
pfurio May 21, 2025
32d8a14
app: enable tools cli, #TASK-7610
pfurio May 21, 2025
8bc76a5
catalog: fix workflow creation issue, #TASK-7610
pfurio May 22, 2025
f8a7a7d
catalog: change scheduler implementation to support queues, #TASK-7442
pfurio Jul 25, 2025
11c5234
core: rename type to processorType, #TASK-7442
pfurio Jul 31, 2025
e8261b2
app: rename ExternalTool category to UserTool, #TASK-7610
pfurio Aug 12, 2025
7028e7c
master: edit k8sExecutor to use queues, #TASK-7442
pfurio Sep 3, 2025
a46805f
master: add correct namespace to k8s, #TASK-7442
pfurio Sep 3, 2025
0799dfa
core: fix type from configuration file, #TASK-7442
pfurio Sep 3, 2025
e807e83
master: fix factory to process queues, #TASK-7442
pfurio Sep 4, 2025
bdc3ed2
catalog: change cpu type from int to String, #TASK-7442
pfurio Sep 5, 2025
373118a
Merge branch 'develop' into TASK-7610
pfurio Sep 5, 2025
89ee41b
Merge branch 'develop' into TASK-7442
pfurio Sep 5, 2025
c53418e
Merge branch 'TASK-7610' into TASK-7442
pfurio Sep 5, 2025
3b9aaab
Merge branch 'develop' into TASK-7442
pfurio Oct 22, 2025
8f90dd1
catalog: improve catalog junit performance tests, #TASK-7442
pfurio Oct 22, 2025
546c47b
catalog: fix configuration test yml, #TASK-7442
pfurio Oct 22, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
package org.opencb.opencga.analysis.customTool;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.opencb.commons.datastore.core.Query;
import org.opencb.commons.datastore.core.QueryOptions;
import org.opencb.opencga.analysis.tools.OpenCgaDockerToolScopeStudy;
import org.opencb.opencga.catalog.db.api.ExternalToolDBAdaptor;
import org.opencb.opencga.catalog.exceptions.CatalogException;
import org.opencb.opencga.core.common.GitRepositoryState;
import org.opencb.opencga.core.common.TimeUtils;
import org.opencb.opencga.core.exceptions.ToolException;
import org.opencb.opencga.core.models.common.Enums;
import org.opencb.opencga.core.models.job.JobRunDockerParams;
import org.opencb.opencga.core.models.job.JobRunParams;
import org.opencb.opencga.core.models.externalTool.*;
import org.opencb.opencga.core.models.job.ToolInfoExecutor;
import org.opencb.opencga.core.response.OpenCGAResult;
import org.opencb.opencga.core.tools.ToolDependency;
import org.opencb.opencga.core.tools.annotations.Tool;
import org.opencb.opencga.core.tools.annotations.ToolParams;
import org.slf4j.Logger;
Expand All @@ -23,11 +30,15 @@ public class CustomToolExecutor extends OpenCgaDockerToolScopeStudy {
public static final String DESCRIPTION = "Execute an analysis from a custom binary.";

@ToolParams
protected JobRunParams runParams = new JobRunParams();
protected ExternalToolRunParams runParams = new ExternalToolRunParams();

private String cliParams;
private String dockerImage;

// Docker credentials
private String username;
private String password;

private final static Logger logger = LoggerFactory.getLogger(CustomToolExecutor.class);

@Override
Expand All @@ -36,44 +47,113 @@ protected void check() throws Exception {

// Check any condition
if (runParams == null) {
throw new ToolException("Missing runParams");
throw new ToolException("Missing ExternalToolRunParams object.");
} else if (StringUtils.isNotEmpty(runParams.getId()) && runParams.getDocker() == null) {
Docker docker = generateDockerObject(runParams);
checkDockerObject(docker);
} else if (runParams.getDocker() != null && StringUtils.isEmpty(runParams.getId())) {
checkDockerObject(runParams.getDocker());
} else {
throw new ToolException("Unexpected ExternalToolRunParams object. "
+ "Either 'id' and 'params/commandLine' or 'docker' should be set.");
}
}

private Docker generateDockerObject(ExternalToolRunParams runParams) throws CatalogException, ToolException {
OpenCGAResult<ExternalTool> result;
if (runParams.getVersion() != null) {
Query query = new Query(ExternalToolDBAdaptor.QueryParams.VERSION.key(), runParams.getVersion());
result = catalogManager.getExternalToolManager().get(study, Collections.singletonList(runParams.getId()), query,
QueryOptions.empty(), false, token);
} else {
result = catalogManager.getExternalToolManager().get(study, runParams.getId(), QueryOptions.empty(), token);
}
if (result.getNumResults() == 0) {
throw new ToolException("Custom tool '" + runParams.getId() + "' not found");
}
ExternalTool externalTool = result.first();

if (externalTool == null) {
throw new ToolException("Custom tool '" + runParams.getId() + "' is null");
}
if (externalTool.getType() != ExternalToolType.CUSTOM_TOOL) {
throw new ToolException("External tool '" + runParams.getId() + "' is not of type " + ExternalToolType.CUSTOM_TOOL);
}
if (externalTool.getDocker() == null) {
throw new ToolException("External tool '" + runParams.getId() + "' does not have a docker object");
}
if (StringUtils.isEmpty(runParams.getCommandLine())) {

Docker docker = externalTool.getDocker();
String commandLine = StringUtils.isNotEmpty(runParams.getCommandLine())
? runParams.getCommandLine()
: docker.getCommandLine();

// Process docker command line to replace variables
Map<String, String> params = new HashMap<>();
if (runParams.getParams() != null) {
params.putAll(runParams.getParams());
}
if (CollectionUtils.isNotEmpty(externalTool.getVariables())) {
for (ExternalToolVariable variable : externalTool.getVariables()) {
String variableId = removePrefix(variable.getId());
if (!params.containsKey(variableId) && StringUtils.isNotEmpty(variable.getDefaultValue())) {
params.put(variableId, variable.getDefaultValue());
}
}
}
String processedCli = inputFileUtils.processCommandLine(study, commandLine, params, temporalInputDir, dockerInputBindings,
getOutDir().toString(), token);
docker.setCommandLine(processedCli);

return docker;
}

private void checkDockerObject(Docker docker) throws ToolException, CatalogException {
if (StringUtils.isEmpty(docker.getCommandLine())) {
throw new ToolException("Missing commandLine");
}
if (runParams.getDocker() == null || StringUtils.isEmpty(runParams.getDocker().getId())) {
runParams.setDocker(new JobRunDockerParams("opencb/opencga-ext-tools", "3.2.1", null));
if (StringUtils.isEmpty(docker.getName())) {
docker.setName("opencb/opencga-ext-tools");
docker.setTag(GitRepositoryState.getInstance().getBuildVersion());
}
if (!runParams.getDocker().getId().contains("/")) {
if (!docker.getName().contains("/")) {
throw new ToolException("Missing repository organization. Format for the docker image should be 'organization/image'");
}
this.dockerImage = runParams.getDocker().getId();
if (StringUtils.isNotEmpty(runParams.getDocker().getTag())) {
this.dockerImage += ":" + runParams.getDocker().getTag();
this.dockerImage = docker.getName();
if (StringUtils.isNotEmpty(docker.getTag())) {
this.dockerImage += ":" + docker.getTag();
}

// Update job tags and attributes
ToolInfoExecutor toolInfoExecutor = new ToolInfoExecutor(runParams.getDocker().getId(), runParams.getDocker().getTag());
ToolInfoExecutor toolInfoExecutor = new ToolInfoExecutor(docker.getName(), docker.getTag());
List<String> tags = new LinkedList<>();
tags.add(ID);
tags.add(this.dockerImage);

List<ToolDependency> dependencyList = new ArrayList<>(1);
dependencyList.add(new ToolDependency(docker.getName(), docker.getTag()));
addDependencies(dependencyList);
updateJobInformation(tags, toolInfoExecutor);

StringBuilder cliParamsBuilder = new StringBuilder();
processInputParams(runParams.getCommandLine(), cliParamsBuilder);
this.cliParams = cliParamsBuilder.toString();
this.cliParams = docker.getCommandLine();
this.username = docker.getUser();
this.password = docker.getPassword();
}

@Override
protected void run() throws Exception {
StopWatch stopWatch = StopWatch.createStarted();

List<AbstractMap.SimpleEntry<String, String>> outputBindings = new ArrayList<>(1);
String outDirPath = getOutDir().toAbsolutePath().toString();
outputBindings.add(new AbstractMap.SimpleEntry<>(outDirPath, outDirPath));

Map<String, String> dockerParams = new HashMap<>();
dockerParams.put("-e", "OPENCGA_TOKEN=" + getExpiringToken());
String cmdline = runDocker(dockerImage, Collections.emptyList(), cliParams, dockerParams);
String cmdline = runDocker(dockerImage, outputBindings, cliParams, dockerParams, null, username, password);

logger.info("Docker command line: " + cmdline);
logger.info("Execution time: " + TimeUtils.durationToString(stopWatch));
logger.info("Docker command line: {}", cmdline);
logger.info("Execution time: {}", TimeUtils.durationToString(stopWatch));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,11 @@ protected String runDocker(String image, AbstractMap.SimpleEntry<String, String>

protected String runDocker(String image, List<AbstractMap.SimpleEntry<String, String>> userOutputBindings, String cmdParams,
Map<String, String> userDockerParams) throws IOException {
return runDocker(image, userOutputBindings, cmdParams, userDockerParams, null, null, null);
}

protected String runDocker(String image, List<AbstractMap.SimpleEntry<String, String>> userOutputBindings, String cmdParams,
Map<String, String> userDockerParams, String registry, String username, String password) throws IOException {
List<AbstractMap.SimpleEntry<String, String>> outputBindings = CollectionUtils.isNotEmpty(userOutputBindings)
? userOutputBindings
: Collections.singletonList(new AbstractMap.SimpleEntry<>(getOutDir().toAbsolutePath().toString(), getOutDir().toAbsolutePath().toString()));
Expand All @@ -169,7 +174,7 @@ protected String runDocker(String image, List<AbstractMap.SimpleEntry<String, St
dockerParams.putAll(userDockerParams);
}

return DockerUtils.run(image, dockerInputBindings, outputBindings, cmdParams, dockerParams);
return DockerUtils.run(image, dockerInputBindings, outputBindings, cmdParams, dockerParams, registry, username, password);
}

}
Loading
Loading