diff --git a/src/main/java/io/seqera/tower/cli/commands/computeenvs/ImportCmd.java b/src/main/java/io/seqera/tower/cli/commands/computeenvs/ImportCmd.java index f2afec75..a7333ebc 100644 --- a/src/main/java/io/seqera/tower/cli/commands/computeenvs/ImportCmd.java +++ b/src/main/java/io/seqera/tower/cli/commands/computeenvs/ImportCmd.java @@ -14,10 +14,15 @@ import io.seqera.tower.ApiException; import io.seqera.tower.cli.commands.computeenvs.add.AbstractAddCmd; import io.seqera.tower.cli.commands.computeenvs.platforms.Platform; +import io.seqera.tower.cli.exceptions.ComputeEnvNotFoundException; +import io.seqera.tower.cli.exceptions.PipelineNotFoundException; import io.seqera.tower.cli.responses.Response; import io.seqera.tower.cli.utils.FilesHelper; import io.seqera.tower.model.ComputeConfig; import io.seqera.tower.model.ComputeEnv; +import io.seqera.tower.model.ComputeEnvDbDto; +import io.seqera.tower.model.ComputeEnvResponseDto; +import io.seqera.tower.model.PipelineDbDto; import picocli.CommandLine; import java.io.IOException; @@ -30,14 +35,22 @@ description = "Add a compute environment from file content." ) public class ImportCmd extends AbstractAddCmd { + @CommandLine.Option(names = {"--overwrite"}, description = "Overwrite the compute env if it already exists.", defaultValue = "false") + public Boolean overwrite; @CommandLine.Parameters(index = "0", paramLabel = "FILENAME", description = "File name to import.", arity = "1") Path fileName = null; @Override protected Response exec() throws ApiException, IOException { + ComputeConfig configObj = parseJson(FilesHelper.readString(fileName), ComputeConfig.class); ComputeEnv.PlatformEnum platform = ComputeEnv.PlatformEnum.fromValue(configObj.getDiscriminator()); + + Long wspId = workspaceId(workspace.workspace); + + if (overwrite) deleteCE(name, wspId); + return addComputeEnv(platform, configObj); } @@ -45,4 +58,12 @@ protected Response exec() throws ApiException, IOException { protected Platform getPlatform() { throw new UnsupportedOperationException("Unknown platform"); } + + private void deleteCE(String name, Long wspId) throws ApiException { + try { + ComputeEnvResponseDto ce = computeEnvByRef(wspId, name); + api().deleteComputeEnv(ce.getId(), wspId); + } catch (ComputeEnvNotFoundException ignored) {} + } + } diff --git a/src/test/java/io/seqera/tower/cli/computeenvs/ComputeEnvsCmdTest.java b/src/test/java/io/seqera/tower/cli/computeenvs/ComputeEnvsCmdTest.java index 6bd3770c..cf6bf20d 100644 --- a/src/test/java/io/seqera/tower/cli/computeenvs/ComputeEnvsCmdTest.java +++ b/src/test/java/io/seqera/tower/cli/computeenvs/ComputeEnvsCmdTest.java @@ -362,6 +362,62 @@ void testImport(OutputType format, MockServerClient mock) throws IOException { assertOutput(format, out, new ComputeEnvAdded(ComputeEnv.PlatformEnum.AWS_BATCH.getValue(), "3T6xWeFD63QIuzdAowvSTC", "json", null, USER_WORKSPACE_NAME)); } + @ParameterizedTest + @EnumSource(OutputType.class) + void testImportWithOverwrite(OutputType format, MockServerClient mock) throws IOException { + + mock.when( + request().withMethod("GET").withPath("/compute-envs"), exactly(1) + ).respond( + response().withStatusCode(200).withBody("{" + + "\"computeEnvs\":[" + + "{" + + "\"id\":\"isnEDBLvHDAIteOEF44ow\"," + + "\"name\":\"demo\"," + + "\"platform\":\"aws-batch\"," + + "\"status\":\"AVAILABLE\"," + + "\"message\":null," + + "\"lastUsed\":null," + + "\"primary\":null," + + "\"workspaceName\":null," + + "\"visibility\":null" + + "}" + + "]}" + ).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("GET").withPath("/compute-envs/isnEDBLvHDAIteOEF44ow"), exactly(1) + ).respond( + response() + .withStatusCode(200) + .withBody(loadResource("compute_env_view")) + .withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("POST").withPath("/compute-envs").withBody("{\"computeEnv\":{\"name\":\"demo\",\"platform\":\"aws-batch\",\"config\":{\"region\":\"eu-west-1\",\"cliPath\":\"/home/ec2-user/miniconda/bin/aws\",\"workDir\":\"s3://nextflow-ci/jordeu\",\"forge\":{\"type\":\"SPOT\",\"minCpus\":0,\"maxCpus\":123,\"gpuEnabled\":false,\"ebsAutoScale\":true,\"disposeOnDeletion\":true,\"fusionEnabled\":false,\"efsCreate\":true},\"discriminator\":\"aws-batch\"},\"credentialsId\":\"6g0ER59L4ZoE5zpOmUP48D\"}}"), exactly(1) + ).respond( + response().withStatusCode(200).withBody("{\"computeEnvId\":\"3T6xWeFD63QIuzdAowvSTC\"}").withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("DELETE").withPath("/compute-envs/isnEDBLvHDAIteOEF44ow"), + exactly(1) + ).respond( + response().withStatusCode(200) + ); + + mock.when( + request().withMethod("GET").withPath("/credentials").withQueryStringParameter("platformId", "aws-batch"), exactly(1) + ).respond( + response().withStatusCode(200).withBody("{\"credentials\":[{\"id\":\"6g0ER59L4ZoE5zpOmUP48D\",\"name\":\"aws\",\"description\":null,\"discriminator\":\"aws\",\"baseUrl\":null,\"category\":null,\"deleted\":null,\"lastUsed\":\"2021-09-09T07:20:53Z\",\"dateCreated\":\"2021-09-08T05:48:51Z\",\"lastUpdated\":\"2021-09-08T05:48:51Z\"}]}").withContentType(MediaType.APPLICATION_JSON) + ); + + ExecOut out = exec(format, mock, "compute-envs", "import", "--overwrite", tempFile(new String(loadResource("cejson"), StandardCharsets.UTF_8), "ce", "json"), "-n", "demo", "-c", "6g0ER59L4ZoE5zpOmUP48D"); + assertOutput(format, out, new ComputeEnvAdded(ComputeEnv.PlatformEnum.AWS_BATCH.getValue(), "3T6xWeFD63QIuzdAowvSTC", "demo", null, USER_WORKSPACE_NAME)); + } + @ParameterizedTest @EnumSource(OutputType.class) void testPrimaryGet(OutputType format, MockServerClient mock) throws JsonProcessingException {