feat(frontend): manage curated computing-unit images from the admin page - #8518
feat(frontend): manage curated computing-unit images from the admin page#8518tanishqgandhi1908 wants to merge 3 commits into
Conversation
An administrator registers an image reference from a public registry, and a computing unit can then be started from it. Off by default until the UI to manage these ships. Texera reads the image's manifest and config blob -- a few kilobytes, never the layers -- to check its start command runs computing-unit-master, which means it was built FROM the Texera computing-unit image, and to resolve the digest behind the reference. A misspelled, private or unsuitable image is refused in seconds, in front of the administrator, rather than when a user's unit will not start. The row records owner/name@sha256:..., and that is what units run, so a tag its owner moves later cannot change what already ran. Nothing is copied and no registry is added: units pull the reference the same way the deployment's own image is already pulled. Uniqueness is enforced by the database, not only checked in the service. Two administrators registering the same link at the same moment both pass a read-then-write check and produce two rows for one image. A curated image was supplied by an administrator and reviewed by nobody, so a unit started from one runs as a non-root user with no privilege escalation and no capabilities. Curated images only -- the deployment's own image is its operator's choice, and one that has replaced it with an image needing root would break on upgrade. The first unit on each node waits for the image to download, about 80 seconds for a 3 GB one, while later units there start at once. Pre-pulling ready images onto nodes is a follow-up.
Admin -> CU Images lists the registered images newest first, with the digest a unit will actually run, and offers Add, Log, Refresh and Remove. A row shows PENDING, VALIDATING, READY or FAILED; the list polls while a check is running and goes quiet once nothing is. Log is where a refused image explains itself -- a tag that does not exist, an image that is not a computing-unit image -- and what to do instead. A deployment with curated images switched off is told so plainly. The API answers 503 on every endpoint there, so the page can do nothing either way; saying it beats an error an administrator cannot tell from a broken deployment. Also routes /api/cu-image to the computing-unit manager in the dev proxy. Without it a local frontend reaches the webserver instead and every call 404s; production already routes through the gateway.
Automated Reviewer SuggestionsBased on the
|
Codecov Report❌ Patch coverage is ❌ Your patch status has failed because the patch coverage (41.40%) is below the target coverage (60.00%). You can increase the patch coverage or adjust the target coverage. Additional details and impacted files@@ Coverage Diff @@
## main #8518 +/- ##
============================================
+ Coverage 93.94% 94.63% +0.68%
+ Complexity 4827 461 -4366
============================================
Files 1209 592 -617
Lines 49705 34013 -15692
Branches 6074 4210 -1864
============================================
- Hits 46695 32187 -14508
+ Misses 1522 1252 -270
+ Partials 1488 574 -914
*This pull request uses carry forward flags. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
| config | throughput | MB/s | latency | max Δ latest / 7d | |
|---|---|---|---|---|---|
| 🔴 | bs=10 sw=10 sl=64 | 462 | 0.282 | 20,967/30,233/30,233 us | 🟢 -19.4% / 🔴 +93.2% |
| 🟢 | bs=100 sw=10 sl=64 | 975 | 0.595 | 99,408/142,470/142,470 us | 🟢 -8.7% / 🔴 +36.2% |
| 🔴 | bs=1000 sw=10 sl=64 | 1,105 | 0.674 | 894,446/1,069,733/1,069,733 us | 🔴 +15.9% / 🔴 +7.1% |
Baseline details
Latest main 069cd20 from same runner
| config | metric | PR | latest main | 7d avg | Δ latest | Δ 7d |
|---|---|---|---|---|---|---|
| bs=10 sw=10 sl=64 | throughput | 462 tuples/sec | 474 tuples/sec | 794.98 tuples/sec | -2.5% | -41.9% |
| bs=10 sw=10 sl=64 | MB/s | 0.282 MB/s | 0.289 MB/s | 0.485 MB/s | -2.4% | -41.9% |
| bs=10 sw=10 sl=64 | p50 | 20,967 us | 19,873 us | 12,443 us | +5.5% | +68.5% |
| bs=10 sw=10 sl=64 | p95 | 30,233 us | 37,531 us | 15,648 us | -19.4% | +93.2% |
| bs=10 sw=10 sl=64 | p99 | 30,233 us | 37,531 us | 19,794 us | -19.4% | +52.7% |
| bs=100 sw=10 sl=64 | throughput | 975 tuples/sec | 904 tuples/sec | 1,034 tuples/sec | +7.9% | -5.7% |
| bs=100 sw=10 sl=64 | MB/s | 0.595 MB/s | 0.552 MB/s | 0.631 MB/s | +7.8% | -5.7% |
| bs=100 sw=10 sl=64 | p50 | 99,408 us | 108,860 us | 97,860 us | -8.7% | +1.6% |
| bs=100 sw=10 sl=64 | p95 | 142,470 us | 138,864 us | 104,570 us | +2.6% | +36.2% |
| bs=100 sw=10 sl=64 | p99 | 142,470 us | 138,864 us | 117,811 us | +2.6% | +20.9% |
| bs=1000 sw=10 sl=64 | throughput | 1,105 tuples/sec | 1,130 tuples/sec | 1,066 tuples/sec | -2.2% | +3.7% |
| bs=1000 sw=10 sl=64 | MB/s | 0.674 MB/s | 0.69 MB/s | 0.651 MB/s | -2.3% | +3.6% |
| bs=1000 sw=10 sl=64 | p50 | 894,446 us | 881,725 us | 958,266 us | +1.4% | -6.7% |
| bs=1000 sw=10 sl=64 | p95 | 1,069,733 us | 923,181 us | 998,734 us | +15.9% | +7.1% |
| bs=1000 sw=10 sl=64 | p99 | 1,069,733 us | 923,181 us | 1,032,953 us | +15.9% | +3.6% |
Raw CSV
config_idx,batch_size,schema_width,string_len,num_batches,total_ms,total_tuples,total_bytes,tuples_per_sec,mb_per_sec,lat_p50_us,lat_p95_us,lat_p99_us
0,10,10,64,20,433.18,200,128000,462,0.282,20966.85,30233.42,30233.42
1,100,10,64,20,2051.52,2000,1280000,975,0.595,99407.57,142469.86,142469.86
2,1000,10,64,20,18100.21,20000,12800000,1105,0.674,894445.72,1069732.80,1069732.80…submit Two from review. An error from the request inside switchMap reached the subscriber, which ends the subscription for good -- so one hiccup while a check was running left the row VALIDATING forever, with Refresh disabled in that state and only a reload to recover. Caught inside the projection now, as the deployment-version poller already does. Enter in either field calls add() directly, where the Add button's disabled state does not apply, so two quick presses sent the same image twice and the second tripped the unique name constraint right after a successful add. Both regressions are pinned by tests that fail without the fix.
What changes were proposed in this PR?
Admin → CU Images, the page for managing the images #8475 made registrable.
Images are listed newest first, each with the digest a unit will actually run, and four actions: Add, Log, Refresh, Remove. A row shows PENDING, VALIDATING, READY or FAILED. The list polls while a check is running and goes quiet once nothing is.
Log is the point of the page. It is where a refused image explains itself — a tag that does not exist, an image that is not a computing-unit image — and says what to do instead.
A deployment with curated images switched off is told so plainly. The API answers 503 on every endpoint there, so the page can do nothing either way; saying that beats an error an administrator cannot tell from a broken deployment.
Also routes
/api/cu-imageto the computing-unit manager in the dev proxy. Without it a local frontend reaches the webserver instead and every call 404s. Production already routes through the gateway, added in #8475.Any related issues, documentation, discussions?
Closes #8470
Part of #8466
Stacked on #8475, whose API this consumes, so GitHub shows that commit here too until it merges. This PR's own change is one commit over it, frontend only.
How was this PR tested?
Nine tests for the page, plus the whole thing run against a real backend.
The polling tests were mutation-checked: removing the filter fails exactly those two.
Against a real stack (
bin/local-dev.sh up, with the computing-unit manager talking to minikube):Driven through the page itself: typed into the Add form, clicked Add, the row appeared VALIDATING and reached its outcome with no further interaction. Once settled, 0 requests over 20 idle seconds. The screenshots above are that stack, not a mock.
Was this PR authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Claude Opus 5)