diff --git a/conf/reflect-config.json b/conf/reflect-config.json index 15495642..6fe61fa5 100644 --- a/conf/reflect-config.json +++ b/conf/reflect-config.json @@ -1124,6 +1124,12 @@ "allDeclaredFields":true, "queryAllDeclaredMethods":true }, +{ + "name":"io.seqera.tower.cli.commands.datastudios.AddCmd", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "methods":[{"name":"","parameterTypes":[] }] +}, { "name":"io.seqera.tower.cli.commands.datastudios.DataStudioConfigurationOptions", "allDeclaredFields":true, @@ -1148,12 +1154,24 @@ "queryAllDeclaredMethods":true, "methods":[{"name":"","parameterTypes":[] }] }, +{ + "name":"io.seqera.tower.cli.commands.datastudios.StartAsNewCmd", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "methods":[{"name":"","parameterTypes":[] }] +}, { "name":"io.seqera.tower.cli.commands.datastudios.StartCmd", "allDeclaredFields":true, "queryAllDeclaredMethods":true, "methods":[{"name":"","parameterTypes":[] }] }, +{ + "name":"io.seqera.tower.cli.commands.datastudios.TemplatesCmd", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "methods":[{"name":"","parameterTypes":[] }] +}, { "name":"io.seqera.tower.cli.commands.datastudios.ViewCmd", "allDeclaredFields":true, @@ -1865,6 +1883,18 @@ "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true }, +{ + "name":"io.seqera.tower.cli.responses.datastudios.DataStudiosCreated", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllDeclaredConstructors":true +}, +{ + "name":"io.seqera.tower.cli.responses.datastudios.DataStudiosTemplatesList", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllDeclaredConstructors":true +}, { "name":"io.seqera.tower.cli.responses.labels.DeleteLabelsResponse", "allDeclaredFields":true, @@ -2290,7 +2320,7 @@ "allDeclaredFields":true, "allDeclaredMethods":true, "allDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":[] }, {"name":"getCliPath","parameterTypes":[] }, {"name":"getComputeJobRole","parameterTypes":[] }, {"name":"getComputeQueue","parameterTypes":[] }, {"name":"getDiscriminator","parameterTypes":[] }, {"name":"getDragenInstanceType","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"] }] + "methods":[{"name":"","parameterTypes":[] }, {"name":"getCliPath","parameterTypes":[] }, {"name":"getComputeJobRole","parameterTypes":[] }, {"name":"getComputeQueue","parameterTypes":[] }, {"name":"getDiscriminator","parameterTypes":[] }, {"name":"getDragenInstanceType","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":"setNextflowConfig","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", @@ -2488,13 +2518,14 @@ "allDeclaredFields":true, "allDeclaredMethods":true, "allDeclaredConstructors":true, - "methods":[{"name":"getDescription","parameterTypes":[] }, {"name":"getIcon","parameterTypes":[] }, {"name":"getLabelIds","parameterTypes":[] }, {"name":"getLaunch","parameterTypes":[] }, {"name":"getName","parameterTypes":[] }] + "methods":[{"name":"","parameterTypes":[] }, {"name":"getDescription","parameterTypes":[] }, {"name":"getIcon","parameterTypes":[] }, {"name":"getLabelIds","parameterTypes":[] }, {"name":"getLaunch","parameterTypes":[] }, {"name":"getName","parameterTypes":[] }, {"name":"setLaunch","parameterTypes":["io.seqera.tower.model.WorkflowLaunchRequest"] }] }, { "name":"io.seqera.tower.model.CreatePipelineResponse", "allDeclaredFields":true, "allDeclaredMethods":true, - "allDeclaredConstructors":true + "allDeclaredConstructors":true, + "methods":[{"name":"","parameterTypes":[] }, {"name":"setPipeline","parameterTypes":["io.seqera.tower.model.PipelineDbDto"] }] }, { "name":"io.seqera.tower.model.CreatePipelineSecretRequest", @@ -2632,6 +2663,12 @@ "queryAllDeclaredConstructors":true, "methods":[{"name":"","parameterTypes":[] }, {"name":"fromValue","parameterTypes":["java.lang.String"] }, {"name":"setDataLinks","parameterTypes":["java.util.List"] }, {"name":"setTotalSize","parameterTypes":["java.lang.Long"] }] }, +{ + "name":"io.seqera.tower.model.DataStudioCheckpointDto", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllDeclaredConstructors":true +}, { "name":"io.seqera.tower.model.DataStudioComputeEnvDto", "allDeclaredFields":true, @@ -2646,6 +2683,20 @@ "queryAllDeclaredConstructors":true, "methods":[{"name":"","parameterTypes":[] }, {"name":"getCondaEnvironment","parameterTypes":[] }, {"name":"getCpu","parameterTypes":[] }, {"name":"getGpu","parameterTypes":[] }, {"name":"getMemory","parameterTypes":[] }, {"name":"getMountData","parameterTypes":[] }, {"name":"setCondaEnvironment","parameterTypes":["java.lang.String"] }, {"name":"setCpu","parameterTypes":["java.lang.Integer"] }, {"name":"setGpu","parameterTypes":["java.lang.Integer"] }, {"name":"setMemory","parameterTypes":["java.lang.Integer"] }, {"name":"setMountData","parameterTypes":["java.util.List"] }] }, +{ + "name":"io.seqera.tower.model.DataStudioCreateRequest", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllDeclaredConstructors":true, + "methods":[{"name":"getComputeEnvId","parameterTypes":[] }, {"name":"getConfiguration","parameterTypes":[] }, {"name":"getDataStudioToolUrl","parameterTypes":[] }, {"name":"getDescription","parameterTypes":[] }, {"name":"getInitialCheckpointId","parameterTypes":[] }, {"name":"getName","parameterTypes":[] }] +}, +{ + "name":"io.seqera.tower.model.DataStudioCreateResponse", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllDeclaredConstructors":true, + "methods":[{"name":"","parameterTypes":[] }, {"name":"setStudio","parameterTypes":["io.seqera.tower.model.DataStudioDto"] }] +}, { "name":"io.seqera.tower.model.DataStudioDto", "allDeclaredFields":true, @@ -2660,6 +2711,13 @@ "queryAllDeclaredConstructors":true, "methods":[{"name":"","parameterTypes":[] }, {"name":"getCheckpointId","parameterTypes":[] }, {"name":"getCheckpointName","parameterTypes":[] }, {"name":"getSessionId","parameterTypes":[] }, {"name":"getStudioName","parameterTypes":[] }, {"name":"setCheckpointId","parameterTypes":["java.lang.Long"] }, {"name":"setCheckpointName","parameterTypes":["java.lang.String"] }, {"name":"setSessionId","parameterTypes":["java.lang.String"] }, {"name":"setStudioName","parameterTypes":["java.lang.String"] }] }, +{ + "name":"io.seqera.tower.model.DataStudioListCheckpointsResponse", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllDeclaredConstructors":true, + "methods":[{"name":"","parameterTypes":[] }, {"name":"setCheckpoints","parameterTypes":["java.util.List"] }, {"name":"setTotalSize","parameterTypes":["java.lang.Long"] }] +}, { "name":"io.seqera.tower.model.DataStudioListResponse", "allDeclaredFields":true, @@ -2714,6 +2772,13 @@ "queryAllDeclaredConstructors":true, "methods":[{"name":"","parameterTypes":[] }, {"name":"getIcon","parameterTypes":[] }, {"name":"getRepository","parameterTypes":[] }, {"name":"setIcon","parameterTypes":["java.lang.String"] }, {"name":"setRepository","parameterTypes":["java.lang.String"] }] }, +{ + "name":"io.seqera.tower.model.DataStudioTemplatesListResponse", + "allDeclaredFields":true, + "queryAllDeclaredMethods":true, + "queryAllDeclaredConstructors":true, + "methods":[{"name":"","parameterTypes":[] }, {"name":"setTemplates","parameterTypes":["java.util.List"] }, {"name":"setTotalSize","parameterTypes":["java.lang.Long"] }] +}, { "name":"io.seqera.tower.model.Dataset", "allDeclaredFields":true, @@ -2946,7 +3011,7 @@ "allDeclaredFields":true, "allDeclaredMethods":true, "allDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":[] }, {"name":"getComputeEnv_JsonNullable","parameterTypes":[] }, {"name":"getConfigProfiles","parameterTypes":[] }, {"name":"getConfigText","parameterTypes":[] }, {"name":"getDateCreated","parameterTypes":[] }, {"name":"getEntryName","parameterTypes":[] }, {"name":"getHeadJobCpus","parameterTypes":[] }, {"name":"getHeadJobMemoryMb","parameterTypes":[] }, {"name":"getId","parameterTypes":[] }, {"name":"getLastUpdated","parameterTypes":[] }, {"name":"getMainScript","parameterTypes":[] }, {"name":"getOptimizationId","parameterTypes":[] }, {"name":"getOptimizationTargets","parameterTypes":[] }, {"name":"getParamsText","parameterTypes":[] }, {"name":"getPipeline","parameterTypes":[] }, {"name":"getPostRunScript","parameterTypes":[] }, {"name":"getPreRunScript","parameterTypes":[] }, {"name":"getPullLatest","parameterTypes":[] }, {"name":"getResume","parameterTypes":[] }, {"name":"getResumeLaunchId","parameterTypes":[] }, {"name":"getRevision","parameterTypes":[] }, {"name":"getRunName","parameterTypes":[] }, {"name":"getSchemaName","parameterTypes":[] }, {"name":"getSessionId","parameterTypes":[] }, {"name":"getStubRun","parameterTypes":[] }, {"name":"getTowerConfig","parameterTypes":[] }, {"name":"getUserSecrets","parameterTypes":[] }, {"name":"getWorkDir","parameterTypes":[] }, {"name":"getWorkspaceSecrets","parameterTypes":[] }, {"name":"setComputeEnv_JsonNullable","parameterTypes":["org.openapitools.jackson.nullable.JsonNullable"] }, {"name":"setConfigProfiles","parameterTypes":["java.util.List"] }, {"name":"setConfigText","parameterTypes":["java.lang.String"] }, {"name":"setDateCreated","parameterTypes":["java.time.OffsetDateTime"] }, {"name":"setEntryName","parameterTypes":["java.lang.String"] }, {"name":"setHeadJobCpus","parameterTypes":["java.lang.Integer"] }, {"name":"setHeadJobMemoryMb","parameterTypes":["java.lang.Integer"] }, {"name":"setId","parameterTypes":["java.lang.String"] }, {"name":"setLastUpdated","parameterTypes":["java.time.OffsetDateTime"] }, {"name":"setMainScript","parameterTypes":["java.lang.String"] }, {"name":"setOptimizationId","parameterTypes":["java.lang.String"] }, {"name":"setOptimizationTargets","parameterTypes":["java.lang.String"] }, {"name":"setParamsText","parameterTypes":["java.lang.String"] }, {"name":"setPipeline","parameterTypes":["java.lang.String"] }, {"name":"setPostRunScript","parameterTypes":["java.lang.String"] }, {"name":"setPreRunScript","parameterTypes":["java.lang.String"] }, {"name":"setPullLatest","parameterTypes":["java.lang.Boolean"] }, {"name":"setResume","parameterTypes":["java.lang.Boolean"] }, {"name":"setResumeLaunchId","parameterTypes":["java.lang.String"] }, {"name":"setRevision","parameterTypes":["java.lang.String"] }, {"name":"setRunName","parameterTypes":["java.lang.String"] }, {"name":"setSchemaName","parameterTypes":["java.lang.String"] }, {"name":"setSessionId","parameterTypes":["java.lang.String"] }, {"name":"setStubRun","parameterTypes":["java.lang.Boolean"] }, {"name":"setTowerConfig","parameterTypes":["java.lang.String"] }, {"name":"setUserSecrets","parameterTypes":["java.util.List"] }, {"name":"setWorkDir","parameterTypes":["java.lang.String"] }, {"name":"setWorkspaceSecrets","parameterTypes":["java.util.List"] }] + "methods":[{"name":"","parameterTypes":[] }, {"name":"getComputeEnv_JsonNullable","parameterTypes":[] }, {"name":"getConfigProfiles","parameterTypes":[] }, {"name":"getConfigText","parameterTypes":[] }, {"name":"getDateCreated","parameterTypes":[] }, {"name":"getEntryName","parameterTypes":[] }, {"name":"getHeadJobCpus","parameterTypes":[] }, {"name":"getHeadJobMemoryMb","parameterTypes":[] }, {"name":"getId","parameterTypes":[] }, {"name":"getLastUpdated","parameterTypes":[] }, {"name":"getMainScript","parameterTypes":[] }, {"name":"getOptimizationId","parameterTypes":[] }, {"name":"getOptimizationTargets","parameterTypes":[] }, {"name":"getParamsText","parameterTypes":[] }, {"name":"getPipeline","parameterTypes":[] }, {"name":"getPostRunScript","parameterTypes":[] }, {"name":"getPreRunScript","parameterTypes":[] }, {"name":"getPullLatest","parameterTypes":[] }, {"name":"getResume","parameterTypes":[] }, {"name":"getResumeLaunchId","parameterTypes":[] }, {"name":"getRevision","parameterTypes":[] }, {"name":"getRunName","parameterTypes":[] }, {"name":"getSchemaName","parameterTypes":[] }, {"name":"getSessionId","parameterTypes":[] }, {"name":"getStubRun","parameterTypes":[] }, {"name":"getTowerConfig","parameterTypes":[] }, {"name":"getUserSecrets","parameterTypes":[] }, {"name":"getWorkDir","parameterTypes":[] }, {"name":"getWorkspaceSecrets","parameterTypes":[] }, {"name":"setComputeEnv_JsonNullable","parameterTypes":["org.openapitools.jackson.nullable.JsonNullable"] }, {"name":"setConfigProfiles","parameterTypes":["java.util.List"] }, {"name":"setConfigText","parameterTypes":["java.lang.String"] }, {"name":"setDateCreated","parameterTypes":["java.time.OffsetDateTime"] }, {"name":"setEntryName","parameterTypes":["java.lang.String"] }, {"name":"setHeadJobCpus","parameterTypes":["java.lang.Integer"] }, {"name":"setHeadJobMemoryMb","parameterTypes":["java.lang.Integer"] }, {"name":"setId","parameterTypes":["java.lang.String"] }, {"name":"setLastUpdated","parameterTypes":["java.time.OffsetDateTime"] }, {"name":"setLaunchContainer","parameterTypes":["java.lang.String"] }, {"name":"setMainScript","parameterTypes":["java.lang.String"] }, {"name":"setOptimizationId","parameterTypes":["java.lang.String"] }, {"name":"setOptimizationTargets","parameterTypes":["java.lang.String"] }, {"name":"setParamsText","parameterTypes":["java.lang.String"] }, {"name":"setPipeline","parameterTypes":["java.lang.String"] }, {"name":"setPostRunScript","parameterTypes":["java.lang.String"] }, {"name":"setPreRunScript","parameterTypes":["java.lang.String"] }, {"name":"setPullLatest","parameterTypes":["java.lang.Boolean"] }, {"name":"setResume","parameterTypes":["java.lang.Boolean"] }, {"name":"setResumeLaunchId","parameterTypes":["java.lang.String"] }, {"name":"setRevision","parameterTypes":["java.lang.String"] }, {"name":"setRunName","parameterTypes":["java.lang.String"] }, {"name":"setSchemaName","parameterTypes":["java.lang.String"] }, {"name":"setSessionId","parameterTypes":["java.lang.String"] }, {"name":"setStubRun","parameterTypes":["java.lang.Boolean"] }, {"name":"setTowerConfig","parameterTypes":["java.lang.String"] }, {"name":"setUserSecrets","parameterTypes":["java.util.List"] }, {"name":"setWorkDir","parameterTypes":["java.lang.String"] }, {"name":"setWorkspaceSecrets","parameterTypes":["java.util.List"] }] }, { "name":"io.seqera.tower.model.LaunchActionRequest", @@ -3195,7 +3260,7 @@ "allDeclaredFields":true, "allDeclaredMethods":true, "allDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":[] }, {"name":"setPassphrase","parameterTypes":["java.lang.String"] }, {"name":"setPrivateKey","parameterTypes":["java.lang.String"] }] + "methods":[{"name":"","parameterTypes":[] }, {"name":"getDiscriminator","parameterTypes":[] }, {"name":"getPassphrase","parameterTypes":[] }, {"name":"getPrivateKey","parameterTypes":[] }, {"name":"setPassphrase","parameterTypes":["java.lang.String"] }, {"name":"setPrivateKey","parameterTypes":["java.lang.String"] }] }, { "name":"io.seqera.tower.model.SecurityKeys", @@ -3416,7 +3481,7 @@ "allDeclaredFields":true, "allDeclaredMethods":true, "allDeclaredConstructors":true, - "methods":[{"name":"","parameterTypes":[] }, {"name":"getComputeEnvId","parameterTypes":[] }, {"name":"getConfigProfiles","parameterTypes":[] }, {"name":"getConfigText","parameterTypes":[] }, {"name":"getDateCreated","parameterTypes":[] }, {"name":"getEntryName","parameterTypes":[] }, {"name":"getHeadJobCpus","parameterTypes":[] }, {"name":"getHeadJobMemoryMb","parameterTypes":[] }, {"name":"getId","parameterTypes":[] }, {"name":"getLabelIds","parameterTypes":[] }, {"name":"getMainScript","parameterTypes":[] }, {"name":"getOptimizationId","parameterTypes":[] }, {"name":"getOptimizationTargets","parameterTypes":[] }, {"name":"getParamsText","parameterTypes":[] }, {"name":"getPipeline","parameterTypes":[] }, {"name":"getPostRunScript","parameterTypes":[] }, {"name":"getPreRunScript","parameterTypes":[] }, {"name":"getPullLatest","parameterTypes":[] }, {"name":"getResume","parameterTypes":[] }, {"name":"getRevision","parameterTypes":[] }, {"name":"getRunName","parameterTypes":[] }, {"name":"getSchemaName","parameterTypes":[] }, {"name":"getSessionId","parameterTypes":[] }, {"name":"getStubRun","parameterTypes":[] }, {"name":"getTowerConfig","parameterTypes":[] }, {"name":"getUserSecrets","parameterTypes":[] }, {"name":"getWorkDir","parameterTypes":[] }, {"name":"getWorkspaceSecrets","parameterTypes":[] }] + "methods":[{"name":"","parameterTypes":[] }, {"name":"getComputeEnvId","parameterTypes":[] }, {"name":"getConfigProfiles","parameterTypes":[] }, {"name":"getConfigText","parameterTypes":[] }, {"name":"getDateCreated","parameterTypes":[] }, {"name":"getEntryName","parameterTypes":[] }, {"name":"getHeadJobCpus","parameterTypes":[] }, {"name":"getHeadJobMemoryMb","parameterTypes":[] }, {"name":"getId","parameterTypes":[] }, {"name":"getLabelIds","parameterTypes":[] }, {"name":"getLaunchContainer","parameterTypes":[] }, {"name":"getMainScript","parameterTypes":[] }, {"name":"getOptimizationId","parameterTypes":[] }, {"name":"getOptimizationTargets","parameterTypes":[] }, {"name":"getParamsText","parameterTypes":[] }, {"name":"getPipeline","parameterTypes":[] }, {"name":"getPostRunScript","parameterTypes":[] }, {"name":"getPreRunScript","parameterTypes":[] }, {"name":"getPullLatest","parameterTypes":[] }, {"name":"getResume","parameterTypes":[] }, {"name":"getRevision","parameterTypes":[] }, {"name":"getRunName","parameterTypes":[] }, {"name":"getSchemaName","parameterTypes":[] }, {"name":"getSessionId","parameterTypes":[] }, {"name":"getStubRun","parameterTypes":[] }, {"name":"getTowerConfig","parameterTypes":[] }, {"name":"getUserSecrets","parameterTypes":[] }, {"name":"getWorkDir","parameterTypes":[] }, {"name":"getWorkspaceSecrets","parameterTypes":[] }, {"name":"setComputeEnvId","parameterTypes":["java.lang.String"] }, {"name":"setDateCreated","parameterTypes":["java.time.OffsetDateTime"] }, {"name":"setId","parameterTypes":["java.lang.String"] }, {"name":"setPipeline","parameterTypes":["java.lang.String"] }, {"name":"setPullLatest","parameterTypes":["java.lang.Boolean"] }, {"name":"setResume","parameterTypes":["java.lang.Boolean"] }, {"name":"setStubRun","parameterTypes":["java.lang.Boolean"] }, {"name":"setUserSecrets","parameterTypes":["java.util.List"] }, {"name":"setWorkDir","parameterTypes":["java.lang.String"] }, {"name":"setWorkspaceSecrets","parameterTypes":["java.util.List"] }] }, { "name":"io.seqera.tower.model.WorkflowLaunchResponse", @@ -3579,6 +3644,10 @@ "queryAllDeclaredMethods":true, "queryAllDeclaredConstructors":true }, +{ + "name":"java.net.UnknownHostException", + "methods":[{"name":"","parameterTypes":["java.lang.String"] }] +}, { "name":"java.nio.file.Path" }, @@ -4144,6 +4213,10 @@ "allDeclaredFields":true, "methods":[{"name":"objectFieldOffset","parameterTypes":["java.lang.reflect.Field"] }, {"name":"putBoolean","parameterTypes":["java.lang.Object","long","boolean"] }] }, +{ + "name":"sun.net.www.protocol.http.ntlm.NTLMAuthentication", + "methods":[{"name":"","parameterTypes":["boolean","java.lang.String","int","java.net.PasswordAuthentication"] }, {"name":"","parameterTypes":["boolean","java.net.URL","java.net.PasswordAuthentication"] }, {"name":"isTrustedSite","parameterTypes":["java.net.URL"] }, {"name":"supportsTransparentAuth","parameterTypes":[] }] +}, { "name":"sun.security.pkcs.SignerInfo[]" }, diff --git a/src/main/java/io/seqera/tower/cli/commands/DataStudiosCmd.java b/src/main/java/io/seqera/tower/cli/commands/DataStudiosCmd.java index 675ea035..be08c39e 100644 --- a/src/main/java/io/seqera/tower/cli/commands/DataStudiosCmd.java +++ b/src/main/java/io/seqera/tower/cli/commands/DataStudiosCmd.java @@ -17,8 +17,11 @@ package io.seqera.tower.cli.commands; +import io.seqera.tower.cli.commands.datastudios.AddCmd; import io.seqera.tower.cli.commands.datastudios.ListCmd; +import io.seqera.tower.cli.commands.datastudios.StartAsNewCmd; import io.seqera.tower.cli.commands.datastudios.StartCmd; +import io.seqera.tower.cli.commands.datastudios.TemplatesCmd; import io.seqera.tower.cli.commands.datastudios.ViewCmd; import picocli.CommandLine; @@ -29,6 +32,9 @@ ViewCmd.class, ListCmd.class, StartCmd.class, + AddCmd.class, + TemplatesCmd.class, + StartAsNewCmd.class } ) public class DataStudiosCmd extends AbstractRootCmd { diff --git a/src/main/java/io/seqera/tower/cli/commands/datastudios/AbstractStudiosCmd.java b/src/main/java/io/seqera/tower/cli/commands/datastudios/AbstractStudiosCmd.java index c008d027..636de0bd 100644 --- a/src/main/java/io/seqera/tower/cli/commands/datastudios/AbstractStudiosCmd.java +++ b/src/main/java/io/seqera/tower/cli/commands/datastudios/AbstractStudiosCmd.java @@ -17,14 +17,23 @@ package io.seqera.tower.cli.commands.datastudios; +import java.io.IOException; +import java.nio.file.Path; import java.util.Optional; import java.util.function.Supplier; import io.seqera.tower.ApiException; import io.seqera.tower.cli.commands.AbstractApiCmd; +import io.seqera.tower.cli.commands.enums.OutputType; +import io.seqera.tower.cli.exceptions.TowerException; +import io.seqera.tower.cli.utils.FilesHelper; +import io.seqera.tower.model.DataStudioConfiguration; import io.seqera.tower.model.DataStudioDto; import io.seqera.tower.model.DataStudioProgressStep; +import io.seqera.tower.model.DataStudioStatus; +import io.seqera.tower.model.DataStudioStatusInfo; +import static io.seqera.tower.cli.utils.ResponseHelper.waitStatus; import static io.seqera.tower.model.DataStudioProgressStepStatus.ERRORED; import static io.seqera.tower.model.DataStudioProgressStepStatus.IN_PROGRESS; @@ -34,6 +43,64 @@ protected DataStudioDto fetchDataStudio(DataStudioRefOptions dataStudioRefOption return api().describeDataStudio(dataStudioRefOptions.dataStudio.sessionId, wspId); } + protected Integer onBeforeExit(int exitCode, String sessionId, Long workspaceId, DataStudioStatus targetStatus) { + boolean showProgress = app().output != OutputType.json; + + try { + return waitStatus( + app().getOut(), + showProgress, + new ProgressStepMessageSupplier(sessionId, workspaceId), + targetStatus, + DataStudioStatus.values(), + () -> checkDataStudioStatus(sessionId, workspaceId), + DataStudioStatus.STOPPED, DataStudioStatus.ERRORED, DataStudioStatus.RUNNING + ); + } catch (InterruptedException e) { + return exitCode; + } + } + + protected DataStudioStatus checkDataStudioStatus(String sessionId, Long workspaceId) { + try { + DataStudioStatusInfo statusInfo = api().describeDataStudio(sessionId, workspaceId).getStatusInfo(); + return statusInfo == null ? null : statusInfo.getStatus(); + } catch (ApiException e) { + return null; + } + } + + protected DataStudioConfiguration dataStudioConfigurationFrom(DataStudioConfigurationOptions configurationOptions, String condaEnvOverride) { + return dataStudioConfigurationFrom(null, configurationOptions, condaEnvOverride); + } + protected DataStudioConfiguration dataStudioConfigurationFrom(DataStudioDto baseStudio, DataStudioConfigurationOptions configurationOptions){ + return dataStudioConfigurationFrom(baseStudio, configurationOptions, null); + } + protected DataStudioConfiguration dataStudioConfigurationFrom(DataStudioDto baseStudio, DataStudioConfigurationOptions configOptions, String condaEnvOverride) { + DataStudioConfiguration dataStudioConfiguration = baseStudio == null || baseStudio.getConfiguration() == null + ? new DataStudioConfiguration() + : baseStudio.getConfiguration(); + + dataStudioConfiguration.setGpu(configOptions.gpu == null + ? dataStudioConfiguration.getGpu() + : configOptions.gpu); + dataStudioConfiguration.setCpu(configOptions.cpu == null + ? dataStudioConfiguration.getCpu() + : configOptions.cpu); + dataStudioConfiguration.setMemory(configOptions.memory == null + ? dataStudioConfiguration.getMemory() + : configOptions.memory); + dataStudioConfiguration.setMountData(configOptions.mountData == null || configOptions.mountData.isEmpty() + ? dataStudioConfiguration.getMountData() + : configOptions.mountData); + + if (condaEnvOverride != null && !condaEnvOverride.isEmpty()) { + dataStudioConfiguration.setCondaEnvironment(condaEnvOverride); + } + + return dataStudioConfiguration; + } + public class ProgressStepMessageSupplier implements Supplier { private final String sessionId; diff --git a/src/main/java/io/seqera/tower/cli/commands/datastudios/AddCmd.java b/src/main/java/io/seqera/tower/cli/commands/datastudios/AddCmd.java new file mode 100644 index 00000000..a859bc64 --- /dev/null +++ b/src/main/java/io/seqera/tower/cli/commands/datastudios/AddCmd.java @@ -0,0 +1,138 @@ +/* + * Copyright 2021-2023, Seqera. + * + * 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 io.seqera.tower.cli.commands.datastudios; + +import io.seqera.tower.ApiException; +import io.seqera.tower.cli.commands.global.WorkspaceOptionalOptions; +import io.seqera.tower.cli.exceptions.TowerException; +import io.seqera.tower.cli.responses.Response; +import io.seqera.tower.cli.responses.datastudios.DataStudiosCreated; +import io.seqera.tower.cli.utils.FilesHelper; +import io.seqera.tower.model.DataStudioConfiguration; +import io.seqera.tower.model.DataStudioCreateRequest; +import io.seqera.tower.model.DataStudioCreateResponse; +import io.seqera.tower.model.DataStudioDto; +import io.seqera.tower.model.DataStudioStatus; +import picocli.CommandLine; + +import java.io.IOException; +import java.nio.file.Path; + +import static io.seqera.tower.cli.utils.ResponseHelper.waitStatus; + +@CommandLine.Command( + name = "add", + description = "Add new data studio." +) +public class AddCmd extends AbstractStudiosCmd{ + + @CommandLine.Option(names = {"-n", "--name"}, description = "Data Studio name.", required = true) + public String name; + + @CommandLine.Option(names = {"-d", "--description"}, description = "Data studio description.") + public String description; + + @CommandLine.Mixin + public WorkspaceOptionalOptions workspace; + + @CommandLine.Option(names = {"-t", "--template"}, description = "Data studio template container image. Available templates can be listed with 'studios templates' command", required = true) + public String template; + + @CommandLine.Option(names = {"-c", "--compute-env"}, description = "Compute environment name.", required = true) + public String computeEnv; + + @CommandLine.Mixin + public DataStudioConfigurationOptions dataStudioConfigOptions; + + @CommandLine.Option(names = {"--conda-env-yml", "--conda-env-yaml"}, description = "Path to a YAML env file with Conda packages to be installed in the Data Studio environment.") + public Path condaEnv; + + @CommandLine.Option(names = {"-a", "--autoStart"}, description = "Create Data Studio and start it immediately, defaults to false", defaultValue = "false") + public Boolean autoStart; + + @CommandLine.Option(names = {"--wait"}, description = "Wait until DataStudio is in RUNNING status. Valid options: ${COMPLETION-CANDIDATES}.") + public DataStudioStatus wait; + + @Override + protected Response exec() throws ApiException { + Long wspId = workspaceId(workspace.workspace); + + try { + DataStudioCreateRequest request = prepareRequest(); + DataStudioCreateResponse response = api().createDataStudio(request, wspId, autoStart); + DataStudioDto dataStudioDto = response.getStudio(); + assert dataStudioDto != null; + return new DataStudiosCreated(dataStudioDto.getSessionId(), wspId, workspaceRef(wspId), autoStart); + } catch (ApiException e) { + if (e.getCode() == 403) { + throw new TowerException(String.format("User not entitled to create studio at %s workspace", wspId)); + } + throw e; + } + } + + DataStudioCreateRequest prepareRequest() throws TowerException { + DataStudioCreateRequest request = new DataStudioCreateRequest(); + request.setName(name); + if (description != null && !description.isEmpty()) {request.description(description);} + request.setDataStudioToolUrl(template); + request.setComputeEnvId(computeEnv); + + String condaEnvString = null; + if (condaEnv != null) { + try { + condaEnvString = FilesHelper.readString(condaEnv); + } catch (IOException e) { + throw new TowerException(String.format("Cannot read conda environment file: %s. %s", condaEnv, e)); + } + } + + + DataStudioConfiguration newConfig = dataStudioConfigurationFrom(dataStudioConfigOptions, condaEnvString); + request.setConfiguration(setDefaults(newConfig)); + return request; + } + + DataStudioConfiguration setDefaults(DataStudioConfiguration config) { + if (config.getGpu() == null) { + config.setGpu(0); + } + if (config.getCpu() == null) { + config.setCpu(2); + } + if (config.getMemory() == null) { + config.setMemory(8192); + } + return config; + } + + @Override + protected Integer onBeforeExit(int exitCode, Response response) { + + if (!autoStart) { + return exitCode; + } + + if (exitCode != 0 || wait == null || response == null) { + return exitCode; + } + + DataStudiosCreated createdResponse = ((DataStudiosCreated) response); + return onBeforeExit(exitCode, createdResponse.sessionId, createdResponse.workspaceId, wait); + } +} diff --git a/src/main/java/io/seqera/tower/cli/commands/datastudios/DataStudioConfigurationOptions.java b/src/main/java/io/seqera/tower/cli/commands/datastudios/DataStudioConfigurationOptions.java index c5ab3bbd..ef4fb5b5 100644 --- a/src/main/java/io/seqera/tower/cli/commands/datastudios/DataStudioConfigurationOptions.java +++ b/src/main/java/io/seqera/tower/cli/commands/datastudios/DataStudioConfigurationOptions.java @@ -17,22 +17,22 @@ package io.seqera.tower.cli.commands.datastudios; +import java.nio.file.Path; import java.util.List; import picocli.CommandLine; public class DataStudioConfigurationOptions { - @CommandLine.Option(names = {"-g", "--gpu"}, description = "Optional configuration override for 'gpu' setting (Integer representing number of cores)") + @CommandLine.Option(names = {"--gpu"}, description = "Optional configuration override for 'gpu' setting (Integer representing number of cores)") public Integer gpu; - @CommandLine.Option(names = {"-c", "--cpu"}, description = "Optional configuration override for 'cpu' setting (Integer representing number of cores)") + @CommandLine.Option(names = {"--cpu"}, description = "Optional configuration override for 'cpu' setting (Integer representing number of cores)") public Integer cpu; - @CommandLine.Option(names = {"-m", "--memory"}, description = "Optional configuration override for 'memory' setting (Integer representing memory in MBs)") + @CommandLine.Option(names = {"--memory"}, description = "Optional configuration override for 'memory' setting (Integer representing memory in MBs)") public Integer memory; @CommandLine.Option(names = {"--mount-data"}, description = "Optional configuration override for 'mountData' setting (comma separate list of datalinkIds)", split = ",") public List mountData; - } diff --git a/src/main/java/io/seqera/tower/cli/commands/datastudios/StartAsNewCmd.java b/src/main/java/io/seqera/tower/cli/commands/datastudios/StartAsNewCmd.java new file mode 100644 index 00000000..5faf1c15 --- /dev/null +++ b/src/main/java/io/seqera/tower/cli/commands/datastudios/StartAsNewCmd.java @@ -0,0 +1,123 @@ +/* + * Copyright 2021-2023, Seqera. + * + * 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 io.seqera.tower.cli.commands.datastudios; + +import io.seqera.tower.ApiException; +import io.seqera.tower.cli.commands.global.WorkspaceOptionalOptions; +import io.seqera.tower.cli.exceptions.TowerException; +import io.seqera.tower.cli.responses.Response; +import io.seqera.tower.cli.responses.datastudios.DataStudiosCreated; +import io.seqera.tower.model.DataStudioCheckpointDto; +import io.seqera.tower.model.DataStudioConfiguration; +import io.seqera.tower.model.DataStudioCreateRequest; +import io.seqera.tower.model.DataStudioCreateResponse; +import io.seqera.tower.model.DataStudioDto; +import io.seqera.tower.model.DataStudioListCheckpointsResponse; +import io.seqera.tower.model.DataStudioStatus; +import picocli.CommandLine; + +import java.util.List; +import java.util.Objects; + +@CommandLine.Command( + name = "start-as-new", + description = "Start a new data studio from an existing one" +) +public class StartAsNewCmd extends AbstractStudiosCmd{ + + @CommandLine.Option(names = {"-pid", "--parentId"}, description = "Parent DataStudio session ID.", required = true) + public String parentStudioSessionId; + + @CommandLine.Option(names = {"-n", "--name"}, description = "Data Studio name.", required = true) + public String name; + + @CommandLine.Option(names = {"-d", "--description"}, description = "Data studio description.") + public String description; + + @CommandLine.Mixin + public WorkspaceOptionalOptions workspace; + + @CommandLine.Mixin + public DataStudioConfigurationOptions dataStudioConfigOptions; + + @CommandLine.Option(names = {"-a", "--autoStart"}, description = "Create Data Studio and start it immediately, defaults to false", defaultValue = "false") + public Boolean autoStart; + + @CommandLine.Option(names = {"--wait"}, description = "Wait until DataStudio is in RUNNING status. Valid options: ${COMPLETION-CANDIDATES}.") + public DataStudioStatus wait; + + @Override + protected Response exec() throws ApiException { + Long wspId = workspaceId(workspace.workspace); + + try { + DataStudioDto parentDataStudio = api().describeDataStudio(parentStudioSessionId, wspId); + if (parentDataStudio == null) { + throw new TowerException(String.format("Parent DataStudio %s not found at %s workspace", parentStudioSessionId, wspId)); + } + + DataStudioListCheckpointsResponse checkpoints = api().listDataStudioCheckpoints(parentDataStudio.getSessionId(), parentDataStudio.getWorkspaceId(), null, 1, null); + + DataStudioCreateRequest request = prepareRequest(parentDataStudio, checkpoints.getCheckpoints()); + DataStudioCreateResponse response = api().createDataStudio(request, wspId, autoStart); + DataStudioDto dataStudioDto = response.getStudio(); + assert dataStudioDto != null; + return new DataStudiosCreated(dataStudioDto.getSessionId(), wspId, workspaceRef(wspId), autoStart); + } catch (ApiException e) { + if (e.getCode() == 403) { + throw new TowerException(String.format("User not entitled to create studio at %s workspace", wspId)); + } + throw e; + } + } + + DataStudioCreateRequest prepareRequest(DataStudioDto parentDataStudio, List checkpoints) { + DataStudioCreateRequest request = new DataStudioCreateRequest(); + request.setName(name); + if (description == null || description.isEmpty()) { + request.description(String.format("Started from studio %s", parentDataStudio.getName())); + } else { + request.description(description); + } + if (checkpoints != null && !checkpoints.isEmpty()) { + request.setInitialCheckpointId(checkpoints.get(0).getId()); + } + request.setDataStudioToolUrl(Objects.requireNonNull(parentDataStudio.getTemplate()).getRepository()); + request.setComputeEnvId(Objects.requireNonNull(parentDataStudio.getComputeEnv()).getId()); + + DataStudioConfiguration newConfig = dataStudioConfigurationFrom(parentDataStudio, dataStudioConfigOptions); + + request.setConfiguration(newConfig); + return request; + } + + @Override + protected Integer onBeforeExit(int exitCode, Response response) { + + if (!autoStart) { + return exitCode; + } + + if (exitCode != 0 || wait == null || response == null) { + return exitCode; + } + + DataStudiosCreated createdResponse = ((DataStudiosCreated) response); + return onBeforeExit(exitCode, createdResponse.sessionId, createdResponse.workspaceId, wait); + } +} diff --git a/src/main/java/io/seqera/tower/cli/commands/datastudios/StartCmd.java b/src/main/java/io/seqera/tower/cli/commands/datastudios/StartCmd.java index 9912f86b..3b0f2f05 100644 --- a/src/main/java/io/seqera/tower/cli/commands/datastudios/StartCmd.java +++ b/src/main/java/io/seqera/tower/cli/commands/datastudios/StartCmd.java @@ -18,7 +18,6 @@ package io.seqera.tower.cli.commands.datastudios; import io.seqera.tower.ApiException; -import io.seqera.tower.cli.commands.enums.OutputType; import io.seqera.tower.cli.commands.global.WorkspaceOptionalOptions; import io.seqera.tower.cli.exceptions.DataStudioNotFoundException; import io.seqera.tower.cli.exceptions.TowerException; @@ -78,6 +77,7 @@ protected Response exec() throws ApiException { } } + @Override protected Integer onBeforeExit(int exitCode, Response response) { @@ -92,61 +92,21 @@ protected Integer onBeforeExit(int exitCode, Response response) { return exitCode; } - boolean showProgress = app().output != OutputType.json; - - try { - return waitStatus( - app().getOut(), - showProgress, - new ProgressStepMessageSupplier(submitted.sessionId, submitted.workspaceId), - wait, - DataStudioStatus.values(), - () -> checkDataStudioStatus(submitted.sessionId, submitted.workspaceId), - DataStudioStatus.STOPPED, DataStudioStatus.ERRORED, DataStudioStatus.RUNNING - ); - } catch (InterruptedException e) { - return exitCode; - } - } - - private DataStudioStatus checkDataStudioStatus(String sessionId, Long workspaceId) { - try { - return api().describeDataStudio(sessionId, workspaceId).getStatusInfo().getStatus(); - } catch (ApiException | NullPointerException e) { - return null; - } + return onBeforeExit(exitCode, submitted.sessionId, submitted.workspaceId, wait); } private DataStudioStartRequest getStartRequestWithOverridesApplied(DataStudioDto dataStudioDto) { - DataStudioConfiguration dataStudioConfiguration = dataStudioDto.getConfiguration() == null - ? new DataStudioConfiguration() - : dataStudioDto.getConfiguration(); - - dataStudioConfiguration.setGpu(dataStudioConfigOptions.gpu == null - ? dataStudioConfiguration.getGpu() - : dataStudioConfigOptions.gpu); - dataStudioConfiguration.setCpu(dataStudioConfigOptions.cpu == null - ? dataStudioConfiguration.getCpu() - : dataStudioConfigOptions.cpu); - dataStudioConfiguration.setMemory(dataStudioConfigOptions.memory == null - ? dataStudioConfiguration.getMemory() - : dataStudioConfigOptions.memory); - dataStudioConfiguration.setMountData(dataStudioConfigOptions.mountData == null - ? dataStudioConfiguration.getMountData() - : dataStudioConfigOptions.mountData); + DataStudioConfiguration newConfig = dataStudioConfigurationFrom(dataStudioDto, dataStudioConfigOptions); String appliedDescription = description == null ? dataStudioDto.getDescription() : description; DataStudioStartRequest request = new DataStudioStartRequest(); - request.setConfiguration(dataStudioConfiguration); + request.setConfiguration(newConfig); request.setDescription(appliedDescription); return request; } - - - } \ No newline at end of file diff --git a/src/main/java/io/seqera/tower/cli/commands/datastudios/TemplatesCmd.java b/src/main/java/io/seqera/tower/cli/commands/datastudios/TemplatesCmd.java new file mode 100644 index 00000000..9e8352ac --- /dev/null +++ b/src/main/java/io/seqera/tower/cli/commands/datastudios/TemplatesCmd.java @@ -0,0 +1,57 @@ +/* + * Copyright 2021-2023, Seqera. + * + * 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 io.seqera.tower.cli.commands.datastudios; + +import io.seqera.tower.ApiException; +import io.seqera.tower.cli.commands.global.WorkspaceOptionalOptions; +import io.seqera.tower.cli.exceptions.TowerException; +import io.seqera.tower.cli.responses.Response; +import io.seqera.tower.cli.responses.datastudios.DataStudiosTemplatesList; +import io.seqera.tower.model.DataStudioTemplatesListResponse; +import picocli.CommandLine; + +@CommandLine.Command( + name = "templates", + description = "List available DataStudio templates" +) +public class TemplatesCmd extends AbstractStudiosCmd { + + @CommandLine.Mixin + public WorkspaceOptionalOptions workspace; + + @CommandLine.Option(names = {"--max"}, description = "Maximum number of templates to return, defaults to 20", defaultValue = "20") + public Integer max; + + @Override + protected Response exec() throws ApiException { + Long wspId = workspaceId(workspace.workspace); + + try { + DataStudioTemplatesListResponse response = api().listDataStudioTemplates(wspId,max,0); + + return new DataStudiosTemplatesList(response.getTemplates()); + } catch (ApiException e) { + if (e.getCode() == 403) { + throw new TowerException("User not entitled to list studio templates"); + } + throw e; + } + } +} diff --git a/src/main/java/io/seqera/tower/cli/responses/datastudios/DataStudiosCreated.java b/src/main/java/io/seqera/tower/cli/responses/datastudios/DataStudiosCreated.java new file mode 100644 index 00000000..c6f9db89 --- /dev/null +++ b/src/main/java/io/seqera/tower/cli/responses/datastudios/DataStudiosCreated.java @@ -0,0 +1,45 @@ +/* + * Copyright 2021-2023, Seqera. + * + * 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 io.seqera.tower.cli.responses.datastudios; + +import io.seqera.tower.cli.responses.Response; +import io.seqera.tower.model.DataStudioDto; + +public class DataStudiosCreated extends Response { + + public final String sessionId; + public final String workspaceRef; + public final Long workspaceId; + public final boolean autoStart; + + public DataStudiosCreated(String sessionId, Long workspaceId, String workspaceRef, boolean autoStart) { + this.sessionId = sessionId; + this.workspaceRef = workspaceRef; + this.workspaceId = workspaceId; + this.autoStart = autoStart; + } + + @Override + public String toString() { + if (autoStart){ + return ansi(String.format("%n @|yellow Data Studio %s CREATED at %s workspace and auto started.|@%n", sessionId, workspaceRef)); + } else { + return ansi(String.format("%n @|yellow Data Studio %s CREATED at %s workspace.|@%n", sessionId, workspaceRef)); + } + } +} diff --git a/src/main/java/io/seqera/tower/cli/responses/datastudios/DataStudiosTemplatesList.java b/src/main/java/io/seqera/tower/cli/responses/datastudios/DataStudiosTemplatesList.java new file mode 100644 index 00000000..b4a42778 --- /dev/null +++ b/src/main/java/io/seqera/tower/cli/responses/datastudios/DataStudiosTemplatesList.java @@ -0,0 +1,60 @@ +/* + * Copyright 2021-2023, Seqera. + * + * 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 io.seqera.tower.cli.responses.datastudios; + +import io.seqera.tower.cli.responses.Response; +import io.seqera.tower.cli.utils.TableList; +import io.seqera.tower.model.DataStudioTemplate; + +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; + +public class DataStudiosTemplatesList extends Response { + + public List templates; + + public DataStudiosTemplatesList(List templates) { + this.templates = templates; + } + + @Override + public void toString(PrintWriter out) { + + out.println(ansi(String.format("%n @|bold Available templates for Data Studios:|@%n"))); + + if (templates.isEmpty()) { + out.println(ansi(" @|yellow No data studios templates found|@")); + return; + } + + List descriptions = new ArrayList<>(List.of("Templates")); + TableList table = new TableList(out, descriptions.size(), descriptions.toArray(new String[descriptions.size()])).sortBy(0); + table.setPrefix(" "); + + templates.forEach(template -> { + List rows = new ArrayList<>(List.of( + template.getRepository() == null ? "" : template.getRepository() + )); + table.addRow(rows.toArray(new String[rows.size()])); + + }); + table.print(); + out.println(""); + } +} diff --git a/src/test/java/io/seqera/tower/cli/datastudios/DataStudiosCmdTest.java b/src/test/java/io/seqera/tower/cli/datastudios/DataStudiosCmdTest.java index d5d60257..80eef0cf 100644 --- a/src/test/java/io/seqera/tower/cli/datastudios/DataStudiosCmdTest.java +++ b/src/test/java/io/seqera/tower/cli/datastudios/DataStudiosCmdTest.java @@ -21,10 +21,13 @@ import io.seqera.tower.cli.BaseCmdTest; import io.seqera.tower.cli.commands.enums.OutputType; import io.seqera.tower.cli.responses.datastudios.DataStudioStartSubmitted; +import io.seqera.tower.cli.responses.datastudios.DataStudiosCreated; import io.seqera.tower.cli.responses.datastudios.DataStudiosList; +import io.seqera.tower.cli.responses.datastudios.DataStudiosTemplatesList; import io.seqera.tower.cli.responses.datastudios.DataStudiosView; import io.seqera.tower.cli.utils.PaginationInfo; import io.seqera.tower.model.DataStudioDto; +import io.seqera.tower.model.DataStudioTemplatesListResponse; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; @@ -612,7 +615,7 @@ void testStartWithConfigOverride(OutputType format, MockServerClient mock) { ); - ExecOut out = exec(format, mock, "studios", "start", "-w", "75887156211589", "-i" ,"3e8370e7", "-c", "4", "--description", "Override description"); + ExecOut out = exec(format, mock, "studios", "start", "-w", "75887156211589", "-i" ,"3e8370e7", "--cpu", "4", "--description", "Override description"); assertOutput(format, out, new DataStudioStartSubmitted("3e8370e7", 75887156211589L, "[organization1 / workspace1]", "http://localhost:"+mock.getPort()+"/orgs/organization1/workspaces/workspace1", true)); @@ -681,4 +684,226 @@ void testStartWithWait(OutputType format, MockServerClient mock) { // verify the API has been polled additionally for the status mock.verify(request().withMethod("GET").withPath("/studios/3e8370e7"), VerificationTimes.exactly(4)); } + + @ParameterizedTest + @EnumSource(OutputType.class) + void testTemplates(OutputType format, MockServerClient mock) throws JsonProcessingException { + mock.when( + request().withMethod("GET").withPath("/user-info"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("user")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("GET").withPath("/user/1264/workspaces"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("workspaces/workspaces_list")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("GET").withPath("/studios/templates") + .withQueryStringParameter("workspaceId", "75887156211589") + .withQueryStringParameter("max", "20"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("datastudios/datastudios_templates_response")).withContentType(MediaType.APPLICATION_JSON) + ); + + ExecOut out = exec(format, mock, "studios", "templates", "-w", "75887156211589"); + + assertOutput(format, out, new DataStudiosTemplatesList(parseJson(""" + { + "templates": [ + { + "repository": "cr.seqera.io/public/data-studio-jupyter:4.2.5-snapshot", + "icon": "jupyter" + }, + { + "repository": "cr.seqera.io/public/data-studio-rstudio:4.4.1-u1-snapshot", + "icon": "rstudio" + }, + { + "repository": "cr.seqera.io/public/data-studio-vscode:1.93.1-snapshot", + "icon": "vscode" + }, + { + "repository": "cr.seqera.io/public/data-studio-xpra:6.2.0-r2-1-snapshot", + "icon": "xpra" + } + ], + "totalSize": 4 + }""", DataStudioTemplatesListResponse.class).getTemplates()) + ); + } + + @ParameterizedTest + @EnumSource(OutputType.class) + void testAdd(OutputType format, MockServerClient mock){ + + mock.when( + request().withMethod("GET").withPath("/user-info"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("user")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("GET").withPath("/user/1264/workspaces"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("workspaces/workspaces_list")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("POST").withPath("/studios") + .withQueryStringParameter("workspaceId", "75887156211589") + .withQueryStringParameter("autostart", "false"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("datastudios/datastudios_created_response")).withContentType(MediaType.APPLICATION_JSON) + ); + + ExecOut out = exec(format, mock, "studios", "add", "-n", "studio-a66d", "-w", "75887156211589", "-t" ,"cr.seqera.io/public/data-studio-vscode:1.93.1-snapshot", "-c", "7WgvfmcjAwp3Or75UphCJl"); + + assertOutput(format, out, new DataStudiosCreated("3e8370e7",75887156211589L, "[organization1 / workspace1]", false)); + } + + // Only run this test in json output format, since extra stdout output is printed out to console with --wait flag + @ParameterizedTest + @EnumSource(value = OutputType.class, names = {"json"}) + void testAddWithAutoStartAndWait(OutputType format, MockServerClient mock){ + + mock.when( + request().withMethod("GET").withPath("/user-info"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("user")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("GET").withPath("/user/1264/workspaces"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("workspaces/workspaces_list")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("POST").withPath("/studios") + .withQueryStringParameter("workspaceId", "75887156211589") + .withQueryStringParameter("autostart", "true"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("datastudios/datastudios_created_response")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("GET").withPath("/studios/3e8370e7").withQueryStringParameter("workspaceId", "75887156211589"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("datastudios/datastudios_view_response_studio_starting")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("GET").withPath("/studios/3e8370e7").withQueryStringParameter("workspaceId", "75887156211589"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("datastudios/datastudios_view_response")).withContentType(MediaType.APPLICATION_JSON) + ); + + ExecOut out = exec(format, mock, "studios", "add", "-n", "studio-a66d", "-w", "75887156211589", "-t" ,"cr.seqera.io/public/data-studio-vscode:1.93.1-snapshot", + "-c", "7WgvfmcjAwp3Or75UphCJl", "-a", "--wait", "running"); + + assertOutput(format, out, new DataStudiosCreated("3e8370e7",75887156211589L, "[organization1 / workspace1]", true)); + + // verify the API has been polled additionally for the status + mock.verify(request().withMethod("GET").withPath("/studios/3e8370e7"), VerificationTimes.exactly(2)); + } + + @ParameterizedTest + @EnumSource(OutputType.class) + void testStartAsNew(OutputType format, MockServerClient mock) throws JsonProcessingException { + + mock.when( + request().withMethod("GET").withPath("/user-info"), exactly(2) + ).respond( + response().withStatusCode(200).withBody(loadResource("user")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("GET").withPath("/user/1264/workspaces"), exactly(2) + ).respond( + response().withStatusCode(200).withBody(loadResource("workspaces/workspaces_list")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("GET").withPath("/studios/3e8370e7").withQueryStringParameter("workspaceId", "75887156211589"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("datastudios/datastudios_view_response_studio_stopped")).withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("GET").withPath("/studios/3e8370e7/checkpoints") + .withQueryStringParameter("workspaceId","75887156211589") + .withQueryStringParameter("max","1"), exactly(1) + ).respond( + response().withStatusCode(200).withBody("{\"checkpoints\":[],\"totalSize\":0}").withContentType(MediaType.APPLICATION_JSON) + ); + + mock.when( + request().withMethod("POST").withPath("/studios") + .withQueryStringParameter("workspaceId", "75887156211589") + .withQueryStringParameter("autostart", "false"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("datastudios/datastudios_start_as_new_response")).withContentType(MediaType.APPLICATION_JSON) + ); + + ExecOut out = exec(format, mock, "studios", "start-as-new", "-pid", "3e8370e7", "-n", "child-studio-a66d", "-w", "75887156211589", "--cpu", "4"); + + assertOutput(format, out, new DataStudiosCreated("8aebf1b8",75887156211589L, "[organization1 / workspace1]", false)); + + + mock.when( + request().withMethod("GET").withPath("/studios/8aebf1b8").withQueryStringParameter("workspaceId", "75887156211589"), exactly(1) + ).respond( + response().withStatusCode(200).withBody(loadResource("datastudios/datastudios_view_start_as_new_response")).withContentType(MediaType.APPLICATION_JSON) + ); + + ExecOut outView = exec(format, mock, "studios", "view", "-i", "8aebf1b8", "-w", "75887156211589"); + + assertOutput(format, outView, new DataStudiosView(parseJson(""" + { + "sessionId": "8aebf1b8", + "workspaceId": 75887156211589, + "user": { + "id": 2345, + "userName": "John Doe", + "email": "john@seqera.io", + "avatar": null + }, + "name": "studio-a66d", + "description": "Started from studio studio-a66d", + "studioUrl": "https://a8aebf1b8.dev-tower.com", + "computeEnv": { + "id": "3xkkzYH2nbD3nZjrzKm0oR", + "name": "ce1", + "platform": "aws-batch", + "region": "us-east-2" + }, + "template": { + "repository": "cr.seqera.io/public/data-studio-vscode:1.93.1-snapshot", + "icon": "vscode" + }, + "configuration": { + "gpu": 0, + "cpu": 4, + "memory": 8192, + "mountData": [], + "condaEnvironment":null + }, + "dateCreated": "2025-01-28T10:44:44.833455494Z", + "lastUpdated": "2025-01-28T10:44:44.833455494Z", + "statusInfo": { + "status": "stopped", + "message": "", + "lastUpdate": "2025-01-28T10:44:44.650457005Z" + }, + "waveBuildUrl": null, + "baseImage": "cr.seqera.io/public/data-studio-vscode:1.93.1-snapshot", + "mountedDataLinks": [], + "progress": [] + } + """, DataStudioDto.class), "[organization1 / workspace1]")); + } + } diff --git a/src/test/resources/runcmd/datastudios/datastudios_created_response.json b/src/test/resources/runcmd/datastudios/datastudios_created_response.json new file mode 100644 index 00000000..5efea702 --- /dev/null +++ b/src/test/resources/runcmd/datastudios/datastudios_created_response.json @@ -0,0 +1,45 @@ +{ + "studio": { + "sessionId": "3e8370e7", + "workspaceId": 75887156211589, + "parentCheckpoint": null, + "user": { + "id": 2345, + "userName": "John Doe", + "email": "john@seqera.io" + }, + "name": "studio-a66d", + "description": null, + "studioUrl": "https://a3e8370e7.dev-tower.com", + "computeEnv": { + "id": "3xkkzYH2nbD3nZjrzKm0oR", + "name": "ce1", + "platform": "aws-batch", + "region": "us-east-2" + }, + "template": { + "repository": "cr.seqera.io/public/data-studio-vscode:1.93.1-snapshot", + "icon": "vscode" + }, + "configuration": { + "gpu": 0, + "cpu": 2, + "memory": 8192, + "mountData": [ + + ], + "condaEnvironment": null + }, + "dateCreated": "2025-01-28T10:44:44.833455494Z", + "lastUpdated": "2025-01-28T10:44:44.833455494Z", + "statusInfo": { + "status": "stopped", + "message": "", + "lastUpdate": "2025-01-28T10:44:44.650457005Z" + }, + "waveBuildUrl": null, + "baseImage": null, + "customImage": false, + "progress": null + } +} \ No newline at end of file diff --git a/src/test/resources/runcmd/datastudios/datastudios_start_as_new_response.json b/src/test/resources/runcmd/datastudios/datastudios_start_as_new_response.json new file mode 100644 index 00000000..6991a5e7 --- /dev/null +++ b/src/test/resources/runcmd/datastudios/datastudios_start_as_new_response.json @@ -0,0 +1,45 @@ +{ + "studio": { + "sessionId": "8aebf1b8", + "workspaceId": 75887156211589, + "parentCheckpoint": null, + "user": { + "id": 2345, + "userName": "John Doe", + "email": "john@seqera.io" + }, + "name": "studio-child", + "description": "Started from studio studio-a66d", + "studioUrl": "https://a8aebf1b8.dev-tower.com", + "computeEnv": { + "id": "3xkkzYH2nbD3nZjrzKm0oR", + "name": "ce1", + "platform": "aws-batch", + "region": "us-east-2" + }, + "template": { + "repository": "cr.seqera.io/public/data-studio-vscode:1.93.1-snapshot", + "icon": "vscode" + }, + "configuration": { + "gpu": 0, + "cpu": 4, + "memory": 8192, + "mountData": [ + + ], + "condaEnvironment": null + }, + "dateCreated": "2025-01-28T10:44:44.833455494Z", + "lastUpdated": "2025-01-28T10:44:44.833455494Z", + "statusInfo": { + "status": "stopped", + "message": "", + "lastUpdate": "2025-01-28T10:44:44.650457005Z" + }, + "waveBuildUrl": null, + "baseImage": null, + "customImage": false, + "progress": null + } +} \ No newline at end of file diff --git a/src/test/resources/runcmd/datastudios/datastudios_templates_response.json b/src/test/resources/runcmd/datastudios/datastudios_templates_response.json new file mode 100644 index 00000000..0f4531f1 --- /dev/null +++ b/src/test/resources/runcmd/datastudios/datastudios_templates_response.json @@ -0,0 +1,21 @@ +{ + "templates": [ + { + "repository": "cr.seqera.io/public/data-studio-jupyter:4.2.5-snapshot", + "icon": "jupyter" + }, + { + "repository": "cr.seqera.io/public/data-studio-rstudio:4.4.1-u1-snapshot", + "icon": "rstudio" + }, + { + "repository": "cr.seqera.io/public/data-studio-vscode:1.93.1-snapshot", + "icon": "vscode" + }, + { + "repository": "cr.seqera.io/public/data-studio-xpra:6.2.0-r2-1-snapshot", + "icon": "xpra" + } + ], + "totalSize": 4 +} \ No newline at end of file diff --git a/src/test/resources/runcmd/datastudios/datastudios_view_start_as_new_response.json b/src/test/resources/runcmd/datastudios/datastudios_view_start_as_new_response.json new file mode 100644 index 00000000..ffb1655e --- /dev/null +++ b/src/test/resources/runcmd/datastudios/datastudios_view_start_as_new_response.json @@ -0,0 +1,41 @@ +{ + "sessionId": "8aebf1b8", + "workspaceId": 75887156211589, + "user": { + "id": 2345, + "userName": "John Doe", + "email": "john@seqera.io", + "avatar": null + }, + "name": "studio-a66d", + "description": "Started from studio studio-a66d", + "studioUrl": "https://a8aebf1b8.dev-tower.com", + "computeEnv": { + "id": "3xkkzYH2nbD3nZjrzKm0oR", + "name": "ce1", + "platform": "aws-batch", + "region": "us-east-2" + }, + "template": { + "repository": "cr.seqera.io/public/data-studio-vscode:1.93.1-snapshot", + "icon": "vscode" + }, + "configuration": { + "gpu": 0, + "cpu": 4, + "memory": 8192, + "mountData": [], + "condaEnvironment":null + }, + "dateCreated": "2025-01-28T10:44:44.833455494Z", + "lastUpdated": "2025-01-28T10:44:44.833455494Z", + "statusInfo": { + "status": "stopped", + "message": "", + "lastUpdate": "2025-01-28T10:44:44.650457005Z" + }, + "waveBuildUrl": null, + "baseImage": "cr.seqera.io/public/data-studio-vscode:1.93.1-snapshot", + "mountedDataLinks": [], + "progress": [] +} \ No newline at end of file