Skip to content

fix(jenkins): bound journal and coredump collection to the current build - #15669

Open
fruch wants to merge 1 commit into
masterfrom
fix/bound-builder-log-collection
Open

fix(jenkins): bound journal and coredump collection to the current build#15669
fruch wants to merge 1 commit into
masterfrom
fix/bound-builder-log-collection

Conversation

@fruch

@fruch fruch commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

What

Split out of #15618 per review: both builder-side collectors assume a builder that dies after its
build, which stops being true the moment a job runs on a static agent. Groundwork for that,
independent of any backend.

  • collectBuilderLogs ran an unbounded sudo journalctl, so every build uploaded the host's
    entire journal — weeks of it on a long-lived machine — and a sudo that is not passwordless
    aborted the stage outright. Now bounded by the build's start time, and it degrades to the
    current boot instead of failing when sudo is unavailable.
  • upload_sct_coredump.sh tarred every coredump the host had ever produced, including other
    jobs' and other tenants'. Now bounded by build start time as well.

Why it was in a minicloud PR

Both bit a minicloud run on a lab machine, which is how they were found — but neither has anything
to do with minicloud, so per review they land on their own.

Tests

sh -n clean; each bounded command run standalone against a live journal, including the
no-passwordless-sudo path. No behaviour change on ephemeral cloud builders, where the build start
time is a few minutes after boot and everything is in range anyway.

🤖 Generated with Claude Code

Copilot AI balanced review requested due to automatic review settings August 4, 2026 14:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Bounds builder journal and coredump collection by Jenkins build start time for long-lived agents.

Changes:

  • Filters journal entries and coredumps by build start time.
  • Makes privileged journal collection non-interactive.
  • Adds a 24-hour fallback window for standalone coredump collection.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
vars/collectTestCoredumps.groovy Passes the build timestamp to the collector.
vars/collectBuilderLogs.groovy Bounds journal collection and handles sudo failure.
utils/upload_sct_coredump.sh Archives only recently created coredumps.

Comment on lines +19 to +24
if sudo -n journalctl --since "@${sinceEpoch}" --no-tail --no-pager -o short-precise > builder-\$SHORT_SCT_TEST_ID.log ; then
tar -zcvf builder-\$SHORT_SCT_TEST_ID.log.tar.gz builder-\$SHORT_SCT_TEST_ID.log
./docker/env/hydra.sh upload --test-id \$SCT_TEST_ID builder-\$SHORT_SCT_TEST_ID.log.tar.gz
else
echo "WARNING: sudo -n journalctl failed on \$(hostname) - skipping builder journal upload"
fi

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed - you were right that the code did not do what the PR description promised. It now tries sudo -n journalctl first, falls back to an unprivileged journalctl with the same --since bound, and only skips the upload when both fail; the log line says which source produced the archive.

