CreateActorTemplate accepts 1 KiB memoryBytes (OOM-killing shared worker pod on wake), get resources -a <missing-atespace> exits 0, and CreateActor/DeleteAtespace hide missing resource details

オープン
#3,290 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
5/5
見積もり時間
1週間以上
初心者へのやさしさ
28/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
go, kubernetes
領域
api, backend, cli, databases

調査の方向性

Start with the listed validation and resource paths in api/ateapi/v1/ateapi.proto, cmd/ateapi/internal/apivalidation/actor_template.go, and internal/ocispec/ocispec.go, then trace the list, create, and delete paths cited under Affected Code Locations. Reproduce the missing-atespace and tiny-memory cases with the provided kubectl ate commands. Done means the four behaviors have clear, separately verified expected outcomes; the worker OOM containment cause is explicitly unestablished in the issue.

索引モデルが issue の本文から書いたものです。

説明

area/api area/api-machinery area/cli area/node kind/bug
Summary & Root Cause
  • Part 1: API validation enforces only memory_bytes > 0, and ociResources passes the value through unclamped as the container's memory limit. CPU, by contrast, is raised to a kernel floor. Nothing stops a value far below what gVisor needs to start a sandbox, so the failure moves from admission (400) to the first wake. There, runsc create is killed and the actor goes to CRASHED. The kernel OOM kill (Memory cgroup out of memory: Killed process (runsc)) also took down the shared worker container (OOMKilled, restart). One tenant template can therefore restart a worker pod that other actors may be using. The code examined here does not establish why the OOM escapes the sandbox's limit and reaches the worker container. That part is observed behavior only.
  • Part 2: List RPCs filter rows by atespace without checking that the atespace exists, so a typo returns an empty page with RC 0.
  • Part 3: CreateActor resolves the template before anything checks the atespace. A missing atespace and a missing template both become the same errActorTemplateNotFound, and apierror.FromError drops the ObjectRef context that resolveActorTemplate added.
  • Part 4: The store collapses every foreign-key violation into one sentinel. The handler cannot say which child resource type (actors, templates, tags) blocks the delete, and the CLI help mentions only actors.
