From bdd9cb9148be9a3643114bbfc7ce6289f694716f Mon Sep 17 00:00:00 2001 From: Jaime Date: Wed, 12 Jun 2024 19:34:28 +0200 Subject: [PATCH 1/8] add missing workflow query attribute to properly retrieve labels --- .../java/io/seqera/tower/cli/commands/LaunchCmd.java | 2 +- .../tower/cli/commands/runs/AbstractRunsCmd.java | 10 ++++++++-- .../io/seqera/tower/cli/commands/runs/DumpCmd.java | 5 +++-- .../io/seqera/tower/cli/commands/runs/RelaunchCmd.java | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main/java/io/seqera/tower/cli/commands/LaunchCmd.java b/src/main/java/io/seqera/tower/cli/commands/LaunchCmd.java index ecfbfdf6..cf986b06 100644 --- a/src/main/java/io/seqera/tower/cli/commands/LaunchCmd.java +++ b/src/main/java/io/seqera/tower/cli/commands/LaunchCmd.java @@ -245,7 +245,7 @@ protected Integer onBeforeExit(int exitCode, Response response) { private WorkflowStatus checkWorkflowStatus(String workflowId, Long workspaceId) { try { - return api().describeWorkflow(workflowId, workspaceId, Collections.emptyList()).getWorkflow().getStatus(); + return api().describeWorkflow(workflowId, workspaceId, NO_WORKFLOW_ATTRIBUTES).getWorkflow().getStatus(); } catch (ApiException | NullPointerException e) { return null; } diff --git a/src/main/java/io/seqera/tower/cli/commands/runs/AbstractRunsCmd.java b/src/main/java/io/seqera/tower/cli/commands/runs/AbstractRunsCmd.java index 3c18ce0e..d05b6d96 100644 --- a/src/main/java/io/seqera/tower/cli/commands/runs/AbstractRunsCmd.java +++ b/src/main/java/io/seqera/tower/cli/commands/runs/AbstractRunsCmd.java @@ -28,16 +28,22 @@ import io.seqera.tower.model.GetProgressResponse; import io.seqera.tower.model.Launch; import io.seqera.tower.model.WorkflowLoad; +import io.seqera.tower.model.WorkflowQueryAttribute; import picocli.CommandLine.Command; +import java.util.List; + @Command abstract public class AbstractRunsCmd extends AbstractApiCmd { public AbstractRunsCmd() { } - protected DescribeWorkflowResponse workflowById(Long workspaceId, String id) throws ApiException { - DescribeWorkflowResponse workflowResponse = api().describeWorkflow(id, workspaceId, NO_WORKFLOW_ATTRIBUTES); + protected DescribeWorkflowResponse workflowById(Long workspaceId, String id, List extraQueryAttributes) throws ApiException { + + List wfQueryAttrs = (extraQueryAttributes == null) ? NO_WORKFLOW_ATTRIBUTES : extraQueryAttributes; + + DescribeWorkflowResponse workflowResponse = api().describeWorkflow(id, workspaceId, wfQueryAttrs); if (workflowResponse == null) { throw new RunNotFoundException(id, workspaceRef(workspaceId)); diff --git a/src/main/java/io/seqera/tower/cli/commands/runs/DumpCmd.java b/src/main/java/io/seqera/tower/cli/commands/runs/DumpCmd.java index 2037c9f2..525891af 100644 --- a/src/main/java/io/seqera/tower/cli/commands/runs/DumpCmd.java +++ b/src/main/java/io/seqera/tower/cli/commands/runs/DumpCmd.java @@ -37,6 +37,7 @@ import io.seqera.tower.model.Workflow; import io.seqera.tower.model.WorkflowLoad; import io.seqera.tower.model.WorkflowMetrics; +import io.seqera.tower.model.WorkflowQueryAttribute; import org.apache.commons.compress.archivers.tar.TarArchiveEntry; import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream; import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream; @@ -169,8 +170,8 @@ private void dumpTasks(PrintWriter progress, TarArchiveOutputStream out, Long ws private void dumpWorkflowDetails(PrintWriter progress, TarArchiveOutputStream out, Long wspId) throws ApiException, IOException { progress.println(ansi("- Workflow details")); - // General workflow info - DescribeWorkflowResponse workflowResponse = workflowById(wspId, id); + // General workflow info (including labels) + DescribeWorkflowResponse workflowResponse = workflowById(wspId, id, List.of(WorkflowQueryAttribute.LABELS)); Workflow workflow = workflowResponse.getWorkflow(); if (workflow == null) { throw new TowerException("Unknown workflow"); diff --git a/src/main/java/io/seqera/tower/cli/commands/runs/RelaunchCmd.java b/src/main/java/io/seqera/tower/cli/commands/runs/RelaunchCmd.java index 6091de01..0e9fcd8a 100644 --- a/src/main/java/io/seqera/tower/cli/commands/runs/RelaunchCmd.java +++ b/src/main/java/io/seqera/tower/cli/commands/runs/RelaunchCmd.java @@ -75,7 +75,7 @@ protected Response exec() throws ApiException, IOException { throw new TowerException("Not allowed to change '--work-dir' option when resuming. Use '--no-resume' if you want to relaunch into a different working directory without resuming."); } - Workflow workflow = workflowById(wspId, id).getWorkflow(); + Workflow workflow = workflowById(wspId, id, NO_WORKFLOW_ATTRIBUTES).getWorkflow(); WorkflowLaunchResponse launch = workflowLaunchResponse(workflow.getId(), wspId); ComputeEnvResponseDto ce = null; From 5a2e4134e57e6988a7f3b0cf73a6ebbd2526599c Mon Sep 17 00:00:00 2001 From: Jaime Date: Tue, 18 Jun 2024 17:16:46 +0200 Subject: [PATCH 2/8] retrieve optimization status along with workflow labels --- .../java/io/seqera/tower/cli/commands/runs/DumpCmd.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/seqera/tower/cli/commands/runs/DumpCmd.java b/src/main/java/io/seqera/tower/cli/commands/runs/DumpCmd.java index 525891af..844c6a53 100644 --- a/src/main/java/io/seqera/tower/cli/commands/runs/DumpCmd.java +++ b/src/main/java/io/seqera/tower/cli/commands/runs/DumpCmd.java @@ -170,8 +170,10 @@ private void dumpTasks(PrintWriter progress, TarArchiveOutputStream out, Long ws private void dumpWorkflowDetails(PrintWriter progress, TarArchiveOutputStream out, Long wspId) throws ApiException, IOException { progress.println(ansi("- Workflow details")); - // General workflow info (including labels) - DescribeWorkflowResponse workflowResponse = workflowById(wspId, id, List.of(WorkflowQueryAttribute.LABELS)); + // General workflow info including: + // + labels + // + optimization status + DescribeWorkflowResponse workflowResponse = workflowById(wspId, id, List.of(WorkflowQueryAttribute.LABELS, WorkflowQueryAttribute.OPTIMIZED)); Workflow workflow = workflowResponse.getWorkflow(); if (workflow == null) { throw new TowerException("Unknown workflow"); From 170d0d873f863b3878ece651d7c10f9078d23420 Mon Sep 17 00:00:00 2001 From: Jaime Date: Tue, 18 Jun 2024 19:18:03 +0200 Subject: [PATCH 3/8] omit optimization data if flag is set --- src/main/java/io/seqera/tower/cli/commands/LaunchCmd.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/seqera/tower/cli/commands/LaunchCmd.java b/src/main/java/io/seqera/tower/cli/commands/LaunchCmd.java index cf986b06..93c27179 100644 --- a/src/main/java/io/seqera/tower/cli/commands/LaunchCmd.java +++ b/src/main/java/io/seqera/tower/cli/commands/LaunchCmd.java @@ -161,8 +161,8 @@ private WorkflowLaunchRequest updateLaunchRequest(WorkflowLaunchRequest base) th .schemaName(coalesce(adv().schemaName, base.getSchemaName())) .pullLatest(coalesce(adv().pullLatest, base.getPullLatest())) .stubRun(coalesce(adv().stubRun, base.getStubRun())) - .optimizationId(base.getOptimizationId()) - .optimizationTargets(base.getOptimizationTargets()) + .optimizationId(coalesce(adv().disableOptimization, false) ? null : base.getOptimizationId()) + .optimizationTargets(coalesce(adv().disableOptimization, false) ? null : base.getOptimizationTargets()) .labelIds(base.getLabelIds()) .headJobCpus(base.getHeadJobCpus()) .headJobMemoryMb(base.getHeadJobMemoryMb()); @@ -373,6 +373,9 @@ public static class AdvancedOptions { @Option(names = {"--workspace-secrets"}, split = ",", description = "Pipeline Secrets required by the pipeline execution. Those secrets must be defined in the launching workspace.") public List workspaceSecrets; + @Option(names = {"--disable-optimization"}, description = "Turn off the optimization for the pipeline before launching.") + public Boolean disableOptimization; + } } From 93c2c0d4381dce03fefaf797c57537c600473282 Mon Sep 17 00:00:00 2001 From: Jaime Date: Tue, 18 Jun 2024 19:19:44 +0200 Subject: [PATCH 4/8] update tests with optimization data --- .../io/seqera/tower/cli/LaunchCmdTest.java | 222 +++++++++++++++--- .../runcmd/pipeline_launch_describe.json | 4 +- .../resources/runcmd/pipelines_sarek.json | 3 + 3 files changed, 200 insertions(+), 29 deletions(-) diff --git a/src/test/java/io/seqera/tower/cli/LaunchCmdTest.java b/src/test/java/io/seqera/tower/cli/LaunchCmdTest.java index 97834e65..7a6598d2 100644 --- a/src/test/java/io/seqera/tower/cli/LaunchCmdTest.java +++ b/src/test/java/io/seqera/tower/cli/LaunchCmdTest.java @@ -98,7 +98,22 @@ void testSubmitLaunchpadPipeline(OutputType format, MockServerClient mock) { ); mock.when( - request().withMethod("POST").withPath("/workflow/launch").withBody("{\"launch\":{\"id\":\"5nmCvXcarkvv8tELMF4KyY\",\"computeEnvId\":\"4X7YrYJp9B1d1DUpfur7DS\",\"pipeline\":\"https://github.com/nf-core/sarek\",\"workDir\":\"/efs\",\"pullLatest\":false,\"stubRun\":false}}"), exactly(1) + request().withMethod("POST").withPath("/workflow/launch") + .withBody(json(""" + { + "launch":{ + "id":"5nmCvXcarkvv8tELMF4KyY", + "computeEnvId":"4X7YrYJp9B1d1DUpfur7DS", + "pipeline":"https://github.com/nf-core/sarek", + "workDir":"/efs", + "pullLatest":false, + "stubRun":false, + "optimizationId": "rOYdwTnmTaRCJjUq", + "optimizationTargets": "cpus, memory" + } + }""" + )), + exactly(1) ).respond( response().withStatusCode(200).withBody(loadResource("workflow_launch")).withContentType(MediaType.APPLICATION_JSON) ); @@ -166,7 +181,27 @@ void testSubmitLaunchpadPipelineWithAdvancedOptions(MockServerClient mock) throw ); mock.when( - request().withMethod("POST").withPath("/workflow/launch").withBody("{\"launch\":{\"id\":\"5nmCvXcarkvv8tELMF4KyY\",\"computeEnvId\":\"4X7YrYJp9B1d1DUpfur7DS\",\"pipeline\":\"https://github.com/nf-core/sarek\",\"workDir\":\"/my_work_dir\",\"revision\":\"develop\",\"configProfiles\":[\"test\",\"docker\"],\"configText\":\"extra_config\",\"preRunScript\":\"pre_run_me\",\"postRunScript\":\"post_run_me\",\"mainScript\":\"alternate.nf\",\"entryName\":\"dsl2\",\"schemaName\":\"my_schema.json\",\"pullLatest\":true,\"stubRun\":true}}"), exactly(1) + request().withMethod("POST").withPath("/workflow/launch") + .withBody(json(""" + { + "launch":{ + "id":"5nmCvXcarkvv8tELMF4KyY", + "computeEnvId":"4X7YrYJp9B1d1DUpfur7DS", + "pipeline":"https://github.com/nf-core/sarek", + "workDir":"/my_work_dir", + "revision":"develop", + "configProfiles":["test","docker"], + "configText":"extra_config", + "preRunScript":"pre_run_me", + "postRunScript":"post_run_me", + "mainScript":"alternate.nf", + "entryName":"dsl2", + "schemaName":"my_schema.json", + "pullLatest":true, + "stubRun":true + }}""" + )), + exactly(1) ).respond( response().withStatusCode(200).withBody(loadResource("workflow_launch")).withContentType(MediaType.APPLICATION_JSON) ); @@ -207,7 +242,24 @@ void testSubmitLaunchpadPipelineWithCustomName(OutputType format, MockServerClie ); mock.when( - request().withMethod("POST").withPath("/workflow/launch").withBody("{\"launch\":{\"id\":\"5nmCvXcarkvv8tELMF4KyY\",\"computeEnvId\":\"4X7YrYJp9B1d1DUpfur7DS\",\"runName\":\"custom_run_name\",\"pipeline\":\"https://github.com/nf-core/sarek\",\"workDir\":\"/efs\",\"pullLatest\":false,\"stubRun\":false}}"), exactly(1) + request().withMethod("POST").withPath("/workflow/launch") + .withBody(json(""" + { + "launch":{ + "id":"5nmCvXcarkvv8tELMF4KyY", + "computeEnvId":"4X7YrYJp9B1d1DUpfur7DS", + "runName":"custom_run_name", + "pipeline":"https://github.com/nf-core/sarek", + "workDir":"/efs", + "pullLatest":false, + "stubRun":false, + "optimizationId": "rOYdwTnmTaRCJjUq", + "optimizationTargets": "cpus, memory" + + } + }""" + )), + exactly(1) ).respond( response().withStatusCode(200).withBody(loadResource("workflow_launch")).withContentType(MediaType.APPLICATION_JSON) ); @@ -246,21 +298,25 @@ void testSubmitLaunchpadPipelineWithLabels(OutputType format, MockServerClient m request() .withMethod("POST") .withPath("/labels") - .withBody(json(" {\n" + - " \"name\": \"LabelThree\",\n" + - " \"resource\": false,\n" + - " \"isDefault\": false\n" + - " }\n")), + .withBody(json(""" + { + "name": "LabelThree", + "resource": false, + "isDefault": false + } + """)), exactly(1) ).respond( response() .withStatusCode(200) - .withBody(json("{\n" + - " \"id\": 3,\n" + - " \"name\": \"LabelThree\",\n" + - " \"resource\": false,\n" + - " \"isDefault\": false\n" + - "}\n")) + .withBody(json(""" + { + "id": 3, + "name": "LabelThree", + "resource": false, + "isDefault": false + } + """)) .withContentType(MediaType.APPLICATION_JSON) ); @@ -282,17 +338,19 @@ void testSubmitLaunchpadPipelineWithLabels(OutputType format, MockServerClient m request() .withMethod("POST") .withPath("/workflow/launch") - .withBody(json(" {\n" + - " \"launch\":{\n" + - " \"id\":\"5nmCvXcarkvv8tELMF4KyY\",\n" + - " \"computeEnvId\":\"4X7YrYJp9B1d1DUpfur7DS\",\n" + - " \"pipeline\":\"https://github.com/nf-core/sarek\",\n" + - " \"workDir\":\"/efs\",\n" + - " \"pullLatest\":false,\n" + - " \"stubRun\":false,\n" + - " \"labelIds\": [2, 3]\n" + - " }\n" + - " }\n")), + .withBody(json(""" + { + "launch":{ + "id":"5nmCvXcarkvv8tELMF4KyY", + "computeEnvId":"4X7YrYJp9B1d1DUpfur7DS", + "pipeline":"https://github.com/nf-core/sarek", + "workDir":"/efs", + "pullLatest":false, + "stubRun":false, + "labelIds": [2, 3] + } + } + """)), exactly(1) ).respond( response().withStatusCode(200).withBody(loadResource("workflow_launch")).withContentType(MediaType.APPLICATION_JSON) @@ -317,13 +375,100 @@ void testSubmitToAWorkspace(MockServerClient mock) { mock.when( request().withMethod("GET").withPath("/compute-envs").withQueryStringParameter("status", "AVAILABLE").withQueryStringParameter("workspaceId", "222756650686576"), exactly(1) ).respond( - response().withStatusCode(200).withBody("{\"computeEnvs\":[{\"id\":\"4iqCDE6C2Stq0jzBsHJvHn\",\"name\":\"aws\",\"platform\":\"aws-batch\",\"status\":\"AVAILABLE\",\"message\":null,\"lastUsed\":null,\"primary\":true,\"workspaceName\":\"cli\",\"visibility\":\"PRIVATE\"}]}").withContentType(MediaType.APPLICATION_JSON) + response().withStatusCode(200) + .withBody(""" + { + "computeEnvs":[ + { + "id":"4iqCDE6C2Stq0jzBsHJvHn", + "name":"aws", + "platform":"aws-batch", + "status":"AVAILABLE", + "message":null, + "lastUsed":null, + "primary":true, + "workspaceName":"cli", + "visibility":"PRIVATE" + } + ] + }""" + ) + .withContentType(MediaType.APPLICATION_JSON) ); mock.when( request().withMethod("GET").withPath("/compute-envs/4iqCDE6C2Stq0jzBsHJvHn").withQueryStringParameter("workspaceId", "222756650686576"), exactly(1) ).respond( - response().withStatusCode(200).withBody("{\"computeEnv\":{\"id\":\"4iqCDE6C2Stq0jzBsHJvHn\",\"name\":\"aws\",\"description\":null,\"platform\":\"aws-batch\",\"config\":{\"region\":\"eu-west-1\",\"computeQueue\":\"TowerForge-4iqCDE6C2Stq0jzBsHJvHn-work\",\"computeJobRole\":null,\"headQueue\":\"TowerForge-4iqCDE6C2Stq0jzBsHJvHn-head\",\"headJobRole\":null,\"cliPath\":\"/home/ec2-user/miniconda/bin/aws\",\"volumes\":[],\"workDir\":\"s3://nextflow-ci/jordeu\",\"preRunScript\":null,\"postRunScript\":null,\"headJobCpus\":null,\"headJobMemoryMb\":null,\"forge\":{\"type\":\"SPOT\",\"minCpus\":0,\"maxCpus\":123,\"gpuEnabled\":false,\"ebsAutoScale\":true,\"instanceTypes\":[],\"allocStrategy\":null,\"imageId\":null,\"vpcId\":null,\"subnets\":[],\"securityGroups\":[],\"fsxMount\":null,\"fsxName\":null,\"fsxSize\":null,\"disposeOnDeletion\":true,\"ec2KeyPair\":null,\"allowBuckets\":[],\"ebsBlockSize\":null,\"fusionEnabled\":false,\"bidPercentage\":null,\"efsCreate\":false,\"efsId\":null,\"efsMount\":null},\"forgedResources\":[{\"IamRole\":\"arn:aws:iam::195996028523:role/TowerForge-4iqCDE6C2Stq0jzBsHJvHn-ServiceRole\"},{\"IamRole\":\"arn:aws:iam::195996028523:role/TowerForge-4iqCDE6C2Stq0jzBsHJvHn-FleetRole\"},{\"IamInstanceProfile\":\"arn:aws:iam::195996028523:instance-profile/TowerForge-4iqCDE6C2Stq0jzBsHJvHn-InstanceRole\"},{\"Ec2LaunchTemplate\":\"TowerForge-4iqCDE6C2Stq0jzBsHJvHn\"},{\"BatchEnv\":\"arn:aws:batch:eu-west-1:195996028523:compute-environment/TowerForge-4iqCDE6C2Stq0jzBsHJvHn-head\"},{\"BatchQueue\":\"arn:aws:batch:eu-west-1:195996028523:job-queue/TowerForge-4iqCDE6C2Stq0jzBsHJvHn-head\"},{\"BatchEnv\":\"arn:aws:batch:eu-west-1:195996028523:compute-environment/TowerForge-4iqCDE6C2Stq0jzBsHJvHn-work\"},{\"BatchQueue\":\"arn:aws:batch:eu-west-1:195996028523:job-queue/TowerForge-4iqCDE6C2Stq0jzBsHJvHn-work\"}],\"discriminator\":\"aws-batch\"},\"dateCreated\":\"2021-09-09T08:53:37Z\",\"lastUpdated\":\"2021-09-09T08:54:13Z\",\"lastUsed\":null,\"deleted\":null,\"status\":\"AVAILABLE\",\"message\":null,\"primary\":null,\"credentialsId\":\"3WzBlcFy1nSE9dSqFT1xPS\"}}").withContentType(MediaType.APPLICATION_JSON) + response().withStatusCode(200) + .withBody(""" + { + "computeEnv":{ + "id":"4iqCDE6C2Stq0jzBsHJvHn", + "name":"aws", + "description":null, + "platform":"aws-batch", + "config":{ + "region":"eu-west-1", + "computeQueue":"TowerForge-4iqCDE6C2Stq0jzBsHJvHn-work", + "computeJobRole":null, + "headQueue":"TowerForge-4iqCDE6C2Stq0jzBsHJvHn-head", + "headJobRole":null, + "cliPath":"/home/ec2-user/miniconda/bin/aws", + "volumes":[], + "workDir":"s3://nextflow-ci/jordeu", + "preRunScript":null, + "postRunScript":null, + "headJobCpus":null, + "headJobMemoryMb":null, + "forge":{ + "type":"SPOT", + "minCpus":0, + "maxCpus":123, + "gpuEnabled":false, + "ebsAutoScale":true, + "instanceTypes":[], + "allocStrategy":null, + "imageId":null, + "vpcId":null, + "subnets":[], + "securityGroups":[], + "fsxMount":null, + "fsxName":null, + "fsxSize":null, + "disposeOnDeletion":true, + "ec2KeyPair":null, + "allowBuckets":[], + "ebsBlockSize":null, + "fusionEnabled":false, + "bidPercentage":null, + "efsCreate":false, + "efsId":null, + "efsMount":null + }, + "forgedResources":[ + {"IamRole":"arn:aws:iam::195996028523:role/TowerForge-4iqCDE6C2Stq0jzBsHJvHn-ServiceRole"}, + {"IamRole":"arn:aws:iam::195996028523:role/TowerForge-4iqCDE6C2Stq0jzBsHJvHn-FleetRole"}, + {"IamInstanceProfile":"arn:aws:iam::195996028523:instance-profile/TowerForge-4iqCDE6C2Stq0jzBsHJvHn-InstanceRole"}, + {"Ec2LaunchTemplate":"TowerForge-4iqCDE6C2Stq0jzBsHJvHn"}, + {"BatchEnv":"arn:aws:batch:eu-west-1:195996028523:compute-environment/TowerForge-4iqCDE6C2Stq0jzBsHJvHn-head"}, + {"BatchQueue":"arn:aws:batch:eu-west-1:195996028523:job-queue/TowerForge-4iqCDE6C2Stq0jzBsHJvHn-head"}, + {"BatchEnv":"arn:aws:batch:eu-west-1:195996028523:compute-environment/TowerForge-4iqCDE6C2Stq0jzBsHJvHn-work"}, + {"BatchQueue":"arn:aws:batch:eu-west-1:195996028523:job-queue/TowerForge-4iqCDE6C2Stq0jzBsHJvHn-work"} + ], + "discriminator":"aws-batch" + }, + "dateCreated":"2021-09-09T08:53:37Z", + "lastUpdated":"2021-09-09T08:54:13Z", + "lastUsed":null, + "deleted":null, + "status":"AVAILABLE", + "message":null, + "primary":null, + "credentialsId":"3WzBlcFy1nSE9dSqFT1xPS" + } + }""" + ) + .withContentType(MediaType.APPLICATION_JSON) ); mock.when( @@ -341,7 +486,28 @@ void testSubmitToAWorkspace(MockServerClient mock) { mock.when( request().withMethod("GET").withPath("/user/1264/workspaces"), exactly(1) ).respond( - response().withStatusCode(200).withBody("{\"orgsAndWorkspaces\":[{\"orgId\":166815615776895,\"name\":\"Seqera\",\"orgLogoUrl\":null,\"workspaceId\":null,\"workspaceName\":null},{\"orgId\":166815615776895,\"orgName\":\"Seqera\",\"orgLogoUrl\":null,\"workspaceId\":222756650686576,\"workspaceName\":\"cli\"}]}").withContentType(MediaType.APPLICATION_JSON) + response().withStatusCode(200) + .withBody(""" + { + "orgsAndWorkspaces":[ + { + "orgId":166815615776895, + "name":"Seqera", + "orgLogoUrl":null, + "workspaceId":null, + "workspaceName":null + }, + { + "orgId":166815615776895, + "orgName":"Seqera", + "orgLogoUrl":null, + "workspaceId":222756650686576, + "workspaceName":"cli" + } + ] + }""" + ) + .withContentType(MediaType.APPLICATION_JSON) ); // Run the command diff --git a/src/test/resources/runcmd/pipeline_launch_describe.json b/src/test/resources/runcmd/pipeline_launch_describe.json index c7cf1861..979fe200 100644 --- a/src/test/resources/runcmd/pipeline_launch_describe.json +++ b/src/test/resources/runcmd/pipeline_launch_describe.json @@ -97,6 +97,8 @@ "schemaName": null, "sessionId": null, "stubRun": false, - "workDir": "/efs" + "workDir": "/efs", + "optimizationId": "rOYdwTnmTaRCJjUq", + "optimizationTargets": "cpus, memory" } } \ No newline at end of file diff --git a/src/test/resources/runcmd/pipelines_sarek.json b/src/test/resources/runcmd/pipelines_sarek.json index ff5fbdac..cfd7fb5d 100644 --- a/src/test/resources/runcmd/pipelines_sarek.json +++ b/src/test/resources/runcmd/pipelines_sarek.json @@ -12,6 +12,9 @@ "organizationName": null, "workspaceName": null, "visibility": null, + "optimizationId": "rOYdwTnmTaRCJjUq", + "optimizationTargets": "cpus, memory", + "optimizationStatus": "OPTIMIZED", "newUnknownAttribute": "check that in the future to add a new attribute doesn't affect old versions" } ], From d4598299e373ae0856a153d943365018d324e397 Mon Sep 17 00:00:00 2001 From: Jaime Date: Tue, 18 Jun 2024 19:21:01 +0200 Subject: [PATCH 5/8] test for disabling optimization --- .../io/seqera/tower/cli/LaunchCmdTest.java | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/src/test/java/io/seqera/tower/cli/LaunchCmdTest.java b/src/test/java/io/seqera/tower/cli/LaunchCmdTest.java index 7a6598d2..b6044f2f 100644 --- a/src/test/java/io/seqera/tower/cli/LaunchCmdTest.java +++ b/src/test/java/io/seqera/tower/cli/LaunchCmdTest.java @@ -216,7 +216,7 @@ void testSubmitLaunchpadPipelineWithAdvancedOptions(MockServerClient mock) throw ExecOut out = exec(mock, "launch", "sarek", "-p", "test,docker", "-r", "develop", "--work-dir", "/my_work_dir", "--config", tempFile("extra_config", "nextflow", "config"), "--pull-latest", "--stub-run", "--pre-run", tempFile("pre_run_me", "pre", "sh"), "--post-run", tempFile("post_run_me", "post", "sh"), - "--main-script", "alternate.nf", "--entry-name", "dsl2", "--schema-name", "my_schema.json"); + "--main-script", "alternate.nf", "--entry-name", "dsl2", "--schema-name", "my_schema.json", "--disable-optimization"); // Assert results assertEquals("", out.stdErr); @@ -519,4 +519,62 @@ void testSubmitToAWorkspace(MockServerClient mock) { assertEquals(0, out.exitCode); } + @ParameterizedTest + @EnumSource(OutputType.class) + void testSubmitLaunchpadPipelineWithOptimizationDisabled(OutputType format, MockServerClient mock) { + + // Create server expectation + mock.when( + request().withMethod("GET").withPath("/pipelines"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("pipelines_sarek")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("GET").withPath("/pipelines/250911634275687/launch"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("pipeline_launch_describe")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("POST").withPath("/workflow/launch") + .withBody(json(""" + { + "launch":{ + "id":"5nmCvXcarkvv8tELMF4KyY", + "computeEnvId":"4X7YrYJp9B1d1DUpfur7DS", + "runName":"custom_run_name", + "pipeline":"https://github.com/nf-core/sarek", + "workDir":"/efs", + "pullLatest":false, + "stubRun":false + } + }""" + )), + exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("workflow_launch")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("GET").withPath("/user-info"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("user")).withContentType(MediaType.APPLICATION_JSON) + ); + + // Run the command + ExecOut out = exec(format, mock, + "launch", "sarek", + "-n", "custom_run_name", + /* + NOTE: when setting this flag, the 'launch.optimizationId' and 'launch.optimizationTargets' fields + in the POST request should be null, and therefore are not present in the mock JSON body expectation. + */ + "--disable-optimization" + ); + + // Assert results + assertOutput(format, out, new RunSubmited("35aLiS0bIM5efd", null, baseUserUrl(mock, "jordi"), USER_WORKSPACE_NAME)); + } + } From a7ac8705b7b57b9d260277552b842a97de71747a Mon Sep 17 00:00:00 2001 From: Jaime Date: Tue, 18 Jun 2024 19:22:05 +0200 Subject: [PATCH 6/8] update reflection files --- conf/reflect-config.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/conf/reflect-config.json b/conf/reflect-config.json index 8b78e101..382dfdb8 100644 --- a/conf/reflect-config.json +++ b/conf/reflect-config.json @@ -2106,7 +2106,7 @@ "allDeclaredFields":true, "allDeclaredMethods":true, "allDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":[] }, {"name":"getCliPath","parameterTypes":[] }, {"name":"getComputeJobRole","parameterTypes":[] }, {"name":"getComputeQueue","parameterTypes":[] }, {"name":"getDiscriminator","parameterTypes":[] }, {"name":"getDragenQueue","parameterTypes":[] }, {"name":"getEnvironment","parameterTypes":[] }, {"name":"getExecutionRole","parameterTypes":[] }, {"name":"getForge","parameterTypes":[] }, {"name":"getForgedResources","parameterTypes":[] }, {"name":"getFusion2Enabled","parameterTypes":[] }, {"name":"getHeadJobCpus","parameterTypes":[] }, {"name":"getHeadJobMemoryMb","parameterTypes":[] }, {"name":"getHeadJobRole","parameterTypes":[] }, {"name":"getHeadQueue","parameterTypes":[] }, {"name":"getLogGroup","parameterTypes":[] }, {"name":"getNvnmeStorageEnabled","parameterTypes":[] }, {"name":"getPostRunScript","parameterTypes":[] }, {"name":"getPreRunScript","parameterTypes":[] }, {"name":"getRegion","parameterTypes":[] }, {"name":"getVolumes","parameterTypes":[] }, {"name":"getWaveEnabled","parameterTypes":[] }, {"name":"getWorkDir","parameterTypes":[] }, {"name":"setCliPath","parameterTypes":["java.lang.String"] }, {"name":"setComputeJobRole","parameterTypes":["java.lang.String"] }, {"name":"setComputeQueue","parameterTypes":["java.lang.String"] }, {"name":"setDragenQueue","parameterTypes":["java.lang.String"] }, {"name":"setEnvironment","parameterTypes":["java.util.List"] }, {"name":"setExecutionRole","parameterTypes":["java.lang.String"] }, {"name":"setForge","parameterTypes":["io.seqera.tower.model.ForgeConfig"] }, {"name":"setForgedResources","parameterTypes":["java.util.List"] }, {"name":"setFusion2Enabled","parameterTypes":["java.lang.Boolean"] }, {"name":"setHeadJobCpus","parameterTypes":["java.lang.Integer"] }, {"name":"setHeadJobMemoryMb","parameterTypes":["java.lang.Integer"] }, {"name":"setHeadJobRole","parameterTypes":["java.lang.String"] }, {"name":"setHeadQueue","parameterTypes":["java.lang.String"] }, {"name":"setLogGroup","parameterTypes":["java.lang.String"] }, {"name":"setNvnmeStorageEnabled","parameterTypes":["java.lang.Boolean"] }, {"name":"setPostRunScript","parameterTypes":["java.lang.String"] }, {"name":"setPreRunScript","parameterTypes":["java.lang.String"] }, {"name":"setRegion","parameterTypes":["java.lang.String"] }, {"name":"setVolumes","parameterTypes":["java.util.List"] }, {"name":"setWaveEnabled","parameterTypes":["java.lang.Boolean"] }, {"name":"setWorkDir","parameterTypes":["java.lang.String"] }] + "methods":[{"name":"","parameterTypes":[] }, {"name":"getCliPath","parameterTypes":[] }, {"name":"getComputeJobRole","parameterTypes":[] }, {"name":"getComputeQueue","parameterTypes":[] }, {"name":"getDiscriminator","parameterTypes":[] }, {"name":"getDragenQueue","parameterTypes":[] }, {"name":"getEnvironment","parameterTypes":[] }, {"name":"getExecutionRole","parameterTypes":[] }, {"name":"getForge","parameterTypes":[] }, {"name":"getForgedResources","parameterTypes":[] }, {"name":"getFusion2Enabled","parameterTypes":[] }, {"name":"getHeadJobCpus","parameterTypes":[] }, {"name":"getHeadJobMemoryMb","parameterTypes":[] }, {"name":"getHeadJobRole","parameterTypes":[] }, {"name":"getHeadQueue","parameterTypes":[] }, {"name":"getLogGroup","parameterTypes":[] }, {"name":"getNvnmeStorageEnabled","parameterTypes":[] }, {"name":"getPostRunScript","parameterTypes":[] }, {"name":"getPreRunScript","parameterTypes":[] }, {"name":"getRegion","parameterTypes":[] }, {"name":"getVolumes","parameterTypes":[] }, {"name":"getWaveEnabled","parameterTypes":[] }, {"name":"getWorkDir","parameterTypes":[] }, {"name":"setCliPath","parameterTypes":["java.lang.String"] }, {"name":"setComputeJobRole","parameterTypes":["java.lang.String"] }, {"name":"setComputeQueue","parameterTypes":["java.lang.String"] }, {"name":"setDragenInstanceType","parameterTypes":["java.lang.String"] }, {"name":"setDragenQueue","parameterTypes":["java.lang.String"] }, {"name":"setEnvironment","parameterTypes":["java.util.List"] }, {"name":"setExecutionRole","parameterTypes":["java.lang.String"] }, {"name":"setForge","parameterTypes":["io.seqera.tower.model.ForgeConfig"] }, {"name":"setForgedResources","parameterTypes":["java.util.List"] }, {"name":"setFusion2Enabled","parameterTypes":["java.lang.Boolean"] }, {"name":"setHeadJobCpus","parameterTypes":["java.lang.Integer"] }, {"name":"setHeadJobMemoryMb","parameterTypes":["java.lang.Integer"] }, {"name":"setHeadJobRole","parameterTypes":["java.lang.String"] }, {"name":"setHeadQueue","parameterTypes":["java.lang.String"] }, {"name":"setLogGroup","parameterTypes":["java.lang.String"] }, {"name":"setNvnmeStorageEnabled","parameterTypes":["java.lang.Boolean"] }, {"name":"setPostRunScript","parameterTypes":["java.lang.String"] }, {"name":"setPreRunScript","parameterTypes":["java.lang.String"] }, {"name":"setRegion","parameterTypes":["java.lang.String"] }, {"name":"setVolumes","parameterTypes":["java.util.List"] }, {"name":"setWaveEnabled","parameterTypes":["java.lang.Boolean"] }, {"name":"setWorkDir","parameterTypes":["java.lang.String"] }] }, { "name":"io.seqera.tower.model.AwsSecurityKeys", @@ -2465,7 +2465,7 @@ "allDeclaredFields":true, "allDeclaredMethods":true, "allDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":[] }, {"name":"getAllocStrategy","parameterTypes":[] }, {"name":"getAllowBuckets","parameterTypes":[] }, {"name":"getArm64Enabled","parameterTypes":[] }, {"name":"getBidPercentage","parameterTypes":[] }, {"name":"getDisposeOnDeletion","parameterTypes":[] }, {"name":"getDragenAmiId","parameterTypes":[] }, {"name":"getDragenEnabled","parameterTypes":[] }, {"name":"getEbsAutoScale","parameterTypes":[] }, {"name":"getEbsBlockSize","parameterTypes":[] }, {"name":"getEbsBootSize","parameterTypes":[] }, {"name":"getEc2KeyPair","parameterTypes":[] }, {"name":"getEcsConfig","parameterTypes":[] }, {"name":"getEfsCreate","parameterTypes":[] }, {"name":"getEfsId","parameterTypes":[] }, {"name":"getEfsMount","parameterTypes":[] }, {"name":"getFargateHeadEnabled","parameterTypes":[] }, {"name":"getFsxMount","parameterTypes":[] }, {"name":"getFsxName","parameterTypes":[] }, {"name":"getFsxSize","parameterTypes":[] }, {"name":"getFusionEnabled","parameterTypes":[] }, {"name":"getGpuEnabled","parameterTypes":[] }, {"name":"getImageId","parameterTypes":[] }, {"name":"getInstanceTypes","parameterTypes":[] }, {"name":"getMaxCpus","parameterTypes":[] }, {"name":"getMinCpus","parameterTypes":[] }, {"name":"getSecurityGroups","parameterTypes":[] }, {"name":"getSubnets","parameterTypes":[] }, {"name":"getType","parameterTypes":[] }, {"name":"getVpcId","parameterTypes":[] }, {"name":"setAllocStrategy","parameterTypes":["io.seqera.tower.model.ForgeConfig$AllocStrategyEnum"] }, {"name":"setAllowBuckets","parameterTypes":["java.util.List"] }, {"name":"setArm64Enabled","parameterTypes":["java.lang.Boolean"] }, {"name":"setBidPercentage","parameterTypes":["java.lang.Integer"] }, {"name":"setDisposeOnDeletion","parameterTypes":["java.lang.Boolean"] }, {"name":"setDragenAmiId","parameterTypes":["java.lang.String"] }, {"name":"setDragenEnabled","parameterTypes":["java.lang.Boolean"] }, {"name":"setEbsAutoScale","parameterTypes":["java.lang.Boolean"] }, {"name":"setEbsBlockSize","parameterTypes":["java.lang.Integer"] }, {"name":"setEbsBootSize","parameterTypes":["java.lang.Integer"] }, {"name":"setEc2KeyPair","parameterTypes":["java.lang.String"] }, {"name":"setEcsConfig","parameterTypes":["java.lang.String"] }, {"name":"setEfsCreate","parameterTypes":["java.lang.Boolean"] }, {"name":"setEfsId","parameterTypes":["java.lang.String"] }, {"name":"setEfsMount","parameterTypes":["java.lang.String"] }, {"name":"setFargateHeadEnabled","parameterTypes":["java.lang.Boolean"] }, {"name":"setFsxMount","parameterTypes":["java.lang.String"] }, {"name":"setFsxName","parameterTypes":["java.lang.String"] }, {"name":"setFsxSize","parameterTypes":["java.lang.Integer"] }, {"name":"setFusionEnabled","parameterTypes":["java.lang.Boolean"] }, {"name":"setGpuEnabled","parameterTypes":["java.lang.Boolean"] }, {"name":"setImageId","parameterTypes":["java.lang.String"] }, {"name":"setInstanceTypes","parameterTypes":["java.util.List"] }, {"name":"setMaxCpus","parameterTypes":["java.lang.Integer"] }, {"name":"setMinCpus","parameterTypes":["java.lang.Integer"] }, {"name":"setSecurityGroups","parameterTypes":["java.util.List"] }, {"name":"setSubnets","parameterTypes":["java.util.List"] }, {"name":"setType","parameterTypes":["io.seqera.tower.model.ForgeConfig$TypeEnum"] }, {"name":"setVpcId","parameterTypes":["java.lang.String"] }] + "methods":[{"name":"","parameterTypes":[] }, {"name":"getAllocStrategy","parameterTypes":[] }, {"name":"getAllowBuckets","parameterTypes":[] }, {"name":"getArm64Enabled","parameterTypes":[] }, {"name":"getBidPercentage","parameterTypes":[] }, {"name":"getDisposeOnDeletion","parameterTypes":[] }, {"name":"getDragenAmiId","parameterTypes":[] }, {"name":"getDragenEnabled","parameterTypes":[] }, {"name":"getEbsAutoScale","parameterTypes":[] }, {"name":"getEbsBlockSize","parameterTypes":[] }, {"name":"getEbsBootSize","parameterTypes":[] }, {"name":"getEc2KeyPair","parameterTypes":[] }, {"name":"getEcsConfig","parameterTypes":[] }, {"name":"getEfsCreate","parameterTypes":[] }, {"name":"getEfsId","parameterTypes":[] }, {"name":"getEfsMount","parameterTypes":[] }, {"name":"getFargateHeadEnabled","parameterTypes":[] }, {"name":"getFsxMount","parameterTypes":[] }, {"name":"getFsxName","parameterTypes":[] }, {"name":"getFsxSize","parameterTypes":[] }, {"name":"getFusionEnabled","parameterTypes":[] }, {"name":"getGpuEnabled","parameterTypes":[] }, {"name":"getImageId","parameterTypes":[] }, {"name":"getInstanceTypes","parameterTypes":[] }, {"name":"getMaxCpus","parameterTypes":[] }, {"name":"getMinCpus","parameterTypes":[] }, {"name":"getSecurityGroups","parameterTypes":[] }, {"name":"getSubnets","parameterTypes":[] }, {"name":"getType","parameterTypes":[] }, {"name":"getVpcId","parameterTypes":[] }, {"name":"setAllocStrategy","parameterTypes":["io.seqera.tower.model.ForgeConfig$AllocStrategyEnum"] }, {"name":"setAllowBuckets","parameterTypes":["java.util.List"] }, {"name":"setArm64Enabled","parameterTypes":["java.lang.Boolean"] }, {"name":"setBidPercentage","parameterTypes":["java.lang.Integer"] }, {"name":"setDisposeOnDeletion","parameterTypes":["java.lang.Boolean"] }, {"name":"setDragenAmiId","parameterTypes":["java.lang.String"] }, {"name":"setDragenEnabled","parameterTypes":["java.lang.Boolean"] }, {"name":"setDragenInstanceType","parameterTypes":["java.lang.String"] }, {"name":"setEbsAutoScale","parameterTypes":["java.lang.Boolean"] }, {"name":"setEbsBlockSize","parameterTypes":["java.lang.Integer"] }, {"name":"setEbsBootSize","parameterTypes":["java.lang.Integer"] }, {"name":"setEc2KeyPair","parameterTypes":["java.lang.String"] }, {"name":"setEcsConfig","parameterTypes":["java.lang.String"] }, {"name":"setEfsCreate","parameterTypes":["java.lang.Boolean"] }, {"name":"setEfsId","parameterTypes":["java.lang.String"] }, {"name":"setEfsMount","parameterTypes":["java.lang.String"] }, {"name":"setFargateHeadEnabled","parameterTypes":["java.lang.Boolean"] }, {"name":"setFsxMount","parameterTypes":["java.lang.String"] }, {"name":"setFsxName","parameterTypes":["java.lang.String"] }, {"name":"setFsxSize","parameterTypes":["java.lang.Integer"] }, {"name":"setFusionEnabled","parameterTypes":["java.lang.Boolean"] }, {"name":"setGpuEnabled","parameterTypes":["java.lang.Boolean"] }, {"name":"setImageId","parameterTypes":["java.lang.String"] }, {"name":"setInstanceTypes","parameterTypes":["java.util.List"] }, {"name":"setMaxCpus","parameterTypes":["java.lang.Integer"] }, {"name":"setMinCpus","parameterTypes":["java.lang.Integer"] }, {"name":"setSecurityGroups","parameterTypes":["java.util.List"] }, {"name":"setSubnets","parameterTypes":["java.util.List"] }, {"name":"setType","parameterTypes":["io.seqera.tower.model.ForgeConfig$TypeEnum"] }, {"name":"setVpcId","parameterTypes":["java.lang.String"] }] }, { "name":"io.seqera.tower.model.ForgeConfig$AllocStrategyEnum", @@ -2870,13 +2870,14 @@ "allDeclaredFields":true, "allDeclaredMethods":true, "allDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":[] }] + "methods":[{"name":"","parameterTypes":[] }, {"name":"getLaunch","parameterTypes":[] }] }, { "name":"io.seqera.tower.model.SubmitWorkflowLaunchResponse", "allDeclaredFields":true, "allDeclaredMethods":true, - "allDeclaredConstructors":true + "allDeclaredConstructors":true, + "methods":[{"name":"","parameterTypes":[] }, {"name":"setWorkflowId","parameterTypes":["java.lang.String"] }] }, { "name":"io.seqera.tower.model.Task", From 41aa2feed7c597d4c5b84ec2b1c1798eeff95b11 Mon Sep 17 00:00:00 2001 From: Jaime Date: Tue, 18 Jun 2024 20:31:17 +0200 Subject: [PATCH 7/8] manually fix missing method in reflection file --- conf/reflect-config.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/conf/reflect-config.json b/conf/reflect-config.json index f39c27ab..cd7f85bf 100644 --- a/conf/reflect-config.json +++ b/conf/reflect-config.json @@ -2824,7 +2824,8 @@ { "name":"io.seqera.tower.model.PipelineOptimizationStatus", "allDeclaredFields":true, - "queryAllDeclaredMethods":true + "queryAllDeclaredMethods":true, + "methods":[{"name":"","parameterTypes":["java.lang.String"] }, {"name":"fromValue","parameterTypes":["java.lang.String"] }] }, { "name":"io.seqera.tower.model.PipelineSecret", From 16d1a99de5a8b22bfc62702d4e0695b27ee84a84 Mon Sep 17 00:00:00 2001 From: Jaime Date: Mon, 22 Jul 2024 19:24:21 +0200 Subject: [PATCH 8/8] fix: missing query param in test --- src/test/java/io/seqera/tower/cli/runs/RunsCmdTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/io/seqera/tower/cli/runs/RunsCmdTest.java b/src/test/java/io/seqera/tower/cli/runs/RunsCmdTest.java index 05ed34c7..26a75103 100644 --- a/src/test/java/io/seqera/tower/cli/runs/RunsCmdTest.java +++ b/src/test/java/io/seqera/tower/cli/runs/RunsCmdTest.java @@ -627,7 +627,7 @@ void testDumpRuns(MockServerClient mock) throws IOException { mock.when( request().withMethod("GET") .withPath("/workflow/5mDfiUtqyptDib") - .withQueryStringParameter("attributes", "labels"), + .withQueryStringParameter("attributes", "labels,optimized"), exactly(1) ).respond( response().withStatusCode(200).withBody(sampleDescribeWorkflowBytes).withContentType(MediaType.APPLICATION_JSON)