diff --git a/.github/workflows/pr-workflow.yaml b/.github/workflows/pr-workflow.yaml index 6467be8d44..e9e167014e 100644 --- a/.github/workflows/pr-workflow.yaml +++ b/.github/workflows/pr-workflow.yaml @@ -146,6 +146,9 @@ jobs: # E2E_JUNIT_FILE is set per step, not here: the lanes below share this # job, so one job-level path would have each overwrite the last. ARTIFACTS: ${{ github.workspace }}/_artifacts + # The NFS driver is installed below, so the existingvolumes suite fails + # rather than skips without it. + E2E_CSI_NFS: "1" steps: - name: Checkout uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 diff --git a/FORK.md b/FORK.md index 8c9bb561ca..5aaaf5d2e0 100644 --- a/FORK.md +++ b/FORK.md @@ -101,6 +101,8 @@ Everything on `giantswarm` that is not in the pin (`git log v0.4.0-alpha1..giant | The egress gateway's ext-proc names its telemetry `atenet-egress` (`OTEL_SERVICE_NAME` on the `atenet-egress` `ext-proc` container; a chart unit test) | the `atenet` binary hardcodes the service name `atenet-router` for both modes and the container set none, so egress spans and logs carried `service.name=atenet-router` | `6627a636` ([#217](https://github.com/giantswarm/substrate/pull/217), rebase-merged 2026-10-09; first release 1.6.2) | fork-only chart change; upstream's `atenet-egress.yaml` has the same gap, not queued | | The gVisor SandboxConfig's pause image is a chart value (`images.pause`, default upstream's `registry.k8s.io/pause:3.10.2@sha256:f548e0e8…`, rendered with `required`; the unit-test suite `charts/substrate/tests/sandboxconfig_gvisor_test.yaml` covers the default, an override and the empty value; the README row; the preserved kubectl-apply manifest keeps upstream's default) | the one image reference the chart hardcoded, and the one an operator could not move: `registry.k8s.io` redirects every pull to a Google Artifact Registry host, so a cluster whose egress admits only its own registry failed every golden boot while creating the pause OCI bundle, before any snapshot existed ([#224](https://github.com/giantswarm/substrate/issues/224)) | `f844d726` ([#225](https://github.com/giantswarm/substrate/pull/225), rebase-merged 2026-10-09; first release 1.6.3) | to file (prepared): branch [`upstream/sandbox-pause-image-value`](https://github.com/giantswarm/substrate/tree/upstream/sandbox-pause-image-value) here (`1591d20d`, the same commit on kagent-dev `main` @ `9c4b1fb5` of 2026-10-08, DCO signed), the shape of [kagent-dev/substrate#23](https://github.com/kagent-dev/substrate/pull/23) (2026-08-20, closed unmerged 2026-10-06 on a stale base); [#37742](https://github.com/giantswarm/giantswarm/issues/37742) row 155 | | The pause image defaults to its gsoci copy: `images.pause` = `gsoci.azurecr.io/giantswarm/pause:3.10.2@sha256:f548e0e8…`, upstream's digest | every Giant Swarm installation pulls from gsoci.azurecr.io, and one whose egress admits only that registry cannot reach `registry.k8s.io`; the same digest, so the snapshots that record it restore unchanged ([#224](https://github.com/giantswarm/substrate/issues/224)) | `dd957c2e` ([#225](https://github.com/giantswarm/substrate/pull/225), rebase-merged 2026-10-09; first release 1.6.3) | **ours to keep**: a Giant Swarm registry is not upstream's default; the upstream-shaped change is the row above | +| `resources.DeepEqual`, the unchanged-value check of the generated declarative validation, compares a slice of proto messages (a repeated message field) element by element with `proto.Equal`, a nil and an empty one being equal | it handed the slice to `reflect.DeepEqual`, which also compares each message's internal state; the RPC logger's marshal fills the size cache, so a repeated message field and its clone differed and an `+k8s:immutable` repeated field (`Actor.existing_volumes`, row below) failed every `CreateActor` with "field is immutable" | [#234](https://github.com/giantswarm/substrate/pull/234) (`fix(resources): compare repeated message fields with proto.Equal`) | none: upstream `main` has the same `DeepEqual`; to file, queued in the upstream engagement list | +| An existing volume mounted per actor at a sub-path: an ActorTemplate declares it (`Volume.existing_volume`, field 10001, an empty marker), `CreateActor` supplies it (`Actor.existing_volumes`, field 10001, immutable; `ExistingVolume` = name, CSI driver, volume handle, access mode `READ_WRITE_MANY`/`READ_ONLY_MANY` in the shape of upstream's `VolumeAccessMode`, and the `sub_path` the actor sees as the volume's root), and `VolumeMount` gains `sub_path` and `read_only` (fields 10001, 10002), so one volume mounts at several paths. `CreateActor` refuses a reference to a volume the template does not declare as existing, a driver without a `CSIDriverConfig`, a handle no PersistentVolume of the driver holds and an access mode the PersistentVolume does not permit (ate-api-server reads PersistentVolumes: a new ClusterRole rule); the PersistentVolume's `volumeAttributes` reach the driver at resume. An unsupplied existing volume contributes neither itself nor its mounts. Substrate never creates, deletes or detaches one: pause, resume and delete only unmount and mount it; a multi-node volume is staged per target, and atelet binds each sub-path from a descriptor opened beneath the volume's root without following symbolic links (`openat2` `RESOLVE_BENEATH|RESOLVE_NO_SYMLINKS`), so a missing directory or a planted link fails the mount. An actor with existing volumes boots from its image instead of the golden snapshot and cannot be cloned from a tag. Tests: unit (validation, workload spec, CSI staging, the sub-path resolver), the `existingvolumes` e2e on kind with the CSI NFS driver (`E2E_CSI_NFS=1` in pr-workflow) | Sessions on one workspace each need their own directory of one read-write-many volume read-write and its git mirrors read-only, hundreds a day; a per-actor volume or snapshot per Session does not scale, and an external volume was created per actor, attached single-node-writer and deleted with it, with no sub-path or read-only mount | [#234](https://github.com/giantswarm/substrate/pull/234) (`feat: mount an existing volume per actor at a sub-path`) | follows agent-substrate/substrate#1637 (shared volumes across actors, open), in the shape proposed there (https://github.com/agent-substrate/substrate/issues/1637#issuecomment-6083442678), on top of #1988's access modes (open); upstream puts it behind the Preview gate of #1994 (open), which this line does not carry, so it is ungated here. [#37742](https://github.com/giantswarm/giantswarm/issues/37742) row 157. Exit: drops at the re-pin that carries #1637's API | Twenty-three patches change Substrate ahead of upstream — egress for an actor while it resumes, without which no skill-carrying agent of the platform boots, the atelet scheduling knobs, the keep policy on the CRD chart's diff --git a/charts/substrate/templates/ate-api-server.yaml b/charts/substrate/templates/ate-api-server.yaml index 3b4fdd7119..a132e76807 100644 --- a/charts/substrate/templates/ate-api-server.yaml +++ b/charts/substrate/templates/ate-api-server.yaml @@ -34,6 +34,11 @@ rules: - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "watch", "list"] +# PersistentVolumes: an actor's existing volumes are checked against them at +# CreateActor, and their volume attributes are read at resume. +- apiGroups: [""] + resources: ["persistentvolumes"] + verbs: ["get", "watch", "list"] # Secret reads for env source resolution are intentionally NOT granted # cluster-wide here. Each demo / tenant is responsible for granting # ate-api-server read access only to the specific Secrets referenced by its diff --git a/cmd/ateapi/internal/apivalidation/actor.go b/cmd/ateapi/internal/apivalidation/actor.go index 77c0d27a5b..32e8341654 100644 --- a/cmd/ateapi/internal/apivalidation/actor.go +++ b/cmd/ateapi/internal/apivalidation/actor.go @@ -165,3 +165,21 @@ func ValidateCustom_ExternalVolume_StorageVolumeId(_ context.Context, _ operatio } return nil } + +// ValidateCustom_ExistingVolume_Driver checks an existing volume's driver +// with the syntax of ExternalVolume.volume_type. +func ValidateCustom_ExistingVolume_Driver(ctx context.Context, op operation.Operation, fldPath *field.Path, value, oldValue *string) field.ErrorList { + return ValidateCustom_ExternalVolume_VolumeType(ctx, op, fldPath, value, oldValue) +} + +// ValidateCustom_ExistingVolume_VolumeHandle checks that an existing +// volume's handle, like a storage volume ID, contains no control characters. +func ValidateCustom_ExistingVolume_VolumeHandle(ctx context.Context, op operation.Operation, fldPath *field.Path, value, oldValue *string) field.ErrorList { + return ValidateCustom_ExternalVolume_StorageVolumeId(ctx, op, fldPath, value, oldValue) +} + +// ValidateCustom_ExistingVolume_SubPath checks an existing volume's root +// with the shape of VolumeMount.sub_path. +func ValidateCustom_ExistingVolume_SubPath(ctx context.Context, op operation.Operation, fldPath *field.Path, value, oldValue *string) field.ErrorList { + return ValidateCustom_VolumeMount_SubPath(ctx, op, fldPath, value, oldValue) +} diff --git a/cmd/ateapi/internal/apivalidation/actor_template.go b/cmd/ateapi/internal/apivalidation/actor_template.go index 93925735f1..5108667893 100644 --- a/cmd/ateapi/internal/apivalidation/actor_template.go +++ b/cmd/ateapi/internal/apivalidation/actor_template.go @@ -62,11 +62,12 @@ func ValidateActorTemplateUpdate(ctx context.Context, fldPath *field.Path, newVa } // ValidateCustom_CreateActorTemplateRequest_ActorTemplate rejects container -// volume mounts that reference volumes the template does not declare. +// volume mounts that reference volumes the template does not declare, and a +// sub_path or read_only on a mount of any volume but an existing one. func ValidateCustom_CreateActorTemplateRequest_ActorTemplate(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ *ateapipb.ActorTemplate) field.ErrorList { - declared := make(map[string]bool, len(value.GetVolumes())) + declared := make(map[string]*ateapipb.Volume, len(value.GetVolumes())) for _, vol := range value.GetVolumes() { - declared[vol.GetName()] = true + declared[vol.GetName()] = vol } var errs field.ErrorList for i, ctr := range value.GetContainers() { @@ -75,10 +76,20 @@ func ValidateCustom_CreateActorTemplateRequest_ActorTemplate(_ context.Context, if name == "" { continue // required is enforced by tags } - if !declared[name] { - errs = append(errs, field.Invalid( - fldPath.Child("containers").Index(i).Child("volume_mounts").Index(j).Child("name"), - name, "must reference a volume declared in the template")) + mountPath := fldPath.Child("containers").Index(i).Child("volume_mounts").Index(j) + vol, ok := declared[name] + if !ok { + errs = append(errs, field.Invalid(mountPath.Child("name"), name, "must reference a volume declared in the template")) + continue + } + if vol.GetExistingVolume() != nil { + continue + } + if mount.GetSubPath() != "" { + errs = append(errs, field.Invalid(mountPath.Child("sub_path"), mount.GetSubPath(), "may be set only on a mount of an existing volume")) + } + if mount.GetReadOnly() { + errs = append(errs, field.Invalid(mountPath.Child("read_only"), true, "may be set only on a mount of an existing volume")) } } } @@ -288,3 +299,25 @@ func ValidateCustom_Capabilities_Add(_ context.Context, _ operation.Operation, f func ValidateCustom_Capabilities_Drop(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ []string) field.ErrorList { return validateCapabilities(fldPath, value, true) } + +// ValidateCustom_VolumeMount_SubPath requires a clean relative Unix path: no +// leading '/', no '.' or '..' segments, '//', trailing '/', or control +// characters. +func ValidateCustom_VolumeMount_SubPath(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ *string) field.ErrorList { + p := *value + if p == "" { + return nil + } + bad := strings.HasPrefix(p, "/") || strings.HasSuffix(p, "/") || + strings.Contains(p, "//") || mountPathBadSegmentRE.MatchString(p) + for _, r := range p { + if r < 0x20 || r == 0x7f { + bad = true + break + } + } + if bad { + return field.ErrorList{field.Invalid(fldPath, p, "must be a clean relative Unix path: must not start or end with '/', and contain no '..', '.', '//', or control characters")} + } + return nil +} diff --git a/cmd/ateapi/internal/apivalidation/actor_template_test.go b/cmd/ateapi/internal/apivalidation/actor_template_test.go index aa55942e18..53fb950df1 100644 --- a/cmd/ateapi/internal/apivalidation/actor_template_test.go +++ b/cmd/ateapi/internal/apivalidation/actor_template_test.go @@ -112,6 +112,68 @@ func TestValidateCreateActorTemplateRequest(t *testing.T) { tmpl.Containers[0].VolumeMounts = []*ateapipb.VolumeMount{{Name: "ghost-vol", MountPath: "/var/data"}} })}, field.ErrorList{field.Invalid(field.NewPath("actor_template", "containers").Index(0).Child("volume_mounts").Index(0).Child("name"), "ghost-vol", "")}, + }, { + "existing volume mounted twice, at a sub-path and read-only", + &ateapipb.CreateActorTemplateRequest{ActorTemplate: validActorTemplate(func(tmpl *ateapipb.ActorTemplate) { + tmpl.Volumes = []*ateapipb.Volume{{Name: "workspace", ExistingVolume: &ateapipb.ExistingVolumeSource{}}} + tmpl.Containers[0].VolumeMounts = []*ateapipb.VolumeMount{ + {Name: "workspace", MountPath: "/workspace", SubPath: "sessions/a"}, + {Name: "workspace", MountPath: "/mirrors", SubPath: "mirrors", ReadOnly: true}, + } + })}, + nil, + }, { + "sub_path and read_only on a mount of another kind of volume", + &ateapipb.CreateActorTemplateRequest{ActorTemplate: validActorTemplate(func(tmpl *ateapipb.ActorTemplate) { + tmpl.Volumes = []*ateapipb.Volume{{Name: "data", DurableDir: &ateapipb.DurableDirVolumeSource{}}} + tmpl.Containers[0].VolumeMounts = []*ateapipb.VolumeMount{{Name: "data", MountPath: "/var/data", SubPath: "a", ReadOnly: true}} + })}, + field.ErrorList{ + field.Invalid(field.NewPath("actor_template", "containers").Index(0).Child("volume_mounts").Index(0).Child("sub_path"), "a", ""), + field.Invalid(field.NewPath("actor_template", "containers").Index(0).Child("volume_mounts").Index(0).Child("read_only"), true, ""), + }, + }, { + "sub_path '/abs'", + &ateapipb.CreateActorTemplateRequest{ActorTemplate: validActorTemplate(func(tmpl *ateapipb.ActorTemplate) { + tmpl.Volumes = []*ateapipb.Volume{{Name: "workspace", ExistingVolume: &ateapipb.ExistingVolumeSource{}}} + tmpl.Containers[0].VolumeMounts = []*ateapipb.VolumeMount{{Name: "workspace", MountPath: "/workspace", SubPath: "/abs"}} + })}, + field.ErrorList{field.Invalid(field.NewPath("actor_template", "containers").Index(0).Child("volume_mounts").Index(0).Child("sub_path"), nil, "")}, + }, { + "sub_path 'a/'", + &ateapipb.CreateActorTemplateRequest{ActorTemplate: validActorTemplate(func(tmpl *ateapipb.ActorTemplate) { + tmpl.Volumes = []*ateapipb.Volume{{Name: "workspace", ExistingVolume: &ateapipb.ExistingVolumeSource{}}} + tmpl.Containers[0].VolumeMounts = []*ateapipb.VolumeMount{{Name: "workspace", MountPath: "/workspace", SubPath: "a/"}} + })}, + field.ErrorList{field.Invalid(field.NewPath("actor_template", "containers").Index(0).Child("volume_mounts").Index(0).Child("sub_path"), nil, "")}, + }, { + "sub_path 'a//b'", + &ateapipb.CreateActorTemplateRequest{ActorTemplate: validActorTemplate(func(tmpl *ateapipb.ActorTemplate) { + tmpl.Volumes = []*ateapipb.Volume{{Name: "workspace", ExistingVolume: &ateapipb.ExistingVolumeSource{}}} + tmpl.Containers[0].VolumeMounts = []*ateapipb.VolumeMount{{Name: "workspace", MountPath: "/workspace", SubPath: "a//b"}} + })}, + field.ErrorList{field.Invalid(field.NewPath("actor_template", "containers").Index(0).Child("volume_mounts").Index(0).Child("sub_path"), nil, "")}, + }, { + "sub_path 'a/../b'", + &ateapipb.CreateActorTemplateRequest{ActorTemplate: validActorTemplate(func(tmpl *ateapipb.ActorTemplate) { + tmpl.Volumes = []*ateapipb.Volume{{Name: "workspace", ExistingVolume: &ateapipb.ExistingVolumeSource{}}} + tmpl.Containers[0].VolumeMounts = []*ateapipb.VolumeMount{{Name: "workspace", MountPath: "/workspace", SubPath: "a/../b"}} + })}, + field.ErrorList{field.Invalid(field.NewPath("actor_template", "containers").Index(0).Child("volume_mounts").Index(0).Child("sub_path"), nil, "")}, + }, { + "sub_path '.'", + &ateapipb.CreateActorTemplateRequest{ActorTemplate: validActorTemplate(func(tmpl *ateapipb.ActorTemplate) { + tmpl.Volumes = []*ateapipb.Volume{{Name: "workspace", ExistingVolume: &ateapipb.ExistingVolumeSource{}}} + tmpl.Containers[0].VolumeMounts = []*ateapipb.VolumeMount{{Name: "workspace", MountPath: "/workspace", SubPath: "."}} + })}, + field.ErrorList{field.Invalid(field.NewPath("actor_template", "containers").Index(0).Child("volume_mounts").Index(0).Child("sub_path"), nil, "")}, + }, { + "sub_path 'a\\x01b'", + &ateapipb.CreateActorTemplateRequest{ActorTemplate: validActorTemplate(func(tmpl *ateapipb.ActorTemplate) { + tmpl.Volumes = []*ateapipb.Volume{{Name: "workspace", ExistingVolume: &ateapipb.ExistingVolumeSource{}}} + tmpl.Containers[0].VolumeMounts = []*ateapipb.VolumeMount{{Name: "workspace", MountPath: "/workspace", SubPath: "a\x01b"}} + })}, + field.ErrorList{field.Invalid(field.NewPath("actor_template", "containers").Index(0).Child("volume_mounts").Index(0).Child("sub_path"), nil, "")}, }, { "missing snapshot_config", &ateapipb.CreateActorTemplateRequest{ActorTemplate: validActorTemplate(func(tmpl *ateapipb.ActorTemplate) { diff --git a/cmd/ateapi/internal/apivalidation/actor_test.go b/cmd/ateapi/internal/apivalidation/actor_test.go index b886db97f6..cd3ca5f8d4 100644 --- a/cmd/ateapi/internal/apivalidation/actor_test.go +++ b/cmd/ateapi/internal/apivalidation/actor_test.go @@ -152,6 +152,48 @@ func TestValidateCreateActorRequest(t *testing.T) { "invalid actor.source_tag.name", validReq(validActor(withSourceTag("as", "invalid value"))), field.ErrorList{field.Invalid(field.NewPath("actor", "source_tag", "name"), nil, "").WithOrigin("format=k8s-short-name")}, + }, { + "valid existing volume", + validReq(validActor(withExistingVolume(nil))), + nil, + }, { + "existing volume without a driver", + validReq(validActor(withExistingVolume(func(ev *ateapipb.ExistingVolume) { ev.Driver = "" }))), + field.ErrorList{field.Required(field.NewPath("actor", "existing_volumes").Index(0).Child("driver"), "")}, + }, { + "existing volume with an invalid driver", + validReq(validActor(withExistingVolume(func(ev *ateapipb.ExistingVolume) { ev.Driver = "Not A Driver" }))), + field.ErrorList{field.Invalid(field.NewPath("actor", "existing_volumes").Index(0).Child("driver"), "Not A Driver", "")}, + }, { + "existing volume without a handle", + validReq(validActor(withExistingVolume(func(ev *ateapipb.ExistingVolume) { ev.VolumeHandle = "" }))), + field.ErrorList{field.Required(field.NewPath("actor", "existing_volumes").Index(0).Child("volume_handle"), "")}, + }, { + "existing volume handle with a control character", + validReq(validActor(withExistingVolume(func(ev *ateapipb.ExistingVolume) { ev.VolumeHandle = "a\x01b" }))), + field.ErrorList{field.Invalid(field.NewPath("actor", "existing_volumes").Index(0).Child("volume_handle"), "a\x01b", "")}, + }, { + "existing volume read-only many", + validReq(validActor(withExistingVolume(func(ev *ateapipb.ExistingVolume) { + ev.AccessMode = ateapipb.VolumeAccessMode_VOLUME_ACCESS_MODE_READ_ONLY_MANY + }))), + nil, + }, { + "existing volume single-node", + validReq(validActor(withExistingVolume(func(ev *ateapipb.ExistingVolume) { + ev.AccessMode = ateapipb.VolumeAccessMode_VOLUME_ACCESS_MODE_READ_WRITE_ONCE + }))), + field.ErrorList{field.Invalid(field.NewPath("actor", "existing_volumes").Index(0).Child("access_mode"), nil, "").WithOrigin("minimum")}, + }, { + "existing volume without an access mode", + validReq(validActor(withExistingVolume(func(ev *ateapipb.ExistingVolume) { + ev.AccessMode = ateapipb.VolumeAccessMode_VOLUME_ACCESS_MODE_UNSPECIFIED + }))), + field.ErrorList{field.Required(field.NewPath("actor", "existing_volumes").Index(0).Child("access_mode"), "")}, + }, { + "existing volume escaping its root", + validReq(validActor(withExistingVolume(func(ev *ateapipb.ExistingVolume) { ev.SubPath = "../other" }))), + field.ErrorList{field.Invalid(field.NewPath("actor", "existing_volumes").Index(0).Child("sub_path"), "../other", "")}, }} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -1004,6 +1046,24 @@ func withActorSourceTag(atespace, name string) func(*ateapipb.Actor) { return func(a *ateapipb.Actor) { a.SourceTag = &ateapipb.ObjectRef{Atespace: atespace, Name: name} } } +// withExistingVolume returns a modifier func (see validActor) which gives the +// actor one valid existing volume, changed by mod when it is not nil. +func withExistingVolume(mod func(*ateapipb.ExistingVolume)) func(*ateapipb.Actor) { + return func(a *ateapipb.Actor) { + ev := &ateapipb.ExistingVolume{ + Name: "workspace", + Driver: "nfs.csi.k8s.io", + VolumeHandle: "nfs-server#share#workspace-1", + AccessMode: ateapipb.VolumeAccessMode_VOLUME_ACCESS_MODE_READ_WRITE_MANY, + SubPath: "sessions/a", + } + if mod != nil { + mod(ev) + } + a.ExistingVolumes = []*ateapipb.ExistingVolume{ev} + } +} + // withActorWorkerAssignment returns a modifier func (see validActor) which sets // the actor's worker_assignment to a valid value. func withActorWorkerAssignment(mods ...func(*ateapipb.WorkerAssignment)) func(*ateapipb.ActorStatus) { diff --git a/cmd/ateapi/internal/apivalidation/zz_generated.validation.go b/cmd/ateapi/internal/apivalidation/zz_generated.validation.go index a4fac889b6..1dc8e7ba2b 100644 --- a/cmd/ateapi/internal/apivalidation/zz_generated.validation.go +++ b/cmd/ateapi/internal/apivalidation/zz_generated.validation.go @@ -325,6 +325,56 @@ func Validate_Actor( errs = append(errs, fn(fldPath.Child("status"), obj.Status, oldVal, oldObj != nil)...) } + { // field ateapipb.Actor.ExistingVolumes + fn := func( + fldPath *field.Path, + obj, oldObj []*ateapipb.ExistingVolume, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if ateDeepEqual(obj, oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.PtrSliceNoNils[ateapipb.ExistingVolume](ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.Immutable(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.MaxItems(ctx, op, fldPath, obj, oldObj, 8).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + // lists with map semantics require unique keys + if e := validate.PtrSliceUnique(ctx, op, fldPath, obj, oldObj, + func(a *ateapipb.ExistingVolume, b *ateapipb.ExistingVolume) bool { return a.Name == b.Name }); len(e) != 0 { + errs = append(errs, e...) + } + // iterate the list and call the type's validation function + if e := validate.EachPtrSliceVal(ctx, op, fldPath, obj, oldObj, + func(a *ateapipb.ExistingVolume, b *ateapipb.ExistingVolume) bool { return a.Name == b.Name }, ateDeepEqual, Validate_ExistingVolume); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.Actor) []*ateapipb.ExistingVolume { + return oldObj.ExistingVolumes + }) + errs = append(errs, fn(fldPath.Child("existing_volumes"), obj.ExistingVolumes, oldVal, oldObj != nil)...) + } + return errs } @@ -3669,6 +3719,189 @@ func Validate_EnvVar( return errs } +// Validate_ExistingVolume validates an instance of ExistingVolume according +// to declarative validation rules in the API schema. +func Validate_ExistingVolume( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *ateapipb.ExistingVolume) (errs field.ErrorList) { + + { // field ateapipb.ExistingVolume.Name + fn := func( + fldPath *field.Path, + obj, oldObj *string, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + if e := validate.ShortName(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.ExistingVolume) *string { + return &oldObj.Name + }) + errs = append(errs, fn(fldPath.Child("name"), &obj.Name, oldVal, oldObj != nil)...) + } + + { // field ateapipb.ExistingVolume.Driver + fn := func( + fldPath *field.Path, + obj, oldObj *string, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + // custom validation + if e := ValidateCustom_ExistingVolume_Driver(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + } + if e := validate.MaxLength(ctx, op, fldPath, obj, oldObj, 253); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.ExistingVolume) *string { + return &oldObj.Driver + }) + errs = append(errs, fn(fldPath.Child("driver"), &obj.Driver, oldVal, oldObj != nil)...) + } + + { // field ateapipb.ExistingVolume.VolumeHandle + fn := func( + fldPath *field.Path, + obj, oldObj *string, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + // custom validation + if e := ValidateCustom_ExistingVolume_VolumeHandle(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + } + if e := validate.MaxLength(ctx, op, fldPath, obj, oldObj, 256); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.ExistingVolume) *string { + return &oldObj.VolumeHandle + }) + errs = append(errs, fn(fldPath.Child("volume_handle"), &obj.VolumeHandle, oldVal, oldObj != nil)...) + } + + { // field ateapipb.ExistingVolume.AccessMode + fn := func( + fldPath *field.Path, + obj, oldObj *ateapipb.VolumeAccessMode, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + if e := validate.Maximum(ctx, op, fldPath, obj, oldObj, 3); len(e) != 0 { + errs = append(errs, e...) + } + if e := validate.Minimum(ctx, op, fldPath, obj, oldObj, 2); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.ExistingVolume) *ateapipb.VolumeAccessMode { + return &oldObj.AccessMode + }) + errs = append(errs, fn(fldPath.Child("access_mode"), &obj.AccessMode, oldVal, oldObj != nil)...) + } + + { // field ateapipb.ExistingVolume.SubPath + fn := func( + fldPath *field.Path, + obj, oldObj *string, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + // custom validation + if e := ValidateCustom_ExistingVolume_SubPath(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + } + if e := validate.MaxLength(ctx, op, fldPath, obj, oldObj, 4096); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.ExistingVolume) *string { + return &oldObj.SubPath + }) + errs = append(errs, fn(fldPath.Child("sub_path"), &obj.SubPath, oldVal, oldObj != nil)...) + } + + return errs +} + // Validate_ExternalSnapshot validates an instance of ExternalSnapshot according // to declarative validation rules in the API schema. func Validate_ExternalSnapshot( @@ -8500,7 +8733,7 @@ func Validate_UpdateWorkerRequest( return errs } -var unionMembershipFor_github_com_agent_substrate_substrate_pkg_proto_ateapipb_Volume_ = validate.NewUnionMembership(validate.NewUnionMember("durable_dir"), validate.NewUnionMember("external_volume_template"), validate.NewUnionMember("system_info"), validate.NewUnionMember("image")) +var unionMembershipFor_github_com_agent_substrate_substrate_pkg_proto_ateapipb_Volume_ = validate.NewUnionMembership(validate.NewUnionMember("durable_dir"), validate.NewUnionMember("external_volume_template"), validate.NewUnionMember("system_info"), validate.NewUnionMember("image"), validate.NewUnionMember("existing_volume")) // Validate_Volume validates an instance of Volume according // to declarative validation rules in the API schema. @@ -8532,6 +8765,12 @@ func Validate_Volume( return false } return obj.Image != nil + }, + func(obj *ateapipb.Volume) bool { + if obj == nil { + return false + } + return obj.ExistingVolume != nil }); len(e) != 0 { errs = append(errs, e...) } @@ -8686,6 +8925,34 @@ func Validate_Volume( errs = append(errs, fn(fldPath.Child("image"), obj.Image, oldVal, oldObj != nil)...) } + { // field ateapipb.Volume.ExistingVolume + fn := func( + fldPath *field.Path, + obj, oldObj *ateapipb.ExistingVolumeSource, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if ateDeepEqual(obj, oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.Volume) *ateapipb.ExistingVolumeSource { + return oldObj.ExistingVolume + }) + errs = append(errs, fn(fldPath.Child("existing_volume"), obj.ExistingVolume, oldVal, oldObj != nil)...) + } + return errs } @@ -8763,6 +9030,69 @@ func Validate_VolumeMount( errs = append(errs, fn(fldPath.Child("mount_path"), &obj.MountPath, oldVal, oldObj != nil)...) } + { // field ateapipb.VolumeMount.SubPath + fn := func( + fldPath *field.Path, + obj, oldObj *string, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + // custom validation + if e := ValidateCustom_VolumeMount_SubPath(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + } + if e := validate.MaxLength(ctx, op, fldPath, obj, oldObj, 4096); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.VolumeMount) *string { + return &oldObj.SubPath + }) + errs = append(errs, fn(fldPath.Child("sub_path"), &obj.SubPath, oldVal, oldObj != nil)...) + } + + { // field ateapipb.VolumeMount.ReadOnly + fn := func( + fldPath *field.Path, + obj, oldObj *bool, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.VolumeMount) *bool { + return &oldObj.ReadOnly + }) + errs = append(errs, fn(fldPath.Child("read_only"), &obj.ReadOnly, oldVal, oldObj != nil)...) + } + return errs } diff --git a/cmd/ateapi/internal/controlapi/access_policy_test.go b/cmd/ateapi/internal/controlapi/access_policy_test.go index 8ac514ff14..83bdbd3861 100644 --- a/cmd/ateapi/internal/controlapi/access_policy_test.go +++ b/cmd/ateapi/internal/controlapi/access_policy_test.go @@ -47,7 +47,7 @@ func TestAccessPolicy_GlobalAndAtespaceGovernance(t *testing.T) { } persistence.SetPolicyManager(policyManager) - svc := NewRPCService(persistence, nil, nil, nil, nil, nil, nil, nil, "", 0, 0, nil, nil, "", nil, nil) + svc := NewRPCService(persistence, nil, nil, nil, nil, nil, nil, nil, nil, "", 0, 0, nil, nil, "", nil, nil) interceptor := authz.UnaryServerInterceptor(authorizer, true) userCtx := func(id string) context.Context { diff --git a/cmd/ateapi/internal/controlapi/actor.go b/cmd/ateapi/internal/controlapi/actor.go index c9ce6bb394..53fc664e93 100644 --- a/cmd/ateapi/internal/controlapi/actor.go +++ b/cmd/ateapi/internal/controlapi/actor.go @@ -88,14 +88,27 @@ func (s *ServiceImpl) CreateActor(ctx context.Context, inActor *ateapipb.Actor) return nil, err } + if err := validateExistingVolumes(ctx, s.pluginRegistry, s.persistentVolumeLister, template, inActor.GetExistingVolumes()); err != nil { + return nil, err + } + // Resolve the explicit tag, or freeze the template's current golden default. + // The golden actor supplies no existing volumes, so its snapshot was + // captured without their mounts: an actor that supplies any boots fresh + // instead of restoring guest state built under another mount set. tagRef := inActor.GetSourceTag() - if tagRef == nil { + switch { + case tagRef == nil && len(inActor.GetExistingVolumes()) > 0: + case tagRef == nil: if legacyGoldenSnapshot(template.GetStatus().GetGoldenSnapshotStatus()) { return nil, goldenSnapshotAwaitingMigration(template) } tagRef = template.GetStatus().GetGoldenSnapshotStatus().GetGoldenTag() - } else { + case len(inActor.GetExistingVolumes()) > 0: + // A tag does not record which existing volumes its guest state was + // captured with. + return nil, status.Error(codes.FailedPrecondition, "Tag cloning does not support actors with existing volumes") + default: for _, volume := range template.GetVolumes() { if volume.GetExternalVolumeTemplate() != nil { // TODO: Permit cloning after CSI volume snapshots are supported. diff --git a/cmd/ateapi/internal/controlapi/existing_volumes.go b/cmd/ateapi/internal/controlapi/existing_volumes.go new file mode 100644 index 0000000000..255520b4a0 --- /dev/null +++ b/cmd/ateapi/internal/controlapi/existing_volumes.go @@ -0,0 +1,220 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package controlapi + +import ( + "context" + "fmt" + "path" + + "github.com/agent-substrate/substrate/internal/proto/ateletpb" + "github.com/agent-substrate/substrate/internal/volume" + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/labels" + corev1listers "k8s.io/client-go/listers/core/v1" +) + +// existingVolume returns the actor's reference for the template's existing +// volume volumeName, or nil. +func existingVolume(actor *ateapipb.Actor, volumeName string) *ateapipb.ExistingVolume { + for _, ev := range actor.GetExistingVolumes() { + if ev.GetName() == volumeName { + return ev + } + } + return nil +} + +// unsuppliedVolume reports whether volumeName is an existing volume of the +// template that the actor does not supply: such a volume contributes neither +// itself nor its mounts. +func unsuppliedVolume(template *ateapipb.ActorTemplate, actor *ateapipb.Actor, volumeName string) bool { + for _, vol := range template.GetVolumes() { + if vol.GetName() == volumeName { + return vol.GetExistingVolume() != nil && existingVolume(actor, volumeName) == nil + } + } + return false +} + +// accessModeToVolume maps the API's access mode to the volume plugins'. +func accessModeToVolume(mode ateapipb.VolumeAccessMode) volume.AccessMode { + switch mode { + case ateapipb.VolumeAccessMode_VOLUME_ACCESS_MODE_READ_ONLY_MANY: + return volume.ReadOnlyMany + case ateapipb.VolumeAccessMode_VOLUME_ACCESS_MODE_READ_WRITE_MANY: + return volume.ReadWriteMany + default: + return volume.ReadWriteOnce + } +} + +// accessModeToAtelet maps the API's access mode to atelet's. +func accessModeToAtelet(mode ateapipb.VolumeAccessMode) ateletpb.VolumeAccessMode { + return ateletpb.VolumeAccessMode(mode) +} + +// pvAccessModes are the PersistentVolume access modes that permit each mode: +// a read-write-many volume may also be mounted read-only on many nodes. +var pvAccessModes = map[ateapipb.VolumeAccessMode][]corev1.PersistentVolumeAccessMode{ + ateapipb.VolumeAccessMode_VOLUME_ACCESS_MODE_READ_ONLY_MANY: {corev1.ReadOnlyMany, corev1.ReadWriteMany}, + ateapipb.VolumeAccessMode_VOLUME_ACCESS_MODE_READ_WRITE_MANY: {corev1.ReadWriteMany}, +} + +// findPersistentVolume returns the PersistentVolume that holds the CSI +// volume handle of driver, or nil. +func findPersistentVolume(pvLister corev1listers.PersistentVolumeLister, driver, handle string) (*corev1.PersistentVolume, error) { + pvs, err := pvLister.List(labels.Everything()) + if err != nil { + return nil, err + } + for _, pv := range pvs { + if csi := pv.Spec.CSI; csi != nil && csi.Driver == driver && csi.VolumeHandle == handle { + return pv, nil + } + } + return nil, nil +} + +// resolveExistingVolume finds the PersistentVolume of an actor's existing +// volume and checks that it permits the volume's access mode. +func resolveExistingVolume(pvLister corev1listers.PersistentVolumeLister, ev *ateapipb.ExistingVolume) (*corev1.PersistentVolume, error) { + name := ev.GetName() + pv, err := findPersistentVolume(pvLister, ev.GetDriver(), ev.GetVolumeHandle()) + if err != nil { + return nil, status.Errorf(codes.Internal, "existing volume %q: listing PersistentVolumes: %v", name, err) + } + if pv == nil { + return nil, status.Errorf(codes.FailedPrecondition, "existing volume %q: no PersistentVolume of driver %q holds volume %q", name, ev.GetDriver(), ev.GetVolumeHandle()) + } + for _, want := range pvAccessModes[ev.GetAccessMode()] { + for _, got := range pv.Spec.AccessModes { + if got == want { + return pv, nil + } + } + } + return nil, status.Errorf(codes.FailedPrecondition, "existing volume %q: PersistentVolume %q permits %v, not %s", name, pv.Name, pv.Spec.AccessModes, ev.GetAccessMode()) +} + +// validateExistingVolumes checks a CreateActor's existing volumes against the +// template and the cluster, so that a volume that cannot be mounted is +// refused at create rather than at the actor's first resume: each must +// supply an existing volume of the template, its driver must be registered, +// and a PersistentVolume of the driver must hold its handle and permit its +// access mode. +func validateExistingVolumes(ctx context.Context, registry VolumePluginRegistry, pvLister corev1listers.PersistentVolumeLister, template *ateapipb.ActorTemplate, evs []*ateapipb.ExistingVolume) error { + for _, ev := range evs { + name := ev.GetName() + declared := false + for _, vol := range template.GetVolumes() { + if vol.GetName() == name && vol.GetExistingVolume() != nil { + declared = true + break + } + } + if !declared { + return status.Errorf(codes.InvalidArgument, "existing volume %q: ActorTemplate declares no existing volume %q", name, name) + } + if _, err := registry.GetPlugin(ctx, ev.GetDriver()); err != nil { + return status.Errorf(codes.FailedPrecondition, "existing volume %q: unknown driver %q: %v", name, ev.GetDriver(), err) + } + if _, err := resolveExistingVolume(pvLister, ev); err != nil { + return err + } + } + return nil +} + +// appendExistingVolumes adds the actor's mounted existing volumes to +// workloadSpec. Their volume context comes from the PersistentVolume at +// resume (fillExistingVolumeContext): unmounting needs none. +func appendExistingVolumes(workloadSpec *ateletpb.WorkloadSpec, template *ateapipb.ActorTemplate, actor *ateapipb.Actor) { + for _, vol := range template.GetVolumes() { + if vol.GetExistingVolume() == nil || !isVolumeMounted(vol.GetName(), template) { + continue + } + ev := existingVolume(actor, vol.GetName()) + if ev == nil { + continue + } + workloadSpec.Volumes = append(workloadSpec.Volumes, &ateletpb.Volume{ + Name: vol.GetName(), + Source: &ateletpb.Volume_External{ + External: &ateletpb.ExternalVolumeSource{ + StorageVolumeId: ev.GetVolumeHandle(), + VolumeType: ev.GetDriver(), + AccessMode: accessModeToAtelet(ev.GetAccessMode()), + }, + }, + }) + } +} + +// existingVolumeMount returns the atelet mount of an existing volume: its +// sub_path is under the actor's root of the volume, and a read-only volume +// mounts read-only. +func existingVolumeMount(mount *ateapipb.VolumeMount, ev *ateapipb.ExistingVolume) *ateletpb.VolumeMount { + subPath := mount.GetSubPath() + if root := ev.GetSubPath(); root != "" { + subPath = path.Join(root, subPath) + } + return &ateletpb.VolumeMount{ + Name: mount.GetName(), + MountPath: mount.GetMountPath(), + SubPath: subPath, + ReadOnly: mount.GetReadOnly() || ev.GetAccessMode() == ateapipb.VolumeAccessMode_VOLUME_ACCESS_MODE_READ_ONLY_MANY, + } +} + +// fillExistingVolumeContext sets each existing volume's volume context in +// workloadSpec from its PersistentVolume, which the driver needs to mount it. +func fillExistingVolumeContext(workloadSpec *ateletpb.WorkloadSpec, pvLister corev1listers.PersistentVolumeLister, actor *ateapipb.Actor) error { + for _, vol := range workloadSpec.GetVolumes() { + ev := existingVolume(actor, vol.GetName()) + ext := vol.GetExternal() + if ev == nil || ext == nil { + continue + } + pv, err := resolveExistingVolume(pvLister, ev) + if err != nil { + return err + } + ext.VolumeContext = pv.Spec.CSI.VolumeAttributes + } + return nil +} + +// attachExistingVolumes attaches the actor's mounted existing volumes to +// node. They are never detached by the actor: other actors on the node may +// be using them. +func attachExistingVolumes(ctx context.Context, registry VolumePluginRegistry, actor *ateapipb.Actor, template *ateapipb.ActorTemplate, node string) error { + for _, ev := range actor.GetExistingVolumes() { + if !isVolumeMounted(ev.GetName(), template) { + continue + } + plugin, err := registry.GetPlugin(ctx, ev.GetDriver()) + if err != nil { + return fmt.Errorf("failed to get volume plugin for %q: %w", ev.GetDriver(), err) + } + if err := plugin.AttachVolume(ctx, ev.GetVolumeHandle(), node, accessModeToVolume(ev.GetAccessMode())); err != nil { + return fmt.Errorf("failed to attach existing volume %q to node %q: %w", ev.GetName(), node, err) + } + } + return nil +} diff --git a/cmd/ateapi/internal/controlapi/existing_volumes_test.go b/cmd/ateapi/internal/controlapi/existing_volumes_test.go new file mode 100644 index 0000000000..81e0a75900 --- /dev/null +++ b/cmd/ateapi/internal/controlapi/existing_volumes_test.go @@ -0,0 +1,287 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package controlapi + +import ( + "context" + "strings" + "testing" + + "github.com/agent-substrate/substrate/internal/proto/ateletpb" + "github.com/agent-substrate/substrate/internal/volume" + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" + "github.com/google/go-cmp/cmp" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/testing/protocmp" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + corev1listers "k8s.io/client-go/listers/core/v1" + "k8s.io/client-go/tools/cache" +) + +const ( + nfsDriver = "nfs.csi.k8s.io" + nfsHandle = "nfs-server#share#workspace-1" +) + +// workspaceTemplate mounts the existing volume "workspace" at /workspace and +// a second existing volume "mirrors" read-only at /mirrors, beside an +// image volume. +func workspaceTemplate() *ateapipb.ActorTemplate { + return &ateapipb.ActorTemplate{ + Containers: []*ateapipb.Container{{ + Name: "agent", + Image: "agent@sha256:0000000000000000000000000000000000000000000000000000000000000000", + VolumeMounts: []*ateapipb.VolumeMount{ + {Name: "tools", MountPath: "/tools"}, + {Name: "workspace", MountPath: "/workspace"}, + {Name: "mirrors", MountPath: "/mirrors", ReadOnly: true}, + }, + }}, + Volumes: []*ateapipb.Volume{ + {Name: "tools", Image: &ateapipb.ImageVolumeSource{Reference: "tools@sha256:0000000000000000000000000000000000000000000000000000000000000000"}}, + {Name: "workspace", ExistingVolume: &ateapipb.ExistingVolumeSource{}}, + {Name: "mirrors", ExistingVolume: &ateapipb.ExistingVolumeSource{}}, + }, + } +} + +// sessionVolumes supply both existing volumes from one handle: the +// session's own directory read-write and the mirrors read-only. +func sessionVolumes(session string) []*ateapipb.ExistingVolume { + return []*ateapipb.ExistingVolume{ + {Name: "workspace", Driver: nfsDriver, VolumeHandle: nfsHandle, AccessMode: ateapipb.VolumeAccessMode_VOLUME_ACCESS_MODE_READ_WRITE_MANY, SubPath: "sessions/" + session}, + {Name: "mirrors", Driver: nfsDriver, VolumeHandle: nfsHandle, AccessMode: ateapipb.VolumeAccessMode_VOLUME_ACCESS_MODE_READ_ONLY_MANY, SubPath: "mirrors"}, + } +} + +func pvLister(t *testing.T, pvs ...*corev1.PersistentVolume) corev1listers.PersistentVolumeLister { + t.Helper() + indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{}) + for _, pv := range pvs { + if err := indexer.Add(pv); err != nil { + t.Fatalf("adding PersistentVolume: %v", err) + } + } + return corev1listers.NewPersistentVolumeLister(indexer) +} + +func workspacePV(modes ...corev1.PersistentVolumeAccessMode) *corev1.PersistentVolume { + return &corev1.PersistentVolume{ + ObjectMeta: metav1.ObjectMeta{Name: "pv-workspace-1"}, + Spec: corev1.PersistentVolumeSpec{ + AccessModes: modes, + PersistentVolumeSource: corev1.PersistentVolumeSource{CSI: &corev1.CSIPersistentVolumeSource{ + Driver: nfsDriver, + VolumeHandle: nfsHandle, + VolumeAttributes: map[string]string{"server": "nfs-server", "share": "/"}, + }}, + }, + } +} + +func TestValidateExistingVolumes(t *testing.T) { + rwx := workspacePV(corev1.ReadWriteMany) + registry := &mockPluginRegistry{plugins: map[string]volume.VolumePluginControlPlane{nfsDriver: &volume.MockVolumePlugin{}}} + with := func(mod func(ev *ateapipb.ExistingVolume)) []*ateapipb.ExistingVolume { + evs := sessionVolumes("a") + mod(evs[0]) + return evs + } + for _, tc := range []struct { + name string + evs []*ateapipb.ExistingVolume + pvs []*corev1.PersistentVolume + wantCode codes.Code + wantMsg string + }{ + {name: "none", wantCode: codes.OK}, + {name: "read-write-many volume, mounted read-write and read-only", evs: sessionVolumes("a"), pvs: []*corev1.PersistentVolume{rwx}, wantCode: codes.OK}, + { + name: "volume the template does not declare as existing", + evs: with(func(ev *ateapipb.ExistingVolume) { ev.Name = "tools" }), + pvs: []*corev1.PersistentVolume{rwx}, + wantCode: codes.InvalidArgument, + wantMsg: `ActorTemplate declares no existing volume "tools"`, + }, + { + name: "unknown driver", + evs: with(func(ev *ateapipb.ExistingVolume) { ev.Driver = "unknown.csi.example.com" }), + pvs: []*corev1.PersistentVolume{rwx}, + wantCode: codes.FailedPrecondition, + wantMsg: `existing volume "workspace": unknown driver "unknown.csi.example.com"`, + }, + { + name: "missing volume", + evs: with(func(ev *ateapipb.ExistingVolume) { ev.VolumeHandle = "no-such-volume" }), + pvs: []*corev1.PersistentVolume{rwx}, + wantCode: codes.FailedPrecondition, + wantMsg: `no PersistentVolume of driver "nfs.csi.k8s.io" holds volume "no-such-volume"`, + }, + { + name: "volume of another driver", + evs: sessionVolumes("a"), + pvs: []*corev1.PersistentVolume{func() *corev1.PersistentVolume { + pv := workspacePV(corev1.ReadWriteMany) + pv.Spec.CSI.Driver = "other" + return pv + }()}, + wantCode: codes.FailedPrecondition, + wantMsg: `no PersistentVolume of driver "nfs.csi.k8s.io" holds volume`, + }, + { + name: "single-node volume", + evs: sessionVolumes("a"), + pvs: []*corev1.PersistentVolume{workspacePV(corev1.ReadWriteOnce)}, + wantCode: codes.FailedPrecondition, + wantMsg: `PersistentVolume "pv-workspace-1" permits [ReadWriteOnce], not VOLUME_ACCESS_MODE_READ_WRITE_MANY`, + }, + { + name: "read-only-many volume mounted read-write", + evs: sessionVolumes("a"), + pvs: []*corev1.PersistentVolume{workspacePV(corev1.ReadOnlyMany)}, + wantCode: codes.FailedPrecondition, + wantMsg: `not VOLUME_ACCESS_MODE_READ_WRITE_MANY`, + }, + } { + t.Run(tc.name, func(t *testing.T) { + err := validateExistingVolumes(context.Background(), registry, pvLister(t, tc.pvs...), workspaceTemplate(), tc.evs) + if got := status.Code(err); got != tc.wantCode { + t.Fatalf("validateExistingVolumes code = %v (%v), want %v", got, err, tc.wantCode) + } + if tc.wantMsg != "" && !strings.Contains(err.Error(), tc.wantMsg) { + t.Errorf("validateExistingVolumes error = %q, want it to contain %q", err, tc.wantMsg) + } + }) + } +} + +func TestWorkloadSpecExistingVolumes(t *testing.T) { + t.Run("supplied volumes mount at their sub-paths", func(t *testing.T) { + actor := &ateapipb.Actor{ExistingVolumes: sessionVolumes("a")} + spec, err := workloadSpecFromActorTemplate(workspaceTemplate(), actor) + if err != nil { + t.Fatalf("workloadSpecFromActorTemplate: %v", err) + } + wantVolumes := []*ateletpb.Volume{ + {Name: "tools", Source: &ateletpb.Volume_Image{Image: &ateletpb.ImageVolumeSource{Reference: "tools@sha256:0000000000000000000000000000000000000000000000000000000000000000"}}}, + {Name: "workspace", Source: &ateletpb.Volume_External{External: &ateletpb.ExternalVolumeSource{StorageVolumeId: nfsHandle, VolumeType: nfsDriver, AccessMode: ateletpb.VolumeAccessMode_VOLUME_ACCESS_MODE_READ_WRITE_MANY}}}, + {Name: "mirrors", Source: &ateletpb.Volume_External{External: &ateletpb.ExternalVolumeSource{StorageVolumeId: nfsHandle, VolumeType: nfsDriver, AccessMode: ateletpb.VolumeAccessMode_VOLUME_ACCESS_MODE_READ_ONLY_MANY}}}, + } + if diff := cmp.Diff(wantVolumes, spec.GetVolumes(), protocmp.Transform()); diff != "" { + t.Errorf("volumes mismatch (-want +got):\n%s", diff) + } + wantMounts := []*ateletpb.VolumeMount{ + {Name: "tools", MountPath: "/tools"}, + {Name: "workspace", MountPath: "/workspace", SubPath: "sessions/a"}, + {Name: "mirrors", MountPath: "/mirrors", SubPath: "mirrors", ReadOnly: true}, + } + if diff := cmp.Diff(wantMounts, spec.GetContainers()[0].GetVolumeMounts(), protocmp.Transform()); diff != "" { + t.Errorf("mounts mismatch (-want +got):\n%s", diff) + } + }) + + t.Run("a mount's sub_path is under the actor's root, and a read-only volume mounts read-only", func(t *testing.T) { + tmpl := workspaceTemplate() + tmpl.Containers[0].VolumeMounts[1].SubPath = "src" + evs := sessionVolumes("a") + evs[1].SubPath = "" + spec, err := workloadSpecFromActorTemplate(tmpl, &ateapipb.Actor{ExistingVolumes: evs}) + if err != nil { + t.Fatalf("workloadSpecFromActorTemplate: %v", err) + } + mounts := spec.GetContainers()[0].GetVolumeMounts() + if got := mounts[1].GetSubPath(); got != "sessions/a/src" { + t.Errorf("workspace sub_path = %q, want sessions/a/src", got) + } + tmpl.Containers[0].VolumeMounts[2].ReadOnly = false + spec, _ = workloadSpecFromActorTemplate(tmpl, &ateapipb.Actor{ExistingVolumes: evs}) + if m := spec.GetContainers()[0].GetVolumeMounts()[2]; !m.GetReadOnly() || m.GetSubPath() != "" { + t.Errorf("mirrors mount = %v, want read-only at the volume root", m) + } + }) + + t.Run("without a reference the request is unchanged", func(t *testing.T) { + // The same template without its existing volumes and their mounts. + plain := workspaceTemplate() + plain.Containers[0].VolumeMounts = plain.Containers[0].VolumeMounts[:1] + plain.Volumes = plain.Volumes[:1] + want, err := workloadSpecFromActorTemplate(plain, &ateapipb.Actor{}) + if err != nil { + t.Fatalf("workloadSpecFromActorTemplate: %v", err) + } + for _, actor := range []*ateapipb.Actor{{}, nil} { + got, err := workloadSpecFromActorTemplate(workspaceTemplate(), actor) + if err != nil { + t.Fatalf("workloadSpecFromActorTemplate: %v", err) + } + if !proto.Equal(want, got) { + t.Errorf("spec without references = %v, want %v", got, want) + } + } + }) +} + +func TestFillExistingVolumeContext(t *testing.T) { + actor := &ateapipb.Actor{ExistingVolumes: sessionVolumes("a")} + spec, err := workloadSpecFromActorTemplate(workspaceTemplate(), actor) + if err != nil { + t.Fatalf("workloadSpecFromActorTemplate: %v", err) + } + if err := fillExistingVolumeContext(spec, pvLister(t, workspacePV(corev1.ReadWriteMany)), actor); err != nil { + t.Fatalf("fillExistingVolumeContext: %v", err) + } + for _, vol := range spec.GetVolumes()[1:] { + if diff := cmp.Diff(map[string]string{"server": "nfs-server", "share": "/"}, vol.GetExternal().GetVolumeContext()); diff != "" { + t.Errorf("%s volume context mismatch (-want +got):\n%s", vol.GetName(), diff) + } + } + + // A PersistentVolume gone since the create fails the resume with the reason. + err = fillExistingVolumeContext(spec, pvLister(t), actor) + if status.Code(err) != codes.FailedPrecondition || !strings.Contains(err.Error(), "no PersistentVolume") { + t.Errorf("fillExistingVolumeContext without the PersistentVolume = %v, want FailedPrecondition", err) + } +} + +// attachRecorder records AttachVolume calls. +type attachRecorder struct { + volume.MockVolumePlugin + attached []string + modes []volume.AccessMode +} + +func (a *attachRecorder) AttachVolume(_ context.Context, volumeID, node string, mode volume.AccessMode) error { + a.attached = append(a.attached, volumeID+"@"+node) + a.modes = append(a.modes, mode) + return nil +} + +func TestAttachExistingVolumes(t *testing.T) { + plugin := &attachRecorder{} + registry := &mockPluginRegistry{plugins: map[string]volume.VolumePluginControlPlane{nfsDriver: plugin}} + actor := &ateapipb.Actor{ExistingVolumes: sessionVolumes("a")} + if err := attachExistingVolumes(context.Background(), registry, actor, workspaceTemplate(), "node-1"); err != nil { + t.Fatalf("attachExistingVolumes: %v", err) + } + if diff := cmp.Diff([]string{nfsHandle + "@node-1", nfsHandle + "@node-1"}, plugin.attached); diff != "" { + t.Errorf("attached mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff([]volume.AccessMode{volume.ReadWriteMany, volume.ReadOnlyMany}, plugin.modes); diff != "" { + t.Errorf("modes mismatch (-want +got):\n%s", diff) + } +} diff --git a/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go b/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go index 88daec6ac9..defdfb9953 100644 --- a/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go +++ b/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go @@ -1597,7 +1597,7 @@ func (f *partialFailVolumePlugin) CreateVolume(ctx context.Context, name, capaci return "storage-" + name, parameters, nil } -func (f *partialFailVolumePlugin) AttachVolume(ctx context.Context, volumeID, node string) error { +func (f *partialFailVolumePlugin) AttachVolume(ctx context.Context, volumeID, node string, _ volume.AccessMode) error { return nil } @@ -1738,7 +1738,7 @@ func (r *retrySuccessVolumePlugin) CreateVolume(ctx context.Context, name, capac return "storage-" + name, parameters, nil } -func (r *retrySuccessVolumePlugin) AttachVolume(ctx context.Context, volumeID, node string) error { +func (r *retrySuccessVolumePlugin) AttachVolume(ctx context.Context, volumeID, node string, _ volume.AccessMode) error { return nil } @@ -1880,7 +1880,7 @@ func (a *attachFailVolumePlugin) CreateVolume(ctx context.Context, name, capacit return "storage-" + name, parameters, nil } -func (a *attachFailVolumePlugin) AttachVolume(ctx context.Context, volumeID, node string) error { +func (a *attachFailVolumePlugin) AttachVolume(ctx context.Context, volumeID, node string, _ volume.AccessMode) error { a.mu.Lock() defer a.mu.Unlock() a.attachAttempts++ @@ -2125,7 +2125,7 @@ func (m *multiVolAttachPlugin) CreateVolume(ctx context.Context, name, capacity, return "storage-" + name, parameters, nil } -func (m *multiVolAttachPlugin) AttachVolume(ctx context.Context, volumeID, node string) error { +func (m *multiVolAttachPlugin) AttachVolume(ctx context.Context, volumeID, node string, _ volume.AccessMode) error { m.mu.Lock() defer m.mu.Unlock() m.attachAttempts[volumeID]++ @@ -2296,7 +2296,7 @@ func (d *detachFailVolumePlugin) CreateVolume(ctx context.Context, name, capacit return "storage-" + name, parameters, nil } -func (d *detachFailVolumePlugin) AttachVolume(ctx context.Context, volumeID, node string) error { +func (d *detachFailVolumePlugin) AttachVolume(ctx context.Context, volumeID, node string, _ volume.AccessMode) error { d.mu.Lock() defer d.mu.Unlock() d.attachedNodes = append(d.attachedNodes, node) diff --git a/cmd/ateapi/internal/controlapi/functionaltest/common_test.go b/cmd/ateapi/internal/controlapi/functionaltest/common_test.go index ae130a6218..22337ce952 100644 --- a/cmd/ateapi/internal/controlapi/functionaltest/common_test.go +++ b/cmd/ateapi/internal/controlapi/functionaltest/common_test.go @@ -135,6 +135,7 @@ func setupTestWithVolumePlugins(t *testing.T, ns string, plugins map[string]volu scFactory := informers.NewSharedInformerFactory(k8sClient, 0) scLister := scFactory.Storage().V1().StorageClasses().Lister() nodeLister := scFactory.Core().V1().Nodes().Lister() + pvLister := scFactory.Core().V1().PersistentVolumes().Lister() substrateInformerFactory := externalversions.NewSharedInformerFactory(substrateClient, 0) workerPoolLister := substrateInformerFactory.Api().V1alpha1().WorkerPools().Lister() @@ -217,6 +218,7 @@ func setupTestWithVolumePlugins(t *testing.T, ns string, plugins map[string]volu sandboxConfigLister, csiDriverConfigLister, scLister, + pvLister, nodeLister, dialer, instruments, diff --git a/cmd/ateapi/internal/controlapi/service.go b/cmd/ateapi/internal/controlapi/service.go index 0efaf8cf83..484a7feaa8 100644 --- a/cmd/ateapi/internal/controlapi/service.go +++ b/cmd/ateapi/internal/controlapi/service.go @@ -82,6 +82,7 @@ func NewRPCService( sandboxConfigLister listersv1alpha1.SandboxConfigLister, csiDriverConfigLister listersv1alpha1.CSIDriverConfigLister, storageClassLister storagev1listers.StorageClassLister, + persistentVolumeLister corev1listers.PersistentVolumeLister, nodeLister corev1listers.NodeLister, dialer *AteletDialer, instruments *Instruments, @@ -108,7 +109,10 @@ func NewRPCService( actorIDJWTPool: actorIDJWTPool, actorIDCAPool: actorIDCAPool, } + impl.pluginRegistry = s + impl.persistentVolumeLister = persistentVolumeLister s.actorWorkflow = NewActorWorkflow(impl, workerCache, dialer, sandboxConfigLister, storageClassLister, nodeLister, instruments, egressGatewayAddress, s, actorWorkflowDeadline, actorRestoreBudget, objectStore) + s.actorWorkflow.persistentVolumeLister = persistentVolumeLister s.workerWorkflow = NewWorkerWorkflow(impl) return s } @@ -188,6 +192,11 @@ type ServiceImpl struct { store store.Interface storageClassLister storagev1listers.StorageClassLister + + // pluginRegistry and persistentVolumeLister resolve what CreateActor + // checks an actor's existing volumes against. + pluginRegistry VolumePluginRegistry + persistentVolumeLister corev1listers.PersistentVolumeLister } // newServiceImpl creates an instance of the service's middleware diff --git a/cmd/ateapi/internal/controlapi/workflow.go b/cmd/ateapi/internal/controlapi/workflow.go index 8cee739565..5f62072f51 100644 --- a/cmd/ateapi/internal/controlapi/workflow.go +++ b/cmd/ateapi/internal/controlapi/workflow.go @@ -116,9 +116,11 @@ type ActorWorkflow struct { instruments *Instruments egressGatewayAddress string pluginRegistry VolumePluginRegistry - workflowDeadline time.Duration - restoreBudget time.Duration - objectStore objectstore.Store + // persistentVolumeLister resolves an actor's existing volumes at resume. + persistentVolumeLister corev1listers.PersistentVolumeLister + workflowDeadline time.Duration + restoreBudget time.Duration + objectStore objectstore.Store // pauseUploads makes every pause durable in the background; nil in a // workflow built without one, which then pauses node-locally only. pauseUploads *pauseUploader diff --git a/cmd/ateapi/internal/controlapi/workflow_resume.go b/cmd/ateapi/internal/controlapi/workflow_resume.go index 0e3bb3d80c..db7b8f4210 100644 --- a/cmd/ateapi/internal/controlapi/workflow_resume.go +++ b/cmd/ateapi/internal/controlapi/workflow_resume.go @@ -27,6 +27,7 @@ import ( "github.com/agent-substrate/substrate/internal/ateattr" "github.com/agent-substrate/substrate/internal/proto/ateletpb" "github.com/agent-substrate/substrate/internal/resources" + "github.com/agent-substrate/substrate/internal/volume" "github.com/agent-substrate/substrate/pkg/proto/ateapipb" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -624,11 +625,11 @@ func (w *ActorWorkflow) ensureVolumesAttached(ctx context.Context, actor *ateapi if err != nil { return fmt.Errorf("failed to get volume plugin for %q: %w", vol.GetVolumeType(), err) } - if err := plugin.AttachVolume(ctx, vol.GetStorageVolumeId(), node); err != nil { + if err := plugin.AttachVolume(ctx, vol.GetStorageVolumeId(), node, volume.ReadWriteOnce); err != nil { return fmt.Errorf("failed to attach volume %q to node %q: %w", vol.GetStorageVolumeId(), node, err) } } - return nil + return attachExistingVolumes(ctx, w.pluginRegistry, actor, actorTemplate, node) } // ensureAteletRestored brings the workload up on the assigned worker: @@ -665,6 +666,9 @@ func (w *ActorWorkflow) ensureAteletRestored(ctx context.Context, actorRef resou if err != nil { return tele, err } + if err := fillExistingVolumeContext(workloadSpec, w.persistentVolumeLister, actor); err != nil { + return tele, err + } egressGateway := w.egressGateway() // The actor's declared limits ride the RPC down to the sandbox so it is sized diff --git a/cmd/ateapi/internal/controlapi/workload_spec.go b/cmd/ateapi/internal/controlapi/workload_spec.go index 8bcc167458..16642756d5 100644 --- a/cmd/ateapi/internal/controlapi/workload_spec.go +++ b/cmd/ateapi/internal/controlapi/workload_spec.go @@ -122,6 +122,7 @@ func workloadSpecFromActorTemplate(actorTemplate *ateapipb.ActorTemplate, actor if err := appendExternalVolumes(workloadSpec, actorTemplate, actor); err != nil { return nil, err } + appendExistingVolumes(workloadSpec, actorTemplate, actor) for _, ctr := range actorTemplate.GetContainers() { ctrResources, err := toAteletResources(ctr.GetResources()) @@ -144,6 +145,13 @@ func workloadSpecFromActorTemplate(actorTemplate *ateapipb.ActorTemplate, actor }) } for _, mount := range ctr.GetVolumeMounts() { + if unsuppliedVolume(actorTemplate, actor, mount.GetName()) { + continue + } + if ev := existingVolume(actor, mount.GetName()); ev != nil { + ateletCtr.VolumeMounts = append(ateletCtr.VolumeMounts, existingVolumeMount(mount, ev)) + continue + } ateletCtr.VolumeMounts = append(ateletCtr.VolumeMounts, &ateletpb.VolumeMount{ Name: mount.GetName(), MountPath: mount.GetMountPath(), diff --git a/cmd/ateapi/main.go b/cmd/ateapi/main.go index bfe19d0ce4..d913cf02fd 100644 --- a/cmd/ateapi/main.go +++ b/cmd/ateapi/main.go @@ -248,6 +248,9 @@ func main() { // exists, the one signal that tells a node gone from one whose workers are // momentarily absent. nodeLister := scInformerFactory.Core().V1().Nodes().Lister() + // PersistentVolumes: the cluster's record of the existing volumes actors + // mount, which CreateActor checks and resume reads the volume context from. + persistentVolumeLister := scInformerFactory.Core().V1().PersistentVolumes().Lister() stopCh := make(chan struct{}) defer close(stopCh) @@ -299,6 +302,7 @@ func main() { sandboxConfigLister, csiDriverConfigLister, storageClassLister, + persistentVolumeLister, nodeLister, ateletDialer, instruments, diff --git a/cmd/atelet/main.go b/cmd/atelet/main.go index bcaa3bf302..ea96f49115 100644 --- a/cmd/atelet/main.go +++ b/cmd/atelet/main.go @@ -521,7 +521,7 @@ func (s *AteomHerder) Run(ctx context.Context, req *ateletpb.RunRequest) (resp * return nil, fmt.Errorf("while resetting actor dirs: %w", err) } - if err := s.mountExternalVolumes(ctx, actorUID, req.GetSpec().GetVolumes()); err != nil { + if err := s.mountExternalVolumes(ctx, actorUID, req.GetSpec()); err != nil { return nil, err } @@ -759,7 +759,7 @@ func (s *AteomHerder) Checkpoint(ctx context.Context, req *ateletpb.CheckpointRe } dPersist = time.Since(tPersist) - if err := s.unmountExternalVolumes(ctx, actorUID, req.GetSpec().GetVolumes()); err != nil { + if err := s.unmountExternalVolumes(ctx, actorUID, req.GetSpec()); err != nil { return nil, fmt.Errorf("while unmounting external volumes: %w", err) } @@ -1133,7 +1133,7 @@ func (s *AteomHerder) Restore(ctx context.Context, req *ateletpb.RestoreRequest) } tMount := time.Now() - mountErr := s.mountExternalVolumes(ctx, actorUID, req.GetSpec().GetVolumes()) + mountErr := s.mountExternalVolumes(ctx, actorUID, req.GetSpec()) dMount = time.Since(tMount) if mountErr != nil { return nil, mountErr @@ -1364,7 +1364,7 @@ func (s *AteomHerder) Terminate(ctx context.Context, req *ateletpb.TerminateRequ s.systemInfoVolumes.Deregister(actorUID) // Unmount external volumes - if err := s.unmountExternalVolumes(ctx, actorUID, req.GetSpec().GetVolumes()); err != nil { + if err := s.unmountExternalVolumes(ctx, actorUID, req.GetSpec()); err != nil { return nil, fmt.Errorf("failed to unmount external volumes during terminate (actor: %s, actorUID: %s): %w", actorRef, actorUID, err) } @@ -1664,6 +1664,8 @@ func buildAteomWorkloadSpec(spec *ateletpb.WorkloadSpec) (*ateompb.WorkloadSpec, csiMounts = append(csiMounts, &ateompb.VolumeMount{ VolumeName: volName, MountPath: vm.GetMountPath(), + SubPath: vm.GetSubPath(), + ReadOnly: vm.GetReadOnly(), }) case *ateletpb.Volume_SystemInfo: siMounts = append(siMounts, &ateompb.SystemInfoVolumeMount{ diff --git a/cmd/atelet/volumes.go b/cmd/atelet/volumes.go index b2698d7004..08f19812e0 100644 --- a/cmd/atelet/volumes.go +++ b/cmd/atelet/volumes.go @@ -29,8 +29,8 @@ import ( "google.golang.org/grpc/status" ) -func (s *AteomHerder) mountExternalVolumes(ctx context.Context, actorUID string, volumes []*ateletpb.Volume) error { - for _, vol := range volumes { +func (s *AteomHerder) mountExternalVolumes(ctx context.Context, actorUID string, spec *ateletpb.WorkloadSpec) error { + for _, vol := range spec.GetVolumes() { ext := vol.GetExternal() if ext == nil { continue @@ -44,16 +44,16 @@ func (s *AteomHerder) mountExternalVolumes(ctx context.Context, actorUID string, if err != nil { return fmt.Errorf("failed to get volume plugin for %q: %w", ext.GetVolumeType(), err) } - if err := plugin.MountVolume(ctx, ext.GetStorageVolumeId(), hostPath, ext.GetVolumeContext()); err != nil { + if err := plugin.MountVolume(ctx, ext.GetStorageVolumeId(), hostPath, ext.GetVolumeContext(), accessMode(ext)); err != nil { return fmt.Errorf("failed to mount volume %q to %q: %w", ext.GetStorageVolumeId(), hostPath, err) } } return nil } -func (s *AteomHerder) unmountExternalVolumes(ctx context.Context, actorUID string, volumes []*ateletpb.Volume) error { +func (s *AteomHerder) unmountExternalVolumes(ctx context.Context, actorUID string, spec *ateletpb.WorkloadSpec) error { var errs []error - for _, vol := range volumes { + for _, vol := range spec.GetVolumes() { ext := vol.GetExternal() if ext == nil { continue @@ -67,7 +67,7 @@ func (s *AteomHerder) unmountExternalVolumes(ctx context.Context, actorUID strin errs = append(errs, fmt.Errorf("failed to get volume plugin for %q (volume %q): %w", ext.GetVolumeType(), ext.GetStorageVolumeId(), err)) continue } - if err := plugin.UnmountVolume(ctx, ext.GetStorageVolumeId(), hostPath); err != nil { + if err := plugin.UnmountVolume(ctx, ext.GetStorageVolumeId(), hostPath, accessMode(ext)); err != nil { if status.Code(err) == codes.NotFound || errors.Is(err, os.ErrNotExist) { slog.WarnContext(ctx, "Volume not found during unmount, assuming already unmounted", slog.String("volume_id", ext.GetStorageVolumeId()), slog.Any("error", err)) } else { @@ -78,6 +78,18 @@ func (s *AteomHerder) unmountExternalVolumes(ctx context.Context, actorUID strin return errors.Join(errs...) } +// accessMode maps an external volume's access mode to the volume plugins'. +func accessMode(ext *ateletpb.ExternalVolumeSource) volume.AccessMode { + switch ext.GetAccessMode() { + case ateletpb.VolumeAccessMode_VOLUME_ACCESS_MODE_READ_ONLY_MANY: + return volume.ReadOnlyMany + case ateletpb.VolumeAccessMode_VOLUME_ACCESS_MODE_READ_WRITE_MANY: + return volume.ReadWriteMany + default: + return volume.ReadWriteOnce + } +} + func (s *AteomHerder) getPlugin(ctx context.Context, driverName string) (volume.VolumePluginWorkerPlane, error) { s.mu.RLock() plugin, ok := s.volumePlugins[driverName] diff --git a/cmd/atelet/volumes_test.go b/cmd/atelet/volumes_test.go index dcd36ecea6..55a5777a83 100644 --- a/cmd/atelet/volumes_test.go +++ b/cmd/atelet/volumes_test.go @@ -45,7 +45,7 @@ type fakeWorkerPlugin struct { mountCalls []mountCall } -func (f *fakeWorkerPlugin) MountVolume(ctx context.Context, volumeID string, targetPath string, attributes map[string]string) error { +func (f *fakeWorkerPlugin) MountVolume(ctx context.Context, volumeID string, targetPath string, attributes map[string]string, _ volume.AccessMode) error { f.mountCalls = append(f.mountCalls, mountCall{ volumeID: volumeID, targetPath: targetPath, @@ -59,7 +59,7 @@ func (f *fakeWorkerPlugin) MountVolume(ctx context.Context, volumeID string, tar return f.mountErr } -func (f *fakeWorkerPlugin) UnmountVolume(ctx context.Context, volumeID string, targetPath string) error { +func (f *fakeWorkerPlugin) UnmountVolume(ctx context.Context, volumeID string, targetPath string, _ volume.AccessMode) error { f.unmounted = append(f.unmounted, volumeID) if f.unmountErrs != nil { if err, ok := f.unmountErrs[volumeID]; ok { @@ -119,7 +119,7 @@ func TestUnmountExternalVolumes(t *testing.T) { }, } - err := s.unmountExternalVolumes(ctx, actorUID, []*ateletpb.Volume{extVol1, durableVol, extVol2}) + err := s.unmountExternalVolumes(ctx, actorUID, &ateletpb.WorkloadSpec{Volumes: []*ateletpb.Volume{extVol1, durableVol, extVol2}}) if err != nil { t.Fatalf("unmountExternalVolumes failed unexpectedly: %v", err) } @@ -138,7 +138,7 @@ func TestUnmountExternalVolumes(t *testing.T) { }, } - err := s.unmountExternalVolumes(ctx, actorUID, []*ateletpb.Volume{extVol1}) + err := s.unmountExternalVolumes(ctx, actorUID, &ateletpb.WorkloadSpec{Volumes: []*ateletpb.Volume{extVol1}}) if err == nil { t.Fatal("unmountExternalVolumes returned nil, want blocking error") } @@ -157,7 +157,7 @@ func TestUnmountExternalVolumes(t *testing.T) { }, } - err := s.unmountExternalVolumes(ctx, actorUID, []*ateletpb.Volume{extVol1, extVol2}) + err := s.unmountExternalVolumes(ctx, actorUID, &ateletpb.WorkloadSpec{Volumes: []*ateletpb.Volume{extVol1, extVol2}}) if err == nil { t.Fatal("unmountExternalVolumes returned nil, want blocking error") } @@ -209,7 +209,7 @@ func TestMountExternalVolumes(t *testing.T) { }, } - err := s.mountExternalVolumes(ctx, actorUID, []*ateletpb.Volume{extVol1, durableVol, extVol2}) + err := s.mountExternalVolumes(ctx, actorUID, &ateletpb.WorkloadSpec{Volumes: []*ateletpb.Volume{extVol1, durableVol, extVol2}}) if err != nil { t.Fatalf("mountExternalVolumes failed unexpectedly: %v", err) } @@ -258,7 +258,7 @@ func TestMountExternalVolumes(t *testing.T) { }, } - err := s.mountExternalVolumes(ctx, actorUID, []*ateletpb.Volume{extVol1}) + err := s.mountExternalVolumes(ctx, actorUID, &ateletpb.WorkloadSpec{Volumes: []*ateletpb.Volume{extVol1}}) if err != nil { t.Fatalf("mountExternalVolumes with existing directory failed: %v", err) } @@ -284,7 +284,7 @@ func TestMountExternalVolumes(t *testing.T) { volumePlugins: map[string]volume.VolumePluginWorkerPlane{}, } - err := s.mountExternalVolumes(ctx, actorUID, []*ateletpb.Volume{unknownVol}) + err := s.mountExternalVolumes(ctx, actorUID, &ateletpb.WorkloadSpec{Volumes: []*ateletpb.Volume{unknownVol}}) if err == nil { t.Fatal("expected mountExternalVolumes to fail with unknown plugin, got nil") } @@ -305,7 +305,7 @@ func TestMountExternalVolumes(t *testing.T) { }, } - err := s.mountExternalVolumes(ctx, actorUID, []*ateletpb.Volume{extVol1}) + err := s.mountExternalVolumes(ctx, actorUID, &ateletpb.WorkloadSpec{Volumes: []*ateletpb.Volume{extVol1}}) if err == nil { t.Fatal("expected mountExternalVolumes to fail, got nil") } @@ -326,7 +326,7 @@ func TestMountExternalVolumes(t *testing.T) { }, } - err := s.mountExternalVolumes(ctx, actorUID, []*ateletpb.Volume{extVol1, extVol2}) + err := s.mountExternalVolumes(ctx, actorUID, &ateletpb.WorkloadSpec{Volumes: []*ateletpb.Volume{extVol1, extVol2}}) if err == nil { t.Fatal("expected mountExternalVolumes to fail, got nil") } @@ -352,7 +352,7 @@ func TestMountExternalVolumes(t *testing.T) { }, } - err := s.mountExternalVolumes(ctx, actorUID, []*ateletpb.Volume{extVol1, extVol2}) + err := s.mountExternalVolumes(ctx, actorUID, &ateletpb.WorkloadSpec{Volumes: []*ateletpb.Volume{extVol1, extVol2}}) if err == nil { t.Fatal("expected mountExternalVolumes to fail when vol-2 fails, got nil") } @@ -418,7 +418,7 @@ func TestVolumeHostDirectoryCleanup(t *testing.T) { }, } - if err := s.mountExternalVolumes(ctx, actorUID, []*ateletpb.Volume{extVol1, extVol2}); err != nil { + if err := s.mountExternalVolumes(ctx, actorUID, &ateletpb.WorkloadSpec{Volumes: []*ateletpb.Volume{extVol1, extVol2}}); err != nil { t.Fatalf("mountExternalVolumes failed: %v", err) } @@ -430,7 +430,7 @@ func TestVolumeHostDirectoryCleanup(t *testing.T) { } } - if err := s.unmountExternalVolumes(ctx, actorUID, []*ateletpb.Volume{extVol1, extVol2}); err != nil { + if err := s.unmountExternalVolumes(ctx, actorUID, &ateletpb.WorkloadSpec{Volumes: []*ateletpb.Volume{extVol1, extVol2}}); err != nil { t.Fatalf("unmountExternalVolumes failed: %v", err) } @@ -453,10 +453,10 @@ func TestVolumeHostDirectoryCleanup(t *testing.T) { } // Mount and then unmount external volumes. - if err := s.mountExternalVolumes(ctx, actorUID, []*ateletpb.Volume{extVol1, extVol2}); err != nil { + if err := s.mountExternalVolumes(ctx, actorUID, &ateletpb.WorkloadSpec{Volumes: []*ateletpb.Volume{extVol1, extVol2}}); err != nil { t.Fatalf("mountExternalVolumes failed: %v", err) } - if err := s.unmountExternalVolumes(ctx, actorUID, []*ateletpb.Volume{extVol1, extVol2}); err != nil { + if err := s.unmountExternalVolumes(ctx, actorUID, &ateletpb.WorkloadSpec{Volumes: []*ateletpb.Volume{extVol1, extVol2}}); err != nil { t.Fatalf("unmountExternalVolumes failed: %v", err) } @@ -500,7 +500,7 @@ func TestVolumeHostDirectoryCleanup(t *testing.T) { }, } - if err := s.mountExternalVolumes(ctx, actorUID, []*ateletpb.Volume{extVol1}); err != nil { + if err := s.mountExternalVolumes(ctx, actorUID, &ateletpb.WorkloadSpec{Volumes: []*ateletpb.Volume{extVol1}}); err != nil { t.Fatalf("mountExternalVolumes failed: %v", err) } diff --git a/cmd/ateom-gvisor/main.go b/cmd/ateom-gvisor/main.go index 0324458442..b603177562 100644 --- a/cmd/ateom-gvisor/main.go +++ b/cmd/ateom-gvisor/main.go @@ -53,6 +53,7 @@ import ( "github.com/agent-substrate/substrate/internal/serverboot" "github.com/agent-substrate/substrate/internal/sizing" "github.com/agent-substrate/substrate/internal/version" + "github.com/agent-substrate/substrate/internal/volumebind" "github.com/agent-substrate/substrate/internal/wakeupprobe" "github.com/spf13/pflag" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" @@ -583,6 +584,11 @@ func (s *AteomService) RunWorkload(ctx context.Context, req *ateompb.RunWorkload if err := s.tunnel.ActivateEgress(ateomstats.ActorAttributionFromRequest(req), egress); err != nil { return nil, err } + // Bind the directories of external volumes the mounts name a sub-path of + // or mount read-only, here for the same reason as the rootfs below. + if err := volumebind.Prepare(req.GetActorDirs().GetVolumesDir(), req.GetSpec().GetContainers()); err != nil { + return nil, fmt.Errorf("while binding volume directories: %w", err) + } // Create and start pause container. The bundle rootfs is composed here — // an overlay of the node's cached image layers plus the bundle's private // upper — because mounting is ateom's job (atelet runs with no @@ -890,6 +896,9 @@ func (s *AteomService) RestoreWorkload(ctx context.Context, req *ateompb.Restore return nil, fmt.Errorf("while restoring durable-dir volumes: %w", err) } } + if err := volumebind.Prepare(req.GetActorDirs().GetVolumesDir(), req.GetSpec().GetContainers()); err != nil { + return nil, fmt.Errorf("while binding volume directories: %w", err) + } // Compose the pause rootfs before create (see RunWorkload). runsc restore // only needs the rootfs to hold the correct content; whether it came from // an untar or an overlay of cached layers is transparent to it. @@ -1027,6 +1036,9 @@ func (s *AteomService) terminateWorkload(ctx context.Context, actorRef resources if err := imagecache.UnmountAllUnder(actorDirs.GetOciBundleDir()); err != nil { errs = append(errs, fmt.Errorf("while unmounting bundle rootfs overlays: %w", err)) } + if err := volumebind.Release(actorDirs.GetVolumesDir(), containers); err != nil { + errs = append(errs, fmt.Errorf("while unbinding volume directories: %w", err)) + } if err := s.unhostActor(ctx, actorUID); err != nil { errs = append(errs, fmt.Errorf("while cleaning up actor network: %w", err)) diff --git a/cmd/ateom-microvm/checkpoint.go b/cmd/ateom-microvm/checkpoint.go index c5fa0beefc..f1963d24cd 100644 --- a/cmd/ateom-microvm/checkpoint.go +++ b/cmd/ateom-microvm/checkpoint.go @@ -28,6 +28,7 @@ import ( "github.com/agent-substrate/substrate/internal/apierror" "github.com/agent-substrate/substrate/internal/resources" + "github.com/agent-substrate/substrate/internal/volumebind" "github.com/agent-substrate/substrate/cmd/ateom-microvm/internal/ch" "github.com/agent-substrate/substrate/cmd/ateom-microvm/internal/kata" @@ -212,7 +213,7 @@ func (s *AteomService) CheckpointWorkload(ctx context.Context, req *ateompb.Chec // Tear down: the actor returns to "available". Best-effort; the snapshot is // already on disk for atelet to ship. tTeardown := time.Now() - if err := s.terminateWorkload(ctx, attribution, actorDirs); err != nil { + if err := s.terminateWorkload(ctx, attribution, actorDirs, req.GetSpec().GetContainers()); err != nil { slog.WarnContext(ctx, "failed to terminate workload after checkpoint", slog.String("actor", attribution.Ref.String()), slog.String("actorUID", actorUID), @@ -399,7 +400,7 @@ func (s *AteomService) TerminateWorkload(ctx context.Context, req *ateompb.Termi attribution := ateomstats.ActorAttributionFromRequest(req) - if err := s.terminateWorkload(ctx, attribution, req.GetActorDirs()); err != nil { + if err := s.terminateWorkload(ctx, attribution, req.GetActorDirs(), req.GetSpec().GetContainers()); err != nil { return nil, fmt.Errorf("failed to terminate workload: %w", err) } @@ -418,7 +419,7 @@ func (s *AteomService) stopActorVM(ctx context.Context, actorUID string, actorDi return s.teardownActor(ctx, actorUID, actorDirs, ra, ch.NewClient(chSocket)) } -func (s *AteomService) terminateWorkload(ctx context.Context, actor resources.ActorAttribution, actorDirs *ateompb.ActorDirs) error { +func (s *AteomService) terminateWorkload(ctx context.Context, actor resources.ActorAttribution, actorDirs *ateompb.ActorDirs, containers []*ateompb.Container) error { var errs []error if err := s.tunnel.Deactivate(ctx, actor); err != nil { errs = append(errs, fmt.Errorf("while deactivating actor networking: %w", err)) @@ -428,6 +429,9 @@ func (s *AteomService) terminateWorkload(ctx context.Context, actor resources.Ac if err := s.stopActorVM(ctx, actorUID, actorDirs); err != nil { errs = append(errs, fmt.Errorf("while tearing down actor: %w", err)) } + if err := volumebind.Release(actorDirs.GetVolumesDir(), containers); err != nil { + errs = append(errs, fmt.Errorf("while unbinding volume directories: %w", err)) + } // Remove attribution after teardown; a failed checkpoint may leave the VM running. if err := s.unhostActor(ctx, actorUID); err != nil { errs = append(errs, fmt.Errorf("while cleaning up actor network: %w", err)) diff --git a/cmd/ateom-microvm/run.go b/cmd/ateom-microvm/run.go index 490e712eb0..d8706670c0 100644 --- a/cmd/ateom-microvm/run.go +++ b/cmd/ateom-microvm/run.go @@ -43,6 +43,7 @@ import ( "github.com/agent-substrate/substrate/internal/proto/ateompb" "github.com/agent-substrate/substrate/internal/resources" "github.com/agent-substrate/substrate/internal/sizing" + "github.com/agent-substrate/substrate/internal/volumebind" "github.com/agent-substrate/substrate/internal/wakeupprobe" specs "github.com/opencontainers/runtime-spec/specs-go" "golang.org/x/sys/unix" @@ -697,6 +698,11 @@ func (s *AteomService) stageMergedRootfs(ctx context.Context, rr resolvedRuntime } } if hasCsiVolumes(containers) { + // The directories mounts name a sub-path of, or mount read-only, are + // bound beside their volumes first, so the share carries them too. + if err := volumebind.Prepare(actorDirs.GetVolumesDir(), containers); err != nil { + return nil, fmt.Errorf("while binding volume directories: %w", err) + } if err := s.stageCsiVolumes(ctx, id, actorDirs.GetVolumesDir()); err != nil { return nil, fmt.Errorf("while staging CSI volumes: %w", err) } diff --git a/docs/csi-volumes.md b/docs/csi-volumes.md index d33bb83c08..6eda80ba22 100644 --- a/docs/csi-volumes.md +++ b/docs/csi-volumes.md @@ -99,6 +99,50 @@ volumeMounts: --- +### Existing Volumes: One Volume, Many Actors + +A volume that exists outside Substrate and outlives its actors, such as a read-write-many workspace several actors work on, is an **existing volume**. The template declares it by name and mounts it; each actor supplies it at `CreateActor`: + +```yaml +volumes: +- name: workspace + existingVolume: {} +- name: mirrors + existingVolume: {} +containers: +- name: agent + volumeMounts: + - name: workspace + mountPath: /workspace + - name: mirrors + mountPath: /mirrors + readOnly: true +``` + +```yaml +existingVolumes: +- name: workspace + driver: nfs.csi.k8s.io + volumeHandle: + accessMode: VOLUME_ACCESS_MODE_READ_WRITE_MANY + subPath: sessions/a +- name: mirrors + driver: nfs.csi.k8s.io + volumeHandle: + accessMode: VOLUME_ACCESS_MODE_READ_ONLY_MANY + subPath: mirrors +``` + +* An existing volume's `subPath` is the directory this actor sees as the volume's root; a mount's own `subPath` is relative to it. So one template serves every actor, each in a directory of its own. One volume may be mounted at several paths. +* The directory must exist on the volume: Substrate never creates one. It is resolved beneath the volume's root without following any symbolic link, so a link that another actor wrote on the volume fails the mount rather than redirecting it. +* `readOnly` mounts read-only, and so does every mount of a `READ_ONLY_MANY` volume. +* `CreateActor` refuses a reference that names no existing volume of the template, a driver without a `CSIDriverConfig`, a handle that no PersistentVolume of the driver holds, and an access mode the PersistentVolume does not permit. The PersistentVolume's `spec.csi.volumeAttributes` are passed to the driver when the volume is mounted, so it must still exist when the actor resumes. +* An existing volume of the template that the actor does not supply contributes neither the volume nor its mounts. +* Substrate never creates, deletes or changes an existing volume, and never detaches one from a node, where other actors may be using it. Pause, resume (on another node too) and delete only unmount and mount it. +* An actor with existing volumes boots from its image instead of the template's golden snapshot, which was captured without their mounts, and cannot be created from a tag. `existingVolumes` is immutable. + +--- + ## 4. End-to-End Example The following example demonstrates setting up an NFS CSI driver with Substrate and deploying an `ActorTemplate` that mounts an external NFS volume. diff --git a/internal/e2e/suites/existingvolumes/existingvolumes_test.go b/internal/e2e/suites/existingvolumes/existingvolumes_test.go new file mode 100644 index 0000000000..494e9c8798 --- /dev/null +++ b/internal/e2e/suites/existingvolumes/existingvolumes_test.go @@ -0,0 +1,441 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package existingvolumes exercises existing volumes against a live Kind +// cluster with the CSI NFS driver (`ate-setup setup csi nfs`): a +// read-write-many volume is provisioned and filled outside Substrate, as a +// Kubernetes PVC a pod prepares, and actors mount directories of it. +package existingvolumes + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "strings" + "testing" + "time" + + "github.com/agent-substrate/substrate/internal/e2e" + "github.com/agent-substrate/substrate/internal/resources" + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + atespace = "existingvolumes" + driver = "nfs.csi.k8s.io" + + workspaceVolume = "workspace" + mirrorsVolume = "mirrors" + workspacePath = "/workspace" + mirrorsPath = "/mirrors" + + mirrorFile = "mirror.txt" + mirrorContent = "a file of the mirrors" + + // probeWrittenContent is the fixed string the probe's /writefile writes. + probeWrittenContent = "written by probe" + + busybox = "busybox@sha256:1487d0af5f52b4ba31c7e465126ee2123fe3f2305d638e7827681e7cf6c83d5e" +) + +// requireNFS skips unless the cluster has the NFS StorageClass. A lane that +// installed it sets E2E_CSI_NFS=1, and there a missing one fails the suite +// instead: a skip there would pass having run nothing. +func requireNFS(ctx context.Context, t *testing.T, clients *e2e.Clients) { + t.Helper() + missing := t.Skipf + if os.Getenv("E2E_CSI_NFS") == "1" { + missing = t.Fatalf + } + if _, err := clients.K8s.StorageV1().StorageClasses().Get(ctx, e2e.StorageClass, metav1.GetOptions{}); err != nil { + missing("StorageClass %q not found (%v); install it with `ate-setup setup csi nfs`", e2e.StorageClass, err) + } +} + +// eventually polls check until it returns true or the timeout passes. +func eventually(t *testing.T, timeout time.Duration, what string, check func() (bool, error)) { + t.Helper() + deadline := time.Now().Add(timeout) + for { + ok, err := check() + if ok { + return + } + if time.Now().After(deadline) { + t.Fatalf("timed out after %v waiting for %s (last error: %v)", timeout, what, err) + } + time.Sleep(2 * time.Second) + } +} + +// runOnVolume runs script in a pod that mounts the claim at /data and +// returns its output. +func runOnVolume(ctx context.Context, t *testing.T, clients *e2e.Clients, ns, claim, name, script string) string { + t.Helper() + pod := &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: ns}, + Spec: corev1.PodSpec{ + RestartPolicy: corev1.RestartPolicyNever, + Containers: []corev1.Container{{ + Name: "sh", + Image: busybox, + Command: []string{"sh", "-c", script}, + VolumeMounts: []corev1.VolumeMount{{Name: "data", MountPath: "/data"}}, + }}, + Volumes: []corev1.Volume{{ + Name: "data", + VolumeSource: corev1.VolumeSource{PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ClaimName: claim}}, + }}, + }, + } + if _, err := clients.K8s.CoreV1().Pods(ns).Create(ctx, pod, metav1.CreateOptions{}); err != nil { + t.Fatalf("creating pod %s: %v", name, err) + } + eventually(t, 3*time.Minute, "pod "+name+" to succeed", func() (bool, error) { + got, err := clients.K8s.CoreV1().Pods(ns).Get(ctx, name, metav1.GetOptions{}) + if err != nil { + return false, err + } + if got.Status.Phase == corev1.PodFailed { + t.Fatalf("pod %s failed: %+v", name, got.Status) + } + return got.Status.Phase == corev1.PodSucceeded, fmt.Errorf("phase %s", got.Status.Phase) + }) + out, err := clients.K8s.CoreV1().Pods(ns).GetLogs(name, &corev1.PodLogOptions{}).Do(ctx).Raw() + if err != nil { + t.Fatalf("reading the logs of pod %s: %v", name, err) + } + return string(out) +} + +// prepareVolume provisions a read-write-many PVC, lays out a session +// directory per actor the probe may write and a mirrors directory with +// mirrorFile, and returns the claim and its PersistentVolume's name and handle. +func prepareVolume(ctx context.Context, t *testing.T, clients *e2e.Clients, ns string) (claim, pvName, handle string) { + t.Helper() + pvc := &corev1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{Name: "workspace", Namespace: ns}, + Spec: corev1.PersistentVolumeClaimSpec{ + AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteMany}, + StorageClassName: &e2e.StorageClass, + Resources: corev1.VolumeResourceRequirements{ + Requests: corev1.ResourceList{corev1.ResourceStorage: resource.MustParse("1Gi")}, + }, + }, + } + if _, err := clients.K8s.CoreV1().PersistentVolumeClaims(ns).Create(ctx, pvc, metav1.CreateOptions{}); err != nil { + t.Fatalf("creating PVC: %v", err) + } + runOnVolume(ctx, t, clients, ns, pvc.Name, "prepare", fmt.Sprintf( + "mkdir -m 0777 -p /data/sessions/a /data/sessions/b && mkdir -p /data/mirrors && printf %%s %q > /data/mirrors/%s && sync", + mirrorContent, mirrorFile)) + + bound, err := clients.K8s.CoreV1().PersistentVolumeClaims(ns).Get(ctx, pvc.Name, metav1.GetOptions{}) + if err != nil { + t.Fatalf("reading PVC: %v", err) + } + pv, err := clients.K8s.CoreV1().PersistentVolumes().Get(ctx, bound.Spec.VolumeName, metav1.GetOptions{}) + if err != nil { + t.Fatalf("reading PersistentVolume %q: %v", bound.Spec.VolumeName, err) + } + if pv.Spec.CSI == nil || pv.Spec.CSI.Driver != driver { + t.Fatalf("PersistentVolume %q is not a volume of %s: %+v", pv.Name, driver, pv.Spec.PersistentVolumeSource) + } + return pvc.Name, pv.Name, pv.Spec.CSI.VolumeHandle +} + +// createTemplate builds a probe ActorTemplate that mounts the existing +// volume "workspace" at workspacePath and "mirrors" read-only at mirrorsPath. +func createTemplate(ctx context.Context, t *testing.T, clients *e2e.Clients, ns *e2e.Namespace) *ateapipb.ActorTemplate { + t.Helper() + env, err := e2e.CheckEnv("BUCKET_NAME") + if err != nil { + t.Fatalf("CheckEnv: %v", err) + } + probeAtespace, _ := e2e.DeployProbe(t, env["BUCKET_NAME"], "existingvolumes") + src := e2e.SubstrateFixture{ + Atespace: probeAtespace, + Name: e2e.ProbeName, + PoolNamespace: probeAtespace, + PoolName: e2e.ProbeName, + DeployWith: "the existingvolumes suite's own DeployProbe", + } + return e2e.CreateSubstrateTemplateFrom(ctx, t, clients, ns.Name, src, e2e.SubstrateTemplateOptions{ + Atespace: atespace, + Name: "probe-" + ns.Name, + PoolName: e2e.ProbeName, + PoolReplicas: 3, + Labels: map[string]string{"existingvolumes": ns.Name}, + SnapshotConfig: &ateapipb.SnapshotConfig{ + StorageLocation: fmt.Sprintf("gs://%s/%s/", env["BUCKET_NAME"], ns.Name), + }, + Modify: func(tmpl *ateapipb.ActorTemplate) { + tmpl.Containers[0].VolumeMounts = append(tmpl.Containers[0].VolumeMounts, + &ateapipb.VolumeMount{Name: workspaceVolume, MountPath: workspacePath}, + &ateapipb.VolumeMount{Name: mirrorsVolume, MountPath: mirrorsPath, ReadOnly: true}) + tmpl.Volumes = append(tmpl.Volumes, + &ateapipb.Volume{Name: workspaceVolume, ExistingVolume: &ateapipb.ExistingVolumeSource{}}, + &ateapipb.Volume{Name: mirrorsVolume, ExistingVolume: &ateapipb.ExistingVolumeSource{}}) + }, + }) +} + +// sessionVolumes supply both existing volumes from one handle: the +// session's own directory read-write and the mirrors read-only. +func sessionVolumes(handle, session string) []*ateapipb.ExistingVolume { + return []*ateapipb.ExistingVolume{ + {Name: workspaceVolume, Driver: driver, VolumeHandle: handle, AccessMode: ateapipb.VolumeAccessMode_VOLUME_ACCESS_MODE_READ_WRITE_MANY, SubPath: "sessions/" + session}, + {Name: mirrorsVolume, Driver: driver, VolumeHandle: handle, AccessMode: ateapipb.VolumeAccessMode_VOLUME_ACCESS_MODE_READ_ONLY_MANY, SubPath: "mirrors"}, + } +} + +func createActor(ctx context.Context, clients *e2e.Clients, tmpl *ateapipb.ActorTemplate, ref resources.ActorRef, evs []*ateapipb.ExistingVolume) (*ateapipb.Actor, error) { + return clients.SubstrateAPI.CreateActor(ctx, &ateapipb.CreateActorRequest{ + Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: ref.Atespace, Name: ref.Name}, + ActorTemplate: e2e.TemplateRef(tmpl), + ExistingVolumes: evs, + }, + }) +} + +// deleteActorAtEnd registers the deletion of an actor when the whole suite +// ends: a later subtest uses an actor an earlier one started. +func deleteActorAtEnd(t *testing.T, clients *e2e.Clients, ref resources.ActorRef) { + t.Cleanup(func() { + cleanupCtx := context.Background() + _, _ = clients.SubstrateAPI.SuspendActor(cleanupCtx, &ateapipb.SuspendActorRequest{Actor: ref.ToObjectRef()}) + _, _ = clients.SubstrateAPI.DeleteActor(cleanupCtx, &ateapipb.DeleteActorRequest{Actor: ref.ToObjectRef()}) + }) +} + +// startActor creates and resumes an actor. +func startActor(ctx context.Context, t *testing.T, clients *e2e.Clients, tmpl *ateapipb.ActorTemplate, ref resources.ActorRef, evs []*ateapipb.ExistingVolume) { + t.Helper() + if _, err := createActor(ctx, clients, tmpl, ref, evs); err != nil { + t.Fatalf("CreateActor %s: %v", ref, err) + } + if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapipb.ResumeActorRequest{Actor: ref.ToObjectRef()}); err != nil { + t.Fatalf("ResumeActor %s: %v", ref, err) + } +} + +func probeJSON(ctx context.Context, t *testing.T, router *e2e.RouterClient, ref resources.ActorRef, path string) map[string]string { + t.Helper() + resp, err := router.Get(ctx, ref, path) + if err != nil { + t.Fatalf("GET %s on %s: %v", path, ref, err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + body, _ := io.ReadAll(resp.Body) + t.Fatalf("GET %s on %s: status %d: %s", path, ref, resp.StatusCode, body) + } + var out map[string]string + if err := json.NewDecoder(resp.Body).Decode(&out); err != nil { + t.Fatalf("decoding %s: %v", path, err) + } + return out +} + +func requireContent(ctx context.Context, t *testing.T, router *e2e.RouterClient, ref resources.ActorRef, path, want string) { + t.Helper() + got := probeJSON(ctx, t, router, ref, "/readfile?path="+path) + if got["error"] != "" { + t.Fatalf("%s: reading %s: %s", ref, path, got["error"]) + } + if got["content"] != want { + t.Errorf("%s: content at %s = %q, want %q", ref, path, got["content"], want) + } +} + +func requireAbsent(ctx context.Context, t *testing.T, router *e2e.RouterClient, ref resources.ActorRef, path string) { + t.Helper() + if got := probeJSON(ctx, t, router, ref, "/readfile?path="+path); got["error"] == "" { + t.Errorf("%s: %s is readable (%q), want it absent", ref, path, got["content"]) + } +} + +func requireWrite(ctx context.Context, t *testing.T, router *e2e.RouterClient, ref resources.ActorRef, path string) { + t.Helper() + if got := probeJSON(ctx, t, router, ref, "/writefile?path="+path); got["error"] != "" { + t.Fatalf("%s: writing %s: %s", ref, path, got["error"]) + } +} + +func requireWriteRefused(ctx context.Context, t *testing.T, router *e2e.RouterClient, ref resources.ActorRef, path string) { + t.Helper() + got := probeJSON(ctx, t, router, ref, "/writefile?path="+path) + if got["error"] == "" { + t.Fatalf("%s: writing %s succeeded, want it refused", ref, path) + } + t.Logf("%s: write to %s refused as expected: %s", ref, path, got["error"]) +} + +// volumeFiles lists the regular files on the volume, relative to its root. +func volumeFiles(ctx context.Context, t *testing.T, clients *e2e.Clients, ns, claim, name string) []string { + t.Helper() + out := runOnVolume(ctx, t, clients, ns, claim, name, "cd /data && find . -type f | sort") + return strings.Fields(out) +} + +func requireFiles(t *testing.T, got []string, want ...string) { + t.Helper() + for _, w := range want { + found := false + for _, g := range got { + if g == w { + found = true + } + } + if !found { + t.Errorf("volume files %v lack %s", got, w) + } + } +} + +func TestExistingVolumes(t *testing.T) { + ctx := context.Background() + clients := e2e.GetClients() + requireNFS(ctx, t, clients) + + ns := e2e.CreateNamespace(t) + claim, pvName, handle := prepareVolume(ctx, t, clients, ns.Name) + t.Logf("existing volume: PersistentVolume %s, handle %s", pvName, handle) + tmpl := createTemplate(ctx, t, clients, ns) + + router, err := e2e.NewRouterClient(ctx) + if err != nil { + t.Fatalf("NewRouterClient: %v", err) + } + defer router.Close() + + actorA := resources.ActorRef{Atespace: atespace, Name: "session-a-" + ns.Name} + actorB := resources.ActorRef{Atespace: atespace, Name: "session-b-" + ns.Name} + plain := resources.ActorRef{Atespace: atespace, Name: "plain-" + ns.Name} + for _, ref := range []resources.ActorRef{actorA, actorB, plain} { + deleteActorAtEnd(t, clients, ref) + } + mirrorPath := mirrorsPath + "/" + mirrorFile + + t.Run("MountsSubPathsAtDeclaredPaths", func(t *testing.T) { + startActor(ctx, t, clients, tmpl, actorA, sessionVolumes(handle, "a")) + requireContent(ctx, t, router, actorA, mirrorPath, mirrorContent) + requireWrite(ctx, t, router, actorA, workspacePath+"/a.txt") + requireContent(ctx, t, router, actorA, workspacePath+"/a.txt", probeWrittenContent) + requireFiles(t, volumeFiles(ctx, t, clients, ns.Name, claim, "inspect-a"), "./sessions/a/a.txt", "./mirrors/"+mirrorFile) + }) + + t.Run("ActorsWriteOnlyTheirOwnSubPath", func(t *testing.T) { + startActor(ctx, t, clients, tmpl, actorB, sessionVolumes(handle, "b")) + requireContent(ctx, t, router, actorB, mirrorPath, mirrorContent) + requireAbsent(ctx, t, router, actorB, workspacePath+"/a.txt") + requireWrite(ctx, t, router, actorB, workspacePath+"/b.txt") + requireWriteRefused(ctx, t, router, actorB, mirrorsPath+"/b.txt") + requireWriteRefused(ctx, t, router, actorA, mirrorsPath+"/a.txt") + files := volumeFiles(ctx, t, clients, ns.Name, claim, "inspect-b") + requireFiles(t, files, "./sessions/a/a.txt", "./sessions/b/b.txt") + for _, f := range files { + if strings.HasPrefix(f, "./mirrors/") && f != "./mirrors/"+mirrorFile { + t.Errorf("the read-only mount wrote %s", f) + } + } + }) + + t.Run("NoReferenceNoMounts", func(t *testing.T) { + startActor(ctx, t, clients, tmpl, plain, nil) + requireAbsent(ctx, t, router, plain, mirrorPath) + if got := probeJSON(ctx, t, router, plain, "/writefile?path="+workspacePath+"/plain.txt"); got["error"] == "" { + t.Errorf("%s wrote %s/plain.txt: the unsupplied volume is mounted", plain, workspacePath) + } + }) + + t.Run("PauseResumeDeleteLeaveTheVolume", func(t *testing.T) { + if _, err := clients.SubstrateAPI.PauseActor(ctx, &ateapipb.PauseActorRequest{Actor: actorA.ToObjectRef()}); err != nil { + t.Fatalf("PauseActor: %v", err) + } + eventually(t, 2*time.Minute, "actor A to pause", func() (bool, error) { + actor, err := clients.SubstrateAPI.GetActor(ctx, &ateapipb.GetActorRequest{Actor: actorA.ToObjectRef()}) + if err != nil { + return false, err + } + state := actor.GetStatus().GetState() + return state == ateapipb.ActorState_ACTOR_STATE_PAUSED, fmt.Errorf("state %v", state) + }) + if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapipb.ResumeActorRequest{Actor: actorA.ToObjectRef()}); err != nil { + t.Fatalf("ResumeActor: %v", err) + } + requireContent(ctx, t, router, actorA, workspacePath+"/a.txt", probeWrittenContent) + requireContent(ctx, t, router, actorA, mirrorPath, mirrorContent) + + // A running actor is not deletable; the suspend unmounts its volumes. + if _, err := clients.SubstrateAPI.SuspendActor(ctx, &ateapipb.SuspendActorRequest{Actor: actorA.ToObjectRef()}); err != nil { + t.Fatalf("SuspendActor: %v", err) + } + if _, err := clients.SubstrateAPI.DeleteActor(ctx, &ateapipb.DeleteActorRequest{Actor: actorA.ToObjectRef()}); err != nil { + t.Fatalf("DeleteActor: %v", err) + } + eventually(t, 2*time.Minute, "actor A to be gone", func() (bool, error) { + _, err := clients.SubstrateAPI.GetActor(ctx, &ateapipb.GetActorRequest{Actor: actorA.ToObjectRef()}) + return status.Code(err) == codes.NotFound, fmt.Errorf("GetActor: %v", err) + }) + if _, err := clients.K8s.CoreV1().PersistentVolumes().Get(ctx, pvName, metav1.GetOptions{}); err != nil { + t.Fatalf("PersistentVolume %s after the delete: %v", pvName, err) + } + requireFiles(t, volumeFiles(ctx, t, clients, ns.Name, claim, "inspect-after-delete"), "./sessions/a/a.txt", "./sessions/b/b.txt", "./mirrors/"+mirrorFile) + // The other actor still works on the volume. + requireContent(ctx, t, router, actorB, workspacePath+"/b.txt", probeWrittenContent) + }) + + t.Run("RefusesBadReferencesAtCreate", func(t *testing.T) { + for _, tc := range []struct { + name string + mod func(ev *ateapipb.ExistingVolume) + wantCode codes.Code + wantMsg string + }{ + { + name: "unknown driver", + mod: func(ev *ateapipb.ExistingVolume) { ev.Driver = "unknown.csi.example.com" }, + wantCode: codes.FailedPrecondition, + wantMsg: `unknown driver "unknown.csi.example.com"`, + }, + { + name: "missing volume", + mod: func(ev *ateapipb.ExistingVolume) { ev.VolumeHandle = "no-such-volume" }, + wantCode: codes.FailedPrecondition, + wantMsg: `no PersistentVolume of driver "nfs.csi.k8s.io" holds volume "no-such-volume"`, + }, + } { + t.Run(tc.name, func(t *testing.T) { + evs := sessionVolumes(handle, "refused") + tc.mod(evs[0]) + ref := resources.ActorRef{Atespace: atespace, Name: "refused-" + ns.Name} + _, err := createActor(ctx, clients, tmpl, ref, evs) + if status.Code(err) != tc.wantCode || !strings.Contains(err.Error(), tc.wantMsg) { + t.Fatalf("CreateActor = %v, want %v containing %q", err, tc.wantCode, tc.wantMsg) + } + t.Logf("refused as expected: %v", err) + }) + } + }) +} diff --git a/internal/e2e/suites/existingvolumes/testmain_test.go b/internal/e2e/suites/existingvolumes/testmain_test.go new file mode 100644 index 0000000000..ff99ca8e29 --- /dev/null +++ b/internal/e2e/suites/existingvolumes/testmain_test.go @@ -0,0 +1,24 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package existingvolumes + +import ( + "os" + "testing" + + "github.com/agent-substrate/substrate/internal/e2e" +) + +func TestMain(m *testing.M) { os.Exit(e2e.RunTestMain(m)) } diff --git a/internal/ocispec/ocispec.go b/internal/ocispec/ocispec.go index 09a8a79b8f..23d1feae1f 100644 --- a/internal/ocispec/ocispec.go +++ b/internal/ocispec/ocispec.go @@ -26,6 +26,7 @@ import ( "github.com/agent-substrate/substrate/internal/imagecache" "github.com/agent-substrate/substrate/internal/proto/ateletpb" + "github.com/agent-substrate/substrate/internal/volumebind" "github.com/opencontainers/runtime-spec/specs-go" ) @@ -182,7 +183,10 @@ func Build(o Options) *specs.Spec { case *ateletpb.Volume_DurableDir: srcPath = filepath.Join(o.DurableDirVolumeMountsDir, vm.GetName()) case *ateletpb.Volume_External: - srcPath = filepath.Join(o.VolumesDir, vm.GetName()) + srcPath = filepath.Join(o.VolumesDir, volumebind.MountDir(vm.GetName(), vm.GetSubPath(), vm.GetReadOnly())) + if vm.GetReadOnly() { + options = []string{"bind", "ro"} + } case *ateletpb.Volume_SystemInfo: srcPath = filepath.Join(o.SystemInfoVolumeRootsDir, vm.GetName()) options = []string{"bind", "ro"} diff --git a/internal/ocispec/ocispec_test.go b/internal/ocispec/ocispec_test.go index f6cb3878ae..98951e2eb2 100644 --- a/internal/ocispec/ocispec_test.go +++ b/internal/ocispec/ocispec_test.go @@ -21,6 +21,7 @@ import ( "github.com/agent-substrate/substrate/internal/imagecache" "github.com/agent-substrate/substrate/internal/proto/ateletpb" + "github.com/agent-substrate/substrate/internal/volumebind" "github.com/opencontainers/runtime-spec/specs-go" ) @@ -62,6 +63,8 @@ func TestBuild_VolumeMounts(t *testing.T) { {Name: "data", MountPath: "/home/counter"}, {Name: "sysinfo", MountPath: "/run/ate"}, {Name: "csi", MountPath: "/mnt/csi"}, + {Name: "csi", MountPath: "/workspace", SubPath: "sessions/a"}, + {Name: "csi", MountPath: "/mirrors", SubPath: "mirrors", ReadOnly: true}, {Name: "agent", MountPath: "/ate"}, }, DurableDirVolumeMountsDir: durableDir, @@ -79,6 +82,8 @@ func TestBuild_VolumeMounts(t *testing.T) { {"/home/counter", durableDir + "/data", []string{"bind", "rw"}}, {"/run/ate", sysInfoDir + "/sysinfo", []string{"bind", "ro"}}, {"/mnt/csi", volumesDir + "/csi", []string{"bind", "rw"}}, + {"/workspace", volumesDir + "/" + volumebind.MountDir("csi", "sessions/a", false), []string{"bind", "rw"}}, + {"/mirrors", volumesDir + "/" + volumebind.MountDir("csi", "mirrors", true), []string{"bind", "ro"}}, {"/ate", imagecache.ImageVolumeMountPath(bundle, "agent"), []string{"bind", "ro"}}, } { m := mountFor(t, spec, tc.dest) diff --git a/internal/proto/ateletpb/atelet.pb.go b/internal/proto/ateletpb/atelet.pb.go index e2e3123b24..456ba9976a 100644 --- a/internal/proto/ateletpb/atelet.pb.go +++ b/internal/proto/ateletpb/atelet.pb.go @@ -35,6 +35,59 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// VolumeAccessMode mirrors ateapi.VolumeAccessMode. +type VolumeAccessMode int32 + +const ( + VolumeAccessMode_VOLUME_ACCESS_MODE_UNSPECIFIED VolumeAccessMode = 0 + VolumeAccessMode_VOLUME_ACCESS_MODE_READ_WRITE_ONCE VolumeAccessMode = 1 + VolumeAccessMode_VOLUME_ACCESS_MODE_READ_ONLY_MANY VolumeAccessMode = 2 + VolumeAccessMode_VOLUME_ACCESS_MODE_READ_WRITE_MANY VolumeAccessMode = 3 +) + +// Enum value maps for VolumeAccessMode. +var ( + VolumeAccessMode_name = map[int32]string{ + 0: "VOLUME_ACCESS_MODE_UNSPECIFIED", + 1: "VOLUME_ACCESS_MODE_READ_WRITE_ONCE", + 2: "VOLUME_ACCESS_MODE_READ_ONLY_MANY", + 3: "VOLUME_ACCESS_MODE_READ_WRITE_MANY", + } + VolumeAccessMode_value = map[string]int32{ + "VOLUME_ACCESS_MODE_UNSPECIFIED": 0, + "VOLUME_ACCESS_MODE_READ_WRITE_ONCE": 1, + "VOLUME_ACCESS_MODE_READ_ONLY_MANY": 2, + "VOLUME_ACCESS_MODE_READ_WRITE_MANY": 3, + } +) + +func (x VolumeAccessMode) Enum() *VolumeAccessMode { + p := new(VolumeAccessMode) + *p = x + return p +} + +func (x VolumeAccessMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (VolumeAccessMode) Descriptor() protoreflect.EnumDescriptor { + return file_atelet_proto_enumTypes[0].Descriptor() +} + +func (VolumeAccessMode) Type() protoreflect.EnumType { + return &file_atelet_proto_enumTypes[0] +} + +func (x VolumeAccessMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use VolumeAccessMode.Descriptor instead. +func (VolumeAccessMode) EnumDescriptor() ([]byte, []int) { + return file_atelet_proto_rawDescGZIP(), []int{0} +} + // ActorMetadataField selects one identity field of the actor. type ActorMetadataField int32 @@ -72,11 +125,11 @@ func (x ActorMetadataField) String() string { } func (ActorMetadataField) Descriptor() protoreflect.EnumDescriptor { - return file_atelet_proto_enumTypes[0].Descriptor() + return file_atelet_proto_enumTypes[1].Descriptor() } func (ActorMetadataField) Type() protoreflect.EnumType { - return &file_atelet_proto_enumTypes[0] + return &file_atelet_proto_enumTypes[1] } func (x ActorMetadataField) Number() protoreflect.EnumNumber { @@ -85,7 +138,7 @@ func (x ActorMetadataField) Number() protoreflect.EnumNumber { // Deprecated: Use ActorMetadataField.Descriptor instead. func (ActorMetadataField) EnumDescriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{0} + return file_atelet_proto_rawDescGZIP(), []int{1} } type CheckpointType int32 @@ -124,11 +177,11 @@ func (x CheckpointType) String() string { } func (CheckpointType) Descriptor() protoreflect.EnumDescriptor { - return file_atelet_proto_enumTypes[1].Descriptor() + return file_atelet_proto_enumTypes[2].Descriptor() } func (CheckpointType) Type() protoreflect.EnumType { - return &file_atelet_proto_enumTypes[1] + return &file_atelet_proto_enumTypes[2] } func (x CheckpointType) Number() protoreflect.EnumNumber { @@ -137,7 +190,7 @@ func (x CheckpointType) Number() protoreflect.EnumNumber { // Deprecated: Use CheckpointType.Descriptor instead. func (CheckpointType) EnumDescriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{1} + return file_atelet_proto_rawDescGZIP(), []int{2} } type SnapshotScope int32 @@ -179,11 +232,11 @@ func (x SnapshotScope) String() string { } func (SnapshotScope) Descriptor() protoreflect.EnumDescriptor { - return file_atelet_proto_enumTypes[2].Descriptor() + return file_atelet_proto_enumTypes[3].Descriptor() } func (SnapshotScope) Type() protoreflect.EnumType { - return &file_atelet_proto_enumTypes[2] + return &file_atelet_proto_enumTypes[3] } func (x SnapshotScope) Number() protoreflect.EnumNumber { @@ -192,7 +245,7 @@ func (x SnapshotScope) Number() protoreflect.EnumNumber { // Deprecated: Use SnapshotScope.Descriptor instead. func (SnapshotScope) EnumDescriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{2} + return file_atelet_proto_rawDescGZIP(), []int{3} } type SetWorkerCapacityRequest struct { @@ -1263,8 +1316,10 @@ type ExternalVolumeSource struct { StorageVolumeId string `protobuf:"bytes,1,opt,name=storage_volume_id,json=storageVolumeId,proto3" json:"storage_volume_id,omitempty"` VolumeType string `protobuf:"bytes,2,opt,name=volume_type,json=volumeType,proto3" json:"volume_type,omitempty"` VolumeContext map[string]string `protobuf:"bytes,3,rep,name=volume_context,json=volumeContext,proto3" json:"volume_context,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // access_mode is how the volume is published; unset is READ_WRITE_ONCE. + AccessMode VolumeAccessMode `protobuf:"varint,4,opt,name=access_mode,json=accessMode,proto3,enum=atelet.VolumeAccessMode" json:"access_mode,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ExternalVolumeSource) Reset() { @@ -1318,6 +1373,13 @@ func (x *ExternalVolumeSource) GetVolumeContext() map[string]string { return nil } +func (x *ExternalVolumeSource) GetAccessMode() VolumeAccessMode { + if x != nil { + return x.AccessMode + } + return VolumeAccessMode_VOLUME_ACCESS_MODE_UNSPECIFIED +} + type ImageVolumeSource struct { state protoimpl.MessageState `protogen:"open.v1"` Reference string `protobuf:"bytes,1,opt,name=reference,proto3" json:"reference,omitempty"` @@ -1767,9 +1829,14 @@ func (*Volume_SystemInfo) isVolume_Source() {} func (*Volume_Image) isVolume_Source() {} type VolumeMount struct { - state protoimpl.MessageState `protogen:"open.v1"` - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - MountPath string `protobuf:"bytes,2,opt,name=mount_path,json=mountPath,proto3" json:"mount_path,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + MountPath string `protobuf:"bytes,2,opt,name=mount_path,json=mountPath,proto3" json:"mount_path,omitempty"` + // sub_path is the directory of an external volume to mount, relative to + // its root; empty mounts the root. + SubPath string `protobuf:"bytes,3,opt,name=sub_path,json=subPath,proto3" json:"sub_path,omitempty"` + // read_only mounts an external volume read-only. + ReadOnly bool `protobuf:"varint,4,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1818,6 +1885,20 @@ func (x *VolumeMount) GetMountPath() string { return "" } +func (x *VolumeMount) GetSubPath() string { + if x != nil { + return x.SubPath + } + return "" +} + +func (x *VolumeMount) GetReadOnly() bool { + if x != nil { + return x.ReadOnly + } + return false +} + type Container struct { state protoimpl.MessageState `protogen:"open.v1"` Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` @@ -3188,12 +3269,14 @@ const file_atelet_proto_rawDesc = "" + "containers\x18\x01 \x03(\v2\x11.atelet.ContainerR\n" + "containers\x12(\n" + "\avolumes\x18\x02 \x03(\v2\x0e.atelet.VolumeR\avolumes\"\x12\n" + - "\x10DurableDirVolume\"\xfd\x01\n" + + "\x10DurableDirVolume\"\xb8\x02\n" + "\x14ExternalVolumeSource\x12*\n" + "\x11storage_volume_id\x18\x01 \x01(\tR\x0fstorageVolumeId\x12\x1f\n" + "\vvolume_type\x18\x02 \x01(\tR\n" + "volumeType\x12V\n" + - "\x0evolume_context\x18\x03 \x03(\v2/.atelet.ExternalVolumeSource.VolumeContextEntryR\rvolumeContext\x1a@\n" + + "\x0evolume_context\x18\x03 \x03(\v2/.atelet.ExternalVolumeSource.VolumeContextEntryR\rvolumeContext\x129\n" + + "\vaccess_mode\x18\x04 \x01(\x0e2\x18.atelet.VolumeAccessModeR\n" + + "accessMode\x1a@\n" + "\x12VolumeContextEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"1\n" + @@ -3221,11 +3304,13 @@ const file_atelet_proto_rawDesc = "" + "\vsystem_info\x18\x04 \x01(\v2\x18.atelet.SystemInfoVolumeH\x00R\n" + "systemInfo\x121\n" + "\x05image\x18\x05 \x01(\v2\x19.atelet.ImageVolumeSourceH\x00R\x05imageB\b\n" + - "\x06source\"@\n" + + "\x06source\"x\n" + "\vVolumeMount\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12\x1d\n" + "\n" + - "mount_path\x18\x02 \x01(\tR\tmountPath\"\xf3\x02\n" + + "mount_path\x18\x02 \x01(\tR\tmountPath\x12\x19\n" + + "\bsub_path\x18\x03 \x01(\tR\asubPath\x12\x1b\n" + + "\tread_only\x18\x04 \x01(\bR\breadOnly\"\xf3\x02\n" + "\tContainer\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12\x14\n" + "\x05image\x18\x02 \x01(\tR\x05image\x12\x18\n" + @@ -3316,7 +3401,12 @@ const file_atelet_proto_rawDesc = "" + "\x0esandbox_assets\x18\x10 \x01(\v2\x15.atelet.SandboxAssetsR\rsandboxAssetsB\b\n" + "\x06configB\x11\n" + "\x0f_egress_gateway\"\x11\n" + - "\x0fRestoreResponse*\x9a\x01\n" + + "\x0fRestoreResponse*\xad\x01\n" + + "\x10VolumeAccessMode\x12\"\n" + + "\x1eVOLUME_ACCESS_MODE_UNSPECIFIED\x10\x00\x12&\n" + + "\"VOLUME_ACCESS_MODE_READ_WRITE_ONCE\x10\x01\x12%\n" + + "!VOLUME_ACCESS_MODE_READ_ONLY_MANY\x10\x02\x12&\n" + + "\"VOLUME_ACCESS_MODE_READ_WRITE_MANY\x10\x03*\x9a\x01\n" + "\x12ActorMetadataField\x12$\n" + " ACTOR_METADATA_FIELD_UNSPECIFIED\x10\x00\x12\x1d\n" + "\x19ACTOR_METADATA_FIELD_NAME\x10\x01\x12!\n" + @@ -3355,129 +3445,131 @@ func file_atelet_proto_rawDescGZIP() []byte { return file_atelet_proto_rawDescData } -var file_atelet_proto_enumTypes = make([]protoimpl.EnumInfo, 3) +var file_atelet_proto_enumTypes = make([]protoimpl.EnumInfo, 4) var file_atelet_proto_msgTypes = make([]protoimpl.MessageInfo, 49) var file_atelet_proto_goTypes = []any{ - (ActorMetadataField)(0), // 0: atelet.ActorMetadataField - (CheckpointType)(0), // 1: atelet.CheckpointType - (SnapshotScope)(0), // 2: atelet.SnapshotScope - (*SetWorkerCapacityRequest)(nil), // 3: atelet.SetWorkerCapacityRequest - (*WorkerResources)(nil), // 4: atelet.WorkerResources - (*Resources)(nil), // 5: atelet.Resources - (*Limits)(nil), // 6: atelet.Limits - (*SetWorkerCapacityResponse)(nil), // 7: atelet.SetWorkerCapacityResponse - (*RequestActorSuspendRequest)(nil), // 8: atelet.RequestActorSuspendRequest - (*RequestActorSuspendResponse)(nil), // 9: atelet.RequestActorSuspendResponse - (*MintActorCertificateRequest)(nil), // 10: atelet.MintActorCertificateRequest - (*MintActorCertificateResponse)(nil), // 11: atelet.MintActorCertificateResponse - (*TerminateRequest)(nil), // 12: atelet.TerminateRequest - (*TerminateResponse)(nil), // 13: atelet.TerminateResponse - (*RunRequest)(nil), // 14: atelet.RunRequest - (*EgressGateway)(nil), // 15: atelet.EgressGateway - (*AssetFile)(nil), // 16: atelet.AssetFile - (*ArchAssets)(nil), // 17: atelet.ArchAssets - (*SandboxAssets)(nil), // 18: atelet.SandboxAssets - (*WorkloadSpec)(nil), // 19: atelet.WorkloadSpec - (*DurableDirVolume)(nil), // 20: atelet.DurableDirVolume - (*ExternalVolumeSource)(nil), // 21: atelet.ExternalVolumeSource - (*ImageVolumeSource)(nil), // 22: atelet.ImageVolumeSource - (*ActorMetadataItem)(nil), // 23: atelet.ActorMetadataItem - (*ActorMetadataDataSource)(nil), // 24: atelet.ActorMetadataDataSource - (*TrustBundleDataSource)(nil), // 25: atelet.TrustBundleDataSource - (*SystemInfoDataSource)(nil), // 26: atelet.SystemInfoDataSource - (*SystemInfoVolume)(nil), // 27: atelet.SystemInfoVolume - (*Volume)(nil), // 28: atelet.Volume - (*VolumeMount)(nil), // 29: atelet.VolumeMount - (*Container)(nil), // 30: atelet.Container - (*SecurityContext)(nil), // 31: atelet.SecurityContext - (*Capabilities)(nil), // 32: atelet.Capabilities - (*ResourceLimits)(nil), // 33: atelet.ResourceLimits - (*EnvEntry)(nil), // 34: atelet.EnvEntry - (*WakeupProbe)(nil), // 35: atelet.WakeupProbe - (*HTTPGetAction)(nil), // 36: atelet.HTTPGetAction - (*RunResponse)(nil), // 37: atelet.RunResponse - (*LocalCheckpointConfiguration)(nil), // 38: atelet.LocalCheckpointConfiguration - (*ExternalCheckpointConfiguration)(nil), // 39: atelet.ExternalCheckpointConfiguration - (*ExternalRestoreConfiguration)(nil), // 40: atelet.ExternalRestoreConfiguration - (*CheckpointRequest)(nil), // 41: atelet.CheckpointRequest - (*CheckpointResponse)(nil), // 42: atelet.CheckpointResponse - (*UploadPausedCheckpointRequest)(nil), // 43: atelet.UploadPausedCheckpointRequest - (*UploadPausedCheckpointResponse)(nil), // 44: atelet.UploadPausedCheckpointResponse - (*PruneLocalCheckpointsRequest)(nil), // 45: atelet.PruneLocalCheckpointsRequest - (*PruneLocalCheckpointsResponse)(nil), // 46: atelet.PruneLocalCheckpointsResponse - (*RestoreRequest)(nil), // 47: atelet.RestoreRequest - (*RestoreResponse)(nil), // 48: atelet.RestoreResponse - nil, // 49: atelet.ArchAssets.FilesEntry - nil, // 50: atelet.SandboxAssets.AssetsEntry - nil, // 51: atelet.ExternalVolumeSource.VolumeContextEntry + (VolumeAccessMode)(0), // 0: atelet.VolumeAccessMode + (ActorMetadataField)(0), // 1: atelet.ActorMetadataField + (CheckpointType)(0), // 2: atelet.CheckpointType + (SnapshotScope)(0), // 3: atelet.SnapshotScope + (*SetWorkerCapacityRequest)(nil), // 4: atelet.SetWorkerCapacityRequest + (*WorkerResources)(nil), // 5: atelet.WorkerResources + (*Resources)(nil), // 6: atelet.Resources + (*Limits)(nil), // 7: atelet.Limits + (*SetWorkerCapacityResponse)(nil), // 8: atelet.SetWorkerCapacityResponse + (*RequestActorSuspendRequest)(nil), // 9: atelet.RequestActorSuspendRequest + (*RequestActorSuspendResponse)(nil), // 10: atelet.RequestActorSuspendResponse + (*MintActorCertificateRequest)(nil), // 11: atelet.MintActorCertificateRequest + (*MintActorCertificateResponse)(nil), // 12: atelet.MintActorCertificateResponse + (*TerminateRequest)(nil), // 13: atelet.TerminateRequest + (*TerminateResponse)(nil), // 14: atelet.TerminateResponse + (*RunRequest)(nil), // 15: atelet.RunRequest + (*EgressGateway)(nil), // 16: atelet.EgressGateway + (*AssetFile)(nil), // 17: atelet.AssetFile + (*ArchAssets)(nil), // 18: atelet.ArchAssets + (*SandboxAssets)(nil), // 19: atelet.SandboxAssets + (*WorkloadSpec)(nil), // 20: atelet.WorkloadSpec + (*DurableDirVolume)(nil), // 21: atelet.DurableDirVolume + (*ExternalVolumeSource)(nil), // 22: atelet.ExternalVolumeSource + (*ImageVolumeSource)(nil), // 23: atelet.ImageVolumeSource + (*ActorMetadataItem)(nil), // 24: atelet.ActorMetadataItem + (*ActorMetadataDataSource)(nil), // 25: atelet.ActorMetadataDataSource + (*TrustBundleDataSource)(nil), // 26: atelet.TrustBundleDataSource + (*SystemInfoDataSource)(nil), // 27: atelet.SystemInfoDataSource + (*SystemInfoVolume)(nil), // 28: atelet.SystemInfoVolume + (*Volume)(nil), // 29: atelet.Volume + (*VolumeMount)(nil), // 30: atelet.VolumeMount + (*Container)(nil), // 31: atelet.Container + (*SecurityContext)(nil), // 32: atelet.SecurityContext + (*Capabilities)(nil), // 33: atelet.Capabilities + (*ResourceLimits)(nil), // 34: atelet.ResourceLimits + (*EnvEntry)(nil), // 35: atelet.EnvEntry + (*WakeupProbe)(nil), // 36: atelet.WakeupProbe + (*HTTPGetAction)(nil), // 37: atelet.HTTPGetAction + (*RunResponse)(nil), // 38: atelet.RunResponse + (*LocalCheckpointConfiguration)(nil), // 39: atelet.LocalCheckpointConfiguration + (*ExternalCheckpointConfiguration)(nil), // 40: atelet.ExternalCheckpointConfiguration + (*ExternalRestoreConfiguration)(nil), // 41: atelet.ExternalRestoreConfiguration + (*CheckpointRequest)(nil), // 42: atelet.CheckpointRequest + (*CheckpointResponse)(nil), // 43: atelet.CheckpointResponse + (*UploadPausedCheckpointRequest)(nil), // 44: atelet.UploadPausedCheckpointRequest + (*UploadPausedCheckpointResponse)(nil), // 45: atelet.UploadPausedCheckpointResponse + (*PruneLocalCheckpointsRequest)(nil), // 46: atelet.PruneLocalCheckpointsRequest + (*PruneLocalCheckpointsResponse)(nil), // 47: atelet.PruneLocalCheckpointsResponse + (*RestoreRequest)(nil), // 48: atelet.RestoreRequest + (*RestoreResponse)(nil), // 49: atelet.RestoreResponse + nil, // 50: atelet.ArchAssets.FilesEntry + nil, // 51: atelet.SandboxAssets.AssetsEntry + nil, // 52: atelet.ExternalVolumeSource.VolumeContextEntry } var file_atelet_proto_depIdxs = []int32{ - 4, // 0: atelet.SetWorkerCapacityRequest.capacity:type_name -> atelet.WorkerResources - 5, // 1: atelet.WorkerResources.resources:type_name -> atelet.Resources - 6, // 2: atelet.Resources.limits:type_name -> atelet.Limits - 19, // 3: atelet.TerminateRequest.spec:type_name -> atelet.WorkloadSpec - 19, // 4: atelet.RunRequest.spec:type_name -> atelet.WorkloadSpec - 18, // 5: atelet.RunRequest.sandbox_assets:type_name -> atelet.SandboxAssets - 15, // 6: atelet.RunRequest.egress_gateway:type_name -> atelet.EgressGateway - 49, // 7: atelet.ArchAssets.files:type_name -> atelet.ArchAssets.FilesEntry - 50, // 8: atelet.SandboxAssets.assets:type_name -> atelet.SandboxAssets.AssetsEntry - 30, // 9: atelet.WorkloadSpec.containers:type_name -> atelet.Container - 28, // 10: atelet.WorkloadSpec.volumes:type_name -> atelet.Volume - 51, // 11: atelet.ExternalVolumeSource.volume_context:type_name -> atelet.ExternalVolumeSource.VolumeContextEntry - 0, // 12: atelet.ActorMetadataItem.field:type_name -> atelet.ActorMetadataField - 23, // 13: atelet.ActorMetadataDataSource.items:type_name -> atelet.ActorMetadataItem - 24, // 14: atelet.SystemInfoDataSource.actor_metadata:type_name -> atelet.ActorMetadataDataSource - 25, // 15: atelet.SystemInfoDataSource.trust_bundle:type_name -> atelet.TrustBundleDataSource - 26, // 16: atelet.SystemInfoVolume.data_sources:type_name -> atelet.SystemInfoDataSource - 20, // 17: atelet.Volume.durable_dir:type_name -> atelet.DurableDirVolume - 21, // 18: atelet.Volume.external:type_name -> atelet.ExternalVolumeSource - 27, // 19: atelet.Volume.system_info:type_name -> atelet.SystemInfoVolume - 22, // 20: atelet.Volume.image:type_name -> atelet.ImageVolumeSource - 34, // 21: atelet.Container.env:type_name -> atelet.EnvEntry - 35, // 22: atelet.Container.wakeup_probe:type_name -> atelet.WakeupProbe - 29, // 23: atelet.Container.volume_mounts:type_name -> atelet.VolumeMount - 31, // 24: atelet.Container.security_context:type_name -> atelet.SecurityContext - 33, // 25: atelet.Container.resources:type_name -> atelet.ResourceLimits - 32, // 26: atelet.SecurityContext.capabilities:type_name -> atelet.Capabilities - 36, // 27: atelet.WakeupProbe.http_get:type_name -> atelet.HTTPGetAction - 19, // 28: atelet.CheckpointRequest.spec:type_name -> atelet.WorkloadSpec - 1, // 29: atelet.CheckpointRequest.type:type_name -> atelet.CheckpointType - 38, // 30: atelet.CheckpointRequest.local_config:type_name -> atelet.LocalCheckpointConfiguration - 39, // 31: atelet.CheckpointRequest.external_config:type_name -> atelet.ExternalCheckpointConfiguration - 2, // 32: atelet.CheckpointRequest.scope:type_name -> atelet.SnapshotScope - 2, // 33: atelet.UploadPausedCheckpointRequest.desired_scope:type_name -> atelet.SnapshotScope - 19, // 34: atelet.RestoreRequest.spec:type_name -> atelet.WorkloadSpec - 1, // 35: atelet.RestoreRequest.type:type_name -> atelet.CheckpointType - 38, // 36: atelet.RestoreRequest.local_config:type_name -> atelet.LocalCheckpointConfiguration - 40, // 37: atelet.RestoreRequest.external_config:type_name -> atelet.ExternalRestoreConfiguration - 2, // 38: atelet.RestoreRequest.scope:type_name -> atelet.SnapshotScope - 15, // 39: atelet.RestoreRequest.egress_gateway:type_name -> atelet.EgressGateway - 18, // 40: atelet.RestoreRequest.sandbox_assets:type_name -> atelet.SandboxAssets - 16, // 41: atelet.ArchAssets.FilesEntry.value:type_name -> atelet.AssetFile - 17, // 42: atelet.SandboxAssets.AssetsEntry.value:type_name -> atelet.ArchAssets - 10, // 43: atelet.AteomSupport.MintActorCertificate:input_type -> atelet.MintActorCertificateRequest - 3, // 44: atelet.AteomSupport.SetWorkerCapacity:input_type -> atelet.SetWorkerCapacityRequest - 8, // 45: atelet.AteomSupport.RequestActorSuspend:input_type -> atelet.RequestActorSuspendRequest - 14, // 46: atelet.AteomHerder.Run:input_type -> atelet.RunRequest - 41, // 47: atelet.AteomHerder.Checkpoint:input_type -> atelet.CheckpointRequest - 47, // 48: atelet.AteomHerder.Restore:input_type -> atelet.RestoreRequest - 43, // 49: atelet.AteomHerder.UploadPausedCheckpoint:input_type -> atelet.UploadPausedCheckpointRequest - 45, // 50: atelet.AteomHerder.PruneLocalCheckpoints:input_type -> atelet.PruneLocalCheckpointsRequest - 12, // 51: atelet.AteomHerder.Terminate:input_type -> atelet.TerminateRequest - 11, // 52: atelet.AteomSupport.MintActorCertificate:output_type -> atelet.MintActorCertificateResponse - 7, // 53: atelet.AteomSupport.SetWorkerCapacity:output_type -> atelet.SetWorkerCapacityResponse - 9, // 54: atelet.AteomSupport.RequestActorSuspend:output_type -> atelet.RequestActorSuspendResponse - 37, // 55: atelet.AteomHerder.Run:output_type -> atelet.RunResponse - 42, // 56: atelet.AteomHerder.Checkpoint:output_type -> atelet.CheckpointResponse - 48, // 57: atelet.AteomHerder.Restore:output_type -> atelet.RestoreResponse - 44, // 58: atelet.AteomHerder.UploadPausedCheckpoint:output_type -> atelet.UploadPausedCheckpointResponse - 46, // 59: atelet.AteomHerder.PruneLocalCheckpoints:output_type -> atelet.PruneLocalCheckpointsResponse - 13, // 60: atelet.AteomHerder.Terminate:output_type -> atelet.TerminateResponse - 52, // [52:61] is the sub-list for method output_type - 43, // [43:52] is the sub-list for method input_type - 43, // [43:43] is the sub-list for extension type_name - 43, // [43:43] is the sub-list for extension extendee - 0, // [0:43] is the sub-list for field type_name + 5, // 0: atelet.SetWorkerCapacityRequest.capacity:type_name -> atelet.WorkerResources + 6, // 1: atelet.WorkerResources.resources:type_name -> atelet.Resources + 7, // 2: atelet.Resources.limits:type_name -> atelet.Limits + 20, // 3: atelet.TerminateRequest.spec:type_name -> atelet.WorkloadSpec + 20, // 4: atelet.RunRequest.spec:type_name -> atelet.WorkloadSpec + 19, // 5: atelet.RunRequest.sandbox_assets:type_name -> atelet.SandboxAssets + 16, // 6: atelet.RunRequest.egress_gateway:type_name -> atelet.EgressGateway + 50, // 7: atelet.ArchAssets.files:type_name -> atelet.ArchAssets.FilesEntry + 51, // 8: atelet.SandboxAssets.assets:type_name -> atelet.SandboxAssets.AssetsEntry + 31, // 9: atelet.WorkloadSpec.containers:type_name -> atelet.Container + 29, // 10: atelet.WorkloadSpec.volumes:type_name -> atelet.Volume + 52, // 11: atelet.ExternalVolumeSource.volume_context:type_name -> atelet.ExternalVolumeSource.VolumeContextEntry + 0, // 12: atelet.ExternalVolumeSource.access_mode:type_name -> atelet.VolumeAccessMode + 1, // 13: atelet.ActorMetadataItem.field:type_name -> atelet.ActorMetadataField + 24, // 14: atelet.ActorMetadataDataSource.items:type_name -> atelet.ActorMetadataItem + 25, // 15: atelet.SystemInfoDataSource.actor_metadata:type_name -> atelet.ActorMetadataDataSource + 26, // 16: atelet.SystemInfoDataSource.trust_bundle:type_name -> atelet.TrustBundleDataSource + 27, // 17: atelet.SystemInfoVolume.data_sources:type_name -> atelet.SystemInfoDataSource + 21, // 18: atelet.Volume.durable_dir:type_name -> atelet.DurableDirVolume + 22, // 19: atelet.Volume.external:type_name -> atelet.ExternalVolumeSource + 28, // 20: atelet.Volume.system_info:type_name -> atelet.SystemInfoVolume + 23, // 21: atelet.Volume.image:type_name -> atelet.ImageVolumeSource + 35, // 22: atelet.Container.env:type_name -> atelet.EnvEntry + 36, // 23: atelet.Container.wakeup_probe:type_name -> atelet.WakeupProbe + 30, // 24: atelet.Container.volume_mounts:type_name -> atelet.VolumeMount + 32, // 25: atelet.Container.security_context:type_name -> atelet.SecurityContext + 34, // 26: atelet.Container.resources:type_name -> atelet.ResourceLimits + 33, // 27: atelet.SecurityContext.capabilities:type_name -> atelet.Capabilities + 37, // 28: atelet.WakeupProbe.http_get:type_name -> atelet.HTTPGetAction + 20, // 29: atelet.CheckpointRequest.spec:type_name -> atelet.WorkloadSpec + 2, // 30: atelet.CheckpointRequest.type:type_name -> atelet.CheckpointType + 39, // 31: atelet.CheckpointRequest.local_config:type_name -> atelet.LocalCheckpointConfiguration + 40, // 32: atelet.CheckpointRequest.external_config:type_name -> atelet.ExternalCheckpointConfiguration + 3, // 33: atelet.CheckpointRequest.scope:type_name -> atelet.SnapshotScope + 3, // 34: atelet.UploadPausedCheckpointRequest.desired_scope:type_name -> atelet.SnapshotScope + 20, // 35: atelet.RestoreRequest.spec:type_name -> atelet.WorkloadSpec + 2, // 36: atelet.RestoreRequest.type:type_name -> atelet.CheckpointType + 39, // 37: atelet.RestoreRequest.local_config:type_name -> atelet.LocalCheckpointConfiguration + 41, // 38: atelet.RestoreRequest.external_config:type_name -> atelet.ExternalRestoreConfiguration + 3, // 39: atelet.RestoreRequest.scope:type_name -> atelet.SnapshotScope + 16, // 40: atelet.RestoreRequest.egress_gateway:type_name -> atelet.EgressGateway + 19, // 41: atelet.RestoreRequest.sandbox_assets:type_name -> atelet.SandboxAssets + 17, // 42: atelet.ArchAssets.FilesEntry.value:type_name -> atelet.AssetFile + 18, // 43: atelet.SandboxAssets.AssetsEntry.value:type_name -> atelet.ArchAssets + 11, // 44: atelet.AteomSupport.MintActorCertificate:input_type -> atelet.MintActorCertificateRequest + 4, // 45: atelet.AteomSupport.SetWorkerCapacity:input_type -> atelet.SetWorkerCapacityRequest + 9, // 46: atelet.AteomSupport.RequestActorSuspend:input_type -> atelet.RequestActorSuspendRequest + 15, // 47: atelet.AteomHerder.Run:input_type -> atelet.RunRequest + 42, // 48: atelet.AteomHerder.Checkpoint:input_type -> atelet.CheckpointRequest + 48, // 49: atelet.AteomHerder.Restore:input_type -> atelet.RestoreRequest + 44, // 50: atelet.AteomHerder.UploadPausedCheckpoint:input_type -> atelet.UploadPausedCheckpointRequest + 46, // 51: atelet.AteomHerder.PruneLocalCheckpoints:input_type -> atelet.PruneLocalCheckpointsRequest + 13, // 52: atelet.AteomHerder.Terminate:input_type -> atelet.TerminateRequest + 12, // 53: atelet.AteomSupport.MintActorCertificate:output_type -> atelet.MintActorCertificateResponse + 8, // 54: atelet.AteomSupport.SetWorkerCapacity:output_type -> atelet.SetWorkerCapacityResponse + 10, // 55: atelet.AteomSupport.RequestActorSuspend:output_type -> atelet.RequestActorSuspendResponse + 38, // 56: atelet.AteomHerder.Run:output_type -> atelet.RunResponse + 43, // 57: atelet.AteomHerder.Checkpoint:output_type -> atelet.CheckpointResponse + 49, // 58: atelet.AteomHerder.Restore:output_type -> atelet.RestoreResponse + 45, // 59: atelet.AteomHerder.UploadPausedCheckpoint:output_type -> atelet.UploadPausedCheckpointResponse + 47, // 60: atelet.AteomHerder.PruneLocalCheckpoints:output_type -> atelet.PruneLocalCheckpointsResponse + 14, // 61: atelet.AteomHerder.Terminate:output_type -> atelet.TerminateResponse + 53, // [53:62] is the sub-list for method output_type + 44, // [44:53] is the sub-list for method input_type + 44, // [44:44] is the sub-list for extension type_name + 44, // [44:44] is the sub-list for extension extendee + 0, // [0:44] is the sub-list for field type_name } func init() { file_atelet_proto_init() } @@ -3509,7 +3601,7 @@ func file_atelet_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_atelet_proto_rawDesc), len(file_atelet_proto_rawDesc)), - NumEnums: 3, + NumEnums: 4, NumMessages: 49, NumExtensions: 0, NumServices: 2, diff --git a/internal/proto/ateletpb/atelet.proto b/internal/proto/ateletpb/atelet.proto index d3559bad8b..1b271de846 100644 --- a/internal/proto/ateletpb/atelet.proto +++ b/internal/proto/ateletpb/atelet.proto @@ -282,6 +282,16 @@ message ExternalVolumeSource { string storage_volume_id = 1; string volume_type = 2; map volume_context = 3; + // access_mode is how the volume is published; unset is READ_WRITE_ONCE. + VolumeAccessMode access_mode = 4; +} + +// VolumeAccessMode mirrors ateapi.VolumeAccessMode. +enum VolumeAccessMode { + VOLUME_ACCESS_MODE_UNSPECIFIED = 0; + VOLUME_ACCESS_MODE_READ_WRITE_ONCE = 1; + VOLUME_ACCESS_MODE_READ_ONLY_MANY = 2; + VOLUME_ACCESS_MODE_READ_WRITE_MANY = 3; } message ImageVolumeSource { @@ -345,6 +355,11 @@ message Volume { message VolumeMount { string name = 1; string mount_path = 2; + // sub_path is the directory of an external volume to mount, relative to + // its root; empty mounts the root. + string sub_path = 3; + // read_only mounts an external volume read-only. + bool read_only = 4; } message Container { diff --git a/internal/proto/ateompb/ateom.pb.go b/internal/proto/ateompb/ateom.pb.go index 5ed1349db9..cfaab00801 100644 --- a/internal/proto/ateompb/ateom.pb.go +++ b/internal/proto/ateompb/ateom.pb.go @@ -769,9 +769,15 @@ func (x *Container) GetImageVolumeMounts() []*ImageVolumeMount { // VolumeMount is one volume mounted into a container. type VolumeMount struct { - state protoimpl.MessageState `protogen:"open.v1"` - VolumeName string `protobuf:"bytes,1,opt,name=volume_name,json=volumeName,proto3" json:"volume_name,omitempty"` - MountPath string `protobuf:"bytes,2,opt,name=mount_path,json=mountPath,proto3" json:"mount_path,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + VolumeName string `protobuf:"bytes,1,opt,name=volume_name,json=volumeName,proto3" json:"volume_name,omitempty"` + MountPath string `protobuf:"bytes,2,opt,name=mount_path,json=mountPath,proto3" json:"mount_path,omitempty"` + // sub_path is the directory of the volume to mount, relative to its root; + // empty mounts the root. ateom binds it beside the volume's mount point + // before the sandbox starts (internal/volumebind). + SubPath string `protobuf:"bytes,3,opt,name=sub_path,json=subPath,proto3" json:"sub_path,omitempty"` + // read_only mounts it read-only. + ReadOnly bool `protobuf:"varint,4,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -820,6 +826,20 @@ func (x *VolumeMount) GetMountPath() string { return "" } +func (x *VolumeMount) GetSubPath() string { + if x != nil { + return x.SubPath + } + return "" +} + +func (x *VolumeMount) GetReadOnly() bool { + if x != nil { + return x.ReadOnly + } + return false +} + // DurableDirVolumeMount is one durable-dir volume mounted into a container. type DurableDirVolumeMount struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -1949,12 +1969,14 @@ const file_ateom_proto_rawDesc = "" + "\x19durable_dir_volume_mounts\x18\x03 \x03(\v2\x1c.ateom.DurableDirVolumeMountR\x16durableDirVolumeMounts\x12>\n" + "\x11csi_volume_mounts\x18\x04 \x03(\v2\x12.ateom.VolumeMountR\x0fcsiVolumeMounts\x12W\n" + "\x19system_info_volume_mounts\x18\x05 \x03(\v2\x1c.ateom.SystemInfoVolumeMountR\x16systemInfoVolumeMounts\x12G\n" + - "\x13image_volume_mounts\x18\x06 \x03(\v2\x17.ateom.ImageVolumeMountR\x11imageVolumeMounts\"M\n" + + "\x13image_volume_mounts\x18\x06 \x03(\v2\x17.ateom.ImageVolumeMountR\x11imageVolumeMounts\"\x85\x01\n" + "\vVolumeMount\x12\x1f\n" + "\vvolume_name\x18\x01 \x01(\tR\n" + "volumeName\x12\x1d\n" + "\n" + - "mount_path\x18\x02 \x01(\tR\tmountPath\"W\n" + + "mount_path\x18\x02 \x01(\tR\tmountPath\x12\x19\n" + + "\bsub_path\x18\x03 \x01(\tR\asubPath\x12\x1b\n" + + "\tread_only\x18\x04 \x01(\bR\breadOnly\"W\n" + "\x15DurableDirVolumeMount\x12\x1f\n" + "\vvolume_name\x18\x01 \x01(\tR\n" + "volumeName\x12\x1d\n" + diff --git a/internal/proto/ateompb/ateom.proto b/internal/proto/ateompb/ateom.proto index 7f234c0be5..5b5a18b180 100644 --- a/internal/proto/ateompb/ateom.proto +++ b/internal/proto/ateompb/ateom.proto @@ -206,6 +206,12 @@ message Container { message VolumeMount { string volume_name = 1; string mount_path = 2; + // sub_path is the directory of the volume to mount, relative to its root; + // empty mounts the root. ateom binds it beside the volume's mount point + // before the sandbox starts (internal/volumebind). + string sub_path = 3; + // read_only mounts it read-only. + bool read_only = 4; } // DurableDirVolumeMount is one durable-dir volume mounted into a container. diff --git a/internal/resources/validate.go b/internal/resources/validate.go index f39e6dbdf9..d9cdace12d 100644 --- a/internal/resources/validate.go +++ b/internal/resources/validate.go @@ -39,7 +39,10 @@ func ToGRPCStatusError(errs field.ErrorList) error { } // DeepEqual compares two values of any type, using proto.Equal if both are -// proto messages, and reflect.DeepEqual otherwise. Declarative validation's +// proto messages or slices of them (a repeated message field), and +// reflect.DeepEqual otherwise. reflect.DeepEqual must not see a message: it +// compares the message's internal state, such as the size cache a marshal +// fills, so a message and its clone would differ. Declarative validation's // generated code reaches it through each generating package's ateDeepEqual. func DeepEqual[T any](a, b T) bool { asProto := func(x any) proto.Message { @@ -53,9 +56,24 @@ func DeepEqual[T any](a, b T) bool { if pa, pb := asProto(a), asProto(b); pa != nil && pb != nil { return proto.Equal(pa, pb) } + if va, vb := reflect.ValueOf(a), reflect.ValueOf(b); va.Kind() == reflect.Slice && vb.Kind() == reflect.Slice && + va.Type().Elem().Implements(protoMessageType) { + // A nil and an empty repeated field are the same field value. + if va.Len() != vb.Len() { + return false + } + for i := range va.Len() { + if !proto.Equal(va.Index(i).Interface().(proto.Message), vb.Index(i).Interface().(proto.Message)) { + return false + } + } + return true + } return reflect.DeepEqual(a, b) } +var protoMessageType = reflect.TypeFor[proto.Message]() + // ValidateResourceName checks that a string conforms to Agent Substrate's // rules for a resource name, which is a subset of the rules for an RFC-1123 // DNS label. This does not check for zero-length strings, which callers may diff --git a/internal/resources/validate_test.go b/internal/resources/validate_test.go index 01f9f1c0bf..1b98650020 100644 --- a/internal/resources/validate_test.go +++ b/internal/resources/validate_test.go @@ -23,6 +23,7 @@ import ( "github.com/agent-substrate/substrate/pkg/proto/ateapipb" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" "k8s.io/apimachinery/pkg/util/validation/field" ) @@ -42,6 +43,9 @@ func TestDeepEqual(t *testing.T) { a := &ateapipb.ObjectRef{Atespace: "a", Name: "x"} b := &ateapipb.ObjectRef{Atespace: "a", Name: "x"} _ = a.String() // populates a's internal state, not b's + // A marshal fills the size cache of every element of a repeated field. + sized := []*ateapipb.ObjectRef{{Atespace: "a", Name: "x"}} + _ = proto.Size(sized[0]) tests := []struct { name string @@ -53,6 +57,10 @@ func TestDeepEqual(t *testing.T) { {name: "nil protos", got: DeepEqual[*ateapipb.ObjectRef](nil, nil), want: true}, {name: "equal non-protos", got: DeepEqual([]string{"a"}, []string{"a"}), want: true}, {name: "different non-protos", got: DeepEqual(1, 2), want: false}, + {name: "equal repeated protos", got: DeepEqual(sized, []*ateapipb.ObjectRef{{Atespace: "a", Name: "x"}}), want: true}, + {name: "different repeated protos", got: DeepEqual(sized, []*ateapipb.ObjectRef{{Atespace: "a", Name: "y"}}), want: false}, + {name: "repeated protos of different lengths", got: DeepEqual(sized, nil), want: false}, + {name: "nil and empty repeated protos", got: DeepEqual([]*ateapipb.ObjectRef{}, nil), want: true}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/volume/csi/plugin.go b/internal/volume/csi/plugin.go index d1cede7777..149126ec13 100644 --- a/internal/volume/csi/plugin.go +++ b/internal/volume/csi/plugin.go @@ -16,8 +16,10 @@ package csi import ( "context" + "crypto/sha256" "crypto/tls" "crypto/x509" + "encoding/hex" "fmt" "log/slog" "os" @@ -122,11 +124,11 @@ func (p *Plugin) DeleteVolume(ctx context.Context, volumeID string) error { } // AttachVolume maps to CSI Controller ControllerPublishVolume. -func (p *Plugin) AttachVolume(ctx context.Context, volumeID string, node string) error { +func (p *Plugin) AttachVolume(ctx context.Context, volumeID string, node string, mode volume.AccessMode) error { req := &csi.ControllerPublishVolumeRequest{ VolumeId: volumeID, NodeId: node, - VolumeCapability: getStandardCapabilities()[0], // Use primary capability + VolumeCapability: mountCapability(mode), Readonly: false, } @@ -173,9 +175,9 @@ func (p *Plugin) DetachVolume(ctx context.Context, volumeID string, node string) // MountVolume maps to CSI Node NodePublishVolume. // It also handles NodeStageVolume staging if required by the driver. -func (p *Plugin) MountVolume(ctx context.Context, volumeID string, targetPath string, volumeContext map[string]string) error { +func (p *Plugin) MountVolume(ctx context.Context, volumeID string, targetPath string, volumeContext map[string]string, mode volume.AccessMode) error { // 1. Stage the volume - stagingPath := filepath.Join(p.stagingDirPrefix, volumeID) + stagingPath := p.stagingPath(volumeID, targetPath, mode) if err := os.MkdirAll(stagingPath, 0750); err != nil { return fmt.Errorf("failed to create staging directory %q: %w", stagingPath, err) } @@ -183,7 +185,7 @@ func (p *Plugin) MountVolume(ctx context.Context, volumeID string, targetPath st stageReq := &csi.NodeStageVolumeRequest{ VolumeId: volumeID, StagingTargetPath: stagingPath, - VolumeCapability: getStandardCapabilities()[0], // Use primary capability + VolumeCapability: mountCapability(mode), VolumeContext: volumeContext, } @@ -201,8 +203,8 @@ func (p *Plugin) MountVolume(ctx context.Context, volumeID string, targetPath st req := &csi.NodePublishVolumeRequest{ VolumeId: volumeID, TargetPath: targetPath, - VolumeCapability: getStandardCapabilities()[0], - Readonly: false, + VolumeCapability: mountCapability(mode), + Readonly: mode == volume.ReadOnlyMany, VolumeContext: volumeContext, } if stagingPath != "" { @@ -218,7 +220,7 @@ func (p *Plugin) MountVolume(ctx context.Context, volumeID string, targetPath st // UnmountVolume maps to CSI Node NodeUnpublishVolume. // It also handles NodeUnstageVolume if staging was used. -func (p *Plugin) UnmountVolume(ctx context.Context, volumeID string, targetPath string) error { +func (p *Plugin) UnmountVolume(ctx context.Context, volumeID string, targetPath string, mode volume.AccessMode) error { // 1. Unpublish (Unmount) the volume req := &csi.NodeUnpublishVolumeRequest{ VolumeId: volumeID, @@ -231,7 +233,7 @@ func (p *Plugin) UnmountVolume(ctx context.Context, volumeID string, targetPath } // 2. Unstage the volume - stagingPath := filepath.Join(p.stagingDirPrefix, volumeID) + stagingPath := p.stagingPath(volumeID, targetPath, mode) unstageReq := &csi.NodeUnstageVolumeRequest{ VolumeId: volumeID, StagingTargetPath: stagingPath, @@ -250,10 +252,37 @@ func (p *Plugin) UnmountVolume(ctx context.Context, volumeID string, targetPath if err := os.Remove(stagingPath); err != nil && !os.IsNotExist(err) { slog.WarnContext(ctx, "failed to remove staging directory", slog.String("path", stagingPath), slog.Any("error", err)) } + if mode.MultiNode() { + // The volume's directory of per-target stagings goes with its last one. + _ = os.Remove(filepath.Dir(stagingPath)) + } return nil } +// stagingPath is where a volume is staged on the node. A volume of a +// multi-node mode is staged once per target, so that one actor unmounting it +// never unstages it under another actor on the same node. +func (p *Plugin) stagingPath(volumeID, targetPath string, mode volume.AccessMode) string { + if !mode.MultiNode() { + return filepath.Join(p.stagingDirPrefix, volumeID) + } + sum := sha256.Sum256([]byte(targetPath)) + return filepath.Join(p.stagingDirPrefix, volumeID, hex.EncodeToString(sum[:8])) +} + +// mountCapability is the mount capability of an access mode. +func mountCapability(mode volume.AccessMode) *csi.VolumeCapability { + capability := getStandardCapabilities()[0] + switch mode { + case volume.ReadOnlyMany: + capability.AccessMode.Mode = csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY + case volume.ReadWriteMany: + capability.AccessMode.Mode = csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER + } + return capability +} + // Helper to provide standard capabilities for general volume operations. // TODO: Support and expose different volume access modes (e.g. ReadWriteMany, ReadOnlyMany) // instead of hardcoding SingleNodeWriter. diff --git a/internal/volume/csi/plugin_test.go b/internal/volume/csi/plugin_test.go index 79b5a75d9d..055dc2b069 100644 --- a/internal/volume/csi/plugin_test.go +++ b/internal/volume/csi/plugin_test.go @@ -21,6 +21,7 @@ import ( "path/filepath" "testing" + "github.com/agent-substrate/substrate/internal/volume" "github.com/container-storage-interface/spec/lib/go/csi" "google.golang.org/grpc" "google.golang.org/grpc/codes" @@ -228,7 +229,7 @@ func TestPlugin_AttachVolume(t *testing.T) { plugin := NewPlugin(client) ctx := context.Background() - err = plugin.AttachVolume(ctx, "test-vol", "node-1") + err = plugin.AttachVolume(ctx, "test-vol", "node-1", volume.ReadWriteOnce) if err != nil { t.Fatalf("AttachVolume failed: %v", err) } @@ -237,7 +238,7 @@ func TestPlugin_AttachVolume(t *testing.T) { driver.controllerPublishVolumeFunc = func(ctx context.Context, req *csi.ControllerPublishVolumeRequest) (*csi.ControllerPublishVolumeResponse, error) { return nil, status.Error(codes.Unimplemented, "unimplemented") } - err = plugin.AttachVolume(ctx, "test-vol", "node-1") + err = plugin.AttachVolume(ctx, "test-vol", "node-1", volume.ReadWriteOnce) if err != nil { t.Errorf("AttachVolume should have ignored Unimplemented error, got: %v", err) } @@ -294,7 +295,7 @@ func TestPlugin_MountVolume(t *testing.T) { targetPath := filepath.Join(tmpDir, "target") ctx := context.Background() - err = plugin.MountVolume(ctx, "test-vol", targetPath, nil) + err = plugin.MountVolume(ctx, "test-vol", targetPath, nil, volume.ReadWriteOnce) if err != nil { t.Fatalf("MountVolume failed: %v", err) } @@ -313,7 +314,7 @@ func TestPlugin_MountVolume(t *testing.T) { os.RemoveAll(tmpDir) os.MkdirAll(plugin.stagingDirPrefix, 0750) - err = plugin.MountVolume(ctx, "test-vol-2", targetPath, nil) + err = plugin.MountVolume(ctx, "test-vol-2", targetPath, nil, volume.ReadWriteOnce) if err != nil { t.Errorf("MountVolume should have succeeded when NodeStageVolume is unimplemented, got: %v", err) } @@ -347,7 +348,7 @@ func TestPlugin_UnmountVolume(t *testing.T) { } ctx := context.Background() - err = plugin.UnmountVolume(ctx, "test-vol", targetPath) + err = plugin.UnmountVolume(ctx, "test-vol", targetPath, volume.ReadWriteOnce) if err != nil { t.Fatalf("UnmountVolume failed: %v", err) } @@ -365,7 +366,7 @@ func TestPlugin_UnmountVolume(t *testing.T) { if err := os.MkdirAll(stagingPath, 0750); err != nil { t.Fatalf("failed to create staging path: %v", err) } - err = plugin.UnmountVolume(ctx, "test-vol", targetPath) + err = plugin.UnmountVolume(ctx, "test-vol", targetPath, volume.ReadWriteOnce) if err != nil { t.Errorf("UnmountVolume should have succeeded when NodeUnstageVolume is unimplemented, got: %v", err) } @@ -408,3 +409,69 @@ func TestClient_Identity(t *testing.T) { t.Fatalf("Probe failed: %v", err) } } + +func TestPlugin_MountVolumeMultiNode(t *testing.T) { + var staged, unstaged []string + var published []*csi.NodePublishVolumeRequest + driver := &mockCSIDriver{ + nodeStageVolumeFunc: func(_ context.Context, req *csi.NodeStageVolumeRequest) (*csi.NodeStageVolumeResponse, error) { + staged = append(staged, req.GetStagingTargetPath()) + return &csi.NodeStageVolumeResponse{}, nil + }, + nodePublishVolumeFunc: func(_ context.Context, req *csi.NodePublishVolumeRequest) (*csi.NodePublishVolumeResponse, error) { + published = append(published, req) + return &csi.NodePublishVolumeResponse{}, nil + }, + nodeUnstageVolumeFunc: func(_ context.Context, req *csi.NodeUnstageVolumeRequest) (*csi.NodeUnstageVolumeResponse, error) { + unstaged = append(unstaged, req.GetStagingTargetPath()) + return &csi.NodeUnstageVolumeResponse{}, nil + }, + } + endpoint, cleanup := startMockCSIDriver(t, driver) + defer cleanup() + client, err := NewCSIClient(endpoint, nil) + if err != nil { + t.Fatalf("failed to create CSI client: %v", err) + } + defer client.Close() + plugin := NewPlugin(client) + tmpDir := t.TempDir() + plugin.stagingDirPrefix = filepath.Join(tmpDir, "staging") + ctx := context.Background() + + // Two actors on one node mount the same read-write-many volume. + targetA, targetB := filepath.Join(tmpDir, "a"), filepath.Join(tmpDir, "b") + for _, target := range []string{targetA, targetB} { + if err := plugin.MountVolume(ctx, "shared", target, nil, volume.ReadWriteMany); err != nil { + t.Fatalf("MountVolume %s: %v", target, err) + } + } + if len(staged) != 2 || staged[0] == staged[1] { + t.Fatalf("staging paths = %v, want one per target", staged) + } + for _, req := range published { + if got := req.GetVolumeCapability().GetAccessMode().GetMode(); got != csi.VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER { + t.Errorf("publish access mode = %v, want MULTI_NODE_MULTI_WRITER", got) + } + if req.GetReadonly() { + t.Errorf("read-write-many volume published read-only") + } + } + + // One actor's unmount unstages only its own staging. + if err := plugin.UnmountVolume(ctx, "shared", targetA, volume.ReadWriteMany); err != nil { + t.Fatalf("UnmountVolume: %v", err) + } + if len(unstaged) != 1 || unstaged[0] != staged[0] { + t.Errorf("unstaged = %v, want only %q", unstaged, staged[0]) + } + + // A read-only-many volume is published read-only. + published = nil + if err := plugin.MountVolume(ctx, "mirrors", targetA, nil, volume.ReadOnlyMany); err != nil { + t.Fatalf("MountVolume: %v", err) + } + if req := published[0]; !req.GetReadonly() || req.GetVolumeCapability().GetAccessMode().GetMode() != csi.VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY { + t.Errorf("read-only-many publish = %v, want read-only MULTI_NODE_READER_ONLY", req) + } +} diff --git a/internal/volume/mock.go b/internal/volume/mock.go index e6c9c99589..32c2a2b524 100644 --- a/internal/volume/mock.go +++ b/internal/volume/mock.go @@ -75,7 +75,7 @@ func (p *MockVolumePlugin) DeleteVolume(ctx context.Context, volumeID string) er } // AttachVolume simulates volume attachment to a node. -func (p *MockVolumePlugin) AttachVolume(ctx context.Context, volumeID string, node string) error { +func (p *MockVolumePlugin) AttachVolume(ctx context.Context, volumeID string, node string, _ AccessMode) error { slog.InfoContext(ctx, "MockVolumePlugin.AttachVolume", slog.String("volumeID", volumeID), slog.String("node", node)) return nil } @@ -87,7 +87,7 @@ func (p *MockVolumePlugin) DetachVolume(ctx context.Context, volumeID string, no } // MountVolume simulates mounting volume on the host. -func (p *MockVolumePlugin) MountVolume(ctx context.Context, volumeID string, targetPath string, volumeContext map[string]string) error { +func (p *MockVolumePlugin) MountVolume(ctx context.Context, volumeID string, targetPath string, volumeContext map[string]string, _ AccessMode) error { slog.InfoContext(ctx, "MockVolumePlugin.MountVolume", slog.String("volumeID", volumeID), slog.String("targetPath", targetPath)) volumeDir := filepath.Join(mockVolumeDirectories, volumeID) @@ -111,7 +111,7 @@ func (p *MockVolumePlugin) MountVolume(ctx context.Context, volumeID string, tar } // UnmountVolume simulates unmounting volume from the host. -func (p *MockVolumePlugin) UnmountVolume(ctx context.Context, volumeID string, targetPath string) error { +func (p *MockVolumePlugin) UnmountVolume(ctx context.Context, volumeID string, targetPath string, _ AccessMode) error { slog.InfoContext(ctx, "MockVolumePlugin.UnmountVolume", slog.String("volumeID", volumeID), slog.String("targetPath", targetPath)) if err := os.Remove(targetPath); err != nil && !os.IsNotExist(err) { diff --git a/internal/volume/plugin.go b/internal/volume/plugin.go index ee54799c2b..7547fcbcf1 100644 --- a/internal/volume/plugin.go +++ b/internal/volume/plugin.go @@ -18,17 +18,33 @@ import ( "context" ) +// AccessMode is how a volume is attached and mounted across nodes. +type AccessMode int + +const ( + // ReadWriteOnce is read-write on a single node. + ReadWriteOnce AccessMode = iota + // ReadOnlyMany is read-only on many nodes. + ReadOnlyMany + // ReadWriteMany is read-write on many nodes. + ReadWriteMany +) + +// MultiNode reports whether a volume of the mode may be in use by several +// actors at once, on one node or many. +func (m AccessMode) MultiNode() bool { return m != ReadWriteOnce } + // VolumePluginControlPlane abstracts storage operations performed on the control plane. type VolumePluginControlPlane interface { DriverName(ctx context.Context) (string, error) CreateVolume(ctx context.Context, name string, capacity string, driverName string, parameters map[string]string) (volumeID string, volumeContext map[string]string, err error) DeleteVolume(ctx context.Context, volumeID string) error - AttachVolume(ctx context.Context, volumeID string, node string) error + AttachVolume(ctx context.Context, volumeID string, node string, mode AccessMode) error DetachVolume(ctx context.Context, volumeID string, node string) error } // VolumePluginWorkerPlane abstracts storage operations performed on worker nodes. type VolumePluginWorkerPlane interface { - MountVolume(ctx context.Context, volumeID string, targetPath string, volumeContext map[string]string) error - UnmountVolume(ctx context.Context, volumeID string, targetPath string) error + MountVolume(ctx context.Context, volumeID string, targetPath string, volumeContext map[string]string, mode AccessMode) error + UnmountVolume(ctx context.Context, volumeID string, targetPath string, mode AccessMode) error } diff --git a/internal/volumebind/volumebind.go b/internal/volumebind/volumebind.go new file mode 100644 index 0000000000..5cba2a6cd8 --- /dev/null +++ b/internal/volumebind/volumebind.go @@ -0,0 +1,159 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package volumebind binds directories of an actor's mounted external +// volumes beside their mount points, read-only where asked, for the mounts +// that name a sub-path or are read-only. ateom runs it: it sees the volumes +// the CSI node plugin published on the host and may mount, which atelet may +// not. +package volumebind + +import ( + "crypto/sha256" + "encoding/hex" + "errors" + "fmt" + "os" + "path/filepath" + + "github.com/agent-substrate/substrate/internal/proto/ateompb" + "golang.org/x/sys/unix" +) + +// MountDir is the directory under an actor's volumes directory that a mount +// of the external volume name binds from: the volume's own mount point, or, +// for a mount of a sub-path or a read-only mount, a bind of its own beside +// it. A volume name is a DNS label, so the suffix never names a volume. +func MountDir(name, subPath string, readOnly bool) string { + if subPath == "" && !readOnly { + return name + } + sum := sha256.Sum256(fmt.Appendf(nil, "%s\x00%t", subPath, readOnly)) + return name + "." + hex.EncodeToString(sum[:6]) +} + +// boundMounts returns the containers' CSI volume mounts that bind a +// directory of their own (MountDir), once per directory. +func boundMounts(containers []*ateompb.Container) []*ateompb.VolumeMount { + var out []*ateompb.VolumeMount + seen := map[string]bool{} + for _, ctr := range containers { + for _, vm := range ctr.GetCsiVolumeMounts() { + dir := MountDir(vm.GetVolumeName(), vm.GetSubPath(), vm.GetReadOnly()) + if dir == vm.GetVolumeName() || seen[dir] { + continue + } + seen[dir] = true + out = append(out, vm) + } + } + return out +} + +// Prepare binds every directory the containers' mounts bind from (MountDir) +// under volumesDir, replacing a bind left by an earlier attempt. It runs +// before the sandbox starts. +func Prepare(volumesDir string, containers []*ateompb.Container) error { + for _, vm := range boundMounts(containers) { + root := filepath.Join(volumesDir, vm.GetVolumeName()) + target := filepath.Join(volumesDir, MountDir(vm.GetVolumeName(), vm.GetSubPath(), vm.GetReadOnly())) + if err := bindVolumeDir(root, vm.GetSubPath(), target, vm.GetReadOnly()); err != nil { + return fmt.Errorf("volume %q: %w", vm.GetVolumeName(), err) + } + } + return nil +} + +// Release unmounts the binds of Prepare. It runs once the sandbox has +// stopped, before the volumes themselves are unmounted. +func Release(volumesDir string, containers []*ateompb.Container) error { + var errs []error + for _, vm := range boundMounts(containers) { + if err := unbindVolumeDir(filepath.Join(volumesDir, MountDir(vm.GetVolumeName(), vm.GetSubPath(), vm.GetReadOnly()))); err != nil { + errs = append(errs, fmt.Errorf("volume %q: %w", vm.GetVolumeName(), err)) + } + } + return errors.Join(errs...) +} + +// openVolumeDir opens the directory subPath of the volume mounted at root +// (root itself when subPath is empty) as an O_PATH descriptor. The path is +// resolved beneath root without following any symbolic link or crossing a +// mount: other actors write the volume, so a link they planted must not turn +// a mount into one of a directory outside it. +func openVolumeDir(root, subPath string) (int, error) { + if subPath == "" { + subPath = "." + } + rootFd, err := unix.Open(root, unix.O_PATH|unix.O_DIRECTORY|unix.O_CLOEXEC, 0) + if err != nil { + return -1, fmt.Errorf("opening volume root %q: %w", root, err) + } + defer unix.Close(rootFd) + fd, err := unix.Openat2(rootFd, subPath, &unix.OpenHow{ + Flags: unix.O_PATH | unix.O_DIRECTORY | unix.O_CLOEXEC, + Resolve: unix.RESOLVE_BENEATH | unix.RESOLVE_NO_SYMLINKS | unix.RESOLVE_NO_MAGICLINKS | unix.RESOLVE_NO_XDEV, + }) + switch { + case errors.Is(err, unix.ENOENT): + return -1, fmt.Errorf("sub_path %q does not exist on the volume", subPath) + case errors.Is(err, unix.ELOOP): + return -1, fmt.Errorf("sub_path %q crosses a symbolic link on the volume", subPath) + case errors.Is(err, unix.ENOTDIR): + return -1, fmt.Errorf("sub_path %q is not a directory on the volume", subPath) + case err != nil: + return -1, fmt.Errorf("opening sub_path %q of the volume: %w", subPath, err) + } + return fd, nil +} + +// bindVolumeDir bind-mounts the directory subPath of the volume mounted at +// root onto target, read-only when readOnly. A bind left by an earlier +// attempt is replaced. +func bindVolumeDir(root, subPath, target string, readOnly bool) error { + fd, err := openVolumeDir(root, subPath) + if err != nil { + return err + } + defer unix.Close(fd) + if err := unbindVolumeDir(target); err != nil { + return err + } + if err := os.MkdirAll(target, 0o750); err != nil { + return fmt.Errorf("creating mount point %q: %w", target, err) + } + // Binding from the descriptor mounts exactly the directory resolved above. + if err := unix.Mount(fmt.Sprintf("/proc/self/fd/%d", fd), target, "", unix.MS_BIND, ""); err != nil { + return fmt.Errorf("bind-mounting sub_path %q at %q: %w", subPath, target, err) + } + if readOnly { + if err := unix.Mount("", target, "", unix.MS_BIND|unix.MS_REMOUNT|unix.MS_RDONLY, ""); err != nil { + _ = unix.Unmount(target, unix.MNT_DETACH) + return fmt.Errorf("making %q read-only: %w", target, err) + } + } + return nil +} + +// unbindVolumeDir unmounts a bind of bindVolumeDir and removes its mount +// point; a target that is absent or not mounted is left as it is. +func unbindVolumeDir(target string) error { + if err := unix.Unmount(target, 0); err != nil && !errors.Is(err, unix.EINVAL) && !errors.Is(err, unix.ENOENT) { + return fmt.Errorf("unmounting %q: %w", target, err) + } + if err := os.Remove(target); err != nil && !os.IsNotExist(err) { + return fmt.Errorf("removing mount point %q: %w", target, err) + } + return nil +} diff --git a/internal/volumebind/volumebind_test.go b/internal/volumebind/volumebind_test.go new file mode 100644 index 0000000000..bc6a007adc --- /dev/null +++ b/internal/volumebind/volumebind_test.go @@ -0,0 +1,119 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package volumebind + +import ( + "os" + "path/filepath" + "strings" + "testing" + + "github.com/agent-substrate/substrate/internal/proto/ateompb" + "golang.org/x/sys/unix" +) + +func TestOpenVolumeDir(t *testing.T) { + root := t.TempDir() + outside := t.TempDir() + for _, dir := range []string{"sessions/a", "mirrors"} { + if err := os.MkdirAll(filepath.Join(root, dir), 0o755); err != nil { + t.Fatal(err) + } + } + if err := os.WriteFile(filepath.Join(root, "file"), nil, 0o644); err != nil { + t.Fatal(err) + } + // Links another actor could plant on the shared volume. + if err := os.Symlink(outside, filepath.Join(root, "sessions", "b")); err != nil { + t.Fatal(err) + } + if err := os.Symlink("../mirrors", filepath.Join(root, "sessions", "c")); err != nil { + t.Fatal(err) + } + + for _, tc := range []struct { + subPath string + wantErr string + }{ + {subPath: ""}, + {subPath: "sessions/a"}, + {subPath: "mirrors"}, + {subPath: "sessions/missing", wantErr: "does not exist"}, + {subPath: "sessions/b", wantErr: "crosses a symbolic link"}, + {subPath: "sessions/c", wantErr: "crosses a symbolic link"}, + {subPath: "file", wantErr: "is not a directory"}, + {subPath: "../" + filepath.Base(outside), wantErr: "opening sub_path"}, + } { + t.Run(tc.subPath, func(t *testing.T) { + fd, err := openVolumeDir(root, tc.subPath) + if tc.wantErr == "" { + if err != nil { + t.Fatalf("openVolumeDir(%q): %v", tc.subPath, err) + } + unix.Close(fd) + return + } + if err == nil { + unix.Close(fd) + t.Fatalf("openVolumeDir(%q) succeeded, want %q", tc.subPath, tc.wantErr) + } + if !strings.Contains(err.Error(), tc.wantErr) { + t.Errorf("openVolumeDir(%q) = %v, want %q", tc.subPath, err, tc.wantErr) + } + }) + } +} + +func TestBoundMounts(t *testing.T) { + containers := []*ateompb.Container{ + {CsiVolumeMounts: []*ateompb.VolumeMount{ + {VolumeName: "ws", MountPath: "/root"}, + {VolumeName: "ws", MountPath: "/workspace", SubPath: "sessions/a"}, + {VolumeName: "ws", MountPath: "/mirrors", SubPath: "mirrors", ReadOnly: true}, + }}, + {CsiVolumeMounts: []*ateompb.VolumeMount{ + {VolumeName: "ws", MountPath: "/also", SubPath: "sessions/a"}, + }}, + } + var got []string + for _, vm := range boundMounts(containers) { + got = append(got, vm.GetMountPath()) + } + if want := []string{"/workspace", "/mirrors"}; strings.Join(got, ",") != strings.Join(want, ",") { + t.Errorf("boundMounts = %v, want %v (one per directory, none for the root mount)", got, want) + } +} + +// A mount of a sub-path or a read-only mount binds a directory of its own, +// one per sub-path and read-only flag, which never names a volume. +func TestMountDir(t *testing.T) { + plain := MountDir("ws", "", false) + sub := MountDir("ws", "sessions/a", false) + subRO := MountDir("ws", "sessions/a", true) + other := MountDir("ws", "sessions/b", false) + if plain != "ws" { + t.Errorf("plain mount dir = %q, want the volume's own", plain) + } + seen := map[string]bool{} + for _, d := range []string{plain, sub, subRO, other} { + if seen[d] { + t.Errorf("mount dir %q is not distinct", d) + } + seen[d] = true + } + if !strings.HasPrefix(sub, "ws.") { + t.Errorf("sub-path mount dir = %q, want ws.", sub) + } +} diff --git a/manifests/ate-install/ate-api-server.yaml b/manifests/ate-install/ate-api-server.yaml index 0a861c7d90..2587b8402a 100644 --- a/manifests/ate-install/ate-api-server.yaml +++ b/manifests/ate-install/ate-api-server.yaml @@ -34,6 +34,11 @@ rules: - apiGroups: ["storage.k8s.io"] resources: ["storageclasses"] verbs: ["get", "watch", "list"] +# PersistentVolumes: an actor's existing volumes are checked against them at +# CreateActor, and their volume attributes are read at resume. +- apiGroups: [""] + resources: ["persistentvolumes"] + verbs: ["get", "watch", "list"] --- # Create Service Account for Workload Identity apiVersion: v1 diff --git a/pkg/proto/ateapipb/ateapi.pb.go b/pkg/proto/ateapipb/ateapi.pb.go index a3ec8fd9c4..0ce4d2f11d 100644 --- a/pkg/proto/ateapipb/ateapi.pb.go +++ b/pkg/proto/ateapipb/ateapi.pb.go @@ -141,6 +141,62 @@ func (TagScope) EnumDescriptor() ([]byte, []int) { return file_ateapi_proto_rawDescGZIP(), []int{1} } +// VolumeAccessMode is how a volume may be attached and mounted across nodes. +type VolumeAccessMode int32 + +const ( + VolumeAccessMode_VOLUME_ACCESS_MODE_UNSPECIFIED VolumeAccessMode = 0 + // Read-write on a single node (CSI SINGLE_NODE_WRITER). + VolumeAccessMode_VOLUME_ACCESS_MODE_READ_WRITE_ONCE VolumeAccessMode = 1 + // Read-only on many nodes (CSI MULTI_NODE_READER_ONLY). + VolumeAccessMode_VOLUME_ACCESS_MODE_READ_ONLY_MANY VolumeAccessMode = 2 + // Read-write on many nodes (CSI MULTI_NODE_MULTI_WRITER). + VolumeAccessMode_VOLUME_ACCESS_MODE_READ_WRITE_MANY VolumeAccessMode = 3 +) + +// Enum value maps for VolumeAccessMode. +var ( + VolumeAccessMode_name = map[int32]string{ + 0: "VOLUME_ACCESS_MODE_UNSPECIFIED", + 1: "VOLUME_ACCESS_MODE_READ_WRITE_ONCE", + 2: "VOLUME_ACCESS_MODE_READ_ONLY_MANY", + 3: "VOLUME_ACCESS_MODE_READ_WRITE_MANY", + } + VolumeAccessMode_value = map[string]int32{ + "VOLUME_ACCESS_MODE_UNSPECIFIED": 0, + "VOLUME_ACCESS_MODE_READ_WRITE_ONCE": 1, + "VOLUME_ACCESS_MODE_READ_ONLY_MANY": 2, + "VOLUME_ACCESS_MODE_READ_WRITE_MANY": 3, + } +) + +func (x VolumeAccessMode) Enum() *VolumeAccessMode { + p := new(VolumeAccessMode) + *p = x + return p +} + +func (x VolumeAccessMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (VolumeAccessMode) Descriptor() protoreflect.EnumDescriptor { + return file_ateapi_proto_enumTypes[2].Descriptor() +} + +func (VolumeAccessMode) Type() protoreflect.EnumType { + return &file_ateapi_proto_enumTypes[2] +} + +func (x VolumeAccessMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use VolumeAccessMode.Descriptor instead. +func (VolumeAccessMode) EnumDescriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{2} +} + type ActorState int32 const ( @@ -195,11 +251,11 @@ func (x ActorState) String() string { } func (ActorState) Descriptor() protoreflect.EnumDescriptor { - return file_ateapi_proto_enumTypes[2].Descriptor() + return file_ateapi_proto_enumTypes[3].Descriptor() } func (ActorState) Type() protoreflect.EnumType { - return &file_ateapi_proto_enumTypes[2] + return &file_ateapi_proto_enumTypes[3] } func (x ActorState) Number() protoreflect.EnumNumber { @@ -208,7 +264,7 @@ func (x ActorState) Number() protoreflect.EnumNumber { // Deprecated: Use ActorState.Descriptor instead. func (ActorState) EnumDescriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{2} + return file_ateapi_proto_rawDescGZIP(), []int{3} } // SandboxClass selects the sandbox runtime family. Snapshots are not portable @@ -246,11 +302,11 @@ func (x SandboxClass) String() string { } func (SandboxClass) Descriptor() protoreflect.EnumDescriptor { - return file_ateapi_proto_enumTypes[3].Descriptor() + return file_ateapi_proto_enumTypes[4].Descriptor() } func (SandboxClass) Type() protoreflect.EnumType { - return &file_ateapi_proto_enumTypes[3] + return &file_ateapi_proto_enumTypes[4] } func (x SandboxClass) Number() protoreflect.EnumNumber { @@ -259,7 +315,7 @@ func (x SandboxClass) Number() protoreflect.EnumNumber { // Deprecated: Use SandboxClass.Descriptor instead. func (SandboxClass) EnumDescriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{3} + return file_ateapi_proto_rawDescGZIP(), []int{4} } // ActorMetadataField selects one identity field of the actor. @@ -299,11 +355,11 @@ func (x ActorMetadataField) String() string { } func (ActorMetadataField) Descriptor() protoreflect.EnumDescriptor { - return file_ateapi_proto_enumTypes[4].Descriptor() + return file_ateapi_proto_enumTypes[5].Descriptor() } func (ActorMetadataField) Type() protoreflect.EnumType { - return &file_ateapi_proto_enumTypes[4] + return &file_ateapi_proto_enumTypes[5] } func (x ActorMetadataField) Number() protoreflect.EnumNumber { @@ -312,7 +368,7 @@ func (x ActorMetadataField) Number() protoreflect.EnumNumber { // Deprecated: Use ActorMetadataField.Descriptor instead. func (ActorMetadataField) EnumDescriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{4} + return file_ateapi_proto_rawDescGZIP(), []int{5} } type WorkerState int32 @@ -350,11 +406,11 @@ func (x WorkerState) String() string { } func (WorkerState) Descriptor() protoreflect.EnumDescriptor { - return file_ateapi_proto_enumTypes[5].Descriptor() + return file_ateapi_proto_enumTypes[6].Descriptor() } func (WorkerState) Type() protoreflect.EnumType { - return &file_ateapi_proto_enumTypes[5] + return &file_ateapi_proto_enumTypes[6] } func (x WorkerState) Number() protoreflect.EnumNumber { @@ -363,7 +419,7 @@ func (x WorkerState) Number() protoreflect.EnumNumber { // Deprecated: Use WorkerState.Descriptor instead. func (WorkerState) EnumDescriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{5} + return file_ateapi_proto_rawDescGZIP(), []int{6} } type ExternalVolume_Status int32 @@ -405,11 +461,11 @@ func (x ExternalVolume_Status) String() string { } func (ExternalVolume_Status) Descriptor() protoreflect.EnumDescriptor { - return file_ateapi_proto_enumTypes[6].Descriptor() + return file_ateapi_proto_enumTypes[7].Descriptor() } func (ExternalVolume_Status) Type() protoreflect.EnumType { - return &file_ateapi_proto_enumTypes[6] + return &file_ateapi_proto_enumTypes[7] } func (x ExternalVolume_Status) Number() protoreflect.EnumNumber { @@ -951,9 +1007,26 @@ type Actor struct { // server and ignored on input. It is always present in output. // // +k8s:optional - Status *ActorStatus `protobuf:"bytes,7,opt,name=status,proto3" json:"status,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + Status *ActorStatus `protobuf:"bytes,7,opt,name=status,proto3" json:"status,omitempty"` + // existing_volumes supply the template's existing volumes + // (Volume.existing_volume) for this actor: each names one and references a + // CSI volume that exists outside Substrate and outlives the actor, such as + // a read-write-many volume several actors work on. Substrate attaches and + // mounts it for this actor, and never creates or deletes it nor changes its + // content. An existing volume of the template that this list does not name + // has neither the volume nor its mounts. An actor that names any boots from + // its image instead of restoring the template's golden snapshot, which was + // captured without these mounts. Set once at creation and immutable + // afterward. + // + // +k8s:optional + // +k8s:maxItems=8 + // +k8s:listType=map + // +k8s:listMapKey=name + // +k8s:immutable + ExistingVolumes []*ExistingVolume `protobuf:"bytes,10001,rep,name=existing_volumes,json=existingVolumes,proto3" json:"existing_volumes,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Actor) Reset() { @@ -1021,6 +1094,126 @@ func (x *Actor) GetStatus() *ActorStatus { return nil } +func (x *Actor) GetExistingVolumes() []*ExistingVolume { + if x != nil { + return x.ExistingVolumes + } + return nil +} + +// ExistingVolume references a CSI volume for one of the template's existing +// volumes. +type ExistingVolume struct { + state protoimpl.MessageState `protogen:"open.v1"` + // name of the template's existing volume this supplies. + // + // +k8s:required + // +k8s:format=k8s-short-name + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // driver is the CSI driver that serves the volume. It must have a + // CSIDriverConfig. + // + // +k8s:required + // +k8s:maxLength=253 + // +k8s:customValidation # same syntax as ExternalVolume.volume_type + Driver string `protobuf:"bytes,2,opt,name=driver,proto3" json:"driver,omitempty"` + // volume_handle is the driver's ID of the volume, as a Kubernetes + // PersistentVolume names it in spec.csi.volumeHandle. A PersistentVolume of + // the driver with this handle must exist; its spec.csi.volumeAttributes are + // passed to the driver when the volume is mounted. Several existing volumes + // of one actor may reference the same handle. + // + // +k8s:required + // +k8s:maxLength=256 + // +k8s:customValidation # no control characters + VolumeHandle string `protobuf:"bytes,3,opt,name=volume_handle,json=volumeHandle,proto3" json:"volume_handle,omitempty"` + // access_mode is READ_WRITE_MANY or READ_ONLY_MANY, and must be one of the + // PersistentVolume's access modes. With READ_ONLY_MANY every mount of the + // volume is read-only. + // + // +k8s:required + // +k8s:minimum=2 + // +k8s:maximum=3 # keep in sync with VolumeAccessMode + AccessMode VolumeAccessMode `protobuf:"varint,4,opt,name=access_mode,json=accessMode,proto3,enum=ateapi.VolumeAccessMode" json:"access_mode,omitempty"` + // sub_path is the directory of the volume that this actor sees as the + // volume's root, in the form of VolumeMount.sub_path; empty is the root. + // The template's mounts of the volume, and their own sub_path, are + // relative to it, so actors of one template can each work in a directory + // of their own. + // + // +k8s:optional + // +k8s:maxLength=4096 + // +k8s:customValidation # clean relative path + SubPath string `protobuf:"bytes,5,opt,name=sub_path,json=subPath,proto3" json:"sub_path,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExistingVolume) Reset() { + *x = ExistingVolume{} + mi := &file_ateapi_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExistingVolume) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExistingVolume) ProtoMessage() {} + +func (x *ExistingVolume) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExistingVolume.ProtoReflect.Descriptor instead. +func (*ExistingVolume) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{6} +} + +func (x *ExistingVolume) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ExistingVolume) GetDriver() string { + if x != nil { + return x.Driver + } + return "" +} + +func (x *ExistingVolume) GetVolumeHandle() string { + if x != nil { + return x.VolumeHandle + } + return "" +} + +func (x *ExistingVolume) GetAccessMode() VolumeAccessMode { + if x != nil { + return x.AccessMode + } + return VolumeAccessMode_VOLUME_ACCESS_MODE_UNSPECIFIED +} + +func (x *ExistingVolume) GetSubPath() string { + if x != nil { + return x.SubPath + } + return "" +} + // EgressPolicy is an egress policy resource nested under an Actor. An Actor has // at most one egress policy resource, named "default". type EgressPolicy struct { @@ -1061,7 +1254,7 @@ type EgressPolicy struct { func (x *EgressPolicy) Reset() { *x = EgressPolicy{} - mi := &file_ateapi_proto_msgTypes[6] + mi := &file_ateapi_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1073,7 +1266,7 @@ func (x *EgressPolicy) String() string { func (*EgressPolicy) ProtoMessage() {} func (x *EgressPolicy) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[6] + mi := &file_ateapi_proto_msgTypes[7] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1086,7 +1279,7 @@ func (x *EgressPolicy) ProtoReflect() protoreflect.Message { // Deprecated: Use EgressPolicy.ProtoReflect.Descriptor instead. func (*EgressPolicy) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{6} + return file_ateapi_proto_rawDescGZIP(), []int{7} } func (x *EgressPolicy) GetMetadata() *ResourceMetadata { @@ -1121,7 +1314,7 @@ type EgressPolicyTemplate struct { func (x *EgressPolicyTemplate) Reset() { *x = EgressPolicyTemplate{} - mi := &file_ateapi_proto_msgTypes[7] + mi := &file_ateapi_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1133,7 +1326,7 @@ func (x *EgressPolicyTemplate) String() string { func (*EgressPolicyTemplate) ProtoMessage() {} func (x *EgressPolicyTemplate) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[7] + mi := &file_ateapi_proto_msgTypes[8] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1146,7 +1339,7 @@ func (x *EgressPolicyTemplate) ProtoReflect() protoreflect.Message { // Deprecated: Use EgressPolicyTemplate.ProtoReflect.Descriptor instead. func (*EgressPolicyTemplate) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{7} + return file_ateapi_proto_rawDescGZIP(), []int{8} } func (x *EgressPolicyTemplate) GetRules() []*EgressRule { @@ -1189,7 +1382,7 @@ type EgressRule struct { func (x *EgressRule) Reset() { *x = EgressRule{} - mi := &file_ateapi_proto_msgTypes[8] + mi := &file_ateapi_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1201,7 +1394,7 @@ func (x *EgressRule) String() string { func (*EgressRule) ProtoMessage() {} func (x *EgressRule) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[8] + mi := &file_ateapi_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1214,7 +1407,7 @@ func (x *EgressRule) ProtoReflect() protoreflect.Message { // Deprecated: Use EgressRule.ProtoReflect.Descriptor instead. func (*EgressRule) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{8} + return file_ateapi_proto_rawDescGZIP(), []int{9} } func (x *EgressRule) GetHttp() *HTTPRule { @@ -1282,7 +1475,7 @@ type HTTPRule struct { func (x *HTTPRule) Reset() { *x = HTTPRule{} - mi := &file_ateapi_proto_msgTypes[9] + mi := &file_ateapi_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1294,7 +1487,7 @@ func (x *HTTPRule) String() string { func (*HTTPRule) ProtoMessage() {} func (x *HTTPRule) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[9] + mi := &file_ateapi_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1307,7 +1500,7 @@ func (x *HTTPRule) ProtoReflect() protoreflect.Message { // Deprecated: Use HTTPRule.ProtoReflect.Descriptor instead. func (*HTTPRule) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{9} + return file_ateapi_proto_rawDescGZIP(), []int{10} } func (x *HTTPRule) GetHostnames() []string { @@ -1367,7 +1560,7 @@ type HTTPSRule struct { func (x *HTTPSRule) Reset() { *x = HTTPSRule{} - mi := &file_ateapi_proto_msgTypes[10] + mi := &file_ateapi_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1379,7 +1572,7 @@ func (x *HTTPSRule) String() string { func (*HTTPSRule) ProtoMessage() {} func (x *HTTPSRule) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[10] + mi := &file_ateapi_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1392,7 +1585,7 @@ func (x *HTTPSRule) ProtoReflect() protoreflect.Message { // Deprecated: Use HTTPSRule.ProtoReflect.Descriptor instead. func (*HTTPSRule) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{10} + return file_ateapi_proto_rawDescGZIP(), []int{11} } func (x *HTTPSRule) GetHostnames() []string { @@ -1443,7 +1636,7 @@ type TLSPassthroughRule struct { func (x *TLSPassthroughRule) Reset() { *x = TLSPassthroughRule{} - mi := &file_ateapi_proto_msgTypes[11] + mi := &file_ateapi_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1455,7 +1648,7 @@ func (x *TLSPassthroughRule) String() string { func (*TLSPassthroughRule) ProtoMessage() {} func (x *TLSPassthroughRule) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[11] + mi := &file_ateapi_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1468,7 +1661,7 @@ func (x *TLSPassthroughRule) ProtoReflect() protoreflect.Message { // Deprecated: Use TLSPassthroughRule.ProtoReflect.Descriptor instead. func (*TLSPassthroughRule) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{11} + return file_ateapi_proto_rawDescGZIP(), []int{12} } func (x *TLSPassthroughRule) GetHostnames() []string { @@ -1509,7 +1702,7 @@ type Ports struct { func (x *Ports) Reset() { *x = Ports{} - mi := &file_ateapi_proto_msgTypes[12] + mi := &file_ateapi_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1521,7 +1714,7 @@ func (x *Ports) String() string { func (*Ports) ProtoMessage() {} func (x *Ports) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[12] + mi := &file_ateapi_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1534,7 +1727,7 @@ func (x *Ports) ProtoReflect() protoreflect.Message { // Deprecated: Use Ports.ProtoReflect.Descriptor instead. func (*Ports) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{12} + return file_ateapi_proto_rawDescGZIP(), []int{13} } func (x *Ports) GetAll() *AllPorts { @@ -1560,7 +1753,7 @@ type AllPorts struct { func (x *AllPorts) Reset() { *x = AllPorts{} - mi := &file_ateapi_proto_msgTypes[13] + mi := &file_ateapi_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1572,7 +1765,7 @@ func (x *AllPorts) String() string { func (*AllPorts) ProtoMessage() {} func (x *AllPorts) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[13] + mi := &file_ateapi_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1585,7 +1778,7 @@ func (x *AllPorts) ProtoReflect() protoreflect.Message { // Deprecated: Use AllPorts.ProtoReflect.Descriptor instead. func (*AllPorts) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{13} + return file_ateapi_proto_rawDescGZIP(), []int{14} } // HttpRuleEffects contains effects applied by a matching HTTP or HTTPS rule. @@ -1612,7 +1805,7 @@ type HttpRuleEffects struct { func (x *HttpRuleEffects) Reset() { *x = HttpRuleEffects{} - mi := &file_ateapi_proto_msgTypes[14] + mi := &file_ateapi_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1624,7 +1817,7 @@ func (x *HttpRuleEffects) String() string { func (*HttpRuleEffects) ProtoMessage() {} func (x *HttpRuleEffects) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[14] + mi := &file_ateapi_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1637,7 +1830,7 @@ func (x *HttpRuleEffects) ProtoReflect() protoreflect.Message { // Deprecated: Use HttpRuleEffects.ProtoReflect.Descriptor instead. func (*HttpRuleEffects) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{14} + return file_ateapi_proto_rawDescGZIP(), []int{15} } func (x *HttpRuleEffects) GetReplaceHeaders() []*CredentialHeader { @@ -1687,7 +1880,7 @@ type CredentialHeader struct { func (x *CredentialHeader) Reset() { *x = CredentialHeader{} - mi := &file_ateapi_proto_msgTypes[15] + mi := &file_ateapi_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1699,7 +1892,7 @@ func (x *CredentialHeader) String() string { func (*CredentialHeader) ProtoMessage() {} func (x *CredentialHeader) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[15] + mi := &file_ateapi_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1712,7 +1905,7 @@ func (x *CredentialHeader) ProtoReflect() protoreflect.Message { // Deprecated: Use CredentialHeader.ProtoReflect.Descriptor instead. func (*CredentialHeader) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{15} + return file_ateapi_proto_rawDescGZIP(), []int{16} } func (x *CredentialHeader) GetHeader() string { @@ -1769,7 +1962,7 @@ type ActorJWTSource struct { func (x *ActorJWTSource) Reset() { *x = ActorJWTSource{} - mi := &file_ateapi_proto_msgTypes[16] + mi := &file_ateapi_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1781,7 +1974,7 @@ func (x *ActorJWTSource) String() string { func (*ActorJWTSource) ProtoMessage() {} func (x *ActorJWTSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[16] + mi := &file_ateapi_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1794,7 +1987,7 @@ func (x *ActorJWTSource) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorJWTSource.ProtoReflect.Descriptor instead. func (*ActorJWTSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{16} + return file_ateapi_proto_rawDescGZIP(), []int{17} } func (x *ActorJWTSource) GetAudiences() []string { @@ -1875,7 +2068,7 @@ type ActorStatus struct { func (x *ActorStatus) Reset() { *x = ActorStatus{} - mi := &file_ateapi_proto_msgTypes[17] + mi := &file_ateapi_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1887,7 +2080,7 @@ func (x *ActorStatus) String() string { func (*ActorStatus) ProtoMessage() {} func (x *ActorStatus) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[17] + mi := &file_ateapi_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1900,7 +2093,7 @@ func (x *ActorStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorStatus.ProtoReflect.Descriptor instead. func (*ActorStatus) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{17} + return file_ateapi_proto_rawDescGZIP(), []int{18} } func (x *ActorStatus) GetState() ActorState { @@ -1984,7 +2177,7 @@ type ActorCrash struct { func (x *ActorCrash) Reset() { *x = ActorCrash{} - mi := &file_ateapi_proto_msgTypes[18] + mi := &file_ateapi_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1996,7 +2189,7 @@ func (x *ActorCrash) String() string { func (*ActorCrash) ProtoMessage() {} func (x *ActorCrash) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[18] + mi := &file_ateapi_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2009,7 +2202,7 @@ func (x *ActorCrash) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorCrash.ProtoReflect.Descriptor instead. func (*ActorCrash) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{18} + return file_ateapi_proto_rawDescGZIP(), []int{19} } func (x *ActorCrash) GetMessage() string { @@ -2090,7 +2283,7 @@ type WorkerAssignment struct { func (x *WorkerAssignment) Reset() { *x = WorkerAssignment{} - mi := &file_ateapi_proto_msgTypes[19] + mi := &file_ateapi_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2102,7 +2295,7 @@ func (x *WorkerAssignment) String() string { func (*WorkerAssignment) ProtoMessage() {} func (x *WorkerAssignment) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[19] + mi := &file_ateapi_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2115,7 +2308,7 @@ func (x *WorkerAssignment) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkerAssignment.ProtoReflect.Descriptor instead. func (*WorkerAssignment) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{19} + return file_ateapi_proto_rawDescGZIP(), []int{20} } func (x *WorkerAssignment) GetWorker() *ObjectRef { @@ -2205,7 +2398,7 @@ type TagStatus struct { func (x *TagStatus) Reset() { *x = TagStatus{} - mi := &file_ateapi_proto_msgTypes[20] + mi := &file_ateapi_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2217,7 +2410,7 @@ func (x *TagStatus) String() string { func (*TagStatus) ProtoMessage() {} func (x *TagStatus) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[20] + mi := &file_ateapi_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2230,7 +2423,7 @@ func (x *TagStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use TagStatus.ProtoReflect.Descriptor instead. func (*TagStatus) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{20} + return file_ateapi_proto_rawDescGZIP(), []int{21} } func (x *TagStatus) GetSnapshot() *ExternalSnapshot { @@ -2289,7 +2482,7 @@ type Tag struct { func (x *Tag) Reset() { *x = Tag{} - mi := &file_ateapi_proto_msgTypes[21] + mi := &file_ateapi_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2301,7 +2494,7 @@ func (x *Tag) String() string { func (*Tag) ProtoMessage() {} func (x *Tag) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[21] + mi := &file_ateapi_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2314,7 +2507,7 @@ func (x *Tag) ProtoReflect() protoreflect.Message { // Deprecated: Use Tag.ProtoReflect.Descriptor instead. func (*Tag) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{21} + return file_ateapi_proto_rawDescGZIP(), []int{22} } func (x *Tag) GetMetadata() *ResourceMetadata { @@ -2360,7 +2553,7 @@ type Atespace struct { func (x *Atespace) Reset() { *x = Atespace{} - mi := &file_ateapi_proto_msgTypes[22] + mi := &file_ateapi_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2372,7 +2565,7 @@ func (x *Atespace) String() string { func (*Atespace) ProtoMessage() {} func (x *Atespace) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[22] + mi := &file_ateapi_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2385,7 +2578,7 @@ func (x *Atespace) ProtoReflect() protoreflect.Message { // Deprecated: Use Atespace.ProtoReflect.Descriptor instead. func (*Atespace) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{22} + return file_ateapi_proto_rawDescGZIP(), []int{23} } func (x *Atespace) GetMetadata() *ResourceMetadata { @@ -2418,7 +2611,7 @@ type ObjectRef struct { func (x *ObjectRef) Reset() { *x = ObjectRef{} - mi := &file_ateapi_proto_msgTypes[23] + mi := &file_ateapi_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2430,7 +2623,7 @@ func (x *ObjectRef) String() string { func (*ObjectRef) ProtoMessage() {} func (x *ObjectRef) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[23] + mi := &file_ateapi_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2443,7 +2636,7 @@ func (x *ObjectRef) ProtoReflect() protoreflect.Message { // Deprecated: Use ObjectRef.ProtoReflect.Descriptor instead. func (*ObjectRef) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{23} + return file_ateapi_proto_rawDescGZIP(), []int{24} } func (x *ObjectRef) GetAtespace() string { @@ -2507,7 +2700,7 @@ type ActorTemplate struct { func (x *ActorTemplate) Reset() { *x = ActorTemplate{} - mi := &file_ateapi_proto_msgTypes[24] + mi := &file_ateapi_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2519,7 +2712,7 @@ func (x *ActorTemplate) String() string { func (*ActorTemplate) ProtoMessage() {} func (x *ActorTemplate) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[24] + mi := &file_ateapi_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2532,7 +2725,7 @@ func (x *ActorTemplate) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorTemplate.ProtoReflect.Descriptor instead. func (*ActorTemplate) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{24} + return file_ateapi_proto_rawDescGZIP(), []int{25} } func (x *ActorTemplate) GetMetadata() *ResourceMetadata { @@ -2615,7 +2808,7 @@ type Resources struct { func (x *Resources) Reset() { *x = Resources{} - mi := &file_ateapi_proto_msgTypes[25] + mi := &file_ateapi_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2627,7 +2820,7 @@ func (x *Resources) String() string { func (*Resources) ProtoMessage() {} func (x *Resources) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[25] + mi := &file_ateapi_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2640,7 +2833,7 @@ func (x *Resources) ProtoReflect() protoreflect.Message { // Deprecated: Use Resources.ProtoReflect.Descriptor instead. func (*Resources) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{25} + return file_ateapi_proto_rawDescGZIP(), []int{26} } func (x *Resources) GetLimits() []*Limits { @@ -2668,7 +2861,7 @@ type Limits struct { func (x *Limits) Reset() { *x = Limits{} - mi := &file_ateapi_proto_msgTypes[26] + mi := &file_ateapi_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2680,7 +2873,7 @@ func (x *Limits) String() string { func (*Limits) ProtoMessage() {} func (x *Limits) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[26] + mi := &file_ateapi_proto_msgTypes[27] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2693,7 +2886,7 @@ func (x *Limits) ProtoReflect() protoreflect.Message { // Deprecated: Use Limits.ProtoReflect.Descriptor instead. func (*Limits) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{26} + return file_ateapi_proto_rawDescGZIP(), []int{27} } func (x *Limits) GetName() string { @@ -2734,7 +2927,7 @@ type GoldenSnapshotStatus struct { func (x *GoldenSnapshotStatus) Reset() { *x = GoldenSnapshotStatus{} - mi := &file_ateapi_proto_msgTypes[27] + mi := &file_ateapi_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2746,7 +2939,7 @@ func (x *GoldenSnapshotStatus) String() string { func (*GoldenSnapshotStatus) ProtoMessage() {} func (x *GoldenSnapshotStatus) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[27] + mi := &file_ateapi_proto_msgTypes[28] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2759,7 +2952,7 @@ func (x *GoldenSnapshotStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use GoldenSnapshotStatus.ProtoReflect.Descriptor instead. func (*GoldenSnapshotStatus) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{27} + return file_ateapi_proto_rawDescGZIP(), []int{28} } func (x *GoldenSnapshotStatus) GetGoldenTag() *ObjectRef { @@ -2793,7 +2986,7 @@ type ActorTemplateStatus struct { func (x *ActorTemplateStatus) Reset() { *x = ActorTemplateStatus{} - mi := &file_ateapi_proto_msgTypes[28] + mi := &file_ateapi_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2805,7 +2998,7 @@ func (x *ActorTemplateStatus) String() string { func (*ActorTemplateStatus) ProtoMessage() {} func (x *ActorTemplateStatus) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[28] + mi := &file_ateapi_proto_msgTypes[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2818,7 +3011,7 @@ func (x *ActorTemplateStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorTemplateStatus.ProtoReflect.Descriptor instead. func (*ActorTemplateStatus) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{28} + return file_ateapi_proto_rawDescGZIP(), []int{29} } func (x *ActorTemplateStatus) GetGoldenSnapshotStatus() *GoldenSnapshotStatus { @@ -2849,7 +3042,7 @@ type SandboxConfig struct { func (x *SandboxConfig) Reset() { *x = SandboxConfig{} - mi := &file_ateapi_proto_msgTypes[29] + mi := &file_ateapi_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2861,7 +3054,7 @@ func (x *SandboxConfig) String() string { func (*SandboxConfig) ProtoMessage() {} func (x *SandboxConfig) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[29] + mi := &file_ateapi_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2874,7 +3067,7 @@ func (x *SandboxConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxConfig.ProtoReflect.Descriptor instead. func (*SandboxConfig) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{29} + return file_ateapi_proto_rawDescGZIP(), []int{30} } func (x *SandboxConfig) GetSandboxClass() SandboxClass { @@ -2928,7 +3121,7 @@ type SnapshotConfig struct { func (x *SnapshotConfig) Reset() { *x = SnapshotConfig{} - mi := &file_ateapi_proto_msgTypes[30] + mi := &file_ateapi_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2940,7 +3133,7 @@ func (x *SnapshotConfig) String() string { func (*SnapshotConfig) ProtoMessage() {} func (x *SnapshotConfig) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[30] + mi := &file_ateapi_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2953,7 +3146,7 @@ func (x *SnapshotConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use SnapshotConfig.ProtoReflect.Descriptor instead. func (*SnapshotConfig) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{30} + return file_ateapi_proto_rawDescGZIP(), []int{31} } func (x *SnapshotConfig) GetOnPause() SnapshotContentScope { @@ -3047,7 +3240,7 @@ type Container struct { func (x *Container) Reset() { *x = Container{} - mi := &file_ateapi_proto_msgTypes[31] + mi := &file_ateapi_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3059,7 +3252,7 @@ func (x *Container) String() string { func (*Container) ProtoMessage() {} func (x *Container) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[31] + mi := &file_ateapi_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3072,7 +3265,7 @@ func (x *Container) ProtoReflect() protoreflect.Message { // Deprecated: Use Container.ProtoReflect.Descriptor instead. func (*Container) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{31} + return file_ateapi_proto_rawDescGZIP(), []int{32} } func (x *Container) GetName() string { @@ -3152,7 +3345,7 @@ type SecurityContext struct { func (x *SecurityContext) Reset() { *x = SecurityContext{} - mi := &file_ateapi_proto_msgTypes[32] + mi := &file_ateapi_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3164,7 +3357,7 @@ func (x *SecurityContext) String() string { func (*SecurityContext) ProtoMessage() {} func (x *SecurityContext) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[32] + mi := &file_ateapi_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3177,7 +3370,7 @@ func (x *SecurityContext) ProtoReflect() protoreflect.Message { // Deprecated: Use SecurityContext.ProtoReflect.Descriptor instead. func (*SecurityContext) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{32} + return file_ateapi_proto_rawDescGZIP(), []int{33} } func (x *SecurityContext) GetCapabilities() *Capabilities { @@ -3215,7 +3408,7 @@ type Capabilities struct { func (x *Capabilities) Reset() { *x = Capabilities{} - mi := &file_ateapi_proto_msgTypes[33] + mi := &file_ateapi_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3227,7 +3420,7 @@ func (x *Capabilities) String() string { func (*Capabilities) ProtoMessage() {} func (x *Capabilities) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[33] + mi := &file_ateapi_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3240,7 +3433,7 @@ func (x *Capabilities) ProtoReflect() protoreflect.Message { // Deprecated: Use Capabilities.ProtoReflect.Descriptor instead. func (*Capabilities) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{33} + return file_ateapi_proto_rawDescGZIP(), []int{34} } func (x *Capabilities) GetAdd() []string { @@ -3278,7 +3471,7 @@ type EnvVar struct { func (x *EnvVar) Reset() { *x = EnvVar{} - mi := &file_ateapi_proto_msgTypes[34] + mi := &file_ateapi_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3290,7 +3483,7 @@ func (x *EnvVar) String() string { func (*EnvVar) ProtoMessage() {} func (x *EnvVar) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[34] + mi := &file_ateapi_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3303,7 +3496,7 @@ func (x *EnvVar) ProtoReflect() protoreflect.Message { // Deprecated: Use EnvVar.ProtoReflect.Descriptor instead. func (*EnvVar) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{34} + return file_ateapi_proto_rawDescGZIP(), []int{35} } func (x *EnvVar) GetName() string { @@ -3343,7 +3536,7 @@ type ContainerWakeupProbe struct { func (x *ContainerWakeupProbe) Reset() { *x = ContainerWakeupProbe{} - mi := &file_ateapi_proto_msgTypes[35] + mi := &file_ateapi_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3355,7 +3548,7 @@ func (x *ContainerWakeupProbe) String() string { func (*ContainerWakeupProbe) ProtoMessage() {} func (x *ContainerWakeupProbe) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[35] + mi := &file_ateapi_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3368,7 +3561,7 @@ func (x *ContainerWakeupProbe) ProtoReflect() protoreflect.Message { // Deprecated: Use ContainerWakeupProbe.ProtoReflect.Descriptor instead. func (*ContainerWakeupProbe) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{35} + return file_ateapi_proto_rawDescGZIP(), []int{36} } func (x *ContainerWakeupProbe) GetHttpGet() *HTTPGetAction { @@ -3408,7 +3601,7 @@ type HTTPGetAction struct { func (x *HTTPGetAction) Reset() { *x = HTTPGetAction{} - mi := &file_ateapi_proto_msgTypes[36] + mi := &file_ateapi_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3420,7 +3613,7 @@ func (x *HTTPGetAction) String() string { func (*HTTPGetAction) ProtoMessage() {} func (x *HTTPGetAction) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[36] + mi := &file_ateapi_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3433,7 +3626,7 @@ func (x *HTTPGetAction) ProtoReflect() protoreflect.Message { // Deprecated: Use HTTPGetAction.ProtoReflect.Descriptor instead. func (*HTTPGetAction) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{36} + return file_ateapi_proto_rawDescGZIP(), []int{37} } func (x *HTTPGetAction) GetPath() string { @@ -3458,7 +3651,7 @@ type Volume struct { // +k8s:format=k8s-short-name Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // Exactly one of durable_dir / external_volume_template / image / - // system_info must be set. + // system_info / existing_volume must be set. // // +k8s:optional // +k8s:unionMember @@ -3473,14 +3666,20 @@ type Volume struct { // // +k8s:optional // +k8s:unionMember - Image *ImageVolumeSource `protobuf:"bytes,6,opt,name=image,proto3" json:"image,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + Image *ImageVolumeSource `protobuf:"bytes,6,opt,name=image,proto3" json:"image,omitempty"` + // existing_volume declares a volume each actor supplies at CreateActor + // (Actor.existing_volumes). + // + // +k8s:optional + // +k8s:unionMember + ExistingVolume *ExistingVolumeSource `protobuf:"bytes,10001,opt,name=existing_volume,json=existingVolume,proto3" json:"existing_volume,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Volume) Reset() { *x = Volume{} - mi := &file_ateapi_proto_msgTypes[37] + mi := &file_ateapi_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3492,7 +3691,7 @@ func (x *Volume) String() string { func (*Volume) ProtoMessage() {} func (x *Volume) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[37] + mi := &file_ateapi_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3505,7 +3704,7 @@ func (x *Volume) ProtoReflect() protoreflect.Message { // Deprecated: Use Volume.ProtoReflect.Descriptor instead. func (*Volume) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{37} + return file_ateapi_proto_rawDescGZIP(), []int{38} } func (x *Volume) GetName() string { @@ -3543,6 +3742,52 @@ func (x *Volume) GetImage() *ImageVolumeSource { return nil } +func (x *Volume) GetExistingVolume() *ExistingVolumeSource { + if x != nil { + return x.ExistingVolume + } + return nil +} + +// ExistingVolumeSource declares a volume that exists outside Substrate and +// that each actor supplies at CreateActor in Actor.existing_volumes. An actor +// that supplies none has neither the volume nor its mounts. +type ExistingVolumeSource struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExistingVolumeSource) Reset() { + *x = ExistingVolumeSource{} + mi := &file_ateapi_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExistingVolumeSource) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExistingVolumeSource) ProtoMessage() {} + +func (x *ExistingVolumeSource) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[39] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExistingVolumeSource.ProtoReflect.Descriptor instead. +func (*ExistingVolumeSource) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{39} +} + // ImageVolumeSource mounts the contents of an OCI image, read-only. The // reference must include a digest: changing the image invalidates // snapshots. @@ -3561,7 +3806,7 @@ type ImageVolumeSource struct { func (x *ImageVolumeSource) Reset() { *x = ImageVolumeSource{} - mi := &file_ateapi_proto_msgTypes[38] + mi := &file_ateapi_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3573,7 +3818,7 @@ func (x *ImageVolumeSource) String() string { func (*ImageVolumeSource) ProtoMessage() {} func (x *ImageVolumeSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[38] + mi := &file_ateapi_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3586,7 +3831,7 @@ func (x *ImageVolumeSource) ProtoReflect() protoreflect.Message { // Deprecated: Use ImageVolumeSource.ProtoReflect.Descriptor instead. func (*ImageVolumeSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{38} + return file_ateapi_proto_rawDescGZIP(), []int{40} } func (x *ImageVolumeSource) GetReference() string { @@ -3606,7 +3851,7 @@ type DurableDirVolumeSource struct { func (x *DurableDirVolumeSource) Reset() { *x = DurableDirVolumeSource{} - mi := &file_ateapi_proto_msgTypes[39] + mi := &file_ateapi_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3618,7 +3863,7 @@ func (x *DurableDirVolumeSource) String() string { func (*DurableDirVolumeSource) ProtoMessage() {} func (x *DurableDirVolumeSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[39] + mi := &file_ateapi_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3631,7 +3876,7 @@ func (x *DurableDirVolumeSource) ProtoReflect() protoreflect.Message { // Deprecated: Use DurableDirVolumeSource.ProtoReflect.Descriptor instead. func (*DurableDirVolumeSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{39} + return file_ateapi_proto_rawDescGZIP(), []int{41} } // ExternalVolumeTemplate provisions an external volume per actor; the volume @@ -3657,7 +3902,7 @@ type ExternalVolumeTemplate struct { func (x *ExternalVolumeTemplate) Reset() { *x = ExternalVolumeTemplate{} - mi := &file_ateapi_proto_msgTypes[40] + mi := &file_ateapi_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3669,7 +3914,7 @@ func (x *ExternalVolumeTemplate) String() string { func (*ExternalVolumeTemplate) ProtoMessage() {} func (x *ExternalVolumeTemplate) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[40] + mi := &file_ateapi_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3682,7 +3927,7 @@ func (x *ExternalVolumeTemplate) ProtoReflect() protoreflect.Message { // Deprecated: Use ExternalVolumeTemplate.ProtoReflect.Descriptor instead. func (*ExternalVolumeTemplate) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{40} + return file_ateapi_proto_rawDescGZIP(), []int{42} } func (x *ExternalVolumeTemplate) GetCapacity() string { @@ -3719,7 +3964,7 @@ type SystemInfoVolumeSource struct { func (x *SystemInfoVolumeSource) Reset() { *x = SystemInfoVolumeSource{} - mi := &file_ateapi_proto_msgTypes[41] + mi := &file_ateapi_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3731,7 +3976,7 @@ func (x *SystemInfoVolumeSource) String() string { func (*SystemInfoVolumeSource) ProtoMessage() {} func (x *SystemInfoVolumeSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[41] + mi := &file_ateapi_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3744,7 +3989,7 @@ func (x *SystemInfoVolumeSource) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemInfoVolumeSource.ProtoReflect.Descriptor instead. func (*SystemInfoVolumeSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{41} + return file_ateapi_proto_rawDescGZIP(), []int{43} } func (x *SystemInfoVolumeSource) GetDataSources() []*SystemInfoDataSource { @@ -3770,7 +4015,7 @@ type SystemInfoDataSource struct { func (x *SystemInfoDataSource) Reset() { *x = SystemInfoDataSource{} - mi := &file_ateapi_proto_msgTypes[42] + mi := &file_ateapi_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3782,7 +4027,7 @@ func (x *SystemInfoDataSource) String() string { func (*SystemInfoDataSource) ProtoMessage() {} func (x *SystemInfoDataSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[42] + mi := &file_ateapi_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3795,7 +4040,7 @@ func (x *SystemInfoDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemInfoDataSource.ProtoReflect.Descriptor instead. func (*SystemInfoDataSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{42} + return file_ateapi_proto_rawDescGZIP(), []int{44} } func (x *SystemInfoDataSource) GetActorMetadata() *ActorMetadataDataSource { @@ -3832,7 +4077,7 @@ type ActorMetadataDataSource struct { func (x *ActorMetadataDataSource) Reset() { *x = ActorMetadataDataSource{} - mi := &file_ateapi_proto_msgTypes[43] + mi := &file_ateapi_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3844,7 +4089,7 @@ func (x *ActorMetadataDataSource) String() string { func (*ActorMetadataDataSource) ProtoMessage() {} func (x *ActorMetadataDataSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[43] + mi := &file_ateapi_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3857,7 +4102,7 @@ func (x *ActorMetadataDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorMetadataDataSource.ProtoReflect.Descriptor instead. func (*ActorMetadataDataSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{43} + return file_ateapi_proto_rawDescGZIP(), []int{45} } func (x *ActorMetadataDataSource) GetItems() []*ActorMetadataItem { @@ -3889,7 +4134,7 @@ type ActorMetadataItem struct { func (x *ActorMetadataItem) Reset() { *x = ActorMetadataItem{} - mi := &file_ateapi_proto_msgTypes[44] + mi := &file_ateapi_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3901,7 +4146,7 @@ func (x *ActorMetadataItem) String() string { func (*ActorMetadataItem) ProtoMessage() {} func (x *ActorMetadataItem) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[44] + mi := &file_ateapi_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3914,7 +4159,7 @@ func (x *ActorMetadataItem) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorMetadataItem.ProtoReflect.Descriptor instead. func (*ActorMetadataItem) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{44} + return file_ateapi_proto_rawDescGZIP(), []int{46} } func (x *ActorMetadataItem) GetField() ActorMetadataField { @@ -3962,7 +4207,7 @@ type TrustBundleDataSource struct { func (x *TrustBundleDataSource) Reset() { *x = TrustBundleDataSource{} - mi := &file_ateapi_proto_msgTypes[45] + mi := &file_ateapi_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3974,7 +4219,7 @@ func (x *TrustBundleDataSource) String() string { func (*TrustBundleDataSource) ProtoMessage() {} func (x *TrustBundleDataSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[45] + mi := &file_ateapi_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3987,7 +4232,7 @@ func (x *TrustBundleDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use TrustBundleDataSource.ProtoReflect.Descriptor instead. func (*TrustBundleDataSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{45} + return file_ateapi_proto_rawDescGZIP(), []int{47} } func (x *TrustBundleDataSource) GetNames() []string { @@ -4019,14 +4264,30 @@ type VolumeMount struct { // +k8s:required // +k8s:maxLength=4096 // +k8s:customValidation # clean-absolute-path shape; no regex/pattern tag exists - MountPath string `protobuf:"bytes,2,opt,name=mount_path,json=mountPath,proto3" json:"mount_path,omitempty"` + MountPath string `protobuf:"bytes,2,opt,name=mount_path,json=mountPath,proto3" json:"mount_path,omitempty"` + // sub_path is the directory of the volume to mount, relative to its root; + // empty mounts the root. It must be a clean relative path: no leading '/', + // no '.' or '..' element, no '//', no trailing '/' and no control + // characters. Only an existing volume's mount may set it. The directory + // must exist, and no element of it may be a symbolic link: a mount that + // would need either fails. + // + // +k8s:optional + // +k8s:maxLength=4096 + // +k8s:customValidation # clean relative path + SubPath string `protobuf:"bytes,10001,opt,name=sub_path,json=subPath,proto3" json:"sub_path,omitempty"` + // read_only mounts the volume read-only. Only an existing volume's mount + // may set it. + // + // +k8s:optional + ReadOnly bool `protobuf:"varint,10002,opt,name=read_only,json=readOnly,proto3" json:"read_only,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *VolumeMount) Reset() { *x = VolumeMount{} - mi := &file_ateapi_proto_msgTypes[46] + mi := &file_ateapi_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4038,7 +4299,7 @@ func (x *VolumeMount) String() string { func (*VolumeMount) ProtoMessage() {} func (x *VolumeMount) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[46] + mi := &file_ateapi_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4051,7 +4312,7 @@ func (x *VolumeMount) ProtoReflect() protoreflect.Message { // Deprecated: Use VolumeMount.ProtoReflect.Descriptor instead. func (*VolumeMount) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{46} + return file_ateapi_proto_rawDescGZIP(), []int{48} } func (x *VolumeMount) GetName() string { @@ -4068,6 +4329,20 @@ func (x *VolumeMount) GetMountPath() string { return "" } +func (x *VolumeMount) GetSubPath() string { + if x != nil { + return x.SubPath + } + return "" +} + +func (x *VolumeMount) GetReadOnly() bool { + if x != nil { + return x.ReadOnly + } + return false +} + type CreateAtespaceRequest struct { state protoimpl.MessageState `protogen:"open.v1"` // The atespace to create. @@ -4080,7 +4355,7 @@ type CreateAtespaceRequest struct { func (x *CreateAtespaceRequest) Reset() { *x = CreateAtespaceRequest{} - mi := &file_ateapi_proto_msgTypes[47] + mi := &file_ateapi_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4092,7 +4367,7 @@ func (x *CreateAtespaceRequest) String() string { func (*CreateAtespaceRequest) ProtoMessage() {} func (x *CreateAtespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[47] + mi := &file_ateapi_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4105,7 +4380,7 @@ func (x *CreateAtespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateAtespaceRequest.ProtoReflect.Descriptor instead. func (*CreateAtespaceRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{47} + return file_ateapi_proto_rawDescGZIP(), []int{49} } func (x *CreateAtespaceRequest) GetAtespace() *Atespace { @@ -4126,7 +4401,7 @@ type GetAtespaceRequest struct { func (x *GetAtespaceRequest) Reset() { *x = GetAtespaceRequest{} - mi := &file_ateapi_proto_msgTypes[48] + mi := &file_ateapi_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4138,7 +4413,7 @@ func (x *GetAtespaceRequest) String() string { func (*GetAtespaceRequest) ProtoMessage() {} func (x *GetAtespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[48] + mi := &file_ateapi_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4151,7 +4426,7 @@ func (x *GetAtespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAtespaceRequest.ProtoReflect.Descriptor instead. func (*GetAtespaceRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{48} + return file_ateapi_proto_rawDescGZIP(), []int{50} } func (x *GetAtespaceRequest) GetAtespace() *ObjectRef { @@ -4182,7 +4457,7 @@ type ListAtespacesRequest struct { func (x *ListAtespacesRequest) Reset() { *x = ListAtespacesRequest{} - mi := &file_ateapi_proto_msgTypes[49] + mi := &file_ateapi_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4194,7 +4469,7 @@ func (x *ListAtespacesRequest) String() string { func (*ListAtespacesRequest) ProtoMessage() {} func (x *ListAtespacesRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[49] + mi := &file_ateapi_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4207,7 +4482,7 @@ func (x *ListAtespacesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAtespacesRequest.ProtoReflect.Descriptor instead. func (*ListAtespacesRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{49} + return file_ateapi_proto_rawDescGZIP(), []int{51} } func (x *ListAtespacesRequest) GetPageSize() int32 { @@ -4236,7 +4511,7 @@ type ListAtespacesResponse struct { func (x *ListAtespacesResponse) Reset() { *x = ListAtespacesResponse{} - mi := &file_ateapi_proto_msgTypes[50] + mi := &file_ateapi_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4248,7 +4523,7 @@ func (x *ListAtespacesResponse) String() string { func (*ListAtespacesResponse) ProtoMessage() {} func (x *ListAtespacesResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[50] + mi := &file_ateapi_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4261,7 +4536,7 @@ func (x *ListAtespacesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAtespacesResponse.ProtoReflect.Descriptor instead. func (*ListAtespacesResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{50} + return file_ateapi_proto_rawDescGZIP(), []int{52} } func (x *ListAtespacesResponse) GetAtespaces() []*Atespace { @@ -4293,7 +4568,7 @@ type DeleteAtespaceRequest struct { func (x *DeleteAtespaceRequest) Reset() { *x = DeleteAtespaceRequest{} - mi := &file_ateapi_proto_msgTypes[51] + mi := &file_ateapi_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4305,7 +4580,7 @@ func (x *DeleteAtespaceRequest) String() string { func (*DeleteAtespaceRequest) ProtoMessage() {} func (x *DeleteAtespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[51] + mi := &file_ateapi_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4318,7 +4593,7 @@ func (x *DeleteAtespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteAtespaceRequest.ProtoReflect.Descriptor instead. func (*DeleteAtespaceRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{51} + return file_ateapi_proto_rawDescGZIP(), []int{53} } func (x *DeleteAtespaceRequest) GetAtespace() *ObjectRef { @@ -4349,7 +4624,7 @@ type CreateActorTemplateRequest struct { func (x *CreateActorTemplateRequest) Reset() { *x = CreateActorTemplateRequest{} - mi := &file_ateapi_proto_msgTypes[52] + mi := &file_ateapi_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4361,7 +4636,7 @@ func (x *CreateActorTemplateRequest) String() string { func (*CreateActorTemplateRequest) ProtoMessage() {} func (x *CreateActorTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[52] + mi := &file_ateapi_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4374,7 +4649,7 @@ func (x *CreateActorTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateActorTemplateRequest.ProtoReflect.Descriptor instead. func (*CreateActorTemplateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{52} + return file_ateapi_proto_rawDescGZIP(), []int{54} } func (x *CreateActorTemplateRequest) GetActorTemplate() *ActorTemplate { @@ -4395,7 +4670,7 @@ type GetActorTemplateRequest struct { func (x *GetActorTemplateRequest) Reset() { *x = GetActorTemplateRequest{} - mi := &file_ateapi_proto_msgTypes[53] + mi := &file_ateapi_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4407,7 +4682,7 @@ func (x *GetActorTemplateRequest) String() string { func (*GetActorTemplateRequest) ProtoMessage() {} func (x *GetActorTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[53] + mi := &file_ateapi_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4420,7 +4695,7 @@ func (x *GetActorTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorTemplateRequest.ProtoReflect.Descriptor instead. func (*GetActorTemplateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{53} + return file_ateapi_proto_rawDescGZIP(), []int{55} } func (x *GetActorTemplateRequest) GetActorTemplate() *ObjectRef { @@ -4457,7 +4732,7 @@ type ListActorTemplatesRequest struct { func (x *ListActorTemplatesRequest) Reset() { *x = ListActorTemplatesRequest{} - mi := &file_ateapi_proto_msgTypes[54] + mi := &file_ateapi_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4469,7 +4744,7 @@ func (x *ListActorTemplatesRequest) String() string { func (*ListActorTemplatesRequest) ProtoMessage() {} func (x *ListActorTemplatesRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[54] + mi := &file_ateapi_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4482,7 +4757,7 @@ func (x *ListActorTemplatesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorTemplatesRequest.ProtoReflect.Descriptor instead. func (*ListActorTemplatesRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{54} + return file_ateapi_proto_rawDescGZIP(), []int{56} } func (x *ListActorTemplatesRequest) GetAtespace() string { @@ -4519,7 +4794,7 @@ type ListActorTemplatesResponse struct { func (x *ListActorTemplatesResponse) Reset() { *x = ListActorTemplatesResponse{} - mi := &file_ateapi_proto_msgTypes[55] + mi := &file_ateapi_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4531,7 +4806,7 @@ func (x *ListActorTemplatesResponse) String() string { func (*ListActorTemplatesResponse) ProtoMessage() {} func (x *ListActorTemplatesResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[55] + mi := &file_ateapi_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4544,7 +4819,7 @@ func (x *ListActorTemplatesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorTemplatesResponse.ProtoReflect.Descriptor instead. func (*ListActorTemplatesResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{55} + return file_ateapi_proto_rawDescGZIP(), []int{57} } func (x *ListActorTemplatesResponse) GetActorTemplates() []*ActorTemplate { @@ -4576,7 +4851,7 @@ type DeleteActorTemplateRequest struct { func (x *DeleteActorTemplateRequest) Reset() { *x = DeleteActorTemplateRequest{} - mi := &file_ateapi_proto_msgTypes[56] + mi := &file_ateapi_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4588,7 +4863,7 @@ func (x *DeleteActorTemplateRequest) String() string { func (*DeleteActorTemplateRequest) ProtoMessage() {} func (x *DeleteActorTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[56] + mi := &file_ateapi_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4601,7 +4876,7 @@ func (x *DeleteActorTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteActorTemplateRequest.ProtoReflect.Descriptor instead. func (*DeleteActorTemplateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{56} + return file_ateapi_proto_rawDescGZIP(), []int{58} } func (x *DeleteActorTemplateRequest) GetActorTemplate() *ObjectRef { @@ -4629,7 +4904,7 @@ type GetActorRequest struct { func (x *GetActorRequest) Reset() { *x = GetActorRequest{} - mi := &file_ateapi_proto_msgTypes[57] + mi := &file_ateapi_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4641,7 +4916,7 @@ func (x *GetActorRequest) String() string { func (*GetActorRequest) ProtoMessage() {} func (x *GetActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[57] + mi := &file_ateapi_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4654,7 +4929,7 @@ func (x *GetActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorRequest.ProtoReflect.Descriptor instead. func (*GetActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{57} + return file_ateapi_proto_rawDescGZIP(), []int{59} } func (x *GetActorRequest) GetActor() *ObjectRef { @@ -4677,7 +4952,7 @@ type CreateActorRequest struct { func (x *CreateActorRequest) Reset() { *x = CreateActorRequest{} - mi := &file_ateapi_proto_msgTypes[58] + mi := &file_ateapi_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4689,7 +4964,7 @@ func (x *CreateActorRequest) String() string { func (*CreateActorRequest) ProtoMessage() {} func (x *CreateActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[58] + mi := &file_ateapi_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4702,7 +4977,7 @@ func (x *CreateActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateActorRequest.ProtoReflect.Descriptor instead. func (*CreateActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{58} + return file_ateapi_proto_rawDescGZIP(), []int{60} } func (x *CreateActorRequest) GetActor() *Actor { @@ -4733,7 +5008,7 @@ type UpdateActorRequest struct { func (x *UpdateActorRequest) Reset() { *x = UpdateActorRequest{} - mi := &file_ateapi_proto_msgTypes[59] + mi := &file_ateapi_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4745,7 +5020,7 @@ func (x *UpdateActorRequest) String() string { func (*UpdateActorRequest) ProtoMessage() {} func (x *UpdateActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[59] + mi := &file_ateapi_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4758,7 +5033,7 @@ func (x *UpdateActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateActorRequest.ProtoReflect.Descriptor instead. func (*UpdateActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{59} + return file_ateapi_proto_rawDescGZIP(), []int{61} } func (x *UpdateActorRequest) GetActor() *Actor { @@ -4792,7 +5067,7 @@ type FencingToken struct { func (x *FencingToken) Reset() { *x = FencingToken{} - mi := &file_ateapi_proto_msgTypes[60] + mi := &file_ateapi_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4804,7 +5079,7 @@ func (x *FencingToken) String() string { func (*FencingToken) ProtoMessage() {} func (x *FencingToken) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[60] + mi := &file_ateapi_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4817,7 +5092,7 @@ func (x *FencingToken) ProtoReflect() protoreflect.Message { // Deprecated: Use FencingToken.ProtoReflect.Descriptor instead. func (*FencingToken) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{60} + return file_ateapi_proto_rawDescGZIP(), []int{62} } func (x *FencingToken) GetHolder() string { @@ -4852,7 +5127,7 @@ type SuspendActorRequest struct { func (x *SuspendActorRequest) Reset() { *x = SuspendActorRequest{} - mi := &file_ateapi_proto_msgTypes[61] + mi := &file_ateapi_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4864,7 +5139,7 @@ func (x *SuspendActorRequest) String() string { func (*SuspendActorRequest) ProtoMessage() {} func (x *SuspendActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[61] + mi := &file_ateapi_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4877,7 +5152,7 @@ func (x *SuspendActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SuspendActorRequest.ProtoReflect.Descriptor instead. func (*SuspendActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{61} + return file_ateapi_proto_rawDescGZIP(), []int{63} } func (x *SuspendActorRequest) GetActor() *ObjectRef { @@ -4903,7 +5178,7 @@ type SuspendActorResponse struct { func (x *SuspendActorResponse) Reset() { *x = SuspendActorResponse{} - mi := &file_ateapi_proto_msgTypes[62] + mi := &file_ateapi_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4915,7 +5190,7 @@ func (x *SuspendActorResponse) String() string { func (*SuspendActorResponse) ProtoMessage() {} func (x *SuspendActorResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[62] + mi := &file_ateapi_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4928,7 +5203,7 @@ func (x *SuspendActorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SuspendActorResponse.ProtoReflect.Descriptor instead. func (*SuspendActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{62} + return file_ateapi_proto_rawDescGZIP(), []int{64} } func (x *SuspendActorResponse) GetActor() *Actor { @@ -4956,7 +5231,7 @@ type PauseActorRequest struct { func (x *PauseActorRequest) Reset() { *x = PauseActorRequest{} - mi := &file_ateapi_proto_msgTypes[63] + mi := &file_ateapi_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4968,7 +5243,7 @@ func (x *PauseActorRequest) String() string { func (*PauseActorRequest) ProtoMessage() {} func (x *PauseActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[63] + mi := &file_ateapi_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4981,7 +5256,7 @@ func (x *PauseActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PauseActorRequest.ProtoReflect.Descriptor instead. func (*PauseActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{63} + return file_ateapi_proto_rawDescGZIP(), []int{65} } func (x *PauseActorRequest) GetActor() *ObjectRef { @@ -5007,7 +5282,7 @@ type PauseActorResponse struct { func (x *PauseActorResponse) Reset() { *x = PauseActorResponse{} - mi := &file_ateapi_proto_msgTypes[64] + mi := &file_ateapi_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5019,7 +5294,7 @@ func (x *PauseActorResponse) String() string { func (*PauseActorResponse) ProtoMessage() {} func (x *PauseActorResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[64] + mi := &file_ateapi_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5032,7 +5307,7 @@ func (x *PauseActorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PauseActorResponse.ProtoReflect.Descriptor instead. func (*PauseActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{64} + return file_ateapi_proto_rawDescGZIP(), []int{66} } func (x *PauseActorResponse) GetActor() *Actor { @@ -5060,7 +5335,7 @@ type ResumeActorRequest struct { func (x *ResumeActorRequest) Reset() { *x = ResumeActorRequest{} - mi := &file_ateapi_proto_msgTypes[65] + mi := &file_ateapi_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5072,7 +5347,7 @@ func (x *ResumeActorRequest) String() string { func (*ResumeActorRequest) ProtoMessage() {} func (x *ResumeActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[65] + mi := &file_ateapi_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5085,7 +5360,7 @@ func (x *ResumeActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ResumeActorRequest.ProtoReflect.Descriptor instead. func (*ResumeActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{65} + return file_ateapi_proto_rawDescGZIP(), []int{67} } func (x *ResumeActorRequest) GetActor() *ObjectRef { @@ -5114,7 +5389,7 @@ type ResumeActorResponse struct { func (x *ResumeActorResponse) Reset() { *x = ResumeActorResponse{} - mi := &file_ateapi_proto_msgTypes[66] + mi := &file_ateapi_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5126,7 +5401,7 @@ func (x *ResumeActorResponse) String() string { func (*ResumeActorResponse) ProtoMessage() {} func (x *ResumeActorResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[66] + mi := &file_ateapi_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5139,7 +5414,7 @@ func (x *ResumeActorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ResumeActorResponse.ProtoReflect.Descriptor instead. func (*ResumeActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{66} + return file_ateapi_proto_rawDescGZIP(), []int{68} } func (x *ResumeActorResponse) GetActor() *Actor { @@ -5169,7 +5444,7 @@ type RevertActorRequest struct { func (x *RevertActorRequest) Reset() { *x = RevertActorRequest{} - mi := &file_ateapi_proto_msgTypes[67] + mi := &file_ateapi_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5181,7 +5456,7 @@ func (x *RevertActorRequest) String() string { func (*RevertActorRequest) ProtoMessage() {} func (x *RevertActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[67] + mi := &file_ateapi_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5194,7 +5469,7 @@ func (x *RevertActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RevertActorRequest.ProtoReflect.Descriptor instead. func (*RevertActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{67} + return file_ateapi_proto_rawDescGZIP(), []int{69} } func (x *RevertActorRequest) GetActor() *ObjectRef { @@ -5216,7 +5491,7 @@ type RevertActorResponse struct { func (x *RevertActorResponse) Reset() { *x = RevertActorResponse{} - mi := &file_ateapi_proto_msgTypes[68] + mi := &file_ateapi_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5228,7 +5503,7 @@ func (x *RevertActorResponse) String() string { func (*RevertActorResponse) ProtoMessage() {} func (x *RevertActorResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[68] + mi := &file_ateapi_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5241,7 +5516,7 @@ func (x *RevertActorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RevertActorResponse.ProtoReflect.Descriptor instead. func (*RevertActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{68} + return file_ateapi_proto_rawDescGZIP(), []int{70} } func (x *RevertActorResponse) GetActor() *Actor { @@ -5270,7 +5545,7 @@ type DeleteActorRequest struct { func (x *DeleteActorRequest) Reset() { *x = DeleteActorRequest{} - mi := &file_ateapi_proto_msgTypes[69] + mi := &file_ateapi_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5282,7 +5557,7 @@ func (x *DeleteActorRequest) String() string { func (*DeleteActorRequest) ProtoMessage() {} func (x *DeleteActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[69] + mi := &file_ateapi_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5295,7 +5570,7 @@ func (x *DeleteActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteActorRequest.ProtoReflect.Descriptor instead. func (*DeleteActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{69} + return file_ateapi_proto_rawDescGZIP(), []int{71} } func (x *DeleteActorRequest) GetActor() *ObjectRef { @@ -5333,7 +5608,7 @@ type GetActorEgressPolicyRequest struct { func (x *GetActorEgressPolicyRequest) Reset() { *x = GetActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[70] + mi := &file_ateapi_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5345,7 +5620,7 @@ func (x *GetActorEgressPolicyRequest) String() string { func (*GetActorEgressPolicyRequest) ProtoMessage() {} func (x *GetActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[70] + mi := &file_ateapi_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5358,7 +5633,7 @@ func (x *GetActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*GetActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{70} + return file_ateapi_proto_rawDescGZIP(), []int{72} } func (x *GetActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -5389,7 +5664,7 @@ type CreateActorEgressPolicyRequest struct { func (x *CreateActorEgressPolicyRequest) Reset() { *x = CreateActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[71] + mi := &file_ateapi_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5401,7 +5676,7 @@ func (x *CreateActorEgressPolicyRequest) String() string { func (*CreateActorEgressPolicyRequest) ProtoMessage() {} func (x *CreateActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[71] + mi := &file_ateapi_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5414,7 +5689,7 @@ func (x *CreateActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*CreateActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{71} + return file_ateapi_proto_rawDescGZIP(), []int{73} } func (x *CreateActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -5452,7 +5727,7 @@ type UpdateActorEgressPolicyRequest struct { func (x *UpdateActorEgressPolicyRequest) Reset() { *x = UpdateActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[72] + mi := &file_ateapi_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5464,7 +5739,7 @@ func (x *UpdateActorEgressPolicyRequest) String() string { func (*UpdateActorEgressPolicyRequest) ProtoMessage() {} func (x *UpdateActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[72] + mi := &file_ateapi_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5477,7 +5752,7 @@ func (x *UpdateActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*UpdateActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{72} + return file_ateapi_proto_rawDescGZIP(), []int{74} } func (x *UpdateActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -5512,7 +5787,7 @@ type DeleteActorEgressPolicyRequest struct { func (x *DeleteActorEgressPolicyRequest) Reset() { *x = DeleteActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[73] + mi := &file_ateapi_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5524,7 +5799,7 @@ func (x *DeleteActorEgressPolicyRequest) String() string { func (*DeleteActorEgressPolicyRequest) ProtoMessage() {} func (x *DeleteActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[73] + mi := &file_ateapi_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5537,7 +5812,7 @@ func (x *DeleteActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*DeleteActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{73} + return file_ateapi_proto_rawDescGZIP(), []int{75} } func (x *DeleteActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -5564,7 +5839,7 @@ type GetEgressPolicyContractRequest struct { func (x *GetEgressPolicyContractRequest) Reset() { *x = GetEgressPolicyContractRequest{} - mi := &file_ateapi_proto_msgTypes[74] + mi := &file_ateapi_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5576,7 +5851,7 @@ func (x *GetEgressPolicyContractRequest) String() string { func (*GetEgressPolicyContractRequest) ProtoMessage() {} func (x *GetEgressPolicyContractRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[74] + mi := &file_ateapi_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5589,7 +5864,7 @@ func (x *GetEgressPolicyContractRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetEgressPolicyContractRequest.ProtoReflect.Descriptor instead. func (*GetEgressPolicyContractRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{74} + return file_ateapi_proto_rawDescGZIP(), []int{76} } // EgressPolicyContract names the egress policy contract a server speaks. @@ -5605,7 +5880,7 @@ type EgressPolicyContract struct { func (x *EgressPolicyContract) Reset() { *x = EgressPolicyContract{} - mi := &file_ateapi_proto_msgTypes[75] + mi := &file_ateapi_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5617,7 +5892,7 @@ func (x *EgressPolicyContract) String() string { func (*EgressPolicyContract) ProtoMessage() {} func (x *EgressPolicyContract) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[75] + mi := &file_ateapi_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5630,7 +5905,7 @@ func (x *EgressPolicyContract) ProtoReflect() protoreflect.Message { // Deprecated: Use EgressPolicyContract.ProtoReflect.Descriptor instead. func (*EgressPolicyContract) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{75} + return file_ateapi_proto_rawDescGZIP(), []int{77} } func (x *EgressPolicyContract) GetVersion() string { @@ -5651,7 +5926,7 @@ type GetTagRequest struct { func (x *GetTagRequest) Reset() { *x = GetTagRequest{} - mi := &file_ateapi_proto_msgTypes[76] + mi := &file_ateapi_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5663,7 +5938,7 @@ func (x *GetTagRequest) String() string { func (*GetTagRequest) ProtoMessage() {} func (x *GetTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[76] + mi := &file_ateapi_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5676,7 +5951,7 @@ func (x *GetTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTagRequest.ProtoReflect.Descriptor instead. func (*GetTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{76} + return file_ateapi_proto_rawDescGZIP(), []int{78} } func (x *GetTagRequest) GetTag() *ObjectRef { @@ -5721,7 +5996,7 @@ type MintActorJWTRequest struct { func (x *MintActorJWTRequest) Reset() { *x = MintActorJWTRequest{} - mi := &file_ateapi_proto_msgTypes[77] + mi := &file_ateapi_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5733,7 +6008,7 @@ func (x *MintActorJWTRequest) String() string { func (*MintActorJWTRequest) ProtoMessage() {} func (x *MintActorJWTRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[77] + mi := &file_ateapi_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5746,7 +6021,7 @@ func (x *MintActorJWTRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorJWTRequest.ProtoReflect.Descriptor instead. func (*MintActorJWTRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{77} + return file_ateapi_proto_rawDescGZIP(), []int{79} } func (x *MintActorJWTRequest) GetActor() *ObjectRef { @@ -5803,7 +6078,7 @@ type MintActorJWTResponse struct { func (x *MintActorJWTResponse) Reset() { *x = MintActorJWTResponse{} - mi := &file_ateapi_proto_msgTypes[78] + mi := &file_ateapi_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5815,7 +6090,7 @@ func (x *MintActorJWTResponse) String() string { func (*MintActorJWTResponse) ProtoMessage() {} func (x *MintActorJWTResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[78] + mi := &file_ateapi_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5828,7 +6103,7 @@ func (x *MintActorJWTResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorJWTResponse.ProtoReflect.Descriptor instead. func (*MintActorJWTResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{78} + return file_ateapi_proto_rawDescGZIP(), []int{80} } func (x *MintActorJWTResponse) GetActorJwt() string { @@ -5873,7 +6148,7 @@ type MintActorCertificateRequest struct { func (x *MintActorCertificateRequest) Reset() { *x = MintActorCertificateRequest{} - mi := &file_ateapi_proto_msgTypes[79] + mi := &file_ateapi_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5885,7 +6160,7 @@ func (x *MintActorCertificateRequest) String() string { func (*MintActorCertificateRequest) ProtoMessage() {} func (x *MintActorCertificateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[79] + mi := &file_ateapi_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5898,7 +6173,7 @@ func (x *MintActorCertificateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorCertificateRequest.ProtoReflect.Descriptor instead. func (*MintActorCertificateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{79} + return file_ateapi_proto_rawDescGZIP(), []int{81} } func (x *MintActorCertificateRequest) GetActor() *ObjectRef { @@ -5935,7 +6210,7 @@ type MintActorCertificateResponse struct { func (x *MintActorCertificateResponse) Reset() { *x = MintActorCertificateResponse{} - mi := &file_ateapi_proto_msgTypes[80] + mi := &file_ateapi_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5947,7 +6222,7 @@ func (x *MintActorCertificateResponse) String() string { func (*MintActorCertificateResponse) ProtoMessage() {} func (x *MintActorCertificateResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[80] + mi := &file_ateapi_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5960,7 +6235,7 @@ func (x *MintActorCertificateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorCertificateResponse.ProtoReflect.Descriptor instead. func (*MintActorCertificateResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{80} + return file_ateapi_proto_rawDescGZIP(), []int{82} } func (x *MintActorCertificateResponse) GetActorCertificates() [][]byte { @@ -5996,7 +6271,7 @@ type ListTagsRequest struct { func (x *ListTagsRequest) Reset() { *x = ListTagsRequest{} - mi := &file_ateapi_proto_msgTypes[81] + mi := &file_ateapi_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6008,7 +6283,7 @@ func (x *ListTagsRequest) String() string { func (*ListTagsRequest) ProtoMessage() {} func (x *ListTagsRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[81] + mi := &file_ateapi_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6021,7 +6296,7 @@ func (x *ListTagsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListTagsRequest.ProtoReflect.Descriptor instead. func (*ListTagsRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{81} + return file_ateapi_proto_rawDescGZIP(), []int{83} } func (x *ListTagsRequest) GetAtespace() string { @@ -6055,7 +6330,7 @@ type ListTagsResponse struct { func (x *ListTagsResponse) Reset() { *x = ListTagsResponse{} - mi := &file_ateapi_proto_msgTypes[82] + mi := &file_ateapi_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6067,7 +6342,7 @@ func (x *ListTagsResponse) String() string { func (*ListTagsResponse) ProtoMessage() {} func (x *ListTagsResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[82] + mi := &file_ateapi_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6080,7 +6355,7 @@ func (x *ListTagsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListTagsResponse.ProtoReflect.Descriptor instead. func (*ListTagsResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{82} + return file_ateapi_proto_rawDescGZIP(), []int{84} } func (x *ListTagsResponse) GetTags() []*Tag { @@ -6125,7 +6400,7 @@ type CreateTagRequest struct { func (x *CreateTagRequest) Reset() { *x = CreateTagRequest{} - mi := &file_ateapi_proto_msgTypes[83] + mi := &file_ateapi_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6137,7 +6412,7 @@ func (x *CreateTagRequest) String() string { func (*CreateTagRequest) ProtoMessage() {} func (x *CreateTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[83] + mi := &file_ateapi_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6150,7 +6425,7 @@ func (x *CreateTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateTagRequest.ProtoReflect.Descriptor instead. func (*CreateTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{83} + return file_ateapi_proto_rawDescGZIP(), []int{85} } func (x *CreateTagRequest) GetTag() *Tag { @@ -6180,7 +6455,7 @@ type UpdateTagRequest struct { func (x *UpdateTagRequest) Reset() { *x = UpdateTagRequest{} - mi := &file_ateapi_proto_msgTypes[84] + mi := &file_ateapi_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6192,7 +6467,7 @@ func (x *UpdateTagRequest) String() string { func (*UpdateTagRequest) ProtoMessage() {} func (x *UpdateTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[84] + mi := &file_ateapi_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6205,7 +6480,7 @@ func (x *UpdateTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateTagRequest.ProtoReflect.Descriptor instead. func (*UpdateTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{84} + return file_ateapi_proto_rawDescGZIP(), []int{86} } func (x *UpdateTagRequest) GetTag() *Tag { @@ -6230,7 +6505,7 @@ type DeleteTagRequest struct { func (x *DeleteTagRequest) Reset() { *x = DeleteTagRequest{} - mi := &file_ateapi_proto_msgTypes[85] + mi := &file_ateapi_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6242,7 +6517,7 @@ func (x *DeleteTagRequest) String() string { func (*DeleteTagRequest) ProtoMessage() {} func (x *DeleteTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[85] + mi := &file_ateapi_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6255,7 +6530,7 @@ func (x *DeleteTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteTagRequest.ProtoReflect.Descriptor instead. func (*DeleteTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{85} + return file_ateapi_proto_rawDescGZIP(), []int{87} } func (x *DeleteTagRequest) GetTag() *ObjectRef { @@ -6294,7 +6569,7 @@ type DeleteOptions struct { func (x *DeleteOptions) Reset() { *x = DeleteOptions{} - mi := &file_ateapi_proto_msgTypes[86] + mi := &file_ateapi_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6306,7 +6581,7 @@ func (x *DeleteOptions) String() string { func (*DeleteOptions) ProtoMessage() {} func (x *DeleteOptions) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[86] + mi := &file_ateapi_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6319,7 +6594,7 @@ func (x *DeleteOptions) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteOptions.ProtoReflect.Descriptor instead. func (*DeleteOptions) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{86} + return file_ateapi_proto_rawDescGZIP(), []int{88} } func (x *DeleteOptions) GetVersion() int64 { @@ -6363,7 +6638,7 @@ type ListWorkerActorAssignmentsRequest struct { func (x *ListWorkerActorAssignmentsRequest) Reset() { *x = ListWorkerActorAssignmentsRequest{} - mi := &file_ateapi_proto_msgTypes[87] + mi := &file_ateapi_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6375,7 +6650,7 @@ func (x *ListWorkerActorAssignmentsRequest) String() string { func (*ListWorkerActorAssignmentsRequest) ProtoMessage() {} func (x *ListWorkerActorAssignmentsRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[87] + mi := &file_ateapi_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6388,7 +6663,7 @@ func (x *ListWorkerActorAssignmentsRequest) ProtoReflect() protoreflect.Message // Deprecated: Use ListWorkerActorAssignmentsRequest.ProtoReflect.Descriptor instead. func (*ListWorkerActorAssignmentsRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{87} + return file_ateapi_proto_rawDescGZIP(), []int{89} } func (x *ListWorkerActorAssignmentsRequest) GetWorker() *ObjectRef { @@ -6425,7 +6700,7 @@ type ListWorkerActorAssignmentsResponse struct { func (x *ListWorkerActorAssignmentsResponse) Reset() { *x = ListWorkerActorAssignmentsResponse{} - mi := &file_ateapi_proto_msgTypes[88] + mi := &file_ateapi_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6437,7 +6712,7 @@ func (x *ListWorkerActorAssignmentsResponse) String() string { func (*ListWorkerActorAssignmentsResponse) ProtoMessage() {} func (x *ListWorkerActorAssignmentsResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[88] + mi := &file_ateapi_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6450,7 +6725,7 @@ func (x *ListWorkerActorAssignmentsResponse) ProtoReflect() protoreflect.Message // Deprecated: Use ListWorkerActorAssignmentsResponse.ProtoReflect.Descriptor instead. func (*ListWorkerActorAssignmentsResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{88} + return file_ateapi_proto_rawDescGZIP(), []int{90} } func (x *ListWorkerActorAssignmentsResponse) GetActorAssignments() []*ActorAssignment { @@ -6488,7 +6763,7 @@ type ListWorkersRequest struct { func (x *ListWorkersRequest) Reset() { *x = ListWorkersRequest{} - mi := &file_ateapi_proto_msgTypes[89] + mi := &file_ateapi_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6500,7 +6775,7 @@ func (x *ListWorkersRequest) String() string { func (*ListWorkersRequest) ProtoMessage() {} func (x *ListWorkersRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[89] + mi := &file_ateapi_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6513,7 +6788,7 @@ func (x *ListWorkersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkersRequest.ProtoReflect.Descriptor instead. func (*ListWorkersRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{89} + return file_ateapi_proto_rawDescGZIP(), []int{91} } func (x *ListWorkersRequest) GetPageSize() int32 { @@ -6542,7 +6817,7 @@ type ListWorkersResponse struct { func (x *ListWorkersResponse) Reset() { *x = ListWorkersResponse{} - mi := &file_ateapi_proto_msgTypes[90] + mi := &file_ateapi_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6554,7 +6829,7 @@ func (x *ListWorkersResponse) String() string { func (*ListWorkersResponse) ProtoMessage() {} func (x *ListWorkersResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[90] + mi := &file_ateapi_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6567,7 +6842,7 @@ func (x *ListWorkersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkersResponse.ProtoReflect.Descriptor instead. func (*ListWorkersResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{90} + return file_ateapi_proto_rawDescGZIP(), []int{92} } func (x *ListWorkersResponse) GetWorkers() []*Worker { @@ -6597,7 +6872,7 @@ type GetWorkerRequest struct { func (x *GetWorkerRequest) Reset() { *x = GetWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[91] + mi := &file_ateapi_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6609,7 +6884,7 @@ func (x *GetWorkerRequest) String() string { func (*GetWorkerRequest) ProtoMessage() {} func (x *GetWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[91] + mi := &file_ateapi_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6622,7 +6897,7 @@ func (x *GetWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkerRequest.ProtoReflect.Descriptor instead. func (*GetWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{91} + return file_ateapi_proto_rawDescGZIP(), []int{93} } func (x *GetWorkerRequest) GetWorker() *ObjectRef { @@ -6644,7 +6919,7 @@ type CreateWorkerRequest struct { func (x *CreateWorkerRequest) Reset() { *x = CreateWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[92] + mi := &file_ateapi_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6656,7 +6931,7 @@ func (x *CreateWorkerRequest) String() string { func (*CreateWorkerRequest) ProtoMessage() {} func (x *CreateWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[92] + mi := &file_ateapi_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6669,7 +6944,7 @@ func (x *CreateWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkerRequest.ProtoReflect.Descriptor instead. func (*CreateWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{92} + return file_ateapi_proto_rawDescGZIP(), []int{94} } func (x *CreateWorkerRequest) GetWorker() *Worker { @@ -6704,7 +6979,7 @@ type UpdateWorkerRequest struct { func (x *UpdateWorkerRequest) Reset() { *x = UpdateWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[93] + mi := &file_ateapi_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6716,7 +6991,7 @@ func (x *UpdateWorkerRequest) String() string { func (*UpdateWorkerRequest) ProtoMessage() {} func (x *UpdateWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[93] + mi := &file_ateapi_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6729,7 +7004,7 @@ func (x *UpdateWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateWorkerRequest.ProtoReflect.Descriptor instead. func (*UpdateWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{93} + return file_ateapi_proto_rawDescGZIP(), []int{95} } func (x *UpdateWorkerRequest) GetWorker() *Worker { @@ -6756,7 +7031,7 @@ type DeleteWorkerRequest struct { func (x *DeleteWorkerRequest) Reset() { *x = DeleteWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[94] + mi := &file_ateapi_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6768,7 +7043,7 @@ func (x *DeleteWorkerRequest) String() string { func (*DeleteWorkerRequest) ProtoMessage() {} func (x *DeleteWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[94] + mi := &file_ateapi_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6781,7 +7056,7 @@ func (x *DeleteWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkerRequest.ProtoReflect.Descriptor instead. func (*DeleteWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{94} + return file_ateapi_proto_rawDescGZIP(), []int{96} } func (x *DeleteWorkerRequest) GetWorker() *ObjectRef { @@ -6811,7 +7086,7 @@ type DrainWorkerRequest struct { func (x *DrainWorkerRequest) Reset() { *x = DrainWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[95] + mi := &file_ateapi_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6823,7 +7098,7 @@ func (x *DrainWorkerRequest) String() string { func (*DrainWorkerRequest) ProtoMessage() {} func (x *DrainWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[95] + mi := &file_ateapi_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6836,7 +7111,7 @@ func (x *DrainWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DrainWorkerRequest.ProtoReflect.Descriptor instead. func (*DrainWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{95} + return file_ateapi_proto_rawDescGZIP(), []int{97} } func (x *DrainWorkerRequest) GetWorker() *ObjectRef { @@ -6874,7 +7149,7 @@ type ListActorsRequest struct { func (x *ListActorsRequest) Reset() { *x = ListActorsRequest{} - mi := &file_ateapi_proto_msgTypes[96] + mi := &file_ateapi_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6886,7 +7161,7 @@ func (x *ListActorsRequest) String() string { func (*ListActorsRequest) ProtoMessage() {} func (x *ListActorsRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[96] + mi := &file_ateapi_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6899,7 +7174,7 @@ func (x *ListActorsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorsRequest.ProtoReflect.Descriptor instead. func (*ListActorsRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{96} + return file_ateapi_proto_rawDescGZIP(), []int{98} } func (x *ListActorsRequest) GetAtespace() string { @@ -6935,7 +7210,7 @@ type ListActorsResponse struct { func (x *ListActorsResponse) Reset() { *x = ListActorsResponse{} - mi := &file_ateapi_proto_msgTypes[97] + mi := &file_ateapi_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6947,7 +7222,7 @@ func (x *ListActorsResponse) String() string { func (*ListActorsResponse) ProtoMessage() {} func (x *ListActorsResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[97] + mi := &file_ateapi_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6960,7 +7235,7 @@ func (x *ListActorsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorsResponse.ProtoReflect.Descriptor instead. func (*ListActorsResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{97} + return file_ateapi_proto_rawDescGZIP(), []int{99} } func (x *ListActorsResponse) GetActors() []*Actor { @@ -7068,7 +7343,7 @@ type Worker struct { func (x *Worker) Reset() { *x = Worker{} - mi := &file_ateapi_proto_msgTypes[98] + mi := &file_ateapi_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7080,7 +7355,7 @@ func (x *Worker) String() string { func (*Worker) ProtoMessage() {} func (x *Worker) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[98] + mi := &file_ateapi_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7093,7 +7368,7 @@ func (x *Worker) ProtoReflect() protoreflect.Message { // Deprecated: Use Worker.ProtoReflect.Descriptor instead. func (*Worker) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{98} + return file_ateapi_proto_rawDescGZIP(), []int{100} } func (x *Worker) GetMetadata() *ResourceMetadata { @@ -7209,7 +7484,7 @@ type WorkerStatus struct { func (x *WorkerStatus) Reset() { *x = WorkerStatus{} - mi := &file_ateapi_proto_msgTypes[99] + mi := &file_ateapi_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7221,7 +7496,7 @@ func (x *WorkerStatus) String() string { func (*WorkerStatus) ProtoMessage() {} func (x *WorkerStatus) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[99] + mi := &file_ateapi_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7234,7 +7509,7 @@ func (x *WorkerStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkerStatus.ProtoReflect.Descriptor instead. func (*WorkerStatus) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{99} + return file_ateapi_proto_rawDescGZIP(), []int{101} } func (x *WorkerStatus) GetState() WorkerState { @@ -7287,7 +7562,7 @@ type WorkerResources struct { func (x *WorkerResources) Reset() { *x = WorkerResources{} - mi := &file_ateapi_proto_msgTypes[100] + mi := &file_ateapi_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7299,7 +7574,7 @@ func (x *WorkerResources) String() string { func (*WorkerResources) ProtoMessage() {} func (x *WorkerResources) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[100] + mi := &file_ateapi_proto_msgTypes[102] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7312,7 +7587,7 @@ func (x *WorkerResources) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkerResources.ProtoReflect.Descriptor instead. func (*WorkerResources) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{100} + return file_ateapi_proto_rawDescGZIP(), []int{102} } func (x *WorkerResources) GetResources() *Resources { @@ -7371,7 +7646,7 @@ type ActorAssignment struct { func (x *ActorAssignment) Reset() { *x = ActorAssignment{} - mi := &file_ateapi_proto_msgTypes[101] + mi := &file_ateapi_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7383,7 +7658,7 @@ func (x *ActorAssignment) String() string { func (*ActorAssignment) ProtoMessage() {} func (x *ActorAssignment) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[101] + mi := &file_ateapi_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7396,7 +7671,7 @@ func (x *ActorAssignment) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorAssignment.ProtoReflect.Descriptor instead. func (*ActorAssignment) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{101} + return file_ateapi_proto_rawDescGZIP(), []int{103} } func (x *ActorAssignment) GetMetadata() *ResourceMetadata { @@ -7461,7 +7736,7 @@ type SetWorkerCapacityRequest struct { func (x *SetWorkerCapacityRequest) Reset() { *x = SetWorkerCapacityRequest{} - mi := &file_ateapi_proto_msgTypes[102] + mi := &file_ateapi_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7473,7 +7748,7 @@ func (x *SetWorkerCapacityRequest) String() string { func (*SetWorkerCapacityRequest) ProtoMessage() {} func (x *SetWorkerCapacityRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[102] + mi := &file_ateapi_proto_msgTypes[104] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7486,7 +7761,7 @@ func (x *SetWorkerCapacityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SetWorkerCapacityRequest.ProtoReflect.Descriptor instead. func (*SetWorkerCapacityRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{102} + return file_ateapi_proto_rawDescGZIP(), []int{104} } func (x *SetWorkerCapacityRequest) GetWorker() *ObjectRef { @@ -7513,7 +7788,7 @@ type SetWorkerCapacityResponse struct { func (x *SetWorkerCapacityResponse) Reset() { *x = SetWorkerCapacityResponse{} - mi := &file_ateapi_proto_msgTypes[103] + mi := &file_ateapi_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7525,7 +7800,7 @@ func (x *SetWorkerCapacityResponse) String() string { func (*SetWorkerCapacityResponse) ProtoMessage() {} func (x *SetWorkerCapacityResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[103] + mi := &file_ateapi_proto_msgTypes[105] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7538,7 +7813,7 @@ func (x *SetWorkerCapacityResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SetWorkerCapacityResponse.ProtoReflect.Descriptor instead. func (*SetWorkerCapacityResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{103} + return file_ateapi_proto_rawDescGZIP(), []int{105} } func (x *SetWorkerCapacityResponse) GetWorker() *Worker { @@ -7577,7 +7852,7 @@ type MintAteomActorCertificateRequest struct { func (x *MintAteomActorCertificateRequest) Reset() { *x = MintAteomActorCertificateRequest{} - mi := &file_ateapi_proto_msgTypes[104] + mi := &file_ateapi_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7589,7 +7864,7 @@ func (x *MintAteomActorCertificateRequest) String() string { func (*MintAteomActorCertificateRequest) ProtoMessage() {} func (x *MintAteomActorCertificateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[104] + mi := &file_ateapi_proto_msgTypes[106] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7602,7 +7877,7 @@ func (x *MintAteomActorCertificateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintAteomActorCertificateRequest.ProtoReflect.Descriptor instead. func (*MintAteomActorCertificateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{104} + return file_ateapi_proto_rawDescGZIP(), []int{106} } func (x *MintAteomActorCertificateRequest) GetActor() *ObjectRef { @@ -7639,7 +7914,7 @@ type MintAteomActorCertificateResponse struct { func (x *MintAteomActorCertificateResponse) Reset() { *x = MintAteomActorCertificateResponse{} - mi := &file_ateapi_proto_msgTypes[105] + mi := &file_ateapi_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7651,7 +7926,7 @@ func (x *MintAteomActorCertificateResponse) String() string { func (*MintAteomActorCertificateResponse) ProtoMessage() {} func (x *MintAteomActorCertificateResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[105] + mi := &file_ateapi_proto_msgTypes[107] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7664,7 +7939,7 @@ func (x *MintAteomActorCertificateResponse) ProtoReflect() protoreflect.Message // Deprecated: Use MintAteomActorCertificateResponse.ProtoReflect.Descriptor instead. func (*MintAteomActorCertificateResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{105} + return file_ateapi_proto_rawDescGZIP(), []int{107} } func (x *MintAteomActorCertificateResponse) GetActorCertificates() [][]byte { @@ -7702,7 +7977,7 @@ type RequestActorSuspendRequest struct { func (x *RequestActorSuspendRequest) Reset() { *x = RequestActorSuspendRequest{} - mi := &file_ateapi_proto_msgTypes[106] + mi := &file_ateapi_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7714,7 +7989,7 @@ func (x *RequestActorSuspendRequest) String() string { func (*RequestActorSuspendRequest) ProtoMessage() {} func (x *RequestActorSuspendRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[106] + mi := &file_ateapi_proto_msgTypes[108] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7727,7 +8002,7 @@ func (x *RequestActorSuspendRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestActorSuspendRequest.ProtoReflect.Descriptor instead. func (*RequestActorSuspendRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{106} + return file_ateapi_proto_rawDescGZIP(), []int{108} } func (x *RequestActorSuspendRequest) GetWorker() *ObjectRef { @@ -7761,7 +8036,7 @@ type RequestActorSuspendResponse struct { func (x *RequestActorSuspendResponse) Reset() { *x = RequestActorSuspendResponse{} - mi := &file_ateapi_proto_msgTypes[107] + mi := &file_ateapi_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7773,7 +8048,7 @@ func (x *RequestActorSuspendResponse) String() string { func (*RequestActorSuspendResponse) ProtoMessage() {} func (x *RequestActorSuspendResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[107] + mi := &file_ateapi_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7786,7 +8061,7 @@ func (x *RequestActorSuspendResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestActorSuspendResponse.ProtoReflect.Descriptor instead. func (*RequestActorSuspendResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{107} + return file_ateapi_proto_rawDescGZIP(), []int{109} } func (x *RequestActorSuspendResponse) GetActor() *Actor { @@ -7821,7 +8096,7 @@ type AccessPolicy struct { func (x *AccessPolicy) Reset() { *x = AccessPolicy{} - mi := &file_ateapi_proto_msgTypes[108] + mi := &file_ateapi_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7833,7 +8108,7 @@ func (x *AccessPolicy) String() string { func (*AccessPolicy) ProtoMessage() {} func (x *AccessPolicy) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[108] + mi := &file_ateapi_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7846,7 +8121,7 @@ func (x *AccessPolicy) ProtoReflect() protoreflect.Message { // Deprecated: Use AccessPolicy.ProtoReflect.Descriptor instead. func (*AccessPolicy) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{108} + return file_ateapi_proto_rawDescGZIP(), []int{110} } func (x *AccessPolicy) GetMetadata() *ResourceMetadata { @@ -7888,7 +8163,7 @@ type Binding struct { func (x *Binding) Reset() { *x = Binding{} - mi := &file_ateapi_proto_msgTypes[109] + mi := &file_ateapi_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7900,7 +8175,7 @@ func (x *Binding) String() string { func (*Binding) ProtoMessage() {} func (x *Binding) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[109] + mi := &file_ateapi_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7913,7 +8188,7 @@ func (x *Binding) ProtoReflect() protoreflect.Message { // Deprecated: Use Binding.ProtoReflect.Descriptor instead. func (*Binding) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{109} + return file_ateapi_proto_rawDescGZIP(), []int{111} } func (x *Binding) GetRole() string { @@ -7939,7 +8214,7 @@ type GetGlobalAccessPolicyRequest struct { func (x *GetGlobalAccessPolicyRequest) Reset() { *x = GetGlobalAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[110] + mi := &file_ateapi_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7951,7 +8226,7 @@ func (x *GetGlobalAccessPolicyRequest) String() string { func (*GetGlobalAccessPolicyRequest) ProtoMessage() {} func (x *GetGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[110] + mi := &file_ateapi_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7964,7 +8239,7 @@ func (x *GetGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGlobalAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*GetGlobalAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{110} + return file_ateapi_proto_rawDescGZIP(), []int{112} } // CreateGlobalAccessPolicyRequest creates the deployment-wide global access policy singleton. @@ -7981,7 +8256,7 @@ type CreateGlobalAccessPolicyRequest struct { func (x *CreateGlobalAccessPolicyRequest) Reset() { *x = CreateGlobalAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[111] + mi := &file_ateapi_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7993,7 +8268,7 @@ func (x *CreateGlobalAccessPolicyRequest) String() string { func (*CreateGlobalAccessPolicyRequest) ProtoMessage() {} func (x *CreateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[111] + mi := &file_ateapi_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8006,7 +8281,7 @@ func (x *CreateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateGlobalAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*CreateGlobalAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{111} + return file_ateapi_proto_rawDescGZIP(), []int{113} } func (x *CreateGlobalAccessPolicyRequest) GetAccessPolicy() *AccessPolicy { @@ -8030,7 +8305,7 @@ type UpdateGlobalAccessPolicyRequest struct { func (x *UpdateGlobalAccessPolicyRequest) Reset() { *x = UpdateGlobalAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[112] + mi := &file_ateapi_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8042,7 +8317,7 @@ func (x *UpdateGlobalAccessPolicyRequest) String() string { func (*UpdateGlobalAccessPolicyRequest) ProtoMessage() {} func (x *UpdateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[112] + mi := &file_ateapi_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8055,7 +8330,7 @@ func (x *UpdateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateGlobalAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*UpdateGlobalAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{112} + return file_ateapi_proto_rawDescGZIP(), []int{114} } func (x *UpdateGlobalAccessPolicyRequest) GetAccessPolicy() *AccessPolicy { @@ -8079,7 +8354,7 @@ type GetAtespaceAccessPolicyRequest struct { func (x *GetAtespaceAccessPolicyRequest) Reset() { *x = GetAtespaceAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[113] + mi := &file_ateapi_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8091,7 +8366,7 @@ func (x *GetAtespaceAccessPolicyRequest) String() string { func (*GetAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *GetAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[113] + mi := &file_ateapi_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8104,7 +8379,7 @@ func (x *GetAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*GetAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{113} + return file_ateapi_proto_rawDescGZIP(), []int{115} } func (x *GetAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -8133,7 +8408,7 @@ type CreateAtespaceAccessPolicyRequest struct { func (x *CreateAtespaceAccessPolicyRequest) Reset() { *x = CreateAtespaceAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[114] + mi := &file_ateapi_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8145,7 +8420,7 @@ func (x *CreateAtespaceAccessPolicyRequest) String() string { func (*CreateAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *CreateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[114] + mi := &file_ateapi_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8158,7 +8433,7 @@ func (x *CreateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message // Deprecated: Use CreateAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*CreateAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{114} + return file_ateapi_proto_rawDescGZIP(), []int{116} } func (x *CreateAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -8194,7 +8469,7 @@ type UpdateAtespaceAccessPolicyRequest struct { func (x *UpdateAtespaceAccessPolicyRequest) Reset() { *x = UpdateAtespaceAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[115] + mi := &file_ateapi_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8206,7 +8481,7 @@ func (x *UpdateAtespaceAccessPolicyRequest) String() string { func (*UpdateAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *UpdateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[115] + mi := &file_ateapi_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8219,7 +8494,7 @@ func (x *UpdateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message // Deprecated: Use UpdateAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*UpdateAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{115} + return file_ateapi_proto_rawDescGZIP(), []int{117} } func (x *UpdateAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -8254,7 +8529,7 @@ type DeleteAtespaceAccessPolicyRequest struct { func (x *DeleteAtespaceAccessPolicyRequest) Reset() { *x = DeleteAtespaceAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[116] + mi := &file_ateapi_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8266,7 +8541,7 @@ func (x *DeleteAtespaceAccessPolicyRequest) String() string { func (*DeleteAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *DeleteAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[116] + mi := &file_ateapi_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8279,7 +8554,7 @@ func (x *DeleteAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message // Deprecated: Use DeleteAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*DeleteAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{116} + return file_ateapi_proto_rawDescGZIP(), []int{118} } func (x *DeleteAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -8340,14 +8615,22 @@ const file_ateapi_proto_rawDesc = "" + "\x12STATUS_UNSPECIFIED\x10\x00\x12\x12\n" + "\x0eSTATUS_PENDING\x10\x01\x12\x12\n" + "\x0eSTATUS_CREATED\x10\x02\x12\x13\n" + - "\x0fSTATUS_DELETING\x10\x03\"\x91\x02\n" + + "\x0fSTATUS_DELETING\x10\x03\"\xd5\x02\n" + "\x05Actor\x124\n" + "\bmetadata\x18\x01 \x01(\v2\x18.ateapi.ResourceMetadataR\bmetadata\x128\n" + "\x0eactor_template\x18\x04 \x01(\v2\x11.ateapi.ObjectRefR\ractorTemplate\x129\n" + "\x0fworker_selector\x18\x05 \x01(\v2\x10.ateapi.SelectorR\x0eworkerSelector\x120\n" + "\n" + "source_tag\x18\x06 \x01(\v2\x11.ateapi.ObjectRefR\tsourceTag\x12+\n" + - "\x06status\x18\a \x01(\v2\x13.ateapi.ActorStatusR\x06status\"n\n" + + "\x06status\x18\a \x01(\v2\x13.ateapi.ActorStatusR\x06status\x12B\n" + + "\x10existing_volumes\x18\x91N \x03(\v2\x16.ateapi.ExistingVolumeR\x0fexistingVolumes\"\xb7\x01\n" + + "\x0eExistingVolume\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x16\n" + + "\x06driver\x18\x02 \x01(\tR\x06driver\x12#\n" + + "\rvolume_handle\x18\x03 \x01(\tR\fvolumeHandle\x129\n" + + "\vaccess_mode\x18\x04 \x01(\x0e2\x18.ateapi.VolumeAccessModeR\n" + + "accessMode\x12\x19\n" + + "\bsub_path\x18\x05 \x01(\tR\asubPath\"n\n" + "\fEgressPolicy\x124\n" + "\bmetadata\x18\x01 \x01(\v2\x18.ateapi.ResourceMetadataR\bmetadata\x12(\n" + "\x05rules\x18\x02 \x03(\v2\x12.ateapi.EgressRuleR\x05rules\"@\n" + @@ -8479,7 +8762,7 @@ const file_ateapi_proto_rawDesc = "" + "\x0ftimeout_seconds\x18\x02 \x01(\x05R\x0etimeoutSeconds\"7\n" + "\rHTTPGetAction\x12\x12\n" + "\x04path\x18\x01 \x01(\tR\x04path\x12\x12\n" + - "\x04port\x18\x02 \x01(\x05R\x04port\"\xa9\x02\n" + + "\x04port\x18\x02 \x01(\x05R\x04port\"\xf1\x02\n" + "\x06Volume\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12?\n" + "\vdurable_dir\x18\x02 \x01(\v2\x1e.ateapi.DurableDirVolumeSourceR\n" + @@ -8487,7 +8770,9 @@ const file_ateapi_proto_rawDesc = "" + "\x18external_volume_template\x18\x03 \x01(\v2\x1e.ateapi.ExternalVolumeTemplateR\x16externalVolumeTemplate\x12?\n" + "\vsystem_info\x18\x05 \x01(\v2\x1e.ateapi.SystemInfoVolumeSourceR\n" + "systemInfo\x12/\n" + - "\x05image\x18\x06 \x01(\v2\x19.ateapi.ImageVolumeSourceR\x05image\"1\n" + + "\x05image\x18\x06 \x01(\v2\x19.ateapi.ImageVolumeSourceR\x05image\x12F\n" + + "\x0fexisting_volume\x18\x91N \x01(\v2\x1c.ateapi.ExistingVolumeSourceR\x0eexistingVolume\"\x16\n" + + "\x14ExistingVolumeSource\"1\n" + "\x11ImageVolumeSource\x12\x1c\n" + "\treference\x18\x01 \x01(\tR\treference\"\x18\n" + "\x16DurableDirVolumeSource\"b\n" + @@ -8506,11 +8791,13 @@ const file_ateapi_proto_rawDesc = "" + "\x04path\x18\x02 \x01(\tR\x04path\"M\n" + "\x15TrustBundleDataSource\x12\x14\n" + "\x05names\x18\x03 \x03(\tR\x05names\x12\x12\n" + - "\x04path\x18\x02 \x01(\tR\x04pathJ\x04\b\x01\x10\x02R\x04name\"@\n" + + "\x04path\x18\x02 \x01(\tR\x04pathJ\x04\b\x01\x10\x02R\x04name\"z\n" + "\vVolumeMount\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12\x1d\n" + "\n" + - "mount_path\x18\x02 \x01(\tR\tmountPath\"E\n" + + "mount_path\x18\x02 \x01(\tR\tmountPath\x12\x1a\n" + + "\bsub_path\x18\x91N \x01(\tR\asubPath\x12\x1c\n" + + "\tread_only\x18\x92N \x01(\bR\breadOnly\"E\n" + "\x15CreateAtespaceRequest\x12,\n" + "\batespace\x18\x01 \x01(\v2\x10.ateapi.AtespaceR\batespace\"C\n" + "\x12GetAtespaceRequest\x12-\n" + @@ -8736,7 +9023,12 @@ const file_ateapi_proto_rawDesc = "" + "\bTagScope\x12\x19\n" + "\x15TAG_SCOPE_UNSPECIFIED\x10\x00\x12\x16\n" + "\x12TAG_SCOPE_ATESPACE\x10\x01\x12\x17\n" + - "\x13TAG_SCOPE_PUBLISHED\x10\x02*\x92\x02\n" + + "\x13TAG_SCOPE_PUBLISHED\x10\x02*\xad\x01\n" + + "\x10VolumeAccessMode\x12\"\n" + + "\x1eVOLUME_ACCESS_MODE_UNSPECIFIED\x10\x00\x12&\n" + + "\"VOLUME_ACCESS_MODE_READ_WRITE_ONCE\x10\x01\x12%\n" + + "!VOLUME_ACCESS_MODE_READ_ONLY_MANY\x10\x02\x12&\n" + + "\"VOLUME_ACCESS_MODE_READ_WRITE_MANY\x10\x03*\x92\x02\n" + "\n" + "ActorState\x12\x1b\n" + "\x17ACTOR_STATE_UNSPECIFIED\x10\x00\x12\x18\n" + @@ -8825,391 +9117,397 @@ func file_ateapi_proto_rawDescGZIP() []byte { return file_ateapi_proto_rawDescData } -var file_ateapi_proto_enumTypes = make([]protoimpl.EnumInfo, 7) -var file_ateapi_proto_msgTypes = make([]protoimpl.MessageInfo, 120) +var file_ateapi_proto_enumTypes = make([]protoimpl.EnumInfo, 8) +var file_ateapi_proto_msgTypes = make([]protoimpl.MessageInfo, 122) var file_ateapi_proto_goTypes = []any{ (SnapshotContentScope)(0), // 0: ateapi.SnapshotContentScope (TagScope)(0), // 1: ateapi.TagScope - (ActorState)(0), // 2: ateapi.ActorState - (SandboxClass)(0), // 3: ateapi.SandboxClass - (ActorMetadataField)(0), // 4: ateapi.ActorMetadataField - (WorkerState)(0), // 5: ateapi.WorkerState - (ExternalVolume_Status)(0), // 6: ateapi.ExternalVolume.Status - (*ExternalSnapshot)(nil), // 7: ateapi.ExternalSnapshot - (*LocalSnapshot)(nil), // 8: ateapi.LocalSnapshot - (*Selector)(nil), // 9: ateapi.Selector - (*ResourceMetadata)(nil), // 10: ateapi.ResourceMetadata - (*ExternalVolume)(nil), // 11: ateapi.ExternalVolume - (*Actor)(nil), // 12: ateapi.Actor - (*EgressPolicy)(nil), // 13: ateapi.EgressPolicy - (*EgressPolicyTemplate)(nil), // 14: ateapi.EgressPolicyTemplate - (*EgressRule)(nil), // 15: ateapi.EgressRule - (*HTTPRule)(nil), // 16: ateapi.HTTPRule - (*HTTPSRule)(nil), // 17: ateapi.HTTPSRule - (*TLSPassthroughRule)(nil), // 18: ateapi.TLSPassthroughRule - (*Ports)(nil), // 19: ateapi.Ports - (*AllPorts)(nil), // 20: ateapi.AllPorts - (*HttpRuleEffects)(nil), // 21: ateapi.HttpRuleEffects - (*CredentialHeader)(nil), // 22: ateapi.CredentialHeader - (*ActorJWTSource)(nil), // 23: ateapi.ActorJWTSource - (*ActorStatus)(nil), // 24: ateapi.ActorStatus - (*ActorCrash)(nil), // 25: ateapi.ActorCrash - (*WorkerAssignment)(nil), // 26: ateapi.WorkerAssignment - (*TagStatus)(nil), // 27: ateapi.TagStatus - (*Tag)(nil), // 28: ateapi.Tag - (*Atespace)(nil), // 29: ateapi.Atespace - (*ObjectRef)(nil), // 30: ateapi.ObjectRef - (*ActorTemplate)(nil), // 31: ateapi.ActorTemplate - (*Resources)(nil), // 32: ateapi.Resources - (*Limits)(nil), // 33: ateapi.Limits - (*GoldenSnapshotStatus)(nil), // 34: ateapi.GoldenSnapshotStatus - (*ActorTemplateStatus)(nil), // 35: ateapi.ActorTemplateStatus - (*SandboxConfig)(nil), // 36: ateapi.SandboxConfig - (*SnapshotConfig)(nil), // 37: ateapi.SnapshotConfig - (*Container)(nil), // 38: ateapi.Container - (*SecurityContext)(nil), // 39: ateapi.SecurityContext - (*Capabilities)(nil), // 40: ateapi.Capabilities - (*EnvVar)(nil), // 41: ateapi.EnvVar - (*ContainerWakeupProbe)(nil), // 42: ateapi.ContainerWakeupProbe - (*HTTPGetAction)(nil), // 43: ateapi.HTTPGetAction - (*Volume)(nil), // 44: ateapi.Volume - (*ImageVolumeSource)(nil), // 45: ateapi.ImageVolumeSource - (*DurableDirVolumeSource)(nil), // 46: ateapi.DurableDirVolumeSource - (*ExternalVolumeTemplate)(nil), // 47: ateapi.ExternalVolumeTemplate - (*SystemInfoVolumeSource)(nil), // 48: ateapi.SystemInfoVolumeSource - (*SystemInfoDataSource)(nil), // 49: ateapi.SystemInfoDataSource - (*ActorMetadataDataSource)(nil), // 50: ateapi.ActorMetadataDataSource - (*ActorMetadataItem)(nil), // 51: ateapi.ActorMetadataItem - (*TrustBundleDataSource)(nil), // 52: ateapi.TrustBundleDataSource - (*VolumeMount)(nil), // 53: ateapi.VolumeMount - (*CreateAtespaceRequest)(nil), // 54: ateapi.CreateAtespaceRequest - (*GetAtespaceRequest)(nil), // 55: ateapi.GetAtespaceRequest - (*ListAtespacesRequest)(nil), // 56: ateapi.ListAtespacesRequest - (*ListAtespacesResponse)(nil), // 57: ateapi.ListAtespacesResponse - (*DeleteAtespaceRequest)(nil), // 58: ateapi.DeleteAtespaceRequest - (*CreateActorTemplateRequest)(nil), // 59: ateapi.CreateActorTemplateRequest - (*GetActorTemplateRequest)(nil), // 60: ateapi.GetActorTemplateRequest - (*ListActorTemplatesRequest)(nil), // 61: ateapi.ListActorTemplatesRequest - (*ListActorTemplatesResponse)(nil), // 62: ateapi.ListActorTemplatesResponse - (*DeleteActorTemplateRequest)(nil), // 63: ateapi.DeleteActorTemplateRequest - (*GetActorRequest)(nil), // 64: ateapi.GetActorRequest - (*CreateActorRequest)(nil), // 65: ateapi.CreateActorRequest - (*UpdateActorRequest)(nil), // 66: ateapi.UpdateActorRequest - (*FencingToken)(nil), // 67: ateapi.FencingToken - (*SuspendActorRequest)(nil), // 68: ateapi.SuspendActorRequest - (*SuspendActorResponse)(nil), // 69: ateapi.SuspendActorResponse - (*PauseActorRequest)(nil), // 70: ateapi.PauseActorRequest - (*PauseActorResponse)(nil), // 71: ateapi.PauseActorResponse - (*ResumeActorRequest)(nil), // 72: ateapi.ResumeActorRequest - (*ResumeActorResponse)(nil), // 73: ateapi.ResumeActorResponse - (*RevertActorRequest)(nil), // 74: ateapi.RevertActorRequest - (*RevertActorResponse)(nil), // 75: ateapi.RevertActorResponse - (*DeleteActorRequest)(nil), // 76: ateapi.DeleteActorRequest - (*GetActorEgressPolicyRequest)(nil), // 77: ateapi.GetActorEgressPolicyRequest - (*CreateActorEgressPolicyRequest)(nil), // 78: ateapi.CreateActorEgressPolicyRequest - (*UpdateActorEgressPolicyRequest)(nil), // 79: ateapi.UpdateActorEgressPolicyRequest - (*DeleteActorEgressPolicyRequest)(nil), // 80: ateapi.DeleteActorEgressPolicyRequest - (*GetEgressPolicyContractRequest)(nil), // 81: ateapi.GetEgressPolicyContractRequest - (*EgressPolicyContract)(nil), // 82: ateapi.EgressPolicyContract - (*GetTagRequest)(nil), // 83: ateapi.GetTagRequest - (*MintActorJWTRequest)(nil), // 84: ateapi.MintActorJWTRequest - (*MintActorJWTResponse)(nil), // 85: ateapi.MintActorJWTResponse - (*MintActorCertificateRequest)(nil), // 86: ateapi.MintActorCertificateRequest - (*MintActorCertificateResponse)(nil), // 87: ateapi.MintActorCertificateResponse - (*ListTagsRequest)(nil), // 88: ateapi.ListTagsRequest - (*ListTagsResponse)(nil), // 89: ateapi.ListTagsResponse - (*CreateTagRequest)(nil), // 90: ateapi.CreateTagRequest - (*UpdateTagRequest)(nil), // 91: ateapi.UpdateTagRequest - (*DeleteTagRequest)(nil), // 92: ateapi.DeleteTagRequest - (*DeleteOptions)(nil), // 93: ateapi.DeleteOptions - (*ListWorkerActorAssignmentsRequest)(nil), // 94: ateapi.ListWorkerActorAssignmentsRequest - (*ListWorkerActorAssignmentsResponse)(nil), // 95: ateapi.ListWorkerActorAssignmentsResponse - (*ListWorkersRequest)(nil), // 96: ateapi.ListWorkersRequest - (*ListWorkersResponse)(nil), // 97: ateapi.ListWorkersResponse - (*GetWorkerRequest)(nil), // 98: ateapi.GetWorkerRequest - (*CreateWorkerRequest)(nil), // 99: ateapi.CreateWorkerRequest - (*UpdateWorkerRequest)(nil), // 100: ateapi.UpdateWorkerRequest - (*DeleteWorkerRequest)(nil), // 101: ateapi.DeleteWorkerRequest - (*DrainWorkerRequest)(nil), // 102: ateapi.DrainWorkerRequest - (*ListActorsRequest)(nil), // 103: ateapi.ListActorsRequest - (*ListActorsResponse)(nil), // 104: ateapi.ListActorsResponse - (*Worker)(nil), // 105: ateapi.Worker - (*WorkerStatus)(nil), // 106: ateapi.WorkerStatus - (*WorkerResources)(nil), // 107: ateapi.WorkerResources - (*ActorAssignment)(nil), // 108: ateapi.ActorAssignment - (*SetWorkerCapacityRequest)(nil), // 109: ateapi.SetWorkerCapacityRequest - (*SetWorkerCapacityResponse)(nil), // 110: ateapi.SetWorkerCapacityResponse - (*MintAteomActorCertificateRequest)(nil), // 111: ateapi.MintAteomActorCertificateRequest - (*MintAteomActorCertificateResponse)(nil), // 112: ateapi.MintAteomActorCertificateResponse - (*RequestActorSuspendRequest)(nil), // 113: ateapi.RequestActorSuspendRequest - (*RequestActorSuspendResponse)(nil), // 114: ateapi.RequestActorSuspendResponse - (*AccessPolicy)(nil), // 115: ateapi.AccessPolicy - (*Binding)(nil), // 116: ateapi.Binding - (*GetGlobalAccessPolicyRequest)(nil), // 117: ateapi.GetGlobalAccessPolicyRequest - (*CreateGlobalAccessPolicyRequest)(nil), // 118: ateapi.CreateGlobalAccessPolicyRequest - (*UpdateGlobalAccessPolicyRequest)(nil), // 119: ateapi.UpdateGlobalAccessPolicyRequest - (*GetAtespaceAccessPolicyRequest)(nil), // 120: ateapi.GetAtespaceAccessPolicyRequest - (*CreateAtespaceAccessPolicyRequest)(nil), // 121: ateapi.CreateAtespaceAccessPolicyRequest - (*UpdateAtespaceAccessPolicyRequest)(nil), // 122: ateapi.UpdateAtespaceAccessPolicyRequest - (*DeleteAtespaceAccessPolicyRequest)(nil), // 123: ateapi.DeleteAtespaceAccessPolicyRequest - nil, // 124: ateapi.Selector.MatchLabelsEntry - nil, // 125: ateapi.ExternalVolume.VolumeContextEntry - nil, // 126: ateapi.Worker.LabelsEntry - (*timestamppb.Timestamp)(nil), // 127: google.protobuf.Timestamp + (VolumeAccessMode)(0), // 2: ateapi.VolumeAccessMode + (ActorState)(0), // 3: ateapi.ActorState + (SandboxClass)(0), // 4: ateapi.SandboxClass + (ActorMetadataField)(0), // 5: ateapi.ActorMetadataField + (WorkerState)(0), // 6: ateapi.WorkerState + (ExternalVolume_Status)(0), // 7: ateapi.ExternalVolume.Status + (*ExternalSnapshot)(nil), // 8: ateapi.ExternalSnapshot + (*LocalSnapshot)(nil), // 9: ateapi.LocalSnapshot + (*Selector)(nil), // 10: ateapi.Selector + (*ResourceMetadata)(nil), // 11: ateapi.ResourceMetadata + (*ExternalVolume)(nil), // 12: ateapi.ExternalVolume + (*Actor)(nil), // 13: ateapi.Actor + (*ExistingVolume)(nil), // 14: ateapi.ExistingVolume + (*EgressPolicy)(nil), // 15: ateapi.EgressPolicy + (*EgressPolicyTemplate)(nil), // 16: ateapi.EgressPolicyTemplate + (*EgressRule)(nil), // 17: ateapi.EgressRule + (*HTTPRule)(nil), // 18: ateapi.HTTPRule + (*HTTPSRule)(nil), // 19: ateapi.HTTPSRule + (*TLSPassthroughRule)(nil), // 20: ateapi.TLSPassthroughRule + (*Ports)(nil), // 21: ateapi.Ports + (*AllPorts)(nil), // 22: ateapi.AllPorts + (*HttpRuleEffects)(nil), // 23: ateapi.HttpRuleEffects + (*CredentialHeader)(nil), // 24: ateapi.CredentialHeader + (*ActorJWTSource)(nil), // 25: ateapi.ActorJWTSource + (*ActorStatus)(nil), // 26: ateapi.ActorStatus + (*ActorCrash)(nil), // 27: ateapi.ActorCrash + (*WorkerAssignment)(nil), // 28: ateapi.WorkerAssignment + (*TagStatus)(nil), // 29: ateapi.TagStatus + (*Tag)(nil), // 30: ateapi.Tag + (*Atespace)(nil), // 31: ateapi.Atespace + (*ObjectRef)(nil), // 32: ateapi.ObjectRef + (*ActorTemplate)(nil), // 33: ateapi.ActorTemplate + (*Resources)(nil), // 34: ateapi.Resources + (*Limits)(nil), // 35: ateapi.Limits + (*GoldenSnapshotStatus)(nil), // 36: ateapi.GoldenSnapshotStatus + (*ActorTemplateStatus)(nil), // 37: ateapi.ActorTemplateStatus + (*SandboxConfig)(nil), // 38: ateapi.SandboxConfig + (*SnapshotConfig)(nil), // 39: ateapi.SnapshotConfig + (*Container)(nil), // 40: ateapi.Container + (*SecurityContext)(nil), // 41: ateapi.SecurityContext + (*Capabilities)(nil), // 42: ateapi.Capabilities + (*EnvVar)(nil), // 43: ateapi.EnvVar + (*ContainerWakeupProbe)(nil), // 44: ateapi.ContainerWakeupProbe + (*HTTPGetAction)(nil), // 45: ateapi.HTTPGetAction + (*Volume)(nil), // 46: ateapi.Volume + (*ExistingVolumeSource)(nil), // 47: ateapi.ExistingVolumeSource + (*ImageVolumeSource)(nil), // 48: ateapi.ImageVolumeSource + (*DurableDirVolumeSource)(nil), // 49: ateapi.DurableDirVolumeSource + (*ExternalVolumeTemplate)(nil), // 50: ateapi.ExternalVolumeTemplate + (*SystemInfoVolumeSource)(nil), // 51: ateapi.SystemInfoVolumeSource + (*SystemInfoDataSource)(nil), // 52: ateapi.SystemInfoDataSource + (*ActorMetadataDataSource)(nil), // 53: ateapi.ActorMetadataDataSource + (*ActorMetadataItem)(nil), // 54: ateapi.ActorMetadataItem + (*TrustBundleDataSource)(nil), // 55: ateapi.TrustBundleDataSource + (*VolumeMount)(nil), // 56: ateapi.VolumeMount + (*CreateAtespaceRequest)(nil), // 57: ateapi.CreateAtespaceRequest + (*GetAtespaceRequest)(nil), // 58: ateapi.GetAtespaceRequest + (*ListAtespacesRequest)(nil), // 59: ateapi.ListAtespacesRequest + (*ListAtespacesResponse)(nil), // 60: ateapi.ListAtespacesResponse + (*DeleteAtespaceRequest)(nil), // 61: ateapi.DeleteAtespaceRequest + (*CreateActorTemplateRequest)(nil), // 62: ateapi.CreateActorTemplateRequest + (*GetActorTemplateRequest)(nil), // 63: ateapi.GetActorTemplateRequest + (*ListActorTemplatesRequest)(nil), // 64: ateapi.ListActorTemplatesRequest + (*ListActorTemplatesResponse)(nil), // 65: ateapi.ListActorTemplatesResponse + (*DeleteActorTemplateRequest)(nil), // 66: ateapi.DeleteActorTemplateRequest + (*GetActorRequest)(nil), // 67: ateapi.GetActorRequest + (*CreateActorRequest)(nil), // 68: ateapi.CreateActorRequest + (*UpdateActorRequest)(nil), // 69: ateapi.UpdateActorRequest + (*FencingToken)(nil), // 70: ateapi.FencingToken + (*SuspendActorRequest)(nil), // 71: ateapi.SuspendActorRequest + (*SuspendActorResponse)(nil), // 72: ateapi.SuspendActorResponse + (*PauseActorRequest)(nil), // 73: ateapi.PauseActorRequest + (*PauseActorResponse)(nil), // 74: ateapi.PauseActorResponse + (*ResumeActorRequest)(nil), // 75: ateapi.ResumeActorRequest + (*ResumeActorResponse)(nil), // 76: ateapi.ResumeActorResponse + (*RevertActorRequest)(nil), // 77: ateapi.RevertActorRequest + (*RevertActorResponse)(nil), // 78: ateapi.RevertActorResponse + (*DeleteActorRequest)(nil), // 79: ateapi.DeleteActorRequest + (*GetActorEgressPolicyRequest)(nil), // 80: ateapi.GetActorEgressPolicyRequest + (*CreateActorEgressPolicyRequest)(nil), // 81: ateapi.CreateActorEgressPolicyRequest + (*UpdateActorEgressPolicyRequest)(nil), // 82: ateapi.UpdateActorEgressPolicyRequest + (*DeleteActorEgressPolicyRequest)(nil), // 83: ateapi.DeleteActorEgressPolicyRequest + (*GetEgressPolicyContractRequest)(nil), // 84: ateapi.GetEgressPolicyContractRequest + (*EgressPolicyContract)(nil), // 85: ateapi.EgressPolicyContract + (*GetTagRequest)(nil), // 86: ateapi.GetTagRequest + (*MintActorJWTRequest)(nil), // 87: ateapi.MintActorJWTRequest + (*MintActorJWTResponse)(nil), // 88: ateapi.MintActorJWTResponse + (*MintActorCertificateRequest)(nil), // 89: ateapi.MintActorCertificateRequest + (*MintActorCertificateResponse)(nil), // 90: ateapi.MintActorCertificateResponse + (*ListTagsRequest)(nil), // 91: ateapi.ListTagsRequest + (*ListTagsResponse)(nil), // 92: ateapi.ListTagsResponse + (*CreateTagRequest)(nil), // 93: ateapi.CreateTagRequest + (*UpdateTagRequest)(nil), // 94: ateapi.UpdateTagRequest + (*DeleteTagRequest)(nil), // 95: ateapi.DeleteTagRequest + (*DeleteOptions)(nil), // 96: ateapi.DeleteOptions + (*ListWorkerActorAssignmentsRequest)(nil), // 97: ateapi.ListWorkerActorAssignmentsRequest + (*ListWorkerActorAssignmentsResponse)(nil), // 98: ateapi.ListWorkerActorAssignmentsResponse + (*ListWorkersRequest)(nil), // 99: ateapi.ListWorkersRequest + (*ListWorkersResponse)(nil), // 100: ateapi.ListWorkersResponse + (*GetWorkerRequest)(nil), // 101: ateapi.GetWorkerRequest + (*CreateWorkerRequest)(nil), // 102: ateapi.CreateWorkerRequest + (*UpdateWorkerRequest)(nil), // 103: ateapi.UpdateWorkerRequest + (*DeleteWorkerRequest)(nil), // 104: ateapi.DeleteWorkerRequest + (*DrainWorkerRequest)(nil), // 105: ateapi.DrainWorkerRequest + (*ListActorsRequest)(nil), // 106: ateapi.ListActorsRequest + (*ListActorsResponse)(nil), // 107: ateapi.ListActorsResponse + (*Worker)(nil), // 108: ateapi.Worker + (*WorkerStatus)(nil), // 109: ateapi.WorkerStatus + (*WorkerResources)(nil), // 110: ateapi.WorkerResources + (*ActorAssignment)(nil), // 111: ateapi.ActorAssignment + (*SetWorkerCapacityRequest)(nil), // 112: ateapi.SetWorkerCapacityRequest + (*SetWorkerCapacityResponse)(nil), // 113: ateapi.SetWorkerCapacityResponse + (*MintAteomActorCertificateRequest)(nil), // 114: ateapi.MintAteomActorCertificateRequest + (*MintAteomActorCertificateResponse)(nil), // 115: ateapi.MintAteomActorCertificateResponse + (*RequestActorSuspendRequest)(nil), // 116: ateapi.RequestActorSuspendRequest + (*RequestActorSuspendResponse)(nil), // 117: ateapi.RequestActorSuspendResponse + (*AccessPolicy)(nil), // 118: ateapi.AccessPolicy + (*Binding)(nil), // 119: ateapi.Binding + (*GetGlobalAccessPolicyRequest)(nil), // 120: ateapi.GetGlobalAccessPolicyRequest + (*CreateGlobalAccessPolicyRequest)(nil), // 121: ateapi.CreateGlobalAccessPolicyRequest + (*UpdateGlobalAccessPolicyRequest)(nil), // 122: ateapi.UpdateGlobalAccessPolicyRequest + (*GetAtespaceAccessPolicyRequest)(nil), // 123: ateapi.GetAtespaceAccessPolicyRequest + (*CreateAtespaceAccessPolicyRequest)(nil), // 124: ateapi.CreateAtespaceAccessPolicyRequest + (*UpdateAtespaceAccessPolicyRequest)(nil), // 125: ateapi.UpdateAtespaceAccessPolicyRequest + (*DeleteAtespaceAccessPolicyRequest)(nil), // 126: ateapi.DeleteAtespaceAccessPolicyRequest + nil, // 127: ateapi.Selector.MatchLabelsEntry + nil, // 128: ateapi.ExternalVolume.VolumeContextEntry + nil, // 129: ateapi.Worker.LabelsEntry + (*timestamppb.Timestamp)(nil), // 130: google.protobuf.Timestamp } var file_ateapi_proto_depIdxs = []int32{ 0, // 0: ateapi.ExternalSnapshot.content_scope:type_name -> ateapi.SnapshotContentScope 0, // 1: ateapi.LocalSnapshot.content_scope:type_name -> ateapi.SnapshotContentScope - 7, // 2: ateapi.LocalSnapshot.durable_copy:type_name -> ateapi.ExternalSnapshot - 124, // 3: ateapi.Selector.match_labels:type_name -> ateapi.Selector.MatchLabelsEntry - 127, // 4: ateapi.ResourceMetadata.create_time:type_name -> google.protobuf.Timestamp - 127, // 5: ateapi.ResourceMetadata.update_time:type_name -> google.protobuf.Timestamp - 6, // 6: ateapi.ExternalVolume.status:type_name -> ateapi.ExternalVolume.Status - 125, // 7: ateapi.ExternalVolume.volume_context:type_name -> ateapi.ExternalVolume.VolumeContextEntry - 10, // 8: ateapi.Actor.metadata:type_name -> ateapi.ResourceMetadata - 30, // 9: ateapi.Actor.actor_template:type_name -> ateapi.ObjectRef - 9, // 10: ateapi.Actor.worker_selector:type_name -> ateapi.Selector - 30, // 11: ateapi.Actor.source_tag:type_name -> ateapi.ObjectRef - 24, // 12: ateapi.Actor.status:type_name -> ateapi.ActorStatus - 10, // 13: ateapi.EgressPolicy.metadata:type_name -> ateapi.ResourceMetadata - 15, // 14: ateapi.EgressPolicy.rules:type_name -> ateapi.EgressRule - 15, // 15: ateapi.EgressPolicyTemplate.rules:type_name -> ateapi.EgressRule - 16, // 16: ateapi.EgressRule.http:type_name -> ateapi.HTTPRule - 17, // 17: ateapi.EgressRule.https:type_name -> ateapi.HTTPSRule - 18, // 18: ateapi.EgressRule.tls_passthrough:type_name -> ateapi.TLSPassthroughRule - 19, // 19: ateapi.HTTPRule.ports:type_name -> ateapi.Ports - 21, // 20: ateapi.HTTPRule.effects:type_name -> ateapi.HttpRuleEffects - 19, // 21: ateapi.HTTPSRule.ports:type_name -> ateapi.Ports - 21, // 22: ateapi.HTTPSRule.effects:type_name -> ateapi.HttpRuleEffects - 19, // 23: ateapi.TLSPassthroughRule.ports:type_name -> ateapi.Ports - 20, // 24: ateapi.Ports.all:type_name -> ateapi.AllPorts - 22, // 25: ateapi.HttpRuleEffects.replace_headers:type_name -> ateapi.CredentialHeader - 23, // 26: ateapi.CredentialHeader.actor_jwt:type_name -> ateapi.ActorJWTSource - 2, // 27: ateapi.ActorStatus.state:type_name -> ateapi.ActorState - 26, // 28: ateapi.ActorStatus.worker_assignment:type_name -> ateapi.WorkerAssignment - 7, // 29: ateapi.ActorStatus.external_snapshot:type_name -> ateapi.ExternalSnapshot - 8, // 30: ateapi.ActorStatus.local_snapshot:type_name -> ateapi.LocalSnapshot - 11, // 31: ateapi.ActorStatus.actor_volumes:type_name -> ateapi.ExternalVolume - 25, // 32: ateapi.ActorStatus.crash:type_name -> ateapi.ActorCrash - 67, // 33: ateapi.ActorStatus.fencing_token:type_name -> ateapi.FencingToken - 127, // 34: ateapi.ActorCrash.crash_time:type_name -> google.protobuf.Timestamp - 30, // 35: ateapi.WorkerAssignment.worker:type_name -> ateapi.ObjectRef - 7, // 36: ateapi.TagStatus.snapshot:type_name -> ateapi.ExternalSnapshot - 10, // 37: ateapi.Tag.metadata:type_name -> ateapi.ResourceMetadata - 27, // 38: ateapi.Tag.status:type_name -> ateapi.TagStatus - 1, // 39: ateapi.Tag.scope:type_name -> ateapi.TagScope - 30, // 40: ateapi.Tag.source_actor:type_name -> ateapi.ObjectRef - 10, // 41: ateapi.Atespace.metadata:type_name -> ateapi.ResourceMetadata - 10, // 42: ateapi.ActorTemplate.metadata:type_name -> ateapi.ResourceMetadata - 9, // 43: ateapi.ActorTemplate.worker_selector:type_name -> ateapi.Selector - 38, // 44: ateapi.ActorTemplate.containers:type_name -> ateapi.Container - 44, // 45: ateapi.ActorTemplate.volumes:type_name -> ateapi.Volume - 37, // 46: ateapi.ActorTemplate.snapshot_config:type_name -> ateapi.SnapshotConfig - 36, // 47: ateapi.ActorTemplate.sandbox_config:type_name -> ateapi.SandboxConfig - 32, // 48: ateapi.ActorTemplate.resources:type_name -> ateapi.Resources - 35, // 49: ateapi.ActorTemplate.status:type_name -> ateapi.ActorTemplateStatus - 14, // 50: ateapi.ActorTemplate.default_egress_policy:type_name -> ateapi.EgressPolicyTemplate - 33, // 51: ateapi.Resources.limits:type_name -> ateapi.Limits - 30, // 52: ateapi.GoldenSnapshotStatus.golden_tag:type_name -> ateapi.ObjectRef - 127, // 53: ateapi.GoldenSnapshotStatus.take_golden_snapshot_at:type_name -> google.protobuf.Timestamp - 34, // 54: ateapi.ActorTemplateStatus.golden_snapshot_status:type_name -> ateapi.GoldenSnapshotStatus - 3, // 55: ateapi.SandboxConfig.sandbox_class:type_name -> ateapi.SandboxClass - 0, // 56: ateapi.SnapshotConfig.on_pause:type_name -> ateapi.SnapshotContentScope - 0, // 57: ateapi.SnapshotConfig.on_commit:type_name -> ateapi.SnapshotContentScope - 41, // 58: ateapi.Container.env:type_name -> ateapi.EnvVar - 42, // 59: ateapi.Container.wakeup_probe:type_name -> ateapi.ContainerWakeupProbe - 53, // 60: ateapi.Container.volume_mounts:type_name -> ateapi.VolumeMount - 39, // 61: ateapi.Container.security_context:type_name -> ateapi.SecurityContext - 32, // 62: ateapi.Container.resources:type_name -> ateapi.Resources - 40, // 63: ateapi.SecurityContext.capabilities:type_name -> ateapi.Capabilities - 43, // 64: ateapi.ContainerWakeupProbe.http_get:type_name -> ateapi.HTTPGetAction - 46, // 65: ateapi.Volume.durable_dir:type_name -> ateapi.DurableDirVolumeSource - 47, // 66: ateapi.Volume.external_volume_template:type_name -> ateapi.ExternalVolumeTemplate - 48, // 67: ateapi.Volume.system_info:type_name -> ateapi.SystemInfoVolumeSource - 45, // 68: ateapi.Volume.image:type_name -> ateapi.ImageVolumeSource - 49, // 69: ateapi.SystemInfoVolumeSource.data_sources:type_name -> ateapi.SystemInfoDataSource - 50, // 70: ateapi.SystemInfoDataSource.actor_metadata:type_name -> ateapi.ActorMetadataDataSource - 52, // 71: ateapi.SystemInfoDataSource.trust_bundle:type_name -> ateapi.TrustBundleDataSource - 51, // 72: ateapi.ActorMetadataDataSource.items:type_name -> ateapi.ActorMetadataItem - 4, // 73: ateapi.ActorMetadataItem.field:type_name -> ateapi.ActorMetadataField - 29, // 74: ateapi.CreateAtespaceRequest.atespace:type_name -> ateapi.Atespace - 30, // 75: ateapi.GetAtespaceRequest.atespace:type_name -> ateapi.ObjectRef - 29, // 76: ateapi.ListAtespacesResponse.atespaces:type_name -> ateapi.Atespace - 30, // 77: ateapi.DeleteAtespaceRequest.atespace:type_name -> ateapi.ObjectRef - 93, // 78: ateapi.DeleteAtespaceRequest.options:type_name -> ateapi.DeleteOptions - 31, // 79: ateapi.CreateActorTemplateRequest.actor_template:type_name -> ateapi.ActorTemplate - 30, // 80: ateapi.GetActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef - 31, // 81: ateapi.ListActorTemplatesResponse.actor_templates:type_name -> ateapi.ActorTemplate - 30, // 82: ateapi.DeleteActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef - 93, // 83: ateapi.DeleteActorTemplateRequest.options:type_name -> ateapi.DeleteOptions - 30, // 84: ateapi.GetActorRequest.actor:type_name -> ateapi.ObjectRef - 12, // 85: ateapi.CreateActorRequest.actor:type_name -> ateapi.Actor - 12, // 86: ateapi.UpdateActorRequest.actor:type_name -> ateapi.Actor - 30, // 87: ateapi.SuspendActorRequest.actor:type_name -> ateapi.ObjectRef - 67, // 88: ateapi.SuspendActorRequest.fencing_token:type_name -> ateapi.FencingToken - 12, // 89: ateapi.SuspendActorResponse.actor:type_name -> ateapi.Actor - 30, // 90: ateapi.PauseActorRequest.actor:type_name -> ateapi.ObjectRef - 67, // 91: ateapi.PauseActorRequest.fencing_token:type_name -> ateapi.FencingToken - 12, // 92: ateapi.PauseActorResponse.actor:type_name -> ateapi.Actor - 30, // 93: ateapi.ResumeActorRequest.actor:type_name -> ateapi.ObjectRef - 67, // 94: ateapi.ResumeActorRequest.fencing_token:type_name -> ateapi.FencingToken - 12, // 95: ateapi.ResumeActorResponse.actor:type_name -> ateapi.Actor - 30, // 96: ateapi.RevertActorRequest.actor:type_name -> ateapi.ObjectRef - 12, // 97: ateapi.RevertActorResponse.actor:type_name -> ateapi.Actor - 30, // 98: ateapi.DeleteActorRequest.actor:type_name -> ateapi.ObjectRef - 93, // 99: ateapi.DeleteActorRequest.options:type_name -> ateapi.DeleteOptions - 30, // 100: ateapi.GetActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 30, // 101: ateapi.CreateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 13, // 102: ateapi.CreateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy - 30, // 103: ateapi.UpdateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 13, // 104: ateapi.UpdateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy - 30, // 105: ateapi.DeleteActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 93, // 106: ateapi.DeleteActorEgressPolicyRequest.options:type_name -> ateapi.DeleteOptions - 30, // 107: ateapi.GetTagRequest.tag:type_name -> ateapi.ObjectRef - 30, // 108: ateapi.MintActorJWTRequest.actor:type_name -> ateapi.ObjectRef - 127, // 109: ateapi.MintActorJWTResponse.expires_at:type_name -> google.protobuf.Timestamp - 30, // 110: ateapi.MintActorCertificateRequest.actor:type_name -> ateapi.ObjectRef - 28, // 111: ateapi.ListTagsResponse.tags:type_name -> ateapi.Tag - 28, // 112: ateapi.CreateTagRequest.tag:type_name -> ateapi.Tag - 28, // 113: ateapi.UpdateTagRequest.tag:type_name -> ateapi.Tag - 30, // 114: ateapi.DeleteTagRequest.tag:type_name -> ateapi.ObjectRef - 93, // 115: ateapi.DeleteTagRequest.options:type_name -> ateapi.DeleteOptions - 30, // 116: ateapi.ListWorkerActorAssignmentsRequest.worker:type_name -> ateapi.ObjectRef - 108, // 117: ateapi.ListWorkerActorAssignmentsResponse.actor_assignments:type_name -> ateapi.ActorAssignment - 105, // 118: ateapi.ListWorkersResponse.workers:type_name -> ateapi.Worker - 30, // 119: ateapi.GetWorkerRequest.worker:type_name -> ateapi.ObjectRef - 105, // 120: ateapi.CreateWorkerRequest.worker:type_name -> ateapi.Worker - 105, // 121: ateapi.UpdateWorkerRequest.worker:type_name -> ateapi.Worker - 30, // 122: ateapi.DeleteWorkerRequest.worker:type_name -> ateapi.ObjectRef - 93, // 123: ateapi.DeleteWorkerRequest.options:type_name -> ateapi.DeleteOptions - 30, // 124: ateapi.DrainWorkerRequest.worker:type_name -> ateapi.ObjectRef - 12, // 125: ateapi.ListActorsResponse.actors:type_name -> ateapi.Actor - 10, // 126: ateapi.Worker.metadata:type_name -> ateapi.ResourceMetadata - 126, // 127: ateapi.Worker.labels:type_name -> ateapi.Worker.LabelsEntry - 106, // 128: ateapi.Worker.status:type_name -> ateapi.WorkerStatus - 5, // 129: ateapi.WorkerStatus.state:type_name -> ateapi.WorkerState - 107, // 130: ateapi.WorkerStatus.capacity:type_name -> ateapi.WorkerResources - 107, // 131: ateapi.WorkerStatus.allocated:type_name -> ateapi.WorkerResources - 32, // 132: ateapi.WorkerResources.resources:type_name -> ateapi.Resources - 10, // 133: ateapi.ActorAssignment.metadata:type_name -> ateapi.ResourceMetadata - 30, // 134: ateapi.ActorAssignment.actor:type_name -> ateapi.ObjectRef - 30, // 135: ateapi.ActorAssignment.actor_template_ref:type_name -> ateapi.ObjectRef - 32, // 136: ateapi.ActorAssignment.resources:type_name -> ateapi.Resources - 30, // 137: ateapi.SetWorkerCapacityRequest.worker:type_name -> ateapi.ObjectRef - 107, // 138: ateapi.SetWorkerCapacityRequest.capacity:type_name -> ateapi.WorkerResources - 105, // 139: ateapi.SetWorkerCapacityResponse.worker:type_name -> ateapi.Worker - 30, // 140: ateapi.MintAteomActorCertificateRequest.actor:type_name -> ateapi.ObjectRef - 30, // 141: ateapi.RequestActorSuspendRequest.worker:type_name -> ateapi.ObjectRef - 30, // 142: ateapi.RequestActorSuspendRequest.actor:type_name -> ateapi.ObjectRef - 12, // 143: ateapi.RequestActorSuspendResponse.actor:type_name -> ateapi.Actor - 10, // 144: ateapi.AccessPolicy.metadata:type_name -> ateapi.ResourceMetadata - 116, // 145: ateapi.AccessPolicy.bindings:type_name -> ateapi.Binding - 115, // 146: ateapi.CreateGlobalAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy - 115, // 147: ateapi.UpdateGlobalAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy - 30, // 148: ateapi.GetAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef - 30, // 149: ateapi.CreateAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef - 115, // 150: ateapi.CreateAtespaceAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy - 30, // 151: ateapi.UpdateAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef - 115, // 152: ateapi.UpdateAtespaceAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy - 30, // 153: ateapi.DeleteAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef - 93, // 154: ateapi.DeleteAtespaceAccessPolicyRequest.options:type_name -> ateapi.DeleteOptions - 64, // 155: ateapi.Control.GetActor:input_type -> ateapi.GetActorRequest - 65, // 156: ateapi.Control.CreateActor:input_type -> ateapi.CreateActorRequest - 66, // 157: ateapi.Control.UpdateActor:input_type -> ateapi.UpdateActorRequest - 68, // 158: ateapi.Control.SuspendActor:input_type -> ateapi.SuspendActorRequest - 70, // 159: ateapi.Control.PauseActor:input_type -> ateapi.PauseActorRequest - 72, // 160: ateapi.Control.ResumeActor:input_type -> ateapi.ResumeActorRequest - 74, // 161: ateapi.Control.RevertActor:input_type -> ateapi.RevertActorRequest - 76, // 162: ateapi.Control.DeleteActor:input_type -> ateapi.DeleteActorRequest - 77, // 163: ateapi.Control.GetActorEgressPolicy:input_type -> ateapi.GetActorEgressPolicyRequest - 78, // 164: ateapi.Control.CreateActorEgressPolicy:input_type -> ateapi.CreateActorEgressPolicyRequest - 79, // 165: ateapi.Control.UpdateActorEgressPolicy:input_type -> ateapi.UpdateActorEgressPolicyRequest - 80, // 166: ateapi.Control.DeleteActorEgressPolicy:input_type -> ateapi.DeleteActorEgressPolicyRequest - 81, // 167: ateapi.Control.GetEgressPolicyContract:input_type -> ateapi.GetEgressPolicyContractRequest - 84, // 168: ateapi.Control.MintActorJWT:input_type -> ateapi.MintActorJWTRequest - 86, // 169: ateapi.Control.MintActorCertificate:input_type -> ateapi.MintActorCertificateRequest - 90, // 170: ateapi.Control.CreateTag:input_type -> ateapi.CreateTagRequest - 83, // 171: ateapi.Control.GetTag:input_type -> ateapi.GetTagRequest - 88, // 172: ateapi.Control.ListTags:input_type -> ateapi.ListTagsRequest - 91, // 173: ateapi.Control.UpdateTag:input_type -> ateapi.UpdateTagRequest - 92, // 174: ateapi.Control.DeleteTag:input_type -> ateapi.DeleteTagRequest - 96, // 175: ateapi.Control.ListWorkers:input_type -> ateapi.ListWorkersRequest - 98, // 176: ateapi.Control.GetWorker:input_type -> ateapi.GetWorkerRequest - 99, // 177: ateapi.Control.CreateWorker:input_type -> ateapi.CreateWorkerRequest - 100, // 178: ateapi.Control.UpdateWorker:input_type -> ateapi.UpdateWorkerRequest - 101, // 179: ateapi.Control.DeleteWorker:input_type -> ateapi.DeleteWorkerRequest - 102, // 180: ateapi.Control.DrainWorker:input_type -> ateapi.DrainWorkerRequest - 94, // 181: ateapi.Control.ListWorkerActorAssignments:input_type -> ateapi.ListWorkerActorAssignmentsRequest - 103, // 182: ateapi.Control.ListActors:input_type -> ateapi.ListActorsRequest - 54, // 183: ateapi.Control.CreateAtespace:input_type -> ateapi.CreateAtespaceRequest - 55, // 184: ateapi.Control.GetAtespace:input_type -> ateapi.GetAtespaceRequest - 56, // 185: ateapi.Control.ListAtespaces:input_type -> ateapi.ListAtespacesRequest - 58, // 186: ateapi.Control.DeleteAtespace:input_type -> ateapi.DeleteAtespaceRequest - 59, // 187: ateapi.Control.CreateActorTemplate:input_type -> ateapi.CreateActorTemplateRequest - 60, // 188: ateapi.Control.GetActorTemplate:input_type -> ateapi.GetActorTemplateRequest - 61, // 189: ateapi.Control.ListActorTemplates:input_type -> ateapi.ListActorTemplatesRequest - 63, // 190: ateapi.Control.DeleteActorTemplate:input_type -> ateapi.DeleteActorTemplateRequest - 117, // 191: ateapi.Control.GetGlobalAccessPolicy:input_type -> ateapi.GetGlobalAccessPolicyRequest - 118, // 192: ateapi.Control.CreateGlobalAccessPolicy:input_type -> ateapi.CreateGlobalAccessPolicyRequest - 119, // 193: ateapi.Control.UpdateGlobalAccessPolicy:input_type -> ateapi.UpdateGlobalAccessPolicyRequest - 120, // 194: ateapi.Control.GetAtespaceAccessPolicy:input_type -> ateapi.GetAtespaceAccessPolicyRequest - 121, // 195: ateapi.Control.CreateAtespaceAccessPolicy:input_type -> ateapi.CreateAtespaceAccessPolicyRequest - 122, // 196: ateapi.Control.UpdateAtespaceAccessPolicy:input_type -> ateapi.UpdateAtespaceAccessPolicyRequest - 123, // 197: ateapi.Control.DeleteAtespaceAccessPolicy:input_type -> ateapi.DeleteAtespaceAccessPolicyRequest - 109, // 198: ateapi.WorkerService.SetWorkerCapacity:input_type -> ateapi.SetWorkerCapacityRequest - 111, // 199: ateapi.WorkerService.MintAteomActorCertificate:input_type -> ateapi.MintAteomActorCertificateRequest - 113, // 200: ateapi.WorkerService.RequestActorSuspend:input_type -> ateapi.RequestActorSuspendRequest - 12, // 201: ateapi.Control.GetActor:output_type -> ateapi.Actor - 12, // 202: ateapi.Control.CreateActor:output_type -> ateapi.Actor - 12, // 203: ateapi.Control.UpdateActor:output_type -> ateapi.Actor - 69, // 204: ateapi.Control.SuspendActor:output_type -> ateapi.SuspendActorResponse - 71, // 205: ateapi.Control.PauseActor:output_type -> ateapi.PauseActorResponse - 73, // 206: ateapi.Control.ResumeActor:output_type -> ateapi.ResumeActorResponse - 75, // 207: ateapi.Control.RevertActor:output_type -> ateapi.RevertActorResponse - 12, // 208: ateapi.Control.DeleteActor:output_type -> ateapi.Actor - 13, // 209: ateapi.Control.GetActorEgressPolicy:output_type -> ateapi.EgressPolicy - 13, // 210: ateapi.Control.CreateActorEgressPolicy:output_type -> ateapi.EgressPolicy - 13, // 211: ateapi.Control.UpdateActorEgressPolicy:output_type -> ateapi.EgressPolicy - 13, // 212: ateapi.Control.DeleteActorEgressPolicy:output_type -> ateapi.EgressPolicy - 82, // 213: ateapi.Control.GetEgressPolicyContract:output_type -> ateapi.EgressPolicyContract - 85, // 214: ateapi.Control.MintActorJWT:output_type -> ateapi.MintActorJWTResponse - 87, // 215: ateapi.Control.MintActorCertificate:output_type -> ateapi.MintActorCertificateResponse - 28, // 216: ateapi.Control.CreateTag:output_type -> ateapi.Tag - 28, // 217: ateapi.Control.GetTag:output_type -> ateapi.Tag - 89, // 218: ateapi.Control.ListTags:output_type -> ateapi.ListTagsResponse - 28, // 219: ateapi.Control.UpdateTag:output_type -> ateapi.Tag - 28, // 220: ateapi.Control.DeleteTag:output_type -> ateapi.Tag - 97, // 221: ateapi.Control.ListWorkers:output_type -> ateapi.ListWorkersResponse - 105, // 222: ateapi.Control.GetWorker:output_type -> ateapi.Worker - 105, // 223: ateapi.Control.CreateWorker:output_type -> ateapi.Worker - 105, // 224: ateapi.Control.UpdateWorker:output_type -> ateapi.Worker - 105, // 225: ateapi.Control.DeleteWorker:output_type -> ateapi.Worker - 105, // 226: ateapi.Control.DrainWorker:output_type -> ateapi.Worker - 95, // 227: ateapi.Control.ListWorkerActorAssignments:output_type -> ateapi.ListWorkerActorAssignmentsResponse - 104, // 228: ateapi.Control.ListActors:output_type -> ateapi.ListActorsResponse - 29, // 229: ateapi.Control.CreateAtespace:output_type -> ateapi.Atespace - 29, // 230: ateapi.Control.GetAtespace:output_type -> ateapi.Atespace - 57, // 231: ateapi.Control.ListAtespaces:output_type -> ateapi.ListAtespacesResponse - 29, // 232: ateapi.Control.DeleteAtespace:output_type -> ateapi.Atespace - 31, // 233: ateapi.Control.CreateActorTemplate:output_type -> ateapi.ActorTemplate - 31, // 234: ateapi.Control.GetActorTemplate:output_type -> ateapi.ActorTemplate - 62, // 235: ateapi.Control.ListActorTemplates:output_type -> ateapi.ListActorTemplatesResponse - 31, // 236: ateapi.Control.DeleteActorTemplate:output_type -> ateapi.ActorTemplate - 115, // 237: ateapi.Control.GetGlobalAccessPolicy:output_type -> ateapi.AccessPolicy - 115, // 238: ateapi.Control.CreateGlobalAccessPolicy:output_type -> ateapi.AccessPolicy - 115, // 239: ateapi.Control.UpdateGlobalAccessPolicy:output_type -> ateapi.AccessPolicy - 115, // 240: ateapi.Control.GetAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy - 115, // 241: ateapi.Control.CreateAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy - 115, // 242: ateapi.Control.UpdateAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy - 115, // 243: ateapi.Control.DeleteAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy - 110, // 244: ateapi.WorkerService.SetWorkerCapacity:output_type -> ateapi.SetWorkerCapacityResponse - 112, // 245: ateapi.WorkerService.MintAteomActorCertificate:output_type -> ateapi.MintAteomActorCertificateResponse - 114, // 246: ateapi.WorkerService.RequestActorSuspend:output_type -> ateapi.RequestActorSuspendResponse - 201, // [201:247] is the sub-list for method output_type - 155, // [155:201] is the sub-list for method input_type - 155, // [155:155] is the sub-list for extension type_name - 155, // [155:155] is the sub-list for extension extendee - 0, // [0:155] is the sub-list for field type_name + 8, // 2: ateapi.LocalSnapshot.durable_copy:type_name -> ateapi.ExternalSnapshot + 127, // 3: ateapi.Selector.match_labels:type_name -> ateapi.Selector.MatchLabelsEntry + 130, // 4: ateapi.ResourceMetadata.create_time:type_name -> google.protobuf.Timestamp + 130, // 5: ateapi.ResourceMetadata.update_time:type_name -> google.protobuf.Timestamp + 7, // 6: ateapi.ExternalVolume.status:type_name -> ateapi.ExternalVolume.Status + 128, // 7: ateapi.ExternalVolume.volume_context:type_name -> ateapi.ExternalVolume.VolumeContextEntry + 11, // 8: ateapi.Actor.metadata:type_name -> ateapi.ResourceMetadata + 32, // 9: ateapi.Actor.actor_template:type_name -> ateapi.ObjectRef + 10, // 10: ateapi.Actor.worker_selector:type_name -> ateapi.Selector + 32, // 11: ateapi.Actor.source_tag:type_name -> ateapi.ObjectRef + 26, // 12: ateapi.Actor.status:type_name -> ateapi.ActorStatus + 14, // 13: ateapi.Actor.existing_volumes:type_name -> ateapi.ExistingVolume + 2, // 14: ateapi.ExistingVolume.access_mode:type_name -> ateapi.VolumeAccessMode + 11, // 15: ateapi.EgressPolicy.metadata:type_name -> ateapi.ResourceMetadata + 17, // 16: ateapi.EgressPolicy.rules:type_name -> ateapi.EgressRule + 17, // 17: ateapi.EgressPolicyTemplate.rules:type_name -> ateapi.EgressRule + 18, // 18: ateapi.EgressRule.http:type_name -> ateapi.HTTPRule + 19, // 19: ateapi.EgressRule.https:type_name -> ateapi.HTTPSRule + 20, // 20: ateapi.EgressRule.tls_passthrough:type_name -> ateapi.TLSPassthroughRule + 21, // 21: ateapi.HTTPRule.ports:type_name -> ateapi.Ports + 23, // 22: ateapi.HTTPRule.effects:type_name -> ateapi.HttpRuleEffects + 21, // 23: ateapi.HTTPSRule.ports:type_name -> ateapi.Ports + 23, // 24: ateapi.HTTPSRule.effects:type_name -> ateapi.HttpRuleEffects + 21, // 25: ateapi.TLSPassthroughRule.ports:type_name -> ateapi.Ports + 22, // 26: ateapi.Ports.all:type_name -> ateapi.AllPorts + 24, // 27: ateapi.HttpRuleEffects.replace_headers:type_name -> ateapi.CredentialHeader + 25, // 28: ateapi.CredentialHeader.actor_jwt:type_name -> ateapi.ActorJWTSource + 3, // 29: ateapi.ActorStatus.state:type_name -> ateapi.ActorState + 28, // 30: ateapi.ActorStatus.worker_assignment:type_name -> ateapi.WorkerAssignment + 8, // 31: ateapi.ActorStatus.external_snapshot:type_name -> ateapi.ExternalSnapshot + 9, // 32: ateapi.ActorStatus.local_snapshot:type_name -> ateapi.LocalSnapshot + 12, // 33: ateapi.ActorStatus.actor_volumes:type_name -> ateapi.ExternalVolume + 27, // 34: ateapi.ActorStatus.crash:type_name -> ateapi.ActorCrash + 70, // 35: ateapi.ActorStatus.fencing_token:type_name -> ateapi.FencingToken + 130, // 36: ateapi.ActorCrash.crash_time:type_name -> google.protobuf.Timestamp + 32, // 37: ateapi.WorkerAssignment.worker:type_name -> ateapi.ObjectRef + 8, // 38: ateapi.TagStatus.snapshot:type_name -> ateapi.ExternalSnapshot + 11, // 39: ateapi.Tag.metadata:type_name -> ateapi.ResourceMetadata + 29, // 40: ateapi.Tag.status:type_name -> ateapi.TagStatus + 1, // 41: ateapi.Tag.scope:type_name -> ateapi.TagScope + 32, // 42: ateapi.Tag.source_actor:type_name -> ateapi.ObjectRef + 11, // 43: ateapi.Atespace.metadata:type_name -> ateapi.ResourceMetadata + 11, // 44: ateapi.ActorTemplate.metadata:type_name -> ateapi.ResourceMetadata + 10, // 45: ateapi.ActorTemplate.worker_selector:type_name -> ateapi.Selector + 40, // 46: ateapi.ActorTemplate.containers:type_name -> ateapi.Container + 46, // 47: ateapi.ActorTemplate.volumes:type_name -> ateapi.Volume + 39, // 48: ateapi.ActorTemplate.snapshot_config:type_name -> ateapi.SnapshotConfig + 38, // 49: ateapi.ActorTemplate.sandbox_config:type_name -> ateapi.SandboxConfig + 34, // 50: ateapi.ActorTemplate.resources:type_name -> ateapi.Resources + 37, // 51: ateapi.ActorTemplate.status:type_name -> ateapi.ActorTemplateStatus + 16, // 52: ateapi.ActorTemplate.default_egress_policy:type_name -> ateapi.EgressPolicyTemplate + 35, // 53: ateapi.Resources.limits:type_name -> ateapi.Limits + 32, // 54: ateapi.GoldenSnapshotStatus.golden_tag:type_name -> ateapi.ObjectRef + 130, // 55: ateapi.GoldenSnapshotStatus.take_golden_snapshot_at:type_name -> google.protobuf.Timestamp + 36, // 56: ateapi.ActorTemplateStatus.golden_snapshot_status:type_name -> ateapi.GoldenSnapshotStatus + 4, // 57: ateapi.SandboxConfig.sandbox_class:type_name -> ateapi.SandboxClass + 0, // 58: ateapi.SnapshotConfig.on_pause:type_name -> ateapi.SnapshotContentScope + 0, // 59: ateapi.SnapshotConfig.on_commit:type_name -> ateapi.SnapshotContentScope + 43, // 60: ateapi.Container.env:type_name -> ateapi.EnvVar + 44, // 61: ateapi.Container.wakeup_probe:type_name -> ateapi.ContainerWakeupProbe + 56, // 62: ateapi.Container.volume_mounts:type_name -> ateapi.VolumeMount + 41, // 63: ateapi.Container.security_context:type_name -> ateapi.SecurityContext + 34, // 64: ateapi.Container.resources:type_name -> ateapi.Resources + 42, // 65: ateapi.SecurityContext.capabilities:type_name -> ateapi.Capabilities + 45, // 66: ateapi.ContainerWakeupProbe.http_get:type_name -> ateapi.HTTPGetAction + 49, // 67: ateapi.Volume.durable_dir:type_name -> ateapi.DurableDirVolumeSource + 50, // 68: ateapi.Volume.external_volume_template:type_name -> ateapi.ExternalVolumeTemplate + 51, // 69: ateapi.Volume.system_info:type_name -> ateapi.SystemInfoVolumeSource + 48, // 70: ateapi.Volume.image:type_name -> ateapi.ImageVolumeSource + 47, // 71: ateapi.Volume.existing_volume:type_name -> ateapi.ExistingVolumeSource + 52, // 72: ateapi.SystemInfoVolumeSource.data_sources:type_name -> ateapi.SystemInfoDataSource + 53, // 73: ateapi.SystemInfoDataSource.actor_metadata:type_name -> ateapi.ActorMetadataDataSource + 55, // 74: ateapi.SystemInfoDataSource.trust_bundle:type_name -> ateapi.TrustBundleDataSource + 54, // 75: ateapi.ActorMetadataDataSource.items:type_name -> ateapi.ActorMetadataItem + 5, // 76: ateapi.ActorMetadataItem.field:type_name -> ateapi.ActorMetadataField + 31, // 77: ateapi.CreateAtespaceRequest.atespace:type_name -> ateapi.Atespace + 32, // 78: ateapi.GetAtespaceRequest.atespace:type_name -> ateapi.ObjectRef + 31, // 79: ateapi.ListAtespacesResponse.atespaces:type_name -> ateapi.Atespace + 32, // 80: ateapi.DeleteAtespaceRequest.atespace:type_name -> ateapi.ObjectRef + 96, // 81: ateapi.DeleteAtespaceRequest.options:type_name -> ateapi.DeleteOptions + 33, // 82: ateapi.CreateActorTemplateRequest.actor_template:type_name -> ateapi.ActorTemplate + 32, // 83: ateapi.GetActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef + 33, // 84: ateapi.ListActorTemplatesResponse.actor_templates:type_name -> ateapi.ActorTemplate + 32, // 85: ateapi.DeleteActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef + 96, // 86: ateapi.DeleteActorTemplateRequest.options:type_name -> ateapi.DeleteOptions + 32, // 87: ateapi.GetActorRequest.actor:type_name -> ateapi.ObjectRef + 13, // 88: ateapi.CreateActorRequest.actor:type_name -> ateapi.Actor + 13, // 89: ateapi.UpdateActorRequest.actor:type_name -> ateapi.Actor + 32, // 90: ateapi.SuspendActorRequest.actor:type_name -> ateapi.ObjectRef + 70, // 91: ateapi.SuspendActorRequest.fencing_token:type_name -> ateapi.FencingToken + 13, // 92: ateapi.SuspendActorResponse.actor:type_name -> ateapi.Actor + 32, // 93: ateapi.PauseActorRequest.actor:type_name -> ateapi.ObjectRef + 70, // 94: ateapi.PauseActorRequest.fencing_token:type_name -> ateapi.FencingToken + 13, // 95: ateapi.PauseActorResponse.actor:type_name -> ateapi.Actor + 32, // 96: ateapi.ResumeActorRequest.actor:type_name -> ateapi.ObjectRef + 70, // 97: ateapi.ResumeActorRequest.fencing_token:type_name -> ateapi.FencingToken + 13, // 98: ateapi.ResumeActorResponse.actor:type_name -> ateapi.Actor + 32, // 99: ateapi.RevertActorRequest.actor:type_name -> ateapi.ObjectRef + 13, // 100: ateapi.RevertActorResponse.actor:type_name -> ateapi.Actor + 32, // 101: ateapi.DeleteActorRequest.actor:type_name -> ateapi.ObjectRef + 96, // 102: ateapi.DeleteActorRequest.options:type_name -> ateapi.DeleteOptions + 32, // 103: ateapi.GetActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 32, // 104: ateapi.CreateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 15, // 105: ateapi.CreateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy + 32, // 106: ateapi.UpdateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 15, // 107: ateapi.UpdateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy + 32, // 108: ateapi.DeleteActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 96, // 109: ateapi.DeleteActorEgressPolicyRequest.options:type_name -> ateapi.DeleteOptions + 32, // 110: ateapi.GetTagRequest.tag:type_name -> ateapi.ObjectRef + 32, // 111: ateapi.MintActorJWTRequest.actor:type_name -> ateapi.ObjectRef + 130, // 112: ateapi.MintActorJWTResponse.expires_at:type_name -> google.protobuf.Timestamp + 32, // 113: ateapi.MintActorCertificateRequest.actor:type_name -> ateapi.ObjectRef + 30, // 114: ateapi.ListTagsResponse.tags:type_name -> ateapi.Tag + 30, // 115: ateapi.CreateTagRequest.tag:type_name -> ateapi.Tag + 30, // 116: ateapi.UpdateTagRequest.tag:type_name -> ateapi.Tag + 32, // 117: ateapi.DeleteTagRequest.tag:type_name -> ateapi.ObjectRef + 96, // 118: ateapi.DeleteTagRequest.options:type_name -> ateapi.DeleteOptions + 32, // 119: ateapi.ListWorkerActorAssignmentsRequest.worker:type_name -> ateapi.ObjectRef + 111, // 120: ateapi.ListWorkerActorAssignmentsResponse.actor_assignments:type_name -> ateapi.ActorAssignment + 108, // 121: ateapi.ListWorkersResponse.workers:type_name -> ateapi.Worker + 32, // 122: ateapi.GetWorkerRequest.worker:type_name -> ateapi.ObjectRef + 108, // 123: ateapi.CreateWorkerRequest.worker:type_name -> ateapi.Worker + 108, // 124: ateapi.UpdateWorkerRequest.worker:type_name -> ateapi.Worker + 32, // 125: ateapi.DeleteWorkerRequest.worker:type_name -> ateapi.ObjectRef + 96, // 126: ateapi.DeleteWorkerRequest.options:type_name -> ateapi.DeleteOptions + 32, // 127: ateapi.DrainWorkerRequest.worker:type_name -> ateapi.ObjectRef + 13, // 128: ateapi.ListActorsResponse.actors:type_name -> ateapi.Actor + 11, // 129: ateapi.Worker.metadata:type_name -> ateapi.ResourceMetadata + 129, // 130: ateapi.Worker.labels:type_name -> ateapi.Worker.LabelsEntry + 109, // 131: ateapi.Worker.status:type_name -> ateapi.WorkerStatus + 6, // 132: ateapi.WorkerStatus.state:type_name -> ateapi.WorkerState + 110, // 133: ateapi.WorkerStatus.capacity:type_name -> ateapi.WorkerResources + 110, // 134: ateapi.WorkerStatus.allocated:type_name -> ateapi.WorkerResources + 34, // 135: ateapi.WorkerResources.resources:type_name -> ateapi.Resources + 11, // 136: ateapi.ActorAssignment.metadata:type_name -> ateapi.ResourceMetadata + 32, // 137: ateapi.ActorAssignment.actor:type_name -> ateapi.ObjectRef + 32, // 138: ateapi.ActorAssignment.actor_template_ref:type_name -> ateapi.ObjectRef + 34, // 139: ateapi.ActorAssignment.resources:type_name -> ateapi.Resources + 32, // 140: ateapi.SetWorkerCapacityRequest.worker:type_name -> ateapi.ObjectRef + 110, // 141: ateapi.SetWorkerCapacityRequest.capacity:type_name -> ateapi.WorkerResources + 108, // 142: ateapi.SetWorkerCapacityResponse.worker:type_name -> ateapi.Worker + 32, // 143: ateapi.MintAteomActorCertificateRequest.actor:type_name -> ateapi.ObjectRef + 32, // 144: ateapi.RequestActorSuspendRequest.worker:type_name -> ateapi.ObjectRef + 32, // 145: ateapi.RequestActorSuspendRequest.actor:type_name -> ateapi.ObjectRef + 13, // 146: ateapi.RequestActorSuspendResponse.actor:type_name -> ateapi.Actor + 11, // 147: ateapi.AccessPolicy.metadata:type_name -> ateapi.ResourceMetadata + 119, // 148: ateapi.AccessPolicy.bindings:type_name -> ateapi.Binding + 118, // 149: ateapi.CreateGlobalAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy + 118, // 150: ateapi.UpdateGlobalAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy + 32, // 151: ateapi.GetAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef + 32, // 152: ateapi.CreateAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef + 118, // 153: ateapi.CreateAtespaceAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy + 32, // 154: ateapi.UpdateAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef + 118, // 155: ateapi.UpdateAtespaceAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy + 32, // 156: ateapi.DeleteAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef + 96, // 157: ateapi.DeleteAtespaceAccessPolicyRequest.options:type_name -> ateapi.DeleteOptions + 67, // 158: ateapi.Control.GetActor:input_type -> ateapi.GetActorRequest + 68, // 159: ateapi.Control.CreateActor:input_type -> ateapi.CreateActorRequest + 69, // 160: ateapi.Control.UpdateActor:input_type -> ateapi.UpdateActorRequest + 71, // 161: ateapi.Control.SuspendActor:input_type -> ateapi.SuspendActorRequest + 73, // 162: ateapi.Control.PauseActor:input_type -> ateapi.PauseActorRequest + 75, // 163: ateapi.Control.ResumeActor:input_type -> ateapi.ResumeActorRequest + 77, // 164: ateapi.Control.RevertActor:input_type -> ateapi.RevertActorRequest + 79, // 165: ateapi.Control.DeleteActor:input_type -> ateapi.DeleteActorRequest + 80, // 166: ateapi.Control.GetActorEgressPolicy:input_type -> ateapi.GetActorEgressPolicyRequest + 81, // 167: ateapi.Control.CreateActorEgressPolicy:input_type -> ateapi.CreateActorEgressPolicyRequest + 82, // 168: ateapi.Control.UpdateActorEgressPolicy:input_type -> ateapi.UpdateActorEgressPolicyRequest + 83, // 169: ateapi.Control.DeleteActorEgressPolicy:input_type -> ateapi.DeleteActorEgressPolicyRequest + 84, // 170: ateapi.Control.GetEgressPolicyContract:input_type -> ateapi.GetEgressPolicyContractRequest + 87, // 171: ateapi.Control.MintActorJWT:input_type -> ateapi.MintActorJWTRequest + 89, // 172: ateapi.Control.MintActorCertificate:input_type -> ateapi.MintActorCertificateRequest + 93, // 173: ateapi.Control.CreateTag:input_type -> ateapi.CreateTagRequest + 86, // 174: ateapi.Control.GetTag:input_type -> ateapi.GetTagRequest + 91, // 175: ateapi.Control.ListTags:input_type -> ateapi.ListTagsRequest + 94, // 176: ateapi.Control.UpdateTag:input_type -> ateapi.UpdateTagRequest + 95, // 177: ateapi.Control.DeleteTag:input_type -> ateapi.DeleteTagRequest + 99, // 178: ateapi.Control.ListWorkers:input_type -> ateapi.ListWorkersRequest + 101, // 179: ateapi.Control.GetWorker:input_type -> ateapi.GetWorkerRequest + 102, // 180: ateapi.Control.CreateWorker:input_type -> ateapi.CreateWorkerRequest + 103, // 181: ateapi.Control.UpdateWorker:input_type -> ateapi.UpdateWorkerRequest + 104, // 182: ateapi.Control.DeleteWorker:input_type -> ateapi.DeleteWorkerRequest + 105, // 183: ateapi.Control.DrainWorker:input_type -> ateapi.DrainWorkerRequest + 97, // 184: ateapi.Control.ListWorkerActorAssignments:input_type -> ateapi.ListWorkerActorAssignmentsRequest + 106, // 185: ateapi.Control.ListActors:input_type -> ateapi.ListActorsRequest + 57, // 186: ateapi.Control.CreateAtespace:input_type -> ateapi.CreateAtespaceRequest + 58, // 187: ateapi.Control.GetAtespace:input_type -> ateapi.GetAtespaceRequest + 59, // 188: ateapi.Control.ListAtespaces:input_type -> ateapi.ListAtespacesRequest + 61, // 189: ateapi.Control.DeleteAtespace:input_type -> ateapi.DeleteAtespaceRequest + 62, // 190: ateapi.Control.CreateActorTemplate:input_type -> ateapi.CreateActorTemplateRequest + 63, // 191: ateapi.Control.GetActorTemplate:input_type -> ateapi.GetActorTemplateRequest + 64, // 192: ateapi.Control.ListActorTemplates:input_type -> ateapi.ListActorTemplatesRequest + 66, // 193: ateapi.Control.DeleteActorTemplate:input_type -> ateapi.DeleteActorTemplateRequest + 120, // 194: ateapi.Control.GetGlobalAccessPolicy:input_type -> ateapi.GetGlobalAccessPolicyRequest + 121, // 195: ateapi.Control.CreateGlobalAccessPolicy:input_type -> ateapi.CreateGlobalAccessPolicyRequest + 122, // 196: ateapi.Control.UpdateGlobalAccessPolicy:input_type -> ateapi.UpdateGlobalAccessPolicyRequest + 123, // 197: ateapi.Control.GetAtespaceAccessPolicy:input_type -> ateapi.GetAtespaceAccessPolicyRequest + 124, // 198: ateapi.Control.CreateAtespaceAccessPolicy:input_type -> ateapi.CreateAtespaceAccessPolicyRequest + 125, // 199: ateapi.Control.UpdateAtespaceAccessPolicy:input_type -> ateapi.UpdateAtespaceAccessPolicyRequest + 126, // 200: ateapi.Control.DeleteAtespaceAccessPolicy:input_type -> ateapi.DeleteAtespaceAccessPolicyRequest + 112, // 201: ateapi.WorkerService.SetWorkerCapacity:input_type -> ateapi.SetWorkerCapacityRequest + 114, // 202: ateapi.WorkerService.MintAteomActorCertificate:input_type -> ateapi.MintAteomActorCertificateRequest + 116, // 203: ateapi.WorkerService.RequestActorSuspend:input_type -> ateapi.RequestActorSuspendRequest + 13, // 204: ateapi.Control.GetActor:output_type -> ateapi.Actor + 13, // 205: ateapi.Control.CreateActor:output_type -> ateapi.Actor + 13, // 206: ateapi.Control.UpdateActor:output_type -> ateapi.Actor + 72, // 207: ateapi.Control.SuspendActor:output_type -> ateapi.SuspendActorResponse + 74, // 208: ateapi.Control.PauseActor:output_type -> ateapi.PauseActorResponse + 76, // 209: ateapi.Control.ResumeActor:output_type -> ateapi.ResumeActorResponse + 78, // 210: ateapi.Control.RevertActor:output_type -> ateapi.RevertActorResponse + 13, // 211: ateapi.Control.DeleteActor:output_type -> ateapi.Actor + 15, // 212: ateapi.Control.GetActorEgressPolicy:output_type -> ateapi.EgressPolicy + 15, // 213: ateapi.Control.CreateActorEgressPolicy:output_type -> ateapi.EgressPolicy + 15, // 214: ateapi.Control.UpdateActorEgressPolicy:output_type -> ateapi.EgressPolicy + 15, // 215: ateapi.Control.DeleteActorEgressPolicy:output_type -> ateapi.EgressPolicy + 85, // 216: ateapi.Control.GetEgressPolicyContract:output_type -> ateapi.EgressPolicyContract + 88, // 217: ateapi.Control.MintActorJWT:output_type -> ateapi.MintActorJWTResponse + 90, // 218: ateapi.Control.MintActorCertificate:output_type -> ateapi.MintActorCertificateResponse + 30, // 219: ateapi.Control.CreateTag:output_type -> ateapi.Tag + 30, // 220: ateapi.Control.GetTag:output_type -> ateapi.Tag + 92, // 221: ateapi.Control.ListTags:output_type -> ateapi.ListTagsResponse + 30, // 222: ateapi.Control.UpdateTag:output_type -> ateapi.Tag + 30, // 223: ateapi.Control.DeleteTag:output_type -> ateapi.Tag + 100, // 224: ateapi.Control.ListWorkers:output_type -> ateapi.ListWorkersResponse + 108, // 225: ateapi.Control.GetWorker:output_type -> ateapi.Worker + 108, // 226: ateapi.Control.CreateWorker:output_type -> ateapi.Worker + 108, // 227: ateapi.Control.UpdateWorker:output_type -> ateapi.Worker + 108, // 228: ateapi.Control.DeleteWorker:output_type -> ateapi.Worker + 108, // 229: ateapi.Control.DrainWorker:output_type -> ateapi.Worker + 98, // 230: ateapi.Control.ListWorkerActorAssignments:output_type -> ateapi.ListWorkerActorAssignmentsResponse + 107, // 231: ateapi.Control.ListActors:output_type -> ateapi.ListActorsResponse + 31, // 232: ateapi.Control.CreateAtespace:output_type -> ateapi.Atespace + 31, // 233: ateapi.Control.GetAtespace:output_type -> ateapi.Atespace + 60, // 234: ateapi.Control.ListAtespaces:output_type -> ateapi.ListAtespacesResponse + 31, // 235: ateapi.Control.DeleteAtespace:output_type -> ateapi.Atespace + 33, // 236: ateapi.Control.CreateActorTemplate:output_type -> ateapi.ActorTemplate + 33, // 237: ateapi.Control.GetActorTemplate:output_type -> ateapi.ActorTemplate + 65, // 238: ateapi.Control.ListActorTemplates:output_type -> ateapi.ListActorTemplatesResponse + 33, // 239: ateapi.Control.DeleteActorTemplate:output_type -> ateapi.ActorTemplate + 118, // 240: ateapi.Control.GetGlobalAccessPolicy:output_type -> ateapi.AccessPolicy + 118, // 241: ateapi.Control.CreateGlobalAccessPolicy:output_type -> ateapi.AccessPolicy + 118, // 242: ateapi.Control.UpdateGlobalAccessPolicy:output_type -> ateapi.AccessPolicy + 118, // 243: ateapi.Control.GetAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy + 118, // 244: ateapi.Control.CreateAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy + 118, // 245: ateapi.Control.UpdateAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy + 118, // 246: ateapi.Control.DeleteAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy + 113, // 247: ateapi.WorkerService.SetWorkerCapacity:output_type -> ateapi.SetWorkerCapacityResponse + 115, // 248: ateapi.WorkerService.MintAteomActorCertificate:output_type -> ateapi.MintAteomActorCertificateResponse + 117, // 249: ateapi.WorkerService.RequestActorSuspend:output_type -> ateapi.RequestActorSuspendResponse + 204, // [204:250] is the sub-list for method output_type + 158, // [158:204] is the sub-list for method input_type + 158, // [158:158] is the sub-list for extension type_name + 158, // [158:158] is the sub-list for extension extendee + 0, // [0:158] is the sub-list for field type_name } func init() { file_ateapi_proto_init() } @@ -9222,8 +9520,8 @@ func file_ateapi_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_ateapi_proto_rawDesc), len(file_ateapi_proto_rawDesc)), - NumEnums: 7, - NumMessages: 120, + NumEnums: 8, + NumMessages: 122, NumExtensions: 0, NumServices: 2, }, diff --git a/pkg/proto/ateapipb/ateapi.proto b/pkg/proto/ateapipb/ateapi.proto index 27ab20e3f4..ffe4a58da2 100644 --- a/pkg/proto/ateapipb/ateapi.proto +++ b/pkg/proto/ateapipb/ateapi.proto @@ -460,6 +460,84 @@ message Actor { // // +k8s:optional ActorStatus status = 7; + + // existing_volumes supply the template's existing volumes + // (Volume.existing_volume) for this actor: each names one and references a + // CSI volume that exists outside Substrate and outlives the actor, such as + // a read-write-many volume several actors work on. Substrate attaches and + // mounts it for this actor, and never creates or deletes it nor changes its + // content. An existing volume of the template that this list does not name + // has neither the volume nor its mounts. An actor that names any boots from + // its image instead of restoring the template's golden snapshot, which was + // captured without these mounts. Set once at creation and immutable + // afterward. + // + // +k8s:optional + // +k8s:maxItems=8 + // +k8s:listType=map + // +k8s:listMapKey=name + // +k8s:immutable + repeated ExistingVolume existing_volumes = 10001; +} + +// VolumeAccessMode is how a volume may be attached and mounted across nodes. +enum VolumeAccessMode { + VOLUME_ACCESS_MODE_UNSPECIFIED = 0; + // Read-write on a single node (CSI SINGLE_NODE_WRITER). + VOLUME_ACCESS_MODE_READ_WRITE_ONCE = 1; + // Read-only on many nodes (CSI MULTI_NODE_READER_ONLY). + VOLUME_ACCESS_MODE_READ_ONLY_MANY = 2; + // Read-write on many nodes (CSI MULTI_NODE_MULTI_WRITER). + VOLUME_ACCESS_MODE_READ_WRITE_MANY = 3; +} + +// ExistingVolume references a CSI volume for one of the template's existing +// volumes. +message ExistingVolume { + // name of the template's existing volume this supplies. + // + // +k8s:required + // +k8s:format=k8s-short-name + string name = 1; + + // driver is the CSI driver that serves the volume. It must have a + // CSIDriverConfig. + // + // +k8s:required + // +k8s:maxLength=253 + // +k8s:customValidation # same syntax as ExternalVolume.volume_type + string driver = 2; + + // volume_handle is the driver's ID of the volume, as a Kubernetes + // PersistentVolume names it in spec.csi.volumeHandle. A PersistentVolume of + // the driver with this handle must exist; its spec.csi.volumeAttributes are + // passed to the driver when the volume is mounted. Several existing volumes + // of one actor may reference the same handle. + // + // +k8s:required + // +k8s:maxLength=256 + // +k8s:customValidation # no control characters + string volume_handle = 3; + + // access_mode is READ_WRITE_MANY or READ_ONLY_MANY, and must be one of the + // PersistentVolume's access modes. With READ_ONLY_MANY every mount of the + // volume is read-only. + // + // +k8s:required + // +k8s:minimum=2 + // +k8s:maximum=3 # keep in sync with VolumeAccessMode + VolumeAccessMode access_mode = 4; + + // sub_path is the directory of the volume that this actor sees as the + // volume's root, in the form of VolumeMount.sub_path; empty is the root. + // The template's mounts of the volume, and their own sub_path, are + // relative to it, so actors of one template can each work in a directory + // of their own. + // + // +k8s:optional + // +k8s:maxLength=4096 + // +k8s:customValidation # clean relative path + string sub_path = 5; } // EgressPolicy is an egress policy resource nested under an Actor. An Actor has @@ -1323,7 +1401,7 @@ message Volume { string name = 1; // Exactly one of durable_dir / external_volume_template / image / - // system_info must be set. + // system_info / existing_volume must be set. // // +k8s:optional // +k8s:unionMember @@ -1342,8 +1420,20 @@ message Volume { // +k8s:optional // +k8s:unionMember ImageVolumeSource image = 6; + + // existing_volume declares a volume each actor supplies at CreateActor + // (Actor.existing_volumes). + // + // +k8s:optional + // +k8s:unionMember + ExistingVolumeSource existing_volume = 10001; } +// ExistingVolumeSource declares a volume that exists outside Substrate and +// that each actor supplies at CreateActor in Actor.existing_volumes. An actor +// that supplies none has neither the volume nor its mounts. +message ExistingVolumeSource {} + // ImageVolumeSource mounts the contents of an OCI image, read-only. The // reference must include a digest: changing the image invalidates // snapshots. @@ -1495,6 +1585,24 @@ message VolumeMount { // +k8s:maxLength=4096 // +k8s:customValidation # clean-absolute-path shape; no regex/pattern tag exists string mount_path = 2; + + // sub_path is the directory of the volume to mount, relative to its root; + // empty mounts the root. It must be a clean relative path: no leading '/', + // no '.' or '..' element, no '//', no trailing '/' and no control + // characters. Only an existing volume's mount may set it. The directory + // must exist, and no element of it may be a symbolic link: a mount that + // would need either fails. + // + // +k8s:optional + // +k8s:maxLength=4096 + // +k8s:customValidation # clean relative path + string sub_path = 10001; + + // read_only mounts the volume read-only. Only an existing volume's mount + // may set it. + // + // +k8s:optional + bool read_only = 10002; } message CreateAtespaceRequest {