diff --git a/src/main/groovy/io/seqera/wave/service/blob/impl/KubeTransferStrategy.groovy b/src/main/groovy/io/seqera/wave/service/blob/impl/KubeTransferStrategy.groovy index 0a5393714..1dcb04256 100644 --- a/src/main/groovy/io/seqera/wave/service/blob/impl/KubeTransferStrategy.groovy +++ b/src/main/groovy/io/seqera/wave/service/blob/impl/KubeTransferStrategy.groovy @@ -53,9 +53,13 @@ class KubeTransferStrategy implements TransferStrategy { final job = k8sService.transferJob(name, blobConfig.s5Image, command, blobConfig) final podList = k8sService.waitJob(job, blobConfig.transferTimeout.toMillis()) final size = podList.items.size() + + if( size < 1 ) + throw new TransferTimeoutException("Transfer job timeout") + final podName = podList.items[size - 1].metadata.name final pod = k8sService.getPod(podName) - final terminated = k8sService.waitPod(pod, blobConfig.transferTimeout.toMillis()) + final terminated = k8sService.waitPod(pod, name, blobConfig.transferTimeout.toMillis()) final stdout = k8sService.logsPod(podName, name) return terminated ? info.completed(terminated.exitCode, stdout) diff --git a/src/main/groovy/io/seqera/wave/service/builder/KubeBuildStrategy.groovy b/src/main/groovy/io/seqera/wave/service/builder/KubeBuildStrategy.groovy index 453945a06..be7fdc178 100644 --- a/src/main/groovy/io/seqera/wave/service/builder/KubeBuildStrategy.groovy +++ b/src/main/groovy/io/seqera/wave/service/builder/KubeBuildStrategy.groovy @@ -101,7 +101,7 @@ class KubeBuildStrategy extends BuildStrategy { final spackCfg0 = req.isSpackBuild ? spackConfig : null final pod = k8sService.buildContainer(name, buildImage, buildCmd, req.workDir, configFile, spackCfg0, selector) final terminated = k8sService.waitPod(pod, buildConfig.buildTimeout.toMillis()) - final stdout = k8sService.logsPod(name, name) + final stdout = k8sService.logsPod(name) if( terminated ) { final digest = proxyService.getImageDigest(req.targetImage) return BuildResult.completed(req.buildId, terminated.exitCode, stdout, req.startTime, digest) diff --git a/src/main/groovy/io/seqera/wave/service/k8s/K8sService.groovy b/src/main/groovy/io/seqera/wave/service/k8s/K8sService.groovy index 27b8b7689..8eb624393 100644 --- a/src/main/groovy/io/seqera/wave/service/k8s/K8sService.groovy +++ b/src/main/groovy/io/seqera/wave/service/k8s/K8sService.groovy @@ -44,6 +44,8 @@ interface K8sService { V1Pod getPod(String name) + String logsPod(String podName) + String logsPod(String podName, String containerName) void deletePod(String name) @@ -56,6 +58,8 @@ interface K8sService { V1ContainerStateTerminated waitPod(V1Pod pod, long timeout) + V1ContainerStateTerminated waitPod(V1Pod pod, String containerName, long timeout) + V1Job transferJob(String name, String containerImage, List args, BlobCacheConfig blobConfig) V1PodList waitJob(V1Job job, Long timeout) diff --git a/src/main/groovy/io/seqera/wave/service/k8s/K8sServiceImpl.groovy b/src/main/groovy/io/seqera/wave/service/k8s/K8sServiceImpl.groovy index dd131179c..3d4288d81 100644 --- a/src/main/groovy/io/seqera/wave/service/k8s/K8sServiceImpl.groovy +++ b/src/main/groovy/io/seqera/wave/service/k8s/K8sServiceImpl.groovy @@ -417,13 +417,29 @@ class K8sServiceImpl implements K8sService { */ @Override V1ContainerStateTerminated waitPod(V1Pod pod, long timeout) { + return waitPod(pod, pod.metadata.name, timeout) + } + + /** + * Wait for a pod a completion + * + * @param pod + * The pod name + * @param timeout + * Max wait time in milliseconds + * @return + * An instance of {@link V1ContainerStateTerminated} representing the termination state + * or {@code null} if the state cannot be determined or timeout was reached, + */ + @Override + V1ContainerStateTerminated waitPod(V1Pod pod, String containerName, long timeout) { final name = pod.metadata.name final start = System.currentTimeMillis() // wait for termination while( true ) { final phase = pod.status?.phase if( phase && phase != 'Pending' ) { - final status = pod.status.containerStatuses.find( it -> it.name==name ) + final status = pod.status.containerStatuses.find( it -> it.name==containerName ) if( !status ) return null if( !status.state ) @@ -443,6 +459,17 @@ class K8sServiceImpl implements K8sService { } } + /** + * Fetch the logs of a pod + * + * @param name The pod name + * @return The logs as a string or when logs are not available or cannot be accessed + */ + @Override + String logsPod(String podName) { + logsPod(podName, podName) + } + /** * Fetch the logs of a pod * @@ -461,6 +488,7 @@ class K8sServiceImpl implements K8sService { } } + /** * Delete a pod * diff --git a/src/main/groovy/io/seqera/wave/service/scan/KubeScanStrategy.groovy b/src/main/groovy/io/seqera/wave/service/scan/KubeScanStrategy.groovy index 49e31113a..c17b9bb85 100644 --- a/src/main/groovy/io/seqera/wave/service/scan/KubeScanStrategy.groovy +++ b/src/main/groovy/io/seqera/wave/service/scan/KubeScanStrategy.groovy @@ -99,7 +99,7 @@ class KubeScanStrategy extends ScanStrategy { return ScanResult.success(req, startTime, TrivyResultProcessor.process(reportFile.text)) } else{ - final stdout = k8sService.logsPod(podName, podName) + final stdout = k8sService.logsPod(podName) log.info("Container scan failed for scan id: ${req.id} - stdout: $stdout") return ScanResult.failure(req, startTime) } diff --git a/src/test/groovy/io/seqera/wave/service/k8s/K8sClientTest.groovy b/src/test/groovy/io/seqera/wave/service/k8s/K8sClientTest.groovy index c7099c8c8..64f0e1d74 100644 --- a/src/test/groovy/io/seqera/wave/service/k8s/K8sClientTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/k8s/K8sClientTest.groovy @@ -51,6 +51,26 @@ class K8sClientTest extends Specification { true } + def 'should create pod' () { + when: + def pod = k8sService.buildContainer( + 'my-pod', + 'busybox', + ['cat','/kaniko/.docker/config.json'], + Path.of('/work/dir'), + Path.of('/creds'), + Path.of('/spack/dir'), + ['my-creds': 'selector']) + then: + true + + when: + def str = k8sService.logsPod('my-pod') + then: + str + + } + def 'should create pod' () { when: def pod = k8sService.buildContainer(