fix: pre-landing review fixes (usage skips a VM destroyed since the list; spawn timeout)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-10-31 19:19:24 +00:00
1 parent eb07dbb3af
commit 4c817a6211
3 files changed
+21 -6

No files matched your search

+11 -3
View File
@@ -806,7 +806,8 @@ cmd_list() {
# usage: VMs and vCPUs per owner, from each VM's size (standard-16 = 16 vCPUs).
# Exits 1 with no table when the VM list or any VM's size cannot be read, so a
# partial count is never taken for the project's usage.
# partial count is never taken for the project's usage. A VM destroyed between
# the list and its size read (404) no longer counts and is not a failure.
cmd_usage() {
local tmp rows loc name owner f i=0 unread=0
rows=$(vm_rows) || { log "usage: could not list the project's VMs"; return 1; }
@@ -814,7 +815,14 @@ cmd_usage() {
while read -r loc name owner _; do
[ -n "$name" ] || continue
i=$(( i + 1 ))
cli vm "$loc/$name" show 2>/dev/null | sed -n "s/^size: /$owner /p" >"$tmp/$i" &
{
case $(api "$tmp/$i.show" vm "$loc/$name" show) in
200) sed -n "s/^size: /$owner /p" "$tmp/$i.show" >"$tmp/$i" ;;
404) ;;
*) : >"$tmp/$i" ;;
esac
rm -f "$tmp/$i.show"
} &
[ $(( i % 8 )) -ne 0 ] || wait
done <<<"$rows"
wait
@@ -824,7 +832,7 @@ cmd_usage() {
log "usage: could not read the size of $unread of $i VMs"
return 1
fi
{ [ "$i" -eq 0 ] || cat "$tmp"/*; } | awk -v me="$OWNER" '
find "$tmp" -type f -exec cat {} + | awk -v me="$OWNER" '
{ n = $2; sub(/^.*-/, "", n); o = $1 == "-" ? "(untagged)" : $1 == "." ? "(other)" : $1
vms[o]++; cpu[o] += n; total += n; count++ }
END {
@@ -107,7 +107,7 @@ printf 200
test.skipIf(!bwkAwk)('usage prints the per-owner table, and up refuses a create that would pass UBI_QUOTA_VCPUS', () => {
const f = fakeApi();
try {
expect(Bun.spawnSync(['awk', '--version'], { env: f.env }).stdout.toString()).toContain('awk version');
expect(Bun.spawnSync(['awk', '--version'], { env: f.env, timeout: 10_000 }).stdout.toString()).toContain('awk version');
const usage = f.run(['usage']);
expect(usage.stderr.toString()).toBe('');
expect(usage.exitCode).toBe(0);
+9 -2
View File
@@ -453,7 +453,7 @@ describe('ubi-runner run, verify and quota against a fake API and a fake ssh', (
'case "$body" in\n' +
' *\'"create"\'*) if [ -n ' + JSON.stringify(opts.refuse ?? '') + ' ]; then printf \'%s\' ' + JSON.stringify(opts.refuse ?? '') + ' > "$out"; printf 400; else echo "$loc $name" >> "$listed"; : > "$out"; printf 200; fi ;;\n' +
' *destroy*) : > "$out"; if [ -f "$listed.destroy-fails" ]; then printf 500; else grep -v " $name$" "$listed" > "$listed.tmp"; mv "$listed.tmp" "$listed"; printf 200; fi ;;\n' +
' *\'"list"\'*) if [ -f "$listed.list-fails" ]; then echo down > "$out"; printf 503; else cat "$listed" > "$out"; printf 200; fi ;;\n' +
' *\'"list"\'*) if [ -f "$listed.list-fails" ]; then echo down > "$out"; printf 503; else cat "$listed" "$listed.ghost" > "$out" 2>/dev/null; printf 200; fi ;;\n' +
' *\'"show"\'*) [ -z "${FAKE_SHOW_DELAY:-}" ] || sleep "$FAKE_SHOW_DELAY"; if [ -f "$listed.show-fails" ]; then echo down > "$out"; printf 503; elif grep -q " $name$" "$listed"; then printf \'state: running\\nsize: standard-16\\nip4: 192.0.2.1\\n\' > "$out"; printf 200; else : > "$out"; printf 404; fi ;;\n' +
' *) : > "$out"; printf 200 ;;\n' +
'esac\n');
@@ -765,7 +765,7 @@ describe('ubi-runner run, verify and quota against a fake API and a fake ssh', (
}, 90_000);
// Value: protects=usage never reports a partial or empty count as the project's real usage, and the quota preflight says when it cannot read usage instead of passing silently; fails_when=a failed vm list or vm show prints a total again (the empty-project fix's `|| true` did that) or the preflight drops its log line; why_new=only successful reads were tested, and #3679 showed an unreadable usage switching the preflight off without a word; seam=none; no_claim=the real API's failure bodies
test('usage exits 1 without a total when the VM list or a size read fails; the quota preflight logs that and leaves the call to the API', () => {
test('usage exits 1 without a total when the VM list or a size read fails, skips a VM destroyed since the list, and the quota preflight logs an unreadable usage and leaves the call to the API', () => {
const f = fakeVm({ listed: 'eu-central-h1 ubirun-peer-9999999999-cccc\n' });
const listed = join(f.root, 'listed');
try {
@@ -787,6 +787,13 @@ describe('ubi-runner run, verify and quota against a fake API and a fake ssh', (
expect(noShow.exitCode).toBe(1);
expect(noShow.stdout.toString()).not.toContain('total');
expect(noShow.stderr.toString()).toContain('usage: could not read the size of 1 of 1 VMs');
rmSync(`${listed}.show-fails`);
// A VM destroyed between the list and its size read (show answers 404) is gone, not unread.
writeFileSync(`${listed}.ghost`, 'eu-central-h1 ubirun-gone-9999999999-dddd-t3\n');
const ghost = run(f, ['usage']);
expect(ghost.exitCode).toBe(0);
expect(ghost.stdout.toString()).toBe('OWNER VMS VCPUS\npeer 1 16\ntotal 1 16\n');
} finally { rmSync(f.root, { recursive: true, force: true }); }
}, 90_000);