fix: add per-attempt timeout and cse budget guard to _apt_get_update - #9058
Conversation
Windows Unit Test Results 3 files 11 suites 46s ⏱️ Results for commit 3d054b1. ♻️ This comment has been updated with latest results. |
There was a problem hiding this comment.
Pull request overview
This PR hardens the Ubuntu _apt_get_update retry helper used during node provisioning by preventing individual apt-get update attempts from monopolizing the global CSE execution budget, and by making “success” depend on both exit status and diagnostics output.
Changes:
- Wrap each
apt-get updateattempt with a per-attempttimeout(default 180s; configurable viaAPT_GET_UPDATE_TIMEOUT_SECONDS) and cap it to the remaining CSE budget when running under CSE. - Add
check_cse_timeoutguards before each attempt and before sleeping between retries; return2to signal “stop retrying due to CSE budget”. - Add ShellSpec coverage validating timeout capping, early-exit semantics, and timeout failure behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| spec/parts/linux/cloud-init/artifacts/cse_helpers_ubuntu_spec.sh | Adds ShellSpec tests for _apt_get_update budget-guard and per-attempt timeout behavior. |
| parts/linux/cloud-init/artifacts/ubuntu/cse_helpers_ubuntu.sh | Implements per-attempt timeouts, remaining-budget capping, and CSE timeout guarding for _apt_get_update. |
| # Only apply CSE timeout guards when CSE_STARTTIME_SECONDS is set (i.e. in a real CSE run). | ||
| # Skipping the guard during VHD build avoids noisy "CSE_STARTTIME_SECONDS is not set" warnings. |
9b7de61 to
ca302a9
Compare
ca302a9 to
3d054b1
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (2)
parts/linux/cloud-init/artifacts/ubuntu/cse_helpers_ubuntu.sh:31
- _apt_get_update now documents/returns status 2 to allow callers to short-circuit when CSE time is nearly exhausted, but at least one caller (
apt_get_install_from_local_repoin this same file) invokes it viaif ! _apt_get_update ...; then ... return 1, which collapses a 2 into a generic failure. That loses the early-exit signal and can cause the CSE to continue into slower fallback paths instead of stopping immediately. Consider preserving the exact return code (e.g., capture$?andreturn $rcwhen rc==2) in wrappers/callers that currently use! _apt_get_update.
# Core update function used by apt_get_update and apt_get_install_from_local_repo
# returns 0 if successful, 1 if retries are exhausted, 2 if the CSE timeout is approaching
# and the caller should short-circuit.
_apt_get_update() {
parts/linux/cloud-init/artifacts/ubuntu/cse_helpers_ubuntu.sh:82
- Quote
$apt_update_outputin the redirection/cat/grep uses to avoid accidental word-splitting or glob expansion if this path ever changes (and to match other code in this file that consistently quotes paths).
timeout "$effectiveTimeout" apt-get ${apt_opts} update > $apt_update_output 2>&1
aptStatus=$?
cat $apt_update_output
# apt-get must both exit 0 and emit no W:/E: lines. Checking the exit status matters now that
# attempts are wrapped in timeout: a killed apt-get may flush no diagnostics at all, which the
| # only the CSE budget checks are skipped during VHD build to avoid noisy "CSE_STARTTIME_SECONDS is not set" warnings. | ||
| if [ -n "${CSE_STARTTIME_SECONDS:-}" ] && ! check_cse_timeout; then | ||
| echo "CSE timeout approaching, exiting apt_get_update early." >&2 | ||
| return 2 |
There was a problem hiding this comment.
The caller should also handle return 2 if you mean to distinguish between 1 & 2, right?
There was a problem hiding this comment.
Problematic codes
if ! _apt_get_update 10 "${opts}"; then
echo "Failed to update apt cache from local repo ${local_repo_dir}"
rm -f "${tmp_list}"
rmdir "${tmp_dir}"
return 1
fi
There was a problem hiding this comment.
wont that be handled with retries, meaning if it failed it will retry X times and then returns 1?
There was a problem hiding this comment.
i think the idea here is that we are returning exit code 99 rather than exit code 124
Devinwong
left a comment
There was a problem hiding this comment.
approve with non-blocking suggestions
Description:
_apt_get_updatewas the only retry helper without a per-attempt timeout or CSE budgetguard. On broken DNS/NSG, 10 uncapped attempts could burn the entire 780s CSE budget and
starve later provisioning steps, surfacing as exit 99 (
ERR_APT_UPDATE_TIMEOUT) — atimeout the function never actually enforced.
Changes
apt-get updateattempt intimeout, defaulting to 180s (override viaAPT_GET_UPDATE_TIMEOUT_SECONDS), capped to the remaining CSE budget.check_cse_timeoutbefore each attempt and before each sleep; return2to letcallers short-circuit, matching
_apt_get_installand_retrycmd_internal.apt-getto exit 0 and emit noW:/E:lines. Required by theabove: a
timeout-killed apt-get may flush no diagnostics, which the previous grep-onlycheck would have misread as success.
Guards are only active when
CSE_STARTTIME_SECONDSis set, so VHD build behavior isunchanged. All callers already use
|| exit $ERR_APT_UPDATE_TIMEOUT, so return2is handled.180s (not the 90s originally proposed) since
apt-get updatefetches index files fromseveral repos sequentially; a tighter cap risks failing slow-but-recoverable mirrors.