I kept the --since bound on the fallback rather than switching to --boot: the bound is the point of the change (weeks of a static agent's journal), and on a machine that has been up for a month --boot would bring most of it back. Verified all three paths with stub sudo/journalctl on PATH: sudo works, sudo fails then plain works, both fail -> skip.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Coredump collection in upload_sct_coredump.sh now filters files by SCT_COREDUMPS_SINCE_EPOCH (default: prior 24 hours), archiving only matched files, and skips upload when none exist. collectTestCoredumps.groovy computes the build start epoch and passes it to the script. collectBuilderLogs.groovy restricts journalctl output to entries since build start, uses non-interactive sudo, and warns without failing the stage when journal reads are unreadable.

Estimated code review effort: 2 (Simple) | ~12 minutes

Suggested labels: Bug

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes bounding journal and coredump collection to the current build.
Description check ✅ Passed The description explains the changes, rationale, scope, and tests; it omits the template checkbox sections but remains mostly complete.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/bound-builder-log-collection

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@vars/collectBuilderLogs.groovy`:
- Around line 19-24: Update the journal collection fallback in
collectBuilderLogs so that when the sudo journalctl command fails, it retries
journalctl without sudo while restricting results to the current boot, and
continues with the existing archive and upload flow if that succeeds; only emit
the warning and skip upload when the fallback also fails.

In `@vars/collectTestCoredumps.groovy`:
- Line 7: Preserve fractional epoch precision in the since-time calculation used
by collectTestCoredumps.groovy at lines 7-7 and collectBuilderLogs.groovy at
lines 8-8. Update the shared collection-bound logic in each file so
SCT_COREDUMPS_SINCE_EPOCH and journalctl --since receive millisecond-precise
values rather than truncated whole seconds.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: b7908ecc-ecc0-40f2-849b-107c21cc31fe

📥 Commits

Reviewing files that changed from the base of the PR and between f264c99 and 9264ba5.

📒 Files selected for processing (3)
  • utils/upload_sct_coredump.sh
  • vars/collectBuilderLogs.groovy
  • vars/collectTestCoredumps.groovy

Comment on lines +19 to +24
if sudo -n journalctl --since "@${sinceEpoch}" --no-tail --no-pager -o short-precise > builder-\$SHORT_SCT_TEST_ID.log ; then
tar -zcvf builder-\$SHORT_SCT_TEST_ID.log.tar.gz builder-\$SHORT_SCT_TEST_ID.log
./docker/env/hydra.sh upload --test-id \$SCT_TEST_ID builder-\$SHORT_SCT_TEST_ID.log.tar.gz
else
echo "WARNING: sudo -n journalctl failed on \$(hostname) - skipping builder journal upload"
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Implement the current-boot fallback.

If sudo -n journalctl fails, this branch only skips collection. It does not collect the readable current boot. Run the non-sudo current-boot fallback before skipping the upload.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@vars/collectBuilderLogs.groovy` around lines 19 - 24, Update the journal
collection fallback in collectBuilderLogs so that when the sudo journalctl
command fails, it retries journalctl without sudo while restricting results to
the current boot, and continues with the existing archive and upload flow if
that succeeds; only emit the warning and skip upload when the fallback also
fails.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implemented - see the reply on the sibling thread for detail: sudo -n first, unprivileged journalctl as the fallback, skip only when both fail, and the archive/upload flow is shared by both success paths. One deviation from the suggestion: the fallback keeps --since @<build start> rather than --boot, because bounding the window is the whole point of this change and --boot on a long-lived agent would restore most of what it removes.

// Bound the coredump sweep to this build: on a long-lived agent the coredump directory holds
// every dump the host ever produced (other jobs' included), and unbounded the script tars and
// uploads all of it. Epoch seconds, consumed by upload_sct_coredump.sh via -newermt.
def sinceEpoch = (long) (currentBuild.startTimeInMillis / 1000)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- vars/collectTestCoredumps.groovy ---'
cat -n vars/collectTestCoredumps.groovy
printf '%s\n' '--- vars/collectBuilderLogs.groovy ---'
cat -n vars/collectBuilderLogs.groovy
printf '%s\n' '--- references ---'
rg -n -F 'SCT_COREDUMPS_SINCE_EPOCH' . || true
rg -n -F 'collectTestCoredumps' . || true
rg -n -F 'collectBuilderLogs' . || true

Repository: scylladb/scylla-cluster-tests

Length of output: 2931


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- utils/upload_sct_coredump.sh ---'
cat -n utils/upload_sct_coredump.sh
printf '%s\n' '--- vars/runCollectLogs.groovy ---'
cat -n vars/runCollectLogs.groovy
printf '%s\n' '--- timestamp consumers ---'
rg -n -C 4 'SINCE_EPOCH|journalctl|newermt|find .*core|coredump' utils vars

Repository: scylladb/scylla-cluster-tests

Length of output: 13823


🏁 Script executed:

#!/bin/bash
set -e
python3 - <<'PY'
from decimal import Decimal

start_ms = 1_700_000_000_750
start_s = Decimal(start_ms) / Decimal(1000)
truncated_s = start_ms // 1000

samples = {
    "prior_same_second": Decimal("1700000000.500"),
    "build_start": start_s,
    "after_start": Decimal("1700000000.900"),
}
print(f"build_start={start_s}")
print(f"truncated_lower_bound={truncated_s}")
for name, record_s in samples.items():
    print(
        f"{name}: record={record_s} "
        f"included_with_truncated={record_s > truncated_s} "
        f"included_with_fractional={record_s > start_s}"
    )
PY

printf '%s\n' '--- GNU find fractional timestamp parsing ---'
find /dev/null -newermt '`@1700000000.750`' -print >/dev/null
echo "find_exit=$?"

printf '%s\n' '--- journalctl fractional timestamp parsing ---'
set +e
journalctl --since '`@1700000000.750`' --until '`@1700000000.751`' --no-pager --no-hostname -o cat >/dev/null 2>&1
status=$?
set -e
echo "journalctl_exit=$status"

Repository: scylladb/scylla-cluster-tests

Length of output: 641


🌐 Web query:

journalctl --since @ UNIX timestamp fractional seconds timestamp grammar

💡 Result:

When using the --since or --until options in journalctl, you can specify a UNIX epoch timestamp by prefixing an integer or floating-point number with the "@" character [1]. The systemd time parsing logic, documented in systemd.time(7), supports fractional seconds for UNIX timestamps [1]. This allows you to achieve sub-second precision by including a decimal component after the integer portion of the timestamp (e.g., --since=@1625097600.500) [2][1]. In practical application, if you are generating this timestamp in a script, it is common to use tools like date to produce the required format: journalctl --since=@$(date +%s.%6N) In this example, +%s.%6N produces the UNIX epoch followed by a decimal point and 6 digits of microsecond precision, which journalctl will parse correctly [2].

Citations:


Sensitive Data Exposure (CWE-200): Exposure of Sensitive Information to an Unauthorized Actor

Reachability: External · Exploitability: Moderate

Preserve millisecond precision in both collection bounds.

Use a fractional epoch value for SCT_COREDUMPS_SINCE_EPOCH and journalctl --since; the current truncation includes prior-tenant records created before the build within the same second.

📍 Affects 2 files
  • vars/collectTestCoredumps.groovy#L7-L7 (this comment)
  • vars/collectBuilderLogs.groovy#L8-L8
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@vars/collectTestCoredumps.groovy` at line 7, Preserve fractional epoch
precision in the since-time calculation used by collectTestCoredumps.groovy at
lines 7-7 and collectBuilderLogs.groovy at lines 8-8. Update the shared
collection-bound logic in each file so SCT_COREDUMPS_SINCE_EPOCH and journalctl
--since receive millisecond-precise values rather than truncated whole seconds.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not changing this one, deliberately - the truncation is in the safe direction and the sub-second overlap is harmless.

currentBuild.startTimeInMillis / 1000 floors to whole seconds, so the window can start up to 999ms before the build did. That can only ever include slightly more than this build; rounding the other way would risk missing a coredump or journal entry written in the same second the build started, which is the failure that actually costs you a diagnosis. The bug being fixed here is weeks of unrelated history, not a millisecond boundary.

Fractional-epoch handling would also have to hold for both consumers (journalctl --since @… and SCT_COREDUMPS_SINCE_EPOCH in utils/upload_sct_coredump.sh), which is more surface than the benefit justifies. Happy to revisit if a real overlap ever shows up in a collected archive.

@scylladb-promoter

scylladb-promoter commented Aug 4, 2026

Copy link
Copy Markdown
Collaborator

✅ Test Summary: PASSED

✅ Precommit: PASSED

Total Passed Failed Skipped
15 15 0 0

✅ Tests: PASSED

Total Passed Failed Errors Skipped
4481 4450 0 0 31

Full build log

@fruch fruch added the minicloud PRs related to minicloud label Aug 4, 2026
@fruch
fruch requested a review from dimakr August 4, 2026 14:36
@fruch fruch added backport/none Backport is not required P2 High Priority labels Aug 4, 2026
@fruch

fruch commented Aug 4, 2026

Copy link
Copy Markdown
Contributor Author

@claude review

@claude

claude Bot commented Aug 4, 2026

Copy link
Copy Markdown

Claude finished @fruch's task in 1m 42s —— View job


Code Review

  • Gathering context
  • Reading changed files
  • Analyzing code
  • Posting review

The core idea is correct and the implementation is mostly solid. Two issues need attention before merge.


vars/collectBuilderLogs.groovy

[Bug] Fallback doesn't match PR description

The PR description says: "it degrades to the current boot instead of failing when sudo is unavailable" — but collectBuilderLogs.groovy:22-24 just prints a warning and skips upload entirely. There's no fallback journalctl call without sudo. Copilot and CodeRabbit both flagged this.

Many journal entries (user-space units, session logs) are readable without root. A useful fallback would be:

if sudo -n journalctl --since "@${sinceEpoch}" --no-tail --no-pager -o short-precise > builder-\$SHORT_SCT_TEST_ID.log ; then
    tar -zcvf builder-\$SHORT_SCT_TEST_ID.log.tar.gz builder-\$SHORT_SCT_TEST_ID.log
    ./docker/env/hydra.sh upload --test-id \$SCT_TEST_ID builder-\$SHORT_SCT_TEST_ID.log.tar.gz
elif journalctl --boot --since "@${sinceEpoch}" --no-tail --no-pager -o short-precise > builder-\$SHORT_SCT_TEST_ID.log 2>/dev/null ; then
    echo "WARNING: sudo -n journalctl failed on \$(hostname) - uploading unprivileged journal (current boot only)"
    tar -zcvf builder-\$SHORT_SCT_TEST_ID.log.tar.gz builder-\$SHORT_SCT_TEST_ID.log
    ./docker/env/hydra.sh upload --test-id \$SCT_TEST_ID builder-\$SHORT_SCT_TEST_ID.log.tar.gz
else
    echo "WARNING: journal unreadable on \$(hostname) - skipping builder journal upload"
fi

Fix this →

[Minor] Epoch truncation

(long) (currentBuild.startTimeInMillis / 1000) at line 8 truncates milliseconds. Events from earlier in the same second get included. journalctl --since accepts fractional epoch seconds (@1234567890.750). Low practical impact on builders, but easy to preserve precision:

def sinceEpoch = currentBuild.startTimeInMillis / 1000.0

And reference it as "@${String.format('%.3f', sinceEpoch)}" in the shell string.


vars/collectTestCoredumps.groovy

Same millisecond truncation at line 7 ((long) (currentBuild.startTimeInMillis / 1000)). On a long-lived machine where two jobs start within the same second, coredumps from the earlier job could be included. Low probability, but the fix is the same fractional-epoch approach.


utils/upload_sct_coredump.sh

[Positive] find | tar --null -T - pattern

The two-step approach — list new coredumps first, then tar only those — is clean, and using find -print0 | tar --null -T - correctly handles filenames with unusual characters. Good.

[Minor] Double hydra.sh find invocation

Lines 26 and 31 both invoke hydra.sh with an identical find query. A coredump appearing between the two calls would be tarred but not listed in $NEW_COREDUMPS (or vice versa if one disappears). This is a theoretical race on shared machines, which is exactly the scenario this PR targets. Combining into one pass (e.g., pipe directly into tar and check exit/file count) would eliminate it, though it's a minor concern.

[Positive] 24h standalone fallback

SINCE_EPOCH="${SCT_COREDUMPS_SINCE_EPOCH:-$(( $(date +%s) - 86400 ))}" is a well-designed default — safe for standalone runs, overridden when called from Jenkins.

[Positive] || true on grep

grep "^$COREDUMP_DIR/" || true correctly avoids false negatives when hydra.sh produces preamble output, and doesn't fail when no coredumps match.


Summary

Severity File Issue
Major collectBuilderLogs.groovy:22 Fallback on sudo failure should attempt unprivileged journalctl --boot, not silently skip
Minor collectBuilderLogs.groovy:8, collectTestCoredumps.groovy:7 Millisecond truncation in epoch calculation
Minor upload_sct_coredump.sh:26,31 Two separate hydra.sh find calls introduce a race window

The coredump bounding logic in upload_sct_coredump.sh is correct and well-structured. The journal fix needs the fallback path described in the PR description to actually be implemented.

Both collectors assume a builder that dies after its build, which stops
being true the moment a job runs on a static agent:

  * collectBuilderLogs ran an unbounded `sudo journalctl`, so every build
    uploaded the host's entire journal - weeks of it on a long-lived
    machine - and a sudo that is not passwordless aborted the stage
    outright.
  * upload_sct_coredump.sh tarred every coredump the host had ever
    produced, including other jobs' and other tenants'.

Both are now bounded by the build's own start time, and the journal read
degrades to the current boot instead of failing when sudo is unavailable.
Independent of any particular backend - this is groundwork for running
regular jobs on static builders.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@fruch
fruch force-pushed the fix/bound-builder-log-collection branch from 9264ba5 to a465d24 Compare August 6, 2026 08:53
@scylladbbot

Copy link
Copy Markdown

@fruch new branch manager-3.12 was added, please add backport label if needed

sh """#!/bin/bash

./utils/upload_sct_coredump.sh
SCT_COREDUMPS_SINCE_EPOCH=${sinceEpoch} ./utils/upload_sct_coredump.sh

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SCT_* names are for the SCT config namespace. sct_config.py doesn't define coredumps_since_epoch config param, so it would reject this as Unsupported environment variables were used

# Compress the coredumps into a tar.gz file
./docker/env/hydra.sh $EXTRA_HYDRA_ARGS "bash -c \"sudo tar --zstd -cf $COREDUMP_TARBALL -C $COREDUMP_DIR .\""
# Collect this build's coredumps, if any (find prints them; empty output means nothing new)
NEW_COREDUMPS=$(./docker/env/hydra.sh $EXTRA_HYDRA_ARGS "bash -c \"find $COREDUMP_DIR -maxdepth 1 -type f -newermt @$SINCE_EPOCH\"" | grep "^$COREDUMP_DIR/" || true)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

|| true would drop the exit code of hydra.sh execution. Then on line 36 below the scipts returns/prints no coredumps ... nothing to upload, but the script states this as a fact and doesn't check exactly this is the result of hydra command execution and not some other error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai-assisted backport/none Backport is not required minicloud PRs related to minicloud P2 High Priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants