From 04108d29944fe5b6184860611959a85f11bd326d Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Tue, 12 Mar 2024 18:36:17 +0100 Subject: [PATCH 01/22] labels added in spack dockerfile Signed-off-by: munishchouhan --- .../controller/ContainerTokenController.groovy | 3 ++- .../wave/service/builder/BuildRequest.groovy | 10 +++++++++- .../builder/ContainerBuildServiceImpl.groovy | 15 +++++++++++++++ .../builder/ContainerBuildServiceTest.groovy | 15 +++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/main/groovy/io/seqera/wave/controller/ContainerTokenController.groovy b/src/main/groovy/io/seqera/wave/controller/ContainerTokenController.groovy index 3ade4f391..d26184a98 100644 --- a/src/main/groovy/io/seqera/wave/controller/ContainerTokenController.groovy +++ b/src/main/groovy/io/seqera/wave/controller/ContainerTokenController.groovy @@ -242,7 +242,8 @@ class ContainerTokenController { cache, scanId, ip, - offset) + offset, + req.labels) } protected BuildRequest buildRequest(SubmitContainerTokenRequest req, PlatformId identity, String ip) { diff --git a/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy b/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy index cb4cba68d..e827e38c2 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy @@ -146,7 +146,14 @@ class BuildRequest { */ volatile boolean uncached - BuildRequest(String containerFile, Path workspace, String repo, String condaFile, String spackFile, BuildFormat format, PlatformId identity, ContainerConfig containerConfig, BuildContext buildContext, ContainerPlatform platform, String configJson, String cacheRepo, String scanId, String ip, String offsetId) { + /** + * Labels to be added in conda and spack build images + */ + final Map labels + + BuildRequest(String containerFile, Path workspace, String repo, String condaFile, String spackFile, BuildFormat format, + PlatformId identity, ContainerConfig containerConfig, BuildContext buildContext, ContainerPlatform platform, + String configJson, String cacheRepo, String scanId, String ip, String offsetId, Map labels) { this.id = computeDigest(containerFile, condaFile, spackFile, platform, repo, buildContext) this.containerFile = containerFile this.containerConfig = containerConfig @@ -166,6 +173,7 @@ class BuildRequest { this.ip = ip this.isSpackBuild = spackFile this.scanId = scanId + this.labels = labels } static protected String makeTarget(BuildFormat format, String repo, String id, @Nullable String condaFile, @Nullable String spackFile) { diff --git a/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy b/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy index d684c85b7..00a1b0a84 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy @@ -146,6 +146,9 @@ class ContainerBuildServiceImpl implements ContainerBuildService { binding.spack_arch = SpackHelper.toSpackArch(req.getPlatform()) binding.spack_cache_bucket = config.cacheBucket binding.spack_key_file = config.secretMountPath + if(req.labels && req.labels.size() > 0){ + binding.labels = formatLabels(req.labels) + } return new TemplateRenderer().render(containerFile, binding) } else { @@ -153,6 +156,18 @@ class ContainerBuildServiceImpl implements ContainerBuildService { } } + static String formatLabels(Map labels) { + def formattedLabels = labels.collect { key, value -> + if (key.contains(' ') || value.contains(' ')) { + return "\"$key\"=\"$value\"" + } else { + return "$key=\"$value\"" + } + }.join(' ') + + return "LABEL $formattedLabels" + } + protected BuildResult launch(BuildRequest req) { // launch an external process to build the container BuildResult resp=null diff --git a/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy b/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy index 443c879e5..0b380c5d6 100644 --- a/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy @@ -445,4 +445,19 @@ class ContainerBuildServiceTest extends Specification { server?.stop(0) } + + def 'should format the labels'(){ + given:'a list of labels' + def labels = [ + 'com.example.vendor':'ACME Incorporated', + 'com.example.label-with-value':'foo', + 'version':'1.0' + ] + + when:'formatted for docker file' + def formattedLabels = service.formatLabels(labels) + + then: 'The result is a string is prefixed by LABEL and all entries separated by space' + formattedLabels == "LABEL \"com.example.vendor\"=\"ACME Incorporated\" com.example.label-with-value=\"foo\" version=\"1.0\"" + } } From 4ae6caa77d9e2fec5b648a6fd8ba722bdadadf2f Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Tue, 12 Mar 2024 18:55:21 +0100 Subject: [PATCH 02/22] labels added in spack dockerfile Signed-off-by: munishchouhan --- .../wave/controller/ContainerTokenController.groovy | 9 ++++++--- .../io/seqera/wave/service/builder/BuildRequest.groovy | 10 +++++++--- .../io/seqera/wave/spack/spack-builder-dockerfile.txt | 3 +++ 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/main/groovy/io/seqera/wave/controller/ContainerTokenController.groovy b/src/main/groovy/io/seqera/wave/controller/ContainerTokenController.groovy index d26184a98..253d618c8 100644 --- a/src/main/groovy/io/seqera/wave/controller/ContainerTokenController.groovy +++ b/src/main/groovy/io/seqera/wave/controller/ContainerTokenController.groovy @@ -227,7 +227,7 @@ class ContainerTokenController { final offset = DataTimeUtils.offsetId(req.timestamp) final scanId = scanEnabled && format==DOCKER ? LongRndKey.rndHex() : null // create a unique digest to identify the request - return new BuildRequest( + def buildRequest = new BuildRequest( (spackContent ? prependBuilderTemplate(containerSpec,format) : containerSpec), Path.of(buildConfig.buildWorkspace), build, @@ -242,8 +242,11 @@ class ContainerTokenController { cache, scanId, ip, - offset, - req.labels) + offset) + if( req.labels ){ + buildRequest.withLabels(req.labels) + } + return buildRequest } protected BuildRequest buildRequest(SubmitContainerTokenRequest req, PlatformId identity, String ip) { diff --git a/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy b/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy index e827e38c2..b1ee75246 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy @@ -149,11 +149,11 @@ class BuildRequest { /** * Labels to be added in conda and spack build images */ - final Map labels + private Map labels BuildRequest(String containerFile, Path workspace, String repo, String condaFile, String spackFile, BuildFormat format, PlatformId identity, ContainerConfig containerConfig, BuildContext buildContext, ContainerPlatform platform, - String configJson, String cacheRepo, String scanId, String ip, String offsetId, Map labels) { + String configJson, String cacheRepo, String scanId, String ip, String offsetId) { this.id = computeDigest(containerFile, condaFile, spackFile, platform, repo, buildContext) this.containerFile = containerFile this.containerConfig = containerConfig @@ -173,7 +173,6 @@ class BuildRequest { this.ip = ip this.isSpackBuild = spackFile this.scanId = scanId - this.labels = labels } static protected String makeTarget(BuildFormat format, String repo, String id, @Nullable String condaFile, @Nullable String spackFile) { @@ -306,4 +305,9 @@ class BuildRequest { boolean formatSingularity() { format==SINGULARITY } + + BuildRequest withLabels(Map labels){ + this.labels = labels + return this + } } diff --git a/src/main/resources/io/seqera/wave/spack/spack-builder-dockerfile.txt b/src/main/resources/io/seqera/wave/spack/spack-builder-dockerfile.txt index 5637b1533..583ca4e64 100644 --- a/src/main/resources/io/seqera/wave/spack/spack-builder-dockerfile.txt +++ b/src/main/resources/io/seqera/wave/spack/spack-builder-dockerfile.txt @@ -2,6 +2,9 @@ FROM {{spack_builder_image}} as builder COPY spack.yaml /opt/spack-env/spack.yaml +#Labels +${labels} + # Assume the values from the environment ARG AWS_STS_REGIONAL_ENDPOINTS ARG AWS_REGION From 00c051778dda52123f456ee890432c94a3cae457 Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Tue, 12 Mar 2024 20:17:47 +0100 Subject: [PATCH 03/22] fixed tests Signed-off-by: munishchouhan --- .../wave/controller/ContainerTokenControllerTest.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/groovy/io/seqera/wave/controller/ContainerTokenControllerTest.groovy b/src/test/groovy/io/seqera/wave/controller/ContainerTokenControllerTest.groovy index 9db111107..924ddebeb 100644 --- a/src/test/groovy/io/seqera/wave/controller/ContainerTokenControllerTest.groovy +++ b/src/test/groovy/io/seqera/wave/controller/ContainerTokenControllerTest.groovy @@ -264,12 +264,12 @@ class ContainerTokenControllerTest extends Specification { submit = new SubmitContainerTokenRequest(containerFile: encode('FROM foo'), spackFile: encode('some::spack-recipe'), containerPlatform: 'arm64') build = controller.makeBuildRequest(submit, PlatformId.NULL, "") then: - build.id == 'b7d730d274d1e057' + build.id == 'd00a2b3fe3d4d0b8' build.containerFile.endsWith('\nFROM foo') build.containerFile.startsWith('# Builder image\n') build.condaFile == null build.spackFile == 'some::spack-recipe' - build.targetImage == 'wave/build:b7d730d274d1e057' + build.targetImage == 'wave/build:d00a2b3fe3d4d0b8' build.workDir == Path.of('/some/wsp').resolve(build.id) build.platform == ContainerPlatform.of('arm64') } From 8503a66204945d6016db720c1fa62f77844eeaf8 Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Tue, 12 Mar 2024 20:50:08 +0100 Subject: [PATCH 04/22] adding labels via kaniko Signed-off-by: munishchouhan --- .../wave/service/builder/BuildRequest.groovy | 4 ++ .../wave/service/builder/BuildStrategy.groovy | 16 ++++++++ .../builder/ContainerBuildServiceImpl.groovy | 15 ------- .../wave/spack/spack-builder-dockerfile.txt | 3 -- .../service/builder/BuildStrategyTest.groovy | 40 +++++++++++++++++++ .../builder/ContainerBuildServiceTest.groovy | 15 ------- 6 files changed, 60 insertions(+), 33 deletions(-) diff --git a/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy b/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy index b1ee75246..685ed16bf 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy @@ -310,4 +310,8 @@ class BuildRequest { this.labels = labels return this } + + Map getLabels() { + return labels + } } diff --git a/src/main/groovy/io/seqera/wave/service/builder/BuildStrategy.groovy b/src/main/groovy/io/seqera/wave/service/builder/BuildStrategy.groovy index 0d8c7dc5b..72e7455b5 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/BuildStrategy.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/BuildStrategy.groovy @@ -86,9 +86,25 @@ abstract class BuildStrategy { result << 'AWS_WEB_IDENTITY_TOKEN_FILE=$(AWS_WEB_IDENTITY_TOKEN_FILE)' } + if(req.labels){ + result << formatLabels(req.labels) + } + return result } + static String formatLabels(Map labels) { + def formattedLabels = labels.collect { key, value -> + if (key.contains(' ') || value.contains(' ')) { + return "--label \"$key\"=\"$value\"" + } else { + return "--label $key=\"$value\"" + } + }.join(' ') + + return formattedLabels + } + protected List singularityLaunchCmd(BuildRequest req) { final result = new ArrayList(10) result diff --git a/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy b/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy index 00a1b0a84..d684c85b7 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy @@ -146,9 +146,6 @@ class ContainerBuildServiceImpl implements ContainerBuildService { binding.spack_arch = SpackHelper.toSpackArch(req.getPlatform()) binding.spack_cache_bucket = config.cacheBucket binding.spack_key_file = config.secretMountPath - if(req.labels && req.labels.size() > 0){ - binding.labels = formatLabels(req.labels) - } return new TemplateRenderer().render(containerFile, binding) } else { @@ -156,18 +153,6 @@ class ContainerBuildServiceImpl implements ContainerBuildService { } } - static String formatLabels(Map labels) { - def formattedLabels = labels.collect { key, value -> - if (key.contains(' ') || value.contains(' ')) { - return "\"$key\"=\"$value\"" - } else { - return "$key=\"$value\"" - } - }.join(' ') - - return "LABEL $formattedLabels" - } - protected BuildResult launch(BuildRequest req) { // launch an external process to build the container BuildResult resp=null diff --git a/src/main/resources/io/seqera/wave/spack/spack-builder-dockerfile.txt b/src/main/resources/io/seqera/wave/spack/spack-builder-dockerfile.txt index 583ca4e64..5637b1533 100644 --- a/src/main/resources/io/seqera/wave/spack/spack-builder-dockerfile.txt +++ b/src/main/resources/io/seqera/wave/spack/spack-builder-dockerfile.txt @@ -2,9 +2,6 @@ FROM {{spack_builder_image}} as builder COPY spack.yaml /opt/spack-env/spack.yaml -#Labels -${labels} - # Assume the values from the environment ARG AWS_STS_REGIONAL_ENDPOINTS ARG AWS_REGION diff --git a/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy b/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy index e41c1c623..cf7af4ca3 100644 --- a/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy @@ -105,4 +105,44 @@ class BuildStrategyTest extends Specification { ] } + def "should format labels correctly"() { + given: "a map of labels" + def labels = [ + "arch": "arm64", + "package name": "salmon", + "version": "1.0.0" + ] + + when: "formatting the labels" + def formattedLabels = BuildStrategy.formatLabels(labels) + + then: "the labels are formatted correctly" + formattedLabels == "--label arch=\"arm64\" --label \"package name\"=\"salmon\" --label version=\"1.0.0\"" + } + + def "should handle empty labels correctly"() { + given: "an empty map of labels" + def labels = [:] + + when: "formatting the labels" + def formattedLabels = BuildStrategy.formatLabels(labels) + + then: "the result is an empty string" + formattedLabels == "" + } + + def "should handle null values correctly"() { + given: "a map of labels with null values" + def labels = [ + "description": null, + "package name": "cowsay" + ] + + when: "formatting the labels" + def formattedLabels = BuildStrategy.formatLabels(labels) + + then: "the labels are formatted correctly, ignoring null values" + formattedLabels == "--label \"package name\"=\"cowsay\"" + } + } diff --git a/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy b/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy index 0b380c5d6..443c879e5 100644 --- a/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy @@ -445,19 +445,4 @@ class ContainerBuildServiceTest extends Specification { server?.stop(0) } - - def 'should format the labels'(){ - given:'a list of labels' - def labels = [ - 'com.example.vendor':'ACME Incorporated', - 'com.example.label-with-value':'foo', - 'version':'1.0' - ] - - when:'formatted for docker file' - def formattedLabels = service.formatLabels(labels) - - then: 'The result is a string is prefixed by LABEL and all entries separated by space' - formattedLabels == "LABEL \"com.example.vendor\"=\"ACME Incorporated\" com.example.label-with-value=\"foo\" version=\"1.0\"" - } } From 2b99d288ac2149c4305582565dbc0995cd2ad95c Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Tue, 12 Mar 2024 20:57:33 +0100 Subject: [PATCH 05/22] adding labels via kaniko Signed-off-by: munishchouhan --- .../wave/service/builder/BuildStrategy.groovy | 20 +++---- .../service/builder/BuildStrategyTest.groovy | 58 +++++++++---------- 2 files changed, 35 insertions(+), 43 deletions(-) diff --git a/src/main/groovy/io/seqera/wave/service/builder/BuildStrategy.groovy b/src/main/groovy/io/seqera/wave/service/builder/BuildStrategy.groovy index 72e7455b5..c004b7ab3 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/BuildStrategy.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/BuildStrategy.groovy @@ -87,24 +87,18 @@ abstract class BuildStrategy { } if(req.labels){ - result << formatLabels(req.labels) + req.labels.forEach { key, value -> + if (key.contains(' ') || value.contains(' ')) { + result << "--label \"$key\"=\"$value\"" + } else { + result << "--label $key=\"$value\"" + } + } } return result } - static String formatLabels(Map labels) { - def formattedLabels = labels.collect { key, value -> - if (key.contains(' ') || value.contains(' ')) { - return "--label \"$key\"=\"$value\"" - } else { - return "--label $key=\"$value\"" - } - }.join(' ') - - return formattedLabels - } - protected List singularityLaunchCmd(BuildRequest req) { final result = new ArrayList(10) result diff --git a/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy b/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy index cf7af4ca3..900edd290 100644 --- a/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy @@ -105,44 +105,42 @@ class BuildStrategyTest extends Specification { ] } - def "should format labels correctly"() { - given: "a map of labels" + def 'should get kaniko command with build context' () { + given: + def cache = 'reg.io/wave/build/cache' + def service = Spy(BuildStrategy) + service.@buildConfig = new BuildConfig() + def build = Mock(BuildContext) {tarDigest >> '123'} + and: + def work = Path.of('/work/foo') + def REQ = new BuildRequest('from foo', work, 'quay.io/wave', null, null, BuildFormat.DOCKER, Mock(PlatformId), null, build, ContainerPlatform.of('amd64'),'{auth}', cache, null, "", null) def labels = [ "arch": "arm64", "package name": "salmon", "version": "1.0.0" ] - when: "formatting the labels" - def formattedLabels = BuildStrategy.formatLabels(labels) + REQ.withLabels(labels) - then: "the labels are formatted correctly" - formattedLabels == "--label arch=\"arm64\" --label \"package name\"=\"salmon\" --label version=\"1.0.0\"" - } - - def "should handle empty labels correctly"() { - given: "an empty map of labels" - def labels = [:] - - when: "formatting the labels" - def formattedLabels = BuildStrategy.formatLabels(labels) - - then: "the result is an empty string" - formattedLabels == "" - } - - def "should handle null values correctly"() { - given: "a map of labels with null values" - def labels = [ - "description": null, - "package name": "cowsay" + when: + def cmd = service.launchCmd(REQ) + then: + cmd == [ + '--dockerfile', + '/work/foo/3980470531b4a52a/Containerfile', + '--context', + '/work/foo/3980470531b4a52a/context', + '--destination', + 'quay.io/wave:3980470531b4a52a', + '--cache=true', + '--custom-platform', + 'linux/amd64', + '--cache-repo', + 'reg.io/wave/build/cache', + '--label arch=\"arm64\"', + '--label \"package name\"=\"salmon\"', + '--label version=\"1.0.0\"' ] - - when: "formatting the labels" - def formattedLabels = BuildStrategy.formatLabels(labels) - - then: "the labels are formatted correctly, ignoring null values" - formattedLabels == "--label \"package name\"=\"cowsay\"" } } From 1d62b7214d77cf441ecd5b39f2e7b0e4375bee8d Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Wed, 13 Mar 2024 11:04:42 +0100 Subject: [PATCH 06/22] fixed test Signed-off-by: munishchouhan --- .../wave/controller/ContainerTokenControllerTest.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/groovy/io/seqera/wave/controller/ContainerTokenControllerTest.groovy b/src/test/groovy/io/seqera/wave/controller/ContainerTokenControllerTest.groovy index 924ddebeb..9db111107 100644 --- a/src/test/groovy/io/seqera/wave/controller/ContainerTokenControllerTest.groovy +++ b/src/test/groovy/io/seqera/wave/controller/ContainerTokenControllerTest.groovy @@ -264,12 +264,12 @@ class ContainerTokenControllerTest extends Specification { submit = new SubmitContainerTokenRequest(containerFile: encode('FROM foo'), spackFile: encode('some::spack-recipe'), containerPlatform: 'arm64') build = controller.makeBuildRequest(submit, PlatformId.NULL, "") then: - build.id == 'd00a2b3fe3d4d0b8' + build.id == 'b7d730d274d1e057' build.containerFile.endsWith('\nFROM foo') build.containerFile.startsWith('# Builder image\n') build.condaFile == null build.spackFile == 'some::spack-recipe' - build.targetImage == 'wave/build:d00a2b3fe3d4d0b8' + build.targetImage == 'wave/build:b7d730d274d1e057' build.workDir == Path.of('/some/wsp').resolve(build.id) build.platform == ContainerPlatform.of('arm64') } From d3a9e148adcc61810e3f9bcb57e55476c7d6ebf1 Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Wed, 13 Mar 2024 12:41:43 +0100 Subject: [PATCH 07/22] corrected label injection in kaniko Signed-off-by: munishchouhan --- .../io/seqera/wave/service/builder/BuildStrategy.groovy | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/main/groovy/io/seqera/wave/service/builder/BuildStrategy.groovy b/src/main/groovy/io/seqera/wave/service/builder/BuildStrategy.groovy index c004b7ab3..f5a55bccf 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/BuildStrategy.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/BuildStrategy.groovy @@ -88,13 +88,10 @@ abstract class BuildStrategy { if(req.labels){ req.labels.forEach { key, value -> - if (key.contains(' ') || value.contains(' ')) { - result << "--label \"$key\"=\"$value\"" - } else { - result << "--label $key=\"$value\"" + result << '--label' + result << "$key=$value".toString() } } - } return result } From 1318e682ffdd52f670d0b51809a6d334276fb4e6 Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Wed, 13 Mar 2024 13:18:18 +0100 Subject: [PATCH 08/22] tests fixed Signed-off-by: munishchouhan --- .../service/builder/BuildStrategyTest.groovy | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy b/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy index 900edd290..4025002e8 100644 --- a/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy @@ -105,15 +105,14 @@ class BuildStrategyTest extends Specification { ] } - def 'should get kaniko command with build context' () { + def 'should get kaniko command with labels' () { given: def cache = 'reg.io/wave/build/cache' def service = Spy(BuildStrategy) service.@buildConfig = new BuildConfig() - def build = Mock(BuildContext) {tarDigest >> '123'} and: def work = Path.of('/work/foo') - def REQ = new BuildRequest('from foo', work, 'quay.io/wave', null, null, BuildFormat.DOCKER, Mock(PlatformId), null, build, ContainerPlatform.of('amd64'),'{auth}', cache, null, "", null) + def REQ = new BuildRequest('from foo', work, 'quay.io/wave', null, null, BuildFormat.DOCKER, Mock(PlatformId), null, null, ContainerPlatform.of('amd64'),'{auth}', cache, null, "", null) def labels = [ "arch": "arm64", "package name": "salmon", @@ -127,19 +126,22 @@ class BuildStrategyTest extends Specification { then: cmd == [ '--dockerfile', - '/work/foo/3980470531b4a52a/Containerfile', + '/work/foo/c168dba125e28777/Containerfile', '--context', - '/work/foo/3980470531b4a52a/context', + '/work/foo/c168dba125e28777/context', '--destination', - 'quay.io/wave:3980470531b4a52a', + 'quay.io/wave:c168dba125e28777', '--cache=true', '--custom-platform', 'linux/amd64', '--cache-repo', 'reg.io/wave/build/cache', - '--label arch=\"arm64\"', - '--label \"package name\"=\"salmon\"', - '--label version=\"1.0.0\"' + '--label', + 'arch=arm64', + '--label', + 'package name=salmon', + '--label', + 'version=1.0.0' ] } From f863e924ad71687ed9b37c91ee7efa8aed4670a8 Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Wed, 13 Mar 2024 17:30:33 +0100 Subject: [PATCH 09/22] labels added to spack singularity file Signed-off-by: munishchouhan --- .../builder/ContainerBuildServiceImpl.groovy | 19 ++++++++-- .../service/builder/BuildStrategyTest.groovy | 4 +-- .../builder/ContainerBuildServiceTest.groovy | 36 ++++++++++++++++++- 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy b/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy index d684c85b7..bb1761911 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy @@ -139,18 +139,33 @@ class ContainerBuildServiceImpl implements ContainerBuildService { : req.containerFile // render the Spack template if needed + final binding = new HashMap(6) + if ( req.formatSingularity() ){ + binding.labels = req.labels?formatLabels(req.labels):null + } if( req.isSpackBuild ) { - final binding = new HashMap(2) binding.spack_builder_image = config.builderImage binding.spack_runner_image = config.runnerImage binding.spack_arch = SpackHelper.toSpackArch(req.getPlatform()) binding.spack_cache_bucket = config.cacheBucket binding.spack_key_file = config.secretMountPath - return new TemplateRenderer().render(containerFile, binding) } else { return containerFile } + return new TemplateRenderer().render(containerFile, binding) + } + + //this method adds labels in singularity container + protected static String formatLabels(Map labels){ + StringBuilder labelsBuilder = new StringBuilder() + labels.each() { key, value -> + labelsBuilder.append(key) + labelsBuilder.append(" ") + labelsBuilder.append(value) + labelsBuilder.append("\n") + } + return labelsBuilder.toString() } protected BuildResult launch(BuildRequest req) { diff --git a/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy b/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy index 4025002e8..c57e53e16 100644 --- a/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy @@ -115,7 +115,7 @@ class BuildStrategyTest extends Specification { def REQ = new BuildRequest('from foo', work, 'quay.io/wave', null, null, BuildFormat.DOCKER, Mock(PlatformId), null, null, ContainerPlatform.of('amd64'),'{auth}', cache, null, "", null) def labels = [ "arch": "arm64", - "package name": "salmon", + "packageName": "salmon", "version": "1.0.0" ] @@ -139,7 +139,7 @@ class BuildStrategyTest extends Specification { '--label', 'arch=arm64', '--label', - 'package name=salmon', + 'packageName=salmon', '--label', 'version=1.0.0' ] diff --git a/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy b/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy index 443c879e5..4c81c8545 100644 --- a/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy @@ -393,7 +393,6 @@ class ContainerBuildServiceTest extends Specification { and: def layer = new Packer().layer(source) def context = BuildContext.of(layer) - and: when: service.saveBuildContext(context, target, Mock(PlatformId)) @@ -445,4 +444,39 @@ class ContainerBuildServiceTest extends Specification { server?.stop(0) } + def 'should resolve singularity file with labels' () { + given: + def folder = Files.createTempDirectory('test') + def builder = new ContainerBuildServiceImpl() + and: + def context = Path.of('/some/context/dir') + def dockerFile = SpackHelper.builderSingularityTemplate() + def spackFile = 'some spack packages' + def REQ = new BuildRequest(dockerFile, folder, 'box:latest', null, spackFile, BuildFormat.SINGULARITY, Mock(PlatformId),null, null, ContainerPlatform.of('amd64'), null, null, null, "", null) + and: + def labels = [ + "arch": "arm64", + "packageName": "salmon", + "version": "1.0.0" + ] + REQ.withLabels(labels) + and: + def spack = Mock(SpackConfig) + + when: + def result = builder.containerFile0(REQ, context, spack) + then: + 1* spack.getCacheBucket() >> 's3://bucket/cache' + 1* spack.getSecretMountPath() >> '/mnt/key' + 1* spack.getBuilderImage() >> 'spack-builder:2.0' + 1* spack.getRunnerImage() >> 'ubuntu:22.04' + and: + result.contains('arch arm64\n' + + 'packageName salmon\n' + + 'version 1.0.0') + + cleanup: + folder?.deleteDir() + } + } From a9236496bf06d19a341bffd9ab548c03f5d4cbaa Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Wed, 13 Mar 2024 18:20:50 +0100 Subject: [PATCH 10/22] labels added to spack singularity file Signed-off-by: munishchouhan --- .../io/seqera/wave/spack/spack-builder-singularityfile.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/resources/io/seqera/wave/spack/spack-builder-singularityfile.txt b/src/main/resources/io/seqera/wave/spack/spack-builder-singularityfile.txt index 5500cd652..dfc15c143 100644 --- a/src/main/resources/io/seqera/wave/spack/spack-builder-singularityfile.txt +++ b/src/main/resources/io/seqera/wave/spack/spack-builder-singularityfile.txt @@ -2,6 +2,9 @@ Bootstrap: docker From: {{spack_builder_image}} Stage: build +%labels +{{labels}} + %setup cat < ${SINGULARITY_ROOTFS}/aws-env.sh export AWS_STS_REGIONAL_ENDPOINTS=${AWS_STS_REGIONAL_ENDPOINTS} From b7d8049509eb6e82b9a434494c2854996fc6642b Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Wed, 13 Mar 2024 19:01:01 +0100 Subject: [PATCH 11/22] labels added in containerfile and removed from kaniko Signed-off-by: munishchouhan --- .../wave/service/builder/BuildStrategy.groovy | 7 --- .../builder/ContainerBuildServiceImpl.groovy | 39 ++++++++++++---- .../spack/spack-builder-singularityfile.txt | 3 -- .../service/builder/BuildStrategyTest.groovy | 40 ----------------- .../builder/ContainerBuildServiceTest.groovy | 44 ++++++++++++++----- 5 files changed, 63 insertions(+), 70 deletions(-) diff --git a/src/main/groovy/io/seqera/wave/service/builder/BuildStrategy.groovy b/src/main/groovy/io/seqera/wave/service/builder/BuildStrategy.groovy index f5a55bccf..0d8c7dc5b 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/BuildStrategy.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/BuildStrategy.groovy @@ -86,13 +86,6 @@ abstract class BuildStrategy { result << 'AWS_WEB_IDENTITY_TOKEN_FILE=$(AWS_WEB_IDENTITY_TOKEN_FILE)' } - if(req.labels){ - req.labels.forEach { key, value -> - result << '--label' - result << "$key=$value".toString() - } - } - return result } diff --git a/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy b/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy index bb1761911..983556aa5 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy @@ -138,27 +138,38 @@ class ContainerBuildServiceImpl implements ContainerBuildService { ? req.containerFile.replace('{{wave_context_dir}}', context.toString()) : req.containerFile - // render the Spack template if needed - final binding = new HashMap(6) - if ( req.formatSingularity() ){ - binding.labels = req.labels?formatLabels(req.labels):null - } if( req.isSpackBuild ) { + // render the Spack template if needed + final binding = new HashMap(2) binding.spack_builder_image = config.builderImage binding.spack_runner_image = config.runnerImage binding.spack_arch = SpackHelper.toSpackArch(req.getPlatform()) binding.spack_cache_bucket = config.cacheBucket binding.spack_key_file = config.secretMountPath + return new TemplateRenderer().render(containerFile, binding) } else { return containerFile } - return new TemplateRenderer().render(containerFile, binding) } //this method adds labels in singularity container - protected static String formatLabels(Map labels){ + protected static String addLabels(String containerFile, BuildRequest req){ + if(req.labels) { + if (req.formatSingularity()) { + return containerFile + getSingularityLabels(req.labels) + } + if (req.formatDocker()){ + return containerFile + getDockerLabels(req.labels) + } + }else{ + return containerFile + } + } + + protected static String getSingularityLabels(Map labels){ StringBuilder labelsBuilder = new StringBuilder() + labelsBuilder.append("\n%labels\n") labels.each() { key, value -> labelsBuilder.append(key) labelsBuilder.append(" ") @@ -168,6 +179,18 @@ class ContainerBuildServiceImpl implements ContainerBuildService { return labelsBuilder.toString() } + protected static String getDockerLabels(Map labels){ + StringBuilder labelsBuilder = new StringBuilder() + labelsBuilder.append("\nLabel ") + labels.each() { key, value -> + labelsBuilder.append(key) + labelsBuilder.append("=") + labelsBuilder.append(value) + labelsBuilder.append(" ") + } + return labelsBuilder.toString() + } + protected BuildResult launch(BuildRequest req) { // launch an external process to build the container BuildResult resp=null @@ -180,7 +203,7 @@ class ContainerBuildServiceImpl implements ContainerBuildService { catch (FileAlreadyExistsException e) { /* ignore it */ } // save the dockerfile final containerFile = req.workDir.resolve('Containerfile') - Files.write(containerFile, containerFile0(req, context, spackConfig).bytes, CREATE, WRITE, TRUNCATE_EXISTING) + Files.write(containerFile, addLabels(containerFile0(req, context, spackConfig), req).bytes, CREATE, WRITE, TRUNCATE_EXISTING) // save build context if( req.buildContext ) { saveBuildContext(req.buildContext, context, req.identity) diff --git a/src/main/resources/io/seqera/wave/spack/spack-builder-singularityfile.txt b/src/main/resources/io/seqera/wave/spack/spack-builder-singularityfile.txt index dfc15c143..5500cd652 100644 --- a/src/main/resources/io/seqera/wave/spack/spack-builder-singularityfile.txt +++ b/src/main/resources/io/seqera/wave/spack/spack-builder-singularityfile.txt @@ -2,9 +2,6 @@ Bootstrap: docker From: {{spack_builder_image}} Stage: build -%labels -{{labels}} - %setup cat < ${SINGULARITY_ROOTFS}/aws-env.sh export AWS_STS_REGIONAL_ENDPOINTS=${AWS_STS_REGIONAL_ENDPOINTS} diff --git a/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy b/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy index c57e53e16..e41c1c623 100644 --- a/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/builder/BuildStrategyTest.groovy @@ -105,44 +105,4 @@ class BuildStrategyTest extends Specification { ] } - def 'should get kaniko command with labels' () { - given: - def cache = 'reg.io/wave/build/cache' - def service = Spy(BuildStrategy) - service.@buildConfig = new BuildConfig() - and: - def work = Path.of('/work/foo') - def REQ = new BuildRequest('from foo', work, 'quay.io/wave', null, null, BuildFormat.DOCKER, Mock(PlatformId), null, null, ContainerPlatform.of('amd64'),'{auth}', cache, null, "", null) - def labels = [ - "arch": "arm64", - "packageName": "salmon", - "version": "1.0.0" - ] - - REQ.withLabels(labels) - - when: - def cmd = service.launchCmd(REQ) - then: - cmd == [ - '--dockerfile', - '/work/foo/c168dba125e28777/Containerfile', - '--context', - '/work/foo/c168dba125e28777/context', - '--destination', - 'quay.io/wave:c168dba125e28777', - '--cache=true', - '--custom-platform', - 'linux/amd64', - '--cache-repo', - 'reg.io/wave/build/cache', - '--label', - 'arch=arm64', - '--label', - 'packageName=salmon', - '--label', - 'version=1.0.0' - ] - } - } diff --git a/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy b/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy index 4c81c8545..2e6ad2101 100644 --- a/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy @@ -450,9 +450,8 @@ class ContainerBuildServiceTest extends Specification { def builder = new ContainerBuildServiceImpl() and: def context = Path.of('/some/context/dir') - def dockerFile = SpackHelper.builderSingularityTemplate() - def spackFile = 'some spack packages' - def REQ = new BuildRequest(dockerFile, folder, 'box:latest', null, spackFile, BuildFormat.SINGULARITY, Mock(PlatformId),null, null, ContainerPlatform.of('amd64'), null, null, null, "", null) + def singularityFile = "Bootstrap: docker \n from alpine" + def REQ = new BuildRequest(singularityFile, folder, 'box:latest', null, null, BuildFormat.SINGULARITY, Mock(PlatformId),null, null, ContainerPlatform.of('amd64'), null, null, null, "", null) and: def labels = [ "arch": "arm64", @@ -460,18 +459,13 @@ class ContainerBuildServiceTest extends Specification { "version": "1.0.0" ] REQ.withLabels(labels) - and: - def spack = Mock(SpackConfig) when: - def result = builder.containerFile0(REQ, context, spack) + def result = builder.addLabels(builder.containerFile0(REQ, context, null), REQ) + then: - 1* spack.getCacheBucket() >> 's3://bucket/cache' - 1* spack.getSecretMountPath() >> '/mnt/key' - 1* spack.getBuilderImage() >> 'spack-builder:2.0' - 1* spack.getRunnerImage() >> 'ubuntu:22.04' - and: - result.contains('arch arm64\n' + + result.contains('%labels\n'+ + 'arch arm64\n' + 'packageName salmon\n' + 'version 1.0.0') @@ -479,4 +473,30 @@ class ContainerBuildServiceTest extends Specification { folder?.deleteDir() } + def 'should resolve docker file with labels' () { + given: + def folder = Files.createTempDirectory('test') + def builder = new ContainerBuildServiceImpl() + and: + def context = Path.of('/some/context/dir') + def dockerFile = "from alpine" + def REQ = new BuildRequest(dockerFile, folder, 'box:latest', null, null, BuildFormat.DOCKER, Mock(PlatformId),null, null, ContainerPlatform.of('amd64'), null, null, null, "", null) + and: + def labels = [ + "arch": "arm64", + "packageName": "salmon", + "version": "1.0.0" + ] + REQ.withLabels(labels) + + when: + def result = builder.addLabels(builder.containerFile0(REQ, context, null), REQ) + + then: + result.contains('Label arch=arm64 packageName=salmon version=1.0.0') + + cleanup: + folder?.deleteDir() + } + } From e7b3e3984614547213bd6272024e03ac0c4c9f36 Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Wed, 13 Mar 2024 19:02:18 +0100 Subject: [PATCH 12/22] minor formatting Signed-off-by: munishchouhan --- .../wave/service/builder/ContainerBuildServiceImpl.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy b/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy index 983556aa5..07094c2ed 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy @@ -138,8 +138,8 @@ class ContainerBuildServiceImpl implements ContainerBuildService { ? req.containerFile.replace('{{wave_context_dir}}', context.toString()) : req.containerFile + // render the Spack template if needed if( req.isSpackBuild ) { - // render the Spack template if needed final binding = new HashMap(2) binding.spack_builder_image = config.builderImage binding.spack_runner_image = config.runnerImage From 12926e15fe0b383c726712c59eb15f15d23d0bfd Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Fri, 15 Mar 2024 11:40:47 +0100 Subject: [PATCH 13/22] labels moved to containerconfig Signed-off-by: munishchouhan --- .../io/seqera/wave/controller/ContainerTokenController.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/groovy/io/seqera/wave/controller/ContainerTokenController.groovy b/src/main/groovy/io/seqera/wave/controller/ContainerTokenController.groovy index 253d618c8..10b05b855 100644 --- a/src/main/groovy/io/seqera/wave/controller/ContainerTokenController.groovy +++ b/src/main/groovy/io/seqera/wave/controller/ContainerTokenController.groovy @@ -243,8 +243,8 @@ class ContainerTokenController { scanId, ip, offset) - if( req.labels ){ - buildRequest.withLabels(req.labels) + if( req.containerConfig.labels ){ + buildRequest.withLabels(req.containerConfig.labels) } return buildRequest } From 75594897284d92ba2ece1df70d7f67139fc4ca1e Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Tue, 19 Mar 2024 08:52:32 +0100 Subject: [PATCH 14/22] minor change Signed-off-by: munishchouhan --- .../io/seqera/wave/service/builder/BuildRequest.groovy | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy b/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy index 685ed16bf..bd7381e4f 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy @@ -149,7 +149,7 @@ class BuildRequest { /** * Labels to be added in conda and spack build images */ - private Map labels + Map labels BuildRequest(String containerFile, Path workspace, String repo, String condaFile, String spackFile, BuildFormat format, PlatformId identity, ContainerConfig containerConfig, BuildContext buildContext, ContainerPlatform platform, @@ -310,8 +310,4 @@ class BuildRequest { this.labels = labels return this } - - Map getLabels() { - return labels - } } From b0a73dd1b91c88886e4470a9691e80b610ed8f6f Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Wed, 10 Apr 2024 12:59:39 +0200 Subject: [PATCH 15/22] changes as per review --- .../wave/controller/ContainerTokenController.groovy | 6 +----- .../io/seqera/wave/service/builder/BuildRequest.groovy | 10 ---------- .../service/builder/ContainerBuildServiceImpl.groovy | 2 +- .../service/builder/ContainerBuildServiceTest.groovy | 2 +- 4 files changed, 3 insertions(+), 17 deletions(-) diff --git a/src/main/groovy/io/seqera/wave/controller/ContainerTokenController.groovy b/src/main/groovy/io/seqera/wave/controller/ContainerTokenController.groovy index cc08293c7..e43c9fcbe 100644 --- a/src/main/groovy/io/seqera/wave/controller/ContainerTokenController.groovy +++ b/src/main/groovy/io/seqera/wave/controller/ContainerTokenController.groovy @@ -235,7 +235,7 @@ class ContainerTokenController { final offset = DataTimeUtils.offsetId(req.timestamp) final scanId = scanEnabled && format==DOCKER ? LongRndKey.rndHex() : null // create a unique digest to identify the request - def buildRequest = new BuildRequest( + return new BuildRequest( (spackContent ? prependBuilderTemplate(containerSpec,format) : containerSpec), Path.of(buildConfig.buildWorkspace), build, @@ -251,10 +251,6 @@ class ContainerTokenController { scanId, ip, offset) - if( req.containerConfig.labels ){ - buildRequest.withLabels(req.containerConfig.labels) - } - return buildRequest } protected BuildTrack buildRequest(SubmitContainerTokenRequest req, PlatformId identity, String ip) { diff --git a/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy b/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy index fc43c48f5..ee7e0f69d 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/BuildRequest.groovy @@ -142,11 +142,6 @@ class BuildRequest { volatile Path workDir - /** - * Labels to be added in conda and spack build images - */ - Map labels - BuildRequest(String containerFile, Path workspace, String repo, String condaFile, String spackFile, BuildFormat format, PlatformId identity, ContainerConfig containerConfig, BuildContext buildContext, ContainerPlatform platform, String configJson, String cacheRepo, String scanId, String ip, String offsetId) { this.containerId = computeDigest(containerFile, condaFile, spackFile, platform, repo, buildContext) this.containerFile = containerFile @@ -318,11 +313,6 @@ class BuildRequest { format==SINGULARITY } - BuildRequest withLabels(Map labels){ - this.labels = labels - return this - } - BuildRequest withBuildId(String id) { this.buildId = containerId + SEP + id this.workDir = workspace.resolve(buildId).toAbsolutePath() diff --git a/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy b/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy index d470a56ba..d3866c222 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy @@ -189,7 +189,7 @@ class ContainerBuildServiceImpl implements ContainerBuildService { protected static String getDockerLabels(Map labels){ StringBuilder labelsBuilder = new StringBuilder() - labelsBuilder.append("\nLabel ") + labelsBuilder.append("\nLABEL ") labels.each() { key, value -> labelsBuilder.append(key) labelsBuilder.append("=") diff --git a/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy b/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy index 6288937f0..fde59aa8f 100644 --- a/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy @@ -493,7 +493,7 @@ class ContainerBuildServiceTest extends Specification { def result = builder.addLabels(builder.containerFile0(REQ, context, null), REQ) then: - result.contains('Label arch=arm64 packageName=salmon version=1.0.0') + result.contains('LABEL arch=arm64 packageName=salmon version=1.0.0') cleanup: folder?.deleteDir() From a1c0dadab4f126b317c53e250c8aeba797db36ce Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Wed, 10 Apr 2024 13:05:30 +0200 Subject: [PATCH 16/22] changes as per review --- .../wave/service/builder/ContainerBuildServiceImpl.groovy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy b/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy index 97456fb9f..9a1df29ee 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy @@ -167,12 +167,12 @@ class ContainerBuildServiceImpl implements ContainerBuildService { //this method adds labels in singularity container protected static String addLabels(String containerFile, BuildRequest req){ - if(req.labels) { + if(req.containerConfig.labels) { if (req.formatSingularity()) { - return containerFile + getSingularityLabels(req.labels) + return containerFile + getSingularityLabels(req.containerConfig.labels) } if (req.formatDocker()){ - return containerFile + getDockerLabels(req.labels) + return containerFile + getDockerLabels(req.containerConfig.labels) } }else{ return containerFile From 49b16e7b7e26821473400b6f4d6e55ae8b9696d1 Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Wed, 10 Apr 2024 14:25:47 +0200 Subject: [PATCH 17/22] minor change --- .../service/builder/ContainerBuildServiceImpl.groovy | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy b/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy index 9a1df29ee..33c298444 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy @@ -166,17 +166,17 @@ class ContainerBuildServiceImpl implements ContainerBuildService { } //this method adds labels in singularity container - protected static String addLabels(String containerFile, BuildRequest req){ - if(req.containerConfig.labels) { + protected static String addLabels(String containerFile, final BuildRequest req){ + final labels = req.containerConfig?.labels + if(labels) { if (req.formatSingularity()) { - return containerFile + getSingularityLabels(req.containerConfig.labels) + return containerFile + getSingularityLabels(labels) } if (req.formatDocker()){ - return containerFile + getDockerLabels(req.containerConfig.labels) + return containerFile + getDockerLabels(labels) } - }else{ - return containerFile } + return containerFile } protected static String getSingularityLabels(Map labels){ From efdfc1aa5606b41ace2ea74471d887b60fca02bd Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Thu, 11 Apr 2024 22:51:40 +0200 Subject: [PATCH 18/22] changes made as per review --- .../wave/core/ContainerAugmenter.groovy | 10 ++++ .../builder/ContainerBuildServiceImpl.groovy | 40 +------------- .../service/builder/FreezeServiceImpl.groovy | 16 ++++++ .../wave/core/ContainerAugmenterTest.groovy | 3 +- .../builder/ContainerBuildServiceTest.groovy | 55 ------------------- .../builder/FreezeServiceImplTest.groovy | 11 +++- 6 files changed, 39 insertions(+), 96 deletions(-) diff --git a/src/main/groovy/io/seqera/wave/core/ContainerAugmenter.groovy b/src/main/groovy/io/seqera/wave/core/ContainerAugmenter.groovy index 05a7ae97a..357050d82 100644 --- a/src/main/groovy/io/seqera/wave/core/ContainerAugmenter.groovy +++ b/src/main/groovy/io/seqera/wave/core/ContainerAugmenter.groovy @@ -353,6 +353,16 @@ class ContainerAugmenter { if( containerConfig.workingDir ) { config.WorkingDir = containerConfig.workingDir } + if ( containerConfig.labels ) { + def labelsMap = new HashMap<>() + for(String label: containerConfig.labels){ + if(label.contains('=')) { + String[] singleLabelArray = label.split("="); + labelsMap.put(singleLabelArray[0], singleLabelArray[1]); + } + } + config.Labels = labelsMap + } if( containerConfig.env ) { config.Env = appendEnv(config.Env as List, containerConfig.env) } diff --git a/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy b/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy index 33c298444..6536f9667 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/ContainerBuildServiceImpl.groovy @@ -165,44 +165,6 @@ class ContainerBuildServiceImpl implements ContainerBuildService { } } - //this method adds labels in singularity container - protected static String addLabels(String containerFile, final BuildRequest req){ - final labels = req.containerConfig?.labels - if(labels) { - if (req.formatSingularity()) { - return containerFile + getSingularityLabels(labels) - } - if (req.formatDocker()){ - return containerFile + getDockerLabels(labels) - } - } - return containerFile - } - - protected static String getSingularityLabels(Map labels){ - StringBuilder labelsBuilder = new StringBuilder() - labelsBuilder.append("\n%labels\n") - labels.each() { key, value -> - labelsBuilder.append(key) - labelsBuilder.append(" ") - labelsBuilder.append(value) - labelsBuilder.append("\n") - } - return labelsBuilder.toString() - } - - protected static String getDockerLabels(Map labels){ - StringBuilder labelsBuilder = new StringBuilder() - labelsBuilder.append("\nLABEL ") - labels.each() { key, value -> - labelsBuilder.append(key) - labelsBuilder.append("=") - labelsBuilder.append(value) - labelsBuilder.append(" ") - } - return labelsBuilder.toString() - } - protected BuildResult launch(BuildRequest req) { // launch an external process to build the container BuildResult resp=null @@ -215,7 +177,7 @@ class ContainerBuildServiceImpl implements ContainerBuildService { catch (FileAlreadyExistsException e) { /* ignore it */ } // save the dockerfile final containerFile = req.workDir.resolve('Containerfile') - Files.write(containerFile, addLabels(containerFile0(req, context, spackConfig), req).bytes, CREATE, WRITE, TRUNCATE_EXISTING) + Files.write(containerFile, containerFile0(req, context, spackConfig).bytes, CREATE, WRITE, TRUNCATE_EXISTING) // save build context if( req.buildContext ) { saveBuildContext(req.buildContext, context, req.identity) diff --git a/src/main/groovy/io/seqera/wave/service/builder/FreezeServiceImpl.groovy b/src/main/groovy/io/seqera/wave/service/builder/FreezeServiceImpl.groovy index 732ed65de..e9bd7137f 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/FreezeServiceImpl.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/FreezeServiceImpl.groovy @@ -145,6 +145,11 @@ class FreezeServiceImpl implements FreezeService { result += " ${Escape.cli(containerConfig.entrypoint)}\n" } + //add Labels + if( containerConfig.labels ) { + result += '%labels\n' + result += " ${constructLabels(containerConfig.labels)}\n" + } // config work dir is not supported // config command is not supported @@ -166,6 +171,11 @@ class FreezeServiceImpl implements FreezeService { if( containerConfig.env ) { result += "ENV ${containerConfig.env.join(' ')}\n" } + // add Labels + // add ENV + if( containerConfig.labels ) { + result += "LABEL ${constructLabels(containerConfig.labels)}\n" + } // add ENTRY if( containerConfig.entrypoint ) { result += "ENTRYPOINT ${containerConfig.entrypoint.collect(it->"\"$it\"")}\n" @@ -177,4 +187,10 @@ class FreezeServiceImpl implements FreezeService { return result } + static String constructLabels(List labels) { + return labels.collect {label -> + def labelParts = label.split('=') + "${labelParts[0]}=\"${labelParts[1]}\"" + }.join(' ') + } } diff --git a/src/test/groovy/io/seqera/wave/core/ContainerAugmenterTest.groovy b/src/test/groovy/io/seqera/wave/core/ContainerAugmenterTest.groovy index ba3ee7aa9..88b2bea19 100644 --- a/src/test/groovy/io/seqera/wave/core/ContainerAugmenterTest.groovy +++ b/src/test/groovy/io/seqera/wave/core/ContainerAugmenterTest.groovy @@ -554,7 +554,7 @@ class ContainerAugmenterTest extends Specification { def manifest = new JsonSlurper().parseText(MANIFEST) as Map and: - def config = new ContainerConfig(workingDir: '/some/work/dir',entrypoint: ['my','entry'], env: ['THIS=THAT']) + def config = new ContainerConfig(workingDir: '/some/work/dir',entrypoint: ['my','entry'], env: ['THIS=THAT'], labels: ['key=value','key2=value 2']) def scanner = new ContainerAugmenter().withContainerConfig(config) def history = new ArrayList(manifest.history) @@ -580,6 +580,7 @@ class ContainerAugmenterTest extends Specification { v1Config.WorkingDir == '/some/work/dir' v1Config.Entrypoint == ['my','entry'] v1Config.Env == ['PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', 'THIS=THAT'] + v1Config.Labels == ['key2':'value 2', 'key':'value'] } diff --git a/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy b/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy index fde59aa8f..8115d2a81 100644 --- a/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/builder/ContainerBuildServiceTest.groovy @@ -444,59 +444,4 @@ class ContainerBuildServiceTest extends Specification { server?.stop(0) } - def 'should resolve singularity file with labels' () { - given: - def folder = Files.createTempDirectory('test') - def builder = new ContainerBuildServiceImpl() - and: - def context = Path.of('/some/context/dir') - def singularityFile = "Bootstrap: docker \n from alpine" - def REQ = new BuildRequest(singularityFile, folder, 'box:latest', null, null, BuildFormat.SINGULARITY, Mock(PlatformId),null, null, ContainerPlatform.of('amd64'), null, null, null, "", null) - and: - def labels = [ - "arch": "arm64", - "packageName": "salmon", - "version": "1.0.0" - ] - REQ.withLabels(labels) - - when: - def result = builder.addLabels(builder.containerFile0(REQ, context, null), REQ) - - then: - result.contains('%labels\n'+ - 'arch arm64\n' + - 'packageName salmon\n' + - 'version 1.0.0') - - cleanup: - folder?.deleteDir() - } - - def 'should resolve docker file with labels' () { - given: - def folder = Files.createTempDirectory('test') - def builder = new ContainerBuildServiceImpl() - and: - def context = Path.of('/some/context/dir') - def dockerFile = "from alpine" - def REQ = new BuildRequest(dockerFile, folder, 'box:latest', null, null, BuildFormat.DOCKER, Mock(PlatformId),null, null, ContainerPlatform.of('amd64'), null, null, null, "", null) - and: - def labels = [ - "arch": "arm64", - "packageName": "salmon", - "version": "1.0.0" - ] - REQ.withLabels(labels) - - when: - def result = builder.addLabels(builder.containerFile0(REQ, context, null), REQ) - - then: - result.contains('LABEL arch=arm64 packageName=salmon version=1.0.0') - - cleanup: - folder?.deleteDir() - } - } diff --git a/src/test/groovy/io/seqera/wave/service/builder/FreezeServiceImplTest.groovy b/src/test/groovy/io/seqera/wave/service/builder/FreezeServiceImplTest.groovy index 910531622..bd45fa0b5 100644 --- a/src/test/groovy/io/seqera/wave/service/builder/FreezeServiceImplTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/builder/FreezeServiceImplTest.groovy @@ -63,6 +63,7 @@ class FreezeServiceImplTest extends Specification { config = new ContainerConfig( workingDir: '/some/work/dir', env: ['FOO=one', 'BAR=two'], + labels: ['FOO=one', 'BAR=two 2'], cmd:['/this','--that'], entrypoint: ['/my','--entry'], layers: layers) @@ -75,6 +76,7 @@ class FreezeServiceImplTest extends Specification { ADD layer-999fff.tar.gz / WORKDIR /some/work/dir ENV FOO=one BAR=two + LABEL FOO="one" BAR="two 2" ENTRYPOINT ["/my", "--entry"] CMD ["/this", "--that"] '''.stripIndent() @@ -117,7 +119,7 @@ class FreezeServiceImplTest extends Specification { given: def l1 = new ContainerLayer('/some/loc', 'digest1') def l2 = new ContainerLayer('/other/loc', 'digest2') - def config = new ContainerConfig(env:['FOO=1', 'BAR=2'], entrypoint: ['bash', '--this', '--that'], layers: [l1, l2]) + def config = new ContainerConfig(env:['FOO=1', 'BAR=2'], entrypoint: ['bash', '--this', '--that'], layers: [l1, l2], labels: ['FOO=1', 'BAR=value 2']) def req = new SubmitContainerTokenRequest(containerImage: 'ubuntu:latest', freeze: true, format: 'sif', containerConfig: config) when: def result = freezeService.createBuildFile(req, Mock(PlatformId)) @@ -133,6 +135,8 @@ class FreezeServiceImplTest extends Specification { export FOO=1 BAR=2 %runscript bash --this --that + %labels + FOO="1" BAR="value 2" '''.stripIndent(true) } @@ -277,4 +281,9 @@ class FreezeServiceImplTest extends Specification { From: ubuntu:latest '''.stripIndent() } + + def'should construct labels' () { + expect: + FreezeServiceImpl.constructLabels(['FOO=1', 'BAR=value 2']) == 'FOO="1" BAR="value 2"' + } } From 7cf792b33f4fc27ef2840eda359367fec3fec442 Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Fri, 12 Apr 2024 12:26:16 +0800 Subject: [PATCH 19/22] minor makeup Signed-off-by: Dr Marco Claudio De La Pierre --- .../groovy/io/seqera/wave/core/ContainerAugmenter.groovy | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/groovy/io/seqera/wave/core/ContainerAugmenter.groovy b/src/main/groovy/io/seqera/wave/core/ContainerAugmenter.groovy index 357050d82..233047fac 100644 --- a/src/main/groovy/io/seqera/wave/core/ContainerAugmenter.groovy +++ b/src/main/groovy/io/seqera/wave/core/ContainerAugmenter.groovy @@ -354,11 +354,11 @@ class ContainerAugmenter { config.WorkingDir = containerConfig.workingDir } if ( containerConfig.labels ) { - def labelsMap = new HashMap<>() + def labelsMap = new HashMap<>() for(String label: containerConfig.labels){ if(label.contains('=')) { - String[] singleLabelArray = label.split("="); - labelsMap.put(singleLabelArray[0], singleLabelArray[1]); + String[] singleLabelArray = label.split("=") + labelsMap.put(singleLabelArray[0], singleLabelArray[1]) } } config.Labels = labelsMap From 14a7b9480497bde29abfca351161287834355c5f Mon Sep 17 00:00:00 2001 From: Dr Marco Claudio De La Pierre Date: Fri, 12 Apr 2024 12:30:54 +0800 Subject: [PATCH 20/22] consistent order for readability: labels after env Signed-off-by: Dr Marco Claudio De La Pierre --- .../io/seqera/wave/core/ContainerAugmenter.groovy | 6 +++--- .../wave/service/builder/FreezeServiceImpl.groovy | 11 +++++------ 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/main/groovy/io/seqera/wave/core/ContainerAugmenter.groovy b/src/main/groovy/io/seqera/wave/core/ContainerAugmenter.groovy index 233047fac..3ee799fdf 100644 --- a/src/main/groovy/io/seqera/wave/core/ContainerAugmenter.groovy +++ b/src/main/groovy/io/seqera/wave/core/ContainerAugmenter.groovy @@ -353,6 +353,9 @@ class ContainerAugmenter { if( containerConfig.workingDir ) { config.WorkingDir = containerConfig.workingDir } + if( containerConfig.env ) { + config.Env = appendEnv(config.Env as List, containerConfig.env) + } if ( containerConfig.labels ) { def labelsMap = new HashMap<>() for(String label: containerConfig.labels){ @@ -363,9 +366,6 @@ class ContainerAugmenter { } config.Labels = labelsMap } - if( containerConfig.env ) { - config.Env = appendEnv(config.Env as List, containerConfig.env) - } if( entryChain ) { config.Env = appendEnv( config.Env as List, [ "WAVE_ENTRY_CHAIN="+entryChain ] ) } diff --git a/src/main/groovy/io/seqera/wave/service/builder/FreezeServiceImpl.groovy b/src/main/groovy/io/seqera/wave/service/builder/FreezeServiceImpl.groovy index e9bd7137f..28c5d8e4a 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/FreezeServiceImpl.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/FreezeServiceImpl.groovy @@ -139,17 +139,17 @@ class FreezeServiceImpl implements FreezeService { result += '%environment\n' result += " export ${containerConfig.env.join(' ')}\n" } + //add Labels + if( containerConfig.labels ) { + result += '%labels\n' + result += " ${constructLabels(containerConfig.labels)}\n" + } // add ENTRY if( containerConfig.entrypoint ) { result += '%runscript\n' result += " ${Escape.cli(containerConfig.entrypoint)}\n" } - //add Labels - if( containerConfig.labels ) { - result += '%labels\n' - result += " ${constructLabels(containerConfig.labels)}\n" - } // config work dir is not supported // config command is not supported @@ -172,7 +172,6 @@ class FreezeServiceImpl implements FreezeService { result += "ENV ${containerConfig.env.join(' ')}\n" } // add Labels - // add ENV if( containerConfig.labels ) { result += "LABEL ${constructLabels(containerConfig.labels)}\n" } From c4dc4286c68a38cc137f616a80c7bc21e5b4b1ec Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Tue, 16 Apr 2024 13:51:40 +0200 Subject: [PATCH 21/22] added doc --- docs/api.md | 51 +++++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/docs/api.md b/docs/api.md index 766a514df..e0359e2b5 100644 --- a/docs/api.md +++ b/docs/api.md @@ -20,7 +20,8 @@ The endpoint returns the name of the container request made available by Wave. entrypoint: string[], cmd: string[], env: string[], - workingDir: string + workingDir: string, + labels: string[], layers: [ { location: string, @@ -47,29 +48,30 @@ The endpoint returns the name of the container request made available by Wave. ``` #### container token request attributes -| Attribute | Description | -| ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -| `containerImage` | Name of the container to be served, e.g., `docker.io/library/ubuntu:latest` (optional). If omitted, the `containerFile` must be provided. | -| `containerConfig.entrypoint` | The container entrypoint command e.g. `['/bin/bash']` | -| `containerConfig.cmd` | The launch command to be used by the Wave container, e.g., `['echo', 'Hello world']` (optional). | -| `containerConfig.env` | The environment variables to be defined in the Wave container e.g. `['FOO=one','BAR=two']` (optional). | -| `containerConfig.workingDir` | The work directory to be used in the Wave container e.g. `/some/work/dir` (optional). | +| Attribute | Description | +|-------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `containerImage` | Name of the container to be served, e.g., `docker.io/library/ubuntu:latest` (optional). If omitted, the `containerFile` must be provided. | +| `containerConfig.entrypoint` | The container entrypoint command e.g. `['/bin/bash']` | +| `containerConfig.cmd` | The launch command to be used by the Wave container, e.g., `['echo', 'Hello world']` (optional). | +| `containerConfig.env` | The environment variables to be defined in the Wave container e.g. `['FOO=one','BAR=two']` (optional). | +| `containerConfig.workingDir` | The work directory to be used in the Wave container e.g. `/some/work/dir` (optional). | +| `containerConfig.labels` | The lis of labels to be added in container image build by wave e.g. `['author=foo','org=bar']` (optional). | | `containerConfig.layers.location` | Either a HTTP URL from where a container layer tar gzip file should be downloaded or tar gzip file base64 encoded and prefixed with `data:` string (optional). | -| `containerConfig.layers.tarDigest` | The SHA256checksum of the provided tar file e.g. `sha256:a7c724b02...`. | -| `containerConfig.layers.gzipDigest` | The SHA256 checksum of the provided layer tar gzip file e.g. `sha256:a7c724b02...`. | -| `containerConfig.layers.gzipSize` | The size in bytes of the the provided layer tar gzip file. | -| `containerFile` | Dockerfile used for building a new container encoded in base64 (optional). When provided, the attribute `containerImage` should be omitted. | -| `condaFile` | Conda environment file encoded as base64 string. | -| `spackFile` | Spack recipe file encoded as base64 string. | -| `containerPlatform` | Target container architecture of the built container e.g. `linux/amd64` (optional). Currently only supporting amd64 and arm64. | -| `buildRepository` | Container repository where container builds should be pushed e.g. `docker.io/user/my-image` (optional). | -| `cacheRepository` | Container repository used to cache build layers `docker.io/user/my-cache` (optional). | -| `timestamp` | Request submission timestap using ISO-8601. | -| `fingerprint` | Request unique fingerprint. | -| `freeze` | The container provisioned will be stored in the specified repository in a permanently. | -| `towerEndpoint` | Seqera Platform service endpoint from where container repositories credentials are retrieved (optional). Default `https://api.cloud.seqera.io`. | -| `towerAccessToken` | Access token of the user account granting the access to the Seqera Platform service specified via `towerEndpoint` (optional). | -| `towerWorkspaceId` | ID of the Seqera Platform workspace from where the container repositories credentials are retrieved (optional). When omitted the personal workspace is used. | +| `containerConfig.layers.tarDigest` | The SHA256checksum of the provided tar file e.g. `sha256:a7c724b02...`. | +| `containerConfig.layers.gzipDigest` | The SHA256 checksum of the provided layer tar gzip file e.g. `sha256:a7c724b02...`. | +| `containerConfig.layers.gzipSize` | The size in bytes of the the provided layer tar gzip file. | +| `containerFile` | Dockerfile used for building a new container encoded in base64 (optional). When provided, the attribute `containerImage` should be omitted. | +| `condaFile` | Conda environment file encoded as base64 string. | +| `spackFile` | Spack recipe file encoded as base64 string. | +| `containerPlatform` | Target container architecture of the built container e.g. `linux/amd64` (optional). Currently only supporting amd64 and arm64. | +| `buildRepository` | Container repository where container builds should be pushed e.g. `docker.io/user/my-image` (optional). | +| `cacheRepository` | Container repository used to cache build layers `docker.io/user/my-cache` (optional). | +| `timestamp` | Request submission timestap using ISO-8601. | +| `fingerprint` | Request unique fingerprint. | +| `freeze` | The container provisioned will be stored in the specified repository in a permanently. | +| `towerEndpoint` | Seqera Platform service endpoint from where container repositories credentials are retrieved (optional). Default `https://api.cloud.seqera.io`. | +| `towerAccessToken` | Access token of the user account granting the access to the Seqera Platform service specified via `towerEndpoint` (optional). | +| `towerWorkspaceId` | ID of the Seqera Platform workspace from where the container repositories credentials are retrieved (optional). When omitted the personal workspace is used. | ### Response @@ -112,7 +114,8 @@ The endpoint returns the name of the container request made available by Wave. tarDigest: string }, ... - ] + ], + labels: string[] }, condaFile: string, spackFile: string, From 5bcaa8699ad8539c8a73ed1a57fc373382b3e8fc Mon Sep 17 00:00:00 2001 From: munishchouhan Date: Tue, 16 Apr 2024 13:52:21 +0200 Subject: [PATCH 22/22] fixed typo --- docs/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.md b/docs/api.md index e0359e2b5..2a0678f8d 100644 --- a/docs/api.md +++ b/docs/api.md @@ -66,7 +66,7 @@ The endpoint returns the name of the container request made available by Wave. | `containerPlatform` | Target container architecture of the built container e.g. `linux/amd64` (optional). Currently only supporting amd64 and arm64. | | `buildRepository` | Container repository where container builds should be pushed e.g. `docker.io/user/my-image` (optional). | | `cacheRepository` | Container repository used to cache build layers `docker.io/user/my-cache` (optional). | -| `timestamp` | Request submission timestap using ISO-8601. | +| `timestamp` | Request submission timestamp using ISO-8601. | | `fingerprint` | Request unique fingerprint. | | `freeze` | The container provisioned will be stored in the specified repository in a permanently. | | `towerEndpoint` | Seqera Platform service endpoint from where container repositories credentials are retrieved (optional). Default `https://api.cloud.seqera.io`. |