Affected Code Locations
  • Part 1 (tiny memoryBytes accepted and OOM-kills worker on wake):
    • api/ateapi/v1/ateapi.proto:1235-1248: Resources.memory_bytes only has +k8s:minimum=0. There is no lower bound.
    • cmd/ateapi/internal/apivalidation/zz_generated.validation.go:7541-7570: the generated check for memory_bytes is validate.Minimum(..., 0) only.
    • cmd/ateapi/internal/apivalidation/actor_template.go:86-97: ValidateCustom_ActorTemplate_Resources rejects only == 0 (Required).
    • cmd/ateapi/internal/apivalidation/zz_generated.validation.go:7526-7531: for CPU, -100 hits Minimum(0) ("must be greater than or equal to 0"), while 0 hits the custom Required at actor_template.go:90-91. That is why the two errors differ.
    • internal/ocispec/ocispec.go:63-78: ociResources copies memory_bytes unchanged into the OCI linux.resources.memory.limit (lines 69-71). CPU gets a kernel-minimum floor (cpuQuotaMinUS, lines 53-57 and 73). Memory has no floor at all.
    • internal/ocispec/ocispec.go:161-164: the container spec's Linux.Resources is set from ociResources.
  • Part 2 (get / List* in a missing atespace exits 0):
    • cmd/ateapi/internal/controlapi/actor.go:225-242: ListActors passes the atespace straight to the store with no existence check. The same applies to actor_template.go:103-118 (ListActorTemplates) and tag.go:87-101 (ListTags, which carries // TODO: implement this at line 99).
    • Contrast: cmd/kubectl-ate/internal/cmd/access_policy.go:170-185 (requireScope) calls GetAtespace and prints atespace %q not found.
  • Part 3 (CreateActor hides whether atespace or template is missing and drops ObjectRef):
    • cmd/ateapi/internal/controlapi/actor.go:86: CreateActor calls resolveActorTemplate first.
    • cmd/ateapi/internal/controlapi/actor_template.go:152-171: errActorTemplateNotFound = apierror.FailedPrecondition("actor template not found") (line 156), wrapped as "%w; ObjectRef: %s " (line 165).
    • internal/apierror/apierror.go:128-139: FromError returns apiErr.Error(), the apierror's own message without the wrapping context, so the ObjectRef suffix never reaches the client.
    • cmd/ateapi/internal/controlapi/actor.go:161-163: the Atespace %s not found branch exists but is unreachable for a missing atespace, because template lookup fails first.
  • Part 4 (DeleteAtespace returns generic "not empty" message vs. --help):
    • cmd/ateapi/internal/store/atepg/atespace.go:136-138: a foreign-key violation maps to bare store.ErrFailedPrecondition.
    • cmd/ateapi/internal/controlapi/atespace.go:120-121: the server formats this as Atespace %s is not empty.
    • cmd/kubectl-ate/internal/cmd/atespace.go:102: Short: "Delete an empty atespace (fails if any actors remain)".

Note: Earlier write-ups cited actor.go:86, 161-163 as the location of errActorTemplateNotFound. At 15b58199 the variable and its wrapping live in actor_template.go:152-171, and actor.go:161-163 is the unreachable "Atespace not found" branch.

Detailed Reproduction Guide
  1. Tiny memory limit:
metadata:
  name: s5-mem1k
  atespace: ate-demo-counter
workerSelector:
  matchLabels:
    workload: counter
resources:
  limits:
    cpuMillicores: "250"
    memoryBytes: "1024"
containers:
- name: counter
  image: gcr.io/<PROJECT_ID>/ate-images/counter
  command:
  - /ko-app/counter
kubectl ate create actor-template -f s5-mem1k.yaml
kubectl ate create actor s5-mem1k-actor -a ate-demo-counter --template s5-mem1k
# Wake through atenet-router (mTLS client), for example:
curl -sS -X POST --cert credential-bundle.pem --key credential-bundle.pem --cacert router-ca.pem \
  -H "ate-target-actor: ate-demo-counter/s5-mem1k-actor" https://atenet-router.ate-system.svc/
kubectl ate get actor s5-mem1k-actor -a ate-demo-counter -o yaml
# Check the worker pod that hosted the wake for an OOM restart:
kubectl -n ate-demo-counter get pods -o custom-columns=NAME:.metadata.name,RESTARTS:.status.containerStatuses[0].restartCount,LAST:.status.containerStatuses[0].lastState.terminated.reason
kubectl get events -A --field-selector reason=OOMKilling
  1. CPU 0 vs -100 (same template with cpuMillicores: "0", then "-100"):
kubectl ate create actor-template -f s5-cpu0.yaml
kubectl ate create actor-template -f s5-cpuneg.yaml
  1. Missing atespace on list:
kubectl ate get actors -a does-not-exist
kubectl ate get actor-templates -a does-not-exist
kubectl ate get tags -a does-not-exist
kubectl ate get access-policy -a does-not-exist
  1. Missing atespace vs missing template, and the delete message:
kubectl ate create actor x -a does-not-exist --template counter
kubectl ate create actor x -a ate-demo-counter --template nope
kubectl ate delete atespace ate-demo-counter
kubectl ate delete atespace --help | head -n 1
Expected vs. Actual Behavior
  • Expected:
    • memoryBytes: 1024 is rejected at create time with InvalidArgument and a documented minimum. A sandbox that exceeds its memory limit is contained to that actor and does not affect the worker pod. CPU 0 and -100 produce consistent messages.
    • Listing in a missing atespace returns NotFound: atespace "does-not-exist" not found, as get access-policy does.
    • CreateActor says which of atespace or template is missing, including <atespace>/<template>.
    • DeleteAtespace names the blocking resource types, and --help does not say "actors" only.
  • Actual:
    • The template is admitted (RC=0). The wake returns HTTP 500 and the actor goes ACTOR_STATE_CRASHED (runsc create killed). The shared worker container is also OOM-killed and restarted. CPU 0 gives Required value but -100 gives must be greater than or equal to 0.
    • The three list commands exit 0 with only a header.
    • Both create actor cases return the identical actor template not found.
    • Delete returns Atespace ate-demo-counter is not empty, while help says (fails if any actors remain).
Observed Output & Logs
$ kubectl ate create actor-template -f s5-mem1k.yaml
ATESPACE           NAME       GOLDEN TAG   ERROR   AGE
ate-demo-counter   s5-mem1k                        0s
RC=0
$ ate_curl s5-mem1k-actor
error resuming actor ate-demo-counter/s5-mem1k-actor
HTTP_CODE:500
status:
  assignedNode: gke-worker-node-1
  crash:
    crashTime: "2026-10-27T00:39:30.763493847Z"
    message: 'resume failed: atelet Run: while calling worker RunWorkload: rpc error:
      code = Internal desc = while creating the sandbox: while running `runsc create`:
      signal: killed'
  state: ACTOR_STATE_CRASHED
$ kubectl ate create actor-template -f s5-cpu0.yaml
Error: failed to create actor template: rpc error: code = InvalidArgument desc = actor_template.resources.limits.cpu_millicores: Required value
RC=1
$ kubectl ate create actor-template -f s5-cpuneg.yaml
Error: failed to create actor template: rpc error: code = InvalidArgument desc = actor_template.resources.limits.cpu_millicores: Invalid value: -100: must be greater than or equal to 0
RC=1
$ kubectl ate get actors -a does-not-exist
ATESPACE   NAME   TEMPLATE   STATE   WORKER POD   WORKER IPS   VERSION   AGE
RC=0
$ kubectl ate get actor-templates -a does-not-exist
ATESPACE   NAME   GOLDEN TAG   ERROR   AGE
RC=0
$ kubectl ate get tags -a does-not-exist
ATESPACE   NAME   SCOPE   STATE   SNAPSHOT   FIDELITY   AGE
RC=0
$ kubectl ate get access-policy -a does-not-exist
Error: atespace "does-not-exist" not found
RC=1
$ kubectl ate create actor x -a does-not-exist --template counter
Error: failed to create actor: rpc error: code = FailedPrecondition desc = actor template not found
RC=1
$ kubectl ate create actor x -a ate-demo-counter --template nope
Error: failed to create actor: rpc error: code = FailedPrecondition desc = actor template not found
RC=1
$ kubectl ate delete atespace ate-demo-counter
Error: failed to delete atespace: rpc error: code = FailedPrecondition desc = Atespace ate-demo-counter is not empty
RC=1
$ kubectl ate delete atespace --help | head -n 1
Delete an empty atespace (fails if any actors remain)
$ kubectl ate create actor-template -f r3-mem1k.yaml
ATESPACE           NAME       GOLDEN TAG   ERROR   AGE
ate-demo-counter   r3-mem1k                        0s
RC=0
$ ate_curl ate-demo-counter/r3-mem1k-actor
error resuming actor ate-demo-counter/r3-mem1k-actor
HTTP_CODE:500 TIME_TOTAL:0.521037s
{
  "state": "ACTOR_STATE_CRASHED",
  "crash": {
    "crashTime": "2026-10-27T02:00:27.157823263Z",
    "message": "resume failed: atelet Run: while calling worker RunWorkload: rpc error: code = Internal desc = while creating the sandbox: while running `runsc create`: signal: terminated"
  },
  "uid": "7d894d64-525c-450b-beb9-954cd9581553"
}
主要言語
Go
スター
5.9k
フォーク
637
平均マージ
2日 1時間
マージ済み PR(30日)
523

環境構築

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

agent-substrate/substrate のほかの issue

agent-substrate/substrate の issue をすべて見る

似ている issue

Go の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。