Repository navigation
Fetch private sandbox assets through the object-store plugin - #2439
Zoe Zhao (zoez7) merged 12 commits into
Conversation
|
cc ILLUM1N0X |
78e1bd0 to
625a6b5
Compare
|
ILLUM1N0X thanks, both addressed in 8467c5c and 625a6b5. On the anonymous read for private On verifying again in atelet: the plugin is a separate process and may be third-party. |
|
The |
I would wait for #2518 to merge and rebase |
625a6b5 to
448e31f
Compare
…ned, snapshot-refusing reads
448e31f to
21a1647
Compare
| // longer reads it: object storage settings belong on the snapshot-plugin | ||
| // sidecar. Only this variable is a signal: EKS pod identity sets AWS_* in | ||
| // every container. | ||
| func rejectStorageEnv() error { |
There was a problem hiding this comment.
Nit: do we need this check? If atelet never used the ATE_STORAGE_BACKEND env var, we wouldn't add this check right?
| return "", wrapFileSystemErr("while closing temp file", err) | ||
| } | ||
|
|
||
| anonymous := u.Scheme == "gs" |
There was a problem hiding this comment.
anonymous := u.Scheme == "gs"
Could you explain why "gs" scheme automatically means it's annoymous?
| if err != nil { | ||
| return "", "", err | ||
| } | ||
| if u.Scheme != "gs" && u.Scheme != "s3" { |
There was a problem hiding this comment.
🤖 blocking 🔴 – On an S3 backend this accepts a gs:// URI and reads its bucket name as an S3 bucket. For gs://gvisor/..., AWS answers 403 (someone else owns the gvisor bucket name) or 301, not 404. toStatus maps that to Internal, which is not in atelet's anonymousFallbackCodes, so atelet never falls back to the anonymous read and gVisor actors fail to start on EKS. kind only works because rustfs returns 404.
Reject a scheme that does not match the configured backend with InvalidArgument, so atelet falls back for gs:// on S3.
|
|
||
| // An object larger than the capacity cannot be staged whatever max_bytes | ||
| // allows, so a request never reserves more than all of it. | ||
| reserve := min(req.GetMaxBytes(), s.capacity) |
There was a problem hiding this comment.
🤖 should-fix 🟡 – atelet always sends max_bytes = 8 GiB and the manifest sets --asset-staging-capacity=8Gi, so every request reserves the whole capacity. All asset fetches on a node therefore run one at a time, even a small gVisor tarball. A request for a missing object also waits here, because open() only runs after Acquire. On kind, a gs://gvisor fetch that will end in NotFound can wait for an unrelated multi-GiB micro-VM download before atelet falls back to the anonymous read.
Suggested change: call open() before Acquire, so NotFound and other open errors return without waiting. Then reserve the object's actual size, capped at max_bytes, instead of max_bytes itself. ObjectStorage.GetObject does not expose a size today, so this needs a small interface addition. The GCS reader has Attrs.Size and S3 has ContentLength.
|
Zoe Zhao (@zoez7) thanks, all four addressed:
|
…rns Internal Fixes an issue introduced in agent-substrate#2439 where running on GKE with a GCS backend causes gs://gvisor asset downloads to fail. When querying gs://gvisor using the cluster's ambient GCP credentials, GCS returns 403 Forbidden, which status.go maps to codes.Internal. Because codes.Internal was omitted from anonymousFallbackCodes, atelet aborted rather than falling back to an anonymous GCS read. This adds codes.Internal to anonymousFallbackCodes and adds unit tests covering the GCS Internal fallback path. - **Unit tests**: `go test ./cmd/atelet/...` passes cleanly. - **E2E validation on GKE**: Verified on Rapid GKE 1.37 (`DATAPLANE=envoy`) with Counter demo: - Actor creation, memory persistence across requests 1 and 2, suspension to snapshot, and resumption from snapshot on request 3 all pass 100%. Fixes agent-substrate#2613 - [ ] Tests pass - [ ] Appropriate changes to documentation are included in the PR
…Internal (agent-substrate#2614) Fixes agent-substrate#2613 On GKE with a GCS backend, the object-store plugin's Workload Identity token gets `412 PreconditionFailed` ("The operation requires that Uniform Bucket Level Access be enabled.") from the public `gs://gvisor`. `toStatus` maps that, like any error it doesn't recognize, to `Internal`, and atelet didn't fall back on `Internal`, so sandbox creation failed after agent-substrate#2439. **Changes** - atelet falls back to an anonymous read on `Internal`. In practice that's any unexpected plugin failure. That's acceptable because anonymous reads only reach public objects, and atelet still checks the sha256. - So a broken plugin isn't hidden: the plugin logs a scrubbed warning when it returns `Internal`, and atelet warns when it falls back. - Updated the `AssetProvider` contract, `api-guide.md` and threat model T-08. **Testing** - Unit tests: `go test ./cmd/atelet/... ./internal/objectstoreplugin/... ./pkg/objectstorage/...` - GKE 1.37 (Envoy dataplane): reproduced the 412 on `main`. With this PR, gVisor prewarm falls back and succeeds, and the counter demo passes create, persistence across requests, suspend, and resume from snapshot. A follow-up issue will discuss the long-term design for plugin fallback. --------- Co-authored-by: Anna Pendleton <13793293+annapendleton@users.noreply.github.com>
atelet held its own storage credential to download sandbox assets, and private micro-VM assets only worked on GCS or S3. Assets now go through the node's object-store plugin, which already has the credentials.
AssetProvider.FetchAssetto the plugin API.pkg/assetfetchshares these checks with other plugins.gs://URL, and only when the plugin returns NotFound, InvalidArgument, Unimplemented or Unavailable, does it fall back to an anonymous read (which serves public buckets such asgs://gvisor). It never falls back when the plugin refuses a snapshot location or the size or digest is wrong.Tested with the kind gVisor and micro-VM lanes before the plugin-first change; only the NFS external-volume tests failed, same as on main. Unit tests cover each fallback and non-fallback code.
Related #2063: assets in the cluster's own store no longer wait on an anonymous GCS lookup first.
Breaking change
Plugins must implement
AssetProviderto serve sandbox assets; publicgs://assets still load anonymously if the plugin can't serve them. atelet exits ifATE_STORAGE_BACKENDis set on it; set storage settings on the snapshot-plugin sidecar. Please add thebreaking-changelabel.Fixes #2385