Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable streaming of build logs #459

Draft
wants to merge 40 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
ff70a52
add getlogs method
munishchouhan Apr 17, 2024
6f3cd8f
fixed builderName
munishchouhan Apr 17, 2024
16481a0
Merge branch 'master' into 451-enable-streaming-of-build-logs
munishchouhan Apr 18, 2024
8af97ef
fixed DockerBuildStrategyTest
munishchouhan Apr 18, 2024
22a574e
Merge remote-tracking branch 'origin/451-enable-streaming-of-build-lo…
munishchouhan Apr 18, 2024
d228dd9
added BuildLogLocalServiceImpl
munishchouhan Apr 18, 2024
a5ba7d9
added getCurrentLogsPod(String name)
munishchouhan Apr 18, 2024
6cb5e0e
fixed logs color issue
munishchouhan Apr 18, 2024
eafcb94
added build in progress phase and dynamic logs loading
munishchouhan Apr 18, 2024
c335997
minor change
munishchouhan Apr 18, 2024
26fdb65
changed to inputstream
munishchouhan Apr 19, 2024
93491f5
strip ansi escape codes
munishchouhan Apr 19, 2024
7869323
added docs
munishchouhan Apr 19, 2024
b287a56
fixed tests
munishchouhan Apr 19, 2024
a294b64
added test
munishchouhan Apr 19, 2024
94f40e7
corrected docs
munishchouhan Apr 19, 2024
db5afde
corrected docs
munishchouhan Apr 19, 2024
f6bb71c
Merge branch 'master' into 451-enable-streaming-of-build-logs
munishchouhan Apr 22, 2024
e7313e7
Merge branch 'master' into 451-enable-streaming-of-build-logs
munishchouhan Apr 22, 2024
1def98a
updated doc [ci skip]
munishchouhan Apr 22, 2024
a43a160
Merge remote-tracking branch 'origin/451-enable-streaming-of-build-lo…
munishchouhan Apr 22, 2024
a559584
reverted doc changes
munishchouhan Apr 22, 2024
0c06d3c
Merge branch 'master' into 451-enable-streaming-of-build-logs
pditommaso Apr 23, 2024
153b0df
Merge branch 'master' into 451-enable-streaming-of-build-logs
munishchouhan Apr 23, 2024
96afbb9
Merge branch 'master' into 451-enable-streaming-of-build-logs
munishchouhan May 4, 2024
534da81
Merge branch 'master' into 451-enable-streaming-of-build-logs
munishchouhan May 15, 2024
4859154
Merge branch 'master' into 451-enable-streaming-of-build-logs
munishchouhan Jun 11, 2024
fd9ea32
fix tests
munishchouhan Jun 11, 2024
7dedb5f
Merge branch 'master' into 451-enable-streaming-of-build-logs
munishchouhan Jul 22, 2024
aeb386c
Merge branch 'master' into 451-enable-streaming-of-build-logs
munishchouhan Aug 14, 2024
0c53ec5
Merge branch 'master' into 451-enable-streaming-of-build-logs
munishchouhan Aug 20, 2024
59f25e8
Merge branch 'master' into 451-enable-streaming-of-build-logs
munishchouhan Aug 29, 2024
1511ddb
fixed errors
munishchouhan Aug 29, 2024
167a9ad
fixed errors
munishchouhan Aug 30, 2024
1752d55
master merged
munishchouhan Oct 17, 2024
e09c9ec
Merge branch 'master' into 451-enable-streaming-of-build-logs
munishchouhan Oct 22, 2024
d6b19e5
fixed error
munishchouhan Oct 22, 2024
ed403ee
fixed error
munishchouhan Oct 22, 2024
1c304b1
fixed tests
munishchouhan Oct 22, 2024
7b09548
Merge branch 'master' into 451-enable-streaming-of-build-logs
munishchouhan Nov 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ abstract class BuildStrategy {
private BuildConfig buildConfig

abstract void build(String jobName, BuildRequest req)


abstract InputStream getLogs(String buildId)

static final public String BUILDKIT_ENTRYPOINT = 'buildctl-daemonless.sh'

List<String> launchCmd(BuildRequest req) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,4 +156,16 @@ class DockerBuildStrategy extends BuildStrategy {
wrapper.add(buildConfig.singularityImage(platform))
return wrapper
}


@Override
InputStream getLogs(String jobName) {
def logCmd = ['docker', 'logs'] + jobName
log.info("Get build logs: ${logCmd.join(' ')}")
final proc = new ProcessBuilder()
.command(logCmd)
.redirectErrorStream(true)
.start()
return proc.inputStream
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ class KubeBuildStrategy extends BuildStrategy {
}
}

@Override
InputStream getLogs(String jobName) {
final pod = k8sService.getLatestPodForJob(jobName)
return k8sService.getCurrentLogsPod(pod.spec.containers.first().name)
}

protected String getBuildImage(BuildRequest buildRequest){
if( buildRequest.formatDocker() ) {
return buildConfig.buildkitImage
Expand Down
2 changes: 2 additions & 0 deletions src/main/groovy/io/seqera/wave/service/k8s/K8sService.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ interface K8sService {

V1Job launchMirrorJob(String name, String containerImage, List<String> args, Path workDir, Path creds, MirrorConfig config)

InputStream getCurrentLogsPod(String name)

V1Pod getLatestPodForJob(String jobName)

}
19 changes: 19 additions & 0 deletions src/main/groovy/io/seqera/wave/service/k8s/K8sServiceImpl.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,25 @@ class K8sServiceImpl implements K8sService {
}
}

/**
* Fetch current available logs of a running pod
*
* @param name The pod name
* @return The logs as a string or when logs are not available or cannot be accessed
*/
@Override
InputStream getCurrentLogsPod(String name) {
try {
def logs = k8sClient.coreV1Api().readNamespacedPodLog(name, namespace, name, false, null, null, "false", false, null, null, null)
logs = logs ? logs.replaceAll("\u001B\\[[;\\d]*m", "") : null // strip ansi escape codes
return new ByteArrayInputStream(logs.getBytes())
} catch (Exception e) {
// logging trace here because errors are expected when the pod is not running
log.trace "Unable to fetch logs for pod: $name", e
return null
}
}

/**
* Delete a pod
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

package io.seqera.wave.service.logs

import java.nio.charset.StandardCharsets
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ExecutorService

Expand All @@ -27,6 +28,7 @@ import groovy.transform.CompileStatic
import groovy.util.logging.Slf4j
import io.micronaut.context.annotation.Requires
import io.micronaut.context.annotation.Value
import io.micronaut.http.MediaType
import io.micronaut.http.server.types.files.StreamedFile
import io.micronaut.objectstorage.ObjectStorageEntry
import io.micronaut.objectstorage.ObjectStorageOperations
Expand All @@ -35,6 +37,7 @@ import io.micronaut.runtime.event.annotation.EventListener
import io.micronaut.scheduling.TaskExecutors
import io.seqera.wave.service.builder.BuildEvent
import io.seqera.wave.service.builder.BuildRequest
import io.seqera.wave.service.builder.BuildStrategy
import io.seqera.wave.service.persistence.PersistenceService
import jakarta.annotation.PostConstruct
import jakarta.inject.Inject
Expand Down Expand Up @@ -64,6 +67,9 @@ class BuildLogServiceImpl implements BuildLogService {
@Inject
private PersistenceService persistenceService

@Inject
private BuildStrategy buildStrategy

@Nullable
@Value('${wave.build.logs.prefix}')
private String prefix
Expand Down Expand Up @@ -129,7 +135,14 @@ class BuildLogServiceImpl implements BuildLogService {
private StreamedFile fetchLogStream0(String buildId) {
if( !buildId ) return null
final Optional<ObjectStorageEntry<?>> result = objectStorageOperations.retrieve(logKey(buildId))
return result.isPresent() ? result.get().toStreamedFile() : null
return result.isPresent() ? result.get().toStreamedFile() : fetchLogStream1(buildId)
}

private StreamedFile fetchLogStream1(String buildId) {
def logStream = buildStrategy.getLogs(buildId)
if( !logStream )
return null
return logStream ? new StreamedFile(logStream, MediaType.APPLICATION_OCTET_STREAM_TYPE) : null
}

@Override
Expand Down
59 changes: 59 additions & 0 deletions src/main/resources/io/seqera/wave/build-view.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,21 @@
Container build failed
</h4>
</div>
{{else build_in_progress}}
<div style="color: #3c763d; background-color: #ffd300; padding: 15px; border: 1px solid transparent; border-radius: 4px;">
<h4 style="margin-top:0; color: inherit;">
Container build in progress
<div style="color: #3c763d; background-color: #dff0d8; padding: 15px; border: 1px solid transparent; border-radius: 4px;">
<h4 style="margin-top:0; color: inherit;">
Container build completed successfully!
</h4>
</div>
{{else build_failed}}
<div style="color: #a94442; background-color: #f2dede; padding: 15px; border: 1px solid transparent; border-radius: 4px;">
<h4 style="margin-top:0; color: inherit;">
Container build failed
</h4>
</div>
{{else build_in_progress}}
{{! build is not completed, show a spinning icon }}
<style>
Expand Down Expand Up @@ -209,6 +224,11 @@
{{/if}}

{{#if build_log_data}}
<h3>Build logs</h3>
<pre id="buildLogs" style="white-space: pre-wrap; overflow-x: auto; overflow-y: auto; background-color: #ededed; padding: 15px; border-radius: 4px; margin-bottom:30px;">{{build_log_data}}</pre>
{{#if build_log_truncated}}
<a href="{{build_log_url}}" download>Click here to download the complete build log</a>
{{/if}}
<h3>Build logs</h3>
<div style="position: relative; margin-bottom: 30px;">
<button id="logCopyBtn" class="copy-btn2" onclick="copyToClipboard('logData', 'logCopyBtn')" title="Copy">
Expand All @@ -226,6 +246,45 @@
</div>
{{/if}}

<script>
function checkStatusAndFetchData() {
fetch("{{server_url}}/v1alpha1/builds/{{build_id}}/status", {method: 'GET'})
.then(response => {
if (!response.ok) {
clearInterval(interval)
return;
}
return response.json();
}).then(statusResponse => {
if (statusResponse.status === 'PENDING') {
fetchData();
}else{
clearInterval(interval)
}
}).catch(error => {
console.error('Error checking status:', error)
clearInterval(interval)
});
}
function fetchData() {
fetch('{{server_url}}/v1alpha1/builds/{{build_id}}/logs', {method: 'GET', cache: 'no-cache'})
.then(response => {
if (!response.ok) {
clearInterval(interval)
return;
}
return response.text();
}).then(logs => {
document.getElementById('buildLogs').innerHTML = logs;
}).catch(error => {
console.error('Error fetching build logs:', error)
clearInterval(interval)
});
}

const interval = setInterval(checkStatusAndFetchData, 2000);
</script>

<div class="footer" style="clear:both;width:100%;">
<hr class="footer-hr" style="height:0;overflow:visible;margin-top:30px;border:0;border-top:1px solid #eee;color:#999999;font-size:12px;line-height:18px;margin-bottom:30px;">
<img style="float:right; width: 150px;" src="data:image/png;base64,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">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ class ContainerBuildServiceTest extends Specification {
// do nothing
log.debug "Running fake build job=$jobName - request=$request"
}

@Override
InputStream getLogs(String podName) {
return "logs for pod name"
}
}

@Primary
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,21 @@ class DockerBuildStrategyTest extends Specification {
def work = Path.of('/work/foo')
when:
def cmd = service.cmdForBuildkit('build-job-name', work, null, null)
def name = 'build-job-name'
then:
cmd == ['docker',
'run',
'--detach',
'--name',
'build-job-name',
name,
'--privileged',
'-v', '/work/foo:/work/foo',
'--entrypoint',
'buildctl-daemonless.sh',
'moby/buildkit:v0.14.1-rootless']

when:
cmd = service.cmdForBuildkit('build-job-name', work, Path.of('/foo/creds.json'), ContainerPlatform.of('arm64'))
cmd = service.cmdForBuildkit(name, work, Path.of('/foo/creds.json'), ContainerPlatform.of('arm64'))
then:
cmd == ['docker',
'run',
Expand Down Expand Up @@ -96,6 +97,7 @@ class DockerBuildStrategyTest extends Specification {
def creds = Path.of('/work/creds.json')
and:
def req = new BuildRequest(
id: '89fb83ce6ec8627b',
containerId: '89fb83ce6ec8627b',
buildId: 'bd-89fb83ce6ec8627b_1',
workspace: Path.of('/work/foo'),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,25 @@ class K8sServiceImplTest extends Specification {
ctx.close()
}

def "should get pod logs"() {
given:
def k8sClient = Mock(K8sClient)
def k8sService = new K8sServiceImpl(k8sClient: k8sClient)
def name = "builder-pod"
def logs = "\u001B[31mINFO: Build is in progress"

when:
InputStream result = k8sService.getCurrentLogsPod(name)

then:
2 * k8sClient.coreV1Api() >> Mock(CoreV1Api)
1 * k8sClient.coreV1Api().readNamespacedPodLog(_, _, _, _, _, _, _, _, _, _, _) >> logs
and:
result instanceof ByteArrayInputStream
String resultString = result.text
resultString == "INFO: Build is in progress"
}

def "getLatestPodForJob should return the latest pod when multiple pods are present"() {
given:
def jobName = "test-job"
Expand Down