From 64e3351aba28ce489b2c302d7b4c2b9bb0dcda43 Mon Sep 17 00:00:00 2001 From: Elijah Rodriguez Date: Wed, 14 Oct 2026 10:31:39 -0700 Subject: [PATCH 01/12] api: nest the external volume template and rename the volume messages The ActorTemplate volume union now carries one CSI member, Volume.external (ExternalVolumeSource), whose template member replaces external_volume_template; a member for shared volumes follows after GA. The per-actor record on ActorStatus.external_volumes becomes ExternalVolumeRef, freeing the plain name for the atespace-scoped resource, and atelet's resolved handle becomes ExternalVolume to match its sibling volume messages. Templates that still carry external_volume_template must be recreated. Fixes #2407, #2436. Co-Authored-By: Claude Fable 5.1 --- .../glutton-storage-template.yaml.tmpl | 7 +- .../internal/demos/counter/counter.go | 7 +- .../internal/demos/counter/counter_test.go | 3 +- cmd/ateapi/internal/apivalidation/actor.go | 6 +- .../apivalidation/actor_template_test.go | 24 +- .../internal/apivalidation/actor_test.go | 14 +- .../internal/apivalidation/validation_test.go | 76 +- .../apivalidation/zz_generated.validation.go | 111 +- cmd/ateapi/internal/controlapi/actor.go | 2 +- .../controlapi/functionaltest/actor_test.go | 104 +- cmd/ateapi/internal/controlapi/volumes.go | 38 +- .../internal/controlapi/volumes_test.go | 114 +- .../internal/controlapi/workflow_delete.go | 4 +- .../internal/controlapi/workflow_resume.go | 2 +- .../controlapi/workflow_resume_test.go | 10 +- .../internal/controlapi/workload_spec.go | 6 +- .../internal/controlapi/workload_spec_test.go | 14 +- .../internal/apivalidation/validation_test.go | 26 +- .../internal/apivalidation/workloadspec.go | 8 +- .../apivalidation/zz_generated.validation.go | 36 +- cmd/atelet/main_test.go | 10 +- cmd/atelet/volumes_test.go | 14 +- .../counter-microvm-csi-test-template.yaml | 7 +- demos/sandbox/manual-test-multi-template.yaml | 14 +- docs/api-guide.md | 2 +- docs/api-style-guide.md | 4 +- docs/csi-volumes.md | 22 +- .../combinedvolumes/combinedvolumes_test.go | 4 +- internal/e2e/suites/demo/demo_test.go | 6 +- internal/proto/ateletpb/atelet.pb.go | 60 +- internal/proto/ateletpb/atelet.proto | 8 +- pkg/proto/ateapipb/ateapi.pb.go | 1211 +++++++++-------- pkg/proto/ateapipb/ateapi.proto | 29 +- tools/apitool/exemptions.json | 20 - tools/apitool/internal/model/model.go | 26 +- 35 files changed, 1083 insertions(+), 966 deletions(-) diff --git a/benchmarking/workloads/manifests/glutton-storage-template.yaml.tmpl b/benchmarking/workloads/manifests/glutton-storage-template.yaml.tmpl index 67812376f6..ab87bfa861 100644 --- a/benchmarking/workloads/manifests/glutton-storage-template.yaml.tmpl +++ b/benchmarking/workloads/manifests/glutton-storage-template.yaml.tmpl @@ -24,9 +24,10 @@ workerSelector: workload: benchmark-ateom volumes: - name: external-storage - externalVolumeTemplate: - capacity: 1Gi - storageClassName: ${STORAGE_CLASS_NAME} + external: + template: + capacity: 1Gi + storageClassName: ${STORAGE_CLASS_NAME} containers: - name: glutton-storage image: ko://github.com/agent-substrate/substrate/cmd/benchmarking/glutton diff --git a/cmd/ate-setup/internal/demos/counter/counter.go b/cmd/ate-setup/internal/demos/counter/counter.go index 39f5848036..fc58142853 100644 --- a/cmd/ate-setup/internal/demos/counter/counter.go +++ b/cmd/ate-setup/internal/demos/counter/counter.go @@ -40,9 +40,10 @@ func (d *demo) externalVolumeValues(e *steps.Env) map[string]string { "EXTERNAL_VOLUME_MOUNTS": " - name: external-data\n" + " mountPath: /external-data", "EXTERNAL_VOLUMES": "- name: external-data\n" + - " externalVolumeTemplate:\n" + - " capacity: 1Gi\n" + - " storageClassName: " + sc, + " external:\n" + + " template:\n" + + " capacity: 1Gi\n" + + " storageClassName: " + sc, } } diff --git a/cmd/ate-setup/internal/demos/counter/counter_test.go b/cmd/ate-setup/internal/demos/counter/counter_test.go index ada06a8977..d1fb4df85e 100644 --- a/cmd/ate-setup/internal/demos/counter/counter_test.go +++ b/cmd/ate-setup/internal/demos/counter/counter_test.go @@ -69,7 +69,8 @@ func TestExternalVolumeRenders(t *testing.T) { for _, want := range []string{ "--validate-existing-file-path=/external-data/test.txt", "mountPath: /external-data", - "externalVolumeTemplate:", + "external:", + "template:", tc.wantSC, } { if !strings.Contains(string(manifest), want) { diff --git a/cmd/ateapi/internal/apivalidation/actor.go b/cmd/ateapi/internal/apivalidation/actor.go index fc1b6895a7..2b7f353cd0 100644 --- a/cmd/ateapi/internal/apivalidation/actor.go +++ b/cmd/ateapi/internal/apivalidation/actor.go @@ -133,14 +133,14 @@ func ValidateCustom_WorkerAssignment_WorkerPodIps(_ context.Context, _ operation return validateDualStackIPs(fldPath, value) } -func ValidateCustom_ExternalVolume_VolumeType(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ *string) field.ErrorList { +func ValidateCustom_ExternalVolumeRef_VolumeType(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ *string) field.ErrorList { return resources.ValidateVolumeType(fldPath, *value) } -func ValidateCustom_ExternalVolume_StorageVolumeId(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ *string) field.ErrorList { +func ValidateCustom_ExternalVolumeRef_StorageVolumeId(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ *string) field.ErrorList { return resources.ValidateStorageVolumeID(fldPath, *value) } -func ValidateCustom_ExternalVolume_VolumeContext(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ map[string]string) field.ErrorList { +func ValidateCustom_ExternalVolumeRef_VolumeContext(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ map[string]string) field.ErrorList { return resources.ValidateCSIMap(fldPath, value) } diff --git a/cmd/ateapi/internal/apivalidation/actor_template_test.go b/cmd/ateapi/internal/apivalidation/actor_template_test.go index fe044102bf..41ab3a32b5 100644 --- a/cmd/ateapi/internal/apivalidation/actor_template_test.go +++ b/cmd/ateapi/internal/apivalidation/actor_template_test.go @@ -776,43 +776,43 @@ func TestValidateActorTemplate(t *testing.T) { }, { name: "valid external volume template", mutate: func(tmpl *ateapipb.ActorTemplate) { - tmpl.Volumes = []*ateapipb.Volume{{Name: "data", ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{Capacity: "10Gi", StorageClassName: "fast-ssd"}}} + tmpl.Volumes = []*ateapipb.Volume{{Name: "data", External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{Capacity: "10Gi", StorageClassName: "fast-ssd"}}}} }, }, { name: "external volume template missing capacity", mutate: func(tmpl *ateapipb.ActorTemplate) { - tmpl.Volumes = []*ateapipb.Volume{{Name: "data", ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{StorageClassName: "fast-ssd"}}} + tmpl.Volumes = []*ateapipb.Volume{{Name: "data", External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{StorageClassName: "fast-ssd"}}}} }, - want: field.ErrorList{field.Required(field.NewPath("volumes").Index(0).Child("external_volume_template", "capacity"), "")}, + want: field.ErrorList{field.Required(field.NewPath("volumes").Index(0).Child("external", "template", "capacity"), "")}, }, { name: "external volume template malformed capacity", mutate: func(tmpl *ateapipb.ActorTemplate) { - tmpl.Volumes = []*ateapipb.Volume{{Name: "data", ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{Capacity: "ten gigs", StorageClassName: "fast-ssd"}}} + tmpl.Volumes = []*ateapipb.Volume{{Name: "data", External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{Capacity: "ten gigs", StorageClassName: "fast-ssd"}}}} }, - want: field.ErrorList{field.Invalid(field.NewPath("volumes").Index(0).Child("external_volume_template", "capacity"), nil, "")}, + want: field.ErrorList{field.Invalid(field.NewPath("volumes").Index(0).Child("external", "template", "capacity"), nil, "")}, }, { name: "external volume template capacity at the length bound", mutate: func(tmpl *ateapipb.ActorTemplate) { - tmpl.Volumes = []*ateapipb.Volume{{Name: "data", ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{Capacity: strings.Repeat("1", 30) + "Gi", StorageClassName: "fast-ssd"}}} + tmpl.Volumes = []*ateapipb.Volume{{Name: "data", External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{Capacity: strings.Repeat("1", 30) + "Gi", StorageClassName: "fast-ssd"}}}} }, }, { name: "external volume template capacity too long", mutate: func(tmpl *ateapipb.ActorTemplate) { - tmpl.Volumes = []*ateapipb.Volume{{Name: "data", ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{Capacity: strings.Repeat("1", 31) + "Gi", StorageClassName: "fast-ssd"}}} + tmpl.Volumes = []*ateapipb.Volume{{Name: "data", External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{Capacity: strings.Repeat("1", 31) + "Gi", StorageClassName: "fast-ssd"}}}} }, - want: field.ErrorList{field.TooLong(field.NewPath("volumes").Index(0).Child("external_volume_template", "capacity"), nil, 32).WithOrigin("maxLength")}, + want: field.ErrorList{field.TooLong(field.NewPath("volumes").Index(0).Child("external", "template", "capacity"), nil, 32).WithOrigin("maxLength")}, }, { name: "external volume template missing storage_class_name", mutate: func(tmpl *ateapipb.ActorTemplate) { - tmpl.Volumes = []*ateapipb.Volume{{Name: "data", ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{Capacity: "10Gi"}}} + tmpl.Volumes = []*ateapipb.Volume{{Name: "data", External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{Capacity: "10Gi"}}}} }, - want: field.ErrorList{field.Required(field.NewPath("volumes").Index(0).Child("external_volume_template", "storage_class_name"), "")}, + want: field.ErrorList{field.Required(field.NewPath("volumes").Index(0).Child("external", "template", "storage_class_name"), "")}, }, { name: "external volume template invalid storage_class_name", mutate: func(tmpl *ateapipb.ActorTemplate) { - tmpl.Volumes = []*ateapipb.Volume{{Name: "data", ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{Capacity: "10Gi", StorageClassName: "Fast SSD"}}} + tmpl.Volumes = []*ateapipb.Volume{{Name: "data", External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{Capacity: "10Gi", StorageClassName: "Fast SSD"}}}} }, - want: field.ErrorList{field.Invalid(field.NewPath("volumes").Index(0).Child("external_volume_template", "storage_class_name"), nil, "").WithOrigin("format=k8s-long-name")}, + want: field.ErrorList{field.Invalid(field.NewPath("volumes").Index(0).Child("external", "template", "storage_class_name"), nil, "").WithOrigin("format=k8s-long-name")}, }, { name: "valid resources", mutate: func(tmpl *ateapipb.ActorTemplate) { diff --git a/cmd/ateapi/internal/apivalidation/actor_test.go b/cmd/ateapi/internal/apivalidation/actor_test.go index 63bd6d3175..08329ba850 100644 --- a/cmd/ateapi/internal/apivalidation/actor_test.go +++ b/cmd/ateapi/internal/apivalidation/actor_test.go @@ -610,9 +610,9 @@ func TestValidateActorUpdate(t *testing.T) { "too many external_volumes", validInput(), validOutput(withStatus(func(s *ateapipb.ActorStatus) { - vols := make([]*ateapipb.ExternalVolume, 33) + vols := make([]*ateapipb.ExternalVolumeRef, 33) for i := range vols { - vols[i] = &ateapipb.ExternalVolume{Name: fmt.Sprintf("vol-%d", i), VolumeType: "substrate.io/mock"} + vols[i] = &ateapipb.ExternalVolumeRef{Name: fmt.Sprintf("vol-%d", i), VolumeType: "substrate.io/mock"} } s.ExternalVolumes = vols })), @@ -623,14 +623,14 @@ func TestValidateActorUpdate(t *testing.T) { "adding a volume on update is allowed", validInput(withStatus()), validOutput(withStatus(func(s *ateapipb.ActorStatus) { - s.ExternalVolumes = []*ateapipb.ExternalVolume{{Name: "vol-a", VolumeType: "substrate.io/mock"}} + s.ExternalVolumes = []*ateapipb.ExternalVolumeRef{{Name: "vol-a", VolumeType: "substrate.io/mock"}} })), nil, }, { "duplicate external_volumes name", validInput(withStatus()), validOutput(withStatus(func(s *ateapipb.ActorStatus) { - s.ExternalVolumes = []*ateapipb.ExternalVolume{ + s.ExternalVolumes = []*ateapipb.ExternalVolumeRef{ {Name: "vol-a", VolumeType: "substrate.io/mock"}, {Name: "vol-a", VolumeType: "substrate.io/mock"}, } @@ -639,14 +639,14 @@ func TestValidateActorUpdate(t *testing.T) { }, { "provisioning transition on an existing volume is valid", validInput(withStatus(func(s *ateapipb.ActorStatus) { - s.ExternalVolumes = []*ateapipb.ExternalVolume{{Name: "vol-a", VolumeType: "substrate.io/mock", Status: ateapipb.ExternalVolume_STATUS_PENDING}} + s.ExternalVolumes = []*ateapipb.ExternalVolumeRef{{Name: "vol-a", VolumeType: "substrate.io/mock", Status: ateapipb.ExternalVolumeRef_STATUS_PENDING}} })), validOutput(withStatus(func(s *ateapipb.ActorStatus) { - s.ExternalVolumes = []*ateapipb.ExternalVolume{{ + s.ExternalVolumes = []*ateapipb.ExternalVolumeRef{{ Name: "vol-a", VolumeType: "substrate.io/mock", StorageVolumeId: "csi-426d29b7", - Status: ateapipb.ExternalVolume_STATUS_CREATED, + Status: ateapipb.ExternalVolumeRef_STATUS_CREATED, VolumeContext: map[string]string{"attachment": "iqn.2026-08.io.ate:vol-a"}, }} })), diff --git a/cmd/ateapi/internal/apivalidation/validation_test.go b/cmd/ateapi/internal/apivalidation/validation_test.go index 9a90cf92c7..10d30d18ed 100644 --- a/cmd/ateapi/internal/apivalidation/validation_test.go +++ b/cmd/ateapi/internal/apivalidation/validation_test.go @@ -871,12 +871,12 @@ func TestValidateTrustBundleDataSource(t *testing.T) { } } -func validExternalVolume(mutate ...func(*ateapipb.ExternalVolume)) *ateapipb.ExternalVolume { - v := &ateapipb.ExternalVolume{ +func validExternalVolume(mutate ...func(*ateapipb.ExternalVolumeRef)) *ateapipb.ExternalVolumeRef { + v := &ateapipb.ExternalVolumeRef{ Name: "my-vol", StorageVolumeId: "valid-storage-id", VolumeType: "mock", - Status: ateapipb.ExternalVolume_STATUS_CREATED, + Status: ateapipb.ExternalVolumeRef_STATUS_CREATED, } for _, m := range mutate { m(v) @@ -889,65 +889,65 @@ func TestValidateExternalVolume(t *testing.T) { tests := []struct { name string - obj *ateapipb.ExternalVolume + obj *ateapipb.ExternalVolumeRef want field.ErrorList }{{ name: "valid external volume", obj: valid(), }, { name: "missing volume name", - obj: valid(func(v *ateapipb.ExternalVolume) { v.Name = "" }), + obj: valid(func(v *ateapipb.ExternalVolumeRef) { v.Name = "" }), want: field.ErrorList{field.Required(field.NewPath("name"), "")}, }, { name: "invalid volume name", - obj: valid(func(v *ateapipb.ExternalVolume) { v.Name = "NOT A VOLUME" }), + obj: valid(func(v *ateapipb.ExternalVolumeRef) { v.Name = "NOT A VOLUME" }), want: field.ErrorList{field.Invalid(field.NewPath("name"), nil, "").WithOrigin("format=k8s-short-name")}, }, { name: "valid external volume with empty storage volume id", - obj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "" }), + obj: valid(func(v *ateapipb.ExternalVolumeRef) { v.StorageVolumeId = "" }), }, { name: "invalid storage volume id with null U+0000", - obj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "vol\x00id" }), + obj: valid(func(v *ateapipb.ExternalVolumeRef) { v.StorageVolumeId = "vol\x00id" }), want: field.ErrorList{field.Invalid(field.NewPath("storage_volume_id"), nil, "")}, }, { name: "storage volume id too long", - obj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = strings.Repeat("x", 257) }), + obj: valid(func(v *ateapipb.ExternalVolumeRef) { v.StorageVolumeId = strings.Repeat("x", 257) }), want: field.ErrorList{field.TooLong(field.NewPath("storage_volume_id"), nil, 256).WithOrigin("maxLength")}, }, { name: "missing volume type", - obj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeType = "" }), + obj: valid(func(v *ateapipb.ExternalVolumeRef) { v.VolumeType = "" }), want: field.ErrorList{field.Required(field.NewPath("volume_type"), "")}, }, { name: "invalid volume type with uppercase", - obj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeType = "MockPlugin" }), + obj: valid(func(v *ateapipb.ExternalVolumeRef) { v.VolumeType = "MockPlugin" }), want: field.ErrorList{field.Invalid(field.NewPath("volume_type"), nil, "")}, }, { name: "valid volume type with 253 characters", - obj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeType = strings.Repeat("a", 253) }), + obj: valid(func(v *ateapipb.ExternalVolumeRef) { v.VolumeType = strings.Repeat("a", 253) }), }, { name: "invalid volume type exceeding 253 characters", - obj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeType = strings.Repeat("a", 254) }), + obj: valid(func(v *ateapipb.ExternalVolumeRef) { v.VolumeType = strings.Repeat("a", 254) }), want: field.ErrorList{ field.Invalid(field.NewPath("volume_type"), nil, ""), field.TooLong(field.NewPath("volume_type"), nil, 253).WithOrigin("maxLength"), }, }, { name: "valid volume with substrate.io prefixed volume type", - obj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeType = "substrate.io/mock" }), + obj: valid(func(v *ateapipb.ExternalVolumeRef) { v.VolumeType = "substrate.io/mock" }), }, { name: "negative status", - obj: valid(func(v *ateapipb.ExternalVolume) { v.Status = ateapipb.ExternalVolume_Status(-1) }), + obj: valid(func(v *ateapipb.ExternalVolumeRef) { v.Status = ateapipb.ExternalVolumeRef_Status(-1) }), want: field.ErrorList{field.Invalid(field.NewPath("status"), nil, "").WithOrigin("minimum")}, }, { name: "status outside the enum", - obj: valid(func(v *ateapipb.ExternalVolume) { v.Status = ateapipb.ExternalVolume_Status(4) }), + obj: valid(func(v *ateapipb.ExternalVolumeRef) { v.Status = ateapipb.ExternalVolumeRef_Status(4) }), want: field.ErrorList{field.Invalid(field.NewPath("status"), nil, "").WithOrigin("maximum")}, }, { name: "storage volume id at the bound", - obj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = strings.Repeat("x", 256) }), + obj: valid(func(v *ateapipb.ExternalVolumeRef) { v.StorageVolumeId = strings.Repeat("x", 256) }), }, { name: "volume_context with many entries, as a CSI driver may return", - obj: valid(func(v *ateapipb.ExternalVolume) { + obj: valid(func(v *ateapipb.ExternalVolumeRef) { ctxMap := make(map[string]string, 100) for i := range 100 { ctxMap[fmt.Sprintf("key-%03d", i)] = "v" @@ -956,12 +956,12 @@ func TestValidateExternalVolume(t *testing.T) { }), }, { name: "volume_context with one long value, as a CSI driver may return", - obj: valid(func(v *ateapipb.ExternalVolume) { + obj: valid(func(v *ateapipb.ExternalVolumeRef) { v.VolumeContext = map[string]string{"attachment": strings.Repeat("v", 4000)} }), }, { name: "volume_context over the size bound", - obj: valid(func(v *ateapipb.ExternalVolume) { + obj: valid(func(v *ateapipb.ExternalVolumeRef) { v.VolumeContext = map[string]string{"attachment": strings.Repeat("v", 40*1024)} }), want: field.ErrorList{field.TooLong(field.NewPath("volume_context"), nil, 40*1024)}, @@ -969,7 +969,7 @@ func TestValidateExternalVolume(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { op := operation.Operation{Type: operation.Create} - assertValidateErr(t, Validate_ExternalVolume(context.Background(), op, nil, tt.obj, nil), tt.want) + assertValidateErr(t, Validate_ExternalVolumeRef(context.Background(), op, nil, tt.obj, nil), tt.want) }) } } @@ -979,8 +979,8 @@ func TestValidateExternalVolume_Update(t *testing.T) { tests := []struct { name string - oldObj *ateapipb.ExternalVolume - newObj *ateapipb.ExternalVolume + oldObj *ateapipb.ExternalVolumeRef + newObj *ateapipb.ExternalVolumeRef want field.ErrorList }{{ name: "unchanged volume is valid", @@ -988,43 +988,43 @@ func TestValidateExternalVolume_Update(t *testing.T) { newObj: valid(), }, { name: "name changed is invalid", - oldObj: valid(func(v *ateapipb.ExternalVolume) { v.Name = "vol1" }), - newObj: valid(func(v *ateapipb.ExternalVolume) { v.Name = "vol2" }), + oldObj: valid(func(v *ateapipb.ExternalVolumeRef) { v.Name = "vol1" }), + newObj: valid(func(v *ateapipb.ExternalVolumeRef) { v.Name = "vol2" }), want: field.ErrorList{field.Invalid(field.NewPath("name"), nil, "").WithOrigin("update")}, }, { name: "storage_volume_id transition from empty to non-empty is valid", - oldObj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "" }), - newObj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "vol-id-1" }), + oldObj: valid(func(v *ateapipb.ExternalVolumeRef) { v.StorageVolumeId = "" }), + newObj: valid(func(v *ateapipb.ExternalVolumeRef) { v.StorageVolumeId = "vol-id-1" }), }, { name: "storage_volume_id changed once set is invalid", - oldObj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "vol-id-1" }), - newObj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "vol-id-2" }), + oldObj: valid(func(v *ateapipb.ExternalVolumeRef) { v.StorageVolumeId = "vol-id-1" }), + newObj: valid(func(v *ateapipb.ExternalVolumeRef) { v.StorageVolumeId = "vol-id-2" }), want: field.ErrorList{field.Invalid(field.NewPath("storage_volume_id"), nil, "").WithOrigin("update")}, }, { name: "storage_volume_id unset once set is invalid", - oldObj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "vol-id-1" }), - newObj: valid(func(v *ateapipb.ExternalVolume) { v.StorageVolumeId = "" }), + oldObj: valid(func(v *ateapipb.ExternalVolumeRef) { v.StorageVolumeId = "vol-id-1" }), + newObj: valid(func(v *ateapipb.ExternalVolumeRef) { v.StorageVolumeId = "" }), want: field.ErrorList{field.Invalid(field.NewPath("storage_volume_id"), nil, "").WithOrigin("update")}, }, { name: "volume_type changed is invalid", - oldObj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeType = "mock" }), - newObj: valid(func(v *ateapipb.ExternalVolume) { v.VolumeType = "pd.csi.storage.gke.io" }), + oldObj: valid(func(v *ateapipb.ExternalVolumeRef) { v.VolumeType = "mock" }), + newObj: valid(func(v *ateapipb.ExternalVolumeRef) { v.VolumeType = "pd.csi.storage.gke.io" }), want: field.ErrorList{field.Invalid(field.NewPath("volume_type"), nil, "").WithOrigin("update")}, }, { name: "status and volume_context changed is valid", - oldObj: valid(func(v *ateapipb.ExternalVolume) { - v.Status = ateapipb.ExternalVolume_STATUS_PENDING + oldObj: valid(func(v *ateapipb.ExternalVolumeRef) { + v.Status = ateapipb.ExternalVolumeRef_STATUS_PENDING v.VolumeContext = nil }), - newObj: valid(func(v *ateapipb.ExternalVolume) { - v.Status = ateapipb.ExternalVolume_STATUS_CREATED + newObj: valid(func(v *ateapipb.ExternalVolumeRef) { + v.Status = ateapipb.ExternalVolumeRef_STATUS_CREATED v.VolumeContext = map[string]string{"foo": "bar"} }), }} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { op := operation.Operation{Type: operation.Update} - assertValidateErr(t, Validate_ExternalVolume(context.Background(), op, nil, tt.newObj, tt.oldObj), tt.want) + assertValidateErr(t, Validate_ExternalVolumeRef(context.Background(), op, nil, tt.newObj, tt.oldObj), tt.want) }) } } diff --git a/cmd/ateapi/internal/apivalidation/zz_generated.validation.go b/cmd/ateapi/internal/apivalidation/zz_generated.validation.go index 6cace304e7..eb7fc53ed5 100644 --- a/cmd/ateapi/internal/apivalidation/zz_generated.validation.go +++ b/cmd/ateapi/internal/apivalidation/zz_generated.validation.go @@ -709,7 +709,7 @@ func Validate_ActorStatus( { // field ateapipb.ActorStatus.ExternalVolumes fn := func( fldPath *field.Path, - obj, oldObj []*ateapipb.ExternalVolume, + obj, oldObj []*ateapipb.ExternalVolumeRef, oldValueCorrelated bool) (errs field.ErrorList) { // don't revalidate unchanged data if oldValueCorrelated && op.Type == operation.Update { @@ -719,7 +719,7 @@ func Validate_ActorStatus( } // call field-attached validations earlyReturn := false - if e := validate.PtrSliceNoNils[ateapipb.ExternalVolume](ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + if e := validate.PtrSliceNoNils[ateapipb.ExternalVolumeRef](ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { errs = append(errs, e...) earlyReturn = true } @@ -735,18 +735,18 @@ func Validate_ActorStatus( } // lists with map semantics require unique keys if e := validate.PtrSliceUnique(ctx, op, fldPath, obj, oldObj, - func(a *ateapipb.ExternalVolume, b *ateapipb.ExternalVolume) bool { return a.Name == b.Name }); len(e) != 0 { + func(a *ateapipb.ExternalVolumeRef, b *ateapipb.ExternalVolumeRef) 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.ExternalVolume, b *ateapipb.ExternalVolume) bool { return a.Name == b.Name }, ateDeepEqual, Validate_ExternalVolume); len(e) != 0 { + func(a *ateapipb.ExternalVolumeRef, b *ateapipb.ExternalVolumeRef) bool { return a.Name == b.Name }, ateDeepEqual, Validate_ExternalVolumeRef); len(e) != 0 { errs = append(errs, e...) } return } oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.ActorStatus) []*ateapipb.ExternalVolume { + func(oldObj *ateapipb.ActorStatus) []*ateapipb.ExternalVolumeRef { return oldObj.ExternalVolumes }) errs = append(errs, fn(fldPath.Child("external_volumes"), obj.ExternalVolumes, oldVal, oldObj != nil)...) @@ -3695,13 +3695,13 @@ func Validate_EnvVar( return errs } -// Validate_ExternalVolume validates an instance of ExternalVolume according +// Validate_ExternalVolumeRef validates an instance of ExternalVolumeRef according // to declarative validation rules in the API schema. -func Validate_ExternalVolume( +func Validate_ExternalVolumeRef( ctx context.Context, op operation.Operation, fldPath *field.Path, - obj, oldObj *ateapipb.ExternalVolume) (errs field.ErrorList) { + obj, oldObj *ateapipb.ExternalVolumeRef) (errs field.ErrorList) { - { // field ateapipb.ExternalVolume.Name + { // field ateapipb.ExternalVolumeRef.Name fn := func( fldPath *field.Path, obj, oldObj *string, @@ -3732,13 +3732,13 @@ func Validate_ExternalVolume( return } oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.ExternalVolume) *string { + func(oldObj *ateapipb.ExternalVolumeRef) *string { return &oldObj.Name }) errs = append(errs, fn(fldPath.Child("name"), &obj.Name, oldVal, oldObj != nil)...) } - { // field ateapipb.ExternalVolume.StorageVolumeId + { // field ateapipb.ExternalVolumeRef.StorageVolumeId fn := func( fldPath *field.Path, obj, oldObj *string, @@ -3763,7 +3763,7 @@ func Validate_ExternalVolume( return // do not proceed } // custom validation - if e := ValidateCustom_ExternalVolume_StorageVolumeId(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + if e := ValidateCustom_ExternalVolumeRef_StorageVolumeId(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 { @@ -3772,13 +3772,13 @@ func Validate_ExternalVolume( return } oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.ExternalVolume) *string { + func(oldObj *ateapipb.ExternalVolumeRef) *string { return &oldObj.StorageVolumeId }) errs = append(errs, fn(fldPath.Child("storage_volume_id"), &obj.StorageVolumeId, oldVal, oldObj != nil)...) } - { // field ateapipb.ExternalVolume.VolumeType + { // field ateapipb.ExternalVolumeRef.VolumeType fn := func( fldPath *field.Path, obj, oldObj *string, @@ -3804,7 +3804,7 @@ func Validate_ExternalVolume( return // do not proceed } // custom validation - if e := ValidateCustom_ExternalVolume_VolumeType(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + if e := ValidateCustom_ExternalVolumeRef_VolumeType(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 { @@ -3813,16 +3813,16 @@ func Validate_ExternalVolume( return } oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.ExternalVolume) *string { + func(oldObj *ateapipb.ExternalVolumeRef) *string { return &oldObj.VolumeType }) errs = append(errs, fn(fldPath.Child("volume_type"), &obj.VolumeType, oldVal, oldObj != nil)...) } - { // field ateapipb.ExternalVolume.Status + { // field ateapipb.ExternalVolumeRef.Status fn := func( fldPath *field.Path, - obj, oldObj *ateapipb.ExternalVolume_Status, + obj, oldObj *ateapipb.ExternalVolumeRef_Status, oldValueCorrelated bool) (errs field.ErrorList) { // don't revalidate unchanged data if oldValueCorrelated && op.Type == operation.Update { @@ -3847,13 +3847,13 @@ func Validate_ExternalVolume( return } oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.ExternalVolume) *ateapipb.ExternalVolume_Status { + func(oldObj *ateapipb.ExternalVolumeRef) *ateapipb.ExternalVolumeRef_Status { return &oldObj.Status }) errs = append(errs, fn(fldPath.Child("status"), &obj.Status, oldVal, oldObj != nil)...) } - { // field ateapipb.ExternalVolume.VolumeContext + { // field ateapipb.ExternalVolumeRef.VolumeContext fn := func( fldPath *field.Path, obj, oldObj map[string]string, @@ -3873,13 +3873,13 @@ func Validate_ExternalVolume( return // do not proceed } // custom validation - if e := ValidateCustom_ExternalVolume_VolumeContext(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + if e := ValidateCustom_ExternalVolumeRef_VolumeContext(ctx, op, fldPath, obj, oldObj); len(e) != 0 { errs = append(errs, e...) } return } oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.ExternalVolume) map[string]string { + func(oldObj *ateapipb.ExternalVolumeRef) map[string]string { return oldObj.VolumeContext }) errs = append(errs, fn(fldPath.Child("volume_context"), obj.VolumeContext, oldVal, oldObj != nil)...) @@ -3888,6 +3888,57 @@ func Validate_ExternalVolume( return errs } +var unionMembershipFor_github_com_agent_substrate_substrate_pkg_proto_ateapipb_ExternalVolumeSource_ = validate.NewUnionMembership(validate.NewUnionMember("template")) + +// Validate_ExternalVolumeSource validates an instance of ExternalVolumeSource according +// to declarative validation rules in the API schema. +func Validate_ExternalVolumeSource( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *ateapipb.ExternalVolumeSource) (errs field.ErrorList) { + + if e := validate.Union(ctx, op, fldPath, obj, oldObj, unionMembershipFor_github_com_agent_substrate_substrate_pkg_proto_ateapipb_ExternalVolumeSource_, + func(obj *ateapipb.ExternalVolumeSource) bool { + if obj == nil { + return false + } + return obj.Template != nil + }); len(e) != 0 { + errs = append(errs, e...) + } + + { // field ateapipb.ExternalVolumeSource.Template + fn := func( + fldPath *field.Path, + obj, oldObj *ateapipb.ExternalVolumeTemplate, + 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 + } + // call the type's validation function + errs = append(errs, Validate_ExternalVolumeTemplate(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.ExternalVolumeSource) *ateapipb.ExternalVolumeTemplate { + return oldObj.Template + }) + errs = append(errs, fn(fldPath.Child("template"), obj.Template, oldVal, oldObj != nil)...) + } + + return errs +} + // Validate_ExternalVolumeTemplate validates an instance of ExternalVolumeTemplate according // to declarative validation rules in the API schema. func Validate_ExternalVolumeTemplate( @@ -8759,7 +8810,7 @@ func Validate_VersionedSandboxCompat( 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"), validate.NewUnionMember("system_info"), validate.NewUnionMember("image")) // Validate_Volume validates an instance of Volume according // to declarative validation rules in the API schema. @@ -8778,7 +8829,7 @@ func Validate_Volume( if obj == nil { return false } - return obj.ExternalVolumeTemplate != nil + return obj.External != nil }, func(obj *ateapipb.Volume) bool { if obj == nil { @@ -8855,10 +8906,10 @@ func Validate_Volume( errs = append(errs, fn(fldPath.Child("durable_dir"), obj.DurableDir, oldVal, oldObj != nil)...) } - { // field ateapipb.Volume.ExternalVolumeTemplate + { // field ateapipb.Volume.External fn := func( fldPath *field.Path, - obj, oldObj *ateapipb.ExternalVolumeTemplate, + obj, oldObj *ateapipb.ExternalVolumeSource, oldValueCorrelated bool) (errs field.ErrorList) { // don't revalidate unchanged data if oldValueCorrelated && op.Type == operation.Update { @@ -8875,14 +8926,14 @@ func Validate_Volume( return // do not proceed } // call the type's validation function - errs = append(errs, Validate_ExternalVolumeTemplate(ctx, op, fldPath, obj, oldObj)...) + errs = append(errs, Validate_ExternalVolumeSource(ctx, op, fldPath, obj, oldObj)...) return } oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.Volume) *ateapipb.ExternalVolumeTemplate { - return oldObj.ExternalVolumeTemplate + func(oldObj *ateapipb.Volume) *ateapipb.ExternalVolumeSource { + return oldObj.External }) - errs = append(errs, fn(fldPath.Child("external_volume_template"), obj.ExternalVolumeTemplate, oldVal, oldObj != nil)...) + errs = append(errs, fn(fldPath.Child("external"), obj.External, oldVal, oldObj != nil)...) } { // field ateapipb.Volume.SystemInfo diff --git a/cmd/ateapi/internal/controlapi/actor.go b/cmd/ateapi/internal/controlapi/actor.go index 98e0004b37..f875b7b065 100644 --- a/cmd/ateapi/internal/controlapi/actor.go +++ b/cmd/ateapi/internal/controlapi/actor.go @@ -93,7 +93,7 @@ func (s *ServiceImpl) CreateActor(ctx context.Context, inActor *ateapipb.Actor) tagRef = template.GetStatus().GetGoldenSnapshotStatus().GetGoldenTag() } else { for _, volume := range template.GetVolumes() { - if volume.GetExternalVolumeTemplate() != nil { + if volume.GetExternal().GetTemplate() != nil { // TODO: Permit cloning after CSI volume snapshots are supported. return nil, apierror.FailedPrecondition("Tag cloning does not support ActorTemplates with external volumes") } diff --git a/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go b/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go index abefeb01a4..02f9fd1afc 100644 --- a/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go +++ b/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go @@ -117,10 +117,10 @@ func TestCreateActor_WithExternalVolumes(t *testing.T) { volumes := []*ateapipb.Volume{ { Name: "ext-vol-1", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", Capacity: "10Gi", - }, + }}, }, } mounts := []*ateapipb.VolumeMount{ @@ -148,8 +148,8 @@ func TestCreateActor_WithExternalVolumes(t *testing.T) { if vol.GetName() != "ext-vol-1" { t.Errorf("volume name = %q, want %q", vol.GetName(), "ext-vol-1") } - if vol.GetStatus() != ateapipb.ExternalVolume_STATUS_PENDING { - t.Errorf("volume status = %v, want %v", vol.GetStatus(), ateapipb.ExternalVolume_STATUS_PENDING) + if vol.GetStatus() != ateapipb.ExternalVolumeRef_STATUS_PENDING { + t.Errorf("volume status = %v, want %v", vol.GetStatus(), ateapipb.ExternalVolumeRef_STATUS_PENDING) } if vol.GetStorageVolumeId() != "" { t.Errorf("expected empty storageVolumeId before resume, got %q", vol.GetStorageVolumeId()) @@ -165,8 +165,8 @@ func TestCreateActor_WithExternalVolumes(t *testing.T) { if len(getResp.GetStatus().GetExternalVolumes()) != 1 { t.Fatalf("expected 1 volume in GetActor response, got %d", len(getResp.GetStatus().GetExternalVolumes())) } - if getResp.GetStatus().GetExternalVolumes()[0].GetStatus() != ateapipb.ExternalVolume_STATUS_PENDING { - t.Errorf("GetActor status = %v, want %v", getResp.GetStatus().GetExternalVolumes()[0].GetStatus(), ateapipb.ExternalVolume_STATUS_PENDING) + if getResp.GetStatus().GetExternalVolumes()[0].GetStatus() != ateapipb.ExternalVolumeRef_STATUS_PENDING { + t.Errorf("GetActor status = %v, want %v", getResp.GetStatus().GetExternalVolumes()[0].GetStatus(), ateapipb.ExternalVolumeRef_STATUS_PENDING) } } @@ -331,9 +331,9 @@ func TestCreateActor_RejectsSnapshotWithExternalVolumes(t *testing.T) { }}, Volumes: []*ateapipb.Volume{{ Name: "data", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ Capacity: "1Gi", StorageClassName: "standard", - }, + }}, }}, }, }) @@ -1372,9 +1372,9 @@ func TestDeleteActor_MultipleVolumeDeletionFailures(t *testing.T) { ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"}, Status: &ateapipb.ActorStatus{ State: ateapipb.ActorState_ACTOR_STATE_SUSPENDED, - ExternalVolumes: []*ateapipb.ExternalVolume{ - {Name: "vol1", StorageVolumeId: "storage-vol-1", Status: ateapipb.ExternalVolume_STATUS_CREATED, VolumeType: "substrate.io/mock"}, - {Name: "vol2", StorageVolumeId: "storage-vol-2", Status: ateapipb.ExternalVolume_STATUS_CREATED, VolumeType: "substrate.io/mock"}, + ExternalVolumes: []*ateapipb.ExternalVolumeRef{ + {Name: "vol1", StorageVolumeId: "storage-vol-1", Status: ateapipb.ExternalVolumeRef_STATUS_CREATED, VolumeType: "substrate.io/mock"}, + {Name: "vol2", StorageVolumeId: "storage-vol-2", Status: ateapipb.ExternalVolumeRef_STATUS_CREATED, VolumeType: "substrate.io/mock"}, }, }, } @@ -1421,7 +1421,7 @@ func (r *retryDeleteVolumePlugin) DeleteVolume(ctx context.Context, volumeID str // TestDeleteActor_VolumeDeletionFailure_RetrySuccess tests that when volume deletion fails // during DeleteActor, the actor transitions to ACTOR_STATE_DELETING and its volumes to -// ExternalVolume_STATUS_DELETING, and a subsequent retry of DeleteActor cleanly finalizes deletion. +// ExternalVolumeRef_STATUS_DELETING, and a subsequent retry of DeleteActor cleanly finalizes deletion. // // Workflow: // 1. Creates a suspended actor with a provisioned external volume. @@ -1448,8 +1448,8 @@ func TestDeleteActor_VolumeDeletionFailure_RetrySuccess(t *testing.T) { ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"}, Status: &ateapipb.ActorStatus{ State: ateapipb.ActorState_ACTOR_STATE_SUSPENDED, - ExternalVolumes: []*ateapipb.ExternalVolume{ - {Name: "vol1", StorageVolumeId: "storage-vol-1", Status: ateapipb.ExternalVolume_STATUS_CREATED, VolumeType: "substrate.io/mock"}, + ExternalVolumes: []*ateapipb.ExternalVolumeRef{ + {Name: "vol1", StorageVolumeId: "storage-vol-1", Status: ateapipb.ExternalVolumeRef_STATUS_CREATED, VolumeType: "substrate.io/mock"}, }, }, } @@ -1465,7 +1465,7 @@ func TestDeleteActor_VolumeDeletionFailure_RetrySuccess(t *testing.T) { t.Fatalf("expected DeleteActor to fail, but got nil") } - // 3. Verify actor is persisted in ACTOR_STATE_DELETING with volume in ExternalVolume_STATUS_DELETING. + // 3. Verify actor is persisted in ACTOR_STATE_DELETING with volume in ExternalVolumeRef_STATUS_DELETING. getResp, err := tc.service.GetActor(context.Background(), &ateapipb.GetActorRequest{ Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "delete-retry-actor"}, }) @@ -1475,7 +1475,7 @@ func TestDeleteActor_VolumeDeletionFailure_RetrySuccess(t *testing.T) { if getResp.GetStatus().GetState() != ateapipb.ActorState_ACTOR_STATE_DELETING { t.Errorf("actor state = %v, want ACTOR_STATE_DELETING", getResp.GetStatus().GetState()) } - if len(getResp.GetStatus().GetExternalVolumes()) != 1 || getResp.GetStatus().GetExternalVolumes()[0].GetStatus() != ateapipb.ExternalVolume_STATUS_DELETING { + if len(getResp.GetStatus().GetExternalVolumes()) != 1 || getResp.GetStatus().GetExternalVolumes()[0].GetStatus() != ateapipb.ExternalVolumeRef_STATUS_DELETING { t.Errorf("actor volume status = %v, want STATUS_DELETING", getResp.GetStatus().GetExternalVolumes()) } @@ -1580,10 +1580,10 @@ func TestActorLifecycle_WithExternalVolumes(t *testing.T) { volumes := []*ateapipb.Volume{ { Name: "data-vol", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "fast", Capacity: "20Gi", - }, + }}, }, } mounts := []*ateapipb.VolumeMount{ @@ -1608,7 +1608,7 @@ func TestActorLifecycle_WithExternalVolumes(t *testing.T) { if createResp.GetStatus().GetState() != ateapipb.ActorState_ACTOR_STATE_SUSPENDED { t.Fatalf("expected initial state ACTOR_STATE_SUSPENDED, got %v", createResp.GetStatus().GetState()) } - if len(createResp.GetStatus().GetExternalVolumes()) != 1 || createResp.GetStatus().GetExternalVolumes()[0].GetStatus() != ateapipb.ExternalVolume_STATUS_PENDING { + if len(createResp.GetStatus().GetExternalVolumes()) != 1 || createResp.GetStatus().GetExternalVolumes()[0].GetStatus() != ateapipb.ExternalVolumeRef_STATUS_PENDING { t.Fatalf("expected 1 pending volume after CreateActor, got %v", createResp.GetStatus().GetExternalVolumes()) } @@ -1622,7 +1622,7 @@ func TestActorLifecycle_WithExternalVolumes(t *testing.T) { if resumeResp.GetActor().GetStatus().GetState() != ateapipb.ActorState_ACTOR_STATE_RUNNING { t.Fatalf("expected state ACTOR_STATE_RUNNING after resume, got %v", resumeResp.GetActor().GetStatus().GetState()) } - if len(resumeResp.GetActor().GetStatus().GetExternalVolumes()) != 1 || resumeResp.GetActor().GetStatus().GetExternalVolumes()[0].GetStatus() != ateapipb.ExternalVolume_STATUS_CREATED { + if len(resumeResp.GetActor().GetStatus().GetExternalVolumes()) != 1 || resumeResp.GetActor().GetStatus().GetExternalVolumes()[0].GetStatus() != ateapipb.ExternalVolumeRef_STATUS_CREATED { t.Fatalf("expected 1 created volume after ResumeActor, got %v", resumeResp.GetActor().GetStatus().GetExternalVolumes()) } if resumeResp.GetActor().GetStatus().GetExternalVolumes()[0].GetStorageVolumeId() == "" { @@ -1723,17 +1723,17 @@ func TestResumeActor_VolumeCreationFailure(t *testing.T) { volumes := []*ateapipb.Volume{ { Name: "succ-vol1", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", Capacity: "10Gi", - }, + }}, }, { Name: "fail-vol2", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", Capacity: "10Gi", - }, + }}, }, } mounts := []*ateapipb.VolumeMount{ @@ -1781,14 +1781,14 @@ func TestResumeActor_VolumeCreationFailure(t *testing.T) { if len(getResp.GetStatus().GetExternalVolumes()) != 2 { t.Fatalf("expected 2 volumes on actor, got %d", len(getResp.GetStatus().GetExternalVolumes())) } - volsByName := make(map[string]*ateapipb.ExternalVolume) + volsByName := make(map[string]*ateapipb.ExternalVolumeRef) for _, v := range getResp.GetStatus().GetExternalVolumes() { volsByName[v.GetName()] = v } - if v1, ok := volsByName["succ-vol1"]; !ok || v1.GetStatus() != ateapipb.ExternalVolume_STATUS_CREATED || v1.GetStorageVolumeId() == "" { + if v1, ok := volsByName["succ-vol1"]; !ok || v1.GetStatus() != ateapipb.ExternalVolumeRef_STATUS_CREATED || v1.GetStorageVolumeId() == "" { t.Errorf("succ-vol1 unexpected state: %v", v1) } - if v2, ok := volsByName["fail-vol2"]; !ok || v2.GetStatus() != ateapipb.ExternalVolume_STATUS_PENDING { + if v2, ok := volsByName["fail-vol2"]; !ok || v2.GetStatus() != ateapipb.ExternalVolumeRef_STATUS_PENDING { t.Errorf("fail-vol2 unexpected state: %v", v2) } @@ -1865,17 +1865,17 @@ func TestResumeActor_VolumeCreationRetrySuccess(t *testing.T) { volumes := []*ateapipb.Volume{ { Name: "succ-vol1", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", Capacity: "10Gi", - }, + }}, }, { Name: "retry-vol2", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", Capacity: "10Gi", - }, + }}, }, } retryMounts := []*ateapipb.VolumeMount{ @@ -1915,14 +1915,14 @@ func TestResumeActor_VolumeCreationRetrySuccess(t *testing.T) { t.Errorf("actor state after first resume = %v, want %v", getResp.GetStatus().GetState(), ateapipb.ActorState_ACTOR_STATE_SUSPENDED) } - volsByName := make(map[string]*ateapipb.ExternalVolume) + volsByName := make(map[string]*ateapipb.ExternalVolumeRef) for _, v := range getResp.GetStatus().GetExternalVolumes() { volsByName[v.GetName()] = v } - if v1, ok := volsByName["succ-vol1"]; !ok || v1.GetStatus() != ateapipb.ExternalVolume_STATUS_CREATED || v1.GetStorageVolumeId() == "" { + if v1, ok := volsByName["succ-vol1"]; !ok || v1.GetStatus() != ateapipb.ExternalVolumeRef_STATUS_CREATED || v1.GetStorageVolumeId() == "" { t.Errorf("succ-vol1 unexpected state after first resume: %v", v1) } - if v2, ok := volsByName["retry-vol2"]; !ok || v2.GetStatus() != ateapipb.ExternalVolume_STATUS_PENDING { + if v2, ok := volsByName["retry-vol2"]; !ok || v2.GetStatus() != ateapipb.ExternalVolumeRef_STATUS_PENDING { t.Errorf("retry-vol2 unexpected state after first resume: %v", v2) } @@ -1945,7 +1945,7 @@ func TestResumeActor_VolumeCreationRetrySuccess(t *testing.T) { t.Errorf("actor state after second resume = %v, want %v", getResp.GetStatus().GetState(), ateapipb.ActorState_ACTOR_STATE_RUNNING) } for _, v := range getResp.GetStatus().GetExternalVolumes() { - if v.GetStatus() != ateapipb.ExternalVolume_STATUS_CREATED || v.GetStorageVolumeId() == "" { + if v.GetStatus() != ateapipb.ExternalVolumeRef_STATUS_CREATED || v.GetStorageVolumeId() == "" { t.Errorf("volume %s unexpected state after second resume: %v", v.GetName(), v) } } @@ -2019,10 +2019,10 @@ func TestResumeActor_VolumeAttachFailureAndRetry(t *testing.T) { volumes := []*ateapipb.Volume{ { Name: "vol1", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", Capacity: "10Gi", - }, + }}, }, } mounts := []*ateapipb.VolumeMount{ @@ -2070,7 +2070,7 @@ func TestResumeActor_VolumeAttachFailureAndRetry(t *testing.T) { t.Fatalf("expected 1 volume on actor, got %d", len(getResp.GetStatus().GetExternalVolumes())) } vol := getResp.GetStatus().GetExternalVolumes()[0] - if vol.GetStatus() != ateapipb.ExternalVolume_STATUS_CREATED || vol.GetStorageVolumeId() == "" { + if vol.GetStatus() != ateapipb.ExternalVolumeRef_STATUS_CREATED || vol.GetStorageVolumeId() == "" { t.Errorf("vol1 unexpected state after failed attach: %v", vol) } @@ -2121,10 +2121,10 @@ func TestResumeActor_VolumeAttachFailure_DeleteActor(t *testing.T) { volumes := []*ateapipb.Volume{ { Name: "vol1", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", Capacity: "10Gi", - }, + }}, }, } mounts := []*ateapipb.VolumeMount{ @@ -2276,17 +2276,17 @@ func TestResumeActor_MultiVolumePartialAttachFailure_Retry(t *testing.T) { volumes := []*ateapipb.Volume{ { Name: "vol1", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", Capacity: "10Gi", - }, + }}, }, { Name: "vol2", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", Capacity: "10Gi", - }, + }}, }, } mounts := []*ateapipb.VolumeMount{ @@ -2446,10 +2446,10 @@ func TestSuspendActor_VolumeDetachFailure_RetrySuccess(t *testing.T) { volumes := []*ateapipb.Volume{ { Name: "vol1", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", Capacity: "10Gi", - }, + }}, }, } mounts := []*ateapipb.VolumeMount{ @@ -2556,10 +2556,10 @@ func TestSuspendActor_VolumeDetachFailure_DeleteActorAnyState(t *testing.T) { volumes := []*ateapipb.Volume{ { Name: "vol1", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", Capacity: "10Gi", - }, + }}, }, } mounts := []*ateapipb.VolumeMount{ @@ -2655,10 +2655,10 @@ func TestPauseActor_VolumeLifecycle_DetachAndResumeAttach(t *testing.T) { volumes := []*ateapipb.Volume{ { Name: "vol1", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", Capacity: "10Gi", - }, + }}, }, } mounts := []*ateapipb.VolumeMount{ @@ -2778,10 +2778,10 @@ func TestPauseActor_VolumeDetachFailure_RetrySuccess(t *testing.T) { volumes := []*ateapipb.Volume{ { Name: "vol1", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", Capacity: "10Gi", - }, + }}, }, } mounts := []*ateapipb.VolumeMount{ diff --git a/cmd/ateapi/internal/controlapi/volumes.go b/cmd/ateapi/internal/controlapi/volumes.go index b2f8292599..a85a5d3f8c 100644 --- a/cmd/ateapi/internal/controlapi/volumes.go +++ b/cmd/ateapi/internal/controlapi/volumes.go @@ -30,14 +30,14 @@ import ( ) // initialActorVolumes constructs initial volume objects in PENDING state before volume creation. -func initialActorVolumes(ctx context.Context, scLister storagev1listers.StorageClassLister, template *ateapipb.ActorTemplate) ([]*ateapipb.ExternalVolume, error) { +func initialActorVolumes(ctx context.Context, scLister storagev1listers.StorageClassLister, template *ateapipb.ActorTemplate) ([]*ateapipb.ExternalVolumeRef, error) { if template == nil { return nil, apierror.InvalidArgument("template is required") } - var volumes []*ateapipb.ExternalVolume + var volumes []*ateapipb.ExternalVolumeRef for _, vol := range template.GetVolumes() { - if vol.GetExternalVolumeTemplate() != nil { - scName := vol.GetExternalVolumeTemplate().GetStorageClassName() + if vol.GetExternal().GetTemplate() != nil { + scName := vol.GetExternal().GetTemplate().GetStorageClassName() sc, err := scLister.Get(scName) if err != nil { if k8serrors.IsNotFound(err) { @@ -46,10 +46,10 @@ func initialActorVolumes(ctx context.Context, scLister storagev1listers.StorageC return nil, apierror.Internal("failed to get StorageClass %q: %v", scName, err) } - volumes = append(volumes, &ateapipb.ExternalVolume{ + volumes = append(volumes, &ateapipb.ExternalVolumeRef{ Name: vol.GetName(), VolumeType: sc.Provisioner, - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ExternalVolumeRef_STATUS_PENDING, }) } } @@ -59,8 +59,8 @@ func initialActorVolumes(ctx context.Context, scLister storagev1listers.StorageC // createActorVolumes provisions external volumes specified in volumesToCreate using the provided volume plugin. // It returns the list of external volumes (with updated status and storage IDs), or an error if any creation fails. // Any volumes processed before or during a failure are returned alongside the error so they can be persisted on the actor. -func createActorVolumes(ctx context.Context, registry VolumePluginRegistry, scLister storagev1listers.StorageClassLister, actorUID string, template *ateapipb.ActorTemplate, volumesToCreate []*ateapipb.ExternalVolume) (resultVolumes []*ateapipb.ExternalVolume, err error) { - resultVolumes = make([]*ateapipb.ExternalVolume, 0, len(volumesToCreate)) +func createActorVolumes(ctx context.Context, registry VolumePluginRegistry, scLister storagev1listers.StorageClassLister, actorUID string, template *ateapipb.ActorTemplate, volumesToCreate []*ateapipb.ExternalVolumeRef) (resultVolumes []*ateapipb.ExternalVolumeRef, err error) { + resultVolumes = make([]*ateapipb.ExternalVolumeRef, 0, len(volumesToCreate)) var currentIdx int defer func() { @@ -82,17 +82,17 @@ func createActorVolumes(ctx context.Context, registry VolumePluginRegistry, scLi break } } - if specVol == nil || specVol.GetExternalVolumeTemplate() == nil { + if specVol == nil || specVol.GetExternal().GetTemplate() == nil { return resultVolumes, apierror.NotFound("volume %q not found in template", volName) } switch vol.GetStatus() { - case ateapipb.ExternalVolume_STATUS_PENDING: + case ateapipb.ExternalVolumeRef_STATUS_PENDING: // proceed with volume creation - case ateapipb.ExternalVolume_STATUS_CREATED: + case ateapipb.ExternalVolumeRef_STATUS_CREATED: resultVolumes = append(resultVolumes, vol) continue - case ateapipb.ExternalVolume_STATUS_DELETING: + case ateapipb.ExternalVolumeRef_STATUS_DELETING: return resultVolumes, apierror.FailedPrecondition("cannot create volume %q in DELETING status", volName) default: return resultVolumes, apierror.Internal("unexpected status %s for volume %q", vol.GetStatus(), volName) @@ -100,7 +100,7 @@ func createActorVolumes(ctx context.Context, registry VolumePluginRegistry, scLi actVolID := actorVolumeID(actorUID, volName) - scName := specVol.GetExternalVolumeTemplate().GetStorageClassName() + scName := specVol.GetExternal().GetTemplate().GetStorageClassName() sc, err := scLister.Get(scName) if err != nil { if k8serrors.IsNotFound(err) { @@ -120,18 +120,18 @@ func createActorVolumes(ctx context.Context, registry VolumePluginRegistry, scLi resp, volErr := plugin.CreateVolume(ctx, volume.CreateVolumeRequest{ Name: actVolID, - Capacity: specVol.GetExternalVolumeTemplate().GetCapacity(), + Capacity: specVol.GetExternal().GetTemplate().GetCapacity(), Parameters: sc.Parameters, }) if volErr != nil { return resultVolumes, apierror.Internal("failed to create volume %q: %v", specVol.GetName(), volErr) } - resultVolumes = append(resultVolumes, &ateapipb.ExternalVolume{ + resultVolumes = append(resultVolumes, &ateapipb.ExternalVolumeRef{ Name: volName, StorageVolumeId: resp.VolumeID, VolumeType: sc.Provisioner, - Status: ateapipb.ExternalVolume_STATUS_CREATED, + Status: ateapipb.ExternalVolumeRef_STATUS_CREATED, VolumeContext: resp.VolumeContext, }) } @@ -139,7 +139,7 @@ func createActorVolumes(ctx context.Context, registry VolumePluginRegistry, scLi } // deleteActorVolumes deletes all external volumes in the list. -func deleteActorVolumes(ctx context.Context, registry VolumePluginRegistry, actorUID string, volumes []*ateapipb.ExternalVolume) error { +func deleteActorVolumes(ctx context.Context, registry VolumePluginRegistry, actorUID string, volumes []*ateapipb.ExternalVolumeRef) error { if actorUID == "" { return errors.New("actorUID is required") } @@ -171,8 +171,8 @@ func deleteActorVolumes(ctx context.Context, registry VolumePluginRegistry, acto } // getMountedActorVolumes filters the actor's volumes and returns only those that are declared and mounted in the ActorTemplate. -func getMountedActorVolumes(ctx context.Context, ref *ateapipb.ObjectRef, volumes []*ateapipb.ExternalVolume, template *ateapipb.ActorTemplate) []*ateapipb.ExternalVolume { - var mounted []*ateapipb.ExternalVolume +func getMountedActorVolumes(ctx context.Context, ref *ateapipb.ObjectRef, volumes []*ateapipb.ExternalVolumeRef, template *ateapipb.ActorTemplate) []*ateapipb.ExternalVolumeRef { + var mounted []*ateapipb.ExternalVolumeRef for _, vol := range volumes { // Find the corresponding volume in the ActorTemplate to check if it's mounted var matchedTemplateVol *ateapipb.Volume diff --git a/cmd/ateapi/internal/controlapi/volumes_test.go b/cmd/ateapi/internal/controlapi/volumes_test.go index 5fb207c11d..95e0d1b986 100644 --- a/cmd/ateapi/internal/controlapi/volumes_test.go +++ b/cmd/ateapi/internal/controlapi/volumes_test.go @@ -63,15 +63,15 @@ func TestActorVolumesStorageClassErrors(t *testing.T) { tmpl := &ateapipb.ActorTemplate{ Volumes: []*ateapipb.Volume{{ Name: "data-vol", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", - }, + }}, }}, } - volumes := []*ateapipb.ExternalVolume{{ + volumes := []*ateapipb.ExternalVolumeRef{{ Name: "data-vol", VolumeType: "mock-standard", - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ExternalVolumeRef_STATUS_PENDING, }} for _, tt := range []struct { @@ -121,9 +121,9 @@ func TestInitialActorVolumes_PendingState(t *testing.T) { Volumes: []*ateapipb.Volume{ { Name: "data-vol-1", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", - }, + }}, }, { Name: "scratch-vol", @@ -134,23 +134,23 @@ func TestInitialActorVolumes_PendingState(t *testing.T) { }, { Name: "data-vol-2", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "fast", - }, + }}, }, }, } - want := []*ateapipb.ExternalVolume{ + want := []*ateapipb.ExternalVolumeRef{ { Name: "data-vol-1", VolumeType: "mock-standard", - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ExternalVolumeRef_STATUS_PENDING, }, { Name: "data-vol-2", VolumeType: "mock-fast", - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ExternalVolumeRef_STATUS_PENDING, }, } @@ -182,9 +182,9 @@ func TestCreateActorVolumes(t *testing.T) { Volumes: []*ateapipb.Volume{ { Name: "data-vol", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", - }, + }}, }, }, } @@ -193,21 +193,21 @@ func TestCreateActorVolumes(t *testing.T) { Volumes: []*ateapipb.Volume{ { Name: "vol1", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", - }, + }}, }, { Name: "vol2", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", - }, + }}, }, { Name: "vol3", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "standard", - }, + }}, }, }, } @@ -215,108 +215,108 @@ func TestCreateActorVolumes(t *testing.T) { tests := []struct { name string tmpl *ateapipb.ActorTemplate - inputVolumes []*ateapipb.ExternalVolume + inputVolumes []*ateapipb.ExternalVolumeRef storageClasses map[string]*storagev1.StorageClass wantErr bool - wantRes []*ateapipb.ExternalVolume + wantRes []*ateapipb.ExternalVolumeRef }{ { name: "partial failure returns error and preserves succeeded, failed, and remaining volumes", tmpl: multiVolTmpl, - inputVolumes: []*ateapipb.ExternalVolume{ + inputVolumes: []*ateapipb.ExternalVolumeRef{ { Name: "vol1", VolumeType: "mock-standard", - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ExternalVolumeRef_STATUS_PENDING, }, { Name: "vol2", - Status: ateapipb.ExternalVolume_STATUS_DELETING, + Status: ateapipb.ExternalVolumeRef_STATUS_DELETING, }, { Name: "vol3", - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ExternalVolumeRef_STATUS_PENDING, }, }, wantErr: true, - wantRes: []*ateapipb.ExternalVolume{ + wantRes: []*ateapipb.ExternalVolumeRef{ { Name: "vol1", StorageVolumeId: "mock-vol-substrate-actor-uid-123-vol1", VolumeType: "mock-standard", - Status: ateapipb.ExternalVolume_STATUS_CREATED, + Status: ateapipb.ExternalVolumeRef_STATUS_CREATED, }, { Name: "vol2", - Status: ateapipb.ExternalVolume_STATUS_DELETING, + Status: ateapipb.ExternalVolumeRef_STATUS_DELETING, }, { Name: "vol3", - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ExternalVolumeRef_STATUS_PENDING, }, }, }, { name: "created volume status succeeds", tmpl: standardTmpl, - inputVolumes: []*ateapipb.ExternalVolume{ + inputVolumes: []*ateapipb.ExternalVolumeRef{ { Name: "data-vol", StorageVolumeId: "existing-vol-id", - Status: ateapipb.ExternalVolume_STATUS_CREATED, + Status: ateapipb.ExternalVolumeRef_STATUS_CREATED, }, }, wantErr: false, - wantRes: []*ateapipb.ExternalVolume{ + wantRes: []*ateapipb.ExternalVolumeRef{ { Name: "data-vol", StorageVolumeId: "existing-vol-id", - Status: ateapipb.ExternalVolume_STATUS_CREATED, + Status: ateapipb.ExternalVolumeRef_STATUS_CREATED, }, }, }, { name: "unspecified volume status returns error", tmpl: standardTmpl, - inputVolumes: []*ateapipb.ExternalVolume{ + inputVolumes: []*ateapipb.ExternalVolumeRef{ { Name: "data-vol", - Status: ateapipb.ExternalVolume_STATUS_UNSPECIFIED, + Status: ateapipb.ExternalVolumeRef_STATUS_UNSPECIFIED, }, }, wantErr: true, - wantRes: []*ateapipb.ExternalVolume{ + wantRes: []*ateapipb.ExternalVolumeRef{ { Name: "data-vol", - Status: ateapipb.ExternalVolume_STATUS_UNSPECIFIED, + Status: ateapipb.ExternalVolumeRef_STATUS_UNSPECIFIED, }, }, }, { name: "volume not found in template returns error", tmpl: &ateapipb.ActorTemplate{}, - inputVolumes: []*ateapipb.ExternalVolume{ + inputVolumes: []*ateapipb.ExternalVolumeRef{ { Name: "missing-vol", - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ExternalVolumeRef_STATUS_PENDING, }, }, wantErr: true, - wantRes: []*ateapipb.ExternalVolume{ + wantRes: []*ateapipb.ExternalVolumeRef{ { Name: "missing-vol", - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ExternalVolumeRef_STATUS_PENDING, }, }, }, { name: "storage class parameters are propagated to volume context", tmpl: standardTmpl, - inputVolumes: []*ateapipb.ExternalVolume{ + inputVolumes: []*ateapipb.ExternalVolumeRef{ { Name: "data-vol", VolumeType: "mock-standard", - Status: ateapipb.ExternalVolume_STATUS_PENDING, + Status: ateapipb.ExternalVolumeRef_STATUS_PENDING, }, }, storageClasses: map[string]*storagev1.StorageClass{ @@ -330,12 +330,12 @@ func TestCreateActorVolumes(t *testing.T) { }, }, wantErr: false, - wantRes: []*ateapipb.ExternalVolume{ + wantRes: []*ateapipb.ExternalVolumeRef{ { Name: "data-vol", StorageVolumeId: "mock-vol-substrate-actor-uid-123-data-vol", VolumeType: "mock-standard", - Status: ateapipb.ExternalVolume_STATUS_CREATED, + Status: ateapipb.ExternalVolumeRef_STATUS_CREATED, VolumeContext: map[string]string{ "type": "pd-ssd", "csi.storage.k8s.io/fstype": "ext4", @@ -395,14 +395,14 @@ func TestDeleteActorVolumes(t *testing.T) { tests := []struct { name string actorUID string - volumes []*ateapipb.ExternalVolume + volumes []*ateapipb.ExternalVolumeRef wantDeleted []string wantErr bool }{ { name: "uses storage volume ID when present", actorUID: "uid-abc", - volumes: []*ateapipb.ExternalVolume{ + volumes: []*ateapipb.ExternalVolumeRef{ {Name: "vol1", StorageVolumeId: "storage-vol-123", VolumeType: "mock"}, }, wantDeleted: []string{"storage-vol-123"}, @@ -411,8 +411,8 @@ func TestDeleteActorVolumes(t *testing.T) { { name: "falls back to actorVolumeID when storage volume ID is empty regardless of status", actorUID: "uid-abc", - volumes: []*ateapipb.ExternalVolume{ - {Name: "vol1", StorageVolumeId: "", Status: ateapipb.ExternalVolume_STATUS_CREATED, VolumeType: "mock"}, + volumes: []*ateapipb.ExternalVolumeRef{ + {Name: "vol1", StorageVolumeId: "", Status: ateapipb.ExternalVolumeRef_STATUS_CREATED, VolumeType: "mock"}, }, wantDeleted: []string{"substrate-uid-abc-vol1"}, wantErr: false, @@ -491,7 +491,7 @@ func TestDetachActorVolumes(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: "default"}, Status: &ateapipb.ActorStatus{ AssignedNode: "node-1", - ExternalVolumes: []*ateapipb.ExternalVolume{ + ExternalVolumes: []*ateapipb.ExternalVolumeRef{ {Name: "vol1", StorageVolumeId: "storage-vol-1", VolumeType: "mock"}, {Name: "vol2", StorageVolumeId: "storage-vol-2", VolumeType: "mock"}, }, @@ -522,7 +522,7 @@ func TestDetachActorVolumes(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: "default"}, Status: &ateapipb.ActorStatus{ AssignedNode: "node-1", - ExternalVolumes: []*ateapipb.ExternalVolume{ + ExternalVolumes: []*ateapipb.ExternalVolumeRef{ {Name: "mounted-vol", StorageVolumeId: "storage-vol-mounted", VolumeType: "mock"}, {Name: "unmounted-vol", StorageVolumeId: "storage-vol-unmounted", VolumeType: "mock"}, }, @@ -551,7 +551,7 @@ func TestDetachActorVolumes(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: "default"}, Status: &ateapipb.ActorStatus{ AssignedNode: "node-1", - ExternalVolumes: []*ateapipb.ExternalVolume{ + ExternalVolumes: []*ateapipb.ExternalVolumeRef{ {Name: "vol1", StorageVolumeId: "", VolumeType: "mock"}, {Name: "vol2", StorageVolumeId: "storage-vol-2", VolumeType: "mock"}, }, @@ -581,7 +581,7 @@ func TestDetachActorVolumes(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: "default"}, Status: &ateapipb.ActorStatus{ AssignedNode: "node-1", - ExternalVolumes: []*ateapipb.ExternalVolume{ + ExternalVolumes: []*ateapipb.ExternalVolumeRef{ {Name: "vol1", StorageVolumeId: "storage-vol-1", VolumeType: "mock"}, {Name: "vol2", StorageVolumeId: "storage-vol-2", VolumeType: "mock"}, }, @@ -599,7 +599,7 @@ func TestDetachActorVolumes(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: "default"}, Status: &ateapipb.ActorStatus{ AssignedNode: "node-1", - ExternalVolumes: []*ateapipb.ExternalVolume{ + ExternalVolumes: []*ateapipb.ExternalVolumeRef{ {Name: "vol1", StorageVolumeId: "storage-vol-1", VolumeType: "mock"}, }, }, @@ -620,7 +620,7 @@ func TestDetachActorVolumes(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: "default"}, Status: &ateapipb.ActorStatus{ AssignedNode: "node-1", - ExternalVolumes: []*ateapipb.ExternalVolume{ + ExternalVolumes: []*ateapipb.ExternalVolumeRef{ {Name: "vol1", StorageVolumeId: "storage-vol-1", VolumeType: "mock"}, {Name: "vol2", StorageVolumeId: "storage-vol-2", VolumeType: "mock"}, }, @@ -644,7 +644,7 @@ func TestDetachActorVolumes(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: "default"}, Status: &ateapipb.ActorStatus{ AssignedNode: "node-1", - ExternalVolumes: []*ateapipb.ExternalVolume{ + ExternalVolumes: []*ateapipb.ExternalVolumeRef{ {Name: "vol1", StorageVolumeId: "storage-vol-1", VolumeType: "unknown-plugin"}, }, }, @@ -658,7 +658,7 @@ func TestDetachActorVolumes(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Name: "actor-1", Atespace: "default"}, Status: &ateapipb.ActorStatus{ AssignedNode: "", - ExternalVolumes: []*ateapipb.ExternalVolume{ + ExternalVolumes: []*ateapipb.ExternalVolumeRef{ {Name: "vol1", StorageVolumeId: "storage-vol-1", VolumeType: "mock"}, }, }, diff --git a/cmd/ateapi/internal/controlapi/workflow_delete.go b/cmd/ateapi/internal/controlapi/workflow_delete.go index e97af85ba5..71643d1a7b 100644 --- a/cmd/ateapi/internal/controlapi/workflow_delete.go +++ b/cmd/ateapi/internal/controlapi/workflow_delete.go @@ -179,7 +179,7 @@ func (w *ActorWorkflow) ensureAteletTerminated(ctx context.Context, actorRef res if vol.GetStorageVolumeId() != "" { workloadSpec.Volumes = append(workloadSpec.Volumes, &ateletpb.Volume{ Name: vol.GetName(), - External: &ateletpb.ExternalVolumeSource{ + External: &ateletpb.ExternalVolume{ StorageVolumeId: vol.GetStorageVolumeId(), VolumeType: vol.GetVolumeType(), VolumeContext: vol.GetVolumeContext(), @@ -332,7 +332,7 @@ func (w *ActorWorkflow) ensureMarkedDeleting(ctx context.Context, actorRef resou storedActor, err := w.store.UpdateActor(ctx, actorRef, store.PreconditionFrom(actor), func(toUpdate *ateapipb.Actor) error { toUpdate.Status.State = ateapipb.ActorState_ACTOR_STATE_DELETING for _, vol := range toUpdate.GetStatus().GetExternalVolumes() { - vol.Status = ateapipb.ExternalVolume_STATUS_DELETING + vol.Status = ateapipb.ExternalVolumeRef_STATUS_DELETING } return nil }) diff --git a/cmd/ateapi/internal/controlapi/workflow_resume.go b/cmd/ateapi/internal/controlapi/workflow_resume.go index 3e472702f9..d43f8a793f 100644 --- a/cmd/ateapi/internal/controlapi/workflow_resume.go +++ b/cmd/ateapi/internal/controlapi/workflow_resume.go @@ -194,7 +194,7 @@ func (w *ActorWorkflow) ensureVolumesCreated(ctx context.Context, actorRef resou pending := false for _, vol := range actor.GetStatus().GetExternalVolumes() { - if vol.GetStatus() == ateapipb.ExternalVolume_STATUS_PENDING { + if vol.GetStatus() == ateapipb.ExternalVolumeRef_STATUS_PENDING { pending = true break } diff --git a/cmd/ateapi/internal/controlapi/workflow_resume_test.go b/cmd/ateapi/internal/controlapi/workflow_resume_test.go index 0c4f00bfdc..4a5125c569 100644 --- a/cmd/ateapi/internal/controlapi/workflow_resume_test.go +++ b/cmd/ateapi/internal/controlapi/workflow_resume_test.go @@ -1602,9 +1602,9 @@ func TestEnsureVolumesAttached_ReturnsPublishContext(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "id1"}, Status: &ateapipb.ActorStatus{ State: ateapipb.ActorState_ACTOR_STATE_RESUMING, - ExternalVolumes: []*ateapipb.ExternalVolume{ - {Name: "mounted", StorageVolumeId: "storage-mounted", VolumeType: "mock", Status: ateapipb.ExternalVolume_STATUS_CREATED}, - {Name: "unmounted", StorageVolumeId: "storage-unmounted", VolumeType: "mock", Status: ateapipb.ExternalVolume_STATUS_CREATED}, + ExternalVolumes: []*ateapipb.ExternalVolumeRef{ + {Name: "mounted", StorageVolumeId: "storage-mounted", VolumeType: "mock", Status: ateapipb.ExternalVolumeRef_STATUS_CREATED}, + {Name: "unmounted", StorageVolumeId: "storage-unmounted", VolumeType: "mock", Status: ateapipb.ExternalVolumeRef_STATUS_CREATED}, }, }, }) @@ -1622,8 +1622,8 @@ func TestEnsureVolumesAttached_ReturnsPublishContext(t *testing.T) { worker := &ateapipb.Worker{NodeName: "node-1"} tmpl := &ateapipb.ActorTemplate{ Volumes: []*ateapipb.Volume{ - {Name: "mounted", ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{StorageClassName: "sc"}}, - {Name: "unmounted", ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{StorageClassName: "sc"}}, + {Name: "mounted", External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{StorageClassName: "sc"}}}, + {Name: "unmounted", External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{StorageClassName: "sc"}}}, }, Containers: []*ateapipb.Container{ {Name: "main", Image: "img", VolumeMounts: []*ateapipb.VolumeMount{{Name: "mounted", MountPath: "/data"}}}, diff --git a/cmd/ateapi/internal/controlapi/workload_spec.go b/cmd/ateapi/internal/controlapi/workload_spec.go index bd1df172ce..399816b818 100644 --- a/cmd/ateapi/internal/controlapi/workload_spec.go +++ b/cmd/ateapi/internal/controlapi/workload_spec.go @@ -154,12 +154,12 @@ func appendExternalVolumes(workloadSpec *ateletpb.WorkloadSpec, template *ateapi return nil } for _, vol := range template.GetVolumes() { - if vol.GetExternalVolumeTemplate() != nil { + if vol.GetExternal().GetTemplate() != nil { if !isVolumeMounted(vol.GetName(), template) { continue } if actor == nil { - return fmt.Errorf("actor is required when externalVolumeTemplate is present") + return fmt.Errorf("actor is required when an external volume is present") } var storageVolID string @@ -178,7 +178,7 @@ func appendExternalVolumes(workloadSpec *ateletpb.WorkloadSpec, template *ateapi } workloadSpec.Volumes = append(workloadSpec.Volumes, &ateletpb.Volume{ Name: vol.GetName(), - External: &ateletpb.ExternalVolumeSource{ + External: &ateletpb.ExternalVolume{ StorageVolumeId: storageVolID, VolumeType: volType, VolumeContext: volCtx, diff --git a/cmd/ateapi/internal/controlapi/workload_spec_test.go b/cmd/ateapi/internal/controlapi/workload_spec_test.go index 68d569b5b6..b6382e559f 100644 --- a/cmd/ateapi/internal/controlapi/workload_spec_test.go +++ b/cmd/ateapi/internal/controlapi/workload_spec_test.go @@ -390,9 +390,9 @@ func TestAppendExternalVolumes(t *testing.T) { Volumes: []*ateapipb.Volume{ { Name: "vol-1", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "pd-standard", - }, + }}, }, { Name: "vol-2", @@ -400,9 +400,9 @@ func TestAppendExternalVolumes(t *testing.T) { }, { Name: "unmounted-vol", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ StorageClassName: "pd-standard", - }, + }}, }, }, } @@ -413,7 +413,7 @@ func TestAppendExternalVolumes(t *testing.T) { Name: "actor-123", }, Status: &ateapipb.ActorStatus{ - ExternalVolumes: []*ateapipb.ExternalVolume{ + ExternalVolumes: []*ateapipb.ExternalVolumeRef{ { Name: "vol-1", StorageVolumeId: "vol-gce-pd-123", @@ -448,7 +448,7 @@ func TestAppendExternalVolumes(t *testing.T) { Volumes: []*ateletpb.Volume{ { Name: "vol-1", - External: &ateletpb.ExternalVolumeSource{ + External: &ateletpb.ExternalVolume{ StorageVolumeId: "vol-gce-pd-123", VolumeType: "pd-standard", VolumeContext: map[string]string{"foo": "bar"}, @@ -470,7 +470,7 @@ func TestAppendExternalVolumes(t *testing.T) { Atespace: "space-abc", Name: "actor-123", }, - Status: &ateapipb.ActorStatus{ExternalVolumes: []*ateapipb.ExternalVolume{}}, + Status: &ateapipb.ActorStatus{ExternalVolumes: []*ateapipb.ExternalVolumeRef{}}, } if err := appendExternalVolumes(&ateletpb.WorkloadSpec{}, template, missingActor, nil); err == nil { t.Errorf("appendExternalVolumes expected error for missing volume, got nil") diff --git a/cmd/atelet/internal/apivalidation/validation_test.go b/cmd/atelet/internal/apivalidation/validation_test.go index 50f50d3c84..db78d64f17 100644 --- a/cmd/atelet/internal/apivalidation/validation_test.go +++ b/cmd/atelet/internal/apivalidation/validation_test.go @@ -1387,8 +1387,8 @@ func TestValidateVolume(t *testing.T) { } return v } - external := func(mutate ...func(*ateletpb.ExternalVolumeSource)) *ateletpb.Volume { - e := &ateletpb.ExternalVolumeSource{ + external := func(mutate ...func(*ateletpb.ExternalVolume)) *ateletpb.Volume { + e := &ateletpb.ExternalVolume{ StorageVolumeId: "projects/p/zones/z/disks/vol-1", VolumeType: "substrate.io/mock", VolumeContext: map[string]string{"fsType": "ext4"}, @@ -1444,48 +1444,48 @@ func TestValidateVolume(t *testing.T) { }, { name: "two sources set", obj: durable(func(v *ateletpb.Volume) { - v.External = &ateletpb.ExternalVolumeSource{StorageVolumeId: "vol-1"} + v.External = &ateletpb.ExternalVolume{StorageVolumeId: "vol-1"} }), want: field.ErrorList{field.Invalid(nil, nil, "").WithOrigin("union")}, }, - // ExternalVolumeSource. + // ExternalVolume. { name: "valid external", obj: external(), }, { name: "external: missing storage_volume_id", - obj: external(func(e *ateletpb.ExternalVolumeSource) { e.StorageVolumeId = "" }), + obj: external(func(e *ateletpb.ExternalVolume) { e.StorageVolumeId = "" }), want: field.ErrorList{field.Required(extPath.Child("storage_volume_id"), "")}, }, { name: "external: storage_volume_id with a control character", - obj: external(func(e *ateletpb.ExternalVolumeSource) { e.StorageVolumeId = "vol\x01" }), + obj: external(func(e *ateletpb.ExternalVolume) { e.StorageVolumeId = "vol\x01" }), want: field.ErrorList{field.Invalid(extPath.Child("storage_volume_id"), nil, "")}, }, { name: "external: storage_volume_id too long", - obj: external(func(e *ateletpb.ExternalVolumeSource) { e.StorageVolumeId = strings.Repeat("x", 257) }), + obj: external(func(e *ateletpb.ExternalVolume) { e.StorageVolumeId = strings.Repeat("x", 257) }), want: field.ErrorList{field.TooLong(extPath.Child("storage_volume_id"), nil, 256).WithOrigin("maxLength")}, }, { name: "external: unset volume_type is allowed", - obj: external(func(e *ateletpb.ExternalVolumeSource) { e.VolumeType = "" }), + obj: external(func(e *ateletpb.ExternalVolume) { e.VolumeType = "" }), }, { name: "external: invalid volume_type: uppercase", - obj: external(func(e *ateletpb.ExternalVolumeSource) { e.VolumeType = "substrate.io/Mock" }), + obj: external(func(e *ateletpb.ExternalVolume) { e.VolumeType = "substrate.io/Mock" }), want: field.ErrorList{field.Invalid(extPath.Child("volume_type"), nil, "")}, }, { name: "external: volume_context with one long value, as a CSI driver may return", - obj: external(func(e *ateletpb.ExternalVolumeSource) { + obj: external(func(e *ateletpb.ExternalVolume) { e.VolumeContext = map[string]string{"k": strings.Repeat("v", 4000)} }), }, { name: "external: volume_context over the size bound", - obj: external(func(e *ateletpb.ExternalVolumeSource) { + obj: external(func(e *ateletpb.ExternalVolume) { e.VolumeContext = map[string]string{"k": strings.Repeat("v", 40*1024)} }), want: field.ErrorList{field.TooLong(extPath.Child("volume_context"), nil, 40*1024)}, }, { name: "external: publish_context with many entries, as a CSI driver may return", - obj: external(func(e *ateletpb.ExternalVolumeSource) { + obj: external(func(e *ateletpb.ExternalVolume) { e.PublishContext = make(map[string]string) for i := range 100 { e.PublishContext[fmt.Sprintf("key-%03d", i)] = "v" @@ -1493,7 +1493,7 @@ func TestValidateVolume(t *testing.T) { }), }, { name: "external: publish_context over the size bound", - obj: external(func(e *ateletpb.ExternalVolumeSource) { + obj: external(func(e *ateletpb.ExternalVolume) { e.PublishContext = map[string]string{"a": strings.Repeat("v", 20*1024), "b": strings.Repeat("v", 20*1024)} }), want: field.ErrorList{field.TooLong(extPath.Child("publish_context"), nil, 40*1024)}, diff --git a/cmd/atelet/internal/apivalidation/workloadspec.go b/cmd/atelet/internal/apivalidation/workloadspec.go index c0e3f94693..8e8a4b0561 100644 --- a/cmd/atelet/internal/apivalidation/workloadspec.go +++ b/cmd/atelet/internal/apivalidation/workloadspec.go @@ -89,19 +89,19 @@ func ValidateCustom_HttpGetAction_Path(_ context.Context, _ operation.Operation, return resources.ValidateHTTPGetPath(fldPath, *value) } -func ValidateCustom_ExternalVolumeSource_StorageVolumeId(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ *string) field.ErrorList { +func ValidateCustom_ExternalVolume_StorageVolumeId(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ *string) field.ErrorList { return resources.ValidateStorageVolumeID(fldPath, *value) } -func ValidateCustom_ExternalVolumeSource_VolumeType(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ *string) field.ErrorList { +func ValidateCustom_ExternalVolume_VolumeType(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ *string) field.ErrorList { return resources.ValidateVolumeType(fldPath, *value) } -func ValidateCustom_ExternalVolumeSource_VolumeContext(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ map[string]string) field.ErrorList { +func ValidateCustom_ExternalVolume_VolumeContext(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ map[string]string) field.ErrorList { return resources.ValidateCSIMap(fldPath, value) } -func ValidateCustom_ExternalVolumeSource_PublishContext(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ map[string]string) field.ErrorList { +func ValidateCustom_ExternalVolume_PublishContext(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ map[string]string) field.ErrorList { return resources.ValidateCSIMap(fldPath, value) } diff --git a/cmd/atelet/internal/apivalidation/zz_generated.validation.go b/cmd/atelet/internal/apivalidation/zz_generated.validation.go index 5974aab64d..5b43f0b1f3 100644 --- a/cmd/atelet/internal/apivalidation/zz_generated.validation.go +++ b/cmd/atelet/internal/apivalidation/zz_generated.validation.go @@ -1398,13 +1398,13 @@ func Validate_ExternalRestoreConfiguration( return errs } -// Validate_ExternalVolumeSource validates an instance of ExternalVolumeSource according +// Validate_ExternalVolume validates an instance of ExternalVolume according // to declarative validation rules in the API schema. -func Validate_ExternalVolumeSource( +func Validate_ExternalVolume( ctx context.Context, op operation.Operation, fldPath *field.Path, - obj, oldObj *ateletpb.ExternalVolumeSource) (errs field.ErrorList) { + obj, oldObj *ateletpb.ExternalVolume) (errs field.ErrorList) { - { // field ateletpb.ExternalVolumeSource.StorageVolumeId + { // field ateletpb.ExternalVolume.StorageVolumeId fn := func( fldPath *field.Path, obj, oldObj *string, @@ -1425,7 +1425,7 @@ func Validate_ExternalVolumeSource( return // do not proceed } // custom validation - if e := ValidateCustom_ExternalVolumeSource_StorageVolumeId(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + if e := ValidateCustom_ExternalVolume_StorageVolumeId(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 { @@ -1434,13 +1434,13 @@ func Validate_ExternalVolumeSource( return } oldVal := safe.Field(oldObj, - func(oldObj *ateletpb.ExternalVolumeSource) *string { + func(oldObj *ateletpb.ExternalVolume) *string { return &oldObj.StorageVolumeId }) errs = append(errs, fn(fldPath.Child("storage_volume_id"), &obj.StorageVolumeId, oldVal, oldObj != nil)...) } - { // field ateletpb.ExternalVolumeSource.VolumeType + { // field ateletpb.ExternalVolume.VolumeType fn := func( fldPath *field.Path, obj, oldObj *string, @@ -1460,7 +1460,7 @@ func Validate_ExternalVolumeSource( return // do not proceed } // custom validation - if e := ValidateCustom_ExternalVolumeSource_VolumeType(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + if e := ValidateCustom_ExternalVolume_VolumeType(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 { @@ -1469,13 +1469,13 @@ func Validate_ExternalVolumeSource( return } oldVal := safe.Field(oldObj, - func(oldObj *ateletpb.ExternalVolumeSource) *string { + func(oldObj *ateletpb.ExternalVolume) *string { return &oldObj.VolumeType }) errs = append(errs, fn(fldPath.Child("volume_type"), &obj.VolumeType, oldVal, oldObj != nil)...) } - { // field ateletpb.ExternalVolumeSource.VolumeContext + { // field ateletpb.ExternalVolume.VolumeContext fn := func( fldPath *field.Path, obj, oldObj map[string]string, @@ -1495,19 +1495,19 @@ func Validate_ExternalVolumeSource( return // do not proceed } // custom validation - if e := ValidateCustom_ExternalVolumeSource_VolumeContext(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + if e := ValidateCustom_ExternalVolume_VolumeContext(ctx, op, fldPath, obj, oldObj); len(e) != 0 { errs = append(errs, e...) } return } oldVal := safe.Field(oldObj, - func(oldObj *ateletpb.ExternalVolumeSource) map[string]string { + func(oldObj *ateletpb.ExternalVolume) map[string]string { return oldObj.VolumeContext }) errs = append(errs, fn(fldPath.Child("volume_context"), obj.VolumeContext, oldVal, oldObj != nil)...) } - { // field ateletpb.ExternalVolumeSource.PublishContext + { // field ateletpb.ExternalVolume.PublishContext fn := func( fldPath *field.Path, obj, oldObj map[string]string, @@ -1527,13 +1527,13 @@ func Validate_ExternalVolumeSource( return // do not proceed } // custom validation - if e := ValidateCustom_ExternalVolumeSource_PublishContext(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + if e := ValidateCustom_ExternalVolume_PublishContext(ctx, op, fldPath, obj, oldObj); len(e) != 0 { errs = append(errs, e...) } return } oldVal := safe.Field(oldObj, - func(oldObj *ateletpb.ExternalVolumeSource) map[string]string { + func(oldObj *ateletpb.ExternalVolume) map[string]string { return oldObj.PublishContext }) errs = append(errs, fn(fldPath.Child("publish_context"), obj.PublishContext, oldVal, oldObj != nil)...) @@ -4299,7 +4299,7 @@ func Validate_Volume( { // field ateletpb.Volume.External fn := func( fldPath *field.Path, - obj, oldObj *ateletpb.ExternalVolumeSource, + obj, oldObj *ateletpb.ExternalVolume, oldValueCorrelated bool) (errs field.ErrorList) { // don't revalidate unchanged data if oldValueCorrelated && op.Type == operation.Update { @@ -4316,11 +4316,11 @@ func Validate_Volume( return // do not proceed } // call the type's validation function - errs = append(errs, Validate_ExternalVolumeSource(ctx, op, fldPath, obj, oldObj)...) + errs = append(errs, Validate_ExternalVolume(ctx, op, fldPath, obj, oldObj)...) return } oldVal := safe.Field(oldObj, - func(oldObj *ateletpb.Volume) *ateletpb.ExternalVolumeSource { + func(oldObj *ateletpb.Volume) *ateletpb.ExternalVolume { return oldObj.External }) errs = append(errs, fn(fldPath.Child("external"), obj.External, oldVal, oldObj != nil)...) diff --git a/cmd/atelet/main_test.go b/cmd/atelet/main_test.go index f17d6d08ea..1dd1a5fa4e 100644 --- a/cmd/atelet/main_test.go +++ b/cmd/atelet/main_test.go @@ -815,7 +815,7 @@ func TestBuildAteomWorkloadSpecForwardsDurableDirMounts(t *testing.T) { Volumes: []*ateletpb.Volume{ {Name: "data", DurableDir: &ateletpb.DurableDirVolume{}}, {Name: "cache", DurableDir: &ateletpb.DurableDirVolume{}}, - {Name: "scratch", External: &ateletpb.ExternalVolumeSource{}}, + {Name: "scratch", External: &ateletpb.ExternalVolume{}}, {Name: "system-info", SystemInfo: &ateletpb.SystemInfoVolume{}}, }, Containers: []*ateletpb.Container{ @@ -917,7 +917,7 @@ func TestBuildAteomWorkloadSpecValidation(t *testing.T) { in: &ateletpb.WorkloadSpec{ Volumes: []*ateletpb.Volume{ {Name: "data", DurableDir: &ateletpb.DurableDirVolume{}}, - {Name: "data", External: &ateletpb.ExternalVolumeSource{}}, + {Name: "data", External: &ateletpb.ExternalVolume{}}, }, Containers: []*ateletpb.Container{ { @@ -1202,7 +1202,7 @@ func TestBuildAteomWorkloadSpec_ImageVolumeMounts(t *testing.T) { Volumes: []*ateletpb.Volume{ {Name: "agent", Image: &ateletpb.ImageVolumeSource{}}, {Name: "data", DurableDir: &ateletpb.DurableDirVolume{}}, - {Name: "ext", External: &ateletpb.ExternalVolumeSource{}}, + {Name: "ext", External: &ateletpb.ExternalVolume{}}, }, Containers: []*ateletpb.Container{{ Name: "app", @@ -1543,7 +1543,7 @@ func TestShouldHaveSnapshots(t *testing.T) { Fidelity: ateletpb.SnapshotFidelity_SNAPSHOT_FIDELITY_VOLUMES, Spec: &ateletpb.WorkloadSpec{ Volumes: []*ateletpb.Volume{ - {Name: "csi", External: &ateletpb.ExternalVolumeSource{}}, + {Name: "csi", External: &ateletpb.ExternalVolume{}}, }, }, }, @@ -1556,7 +1556,7 @@ func TestShouldHaveSnapshots(t *testing.T) { Spec: &ateletpb.WorkloadSpec{ Volumes: []*ateletpb.Volume{ {Name: "durable", DurableDir: &ateletpb.DurableDirVolume{}}, - {Name: "csi", External: &ateletpb.ExternalVolumeSource{}}, + {Name: "csi", External: &ateletpb.ExternalVolume{}}, }, }, }, diff --git a/cmd/atelet/volumes_test.go b/cmd/atelet/volumes_test.go index cab35adcb2..94bb72f6cf 100644 --- a/cmd/atelet/volumes_test.go +++ b/cmd/atelet/volumes_test.go @@ -91,14 +91,14 @@ func TestUnmountExternalVolumes(t *testing.T) { extVol1 := &ateletpb.Volume{ Name: "vol-1", - External: &ateletpb.ExternalVolumeSource{ + External: &ateletpb.ExternalVolume{ StorageVolumeId: "mock-vol-1", VolumeType: "mock-driver", }, } extVol2 := &ateletpb.Volume{ Name: "vol-2", - External: &ateletpb.ExternalVolumeSource{ + External: &ateletpb.ExternalVolume{ StorageVolumeId: "mock-vol-2", VolumeType: "mock-driver", }, @@ -171,7 +171,7 @@ func TestMountExternalVolumes(t *testing.T) { extVol1 := &ateletpb.Volume{ Name: "vol-1", - External: &ateletpb.ExternalVolumeSource{ + External: &ateletpb.ExternalVolume{ StorageVolumeId: "mock-vol-1", VolumeType: "mock-driver", VolumeContext: map[string]string{"key": "val1"}, @@ -179,7 +179,7 @@ func TestMountExternalVolumes(t *testing.T) { } extVol2 := &ateletpb.Volume{ Name: "vol-2", - External: &ateletpb.ExternalVolumeSource{ + External: &ateletpb.ExternalVolume{ StorageVolumeId: "mock-vol-2", VolumeType: "mock-driver", VolumeContext: map[string]string{"key": "val2"}, @@ -263,7 +263,7 @@ func TestMountExternalVolumes(t *testing.T) { unknownVol := &ateletpb.Volume{ Name: "vol-unknown", - External: &ateletpb.ExternalVolumeSource{ + External: &ateletpb.ExternalVolume{ StorageVolumeId: "mock-vol-unknown", VolumeType: "unknown-driver", }, @@ -380,14 +380,14 @@ func TestVolumeHostDirectoryCleanup(t *testing.T) { extVol1 := &ateletpb.Volume{ Name: "vol-1", - External: &ateletpb.ExternalVolumeSource{ + External: &ateletpb.ExternalVolume{ StorageVolumeId: "mock-vol-1", VolumeType: "mock-driver", }, } extVol2 := &ateletpb.Volume{ Name: "vol-2", - External: &ateletpb.ExternalVolumeSource{ + External: &ateletpb.ExternalVolume{ StorageVolumeId: "mock-vol-2", VolumeType: "mock-driver", }, diff --git a/demos/counter/counter-microvm-csi-test-template.yaml b/demos/counter/counter-microvm-csi-test-template.yaml index 29d65c3d14..96cc8ce9f8 100644 --- a/demos/counter/counter-microvm-csi-test-template.yaml +++ b/demos/counter/counter-microvm-csi-test-template.yaml @@ -40,6 +40,7 @@ sandboxConfig: configName: microvm volumes: - name: data - externalVolumeTemplate: - capacity: 1Gi - storageClassName: csi-hostpath-sc + external: + template: + capacity: 1Gi + storageClassName: csi-hostpath-sc diff --git a/demos/sandbox/manual-test-multi-template.yaml b/demos/sandbox/manual-test-multi-template.yaml index 6476c31be0..5d80f603a0 100644 --- a/demos/sandbox/manual-test-multi-template.yaml +++ b/demos/sandbox/manual-test-multi-template.yaml @@ -42,10 +42,12 @@ sandboxConfig: configName: gvisor-default volumes: - name: vol-hostpath - externalVolumeTemplate: - capacity: 1Gi - storageClassName: csi-hostpath-sc + external: + template: + capacity: 1Gi + storageClassName: csi-hostpath-sc - name: vol-nfs - externalVolumeTemplate: - capacity: 1Gi - storageClassName: csi-nfs-sc + external: + template: + capacity: 1Gi + storageClassName: csi-nfs-sc diff --git a/docs/api-guide.md b/docs/api-guide.md index d87e300aa6..c3ae5be63c 100644 --- a/docs/api-guide.md +++ b/docs/api-guide.md @@ -125,7 +125,7 @@ The `ActorTemplate` defines the code, environment, and state-management policies | `sandboxConfig` | `SandboxConfig` | **Required.** The sandbox runtime selection: `sandboxClass` (**required**, `SANDBOX_CLASS_GVISOR` or `SANDBOX_CLASS_MICROVM`) picks the runtime family this template's actors require — only `WorkerPool`s whose `sandboxClasses` entry matches are eligible — and `configName` (**required**) names the cluster-scoped [`SandboxConfig`](#3-sandboxconfig-the-sandbox-itself) object supplying the sandbox binaries. It must reference an existing config of the matching class; `CreateActorTemplate` rejects the template otherwise. | | `workerSelector` | `*Selector` | Optional. Gates which `WorkerPool`s actors from this template may use, by matching against each pool's labels (`matchLabels`). If unset, all pools are eligible (subject to the actor's own `worker_selector`). | | `snapshotConfig` | `SnapshotConfig` | **Required.** The base object-storage location snapshots are written under, the snapshot fidelity (`preferredFidelity`) every Pause and Suspend captures (`SNAPSHOT_FIDELITY_ROOTFS` requires `sandboxClass: SANDBOX_CLASS_MICROVM`), and automated golden snapshot creation (`goldenSnapshotConfig.mode`). See [Snapshot Storage Layout](#snapshot-storage-layout). | -| `volumes` | `[]Volume` | Optional. Volumes the containers may mount, each a `durableDir`, an `externalVolumeTemplate` (see [CSI Volumes Guide](csi-volumes.md)), or a `systemInfo` volume (see [SystemInfo Volumes](#systeminfo-volumes)). Every declared volume must be mounted by at least one container. A `microvm` template may declare several `durableDir` volumes; a `gvisor` template is limited to one. | +| `volumes` | `[]Volume` | Optional. Volumes the containers may mount, each a `durableDir`, an `external` CSI volume source (see [CSI Volumes Guide](csi-volumes.md)), or a `systemInfo` volume (see [SystemInfo Volumes](#systeminfo-volumes)). Every declared volume must be mounted by at least one container. A `microvm` template may declare several `durableDir` volumes; a `gvisor` template is limited to one. | | `resources` | `*ResourceRequirements` | Optional. Declares each actor's compute size via `limits` — see [Sandbox Right-Sizing](#sandbox-right-sizing-resources). Immutable, like the rest of the template. | The sandbox itself — the binaries (e.g. the gVisor `runsc` binary) and the `pauseImage` holding the sandbox's namespaces — comes from the cluster-scoped [`SandboxConfig`](#3-sandboxconfig-the-sandbox-itself) object the template names via `sandboxConfig.configName`. An actor always resolves the config from its current template — repointing the actor at another template requires the same config. diff --git a/docs/api-style-guide.md b/docs/api-style-guide.md index 6809490e11..95bdf94da9 100644 --- a/docs/api-style-guide.md +++ b/docs/api-style-guide.md @@ -610,7 +610,7 @@ message Volume { // +k8s:format=k8s-short-name string name = 1; - // Exactly one of durable_dir / external_volume_template / image must be set. + // Exactly one of durable_dir / external / image must be set. // // +k8s:optional // +k8s:unionMember @@ -618,7 +618,7 @@ message Volume { // +k8s:optional // +k8s:unionMember - ExternalVolumeTemplate external_volume_template = 3; + ExternalVolumeSource external = 7; // +k8s:optional // +k8s:unionMember diff --git a/docs/csi-volumes.md b/docs/csi-volumes.md index ae170b3f25..347a98c87d 100644 --- a/docs/csi-volumes.md +++ b/docs/csi-volumes.md @@ -8,7 +8,7 @@ Substrate integrates with the **Container Storage Interface (CSI)** to provide d In Kubernetes, volumes are reconciled asynchronously via standard Kubernetes objects (e.g. `PersistentVolumeClaim`, `PersistentVolume`). Agent Substrate takes a different approach tailored for actor lifecycle operations: -* **No PV or PVC Objects:** External volumes are declaratively defined in the [`ActorTemplate`](api-guide.md#2-actortemplate-the-workload-blueprint) via `externalVolumeTemplate` and provisioned dynamically for each actor instance. Volume operations are coupled directly with the actor lifecycle. +* **No PV or PVC Objects:** External volumes are declaratively defined in the [`ActorTemplate`](api-guide.md#2-actortemplate-the-workload-blueprint) via `external.template` and provisioned dynamically for each actor instance. Volume operations are coupled directly with the actor lifecycle. * **Direct Network-Based CSI Controller:** The Substrate control plane (`ateapi`) communicates directly with the CSI Controller gRPC service over the network (via TCP or DNS endpoints, optionally secured with TLS/mTLS). --- @@ -66,7 +66,7 @@ External volumes are declared on the `ActorTemplate` resource. For complete deta To attach a CSI volume to an actor: -1. Define the volume under `volumes` with an `externalVolumeTemplate`. +1. Define the volume under `volumes` with an `external.template`. 2. Mount the volume inside one or more containers under `containers[].volumeMounts`. #### `volumes[]` @@ -74,14 +74,15 @@ To attach a CSI volume to an actor: ```yaml volumes: - name: my-data-volume - externalVolumeTemplate: - capacity: 10Gi - storageClassName: standard-rwx + external: + template: + capacity: 10Gi + storageClassName: standard-rwx ``` * `name`: Unique DNS-label-compliant volume name. -* `externalVolumeTemplate.capacity`: Quantity string representing the requested volume size (e.g. `1Gi`, `50Gi`). -* `externalVolumeTemplate.storageClassName`: Name of a Kubernetes `StorageClass` present in the cluster whose `provisioner` matches a registered `CSIDriverConfig`. +* `external.template.capacity`: Quantity string representing the requested volume size (e.g. `1Gi`, `50Gi`). +* `external.template.storageClassName`: Name of a Kubernetes `StorageClass` present in the cluster whose `provisioner` matches a registered `CSIDriverConfig`. #### `containers[].volumeMounts[]` @@ -186,7 +187,8 @@ snapshotConfig: storageLocation: gs://my-snapshots-bucket/stateful-agent volumes: - name: shared-storage - externalVolumeTemplate: - capacity: 5Gi - storageClassName: csi-nfs-sc + external: + template: + capacity: 5Gi + storageClassName: csi-nfs-sc ``` diff --git a/internal/e2e/suites/combinedvolumes/combinedvolumes_test.go b/internal/e2e/suites/combinedvolumes/combinedvolumes_test.go index 70e6b5b823..7fed2c5938 100644 --- a/internal/e2e/suites/combinedvolumes/combinedvolumes_test.go +++ b/internal/e2e/suites/combinedvolumes/combinedvolumes_test.go @@ -228,10 +228,10 @@ func createTemplate(ctx context.Context, t *testing.T, clients *e2e.Clients, ns &ateapipb.VolumeMount{Name: extVolume, MountPath: extPathB}) tmpl.Volumes = append(tmpl.Volumes, &ateapipb.Volume{ Name: extVolume, - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ Capacity: extCapacity, StorageClassName: storageClass, - }, + }}, }) }, }) diff --git a/internal/e2e/suites/demo/demo_test.go b/internal/e2e/suites/demo/demo_test.go index 661615b57a..48841beb69 100644 --- a/internal/e2e/suites/demo/demo_test.go +++ b/internal/e2e/suites/demo/demo_test.go @@ -441,7 +441,7 @@ func TestDeleteActorAnyStateWithExternalVolume(t *testing.T) { t.Fatalf("expected actor to have volumes, got 0") } for _, vol := range actor.GetStatus().GetExternalVolumes() { - if vol.Status != ateapipb.ExternalVolume_STATUS_CREATED { + if vol.Status != ateapipb.ExternalVolumeRef_STATUS_CREATED { t.Fatalf("expected volume %q to be CREATED, got %s", vol.Name, vol.Status) } } @@ -1364,10 +1364,10 @@ func createActorTemplateWithExternalVolume(ctx context.Context, t *testing.T, cl if !hasExtVol { at.Volumes = append(at.Volumes, &ateapipb.Volume{ Name: "external-data", - ExternalVolumeTemplate: &ateapipb.ExternalVolumeTemplate{ + External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{ Capacity: "1Gi", StorageClassName: scName, - }, + }}, }) } } diff --git a/internal/proto/ateletpb/atelet.pb.go b/internal/proto/ateletpb/atelet.pb.go index 2181e83c54..b0808aa3b7 100644 --- a/internal/proto/ateletpb/atelet.pb.go +++ b/internal/proto/ateletpb/atelet.pb.go @@ -1581,17 +1581,17 @@ func (*DurableDirVolume) Descriptor() ([]byte, []int) { return file_atelet_proto_rawDescGZIP(), []int{20} } -type ExternalVolumeSource struct { +type ExternalVolume struct { state protoimpl.MessageState `protogen:"open.v1"` // Required, unlike the actor status counterpart: the control plane only // sends volumes that finished provisioning. // // +k8s:required - // +k8s:maxLength=256 # matches ExternalVolume.storage_volume_id's bound + // +k8s:maxLength=256 # matches ExternalVolumeRef.storage_volume_id's bound // +k8s:customValidation # no control characters StorageVolumeId string `protobuf:"bytes,1,opt,name=storage_volume_id,json=storageVolumeId,proto3" json:"storage_volume_id,omitempty"` // +k8s:optional - // +k8s:maxLength=253 # matches ExternalVolume.volume_type's bound + // +k8s:maxLength=253 # matches ExternalVolumeRef.volume_type's bound // +k8s:customValidation # optional "substrate.io/" prefix + DNS subdomain VolumeType string `protobuf:"bytes,2,opt,name=volume_type,json=volumeType,proto3" json:"volume_type,omitempty"` // volume_context is the driver's provisioning metadata. Its entries are the @@ -1610,20 +1610,20 @@ type ExternalVolumeSource struct { sizeCache protoimpl.SizeCache } -func (x *ExternalVolumeSource) Reset() { - *x = ExternalVolumeSource{} +func (x *ExternalVolume) Reset() { + *x = ExternalVolume{} mi := &file_atelet_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *ExternalVolumeSource) String() string { +func (x *ExternalVolume) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ExternalVolumeSource) ProtoMessage() {} +func (*ExternalVolume) ProtoMessage() {} -func (x *ExternalVolumeSource) ProtoReflect() protoreflect.Message { +func (x *ExternalVolume) ProtoReflect() protoreflect.Message { mi := &file_atelet_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1635,33 +1635,33 @@ func (x *ExternalVolumeSource) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ExternalVolumeSource.ProtoReflect.Descriptor instead. -func (*ExternalVolumeSource) Descriptor() ([]byte, []int) { +// Deprecated: Use ExternalVolume.ProtoReflect.Descriptor instead. +func (*ExternalVolume) Descriptor() ([]byte, []int) { return file_atelet_proto_rawDescGZIP(), []int{21} } -func (x *ExternalVolumeSource) GetStorageVolumeId() string { +func (x *ExternalVolume) GetStorageVolumeId() string { if x != nil { return x.StorageVolumeId } return "" } -func (x *ExternalVolumeSource) GetVolumeType() string { +func (x *ExternalVolume) GetVolumeType() string { if x != nil { return x.VolumeType } return "" } -func (x *ExternalVolumeSource) GetVolumeContext() map[string]string { +func (x *ExternalVolume) GetVolumeContext() map[string]string { if x != nil { return x.VolumeContext } return nil } -func (x *ExternalVolumeSource) GetPublishContext() map[string]string { +func (x *ExternalVolume) GetPublishContext() map[string]string { if x != nil { return x.PublishContext } @@ -2025,7 +2025,7 @@ type Volume struct { DurableDir *DurableDirVolume `protobuf:"bytes,2,opt,name=durable_dir,json=durableDir,proto3" json:"durable_dir,omitempty"` // +k8s:optional // +k8s:unionMember - External *ExternalVolumeSource `protobuf:"bytes,3,opt,name=external,proto3" json:"external,omitempty"` + External *ExternalVolume `protobuf:"bytes,3,opt,name=external,proto3" json:"external,omitempty"` // +k8s:optional // +k8s:unionMember SystemInfo *SystemInfoVolume `protobuf:"bytes,4,opt,name=system_info,json=systemInfo,proto3" json:"system_info,omitempty"` @@ -2080,7 +2080,7 @@ func (x *Volume) GetDurableDir() *DurableDirVolume { return nil } -func (x *Volume) GetExternal() *ExternalVolumeSource { +func (x *Volume) GetExternal() *ExternalVolume { if x != nil { return x.External } @@ -3548,13 +3548,13 @@ 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\"\x9b\x03\n" + - "\x14ExternalVolumeSource\x12*\n" + + "\x10DurableDirVolume\"\x89\x03\n" + + "\x0eExternalVolume\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\x12Y\n" + - "\x0fpublish_context\x18\x04 \x03(\v20.atelet.ExternalVolumeSource.PublishContextEntryR\x0epublishContext\x1a@\n" + + "volumeType\x12P\n" + + "\x0evolume_context\x18\x03 \x03(\v2).atelet.ExternalVolume.VolumeContextEntryR\rvolumeContext\x12S\n" + + "\x0fpublish_context\x18\x04 \x03(\v2*.atelet.ExternalVolume.PublishContextEntryR\x0epublishContext\x1a@\n" + "\x12VolumeContextEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\x1aA\n" + @@ -3575,12 +3575,12 @@ const file_atelet_proto_rawDesc = "" + "\x0eactor_metadata\x18\x01 \x01(\v2\x1f.atelet.ActorMetadataDataSourceR\ractorMetadata\x12@\n" + "\ftrust_bundle\x18\x02 \x01(\v2\x1d.atelet.TrustBundleDataSourceR\vtrustBundle\"S\n" + "\x10SystemInfoVolume\x12?\n" + - "\fdata_sources\x18\x01 \x03(\v2\x1c.atelet.SystemInfoDataSourceR\vdataSources\"\xfd\x01\n" + + "\fdata_sources\x18\x01 \x03(\v2\x1c.atelet.SystemInfoDataSourceR\vdataSources\"\xf7\x01\n" + "\x06Volume\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x129\n" + "\vdurable_dir\x18\x02 \x01(\v2\x18.atelet.DurableDirVolumeR\n" + - "durableDir\x128\n" + - "\bexternal\x18\x03 \x01(\v2\x1c.atelet.ExternalVolumeSourceR\bexternal\x129\n" + + "durableDir\x122\n" + + "\bexternal\x18\x03 \x01(\v2\x16.atelet.ExternalVolumeR\bexternal\x129\n" + "\vsystem_info\x18\x04 \x01(\v2\x18.atelet.SystemInfoVolumeR\n" + "systemInfo\x12/\n" + "\x05image\x18\x05 \x01(\v2\x19.atelet.ImageVolumeSourceR\x05image\"@\n" + @@ -3734,7 +3734,7 @@ var file_atelet_proto_goTypes = []any{ (*SandboxAssets)(nil), // 21: atelet.SandboxAssets (*WorkloadSpec)(nil), // 22: atelet.WorkloadSpec (*DurableDirVolume)(nil), // 23: atelet.DurableDirVolume - (*ExternalVolumeSource)(nil), // 24: atelet.ExternalVolumeSource + (*ExternalVolume)(nil), // 24: atelet.ExternalVolume (*ImageVolumeSource)(nil), // 25: atelet.ImageVolumeSource (*ActorMetadataItem)(nil), // 26: atelet.ActorMetadataItem (*ActorMetadataDataSource)(nil), // 27: atelet.ActorMetadataDataSource @@ -3762,8 +3762,8 @@ var file_atelet_proto_goTypes = []any{ (*RestoreResponse)(nil), // 49: atelet.RestoreResponse nil, // 50: atelet.ArchAssets.FilesEntry nil, // 51: atelet.SandboxAssets.AssetsEntry - nil, // 52: atelet.ExternalVolumeSource.VolumeContextEntry - nil, // 53: atelet.ExternalVolumeSource.PublishContextEntry + nil, // 52: atelet.ExternalVolume.VolumeContextEntry + nil, // 53: atelet.ExternalVolume.PublishContextEntry } var file_atelet_proto_depIdxs = []int32{ 7, // 0: atelet.RegisterWorkerRequest.capacity:type_name -> atelet.WorkerResources @@ -3781,15 +3781,15 @@ var file_atelet_proto_depIdxs = []int32{ 51, // 12: atelet.SandboxAssets.assets:type_name -> atelet.SandboxAssets.AssetsEntry 33, // 13: atelet.WorkloadSpec.containers:type_name -> atelet.Container 31, // 14: atelet.WorkloadSpec.volumes:type_name -> atelet.Volume - 52, // 15: atelet.ExternalVolumeSource.volume_context:type_name -> atelet.ExternalVolumeSource.VolumeContextEntry - 53, // 16: atelet.ExternalVolumeSource.publish_context:type_name -> atelet.ExternalVolumeSource.PublishContextEntry + 52, // 15: atelet.ExternalVolume.volume_context:type_name -> atelet.ExternalVolume.VolumeContextEntry + 53, // 16: atelet.ExternalVolume.publish_context:type_name -> atelet.ExternalVolume.PublishContextEntry 0, // 17: atelet.ActorMetadataItem.field:type_name -> atelet.ActorMetadataField 26, // 18: atelet.ActorMetadataDataSource.items:type_name -> atelet.ActorMetadataItem 27, // 19: atelet.SystemInfoDataSource.actor_metadata:type_name -> atelet.ActorMetadataDataSource 28, // 20: atelet.SystemInfoDataSource.trust_bundle:type_name -> atelet.TrustBundleDataSource 29, // 21: atelet.SystemInfoVolume.data_sources:type_name -> atelet.SystemInfoDataSource 23, // 22: atelet.Volume.durable_dir:type_name -> atelet.DurableDirVolume - 24, // 23: atelet.Volume.external:type_name -> atelet.ExternalVolumeSource + 24, // 23: atelet.Volume.external:type_name -> atelet.ExternalVolume 30, // 24: atelet.Volume.system_info:type_name -> atelet.SystemInfoVolume 25, // 25: atelet.Volume.image:type_name -> atelet.ImageVolumeSource 37, // 26: atelet.Container.env:type_name -> atelet.EnvEntry diff --git a/internal/proto/ateletpb/atelet.proto b/internal/proto/ateletpb/atelet.proto index 6c13cb4e31..5b635efb77 100644 --- a/internal/proto/ateletpb/atelet.proto +++ b/internal/proto/ateletpb/atelet.proto @@ -451,17 +451,17 @@ message WorkloadSpec { message DurableDirVolume { } -message ExternalVolumeSource { +message ExternalVolume { // Required, unlike the actor status counterpart: the control plane only // sends volumes that finished provisioning. // // +k8s:required - // +k8s:maxLength=256 # matches ExternalVolume.storage_volume_id's bound + // +k8s:maxLength=256 # matches ExternalVolumeRef.storage_volume_id's bound // +k8s:customValidation # no control characters string storage_volume_id = 1; // +k8s:optional - // +k8s:maxLength=253 # matches ExternalVolume.volume_type's bound + // +k8s:maxLength=253 # matches ExternalVolumeRef.volume_type's bound // +k8s:customValidation # optional "substrate.io/" prefix + DNS subdomain string volume_type = 2; @@ -590,7 +590,7 @@ message Volume { // +k8s:optional // +k8s:unionMember - ExternalVolumeSource external = 3; + ExternalVolume external = 3; // +k8s:optional // +k8s:unionMember diff --git a/pkg/proto/ateapipb/ateapi.pb.go b/pkg/proto/ateapipb/ateapi.pb.go index fde3450ce7..d75b9ec9cc 100644 --- a/pkg/proto/ateapipb/ateapi.pb.go +++ b/pkg/proto/ateapipb/ateapi.pb.go @@ -529,27 +529,28 @@ func (WorkerState) EnumDescriptor() ([]byte, []int) { return file_ateapi_proto_rawDescGZIP(), []int{8} } -type ExternalVolume_Status int32 +// Status is the volume's lifecycle state in the storage system. +type ExternalVolumeRef_Status int32 const ( - ExternalVolume_STATUS_UNSPECIFIED ExternalVolume_Status = 0 + ExternalVolumeRef_STATUS_UNSPECIFIED ExternalVolumeRef_Status = 0 // Volume creation pending in the storage system. - ExternalVolume_STATUS_PENDING ExternalVolume_Status = 1 + ExternalVolumeRef_STATUS_PENDING ExternalVolumeRef_Status = 1 // Volume successfully created in the storage system. - ExternalVolume_STATUS_CREATED ExternalVolume_Status = 2 + ExternalVolumeRef_STATUS_CREATED ExternalVolumeRef_Status = 2 // Volume being deleted from the storage system. - ExternalVolume_STATUS_DELETING ExternalVolume_Status = 3 // Keep this in sync with ExternalVolume.status's maximum. + ExternalVolumeRef_STATUS_DELETING ExternalVolumeRef_Status = 3 // Keep this in sync with ExternalVolumeRef.status's maximum. ) -// Enum value maps for ExternalVolume_Status. +// Enum value maps for ExternalVolumeRef_Status. var ( - ExternalVolume_Status_name = map[int32]string{ + ExternalVolumeRef_Status_name = map[int32]string{ 0: "STATUS_UNSPECIFIED", 1: "STATUS_PENDING", 2: "STATUS_CREATED", 3: "STATUS_DELETING", } - ExternalVolume_Status_value = map[string]int32{ + ExternalVolumeRef_Status_value = map[string]int32{ "STATUS_UNSPECIFIED": 0, "STATUS_PENDING": 1, "STATUS_CREATED": 2, @@ -557,30 +558,30 @@ var ( } ) -func (x ExternalVolume_Status) Enum() *ExternalVolume_Status { - p := new(ExternalVolume_Status) +func (x ExternalVolumeRef_Status) Enum() *ExternalVolumeRef_Status { + p := new(ExternalVolumeRef_Status) *p = x return p } -func (x ExternalVolume_Status) String() string { +func (x ExternalVolumeRef_Status) String() string { return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } -func (ExternalVolume_Status) Descriptor() protoreflect.EnumDescriptor { +func (ExternalVolumeRef_Status) Descriptor() protoreflect.EnumDescriptor { return file_ateapi_proto_enumTypes[9].Descriptor() } -func (ExternalVolume_Status) Type() protoreflect.EnumType { +func (ExternalVolumeRef_Status) Type() protoreflect.EnumType { return &file_ateapi_proto_enumTypes[9] } -func (x ExternalVolume_Status) Number() protoreflect.EnumNumber { +func (x ExternalVolumeRef_Status) Number() protoreflect.EnumNumber { return protoreflect.EnumNumber(x) } -// Deprecated: Use ExternalVolume_Status.Descriptor instead. -func (ExternalVolume_Status) EnumDescriptor() ([]byte, []int) { +// Deprecated: Use ExternalVolumeRef_Status.Descriptor instead. +func (ExternalVolumeRef_Status) EnumDescriptor() ([]byte, []int) { return file_ateapi_proto_rawDescGZIP(), []int{5, 0} } @@ -1009,7 +1010,8 @@ func (x *ResourceMetadata) GetUpdateTime() *timestamppb.Timestamp { return nil } -type ExternalVolume struct { +// ExternalVolumeRef is one actor's view of an external volume it mounts. +type ExternalVolumeRef struct { state protoimpl.MessageState `protogen:"open.v1"` // Name of the volume specified in the actor template. Template volume // names are DNS labels. @@ -1043,10 +1045,12 @@ type ExternalVolume struct { // +k8s:update=NoUnset # set-once, like name above // +k8s:customValidation VolumeType string `protobuf:"bytes,3,opt,name=volume_type,json=volumeType,proto3" json:"volume_type,omitempty"` + // status is the volume's lifecycle state in the storage system. + // // +k8s:optional // +k8s:minimum=1 // +k8s:maximum=3 # keep this in sync with the Status enum - Status ExternalVolume_Status `protobuf:"varint,4,opt,name=status,proto3,enum=ateapi.ExternalVolume_Status" json:"status,omitempty"` + Status ExternalVolumeRef_Status `protobuf:"varint,4,opt,name=status,proto3,enum=ateapi.ExternalVolumeRef_Status" json:"status,omitempty"` // volume_context contains metadata returned by the CSI driver during volume // provisioning, needed by the node plugin for mounting (e.g. attachment // info). Keys and values are the driver's own, so the map is only bounded, @@ -1059,20 +1063,20 @@ type ExternalVolume struct { sizeCache protoimpl.SizeCache } -func (x *ExternalVolume) Reset() { - *x = ExternalVolume{} +func (x *ExternalVolumeRef) Reset() { + *x = ExternalVolumeRef{} mi := &file_ateapi_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *ExternalVolume) String() string { +func (x *ExternalVolumeRef) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ExternalVolume) ProtoMessage() {} +func (*ExternalVolumeRef) ProtoMessage() {} -func (x *ExternalVolume) ProtoReflect() protoreflect.Message { +func (x *ExternalVolumeRef) ProtoReflect() protoreflect.Message { mi := &file_ateapi_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1084,40 +1088,40 @@ func (x *ExternalVolume) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ExternalVolume.ProtoReflect.Descriptor instead. -func (*ExternalVolume) Descriptor() ([]byte, []int) { +// Deprecated: Use ExternalVolumeRef.ProtoReflect.Descriptor instead. +func (*ExternalVolumeRef) Descriptor() ([]byte, []int) { return file_ateapi_proto_rawDescGZIP(), []int{5} } -func (x *ExternalVolume) GetName() string { +func (x *ExternalVolumeRef) GetName() string { if x != nil { return x.Name } return "" } -func (x *ExternalVolume) GetStorageVolumeId() string { +func (x *ExternalVolumeRef) GetStorageVolumeId() string { if x != nil { return x.StorageVolumeId } return "" } -func (x *ExternalVolume) GetVolumeType() string { +func (x *ExternalVolumeRef) GetVolumeType() string { if x != nil { return x.VolumeType } return "" } -func (x *ExternalVolume) GetStatus() ExternalVolume_Status { +func (x *ExternalVolumeRef) GetStatus() ExternalVolumeRef_Status { if x != nil { return x.Status } - return ExternalVolume_STATUS_UNSPECIFIED + return ExternalVolumeRef_STATUS_UNSPECIFIED } -func (x *ExternalVolume) GetVolumeContext() map[string]string { +func (x *ExternalVolumeRef) GetVolumeContext() map[string]string { if x != nil { return x.VolumeContext } @@ -1991,7 +1995,7 @@ type ActorStatus struct { // +k8s:maxItems=32 # matches the template's volumes bound // +k8s:listType=map // +k8s:listMapKey=name - ExternalVolumes []*ExternalVolume `protobuf:"bytes,7,rep,name=external_volumes,json=externalVolumes,proto3" json:"external_volumes,omitempty"` + ExternalVolumes []*ExternalVolumeRef `protobuf:"bytes,7,rep,name=external_volumes,json=externalVolumes,proto3" json:"external_volumes,omitempty"` // crash records why and when the Actor entered CRASHED. It is set with the // CRASHED state and cleared when a revert returns the Actor to SUSPENDED. // @@ -2070,7 +2074,7 @@ func (x *ActorStatus) GetWorkerAssignment() *WorkerAssignment { return nil } -func (x *ActorStatus) GetExternalVolumes() []*ExternalVolume { +func (x *ActorStatus) GetExternalVolumes() []*ExternalVolumeRef { if x != nil { return x.ExternalVolumes } @@ -3621,15 +3625,18 @@ type Volume struct { // +k8s:required // +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. + // Exactly one of durable_dir / external / image / system_info must be + // set. // // +k8s:optional // +k8s:unionMember DurableDir *DurableDirVolumeSource `protobuf:"bytes,2,opt,name=durable_dir,json=durableDir,proto3" json:"durable_dir,omitempty"` + // external is a CSI volume: provisioned for this actor from a template, + // or a SharedVolume the actor references. + // // +k8s:optional // +k8s:unionMember - ExternalVolumeTemplate *ExternalVolumeTemplate `protobuf:"bytes,3,opt,name=external_volume_template,json=externalVolumeTemplate,proto3" json:"external_volume_template,omitempty"` + External *ExternalVolumeSource `protobuf:"bytes,7,opt,name=external,proto3" json:"external,omitempty"` // +k8s:optional // +k8s:unionMember SystemInfo *SystemInfoVolumeSource `protobuf:"bytes,5,opt,name=system_info,json=systemInfo,proto3" json:"system_info,omitempty"` @@ -3686,9 +3693,9 @@ func (x *Volume) GetDurableDir() *DurableDirVolumeSource { return nil } -func (x *Volume) GetExternalVolumeTemplate() *ExternalVolumeTemplate { +func (x *Volume) GetExternal() *ExternalVolumeSource { if x != nil { - return x.ExternalVolumeTemplate + return x.External } return nil } @@ -3707,6 +3714,56 @@ func (x *Volume) GetImage() *ImageVolumeSource { return nil } +// ExternalVolumeSource is a CSI volume: provisioned for the actor from a +// template, or a SharedVolume that already exists. +type ExternalVolumeSource struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Exactly one of template / shared_volume must be set. + // + // +k8s:optional + // +k8s:unionMember + Template *ExternalVolumeTemplate `protobuf:"bytes,1,opt,name=template,proto3" json:"template,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ExternalVolumeSource) Reset() { + *x = ExternalVolumeSource{} + mi := &file_ateapi_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ExternalVolumeSource) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExternalVolumeSource) ProtoMessage() {} + +func (x *ExternalVolumeSource) 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 ExternalVolumeSource.ProtoReflect.Descriptor instead. +func (*ExternalVolumeSource) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{39} +} + +func (x *ExternalVolumeSource) GetTemplate() *ExternalVolumeTemplate { + if x != nil { + return x.Template + } + return nil +} + // ImageVolumeSource mounts the contents of an OCI image, read-only. The // reference must include a digest: changing the image invalidates // snapshots. @@ -3725,7 +3782,7 @@ type ImageVolumeSource struct { func (x *ImageVolumeSource) Reset() { *x = ImageVolumeSource{} - mi := &file_ateapi_proto_msgTypes[39] + mi := &file_ateapi_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3737,7 +3794,7 @@ func (x *ImageVolumeSource) String() string { func (*ImageVolumeSource) ProtoMessage() {} func (x *ImageVolumeSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[39] + mi := &file_ateapi_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3750,7 +3807,7 @@ func (x *ImageVolumeSource) ProtoReflect() protoreflect.Message { // Deprecated: Use ImageVolumeSource.ProtoReflect.Descriptor instead. func (*ImageVolumeSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{39} + return file_ateapi_proto_rawDescGZIP(), []int{40} } func (x *ImageVolumeSource) GetReference() string { @@ -3770,7 +3827,7 @@ type DurableDirVolumeSource struct { func (x *DurableDirVolumeSource) Reset() { *x = DurableDirVolumeSource{} - mi := &file_ateapi_proto_msgTypes[40] + mi := &file_ateapi_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3782,7 +3839,7 @@ func (x *DurableDirVolumeSource) String() string { func (*DurableDirVolumeSource) ProtoMessage() {} func (x *DurableDirVolumeSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[40] + mi := &file_ateapi_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3795,7 +3852,7 @@ func (x *DurableDirVolumeSource) ProtoReflect() protoreflect.Message { // Deprecated: Use DurableDirVolumeSource.ProtoReflect.Descriptor instead. func (*DurableDirVolumeSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{40} + return file_ateapi_proto_rawDescGZIP(), []int{41} } // ExternalVolumeTemplate provisions an external volume per actor; the volume @@ -3821,7 +3878,7 @@ type ExternalVolumeTemplate struct { func (x *ExternalVolumeTemplate) Reset() { *x = ExternalVolumeTemplate{} - mi := &file_ateapi_proto_msgTypes[41] + mi := &file_ateapi_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3833,7 +3890,7 @@ func (x *ExternalVolumeTemplate) String() string { func (*ExternalVolumeTemplate) ProtoMessage() {} func (x *ExternalVolumeTemplate) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[41] + mi := &file_ateapi_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3846,7 +3903,7 @@ func (x *ExternalVolumeTemplate) ProtoReflect() protoreflect.Message { // Deprecated: Use ExternalVolumeTemplate.ProtoReflect.Descriptor instead. func (*ExternalVolumeTemplate) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{41} + return file_ateapi_proto_rawDescGZIP(), []int{42} } func (x *ExternalVolumeTemplate) GetCapacity() string { @@ -3883,7 +3940,7 @@ type SystemInfoVolumeSource struct { func (x *SystemInfoVolumeSource) Reset() { *x = SystemInfoVolumeSource{} - mi := &file_ateapi_proto_msgTypes[42] + mi := &file_ateapi_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3895,7 +3952,7 @@ func (x *SystemInfoVolumeSource) String() string { func (*SystemInfoVolumeSource) ProtoMessage() {} func (x *SystemInfoVolumeSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[42] + mi := &file_ateapi_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3908,7 +3965,7 @@ func (x *SystemInfoVolumeSource) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemInfoVolumeSource.ProtoReflect.Descriptor instead. func (*SystemInfoVolumeSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{42} + return file_ateapi_proto_rawDescGZIP(), []int{43} } func (x *SystemInfoVolumeSource) GetDataSources() []*SystemInfoDataSource { @@ -3934,7 +3991,7 @@ type SystemInfoDataSource struct { func (x *SystemInfoDataSource) Reset() { *x = SystemInfoDataSource{} - mi := &file_ateapi_proto_msgTypes[43] + mi := &file_ateapi_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3946,7 +4003,7 @@ func (x *SystemInfoDataSource) String() string { func (*SystemInfoDataSource) ProtoMessage() {} func (x *SystemInfoDataSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[43] + mi := &file_ateapi_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3959,7 +4016,7 @@ func (x *SystemInfoDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemInfoDataSource.ProtoReflect.Descriptor instead. func (*SystemInfoDataSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{43} + return file_ateapi_proto_rawDescGZIP(), []int{44} } func (x *SystemInfoDataSource) GetActorMetadata() *ActorMetadataDataSource { @@ -3996,7 +4053,7 @@ type ActorMetadataDataSource struct { func (x *ActorMetadataDataSource) Reset() { *x = ActorMetadataDataSource{} - mi := &file_ateapi_proto_msgTypes[44] + mi := &file_ateapi_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4008,7 +4065,7 @@ func (x *ActorMetadataDataSource) String() string { func (*ActorMetadataDataSource) ProtoMessage() {} func (x *ActorMetadataDataSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[44] + mi := &file_ateapi_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4021,7 +4078,7 @@ func (x *ActorMetadataDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorMetadataDataSource.ProtoReflect.Descriptor instead. func (*ActorMetadataDataSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{44} + return file_ateapi_proto_rawDescGZIP(), []int{45} } func (x *ActorMetadataDataSource) GetItems() []*ActorMetadataItem { @@ -4053,7 +4110,7 @@ type ActorMetadataItem struct { func (x *ActorMetadataItem) Reset() { *x = ActorMetadataItem{} - mi := &file_ateapi_proto_msgTypes[45] + mi := &file_ateapi_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4065,7 +4122,7 @@ func (x *ActorMetadataItem) String() string { func (*ActorMetadataItem) ProtoMessage() {} func (x *ActorMetadataItem) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[45] + mi := &file_ateapi_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4078,7 +4135,7 @@ func (x *ActorMetadataItem) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorMetadataItem.ProtoReflect.Descriptor instead. func (*ActorMetadataItem) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{45} + return file_ateapi_proto_rawDescGZIP(), []int{46} } func (x *ActorMetadataItem) GetField() ActorMetadataField { @@ -4130,7 +4187,7 @@ type TrustBundleDataSource struct { func (x *TrustBundleDataSource) Reset() { *x = TrustBundleDataSource{} - mi := &file_ateapi_proto_msgTypes[46] + mi := &file_ateapi_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4142,7 +4199,7 @@ func (x *TrustBundleDataSource) String() string { func (*TrustBundleDataSource) ProtoMessage() {} func (x *TrustBundleDataSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[46] + mi := &file_ateapi_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4155,7 +4212,7 @@ func (x *TrustBundleDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use TrustBundleDataSource.ProtoReflect.Descriptor instead. func (*TrustBundleDataSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{46} + return file_ateapi_proto_rawDescGZIP(), []int{47} } func (x *TrustBundleDataSource) GetNames() []string { @@ -4194,7 +4251,7 @@ type VolumeMount struct { func (x *VolumeMount) Reset() { *x = VolumeMount{} - mi := &file_ateapi_proto_msgTypes[47] + mi := &file_ateapi_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4206,7 +4263,7 @@ func (x *VolumeMount) String() string { func (*VolumeMount) ProtoMessage() {} func (x *VolumeMount) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[47] + mi := &file_ateapi_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4219,7 +4276,7 @@ func (x *VolumeMount) ProtoReflect() protoreflect.Message { // Deprecated: Use VolumeMount.ProtoReflect.Descriptor instead. func (*VolumeMount) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{47} + return file_ateapi_proto_rawDescGZIP(), []int{48} } func (x *VolumeMount) GetName() string { @@ -4248,7 +4305,7 @@ type CreateAtespaceRequest struct { func (x *CreateAtespaceRequest) Reset() { *x = CreateAtespaceRequest{} - mi := &file_ateapi_proto_msgTypes[48] + mi := &file_ateapi_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4260,7 +4317,7 @@ func (x *CreateAtespaceRequest) String() string { func (*CreateAtespaceRequest) ProtoMessage() {} func (x *CreateAtespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[48] + mi := &file_ateapi_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4273,7 +4330,7 @@ func (x *CreateAtespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateAtespaceRequest.ProtoReflect.Descriptor instead. func (*CreateAtespaceRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{48} + return file_ateapi_proto_rawDescGZIP(), []int{49} } func (x *CreateAtespaceRequest) GetAtespace() *Atespace { @@ -4294,7 +4351,7 @@ type GetAtespaceRequest struct { func (x *GetAtespaceRequest) Reset() { *x = GetAtespaceRequest{} - mi := &file_ateapi_proto_msgTypes[49] + mi := &file_ateapi_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4306,7 +4363,7 @@ func (x *GetAtespaceRequest) String() string { func (*GetAtespaceRequest) ProtoMessage() {} func (x *GetAtespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[49] + mi := &file_ateapi_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4319,7 +4376,7 @@ func (x *GetAtespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAtespaceRequest.ProtoReflect.Descriptor instead. func (*GetAtespaceRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{49} + return file_ateapi_proto_rawDescGZIP(), []int{50} } func (x *GetAtespaceRequest) GetAtespace() *ObjectRef { @@ -4350,7 +4407,7 @@ type ListAtespacesRequest struct { func (x *ListAtespacesRequest) Reset() { *x = ListAtespacesRequest{} - mi := &file_ateapi_proto_msgTypes[50] + mi := &file_ateapi_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4362,7 +4419,7 @@ func (x *ListAtespacesRequest) String() string { func (*ListAtespacesRequest) ProtoMessage() {} func (x *ListAtespacesRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[50] + mi := &file_ateapi_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4375,7 +4432,7 @@ func (x *ListAtespacesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAtespacesRequest.ProtoReflect.Descriptor instead. func (*ListAtespacesRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{50} + return file_ateapi_proto_rawDescGZIP(), []int{51} } func (x *ListAtespacesRequest) GetPageSize() int32 { @@ -4404,7 +4461,7 @@ type ListAtespacesResponse struct { func (x *ListAtespacesResponse) Reset() { *x = ListAtespacesResponse{} - mi := &file_ateapi_proto_msgTypes[51] + mi := &file_ateapi_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4416,7 +4473,7 @@ func (x *ListAtespacesResponse) String() string { func (*ListAtespacesResponse) ProtoMessage() {} func (x *ListAtespacesResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[51] + mi := &file_ateapi_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4429,7 +4486,7 @@ func (x *ListAtespacesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAtespacesResponse.ProtoReflect.Descriptor instead. func (*ListAtespacesResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{51} + return file_ateapi_proto_rawDescGZIP(), []int{52} } func (x *ListAtespacesResponse) GetAtespaces() []*Atespace { @@ -4461,7 +4518,7 @@ type DeleteAtespaceRequest struct { func (x *DeleteAtespaceRequest) Reset() { *x = DeleteAtespaceRequest{} - mi := &file_ateapi_proto_msgTypes[52] + mi := &file_ateapi_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4473,7 +4530,7 @@ func (x *DeleteAtespaceRequest) String() string { func (*DeleteAtespaceRequest) ProtoMessage() {} func (x *DeleteAtespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[52] + mi := &file_ateapi_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4486,7 +4543,7 @@ func (x *DeleteAtespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteAtespaceRequest.ProtoReflect.Descriptor instead. func (*DeleteAtespaceRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{52} + return file_ateapi_proto_rawDescGZIP(), []int{53} } func (x *DeleteAtespaceRequest) GetAtespace() *ObjectRef { @@ -4517,7 +4574,7 @@ type CreateActorTemplateRequest struct { func (x *CreateActorTemplateRequest) Reset() { *x = CreateActorTemplateRequest{} - mi := &file_ateapi_proto_msgTypes[53] + mi := &file_ateapi_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4529,7 +4586,7 @@ func (x *CreateActorTemplateRequest) String() string { func (*CreateActorTemplateRequest) ProtoMessage() {} func (x *CreateActorTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[53] + mi := &file_ateapi_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4542,7 +4599,7 @@ func (x *CreateActorTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateActorTemplateRequest.ProtoReflect.Descriptor instead. func (*CreateActorTemplateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{53} + return file_ateapi_proto_rawDescGZIP(), []int{54} } func (x *CreateActorTemplateRequest) GetActorTemplate() *ActorTemplate { @@ -4563,7 +4620,7 @@ type GetActorTemplateRequest struct { func (x *GetActorTemplateRequest) Reset() { *x = GetActorTemplateRequest{} - mi := &file_ateapi_proto_msgTypes[54] + mi := &file_ateapi_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4575,7 +4632,7 @@ func (x *GetActorTemplateRequest) String() string { func (*GetActorTemplateRequest) ProtoMessage() {} func (x *GetActorTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[54] + mi := &file_ateapi_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4588,7 +4645,7 @@ func (x *GetActorTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorTemplateRequest.ProtoReflect.Descriptor instead. func (*GetActorTemplateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{54} + return file_ateapi_proto_rawDescGZIP(), []int{55} } func (x *GetActorTemplateRequest) GetActorTemplate() *ObjectRef { @@ -4625,7 +4682,7 @@ type ListActorTemplatesRequest struct { func (x *ListActorTemplatesRequest) Reset() { *x = ListActorTemplatesRequest{} - mi := &file_ateapi_proto_msgTypes[55] + mi := &file_ateapi_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4637,7 +4694,7 @@ func (x *ListActorTemplatesRequest) String() string { func (*ListActorTemplatesRequest) ProtoMessage() {} func (x *ListActorTemplatesRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[55] + mi := &file_ateapi_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4650,7 +4707,7 @@ func (x *ListActorTemplatesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorTemplatesRequest.ProtoReflect.Descriptor instead. func (*ListActorTemplatesRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{55} + return file_ateapi_proto_rawDescGZIP(), []int{56} } func (x *ListActorTemplatesRequest) GetAtespace() string { @@ -4687,7 +4744,7 @@ type ListActorTemplatesResponse struct { func (x *ListActorTemplatesResponse) Reset() { *x = ListActorTemplatesResponse{} - mi := &file_ateapi_proto_msgTypes[56] + mi := &file_ateapi_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4699,7 +4756,7 @@ func (x *ListActorTemplatesResponse) String() string { func (*ListActorTemplatesResponse) ProtoMessage() {} func (x *ListActorTemplatesResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[56] + mi := &file_ateapi_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4712,7 +4769,7 @@ func (x *ListActorTemplatesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorTemplatesResponse.ProtoReflect.Descriptor instead. func (*ListActorTemplatesResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{56} + return file_ateapi_proto_rawDescGZIP(), []int{57} } func (x *ListActorTemplatesResponse) GetActorTemplates() []*ActorTemplate { @@ -4744,7 +4801,7 @@ type DeleteActorTemplateRequest struct { func (x *DeleteActorTemplateRequest) Reset() { *x = DeleteActorTemplateRequest{} - mi := &file_ateapi_proto_msgTypes[57] + mi := &file_ateapi_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4756,7 +4813,7 @@ func (x *DeleteActorTemplateRequest) String() string { func (*DeleteActorTemplateRequest) ProtoMessage() {} func (x *DeleteActorTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[57] + mi := &file_ateapi_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4769,7 +4826,7 @@ func (x *DeleteActorTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteActorTemplateRequest.ProtoReflect.Descriptor instead. func (*DeleteActorTemplateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{57} + return file_ateapi_proto_rawDescGZIP(), []int{58} } func (x *DeleteActorTemplateRequest) GetActorTemplate() *ObjectRef { @@ -4797,7 +4854,7 @@ type GetActorRequest struct { func (x *GetActorRequest) Reset() { *x = GetActorRequest{} - mi := &file_ateapi_proto_msgTypes[58] + mi := &file_ateapi_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4809,7 +4866,7 @@ func (x *GetActorRequest) String() string { func (*GetActorRequest) ProtoMessage() {} func (x *GetActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[58] + mi := &file_ateapi_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4822,7 +4879,7 @@ func (x *GetActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorRequest.ProtoReflect.Descriptor instead. func (*GetActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{58} + return file_ateapi_proto_rawDescGZIP(), []int{59} } func (x *GetActorRequest) GetActor() *ObjectRef { @@ -4845,7 +4902,7 @@ type CreateActorRequest struct { func (x *CreateActorRequest) Reset() { *x = CreateActorRequest{} - mi := &file_ateapi_proto_msgTypes[59] + mi := &file_ateapi_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4857,7 +4914,7 @@ func (x *CreateActorRequest) String() string { func (*CreateActorRequest) ProtoMessage() {} func (x *CreateActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[59] + mi := &file_ateapi_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4870,7 +4927,7 @@ func (x *CreateActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateActorRequest.ProtoReflect.Descriptor instead. func (*CreateActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{59} + return file_ateapi_proto_rawDescGZIP(), []int{60} } func (x *CreateActorRequest) GetActor() *Actor { @@ -4901,7 +4958,7 @@ type UpdateActorRequest struct { func (x *UpdateActorRequest) Reset() { *x = UpdateActorRequest{} - mi := &file_ateapi_proto_msgTypes[60] + mi := &file_ateapi_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4913,7 +4970,7 @@ func (x *UpdateActorRequest) String() string { func (*UpdateActorRequest) ProtoMessage() {} func (x *UpdateActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[60] + mi := &file_ateapi_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4926,7 +4983,7 @@ func (x *UpdateActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateActorRequest.ProtoReflect.Descriptor instead. func (*UpdateActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{60} + return file_ateapi_proto_rawDescGZIP(), []int{61} } func (x *UpdateActorRequest) GetActor() *Actor { @@ -4947,7 +5004,7 @@ type SuspendActorRequest struct { func (x *SuspendActorRequest) Reset() { *x = SuspendActorRequest{} - mi := &file_ateapi_proto_msgTypes[61] + mi := &file_ateapi_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4959,7 +5016,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[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4972,7 +5029,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{62} } func (x *SuspendActorRequest) GetActor() *ObjectRef { @@ -4991,7 +5048,7 @@ type SuspendActorResponse struct { func (x *SuspendActorResponse) Reset() { *x = SuspendActorResponse{} - mi := &file_ateapi_proto_msgTypes[62] + mi := &file_ateapi_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5003,7 +5060,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[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5016,7 +5073,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{63} } func (x *SuspendActorResponse) GetActor() *Actor { @@ -5037,7 +5094,7 @@ type PauseActorRequest struct { func (x *PauseActorRequest) Reset() { *x = PauseActorRequest{} - mi := &file_ateapi_proto_msgTypes[63] + mi := &file_ateapi_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5049,7 +5106,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[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5062,7 +5119,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{64} } func (x *PauseActorRequest) GetActor() *ObjectRef { @@ -5081,7 +5138,7 @@ type PauseActorResponse struct { func (x *PauseActorResponse) Reset() { *x = PauseActorResponse{} - mi := &file_ateapi_proto_msgTypes[64] + mi := &file_ateapi_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5093,7 +5150,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[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5106,7 +5163,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{65} } func (x *PauseActorResponse) GetActor() *Actor { @@ -5127,7 +5184,7 @@ type ResumeActorRequest struct { func (x *ResumeActorRequest) Reset() { *x = ResumeActorRequest{} - mi := &file_ateapi_proto_msgTypes[65] + mi := &file_ateapi_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5139,7 +5196,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[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5152,7 +5209,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{66} } func (x *ResumeActorRequest) GetActor() *ObjectRef { @@ -5174,7 +5231,7 @@ type ResumeActorResponse struct { func (x *ResumeActorResponse) Reset() { *x = ResumeActorResponse{} - mi := &file_ateapi_proto_msgTypes[66] + mi := &file_ateapi_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5186,7 +5243,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[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5199,7 +5256,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{67} } func (x *ResumeActorResponse) GetActor() *Actor { @@ -5229,7 +5286,7 @@ type RevertActorRequest struct { func (x *RevertActorRequest) Reset() { *x = RevertActorRequest{} - mi := &file_ateapi_proto_msgTypes[67] + mi := &file_ateapi_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5241,7 +5298,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[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5254,7 +5311,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{68} } func (x *RevertActorRequest) GetActor() *ObjectRef { @@ -5276,7 +5333,7 @@ type RevertActorResponse struct { func (x *RevertActorResponse) Reset() { *x = RevertActorResponse{} - mi := &file_ateapi_proto_msgTypes[68] + mi := &file_ateapi_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5288,7 +5345,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[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5301,7 +5358,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{69} } func (x *RevertActorResponse) GetActor() *Actor { @@ -5330,7 +5387,7 @@ type DeleteActorRequest struct { func (x *DeleteActorRequest) Reset() { *x = DeleteActorRequest{} - mi := &file_ateapi_proto_msgTypes[69] + mi := &file_ateapi_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5342,7 +5399,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[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5355,7 +5412,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{70} } func (x *DeleteActorRequest) GetActor() *ObjectRef { @@ -5399,7 +5456,7 @@ type GetActorEgressPolicyRequest struct { func (x *GetActorEgressPolicyRequest) Reset() { *x = GetActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[70] + mi := &file_ateapi_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5411,7 +5468,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[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5424,7 +5481,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{71} } func (x *GetActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -5462,7 +5519,7 @@ type CreateActorEgressPolicyRequest struct { func (x *CreateActorEgressPolicyRequest) Reset() { *x = CreateActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[71] + mi := &file_ateapi_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5474,7 +5531,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[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5487,7 +5544,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{72} } func (x *CreateActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -5525,7 +5582,7 @@ type UpdateActorEgressPolicyRequest struct { func (x *UpdateActorEgressPolicyRequest) Reset() { *x = UpdateActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[72] + mi := &file_ateapi_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5537,7 +5594,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[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5550,7 +5607,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{73} } func (x *UpdateActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -5591,7 +5648,7 @@ type DeleteActorEgressPolicyRequest struct { func (x *DeleteActorEgressPolicyRequest) Reset() { *x = DeleteActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[73] + mi := &file_ateapi_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5603,7 +5660,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[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5616,7 +5673,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{74} } func (x *DeleteActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -5651,7 +5708,7 @@ type GetTagRequest struct { func (x *GetTagRequest) Reset() { *x = GetTagRequest{} - mi := &file_ateapi_proto_msgTypes[74] + mi := &file_ateapi_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5663,7 +5720,7 @@ func (x *GetTagRequest) String() string { func (*GetTagRequest) ProtoMessage() {} func (x *GetTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[74] + mi := &file_ateapi_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5676,7 +5733,7 @@ func (x *GetTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTagRequest.ProtoReflect.Descriptor instead. func (*GetTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{74} + return file_ateapi_proto_rawDescGZIP(), []int{75} } func (x *GetTagRequest) GetTag() *ObjectRef { @@ -5715,7 +5772,7 @@ type MintActorJwtRequest struct { func (x *MintActorJwtRequest) Reset() { *x = MintActorJwtRequest{} - mi := &file_ateapi_proto_msgTypes[75] + mi := &file_ateapi_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5727,7 +5784,7 @@ func (x *MintActorJwtRequest) String() string { func (*MintActorJwtRequest) ProtoMessage() {} func (x *MintActorJwtRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[75] + mi := &file_ateapi_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5740,7 +5797,7 @@ func (x *MintActorJwtRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorJwtRequest.ProtoReflect.Descriptor instead. func (*MintActorJwtRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{75} + return file_ateapi_proto_rawDescGZIP(), []int{76} } func (x *MintActorJwtRequest) GetActor() *ObjectRef { @@ -5790,7 +5847,7 @@ type MintActorJwtResponse struct { func (x *MintActorJwtResponse) Reset() { *x = MintActorJwtResponse{} - mi := &file_ateapi_proto_msgTypes[76] + mi := &file_ateapi_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5802,7 +5859,7 @@ func (x *MintActorJwtResponse) String() string { func (*MintActorJwtResponse) ProtoMessage() {} func (x *MintActorJwtResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[76] + mi := &file_ateapi_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5815,7 +5872,7 @@ func (x *MintActorJwtResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorJwtResponse.ProtoReflect.Descriptor instead. func (*MintActorJwtResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{76} + return file_ateapi_proto_rawDescGZIP(), []int{77} } func (x *MintActorJwtResponse) GetActorJwt() string { @@ -5860,7 +5917,7 @@ type MintActorCertificateRequest struct { func (x *MintActorCertificateRequest) Reset() { *x = MintActorCertificateRequest{} - mi := &file_ateapi_proto_msgTypes[77] + mi := &file_ateapi_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5872,7 +5929,7 @@ func (x *MintActorCertificateRequest) String() string { func (*MintActorCertificateRequest) ProtoMessage() {} func (x *MintActorCertificateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[77] + mi := &file_ateapi_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5885,7 +5942,7 @@ func (x *MintActorCertificateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorCertificateRequest.ProtoReflect.Descriptor instead. func (*MintActorCertificateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{77} + return file_ateapi_proto_rawDescGZIP(), []int{78} } func (x *MintActorCertificateRequest) GetActor() *ObjectRef { @@ -5922,7 +5979,7 @@ type MintActorCertificateResponse struct { func (x *MintActorCertificateResponse) Reset() { *x = MintActorCertificateResponse{} - mi := &file_ateapi_proto_msgTypes[78] + mi := &file_ateapi_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5934,7 +5991,7 @@ func (x *MintActorCertificateResponse) String() string { func (*MintActorCertificateResponse) ProtoMessage() {} func (x *MintActorCertificateResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[78] + mi := &file_ateapi_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5947,7 +6004,7 @@ func (x *MintActorCertificateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorCertificateResponse.ProtoReflect.Descriptor instead. func (*MintActorCertificateResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{78} + return file_ateapi_proto_rawDescGZIP(), []int{79} } func (x *MintActorCertificateResponse) GetActorCertificates() [][]byte { @@ -5983,7 +6040,7 @@ type ListTagsRequest struct { func (x *ListTagsRequest) Reset() { *x = ListTagsRequest{} - mi := &file_ateapi_proto_msgTypes[79] + mi := &file_ateapi_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5995,7 +6052,7 @@ func (x *ListTagsRequest) String() string { func (*ListTagsRequest) ProtoMessage() {} func (x *ListTagsRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[79] + mi := &file_ateapi_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6008,7 +6065,7 @@ func (x *ListTagsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListTagsRequest.ProtoReflect.Descriptor instead. func (*ListTagsRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{79} + return file_ateapi_proto_rawDescGZIP(), []int{80} } func (x *ListTagsRequest) GetAtespace() string { @@ -6042,7 +6099,7 @@ type ListTagsResponse struct { func (x *ListTagsResponse) Reset() { *x = ListTagsResponse{} - mi := &file_ateapi_proto_msgTypes[80] + mi := &file_ateapi_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6054,7 +6111,7 @@ func (x *ListTagsResponse) String() string { func (*ListTagsResponse) ProtoMessage() {} func (x *ListTagsResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[80] + mi := &file_ateapi_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6067,7 +6124,7 @@ func (x *ListTagsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListTagsResponse.ProtoReflect.Descriptor instead. func (*ListTagsResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{80} + return file_ateapi_proto_rawDescGZIP(), []int{81} } func (x *ListTagsResponse) GetTags() []*Tag { @@ -6112,7 +6169,7 @@ type CreateTagRequest struct { func (x *CreateTagRequest) Reset() { *x = CreateTagRequest{} - mi := &file_ateapi_proto_msgTypes[81] + mi := &file_ateapi_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6124,7 +6181,7 @@ func (x *CreateTagRequest) String() string { func (*CreateTagRequest) ProtoMessage() {} func (x *CreateTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[81] + mi := &file_ateapi_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6137,7 +6194,7 @@ func (x *CreateTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateTagRequest.ProtoReflect.Descriptor instead. func (*CreateTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{81} + return file_ateapi_proto_rawDescGZIP(), []int{82} } func (x *CreateTagRequest) GetTag() *Tag { @@ -6167,7 +6224,7 @@ type UpdateTagRequest struct { func (x *UpdateTagRequest) Reset() { *x = UpdateTagRequest{} - mi := &file_ateapi_proto_msgTypes[82] + mi := &file_ateapi_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6179,7 +6236,7 @@ func (x *UpdateTagRequest) String() string { func (*UpdateTagRequest) ProtoMessage() {} func (x *UpdateTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[82] + mi := &file_ateapi_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6192,7 +6249,7 @@ func (x *UpdateTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateTagRequest.ProtoReflect.Descriptor instead. func (*UpdateTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{82} + return file_ateapi_proto_rawDescGZIP(), []int{83} } func (x *UpdateTagRequest) GetTag() *Tag { @@ -6217,7 +6274,7 @@ type DeleteTagRequest struct { func (x *DeleteTagRequest) Reset() { *x = DeleteTagRequest{} - mi := &file_ateapi_proto_msgTypes[83] + mi := &file_ateapi_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6229,7 +6286,7 @@ func (x *DeleteTagRequest) String() string { func (*DeleteTagRequest) ProtoMessage() {} func (x *DeleteTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[83] + mi := &file_ateapi_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6242,7 +6299,7 @@ func (x *DeleteTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteTagRequest.ProtoReflect.Descriptor instead. func (*DeleteTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{83} + return file_ateapi_proto_rawDescGZIP(), []int{84} } func (x *DeleteTagRequest) GetTag() *ObjectRef { @@ -6281,7 +6338,7 @@ type DeleteOptions struct { func (x *DeleteOptions) Reset() { *x = DeleteOptions{} - mi := &file_ateapi_proto_msgTypes[84] + mi := &file_ateapi_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6293,7 +6350,7 @@ func (x *DeleteOptions) String() string { func (*DeleteOptions) ProtoMessage() {} func (x *DeleteOptions) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[84] + mi := &file_ateapi_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6306,7 +6363,7 @@ func (x *DeleteOptions) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteOptions.ProtoReflect.Descriptor instead. func (*DeleteOptions) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{84} + return file_ateapi_proto_rawDescGZIP(), []int{85} } func (x *DeleteOptions) GetVersion() int64 { @@ -6350,7 +6407,7 @@ type ListWorkerActorAssignmentsRequest struct { func (x *ListWorkerActorAssignmentsRequest) Reset() { *x = ListWorkerActorAssignmentsRequest{} - mi := &file_ateapi_proto_msgTypes[85] + mi := &file_ateapi_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6362,7 +6419,7 @@ func (x *ListWorkerActorAssignmentsRequest) String() string { func (*ListWorkerActorAssignmentsRequest) ProtoMessage() {} func (x *ListWorkerActorAssignmentsRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[85] + mi := &file_ateapi_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6375,7 +6432,7 @@ func (x *ListWorkerActorAssignmentsRequest) ProtoReflect() protoreflect.Message // Deprecated: Use ListWorkerActorAssignmentsRequest.ProtoReflect.Descriptor instead. func (*ListWorkerActorAssignmentsRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{85} + return file_ateapi_proto_rawDescGZIP(), []int{86} } func (x *ListWorkerActorAssignmentsRequest) GetWorker() *ObjectRef { @@ -6412,7 +6469,7 @@ type ListWorkerActorAssignmentsResponse struct { func (x *ListWorkerActorAssignmentsResponse) Reset() { *x = ListWorkerActorAssignmentsResponse{} - mi := &file_ateapi_proto_msgTypes[86] + mi := &file_ateapi_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6424,7 +6481,7 @@ func (x *ListWorkerActorAssignmentsResponse) String() string { func (*ListWorkerActorAssignmentsResponse) ProtoMessage() {} func (x *ListWorkerActorAssignmentsResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[86] + mi := &file_ateapi_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6437,7 +6494,7 @@ func (x *ListWorkerActorAssignmentsResponse) ProtoReflect() protoreflect.Message // Deprecated: Use ListWorkerActorAssignmentsResponse.ProtoReflect.Descriptor instead. func (*ListWorkerActorAssignmentsResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{86} + return file_ateapi_proto_rawDescGZIP(), []int{87} } func (x *ListWorkerActorAssignmentsResponse) GetActorAssignments() []*ActorAssignment { @@ -6475,7 +6532,7 @@ type ListWorkersRequest struct { func (x *ListWorkersRequest) Reset() { *x = ListWorkersRequest{} - mi := &file_ateapi_proto_msgTypes[87] + mi := &file_ateapi_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6487,7 +6544,7 @@ func (x *ListWorkersRequest) String() string { func (*ListWorkersRequest) ProtoMessage() {} func (x *ListWorkersRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[87] + mi := &file_ateapi_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6500,7 +6557,7 @@ func (x *ListWorkersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkersRequest.ProtoReflect.Descriptor instead. func (*ListWorkersRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{87} + return file_ateapi_proto_rawDescGZIP(), []int{88} } func (x *ListWorkersRequest) GetPageSize() int32 { @@ -6529,7 +6586,7 @@ type ListWorkersResponse struct { func (x *ListWorkersResponse) Reset() { *x = ListWorkersResponse{} - mi := &file_ateapi_proto_msgTypes[88] + mi := &file_ateapi_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6541,7 +6598,7 @@ func (x *ListWorkersResponse) String() string { func (*ListWorkersResponse) ProtoMessage() {} func (x *ListWorkersResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[88] + mi := &file_ateapi_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6554,7 +6611,7 @@ func (x *ListWorkersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkersResponse.ProtoReflect.Descriptor instead. func (*ListWorkersResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{88} + return file_ateapi_proto_rawDescGZIP(), []int{89} } func (x *ListWorkersResponse) GetWorkers() []*Worker { @@ -6584,7 +6641,7 @@ type GetWorkerRequest struct { func (x *GetWorkerRequest) Reset() { *x = GetWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[89] + mi := &file_ateapi_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6596,7 +6653,7 @@ func (x *GetWorkerRequest) String() string { func (*GetWorkerRequest) ProtoMessage() {} func (x *GetWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[89] + mi := &file_ateapi_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6609,7 +6666,7 @@ func (x *GetWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkerRequest.ProtoReflect.Descriptor instead. func (*GetWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{89} + return file_ateapi_proto_rawDescGZIP(), []int{90} } func (x *GetWorkerRequest) GetWorker() *ObjectRef { @@ -6631,7 +6688,7 @@ type CreateWorkerRequest struct { func (x *CreateWorkerRequest) Reset() { *x = CreateWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[90] + mi := &file_ateapi_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6643,7 +6700,7 @@ func (x *CreateWorkerRequest) String() string { func (*CreateWorkerRequest) ProtoMessage() {} func (x *CreateWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[90] + mi := &file_ateapi_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6656,7 +6713,7 @@ func (x *CreateWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkerRequest.ProtoReflect.Descriptor instead. func (*CreateWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{90} + return file_ateapi_proto_rawDescGZIP(), []int{91} } func (x *CreateWorkerRequest) GetWorker() *Worker { @@ -6691,7 +6748,7 @@ type UpdateWorkerRequest struct { func (x *UpdateWorkerRequest) Reset() { *x = UpdateWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[91] + mi := &file_ateapi_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6703,7 +6760,7 @@ func (x *UpdateWorkerRequest) String() string { func (*UpdateWorkerRequest) ProtoMessage() {} func (x *UpdateWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[91] + mi := &file_ateapi_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6716,7 +6773,7 @@ func (x *UpdateWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateWorkerRequest.ProtoReflect.Descriptor instead. func (*UpdateWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{91} + return file_ateapi_proto_rawDescGZIP(), []int{92} } func (x *UpdateWorkerRequest) GetWorker() *Worker { @@ -6743,7 +6800,7 @@ type DeleteWorkerRequest struct { func (x *DeleteWorkerRequest) Reset() { *x = DeleteWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[92] + mi := &file_ateapi_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6755,7 +6812,7 @@ func (x *DeleteWorkerRequest) String() string { func (*DeleteWorkerRequest) ProtoMessage() {} func (x *DeleteWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[92] + mi := &file_ateapi_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6768,7 +6825,7 @@ func (x *DeleteWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkerRequest.ProtoReflect.Descriptor instead. func (*DeleteWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{92} + return file_ateapi_proto_rawDescGZIP(), []int{93} } func (x *DeleteWorkerRequest) GetWorker() *ObjectRef { @@ -6798,7 +6855,7 @@ type DrainWorkerRequest struct { func (x *DrainWorkerRequest) Reset() { *x = DrainWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[93] + mi := &file_ateapi_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6810,7 +6867,7 @@ func (x *DrainWorkerRequest) String() string { func (*DrainWorkerRequest) ProtoMessage() {} func (x *DrainWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[93] + mi := &file_ateapi_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6823,7 +6880,7 @@ func (x *DrainWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DrainWorkerRequest.ProtoReflect.Descriptor instead. func (*DrainWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{93} + return file_ateapi_proto_rawDescGZIP(), []int{94} } func (x *DrainWorkerRequest) GetWorker() *ObjectRef { @@ -6844,7 +6901,7 @@ type DrainWorkerResponse struct { func (x *DrainWorkerResponse) Reset() { *x = DrainWorkerResponse{} - mi := &file_ateapi_proto_msgTypes[94] + mi := &file_ateapi_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6856,7 +6913,7 @@ func (x *DrainWorkerResponse) String() string { func (*DrainWorkerResponse) ProtoMessage() {} func (x *DrainWorkerResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[94] + mi := &file_ateapi_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6869,7 +6926,7 @@ func (x *DrainWorkerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DrainWorkerResponse.ProtoReflect.Descriptor instead. func (*DrainWorkerResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{94} + return file_ateapi_proto_rawDescGZIP(), []int{95} } func (x *DrainWorkerResponse) GetWorker() *Worker { @@ -6907,7 +6964,7 @@ type ListActorsRequest struct { func (x *ListActorsRequest) Reset() { *x = ListActorsRequest{} - mi := &file_ateapi_proto_msgTypes[95] + mi := &file_ateapi_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6919,7 +6976,7 @@ func (x *ListActorsRequest) String() string { func (*ListActorsRequest) ProtoMessage() {} func (x *ListActorsRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[95] + mi := &file_ateapi_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6932,7 +6989,7 @@ func (x *ListActorsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorsRequest.ProtoReflect.Descriptor instead. func (*ListActorsRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{95} + return file_ateapi_proto_rawDescGZIP(), []int{96} } func (x *ListActorsRequest) GetAtespace() string { @@ -6968,7 +7025,7 @@ type ListActorsResponse struct { func (x *ListActorsResponse) Reset() { *x = ListActorsResponse{} - mi := &file_ateapi_proto_msgTypes[96] + mi := &file_ateapi_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6980,7 +7037,7 @@ func (x *ListActorsResponse) String() string { func (*ListActorsResponse) ProtoMessage() {} func (x *ListActorsResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[96] + mi := &file_ateapi_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6993,7 +7050,7 @@ func (x *ListActorsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorsResponse.ProtoReflect.Descriptor instead. func (*ListActorsResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{96} + return file_ateapi_proto_rawDescGZIP(), []int{97} } func (x *ListActorsResponse) GetActors() []*Actor { @@ -7100,7 +7157,7 @@ type Worker struct { func (x *Worker) Reset() { *x = Worker{} - mi := &file_ateapi_proto_msgTypes[97] + mi := &file_ateapi_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7112,7 +7169,7 @@ func (x *Worker) String() string { func (*Worker) ProtoMessage() {} func (x *Worker) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[97] + mi := &file_ateapi_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7125,7 +7182,7 @@ func (x *Worker) ProtoReflect() protoreflect.Message { // Deprecated: Use Worker.ProtoReflect.Descriptor instead. func (*Worker) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{97} + return file_ateapi_proto_rawDescGZIP(), []int{98} } func (x *Worker) GetMetadata() *ResourceMetadata { @@ -7254,7 +7311,7 @@ type WorkerStatus struct { func (x *WorkerStatus) Reset() { *x = WorkerStatus{} - mi := &file_ateapi_proto_msgTypes[98] + mi := &file_ateapi_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7266,7 +7323,7 @@ func (x *WorkerStatus) String() string { func (*WorkerStatus) ProtoMessage() {} func (x *WorkerStatus) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[98] + mi := &file_ateapi_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7279,7 +7336,7 @@ func (x *WorkerStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkerStatus.ProtoReflect.Descriptor instead. func (*WorkerStatus) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{98} + return file_ateapi_proto_rawDescGZIP(), []int{99} } func (x *WorkerStatus) GetState() WorkerState { @@ -7346,7 +7403,7 @@ type SandboxRuntime struct { func (x *SandboxRuntime) Reset() { *x = SandboxRuntime{} - mi := &file_ateapi_proto_msgTypes[99] + mi := &file_ateapi_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7358,7 +7415,7 @@ func (x *SandboxRuntime) String() string { func (*SandboxRuntime) ProtoMessage() {} func (x *SandboxRuntime) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[99] + mi := &file_ateapi_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7371,7 +7428,7 @@ func (x *SandboxRuntime) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxRuntime.ProtoReflect.Descriptor instead. func (*SandboxRuntime) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{99} + return file_ateapi_proto_rawDescGZIP(), []int{100} } func (x *SandboxRuntime) GetSandboxClass() string { @@ -7419,7 +7476,7 @@ type VersionedSandboxCompat struct { func (x *VersionedSandboxCompat) Reset() { *x = VersionedSandboxCompat{} - mi := &file_ateapi_proto_msgTypes[100] + mi := &file_ateapi_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7431,7 +7488,7 @@ func (x *VersionedSandboxCompat) String() string { func (*VersionedSandboxCompat) ProtoMessage() {} func (x *VersionedSandboxCompat) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[100] + mi := &file_ateapi_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7444,7 +7501,7 @@ func (x *VersionedSandboxCompat) ProtoReflect() protoreflect.Message { // Deprecated: Use VersionedSandboxCompat.ProtoReflect.Descriptor instead. func (*VersionedSandboxCompat) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{100} + return file_ateapi_proto_rawDescGZIP(), []int{101} } func (x *VersionedSandboxCompat) GetSchemaVersion() string { @@ -7480,7 +7537,7 @@ type AttributeEntry struct { func (x *AttributeEntry) Reset() { *x = AttributeEntry{} - mi := &file_ateapi_proto_msgTypes[101] + mi := &file_ateapi_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7492,7 +7549,7 @@ func (x *AttributeEntry) String() string { func (*AttributeEntry) ProtoMessage() {} func (x *AttributeEntry) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[101] + mi := &file_ateapi_proto_msgTypes[102] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7505,7 +7562,7 @@ func (x *AttributeEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use AttributeEntry.ProtoReflect.Descriptor instead. func (*AttributeEntry) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{101} + return file_ateapi_proto_rawDescGZIP(), []int{102} } func (x *AttributeEntry) GetKey() string { @@ -7544,7 +7601,7 @@ type WorkerResources struct { func (x *WorkerResources) Reset() { *x = WorkerResources{} - mi := &file_ateapi_proto_msgTypes[102] + mi := &file_ateapi_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7556,7 +7613,7 @@ func (x *WorkerResources) String() string { func (*WorkerResources) ProtoMessage() {} func (x *WorkerResources) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[102] + mi := &file_ateapi_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7569,7 +7626,7 @@ func (x *WorkerResources) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkerResources.ProtoReflect.Descriptor instead. func (*WorkerResources) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{102} + return file_ateapi_proto_rawDescGZIP(), []int{103} } func (x *WorkerResources) GetResources() *Resources { @@ -7622,7 +7679,7 @@ type ActorAssignment struct { func (x *ActorAssignment) Reset() { *x = ActorAssignment{} - mi := &file_ateapi_proto_msgTypes[103] + mi := &file_ateapi_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7634,7 +7691,7 @@ func (x *ActorAssignment) String() string { func (*ActorAssignment) ProtoMessage() {} func (x *ActorAssignment) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[103] + mi := &file_ateapi_proto_msgTypes[104] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7647,7 +7704,7 @@ func (x *ActorAssignment) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorAssignment.ProtoReflect.Descriptor instead. func (*ActorAssignment) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{103} + return file_ateapi_proto_rawDescGZIP(), []int{104} } func (x *ActorAssignment) GetMetadata() *ResourceMetadata { @@ -7718,7 +7775,7 @@ type RegisterWorkerRequest struct { func (x *RegisterWorkerRequest) Reset() { *x = RegisterWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[104] + mi := &file_ateapi_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7730,7 +7787,7 @@ func (x *RegisterWorkerRequest) String() string { func (*RegisterWorkerRequest) ProtoMessage() {} func (x *RegisterWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[104] + mi := &file_ateapi_proto_msgTypes[105] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7743,7 +7800,7 @@ func (x *RegisterWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterWorkerRequest.ProtoReflect.Descriptor instead. func (*RegisterWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{104} + return file_ateapi_proto_rawDescGZIP(), []int{105} } func (x *RegisterWorkerRequest) GetWorker() *ObjectRef { @@ -7784,7 +7841,7 @@ type RegisterWorkerResponse struct { func (x *RegisterWorkerResponse) Reset() { *x = RegisterWorkerResponse{} - mi := &file_ateapi_proto_msgTypes[105] + mi := &file_ateapi_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7796,7 +7853,7 @@ func (x *RegisterWorkerResponse) String() string { func (*RegisterWorkerResponse) ProtoMessage() {} func (x *RegisterWorkerResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[105] + mi := &file_ateapi_proto_msgTypes[106] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7809,7 +7866,7 @@ func (x *RegisterWorkerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterWorkerResponse.ProtoReflect.Descriptor instead. func (*RegisterWorkerResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{105} + return file_ateapi_proto_rawDescGZIP(), []int{106} } func (x *RegisterWorkerResponse) GetWorker() *Worker { @@ -7848,7 +7905,7 @@ type MintAteomActorCertificateRequest struct { func (x *MintAteomActorCertificateRequest) Reset() { *x = MintAteomActorCertificateRequest{} - mi := &file_ateapi_proto_msgTypes[106] + mi := &file_ateapi_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7860,7 +7917,7 @@ func (x *MintAteomActorCertificateRequest) String() string { func (*MintAteomActorCertificateRequest) ProtoMessage() {} func (x *MintAteomActorCertificateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[106] + mi := &file_ateapi_proto_msgTypes[107] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7873,7 +7930,7 @@ func (x *MintAteomActorCertificateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintAteomActorCertificateRequest.ProtoReflect.Descriptor instead. func (*MintAteomActorCertificateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{106} + return file_ateapi_proto_rawDescGZIP(), []int{107} } func (x *MintAteomActorCertificateRequest) GetActor() *ObjectRef { @@ -7910,7 +7967,7 @@ type MintAteomActorCertificateResponse struct { func (x *MintAteomActorCertificateResponse) Reset() { *x = MintAteomActorCertificateResponse{} - mi := &file_ateapi_proto_msgTypes[107] + mi := &file_ateapi_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7922,7 +7979,7 @@ func (x *MintAteomActorCertificateResponse) String() string { func (*MintAteomActorCertificateResponse) ProtoMessage() {} func (x *MintAteomActorCertificateResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[107] + mi := &file_ateapi_proto_msgTypes[108] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7935,7 +7992,7 @@ func (x *MintAteomActorCertificateResponse) ProtoReflect() protoreflect.Message // Deprecated: Use MintAteomActorCertificateResponse.ProtoReflect.Descriptor instead. func (*MintAteomActorCertificateResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{107} + return file_ateapi_proto_rawDescGZIP(), []int{108} } func (x *MintAteomActorCertificateResponse) GetActorCertificates() [][]byte { @@ -7973,7 +8030,7 @@ type RequestActorSuspendRequest struct { func (x *RequestActorSuspendRequest) Reset() { *x = RequestActorSuspendRequest{} - mi := &file_ateapi_proto_msgTypes[108] + mi := &file_ateapi_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7985,7 +8042,7 @@ func (x *RequestActorSuspendRequest) String() string { func (*RequestActorSuspendRequest) ProtoMessage() {} func (x *RequestActorSuspendRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[108] + mi := &file_ateapi_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7998,7 +8055,7 @@ func (x *RequestActorSuspendRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestActorSuspendRequest.ProtoReflect.Descriptor instead. func (*RequestActorSuspendRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{108} + return file_ateapi_proto_rawDescGZIP(), []int{109} } func (x *RequestActorSuspendRequest) GetWorker() *ObjectRef { @@ -8032,7 +8089,7 @@ type RequestActorSuspendResponse struct { func (x *RequestActorSuspendResponse) Reset() { *x = RequestActorSuspendResponse{} - mi := &file_ateapi_proto_msgTypes[109] + mi := &file_ateapi_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8044,7 +8101,7 @@ func (x *RequestActorSuspendResponse) String() string { func (*RequestActorSuspendResponse) ProtoMessage() {} func (x *RequestActorSuspendResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[109] + mi := &file_ateapi_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8057,7 +8114,7 @@ func (x *RequestActorSuspendResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestActorSuspendResponse.ProtoReflect.Descriptor instead. func (*RequestActorSuspendResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{109} + return file_ateapi_proto_rawDescGZIP(), []int{110} } func (x *RequestActorSuspendResponse) GetActor() *Actor { @@ -8092,7 +8149,7 @@ type AccessPolicy struct { func (x *AccessPolicy) Reset() { *x = AccessPolicy{} - mi := &file_ateapi_proto_msgTypes[110] + mi := &file_ateapi_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8104,7 +8161,7 @@ func (x *AccessPolicy) String() string { func (*AccessPolicy) ProtoMessage() {} func (x *AccessPolicy) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[110] + mi := &file_ateapi_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8117,7 +8174,7 @@ func (x *AccessPolicy) ProtoReflect() protoreflect.Message { // Deprecated: Use AccessPolicy.ProtoReflect.Descriptor instead. func (*AccessPolicy) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{110} + return file_ateapi_proto_rawDescGZIP(), []int{111} } func (x *AccessPolicy) GetMetadata() *ResourceMetadata { @@ -8159,7 +8216,7 @@ type Binding struct { func (x *Binding) Reset() { *x = Binding{} - mi := &file_ateapi_proto_msgTypes[111] + mi := &file_ateapi_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8171,7 +8228,7 @@ func (x *Binding) String() string { func (*Binding) ProtoMessage() {} func (x *Binding) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[111] + mi := &file_ateapi_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8184,7 +8241,7 @@ func (x *Binding) ProtoReflect() protoreflect.Message { // Deprecated: Use Binding.ProtoReflect.Descriptor instead. func (*Binding) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{111} + return file_ateapi_proto_rawDescGZIP(), []int{112} } func (x *Binding) GetRole() string { @@ -8216,7 +8273,7 @@ type GetGlobalAccessPolicyRequest struct { func (x *GetGlobalAccessPolicyRequest) Reset() { *x = GetGlobalAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[112] + mi := &file_ateapi_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8228,7 +8285,7 @@ func (x *GetGlobalAccessPolicyRequest) String() string { func (*GetGlobalAccessPolicyRequest) ProtoMessage() {} func (x *GetGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[112] + mi := &file_ateapi_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8241,7 +8298,7 @@ func (x *GetGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGlobalAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*GetGlobalAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{112} + return file_ateapi_proto_rawDescGZIP(), []int{113} } func (x *GetGlobalAccessPolicyRequest) GetName() string { @@ -8265,7 +8322,7 @@ type CreateGlobalAccessPolicyRequest struct { func (x *CreateGlobalAccessPolicyRequest) Reset() { *x = CreateGlobalAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[113] + mi := &file_ateapi_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8277,7 +8334,7 @@ func (x *CreateGlobalAccessPolicyRequest) String() string { func (*CreateGlobalAccessPolicyRequest) ProtoMessage() {} func (x *CreateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[113] + mi := &file_ateapi_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8290,7 +8347,7 @@ func (x *CreateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateGlobalAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*CreateGlobalAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{113} + return file_ateapi_proto_rawDescGZIP(), []int{114} } func (x *CreateGlobalAccessPolicyRequest) GetAccessPolicy() *AccessPolicy { @@ -8314,7 +8371,7 @@ type UpdateGlobalAccessPolicyRequest struct { func (x *UpdateGlobalAccessPolicyRequest) Reset() { *x = UpdateGlobalAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[114] + mi := &file_ateapi_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8326,7 +8383,7 @@ func (x *UpdateGlobalAccessPolicyRequest) String() string { func (*UpdateGlobalAccessPolicyRequest) ProtoMessage() {} func (x *UpdateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[114] + mi := &file_ateapi_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8339,7 +8396,7 @@ func (x *UpdateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateGlobalAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*UpdateGlobalAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{114} + return file_ateapi_proto_rawDescGZIP(), []int{115} } func (x *UpdateGlobalAccessPolicyRequest) GetAccessPolicy() *AccessPolicy { @@ -8369,7 +8426,7 @@ type GetAtespaceAccessPolicyRequest struct { func (x *GetAtespaceAccessPolicyRequest) Reset() { *x = GetAtespaceAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[115] + mi := &file_ateapi_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8381,7 +8438,7 @@ func (x *GetAtespaceAccessPolicyRequest) String() string { func (*GetAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *GetAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[115] + mi := &file_ateapi_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8394,7 +8451,7 @@ func (x *GetAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*GetAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{115} + return file_ateapi_proto_rawDescGZIP(), []int{116} } func (x *GetAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -8430,7 +8487,7 @@ type CreateAtespaceAccessPolicyRequest struct { func (x *CreateAtespaceAccessPolicyRequest) Reset() { *x = CreateAtespaceAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[116] + mi := &file_ateapi_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8442,7 +8499,7 @@ func (x *CreateAtespaceAccessPolicyRequest) String() string { func (*CreateAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *CreateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[116] + mi := &file_ateapi_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8455,7 +8512,7 @@ func (x *CreateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message // Deprecated: Use CreateAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*CreateAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{116} + return file_ateapi_proto_rawDescGZIP(), []int{117} } func (x *CreateAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -8491,7 +8548,7 @@ type UpdateAtespaceAccessPolicyRequest struct { func (x *UpdateAtespaceAccessPolicyRequest) Reset() { *x = UpdateAtespaceAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[117] + mi := &file_ateapi_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8503,7 +8560,7 @@ func (x *UpdateAtespaceAccessPolicyRequest) String() string { func (*UpdateAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *UpdateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[117] + mi := &file_ateapi_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8516,7 +8573,7 @@ func (x *UpdateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message // Deprecated: Use UpdateAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*UpdateAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{117} + return file_ateapi_proto_rawDescGZIP(), []int{118} } func (x *UpdateAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -8557,7 +8614,7 @@ type DeleteAtespaceAccessPolicyRequest struct { func (x *DeleteAtespaceAccessPolicyRequest) Reset() { *x = DeleteAtespaceAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[118] + mi := &file_ateapi_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8569,7 +8626,7 @@ func (x *DeleteAtespaceAccessPolicyRequest) String() string { func (*DeleteAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *DeleteAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[118] + mi := &file_ateapi_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8582,7 +8639,7 @@ func (x *DeleteAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message // Deprecated: Use DeleteAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*DeleteAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{118} + return file_ateapi_proto_rawDescGZIP(), []int{119} } func (x *DeleteAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -8639,14 +8696,14 @@ const file_ateapi_proto_rawDesc = "" + "\vcreate_time\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampR\n" + "createTime\x12;\n" + "\vupdate_time\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\n" + - "updateTime\"\x9b\x03\n" + - "\x0eExternalVolume\x12\x12\n" + + "updateTime\"\xa4\x03\n" + + "\x11ExternalVolumeRef\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12*\n" + "\x11storage_volume_id\x18\x02 \x01(\tR\x0fstorageVolumeId\x12\x1f\n" + "\vvolume_type\x18\x03 \x01(\tR\n" + - "volumeType\x125\n" + - "\x06status\x18\x04 \x01(\x0e2\x1d.ateapi.ExternalVolume.StatusR\x06status\x12P\n" + - "\x0evolume_context\x18\x05 \x03(\v2).ateapi.ExternalVolume.VolumeContextEntryR\rvolumeContext\x1a@\n" + + "volumeType\x128\n" + + "\x06status\x18\x04 \x01(\x0e2 .ateapi.ExternalVolumeRef.StatusR\x06status\x12S\n" + + "\x0evolume_context\x18\x05 \x03(\v2,.ateapi.ExternalVolumeRef.VolumeContextEntryR\rvolumeContext\x1a@\n" + "\x12VolumeContextEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"]\n" + @@ -8695,11 +8752,11 @@ const file_ateapi_proto_rawDesc = "" + "\tactor_jwt\x18\x04 \x01(\v2\x16.ateapi.ActorJwtSourceR\bactorJwt\"]\n" + "\x0eActorJwtSource\x12\x1c\n" + "\taudiences\x18\x01 \x03(\tR\taudiences\x12-\n" + - "\x12expiration_seconds\x18\x02 \x01(\x03R\x11expirationSeconds\"\xfa\x02\n" + + "\x12expiration_seconds\x18\x02 \x01(\x03R\x11expirationSeconds\"\xfd\x02\n" + "\vActorStatus\x12(\n" + "\x05state\x18\x01 \x01(\x0e2\x12.ateapi.ActorStateR\x05state\x12E\n" + - "\x11worker_assignment\x18\x02 \x01(\v2\x18.ateapi.WorkerAssignmentR\x10workerAssignment\x12A\n" + - "\x10external_volumes\x18\a \x03(\v2\x16.ateapi.ExternalVolumeR\x0fexternalVolumes\x12(\n" + + "\x11worker_assignment\x18\x02 \x01(\v2\x18.ateapi.WorkerAssignmentR\x10workerAssignment\x12D\n" + + "\x10external_volumes\x18\a \x03(\v2\x19.ateapi.ExternalVolumeRefR\x0fexternalVolumes\x12(\n" + "\x05crash\x18\t \x01(\v2\x12.ateapi.ActorCrashR\x05crash\x12#\n" + "\rassigned_node\x18\n" + " \x01(\tR\fassignedNode\x12.\n" + @@ -8790,15 +8847,17 @@ 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\"\x89\x02\n" + "\x06Volume\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12?\n" + "\vdurable_dir\x18\x02 \x01(\v2\x1e.ateapi.DurableDirVolumeSourceR\n" + - "durableDir\x12X\n" + - "\x18external_volume_template\x18\x03 \x01(\v2\x1e.ateapi.ExternalVolumeTemplateR\x16externalVolumeTemplate\x12?\n" + + "durableDir\x128\n" + + "\bexternal\x18\a \x01(\v2\x1c.ateapi.ExternalVolumeSourceR\bexternal\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\"R\n" + + "\x14ExternalVolumeSource\x12:\n" + + "\btemplate\x18\x01 \x01(\v2\x1e.ateapi.ExternalVolumeTemplateR\btemplate\"1\n" + "\x11ImageVolumeSource\x12\x1c\n" + "\treference\x18\x01 \x01(\tR\treference\"\x18\n" + "\x16DurableDirVolumeSource\"b\n" + @@ -9158,7 +9217,7 @@ func file_ateapi_proto_rawDescGZIP() []byte { } var file_ateapi_proto_enumTypes = make([]protoimpl.EnumInfo, 10) -var file_ateapi_proto_msgTypes = make([]protoimpl.MessageInfo, 122) +var file_ateapi_proto_msgTypes = make([]protoimpl.MessageInfo, 123) var file_ateapi_proto_goTypes = []any{ (SnapshotOwner)(0), // 0: ateapi.SnapshotOwner (SnapshotStorageStatus)(0), // 1: ateapi.SnapshotStorageStatus @@ -9169,13 +9228,13 @@ var file_ateapi_proto_goTypes = []any{ (GoldenSnapshotMode)(0), // 6: ateapi.GoldenSnapshotMode (ActorMetadataField)(0), // 7: ateapi.ActorMetadataField (WorkerState)(0), // 8: ateapi.WorkerState - (ExternalVolume_Status)(0), // 9: ateapi.ExternalVolume.Status + (ExternalVolumeRef_Status)(0), // 9: ateapi.ExternalVolumeRef.Status (*ObjectSnapshot)(nil), // 10: ateapi.ObjectSnapshot (*SnapshotStorage)(nil), // 11: ateapi.SnapshotStorage (*Snapshot)(nil), // 12: ateapi.Snapshot (*Selector)(nil), // 13: ateapi.Selector (*ResourceMetadata)(nil), // 14: ateapi.ResourceMetadata - (*ExternalVolume)(nil), // 15: ateapi.ExternalVolume + (*ExternalVolumeRef)(nil), // 15: ateapi.ExternalVolumeRef (*Actor)(nil), // 16: ateapi.Actor (*EgressPolicy)(nil), // 17: ateapi.EgressPolicy (*EgressRule)(nil), // 18: ateapi.EgressRule @@ -9209,90 +9268,91 @@ var file_ateapi_proto_goTypes = []any{ (*ContainerWakeupProbe)(nil), // 46: ateapi.ContainerWakeupProbe (*HttpGetAction)(nil), // 47: ateapi.HttpGetAction (*Volume)(nil), // 48: ateapi.Volume - (*ImageVolumeSource)(nil), // 49: ateapi.ImageVolumeSource - (*DurableDirVolumeSource)(nil), // 50: ateapi.DurableDirVolumeSource - (*ExternalVolumeTemplate)(nil), // 51: ateapi.ExternalVolumeTemplate - (*SystemInfoVolumeSource)(nil), // 52: ateapi.SystemInfoVolumeSource - (*SystemInfoDataSource)(nil), // 53: ateapi.SystemInfoDataSource - (*ActorMetadataDataSource)(nil), // 54: ateapi.ActorMetadataDataSource - (*ActorMetadataItem)(nil), // 55: ateapi.ActorMetadataItem - (*TrustBundleDataSource)(nil), // 56: ateapi.TrustBundleDataSource - (*VolumeMount)(nil), // 57: ateapi.VolumeMount - (*CreateAtespaceRequest)(nil), // 58: ateapi.CreateAtespaceRequest - (*GetAtespaceRequest)(nil), // 59: ateapi.GetAtespaceRequest - (*ListAtespacesRequest)(nil), // 60: ateapi.ListAtespacesRequest - (*ListAtespacesResponse)(nil), // 61: ateapi.ListAtespacesResponse - (*DeleteAtespaceRequest)(nil), // 62: ateapi.DeleteAtespaceRequest - (*CreateActorTemplateRequest)(nil), // 63: ateapi.CreateActorTemplateRequest - (*GetActorTemplateRequest)(nil), // 64: ateapi.GetActorTemplateRequest - (*ListActorTemplatesRequest)(nil), // 65: ateapi.ListActorTemplatesRequest - (*ListActorTemplatesResponse)(nil), // 66: ateapi.ListActorTemplatesResponse - (*DeleteActorTemplateRequest)(nil), // 67: ateapi.DeleteActorTemplateRequest - (*GetActorRequest)(nil), // 68: ateapi.GetActorRequest - (*CreateActorRequest)(nil), // 69: ateapi.CreateActorRequest - (*UpdateActorRequest)(nil), // 70: ateapi.UpdateActorRequest - (*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 - (*GetTagRequest)(nil), // 84: ateapi.GetTagRequest - (*MintActorJwtRequest)(nil), // 85: ateapi.MintActorJwtRequest - (*MintActorJwtResponse)(nil), // 86: ateapi.MintActorJwtResponse - (*MintActorCertificateRequest)(nil), // 87: ateapi.MintActorCertificateRequest - (*MintActorCertificateResponse)(nil), // 88: ateapi.MintActorCertificateResponse - (*ListTagsRequest)(nil), // 89: ateapi.ListTagsRequest - (*ListTagsResponse)(nil), // 90: ateapi.ListTagsResponse - (*CreateTagRequest)(nil), // 91: ateapi.CreateTagRequest - (*UpdateTagRequest)(nil), // 92: ateapi.UpdateTagRequest - (*DeleteTagRequest)(nil), // 93: ateapi.DeleteTagRequest - (*DeleteOptions)(nil), // 94: ateapi.DeleteOptions - (*ListWorkerActorAssignmentsRequest)(nil), // 95: ateapi.ListWorkerActorAssignmentsRequest - (*ListWorkerActorAssignmentsResponse)(nil), // 96: ateapi.ListWorkerActorAssignmentsResponse - (*ListWorkersRequest)(nil), // 97: ateapi.ListWorkersRequest - (*ListWorkersResponse)(nil), // 98: ateapi.ListWorkersResponse - (*GetWorkerRequest)(nil), // 99: ateapi.GetWorkerRequest - (*CreateWorkerRequest)(nil), // 100: ateapi.CreateWorkerRequest - (*UpdateWorkerRequest)(nil), // 101: ateapi.UpdateWorkerRequest - (*DeleteWorkerRequest)(nil), // 102: ateapi.DeleteWorkerRequest - (*DrainWorkerRequest)(nil), // 103: ateapi.DrainWorkerRequest - (*DrainWorkerResponse)(nil), // 104: ateapi.DrainWorkerResponse - (*ListActorsRequest)(nil), // 105: ateapi.ListActorsRequest - (*ListActorsResponse)(nil), // 106: ateapi.ListActorsResponse - (*Worker)(nil), // 107: ateapi.Worker - (*WorkerStatus)(nil), // 108: ateapi.WorkerStatus - (*SandboxRuntime)(nil), // 109: ateapi.SandboxRuntime - (*VersionedSandboxCompat)(nil), // 110: ateapi.VersionedSandboxCompat - (*AttributeEntry)(nil), // 111: ateapi.AttributeEntry - (*WorkerResources)(nil), // 112: ateapi.WorkerResources - (*ActorAssignment)(nil), // 113: ateapi.ActorAssignment - (*RegisterWorkerRequest)(nil), // 114: ateapi.RegisterWorkerRequest - (*RegisterWorkerResponse)(nil), // 115: ateapi.RegisterWorkerResponse - (*MintAteomActorCertificateRequest)(nil), // 116: ateapi.MintAteomActorCertificateRequest - (*MintAteomActorCertificateResponse)(nil), // 117: ateapi.MintAteomActorCertificateResponse - (*RequestActorSuspendRequest)(nil), // 118: ateapi.RequestActorSuspendRequest - (*RequestActorSuspendResponse)(nil), // 119: ateapi.RequestActorSuspendResponse - (*AccessPolicy)(nil), // 120: ateapi.AccessPolicy - (*Binding)(nil), // 121: ateapi.Binding - (*GetGlobalAccessPolicyRequest)(nil), // 122: ateapi.GetGlobalAccessPolicyRequest - (*CreateGlobalAccessPolicyRequest)(nil), // 123: ateapi.CreateGlobalAccessPolicyRequest - (*UpdateGlobalAccessPolicyRequest)(nil), // 124: ateapi.UpdateGlobalAccessPolicyRequest - (*GetAtespaceAccessPolicyRequest)(nil), // 125: ateapi.GetAtespaceAccessPolicyRequest - (*CreateAtespaceAccessPolicyRequest)(nil), // 126: ateapi.CreateAtespaceAccessPolicyRequest - (*UpdateAtespaceAccessPolicyRequest)(nil), // 127: ateapi.UpdateAtespaceAccessPolicyRequest - (*DeleteAtespaceAccessPolicyRequest)(nil), // 128: ateapi.DeleteAtespaceAccessPolicyRequest - nil, // 129: ateapi.Selector.MatchLabelsEntry - nil, // 130: ateapi.ExternalVolume.VolumeContextEntry - nil, // 131: ateapi.Worker.LabelsEntry - (*timestamppb.Timestamp)(nil), // 132: google.protobuf.Timestamp + (*ExternalVolumeSource)(nil), // 49: ateapi.ExternalVolumeSource + (*ImageVolumeSource)(nil), // 50: ateapi.ImageVolumeSource + (*DurableDirVolumeSource)(nil), // 51: ateapi.DurableDirVolumeSource + (*ExternalVolumeTemplate)(nil), // 52: ateapi.ExternalVolumeTemplate + (*SystemInfoVolumeSource)(nil), // 53: ateapi.SystemInfoVolumeSource + (*SystemInfoDataSource)(nil), // 54: ateapi.SystemInfoDataSource + (*ActorMetadataDataSource)(nil), // 55: ateapi.ActorMetadataDataSource + (*ActorMetadataItem)(nil), // 56: ateapi.ActorMetadataItem + (*TrustBundleDataSource)(nil), // 57: ateapi.TrustBundleDataSource + (*VolumeMount)(nil), // 58: ateapi.VolumeMount + (*CreateAtespaceRequest)(nil), // 59: ateapi.CreateAtespaceRequest + (*GetAtespaceRequest)(nil), // 60: ateapi.GetAtespaceRequest + (*ListAtespacesRequest)(nil), // 61: ateapi.ListAtespacesRequest + (*ListAtespacesResponse)(nil), // 62: ateapi.ListAtespacesResponse + (*DeleteAtespaceRequest)(nil), // 63: ateapi.DeleteAtespaceRequest + (*CreateActorTemplateRequest)(nil), // 64: ateapi.CreateActorTemplateRequest + (*GetActorTemplateRequest)(nil), // 65: ateapi.GetActorTemplateRequest + (*ListActorTemplatesRequest)(nil), // 66: ateapi.ListActorTemplatesRequest + (*ListActorTemplatesResponse)(nil), // 67: ateapi.ListActorTemplatesResponse + (*DeleteActorTemplateRequest)(nil), // 68: ateapi.DeleteActorTemplateRequest + (*GetActorRequest)(nil), // 69: ateapi.GetActorRequest + (*CreateActorRequest)(nil), // 70: ateapi.CreateActorRequest + (*UpdateActorRequest)(nil), // 71: ateapi.UpdateActorRequest + (*SuspendActorRequest)(nil), // 72: ateapi.SuspendActorRequest + (*SuspendActorResponse)(nil), // 73: ateapi.SuspendActorResponse + (*PauseActorRequest)(nil), // 74: ateapi.PauseActorRequest + (*PauseActorResponse)(nil), // 75: ateapi.PauseActorResponse + (*ResumeActorRequest)(nil), // 76: ateapi.ResumeActorRequest + (*ResumeActorResponse)(nil), // 77: ateapi.ResumeActorResponse + (*RevertActorRequest)(nil), // 78: ateapi.RevertActorRequest + (*RevertActorResponse)(nil), // 79: ateapi.RevertActorResponse + (*DeleteActorRequest)(nil), // 80: ateapi.DeleteActorRequest + (*GetActorEgressPolicyRequest)(nil), // 81: ateapi.GetActorEgressPolicyRequest + (*CreateActorEgressPolicyRequest)(nil), // 82: ateapi.CreateActorEgressPolicyRequest + (*UpdateActorEgressPolicyRequest)(nil), // 83: ateapi.UpdateActorEgressPolicyRequest + (*DeleteActorEgressPolicyRequest)(nil), // 84: ateapi.DeleteActorEgressPolicyRequest + (*GetTagRequest)(nil), // 85: ateapi.GetTagRequest + (*MintActorJwtRequest)(nil), // 86: ateapi.MintActorJwtRequest + (*MintActorJwtResponse)(nil), // 87: ateapi.MintActorJwtResponse + (*MintActorCertificateRequest)(nil), // 88: ateapi.MintActorCertificateRequest + (*MintActorCertificateResponse)(nil), // 89: ateapi.MintActorCertificateResponse + (*ListTagsRequest)(nil), // 90: ateapi.ListTagsRequest + (*ListTagsResponse)(nil), // 91: ateapi.ListTagsResponse + (*CreateTagRequest)(nil), // 92: ateapi.CreateTagRequest + (*UpdateTagRequest)(nil), // 93: ateapi.UpdateTagRequest + (*DeleteTagRequest)(nil), // 94: ateapi.DeleteTagRequest + (*DeleteOptions)(nil), // 95: ateapi.DeleteOptions + (*ListWorkerActorAssignmentsRequest)(nil), // 96: ateapi.ListWorkerActorAssignmentsRequest + (*ListWorkerActorAssignmentsResponse)(nil), // 97: ateapi.ListWorkerActorAssignmentsResponse + (*ListWorkersRequest)(nil), // 98: ateapi.ListWorkersRequest + (*ListWorkersResponse)(nil), // 99: ateapi.ListWorkersResponse + (*GetWorkerRequest)(nil), // 100: ateapi.GetWorkerRequest + (*CreateWorkerRequest)(nil), // 101: ateapi.CreateWorkerRequest + (*UpdateWorkerRequest)(nil), // 102: ateapi.UpdateWorkerRequest + (*DeleteWorkerRequest)(nil), // 103: ateapi.DeleteWorkerRequest + (*DrainWorkerRequest)(nil), // 104: ateapi.DrainWorkerRequest + (*DrainWorkerResponse)(nil), // 105: ateapi.DrainWorkerResponse + (*ListActorsRequest)(nil), // 106: ateapi.ListActorsRequest + (*ListActorsResponse)(nil), // 107: ateapi.ListActorsResponse + (*Worker)(nil), // 108: ateapi.Worker + (*WorkerStatus)(nil), // 109: ateapi.WorkerStatus + (*SandboxRuntime)(nil), // 110: ateapi.SandboxRuntime + (*VersionedSandboxCompat)(nil), // 111: ateapi.VersionedSandboxCompat + (*AttributeEntry)(nil), // 112: ateapi.AttributeEntry + (*WorkerResources)(nil), // 113: ateapi.WorkerResources + (*ActorAssignment)(nil), // 114: ateapi.ActorAssignment + (*RegisterWorkerRequest)(nil), // 115: ateapi.RegisterWorkerRequest + (*RegisterWorkerResponse)(nil), // 116: ateapi.RegisterWorkerResponse + (*MintAteomActorCertificateRequest)(nil), // 117: ateapi.MintAteomActorCertificateRequest + (*MintAteomActorCertificateResponse)(nil), // 118: ateapi.MintAteomActorCertificateResponse + (*RequestActorSuspendRequest)(nil), // 119: ateapi.RequestActorSuspendRequest + (*RequestActorSuspendResponse)(nil), // 120: ateapi.RequestActorSuspendResponse + (*AccessPolicy)(nil), // 121: ateapi.AccessPolicy + (*Binding)(nil), // 122: ateapi.Binding + (*GetGlobalAccessPolicyRequest)(nil), // 123: ateapi.GetGlobalAccessPolicyRequest + (*CreateGlobalAccessPolicyRequest)(nil), // 124: ateapi.CreateGlobalAccessPolicyRequest + (*UpdateGlobalAccessPolicyRequest)(nil), // 125: ateapi.UpdateGlobalAccessPolicyRequest + (*GetAtespaceAccessPolicyRequest)(nil), // 126: ateapi.GetAtespaceAccessPolicyRequest + (*CreateAtespaceAccessPolicyRequest)(nil), // 127: ateapi.CreateAtespaceAccessPolicyRequest + (*UpdateAtespaceAccessPolicyRequest)(nil), // 128: ateapi.UpdateAtespaceAccessPolicyRequest + (*DeleteAtespaceAccessPolicyRequest)(nil), // 129: ateapi.DeleteAtespaceAccessPolicyRequest + nil, // 130: ateapi.Selector.MatchLabelsEntry + nil, // 131: ateapi.ExternalVolumeRef.VolumeContextEntry + nil, // 132: ateapi.Worker.LabelsEntry + (*timestamppb.Timestamp)(nil), // 133: google.protobuf.Timestamp } var file_ateapi_proto_depIdxs = []int32{ 1, // 0: ateapi.SnapshotStorage.status:type_name -> ateapi.SnapshotStorageStatus @@ -9300,11 +9360,11 @@ var file_ateapi_proto_depIdxs = []int32{ 0, // 2: ateapi.Snapshot.owner:type_name -> ateapi.SnapshotOwner 2, // 3: ateapi.Snapshot.fidelity:type_name -> ateapi.SnapshotFidelity 11, // 4: ateapi.Snapshot.durable_snapshot:type_name -> ateapi.SnapshotStorage - 129, // 5: ateapi.Selector.match_labels:type_name -> ateapi.Selector.MatchLabelsEntry - 132, // 6: ateapi.ResourceMetadata.create_time:type_name -> google.protobuf.Timestamp - 132, // 7: ateapi.ResourceMetadata.update_time:type_name -> google.protobuf.Timestamp - 9, // 8: ateapi.ExternalVolume.status:type_name -> ateapi.ExternalVolume.Status - 130, // 9: ateapi.ExternalVolume.volume_context:type_name -> ateapi.ExternalVolume.VolumeContextEntry + 130, // 5: ateapi.Selector.match_labels:type_name -> ateapi.Selector.MatchLabelsEntry + 133, // 6: ateapi.ResourceMetadata.create_time:type_name -> google.protobuf.Timestamp + 133, // 7: ateapi.ResourceMetadata.update_time:type_name -> google.protobuf.Timestamp + 9, // 8: ateapi.ExternalVolumeRef.status:type_name -> ateapi.ExternalVolumeRef.Status + 131, // 9: ateapi.ExternalVolumeRef.volume_context:type_name -> ateapi.ExternalVolumeRef.VolumeContextEntry 14, // 10: ateapi.Actor.metadata:type_name -> ateapi.ResourceMetadata 33, // 11: ateapi.Actor.actor_template:type_name -> ateapi.ObjectRef 13, // 12: ateapi.Actor.worker_selector:type_name -> ateapi.Selector @@ -9325,10 +9385,10 @@ var file_ateapi_proto_depIdxs = []int32{ 26, // 27: ateapi.CredentialHeader.actor_jwt:type_name -> ateapi.ActorJwtSource 4, // 28: ateapi.ActorStatus.state:type_name -> ateapi.ActorState 29, // 29: ateapi.ActorStatus.worker_assignment:type_name -> ateapi.WorkerAssignment - 15, // 30: ateapi.ActorStatus.external_volumes:type_name -> ateapi.ExternalVolume + 15, // 30: ateapi.ActorStatus.external_volumes:type_name -> ateapi.ExternalVolumeRef 28, // 31: ateapi.ActorStatus.crash:type_name -> ateapi.ActorCrash 12, // 32: ateapi.ActorStatus.snapshots:type_name -> ateapi.Snapshot - 132, // 33: ateapi.ActorCrash.crash_time:type_name -> google.protobuf.Timestamp + 133, // 33: ateapi.ActorCrash.crash_time:type_name -> google.protobuf.Timestamp 33, // 34: ateapi.WorkerAssignment.worker:type_name -> ateapi.ObjectRef 12, // 35: ateapi.TagStatus.snapshot:type_name -> ateapi.Snapshot 14, // 36: ateapi.Tag.metadata:type_name -> ateapi.ResourceMetadata @@ -9346,7 +9406,7 @@ var file_ateapi_proto_depIdxs = []int32{ 38, // 48: ateapi.ActorTemplate.status:type_name -> ateapi.ActorTemplateStatus 36, // 49: ateapi.Resources.limits:type_name -> ateapi.Limits 33, // 50: ateapi.GoldenSnapshotStatus.golden_tag:type_name -> ateapi.ObjectRef - 132, // 51: ateapi.GoldenSnapshotStatus.take_golden_snapshot_at:type_name -> google.protobuf.Timestamp + 133, // 51: ateapi.GoldenSnapshotStatus.take_golden_snapshot_at:type_name -> google.protobuf.Timestamp 37, // 52: ateapi.ActorTemplateStatus.golden_snapshot_status:type_name -> ateapi.GoldenSnapshotStatus 5, // 53: ateapi.SandboxConfig.sandbox_class:type_name -> ateapi.SandboxClass 2, // 54: ateapi.SnapshotConfig.preferred_fidelity:type_name -> ateapi.SnapshotFidelity @@ -9354,199 +9414,200 @@ var file_ateapi_proto_depIdxs = []int32{ 6, // 56: ateapi.GoldenSnapshotConfig.mode:type_name -> ateapi.GoldenSnapshotMode 45, // 57: ateapi.Container.env:type_name -> ateapi.EnvVar 46, // 58: ateapi.Container.wakeup_probe:type_name -> ateapi.ContainerWakeupProbe - 57, // 59: ateapi.Container.volume_mounts:type_name -> ateapi.VolumeMount + 58, // 59: ateapi.Container.volume_mounts:type_name -> ateapi.VolumeMount 43, // 60: ateapi.Container.security_context:type_name -> ateapi.SecurityContext 35, // 61: ateapi.Container.resources:type_name -> ateapi.Resources 44, // 62: ateapi.SecurityContext.capabilities:type_name -> ateapi.Capabilities 47, // 63: ateapi.ContainerWakeupProbe.http_get:type_name -> ateapi.HttpGetAction - 50, // 64: ateapi.Volume.durable_dir:type_name -> ateapi.DurableDirVolumeSource - 51, // 65: ateapi.Volume.external_volume_template:type_name -> ateapi.ExternalVolumeTemplate - 52, // 66: ateapi.Volume.system_info:type_name -> ateapi.SystemInfoVolumeSource - 49, // 67: ateapi.Volume.image:type_name -> ateapi.ImageVolumeSource - 53, // 68: ateapi.SystemInfoVolumeSource.data_sources:type_name -> ateapi.SystemInfoDataSource - 54, // 69: ateapi.SystemInfoDataSource.actor_metadata:type_name -> ateapi.ActorMetadataDataSource - 56, // 70: ateapi.SystemInfoDataSource.trust_bundle:type_name -> ateapi.TrustBundleDataSource - 55, // 71: ateapi.ActorMetadataDataSource.items:type_name -> ateapi.ActorMetadataItem - 7, // 72: ateapi.ActorMetadataItem.field:type_name -> ateapi.ActorMetadataField - 32, // 73: ateapi.CreateAtespaceRequest.atespace:type_name -> ateapi.Atespace - 33, // 74: ateapi.GetAtespaceRequest.atespace:type_name -> ateapi.ObjectRef - 32, // 75: ateapi.ListAtespacesResponse.atespaces:type_name -> ateapi.Atespace - 33, // 76: ateapi.DeleteAtespaceRequest.atespace:type_name -> ateapi.ObjectRef - 94, // 77: ateapi.DeleteAtespaceRequest.options:type_name -> ateapi.DeleteOptions - 34, // 78: ateapi.CreateActorTemplateRequest.actor_template:type_name -> ateapi.ActorTemplate - 33, // 79: ateapi.GetActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef - 34, // 80: ateapi.ListActorTemplatesResponse.actor_templates:type_name -> ateapi.ActorTemplate - 33, // 81: ateapi.DeleteActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef - 94, // 82: ateapi.DeleteActorTemplateRequest.options:type_name -> ateapi.DeleteOptions - 33, // 83: ateapi.GetActorRequest.actor:type_name -> ateapi.ObjectRef - 16, // 84: ateapi.CreateActorRequest.actor:type_name -> ateapi.Actor - 16, // 85: ateapi.UpdateActorRequest.actor:type_name -> ateapi.Actor - 33, // 86: ateapi.SuspendActorRequest.actor:type_name -> ateapi.ObjectRef - 16, // 87: ateapi.SuspendActorResponse.actor:type_name -> ateapi.Actor - 33, // 88: ateapi.PauseActorRequest.actor:type_name -> ateapi.ObjectRef - 16, // 89: ateapi.PauseActorResponse.actor:type_name -> ateapi.Actor - 33, // 90: ateapi.ResumeActorRequest.actor:type_name -> ateapi.ObjectRef - 16, // 91: ateapi.ResumeActorResponse.actor:type_name -> ateapi.Actor - 33, // 92: ateapi.RevertActorRequest.actor:type_name -> ateapi.ObjectRef - 16, // 93: ateapi.RevertActorResponse.actor:type_name -> ateapi.Actor - 33, // 94: ateapi.DeleteActorRequest.actor:type_name -> ateapi.ObjectRef - 94, // 95: ateapi.DeleteActorRequest.options:type_name -> ateapi.DeleteOptions - 33, // 96: ateapi.GetActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 33, // 97: ateapi.CreateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 17, // 98: ateapi.CreateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy - 33, // 99: ateapi.UpdateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 17, // 100: ateapi.UpdateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy - 33, // 101: ateapi.DeleteActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 94, // 102: ateapi.DeleteActorEgressPolicyRequest.options:type_name -> ateapi.DeleteOptions - 33, // 103: ateapi.GetTagRequest.tag:type_name -> ateapi.ObjectRef - 33, // 104: ateapi.MintActorJwtRequest.actor:type_name -> ateapi.ObjectRef - 132, // 105: ateapi.MintActorJwtResponse.expires_at:type_name -> google.protobuf.Timestamp - 33, // 106: ateapi.MintActorCertificateRequest.actor:type_name -> ateapi.ObjectRef - 31, // 107: ateapi.ListTagsResponse.tags:type_name -> ateapi.Tag - 31, // 108: ateapi.CreateTagRequest.tag:type_name -> ateapi.Tag - 31, // 109: ateapi.UpdateTagRequest.tag:type_name -> ateapi.Tag - 33, // 110: ateapi.DeleteTagRequest.tag:type_name -> ateapi.ObjectRef - 94, // 111: ateapi.DeleteTagRequest.options:type_name -> ateapi.DeleteOptions - 33, // 112: ateapi.ListWorkerActorAssignmentsRequest.worker:type_name -> ateapi.ObjectRef - 113, // 113: ateapi.ListWorkerActorAssignmentsResponse.actor_assignments:type_name -> ateapi.ActorAssignment - 107, // 114: ateapi.ListWorkersResponse.workers:type_name -> ateapi.Worker - 33, // 115: ateapi.GetWorkerRequest.worker:type_name -> ateapi.ObjectRef - 107, // 116: ateapi.CreateWorkerRequest.worker:type_name -> ateapi.Worker - 107, // 117: ateapi.UpdateWorkerRequest.worker:type_name -> ateapi.Worker - 33, // 118: ateapi.DeleteWorkerRequest.worker:type_name -> ateapi.ObjectRef - 94, // 119: ateapi.DeleteWorkerRequest.options:type_name -> ateapi.DeleteOptions - 33, // 120: ateapi.DrainWorkerRequest.worker:type_name -> ateapi.ObjectRef - 107, // 121: ateapi.DrainWorkerResponse.worker:type_name -> ateapi.Worker - 16, // 122: ateapi.ListActorsResponse.actors:type_name -> ateapi.Actor - 14, // 123: ateapi.Worker.metadata:type_name -> ateapi.ResourceMetadata - 131, // 124: ateapi.Worker.labels:type_name -> ateapi.Worker.LabelsEntry - 108, // 125: ateapi.Worker.status:type_name -> ateapi.WorkerStatus - 8, // 126: ateapi.WorkerStatus.state:type_name -> ateapi.WorkerState - 112, // 127: ateapi.WorkerStatus.capacity:type_name -> ateapi.WorkerResources - 112, // 128: ateapi.WorkerStatus.allocated:type_name -> ateapi.WorkerResources - 109, // 129: ateapi.WorkerStatus.default_runtime:type_name -> ateapi.SandboxRuntime - 109, // 130: ateapi.WorkerStatus.restorable_runtimes:type_name -> ateapi.SandboxRuntime - 110, // 131: ateapi.SandboxRuntime.version:type_name -> ateapi.VersionedSandboxCompat - 111, // 132: ateapi.VersionedSandboxCompat.attributes:type_name -> ateapi.AttributeEntry - 35, // 133: ateapi.WorkerResources.resources:type_name -> ateapi.Resources - 14, // 134: ateapi.ActorAssignment.metadata:type_name -> ateapi.ResourceMetadata - 33, // 135: ateapi.ActorAssignment.actor:type_name -> ateapi.ObjectRef - 35, // 136: ateapi.ActorAssignment.resources:type_name -> ateapi.Resources - 33, // 137: ateapi.RegisterWorkerRequest.worker:type_name -> ateapi.ObjectRef - 112, // 138: ateapi.RegisterWorkerRequest.capacity:type_name -> ateapi.WorkerResources - 109, // 139: ateapi.RegisterWorkerRequest.default_runtime:type_name -> ateapi.SandboxRuntime - 109, // 140: ateapi.RegisterWorkerRequest.restorable_runtimes:type_name -> ateapi.SandboxRuntime - 107, // 141: ateapi.RegisterWorkerResponse.worker:type_name -> ateapi.Worker - 33, // 142: ateapi.MintAteomActorCertificateRequest.actor:type_name -> ateapi.ObjectRef - 33, // 143: ateapi.RequestActorSuspendRequest.worker:type_name -> ateapi.ObjectRef - 33, // 144: ateapi.RequestActorSuspendRequest.actor:type_name -> ateapi.ObjectRef - 16, // 145: ateapi.RequestActorSuspendResponse.actor:type_name -> ateapi.Actor - 14, // 146: ateapi.AccessPolicy.metadata:type_name -> ateapi.ResourceMetadata - 121, // 147: ateapi.AccessPolicy.bindings:type_name -> ateapi.Binding - 120, // 148: ateapi.CreateGlobalAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy - 120, // 149: ateapi.UpdateGlobalAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy - 33, // 150: ateapi.GetAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef - 33, // 151: ateapi.CreateAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef - 120, // 152: ateapi.CreateAtespaceAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy - 33, // 153: ateapi.UpdateAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef - 120, // 154: ateapi.UpdateAtespaceAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy - 33, // 155: ateapi.DeleteAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef - 94, // 156: ateapi.DeleteAtespaceAccessPolicyRequest.options:type_name -> ateapi.DeleteOptions - 68, // 157: ateapi.Control.GetActor:input_type -> ateapi.GetActorRequest - 69, // 158: ateapi.Control.CreateActor:input_type -> ateapi.CreateActorRequest - 70, // 159: ateapi.Control.UpdateActor:input_type -> ateapi.UpdateActorRequest - 71, // 160: ateapi.Control.SuspendActor:input_type -> ateapi.SuspendActorRequest - 73, // 161: ateapi.Control.PauseActor:input_type -> ateapi.PauseActorRequest - 75, // 162: ateapi.Control.ResumeActor:input_type -> ateapi.ResumeActorRequest - 77, // 163: ateapi.Control.RevertActor:input_type -> ateapi.RevertActorRequest - 79, // 164: ateapi.Control.DeleteActor:input_type -> ateapi.DeleteActorRequest - 80, // 165: ateapi.Control.GetActorEgressPolicy:input_type -> ateapi.GetActorEgressPolicyRequest - 81, // 166: ateapi.Control.CreateActorEgressPolicy:input_type -> ateapi.CreateActorEgressPolicyRequest - 82, // 167: ateapi.Control.UpdateActorEgressPolicy:input_type -> ateapi.UpdateActorEgressPolicyRequest - 83, // 168: ateapi.Control.DeleteActorEgressPolicy:input_type -> ateapi.DeleteActorEgressPolicyRequest - 85, // 169: ateapi.Control.MintActorJwt:input_type -> ateapi.MintActorJwtRequest - 87, // 170: ateapi.Control.MintActorCertificate:input_type -> ateapi.MintActorCertificateRequest - 91, // 171: ateapi.Control.CreateTag:input_type -> ateapi.CreateTagRequest - 84, // 172: ateapi.Control.GetTag:input_type -> ateapi.GetTagRequest - 89, // 173: ateapi.Control.ListTags:input_type -> ateapi.ListTagsRequest - 92, // 174: ateapi.Control.UpdateTag:input_type -> ateapi.UpdateTagRequest - 93, // 175: ateapi.Control.DeleteTag:input_type -> ateapi.DeleteTagRequest - 97, // 176: ateapi.Control.ListWorkers:input_type -> ateapi.ListWorkersRequest - 99, // 177: ateapi.Control.GetWorker:input_type -> ateapi.GetWorkerRequest - 100, // 178: ateapi.Control.CreateWorker:input_type -> ateapi.CreateWorkerRequest - 101, // 179: ateapi.Control.UpdateWorker:input_type -> ateapi.UpdateWorkerRequest - 102, // 180: ateapi.Control.DeleteWorker:input_type -> ateapi.DeleteWorkerRequest - 103, // 181: ateapi.Control.DrainWorker:input_type -> ateapi.DrainWorkerRequest - 95, // 182: ateapi.Control.ListWorkerActorAssignments:input_type -> ateapi.ListWorkerActorAssignmentsRequest - 105, // 183: ateapi.Control.ListActors:input_type -> ateapi.ListActorsRequest - 58, // 184: ateapi.Control.CreateAtespace:input_type -> ateapi.CreateAtespaceRequest - 59, // 185: ateapi.Control.GetAtespace:input_type -> ateapi.GetAtespaceRequest - 60, // 186: ateapi.Control.ListAtespaces:input_type -> ateapi.ListAtespacesRequest - 62, // 187: ateapi.Control.DeleteAtespace:input_type -> ateapi.DeleteAtespaceRequest - 63, // 188: ateapi.Control.CreateActorTemplate:input_type -> ateapi.CreateActorTemplateRequest - 64, // 189: ateapi.Control.GetActorTemplate:input_type -> ateapi.GetActorTemplateRequest - 65, // 190: ateapi.Control.ListActorTemplates:input_type -> ateapi.ListActorTemplatesRequest - 67, // 191: ateapi.Control.DeleteActorTemplate:input_type -> ateapi.DeleteActorTemplateRequest - 122, // 192: ateapi.Control.GetGlobalAccessPolicy:input_type -> ateapi.GetGlobalAccessPolicyRequest - 123, // 193: ateapi.Control.CreateGlobalAccessPolicy:input_type -> ateapi.CreateGlobalAccessPolicyRequest - 124, // 194: ateapi.Control.UpdateGlobalAccessPolicy:input_type -> ateapi.UpdateGlobalAccessPolicyRequest - 125, // 195: ateapi.Control.GetAtespaceAccessPolicy:input_type -> ateapi.GetAtespaceAccessPolicyRequest - 126, // 196: ateapi.Control.CreateAtespaceAccessPolicy:input_type -> ateapi.CreateAtespaceAccessPolicyRequest - 127, // 197: ateapi.Control.UpdateAtespaceAccessPolicy:input_type -> ateapi.UpdateAtespaceAccessPolicyRequest - 128, // 198: ateapi.Control.DeleteAtespaceAccessPolicy:input_type -> ateapi.DeleteAtespaceAccessPolicyRequest - 114, // 199: ateapi.WorkerService.RegisterWorker:input_type -> ateapi.RegisterWorkerRequest - 116, // 200: ateapi.WorkerService.MintAteomActorCertificate:input_type -> ateapi.MintAteomActorCertificateRequest - 118, // 201: ateapi.WorkerService.RequestActorSuspend:input_type -> ateapi.RequestActorSuspendRequest - 16, // 202: ateapi.Control.GetActor:output_type -> ateapi.Actor - 16, // 203: ateapi.Control.CreateActor:output_type -> ateapi.Actor - 16, // 204: ateapi.Control.UpdateActor:output_type -> ateapi.Actor - 72, // 205: ateapi.Control.SuspendActor:output_type -> ateapi.SuspendActorResponse - 74, // 206: ateapi.Control.PauseActor:output_type -> ateapi.PauseActorResponse - 76, // 207: ateapi.Control.ResumeActor:output_type -> ateapi.ResumeActorResponse - 78, // 208: ateapi.Control.RevertActor:output_type -> ateapi.RevertActorResponse - 16, // 209: ateapi.Control.DeleteActor:output_type -> ateapi.Actor - 17, // 210: ateapi.Control.GetActorEgressPolicy:output_type -> ateapi.EgressPolicy - 17, // 211: ateapi.Control.CreateActorEgressPolicy:output_type -> ateapi.EgressPolicy - 17, // 212: ateapi.Control.UpdateActorEgressPolicy:output_type -> ateapi.EgressPolicy - 17, // 213: ateapi.Control.DeleteActorEgressPolicy:output_type -> ateapi.EgressPolicy - 86, // 214: ateapi.Control.MintActorJwt:output_type -> ateapi.MintActorJwtResponse - 88, // 215: ateapi.Control.MintActorCertificate:output_type -> ateapi.MintActorCertificateResponse - 31, // 216: ateapi.Control.CreateTag:output_type -> ateapi.Tag - 31, // 217: ateapi.Control.GetTag:output_type -> ateapi.Tag - 90, // 218: ateapi.Control.ListTags:output_type -> ateapi.ListTagsResponse - 31, // 219: ateapi.Control.UpdateTag:output_type -> ateapi.Tag - 31, // 220: ateapi.Control.DeleteTag:output_type -> ateapi.Tag - 98, // 221: ateapi.Control.ListWorkers:output_type -> ateapi.ListWorkersResponse - 107, // 222: ateapi.Control.GetWorker:output_type -> ateapi.Worker - 107, // 223: ateapi.Control.CreateWorker:output_type -> ateapi.Worker - 107, // 224: ateapi.Control.UpdateWorker:output_type -> ateapi.Worker - 107, // 225: ateapi.Control.DeleteWorker:output_type -> ateapi.Worker - 104, // 226: ateapi.Control.DrainWorker:output_type -> ateapi.DrainWorkerResponse - 96, // 227: ateapi.Control.ListWorkerActorAssignments:output_type -> ateapi.ListWorkerActorAssignmentsResponse - 106, // 228: ateapi.Control.ListActors:output_type -> ateapi.ListActorsResponse - 32, // 229: ateapi.Control.CreateAtespace:output_type -> ateapi.Atespace - 32, // 230: ateapi.Control.GetAtespace:output_type -> ateapi.Atespace - 61, // 231: ateapi.Control.ListAtespaces:output_type -> ateapi.ListAtespacesResponse - 32, // 232: ateapi.Control.DeleteAtespace:output_type -> ateapi.Atespace - 34, // 233: ateapi.Control.CreateActorTemplate:output_type -> ateapi.ActorTemplate - 34, // 234: ateapi.Control.GetActorTemplate:output_type -> ateapi.ActorTemplate - 66, // 235: ateapi.Control.ListActorTemplates:output_type -> ateapi.ListActorTemplatesResponse - 34, // 236: ateapi.Control.DeleteActorTemplate:output_type -> ateapi.ActorTemplate - 120, // 237: ateapi.Control.GetGlobalAccessPolicy:output_type -> ateapi.AccessPolicy - 120, // 238: ateapi.Control.CreateGlobalAccessPolicy:output_type -> ateapi.AccessPolicy - 120, // 239: ateapi.Control.UpdateGlobalAccessPolicy:output_type -> ateapi.AccessPolicy - 120, // 240: ateapi.Control.GetAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy - 120, // 241: ateapi.Control.CreateAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy - 120, // 242: ateapi.Control.UpdateAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy - 120, // 243: ateapi.Control.DeleteAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy - 115, // 244: ateapi.WorkerService.RegisterWorker:output_type -> ateapi.RegisterWorkerResponse - 117, // 245: ateapi.WorkerService.MintAteomActorCertificate:output_type -> ateapi.MintAteomActorCertificateResponse - 119, // 246: ateapi.WorkerService.RequestActorSuspend:output_type -> ateapi.RequestActorSuspendResponse - 202, // [202:247] is the sub-list for method output_type - 157, // [157:202] is the sub-list for method input_type - 157, // [157:157] is the sub-list for extension type_name - 157, // [157:157] is the sub-list for extension extendee - 0, // [0:157] is the sub-list for field type_name + 51, // 64: ateapi.Volume.durable_dir:type_name -> ateapi.DurableDirVolumeSource + 49, // 65: ateapi.Volume.external:type_name -> ateapi.ExternalVolumeSource + 53, // 66: ateapi.Volume.system_info:type_name -> ateapi.SystemInfoVolumeSource + 50, // 67: ateapi.Volume.image:type_name -> ateapi.ImageVolumeSource + 52, // 68: ateapi.ExternalVolumeSource.template:type_name -> ateapi.ExternalVolumeTemplate + 54, // 69: ateapi.SystemInfoVolumeSource.data_sources:type_name -> ateapi.SystemInfoDataSource + 55, // 70: ateapi.SystemInfoDataSource.actor_metadata:type_name -> ateapi.ActorMetadataDataSource + 57, // 71: ateapi.SystemInfoDataSource.trust_bundle:type_name -> ateapi.TrustBundleDataSource + 56, // 72: ateapi.ActorMetadataDataSource.items:type_name -> ateapi.ActorMetadataItem + 7, // 73: ateapi.ActorMetadataItem.field:type_name -> ateapi.ActorMetadataField + 32, // 74: ateapi.CreateAtespaceRequest.atespace:type_name -> ateapi.Atespace + 33, // 75: ateapi.GetAtespaceRequest.atespace:type_name -> ateapi.ObjectRef + 32, // 76: ateapi.ListAtespacesResponse.atespaces:type_name -> ateapi.Atespace + 33, // 77: ateapi.DeleteAtespaceRequest.atespace:type_name -> ateapi.ObjectRef + 95, // 78: ateapi.DeleteAtespaceRequest.options:type_name -> ateapi.DeleteOptions + 34, // 79: ateapi.CreateActorTemplateRequest.actor_template:type_name -> ateapi.ActorTemplate + 33, // 80: ateapi.GetActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef + 34, // 81: ateapi.ListActorTemplatesResponse.actor_templates:type_name -> ateapi.ActorTemplate + 33, // 82: ateapi.DeleteActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef + 95, // 83: ateapi.DeleteActorTemplateRequest.options:type_name -> ateapi.DeleteOptions + 33, // 84: ateapi.GetActorRequest.actor:type_name -> ateapi.ObjectRef + 16, // 85: ateapi.CreateActorRequest.actor:type_name -> ateapi.Actor + 16, // 86: ateapi.UpdateActorRequest.actor:type_name -> ateapi.Actor + 33, // 87: ateapi.SuspendActorRequest.actor:type_name -> ateapi.ObjectRef + 16, // 88: ateapi.SuspendActorResponse.actor:type_name -> ateapi.Actor + 33, // 89: ateapi.PauseActorRequest.actor:type_name -> ateapi.ObjectRef + 16, // 90: ateapi.PauseActorResponse.actor:type_name -> ateapi.Actor + 33, // 91: ateapi.ResumeActorRequest.actor:type_name -> ateapi.ObjectRef + 16, // 92: ateapi.ResumeActorResponse.actor:type_name -> ateapi.Actor + 33, // 93: ateapi.RevertActorRequest.actor:type_name -> ateapi.ObjectRef + 16, // 94: ateapi.RevertActorResponse.actor:type_name -> ateapi.Actor + 33, // 95: ateapi.DeleteActorRequest.actor:type_name -> ateapi.ObjectRef + 95, // 96: ateapi.DeleteActorRequest.options:type_name -> ateapi.DeleteOptions + 33, // 97: ateapi.GetActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 33, // 98: ateapi.CreateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 17, // 99: ateapi.CreateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy + 33, // 100: ateapi.UpdateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 17, // 101: ateapi.UpdateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy + 33, // 102: ateapi.DeleteActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 95, // 103: ateapi.DeleteActorEgressPolicyRequest.options:type_name -> ateapi.DeleteOptions + 33, // 104: ateapi.GetTagRequest.tag:type_name -> ateapi.ObjectRef + 33, // 105: ateapi.MintActorJwtRequest.actor:type_name -> ateapi.ObjectRef + 133, // 106: ateapi.MintActorJwtResponse.expires_at:type_name -> google.protobuf.Timestamp + 33, // 107: ateapi.MintActorCertificateRequest.actor:type_name -> ateapi.ObjectRef + 31, // 108: ateapi.ListTagsResponse.tags:type_name -> ateapi.Tag + 31, // 109: ateapi.CreateTagRequest.tag:type_name -> ateapi.Tag + 31, // 110: ateapi.UpdateTagRequest.tag:type_name -> ateapi.Tag + 33, // 111: ateapi.DeleteTagRequest.tag:type_name -> ateapi.ObjectRef + 95, // 112: ateapi.DeleteTagRequest.options:type_name -> ateapi.DeleteOptions + 33, // 113: ateapi.ListWorkerActorAssignmentsRequest.worker:type_name -> ateapi.ObjectRef + 114, // 114: ateapi.ListWorkerActorAssignmentsResponse.actor_assignments:type_name -> ateapi.ActorAssignment + 108, // 115: ateapi.ListWorkersResponse.workers:type_name -> ateapi.Worker + 33, // 116: ateapi.GetWorkerRequest.worker:type_name -> ateapi.ObjectRef + 108, // 117: ateapi.CreateWorkerRequest.worker:type_name -> ateapi.Worker + 108, // 118: ateapi.UpdateWorkerRequest.worker:type_name -> ateapi.Worker + 33, // 119: ateapi.DeleteWorkerRequest.worker:type_name -> ateapi.ObjectRef + 95, // 120: ateapi.DeleteWorkerRequest.options:type_name -> ateapi.DeleteOptions + 33, // 121: ateapi.DrainWorkerRequest.worker:type_name -> ateapi.ObjectRef + 108, // 122: ateapi.DrainWorkerResponse.worker:type_name -> ateapi.Worker + 16, // 123: ateapi.ListActorsResponse.actors:type_name -> ateapi.Actor + 14, // 124: ateapi.Worker.metadata:type_name -> ateapi.ResourceMetadata + 132, // 125: ateapi.Worker.labels:type_name -> ateapi.Worker.LabelsEntry + 109, // 126: ateapi.Worker.status:type_name -> ateapi.WorkerStatus + 8, // 127: ateapi.WorkerStatus.state:type_name -> ateapi.WorkerState + 113, // 128: ateapi.WorkerStatus.capacity:type_name -> ateapi.WorkerResources + 113, // 129: ateapi.WorkerStatus.allocated:type_name -> ateapi.WorkerResources + 110, // 130: ateapi.WorkerStatus.default_runtime:type_name -> ateapi.SandboxRuntime + 110, // 131: ateapi.WorkerStatus.restorable_runtimes:type_name -> ateapi.SandboxRuntime + 111, // 132: ateapi.SandboxRuntime.version:type_name -> ateapi.VersionedSandboxCompat + 112, // 133: ateapi.VersionedSandboxCompat.attributes:type_name -> ateapi.AttributeEntry + 35, // 134: ateapi.WorkerResources.resources:type_name -> ateapi.Resources + 14, // 135: ateapi.ActorAssignment.metadata:type_name -> ateapi.ResourceMetadata + 33, // 136: ateapi.ActorAssignment.actor:type_name -> ateapi.ObjectRef + 35, // 137: ateapi.ActorAssignment.resources:type_name -> ateapi.Resources + 33, // 138: ateapi.RegisterWorkerRequest.worker:type_name -> ateapi.ObjectRef + 113, // 139: ateapi.RegisterWorkerRequest.capacity:type_name -> ateapi.WorkerResources + 110, // 140: ateapi.RegisterWorkerRequest.default_runtime:type_name -> ateapi.SandboxRuntime + 110, // 141: ateapi.RegisterWorkerRequest.restorable_runtimes:type_name -> ateapi.SandboxRuntime + 108, // 142: ateapi.RegisterWorkerResponse.worker:type_name -> ateapi.Worker + 33, // 143: ateapi.MintAteomActorCertificateRequest.actor:type_name -> ateapi.ObjectRef + 33, // 144: ateapi.RequestActorSuspendRequest.worker:type_name -> ateapi.ObjectRef + 33, // 145: ateapi.RequestActorSuspendRequest.actor:type_name -> ateapi.ObjectRef + 16, // 146: ateapi.RequestActorSuspendResponse.actor:type_name -> ateapi.Actor + 14, // 147: ateapi.AccessPolicy.metadata:type_name -> ateapi.ResourceMetadata + 122, // 148: ateapi.AccessPolicy.bindings:type_name -> ateapi.Binding + 121, // 149: ateapi.CreateGlobalAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy + 121, // 150: ateapi.UpdateGlobalAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy + 33, // 151: ateapi.GetAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef + 33, // 152: ateapi.CreateAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef + 121, // 153: ateapi.CreateAtespaceAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy + 33, // 154: ateapi.UpdateAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef + 121, // 155: ateapi.UpdateAtespaceAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy + 33, // 156: ateapi.DeleteAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef + 95, // 157: ateapi.DeleteAtespaceAccessPolicyRequest.options:type_name -> ateapi.DeleteOptions + 69, // 158: ateapi.Control.GetActor:input_type -> ateapi.GetActorRequest + 70, // 159: ateapi.Control.CreateActor:input_type -> ateapi.CreateActorRequest + 71, // 160: ateapi.Control.UpdateActor:input_type -> ateapi.UpdateActorRequest + 72, // 161: ateapi.Control.SuspendActor:input_type -> ateapi.SuspendActorRequest + 74, // 162: ateapi.Control.PauseActor:input_type -> ateapi.PauseActorRequest + 76, // 163: ateapi.Control.ResumeActor:input_type -> ateapi.ResumeActorRequest + 78, // 164: ateapi.Control.RevertActor:input_type -> ateapi.RevertActorRequest + 80, // 165: ateapi.Control.DeleteActor:input_type -> ateapi.DeleteActorRequest + 81, // 166: ateapi.Control.GetActorEgressPolicy:input_type -> ateapi.GetActorEgressPolicyRequest + 82, // 167: ateapi.Control.CreateActorEgressPolicy:input_type -> ateapi.CreateActorEgressPolicyRequest + 83, // 168: ateapi.Control.UpdateActorEgressPolicy:input_type -> ateapi.UpdateActorEgressPolicyRequest + 84, // 169: ateapi.Control.DeleteActorEgressPolicy:input_type -> ateapi.DeleteActorEgressPolicyRequest + 86, // 170: ateapi.Control.MintActorJwt:input_type -> ateapi.MintActorJwtRequest + 88, // 171: ateapi.Control.MintActorCertificate:input_type -> ateapi.MintActorCertificateRequest + 92, // 172: ateapi.Control.CreateTag:input_type -> ateapi.CreateTagRequest + 85, // 173: ateapi.Control.GetTag:input_type -> ateapi.GetTagRequest + 90, // 174: ateapi.Control.ListTags:input_type -> ateapi.ListTagsRequest + 93, // 175: ateapi.Control.UpdateTag:input_type -> ateapi.UpdateTagRequest + 94, // 176: ateapi.Control.DeleteTag:input_type -> ateapi.DeleteTagRequest + 98, // 177: ateapi.Control.ListWorkers:input_type -> ateapi.ListWorkersRequest + 100, // 178: ateapi.Control.GetWorker:input_type -> ateapi.GetWorkerRequest + 101, // 179: ateapi.Control.CreateWorker:input_type -> ateapi.CreateWorkerRequest + 102, // 180: ateapi.Control.UpdateWorker:input_type -> ateapi.UpdateWorkerRequest + 103, // 181: ateapi.Control.DeleteWorker:input_type -> ateapi.DeleteWorkerRequest + 104, // 182: ateapi.Control.DrainWorker:input_type -> ateapi.DrainWorkerRequest + 96, // 183: ateapi.Control.ListWorkerActorAssignments:input_type -> ateapi.ListWorkerActorAssignmentsRequest + 106, // 184: ateapi.Control.ListActors:input_type -> ateapi.ListActorsRequest + 59, // 185: ateapi.Control.CreateAtespace:input_type -> ateapi.CreateAtespaceRequest + 60, // 186: ateapi.Control.GetAtespace:input_type -> ateapi.GetAtespaceRequest + 61, // 187: ateapi.Control.ListAtespaces:input_type -> ateapi.ListAtespacesRequest + 63, // 188: ateapi.Control.DeleteAtespace:input_type -> ateapi.DeleteAtespaceRequest + 64, // 189: ateapi.Control.CreateActorTemplate:input_type -> ateapi.CreateActorTemplateRequest + 65, // 190: ateapi.Control.GetActorTemplate:input_type -> ateapi.GetActorTemplateRequest + 66, // 191: ateapi.Control.ListActorTemplates:input_type -> ateapi.ListActorTemplatesRequest + 68, // 192: ateapi.Control.DeleteActorTemplate:input_type -> ateapi.DeleteActorTemplateRequest + 123, // 193: ateapi.Control.GetGlobalAccessPolicy:input_type -> ateapi.GetGlobalAccessPolicyRequest + 124, // 194: ateapi.Control.CreateGlobalAccessPolicy:input_type -> ateapi.CreateGlobalAccessPolicyRequest + 125, // 195: ateapi.Control.UpdateGlobalAccessPolicy:input_type -> ateapi.UpdateGlobalAccessPolicyRequest + 126, // 196: ateapi.Control.GetAtespaceAccessPolicy:input_type -> ateapi.GetAtespaceAccessPolicyRequest + 127, // 197: ateapi.Control.CreateAtespaceAccessPolicy:input_type -> ateapi.CreateAtespaceAccessPolicyRequest + 128, // 198: ateapi.Control.UpdateAtespaceAccessPolicy:input_type -> ateapi.UpdateAtespaceAccessPolicyRequest + 129, // 199: ateapi.Control.DeleteAtespaceAccessPolicy:input_type -> ateapi.DeleteAtespaceAccessPolicyRequest + 115, // 200: ateapi.WorkerService.RegisterWorker:input_type -> ateapi.RegisterWorkerRequest + 117, // 201: ateapi.WorkerService.MintAteomActorCertificate:input_type -> ateapi.MintAteomActorCertificateRequest + 119, // 202: ateapi.WorkerService.RequestActorSuspend:input_type -> ateapi.RequestActorSuspendRequest + 16, // 203: ateapi.Control.GetActor:output_type -> ateapi.Actor + 16, // 204: ateapi.Control.CreateActor:output_type -> ateapi.Actor + 16, // 205: ateapi.Control.UpdateActor:output_type -> ateapi.Actor + 73, // 206: ateapi.Control.SuspendActor:output_type -> ateapi.SuspendActorResponse + 75, // 207: ateapi.Control.PauseActor:output_type -> ateapi.PauseActorResponse + 77, // 208: ateapi.Control.ResumeActor:output_type -> ateapi.ResumeActorResponse + 79, // 209: ateapi.Control.RevertActor:output_type -> ateapi.RevertActorResponse + 16, // 210: ateapi.Control.DeleteActor:output_type -> ateapi.Actor + 17, // 211: ateapi.Control.GetActorEgressPolicy:output_type -> ateapi.EgressPolicy + 17, // 212: ateapi.Control.CreateActorEgressPolicy:output_type -> ateapi.EgressPolicy + 17, // 213: ateapi.Control.UpdateActorEgressPolicy:output_type -> ateapi.EgressPolicy + 17, // 214: ateapi.Control.DeleteActorEgressPolicy:output_type -> ateapi.EgressPolicy + 87, // 215: ateapi.Control.MintActorJwt:output_type -> ateapi.MintActorJwtResponse + 89, // 216: ateapi.Control.MintActorCertificate:output_type -> ateapi.MintActorCertificateResponse + 31, // 217: ateapi.Control.CreateTag:output_type -> ateapi.Tag + 31, // 218: ateapi.Control.GetTag:output_type -> ateapi.Tag + 91, // 219: ateapi.Control.ListTags:output_type -> ateapi.ListTagsResponse + 31, // 220: ateapi.Control.UpdateTag:output_type -> ateapi.Tag + 31, // 221: ateapi.Control.DeleteTag:output_type -> ateapi.Tag + 99, // 222: ateapi.Control.ListWorkers:output_type -> ateapi.ListWorkersResponse + 108, // 223: ateapi.Control.GetWorker:output_type -> ateapi.Worker + 108, // 224: ateapi.Control.CreateWorker:output_type -> ateapi.Worker + 108, // 225: ateapi.Control.UpdateWorker:output_type -> ateapi.Worker + 108, // 226: ateapi.Control.DeleteWorker:output_type -> ateapi.Worker + 105, // 227: ateapi.Control.DrainWorker:output_type -> ateapi.DrainWorkerResponse + 97, // 228: ateapi.Control.ListWorkerActorAssignments:output_type -> ateapi.ListWorkerActorAssignmentsResponse + 107, // 229: ateapi.Control.ListActors:output_type -> ateapi.ListActorsResponse + 32, // 230: ateapi.Control.CreateAtespace:output_type -> ateapi.Atespace + 32, // 231: ateapi.Control.GetAtespace:output_type -> ateapi.Atespace + 62, // 232: ateapi.Control.ListAtespaces:output_type -> ateapi.ListAtespacesResponse + 32, // 233: ateapi.Control.DeleteAtespace:output_type -> ateapi.Atespace + 34, // 234: ateapi.Control.CreateActorTemplate:output_type -> ateapi.ActorTemplate + 34, // 235: ateapi.Control.GetActorTemplate:output_type -> ateapi.ActorTemplate + 67, // 236: ateapi.Control.ListActorTemplates:output_type -> ateapi.ListActorTemplatesResponse + 34, // 237: ateapi.Control.DeleteActorTemplate:output_type -> ateapi.ActorTemplate + 121, // 238: ateapi.Control.GetGlobalAccessPolicy:output_type -> ateapi.AccessPolicy + 121, // 239: ateapi.Control.CreateGlobalAccessPolicy:output_type -> ateapi.AccessPolicy + 121, // 240: ateapi.Control.UpdateGlobalAccessPolicy:output_type -> ateapi.AccessPolicy + 121, // 241: ateapi.Control.GetAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy + 121, // 242: ateapi.Control.CreateAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy + 121, // 243: ateapi.Control.UpdateAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy + 121, // 244: ateapi.Control.DeleteAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy + 116, // 245: ateapi.WorkerService.RegisterWorker:output_type -> ateapi.RegisterWorkerResponse + 118, // 246: ateapi.WorkerService.MintAteomActorCertificate:output_type -> ateapi.MintAteomActorCertificateResponse + 120, // 247: ateapi.WorkerService.RequestActorSuspend:output_type -> ateapi.RequestActorSuspendResponse + 203, // [203:248] is the sub-list for method output_type + 158, // [158:203] 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() } @@ -9560,7 +9621,7 @@ func file_ateapi_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_ateapi_proto_rawDesc), len(file_ateapi_proto_rawDesc)), NumEnums: 10, - NumMessages: 122, + NumMessages: 123, NumExtensions: 0, NumServices: 2, }, diff --git a/pkg/proto/ateapipb/ateapi.proto b/pkg/proto/ateapipb/ateapi.proto index b53d1541e7..f2a018e9fb 100644 --- a/pkg/proto/ateapipb/ateapi.proto +++ b/pkg/proto/ateapipb/ateapi.proto @@ -371,7 +371,8 @@ message ResourceMetadata { google.protobuf.Timestamp update_time = 6; } -message ExternalVolume { +// ExternalVolumeRef is one actor's view of an external volume it mounts. +message ExternalVolumeRef { // Name of the volume specified in the actor template. Template volume // names are DNS labels. // @@ -407,6 +408,7 @@ message ExternalVolume { // +k8s:customValidation string volume_type = 3; + // Status is the volume's lifecycle state in the storage system. enum Status { STATUS_UNSPECIFIED = 0; // Volume creation pending in the storage system. @@ -415,9 +417,11 @@ message ExternalVolume { STATUS_CREATED = 2; // Volume being deleted from the storage system. STATUS_DELETING = 3; - // Keep this in sync with ExternalVolume.status's maximum. + // Keep this in sync with ExternalVolumeRef.status's maximum. } + // status is the volume's lifecycle state in the storage system. + // // +k8s:optional // +k8s:minimum=1 // +k8s:maximum=3 # keep this in sync with the Status enum @@ -780,7 +784,7 @@ message ActorStatus { // +k8s:maxItems=32 # matches the template's volumes bound // +k8s:listType=map // +k8s:listMapKey=name - repeated ExternalVolume external_volumes = 7; + repeated ExternalVolumeRef external_volumes = 7; // crash records why and when the Actor entered CRASHED. It is set with the // CRASHED state and cleared when a revert returns the Actor to SUSPENDED. @@ -1321,16 +1325,19 @@ message Volume { // +k8s:format=k8s-short-name string name = 1; - // Exactly one of durable_dir / external_volume_template / image / - // system_info must be set. + // Exactly one of durable_dir / external / image / system_info must be + // set. // // +k8s:optional // +k8s:unionMember DurableDirVolumeSource durable_dir = 2; + // external is a CSI volume: provisioned for this actor from a template, + // or a SharedVolume the actor references. + // // +k8s:optional // +k8s:unionMember - ExternalVolumeTemplate external_volume_template = 3; + ExternalVolumeSource external = 7; // +k8s:optional // +k8s:unionMember @@ -1343,6 +1350,16 @@ message Volume { ImageVolumeSource image = 6; } +// ExternalVolumeSource is a CSI volume: provisioned for the actor from a +// template, or a SharedVolume that already exists. +message ExternalVolumeSource { + // Exactly one of template / shared_volume must be set. + // + // +k8s:optional + // +k8s:unionMember + ExternalVolumeTemplate template = 1; +} + // ImageVolumeSource mounts the contents of an OCI image, read-only. The // reference must include a digest: changing the image invalidates // snapshots. diff --git a/tools/apitool/exemptions.json b/tools/apitool/exemptions.json index 804256c62f..bc517bdae8 100644 --- a/tools/apitool/exemptions.json +++ b/tools/apitool/exemptions.json @@ -149,21 +149,6 @@ "subject": "ateapi.DrainWorkerRequest", "message": "message has no doc comment" }, - { - "rule": "documented", - "subject": "ateapi.ExternalVolume", - "message": "message has no doc comment" - }, - { - "rule": "documented", - "subject": "ateapi.ExternalVolume.Status", - "message": "enum has no doc comment" - }, - { - "rule": "documented", - "subject": "ateapi.ExternalVolume.status", - "message": "field has no doc comment" - }, { "rule": "documented", "subject": "ateapi.GetActorRequest", @@ -369,11 +354,6 @@ "subject": "ateapi.Volume", "message": "message has no doc comment" }, - { - "rule": "documented", - "subject": "ateapi.Volume.external_volume_template", - "message": "field has no doc comment" - }, { "rule": "documented", "subject": "ateapi.Volume.system_info", diff --git a/tools/apitool/internal/model/model.go b/tools/apitool/internal/model/model.go index 7a664e341e..70105cfd59 100644 --- a/tools/apitool/internal/model/model.go +++ b/tools/apitool/internal/model/model.go @@ -41,7 +41,7 @@ type API struct { Messages []Message // Enums lists every enum declared in the file, top-level and nested, // flattened the same way as Messages. For example, both the top-level - // "ateapi.ActorState" and the nested "ateapi.ExternalVolume.Status" + // "ateapi.ActorState" and the nested "ateapi.ExternalVolumeRef.Status" // appear here. Enums []Enum } @@ -101,7 +101,7 @@ type Message struct { // Name is the message's short name, with its enclosing message's name // dotted in front for a nested type. For example, "ResourceMetadata" // for a top-level message. ateapi.proto has no nested message today - // (only a nested enum, ExternalVolume.Status - see Enum.Name for that + // (only a nested enum, ExternalVolumeRef.Status - see Enum.Name for that // shape); a nested message named "Child" inside "Parent" would read // "Parent.Child" here. Name string @@ -132,13 +132,13 @@ type Field struct { // Repeated is true for a `repeated` field, not a map - see // MapValueKind for those. For example, true for - // `repeated ExternalVolume external_volumes = 7;` on ActorStatus; false + // `repeated ExternalVolumeRef external_volumes = 7;` on ActorStatus; false // for ResourceMetadata.atespace. Repeated bool // TypeDisplay is always a ready-to-render string. For example, "string" // for ResourceMetadata.name, "int64" for ResourceMetadata.version, - // "repeated ExternalVolume" for ActorStatus.external_volumes, + // "repeated ExternalVolumeRef" for ActorStatus.external_volumes, // "map" for SandboxAssets.assets, "ActorState" for // ActorStatus.state, or "google.protobuf.Timestamp" for // ResourceMetadata.create_time. @@ -184,25 +184,25 @@ type Field struct { // Enum is one enum declared in the file, top-level or nested. type Enum struct { // FullName is the enum's proto full name. For example, "ateapi.ActorState" - // for a top-level enum, or "ateapi.ExternalVolume.Status" for one - // nested inside the ExternalVolume message. + // for a top-level enum, or "ateapi.ExternalVolumeRef.Status" for one + // nested inside the ExternalVolumeRef message. FullName string // Name is the enum's short name, with its enclosing message's name // dotted in front for a nested enum. For example, "ActorState" for - // the top-level enum, or "ExternalVolume.Status" for the one nested - // inside ExternalVolume. + // the top-level enum, or "ExternalVolumeRef.Status" for the one nested + // inside ExternalVolumeRef. Name string // ParentFullName is the enclosing message's full name, or "" for a // top-level enum. For example, "" for "ateapi.ActorState", or - // "ateapi.ExternalVolume" for "ateapi.ExternalVolume.Status". + // "ateapi.ExternalVolumeRef" for "ateapi.ExternalVolumeRef.Status". ParentFullName string // Comment is the enum's leading doc comment. ateapi.proto's ActorState - // and ExternalVolume.Status have none today, so this is often "" in + // and ExternalVolumeRef.Status have none today, so this is often "" in // practice even though the field is populated the same way as for a // message or field. Comment string // Values lists the enum's values, in declaration order. For example, - // ExternalVolume.Status's STATUS_UNSPECIFIED, STATUS_PENDING, + // ExternalVolumeRef.Status's STATUS_UNSPECIFIED, STATUS_PENDING, // STATUS_CREATED, STATUS_DELETING. Values []EnumValue } @@ -221,13 +221,13 @@ func (e Enum) ValueByNumber(number int32) *EnumValue { // EnumValue is one value declared on an Enum. type EnumValue struct { // Name is the value's proto name. For example, "STATUS_PENDING" for - // ExternalVolume.Status. + // ExternalVolumeRef.Status. Name string // Number is the value's proto number. For example, 1 for // `STATUS_PENDING = 1;`. Number int32 // Comment is the value's leading doc comment. For example, "Volume - // creation pending in the storage system." for ExternalVolume.Status's + // creation pending in the storage system." for ExternalVolumeRef.Status's // STATUS_PENDING. Comment string } From 16b682b19d87d69377a932131be2967c71e0d742 Mon Sep 17 00:00:00 2001 From: Elijah Rodriguez Date: Wed, 14 Oct 2026 10:33:16 -0700 Subject: [PATCH 02/12] atelet: add the empty_dir volume source An EmptyDirVolume is an empty host directory at the same path an external volume would be published to, mounted into the sandbox the same way. It lets a golden actor warm up against a placeholder for an external volume it must not mount, so the snapshot's mount table matches the real actor's on both gVisor and microVM. Co-Authored-By: Claude Fable 5.1 --- .../apivalidation/zz_generated.validation.go | 36 +- cmd/atelet/main.go | 2 +- cmd/atelet/main_test.go | 3 + cmd/atelet/volumes.go | 18 +- cmd/atelet/volumes_test.go | 20 + internal/proto/ateletpb/atelet.pb.go | 395 ++++++++++-------- internal/proto/ateletpb/atelet.proto | 10 +- 7 files changed, 308 insertions(+), 176 deletions(-) diff --git a/cmd/atelet/internal/apivalidation/zz_generated.validation.go b/cmd/atelet/internal/apivalidation/zz_generated.validation.go index 5b43f0b1f3..24d49d0da7 100644 --- a/cmd/atelet/internal/apivalidation/zz_generated.validation.go +++ b/cmd/atelet/internal/apivalidation/zz_generated.validation.go @@ -4200,7 +4200,7 @@ func Validate_VersionedSandboxCompat( return errs } -var unionMembershipFor_github_com_agent_substrate_substrate_internal_proto_ateletpb_Volume_ = validate.NewUnionMembership(validate.NewUnionMember("durable_dir"), validate.NewUnionMember("external"), validate.NewUnionMember("system_info"), validate.NewUnionMember("image")) +var unionMembershipFor_github_com_agent_substrate_substrate_internal_proto_ateletpb_Volume_ = validate.NewUnionMembership(validate.NewUnionMember("durable_dir"), validate.NewUnionMember("external"), validate.NewUnionMember("system_info"), validate.NewUnionMember("image"), validate.NewUnionMember("empty_dir")) // Validate_Volume validates an instance of Volume according // to declarative validation rules in the API schema. @@ -4232,6 +4232,12 @@ func Validate_Volume( return false } return obj.Image != nil + }, + func(obj *ateletpb.Volume) bool { + if obj == nil { + return false + } + return obj.EmptyDir != nil }); len(e) != 0 { errs = append(errs, e...) } @@ -4386,6 +4392,34 @@ func Validate_Volume( errs = append(errs, fn(fldPath.Child("image"), obj.Image, oldVal, oldObj != nil)...) } + { // field ateletpb.Volume.EmptyDir + fn := func( + fldPath *field.Path, + obj, oldObj *ateletpb.EmptyDirVolume, + 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 *ateletpb.Volume) *ateletpb.EmptyDirVolume { + return oldObj.EmptyDir + }) + errs = append(errs, fn(fldPath.Child("empty_dir"), obj.EmptyDir, oldVal, oldObj != nil)...) + } + return errs } diff --git a/cmd/atelet/main.go b/cmd/atelet/main.go index e4a5dab2ea..46731542c0 100644 --- a/cmd/atelet/main.go +++ b/cmd/atelet/main.go @@ -1587,7 +1587,7 @@ func buildAteomWorkloadSpec(spec *ateletpb.WorkloadSpec, containerSpecs []*ateom VolumeName: volName, MountPath: vm.GetMountPath(), }) - case vol.GetExternal() != nil: + case vol.GetExternal() != nil, vol.GetEmptyDir() != nil: csiMounts = append(csiMounts, &ateompb.VolumeMount{ VolumeName: volName, MountPath: vm.GetMountPath(), diff --git a/cmd/atelet/main_test.go b/cmd/atelet/main_test.go index 1dd1a5fa4e..0fe9aaa8a3 100644 --- a/cmd/atelet/main_test.go +++ b/cmd/atelet/main_test.go @@ -816,6 +816,7 @@ func TestBuildAteomWorkloadSpecForwardsDurableDirMounts(t *testing.T) { {Name: "data", DurableDir: &ateletpb.DurableDirVolume{}}, {Name: "cache", DurableDir: &ateletpb.DurableDirVolume{}}, {Name: "scratch", External: &ateletpb.ExternalVolume{}}, + {Name: "empty", EmptyDir: &ateletpb.EmptyDirVolume{}}, {Name: "system-info", SystemInfo: &ateletpb.SystemInfoVolume{}}, }, Containers: []*ateletpb.Container{ @@ -825,6 +826,7 @@ func TestBuildAteomWorkloadSpecForwardsDurableDirMounts(t *testing.T) { {Name: "data", MountPath: "/home/counter"}, {Name: "cache", MountPath: "/var/cache"}, {Name: "scratch", MountPath: "/scratch"}, + {Name: "empty", MountPath: "/empty"}, {Name: "system-info", MountPath: "/run/ate"}, }, }, @@ -849,6 +851,7 @@ func TestBuildAteomWorkloadSpecForwardsDurableDirMounts(t *testing.T) { }, CsiVolumeMounts: []*ateompb.VolumeMount{ {VolumeName: "scratch", MountPath: "/scratch"}, + {VolumeName: "empty", MountPath: "/empty"}, }, SystemInfoVolumeMounts: []*ateompb.SystemInfoVolumeMount{ {VolumeName: "system-info", MountPath: "/run/ate"}, diff --git a/cmd/atelet/volumes.go b/cmd/atelet/volumes.go index 2cc0ee6810..b114905242 100644 --- a/cmd/atelet/volumes.go +++ b/cmd/atelet/volumes.go @@ -31,11 +31,17 @@ import ( func (s *AteomHerder) mountExternalVolumes(ctx context.Context, actorUID string, volumes []*ateletpb.Volume) error { for _, vol := range volumes { + hostPath := ateletpath.VolumeHostPath(actorUID, vol.GetName()) + if vol.GetEmptyDir() != nil { + if err := resetEmptyDir(hostPath); err != nil { + return err + } + continue + } ext := vol.GetExternal() if ext == nil { continue } - hostPath := ateletpath.VolumeHostPath(actorUID, vol.GetName()) if err := os.MkdirAll(hostPath, 0o750); err != nil { return fmt.Errorf("failed to create mount point %q: %w", hostPath, err) } @@ -56,6 +62,16 @@ func (s *AteomHerder) mountExternalVolumes(ctx context.Context, actorUID string, return nil } +func resetEmptyDir(hostPath string) error { + if err := os.RemoveAll(hostPath); err != nil { + return fmt.Errorf("failed to clear empty dir %q: %w", hostPath, err) + } + if err := os.MkdirAll(hostPath, 0o750); err != nil { + return fmt.Errorf("failed to create empty dir %q: %w", hostPath, err) + } + return nil +} + func (s *AteomHerder) unmountExternalVolumes(ctx context.Context, actorUID string, volumes []*ateletpb.Volume) error { var errs []error for _, vol := range volumes { diff --git a/cmd/atelet/volumes_test.go b/cmd/atelet/volumes_test.go index 94bb72f6cf..c016bd5100 100644 --- a/cmd/atelet/volumes_test.go +++ b/cmd/atelet/volumes_test.go @@ -552,3 +552,23 @@ func TestDirectCSIDriverConfigGetter(t *testing.T) { t.Fatalf("expected error for missing driver, got nil") } } + +func TestResetEmptyDirClearsPreviousContents(t *testing.T) { + dir := filepath.Join(t.TempDir(), "volumes", "shared") + if err := os.MkdirAll(dir, 0o750); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(dir, "stale"), []byte("x"), 0o600); err != nil { + t.Fatal(err) + } + if err := resetEmptyDir(dir); err != nil { + t.Fatalf("resetEmptyDir: %v", err) + } + entries, err := os.ReadDir(dir) + if err != nil { + t.Fatalf("ReadDir: %v", err) + } + if len(entries) != 0 { + t.Fatalf("dir still has %d entries after reset", len(entries)) + } +} diff --git a/internal/proto/ateletpb/atelet.pb.go b/internal/proto/ateletpb/atelet.pb.go index b0808aa3b7..41bb14e210 100644 --- a/internal/proto/ateletpb/atelet.pb.go +++ b/internal/proto/ateletpb/atelet.pb.go @@ -1581,6 +1581,43 @@ func (*DurableDirVolume) Descriptor() ([]byte, []int) { return file_atelet_proto_rawDescGZIP(), []int{20} } +// EmptyDirVolume is an empty host directory at the external volume path. +type EmptyDirVolume struct { + state protoimpl.MessageState `protogen:"open.v1"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *EmptyDirVolume) Reset() { + *x = EmptyDirVolume{} + mi := &file_atelet_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EmptyDirVolume) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EmptyDirVolume) ProtoMessage() {} + +func (x *EmptyDirVolume) ProtoReflect() protoreflect.Message { + mi := &file_atelet_proto_msgTypes[21] + 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 EmptyDirVolume.ProtoReflect.Descriptor instead. +func (*EmptyDirVolume) Descriptor() ([]byte, []int) { + return file_atelet_proto_rawDescGZIP(), []int{21} +} + type ExternalVolume struct { state protoimpl.MessageState `protogen:"open.v1"` // Required, unlike the actor status counterpart: the control plane only @@ -1612,7 +1649,7 @@ type ExternalVolume struct { func (x *ExternalVolume) Reset() { *x = ExternalVolume{} - mi := &file_atelet_proto_msgTypes[21] + mi := &file_atelet_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1624,7 +1661,7 @@ func (x *ExternalVolume) String() string { func (*ExternalVolume) ProtoMessage() {} func (x *ExternalVolume) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[21] + mi := &file_atelet_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1637,7 +1674,7 @@ func (x *ExternalVolume) ProtoReflect() protoreflect.Message { // Deprecated: Use ExternalVolume.ProtoReflect.Descriptor instead. func (*ExternalVolume) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{21} + return file_atelet_proto_rawDescGZIP(), []int{22} } func (x *ExternalVolume) GetStorageVolumeId() string { @@ -1682,7 +1719,7 @@ type ImageVolumeSource struct { func (x *ImageVolumeSource) Reset() { *x = ImageVolumeSource{} - mi := &file_atelet_proto_msgTypes[22] + mi := &file_atelet_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1694,7 +1731,7 @@ func (x *ImageVolumeSource) String() string { func (*ImageVolumeSource) ProtoMessage() {} func (x *ImageVolumeSource) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[22] + mi := &file_atelet_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1707,7 +1744,7 @@ func (x *ImageVolumeSource) ProtoReflect() protoreflect.Message { // Deprecated: Use ImageVolumeSource.ProtoReflect.Descriptor instead. func (*ImageVolumeSource) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{22} + return file_atelet_proto_rawDescGZIP(), []int{23} } func (x *ImageVolumeSource) GetReference() string { @@ -1739,7 +1776,7 @@ type ActorMetadataItem struct { func (x *ActorMetadataItem) Reset() { *x = ActorMetadataItem{} - mi := &file_atelet_proto_msgTypes[23] + mi := &file_atelet_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1751,7 +1788,7 @@ func (x *ActorMetadataItem) String() string { func (*ActorMetadataItem) ProtoMessage() {} func (x *ActorMetadataItem) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[23] + mi := &file_atelet_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1764,7 +1801,7 @@ func (x *ActorMetadataItem) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorMetadataItem.ProtoReflect.Descriptor instead. func (*ActorMetadataItem) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{23} + return file_atelet_proto_rawDescGZIP(), []int{24} } func (x *ActorMetadataItem) GetField() ActorMetadataField { @@ -1800,7 +1837,7 @@ type ActorMetadataDataSource struct { func (x *ActorMetadataDataSource) Reset() { *x = ActorMetadataDataSource{} - mi := &file_atelet_proto_msgTypes[24] + mi := &file_atelet_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1812,7 +1849,7 @@ func (x *ActorMetadataDataSource) String() string { func (*ActorMetadataDataSource) ProtoMessage() {} func (x *ActorMetadataDataSource) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[24] + mi := &file_atelet_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1825,7 +1862,7 @@ func (x *ActorMetadataDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorMetadataDataSource.ProtoReflect.Descriptor instead. func (*ActorMetadataDataSource) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{24} + return file_atelet_proto_rawDescGZIP(), []int{25} } func (x *ActorMetadataDataSource) GetItems() []*ActorMetadataItem { @@ -1859,7 +1896,7 @@ type TrustBundleDataSource struct { func (x *TrustBundleDataSource) Reset() { *x = TrustBundleDataSource{} - mi := &file_atelet_proto_msgTypes[25] + mi := &file_atelet_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1871,7 +1908,7 @@ func (x *TrustBundleDataSource) String() string { func (*TrustBundleDataSource) ProtoMessage() {} func (x *TrustBundleDataSource) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[25] + mi := &file_atelet_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1884,7 +1921,7 @@ func (x *TrustBundleDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use TrustBundleDataSource.ProtoReflect.Descriptor instead. func (*TrustBundleDataSource) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{25} + return file_atelet_proto_rawDescGZIP(), []int{26} } func (x *TrustBundleDataSource) GetPath() string { @@ -1919,7 +1956,7 @@ type SystemInfoDataSource struct { func (x *SystemInfoDataSource) Reset() { *x = SystemInfoDataSource{} - mi := &file_atelet_proto_msgTypes[26] + mi := &file_atelet_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1931,7 +1968,7 @@ func (x *SystemInfoDataSource) String() string { func (*SystemInfoDataSource) ProtoMessage() {} func (x *SystemInfoDataSource) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[26] + mi := &file_atelet_proto_msgTypes[27] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1944,7 +1981,7 @@ func (x *SystemInfoDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemInfoDataSource.ProtoReflect.Descriptor instead. func (*SystemInfoDataSource) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{26} + return file_atelet_proto_rawDescGZIP(), []int{27} } func (x *SystemInfoDataSource) GetActorMetadata() *ActorMetadataDataSource { @@ -1977,7 +2014,7 @@ type SystemInfoVolume struct { func (x *SystemInfoVolume) Reset() { *x = SystemInfoVolume{} - mi := &file_atelet_proto_msgTypes[27] + mi := &file_atelet_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1989,7 +2026,7 @@ func (x *SystemInfoVolume) String() string { func (*SystemInfoVolume) ProtoMessage() {} func (x *SystemInfoVolume) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[27] + mi := &file_atelet_proto_msgTypes[28] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2002,7 +2039,7 @@ func (x *SystemInfoVolume) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemInfoVolume.ProtoReflect.Descriptor instead. func (*SystemInfoVolume) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{27} + return file_atelet_proto_rawDescGZIP(), []int{28} } func (x *SystemInfoVolume) GetDataSources() []*SystemInfoDataSource { @@ -2018,7 +2055,7 @@ type Volume struct { // +k8s:required // +k8s:format=k8s-short-name Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - // Exactly one of durable_dir / external / system_info / image must be set. + // Exactly one of durable_dir / external / system_info / image / empty_dir must be set. // // +k8s:optional // +k8s:unionMember @@ -2031,14 +2068,17 @@ type Volume struct { SystemInfo *SystemInfoVolume `protobuf:"bytes,4,opt,name=system_info,json=systemInfo,proto3" json:"system_info,omitempty"` // +k8s:optional // +k8s:unionMember - Image *ImageVolumeSource `protobuf:"bytes,5,opt,name=image,proto3" json:"image,omitempty"` + Image *ImageVolumeSource `protobuf:"bytes,5,opt,name=image,proto3" json:"image,omitempty"` + // +k8s:optional + // +k8s:unionMember + EmptyDir *EmptyDirVolume `protobuf:"bytes,6,opt,name=empty_dir,json=emptyDir,proto3" json:"empty_dir,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *Volume) Reset() { *x = Volume{} - mi := &file_atelet_proto_msgTypes[28] + mi := &file_atelet_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2050,7 +2090,7 @@ func (x *Volume) String() string { func (*Volume) ProtoMessage() {} func (x *Volume) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[28] + mi := &file_atelet_proto_msgTypes[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2063,7 +2103,7 @@ func (x *Volume) ProtoReflect() protoreflect.Message { // Deprecated: Use Volume.ProtoReflect.Descriptor instead. func (*Volume) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{28} + return file_atelet_proto_rawDescGZIP(), []int{29} } func (x *Volume) GetName() string { @@ -2101,6 +2141,13 @@ func (x *Volume) GetImage() *ImageVolumeSource { return nil } +func (x *Volume) GetEmptyDir() *EmptyDirVolume { + if x != nil { + return x.EmptyDir + } + return nil +} + type VolumeMount struct { state protoimpl.MessageState `protogen:"open.v1"` // name must match the name of a Volume. @@ -2120,7 +2167,7 @@ type VolumeMount struct { func (x *VolumeMount) Reset() { *x = VolumeMount{} - mi := &file_atelet_proto_msgTypes[29] + mi := &file_atelet_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2132,7 +2179,7 @@ func (x *VolumeMount) String() string { func (*VolumeMount) ProtoMessage() {} func (x *VolumeMount) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[29] + mi := &file_atelet_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2145,7 +2192,7 @@ func (x *VolumeMount) ProtoReflect() protoreflect.Message { // Deprecated: Use VolumeMount.ProtoReflect.Descriptor instead. func (*VolumeMount) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{29} + return file_atelet_proto_rawDescGZIP(), []int{30} } func (x *VolumeMount) GetName() string { @@ -2210,7 +2257,7 @@ type Container struct { func (x *Container) Reset() { *x = Container{} - mi := &file_atelet_proto_msgTypes[30] + mi := &file_atelet_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2222,7 +2269,7 @@ func (x *Container) String() string { func (*Container) ProtoMessage() {} func (x *Container) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[30] + mi := &file_atelet_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2235,7 +2282,7 @@ func (x *Container) ProtoReflect() protoreflect.Message { // Deprecated: Use Container.ProtoReflect.Descriptor instead. func (*Container) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{30} + return file_atelet_proto_rawDescGZIP(), []int{31} } func (x *Container) GetName() string { @@ -2312,7 +2359,7 @@ type SecurityContext struct { func (x *SecurityContext) Reset() { *x = SecurityContext{} - mi := &file_atelet_proto_msgTypes[31] + mi := &file_atelet_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2324,7 +2371,7 @@ func (x *SecurityContext) String() string { func (*SecurityContext) ProtoMessage() {} func (x *SecurityContext) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[31] + mi := &file_atelet_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2337,7 +2384,7 @@ func (x *SecurityContext) ProtoReflect() protoreflect.Message { // Deprecated: Use SecurityContext.ProtoReflect.Descriptor instead. func (*SecurityContext) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{31} + return file_atelet_proto_rawDescGZIP(), []int{32} } func (x *SecurityContext) GetCapabilities() *Capabilities { @@ -2367,7 +2414,7 @@ type Capabilities struct { func (x *Capabilities) Reset() { *x = Capabilities{} - mi := &file_atelet_proto_msgTypes[32] + mi := &file_atelet_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2379,7 +2426,7 @@ func (x *Capabilities) String() string { func (*Capabilities) ProtoMessage() {} func (x *Capabilities) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[32] + mi := &file_atelet_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2392,7 +2439,7 @@ func (x *Capabilities) ProtoReflect() protoreflect.Message { // Deprecated: Use Capabilities.ProtoReflect.Descriptor instead. func (*Capabilities) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{32} + return file_atelet_proto_rawDescGZIP(), []int{33} } func (x *Capabilities) GetAdd() []string { @@ -2430,7 +2477,7 @@ type ResourceLimits struct { func (x *ResourceLimits) Reset() { *x = ResourceLimits{} - mi := &file_atelet_proto_msgTypes[33] + mi := &file_atelet_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2442,7 +2489,7 @@ func (x *ResourceLimits) String() string { func (*ResourceLimits) ProtoMessage() {} func (x *ResourceLimits) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[33] + mi := &file_atelet_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2455,7 +2502,7 @@ func (x *ResourceLimits) ProtoReflect() protoreflect.Message { // Deprecated: Use ResourceLimits.ProtoReflect.Descriptor instead. func (*ResourceLimits) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{33} + return file_atelet_proto_rawDescGZIP(), []int{34} } func (x *ResourceLimits) GetMemoryBytes() int64 { @@ -2489,7 +2536,7 @@ type EnvEntry struct { func (x *EnvEntry) Reset() { *x = EnvEntry{} - mi := &file_atelet_proto_msgTypes[34] + mi := &file_atelet_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2501,7 +2548,7 @@ func (x *EnvEntry) String() string { func (*EnvEntry) ProtoMessage() {} func (x *EnvEntry) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[34] + mi := &file_atelet_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2514,7 +2561,7 @@ func (x *EnvEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use EnvEntry.ProtoReflect.Descriptor instead. func (*EnvEntry) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{34} + return file_atelet_proto_rawDescGZIP(), []int{35} } func (x *EnvEntry) GetName() string { @@ -2549,7 +2596,7 @@ type WakeupProbe struct { func (x *WakeupProbe) Reset() { *x = WakeupProbe{} - mi := &file_atelet_proto_msgTypes[35] + mi := &file_atelet_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2561,7 +2608,7 @@ func (x *WakeupProbe) String() string { func (*WakeupProbe) ProtoMessage() {} func (x *WakeupProbe) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[35] + mi := &file_atelet_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2574,7 +2621,7 @@ func (x *WakeupProbe) ProtoReflect() protoreflect.Message { // Deprecated: Use WakeupProbe.ProtoReflect.Descriptor instead. func (*WakeupProbe) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{35} + return file_atelet_proto_rawDescGZIP(), []int{36} } func (x *WakeupProbe) GetHttpGet() *HttpGetAction { @@ -2612,7 +2659,7 @@ type HttpGetAction struct { func (x *HttpGetAction) Reset() { *x = HttpGetAction{} - mi := &file_atelet_proto_msgTypes[36] + mi := &file_atelet_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2624,7 +2671,7 @@ func (x *HttpGetAction) String() string { func (*HttpGetAction) ProtoMessage() {} func (x *HttpGetAction) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[36] + mi := &file_atelet_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2637,7 +2684,7 @@ func (x *HttpGetAction) ProtoReflect() protoreflect.Message { // Deprecated: Use HttpGetAction.ProtoReflect.Descriptor instead. func (*HttpGetAction) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{36} + return file_atelet_proto_rawDescGZIP(), []int{37} } func (x *HttpGetAction) GetPath() string { @@ -2662,7 +2709,7 @@ type RunResponse struct { func (x *RunResponse) Reset() { *x = RunResponse{} - mi := &file_atelet_proto_msgTypes[37] + mi := &file_atelet_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2674,7 +2721,7 @@ func (x *RunResponse) String() string { func (*RunResponse) ProtoMessage() {} func (x *RunResponse) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[37] + mi := &file_atelet_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2687,7 +2734,7 @@ func (x *RunResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RunResponse.ProtoReflect.Descriptor instead. func (*RunResponse) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{37} + return file_atelet_proto_rawDescGZIP(), []int{38} } type LocalCheckpointConfiguration struct { @@ -2706,7 +2753,7 @@ type LocalCheckpointConfiguration struct { func (x *LocalCheckpointConfiguration) Reset() { *x = LocalCheckpointConfiguration{} - mi := &file_atelet_proto_msgTypes[38] + mi := &file_atelet_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2718,7 +2765,7 @@ func (x *LocalCheckpointConfiguration) String() string { func (*LocalCheckpointConfiguration) ProtoMessage() {} func (x *LocalCheckpointConfiguration) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[38] + mi := &file_atelet_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2731,7 +2778,7 @@ func (x *LocalCheckpointConfiguration) ProtoReflect() protoreflect.Message { // Deprecated: Use LocalCheckpointConfiguration.ProtoReflect.Descriptor instead. func (*LocalCheckpointConfiguration) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{38} + return file_atelet_proto_rawDescGZIP(), []int{39} } func (x *LocalCheckpointConfiguration) GetSnapshotName() string { @@ -2756,7 +2803,7 @@ type ExternalCheckpointConfiguration struct { func (x *ExternalCheckpointConfiguration) Reset() { *x = ExternalCheckpointConfiguration{} - mi := &file_atelet_proto_msgTypes[39] + mi := &file_atelet_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2768,7 +2815,7 @@ func (x *ExternalCheckpointConfiguration) String() string { func (*ExternalCheckpointConfiguration) ProtoMessage() {} func (x *ExternalCheckpointConfiguration) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[39] + mi := &file_atelet_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2781,7 +2828,7 @@ func (x *ExternalCheckpointConfiguration) ProtoReflect() protoreflect.Message { // Deprecated: Use ExternalCheckpointConfiguration.ProtoReflect.Descriptor instead. func (*ExternalCheckpointConfiguration) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{39} + return file_atelet_proto_rawDescGZIP(), []int{40} } func (x *ExternalCheckpointConfiguration) GetSnapshotUri() string { @@ -2810,7 +2857,7 @@ type ExternalRestoreConfiguration struct { func (x *ExternalRestoreConfiguration) Reset() { *x = ExternalRestoreConfiguration{} - mi := &file_atelet_proto_msgTypes[40] + mi := &file_atelet_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2822,7 +2869,7 @@ func (x *ExternalRestoreConfiguration) String() string { func (*ExternalRestoreConfiguration) ProtoMessage() {} func (x *ExternalRestoreConfiguration) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[40] + mi := &file_atelet_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2835,7 +2882,7 @@ func (x *ExternalRestoreConfiguration) ProtoReflect() protoreflect.Message { // Deprecated: Use ExternalRestoreConfiguration.ProtoReflect.Descriptor instead. func (*ExternalRestoreConfiguration) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{40} + return file_atelet_proto_rawDescGZIP(), []int{41} } func (x *ExternalRestoreConfiguration) GetSnapshotUri() string { @@ -2902,7 +2949,7 @@ type CheckpointRequest struct { func (x *CheckpointRequest) Reset() { *x = CheckpointRequest{} - mi := &file_atelet_proto_msgTypes[41] + mi := &file_atelet_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2914,7 +2961,7 @@ func (x *CheckpointRequest) String() string { func (*CheckpointRequest) ProtoMessage() {} func (x *CheckpointRequest) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[41] + mi := &file_atelet_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2927,7 +2974,7 @@ func (x *CheckpointRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckpointRequest.ProtoReflect.Descriptor instead. func (*CheckpointRequest) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{41} + return file_atelet_proto_rawDescGZIP(), []int{42} } func (x *CheckpointRequest) GetWorkerPodUid() string { @@ -3015,7 +3062,7 @@ type CheckpointResponse struct { func (x *CheckpointResponse) Reset() { *x = CheckpointResponse{} - mi := &file_atelet_proto_msgTypes[42] + mi := &file_atelet_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3027,7 +3074,7 @@ func (x *CheckpointResponse) String() string { func (*CheckpointResponse) ProtoMessage() {} func (x *CheckpointResponse) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[42] + mi := &file_atelet_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3040,7 +3087,7 @@ func (x *CheckpointResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckpointResponse.ProtoReflect.Descriptor instead. func (*CheckpointResponse) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{42} + return file_atelet_proto_rawDescGZIP(), []int{43} } type UploadPausedCheckpointRequest struct { @@ -3092,7 +3139,7 @@ type UploadPausedCheckpointRequest struct { func (x *UploadPausedCheckpointRequest) Reset() { *x = UploadPausedCheckpointRequest{} - mi := &file_atelet_proto_msgTypes[43] + mi := &file_atelet_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3104,7 +3151,7 @@ func (x *UploadPausedCheckpointRequest) String() string { func (*UploadPausedCheckpointRequest) ProtoMessage() {} func (x *UploadPausedCheckpointRequest) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[43] + mi := &file_atelet_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3117,7 +3164,7 @@ func (x *UploadPausedCheckpointRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UploadPausedCheckpointRequest.ProtoReflect.Descriptor instead. func (*UploadPausedCheckpointRequest) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{43} + return file_atelet_proto_rawDescGZIP(), []int{44} } func (x *UploadPausedCheckpointRequest) GetAtespace() string { @@ -3184,7 +3231,7 @@ type UploadPausedCheckpointResponse struct { func (x *UploadPausedCheckpointResponse) Reset() { *x = UploadPausedCheckpointResponse{} - mi := &file_atelet_proto_msgTypes[44] + mi := &file_atelet_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3196,7 +3243,7 @@ func (x *UploadPausedCheckpointResponse) String() string { func (*UploadPausedCheckpointResponse) ProtoMessage() {} func (x *UploadPausedCheckpointResponse) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[44] + mi := &file_atelet_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3209,7 +3256,7 @@ func (x *UploadPausedCheckpointResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UploadPausedCheckpointResponse.ProtoReflect.Descriptor instead. func (*UploadPausedCheckpointResponse) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{44} + return file_atelet_proto_rawDescGZIP(), []int{45} } // +k8s:customValidation # the set config matches type @@ -3285,7 +3332,7 @@ type RestoreRequest struct { func (x *RestoreRequest) Reset() { *x = RestoreRequest{} - mi := &file_atelet_proto_msgTypes[45] + mi := &file_atelet_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3297,7 +3344,7 @@ func (x *RestoreRequest) String() string { func (*RestoreRequest) ProtoMessage() {} func (x *RestoreRequest) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[45] + mi := &file_atelet_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3310,7 +3357,7 @@ func (x *RestoreRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RestoreRequest.ProtoReflect.Descriptor instead. func (*RestoreRequest) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{45} + return file_atelet_proto_rawDescGZIP(), []int{46} } func (x *RestoreRequest) GetWorkerPodUid() string { @@ -3426,7 +3473,7 @@ type RestoreResponse struct { func (x *RestoreResponse) Reset() { *x = RestoreResponse{} - mi := &file_atelet_proto_msgTypes[46] + mi := &file_atelet_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3438,7 +3485,7 @@ func (x *RestoreResponse) String() string { func (*RestoreResponse) ProtoMessage() {} func (x *RestoreResponse) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[46] + mi := &file_atelet_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3451,7 +3498,7 @@ func (x *RestoreResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RestoreResponse.ProtoReflect.Descriptor instead. func (*RestoreResponse) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{46} + return file_atelet_proto_rawDescGZIP(), []int{47} } var File_atelet_proto protoreflect.FileDescriptor @@ -3548,7 +3595,8 @@ 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\"\x89\x03\n" + + "\x10DurableDirVolume\"\x10\n" + + "\x0eEmptyDirVolume\"\x89\x03\n" + "\x0eExternalVolume\x12*\n" + "\x11storage_volume_id\x18\x01 \x01(\tR\x0fstorageVolumeId\x12\x1f\n" + "\vvolume_type\x18\x02 \x01(\tR\n" + @@ -3575,7 +3623,7 @@ const file_atelet_proto_rawDesc = "" + "\x0eactor_metadata\x18\x01 \x01(\v2\x1f.atelet.ActorMetadataDataSourceR\ractorMetadata\x12@\n" + "\ftrust_bundle\x18\x02 \x01(\v2\x1d.atelet.TrustBundleDataSourceR\vtrustBundle\"S\n" + "\x10SystemInfoVolume\x12?\n" + - "\fdata_sources\x18\x01 \x03(\v2\x1c.atelet.SystemInfoDataSourceR\vdataSources\"\xf7\x01\n" + + "\fdata_sources\x18\x01 \x03(\v2\x1c.atelet.SystemInfoDataSourceR\vdataSources\"\xac\x02\n" + "\x06Volume\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x129\n" + "\vdurable_dir\x18\x02 \x01(\v2\x18.atelet.DurableDirVolumeR\n" + @@ -3583,7 +3631,8 @@ const file_atelet_proto_rawDesc = "" + "\bexternal\x18\x03 \x01(\v2\x16.atelet.ExternalVolumeR\bexternal\x129\n" + "\vsystem_info\x18\x04 \x01(\v2\x18.atelet.SystemInfoVolumeR\n" + "systemInfo\x12/\n" + - "\x05image\x18\x05 \x01(\v2\x19.atelet.ImageVolumeSourceR\x05image\"@\n" + + "\x05image\x18\x05 \x01(\v2\x19.atelet.ImageVolumeSourceR\x05image\x123\n" + + "\tempty_dir\x18\x06 \x01(\v2\x16.atelet.EmptyDirVolumeR\bemptyDir\"@\n" + "\vVolumeMount\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12\x1d\n" + "\n" + @@ -3708,7 +3757,7 @@ func file_atelet_proto_rawDescGZIP() []byte { } var file_atelet_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_atelet_proto_msgTypes = make([]protoimpl.MessageInfo, 51) +var file_atelet_proto_msgTypes = make([]protoimpl.MessageInfo, 52) var file_atelet_proto_goTypes = []any{ (ActorMetadataField)(0), // 0: atelet.ActorMetadataField (CheckpointType)(0), // 1: atelet.CheckpointType @@ -3734,36 +3783,37 @@ var file_atelet_proto_goTypes = []any{ (*SandboxAssets)(nil), // 21: atelet.SandboxAssets (*WorkloadSpec)(nil), // 22: atelet.WorkloadSpec (*DurableDirVolume)(nil), // 23: atelet.DurableDirVolume - (*ExternalVolume)(nil), // 24: atelet.ExternalVolume - (*ImageVolumeSource)(nil), // 25: atelet.ImageVolumeSource - (*ActorMetadataItem)(nil), // 26: atelet.ActorMetadataItem - (*ActorMetadataDataSource)(nil), // 27: atelet.ActorMetadataDataSource - (*TrustBundleDataSource)(nil), // 28: atelet.TrustBundleDataSource - (*SystemInfoDataSource)(nil), // 29: atelet.SystemInfoDataSource - (*SystemInfoVolume)(nil), // 30: atelet.SystemInfoVolume - (*Volume)(nil), // 31: atelet.Volume - (*VolumeMount)(nil), // 32: atelet.VolumeMount - (*Container)(nil), // 33: atelet.Container - (*SecurityContext)(nil), // 34: atelet.SecurityContext - (*Capabilities)(nil), // 35: atelet.Capabilities - (*ResourceLimits)(nil), // 36: atelet.ResourceLimits - (*EnvEntry)(nil), // 37: atelet.EnvEntry - (*WakeupProbe)(nil), // 38: atelet.WakeupProbe - (*HttpGetAction)(nil), // 39: atelet.HttpGetAction - (*RunResponse)(nil), // 40: atelet.RunResponse - (*LocalCheckpointConfiguration)(nil), // 41: atelet.LocalCheckpointConfiguration - (*ExternalCheckpointConfiguration)(nil), // 42: atelet.ExternalCheckpointConfiguration - (*ExternalRestoreConfiguration)(nil), // 43: atelet.ExternalRestoreConfiguration - (*CheckpointRequest)(nil), // 44: atelet.CheckpointRequest - (*CheckpointResponse)(nil), // 45: atelet.CheckpointResponse - (*UploadPausedCheckpointRequest)(nil), // 46: atelet.UploadPausedCheckpointRequest - (*UploadPausedCheckpointResponse)(nil), // 47: atelet.UploadPausedCheckpointResponse - (*RestoreRequest)(nil), // 48: atelet.RestoreRequest - (*RestoreResponse)(nil), // 49: atelet.RestoreResponse - nil, // 50: atelet.ArchAssets.FilesEntry - nil, // 51: atelet.SandboxAssets.AssetsEntry - nil, // 52: atelet.ExternalVolume.VolumeContextEntry - nil, // 53: atelet.ExternalVolume.PublishContextEntry + (*EmptyDirVolume)(nil), // 24: atelet.EmptyDirVolume + (*ExternalVolume)(nil), // 25: atelet.ExternalVolume + (*ImageVolumeSource)(nil), // 26: atelet.ImageVolumeSource + (*ActorMetadataItem)(nil), // 27: atelet.ActorMetadataItem + (*ActorMetadataDataSource)(nil), // 28: atelet.ActorMetadataDataSource + (*TrustBundleDataSource)(nil), // 29: atelet.TrustBundleDataSource + (*SystemInfoDataSource)(nil), // 30: atelet.SystemInfoDataSource + (*SystemInfoVolume)(nil), // 31: atelet.SystemInfoVolume + (*Volume)(nil), // 32: atelet.Volume + (*VolumeMount)(nil), // 33: atelet.VolumeMount + (*Container)(nil), // 34: atelet.Container + (*SecurityContext)(nil), // 35: atelet.SecurityContext + (*Capabilities)(nil), // 36: atelet.Capabilities + (*ResourceLimits)(nil), // 37: atelet.ResourceLimits + (*EnvEntry)(nil), // 38: atelet.EnvEntry + (*WakeupProbe)(nil), // 39: atelet.WakeupProbe + (*HttpGetAction)(nil), // 40: atelet.HttpGetAction + (*RunResponse)(nil), // 41: atelet.RunResponse + (*LocalCheckpointConfiguration)(nil), // 42: atelet.LocalCheckpointConfiguration + (*ExternalCheckpointConfiguration)(nil), // 43: atelet.ExternalCheckpointConfiguration + (*ExternalRestoreConfiguration)(nil), // 44: atelet.ExternalRestoreConfiguration + (*CheckpointRequest)(nil), // 45: atelet.CheckpointRequest + (*CheckpointResponse)(nil), // 46: atelet.CheckpointResponse + (*UploadPausedCheckpointRequest)(nil), // 47: atelet.UploadPausedCheckpointRequest + (*UploadPausedCheckpointResponse)(nil), // 48: atelet.UploadPausedCheckpointResponse + (*RestoreRequest)(nil), // 49: atelet.RestoreRequest + (*RestoreResponse)(nil), // 50: atelet.RestoreResponse + nil, // 51: atelet.ArchAssets.FilesEntry + nil, // 52: atelet.SandboxAssets.AssetsEntry + nil, // 53: atelet.ExternalVolume.VolumeContextEntry + nil, // 54: atelet.ExternalVolume.PublishContextEntry } var file_atelet_proto_depIdxs = []int32{ 7, // 0: atelet.RegisterWorkerRequest.capacity:type_name -> atelet.WorkerResources @@ -3777,64 +3827,65 @@ var file_atelet_proto_depIdxs = []int32{ 22, // 8: atelet.RunRequest.spec:type_name -> atelet.WorkloadSpec 21, // 9: atelet.RunRequest.sandbox_assets:type_name -> atelet.SandboxAssets 18, // 10: atelet.RunRequest.egress_gateway:type_name -> atelet.EgressGateway - 50, // 11: atelet.ArchAssets.files:type_name -> atelet.ArchAssets.FilesEntry - 51, // 12: atelet.SandboxAssets.assets:type_name -> atelet.SandboxAssets.AssetsEntry - 33, // 13: atelet.WorkloadSpec.containers:type_name -> atelet.Container - 31, // 14: atelet.WorkloadSpec.volumes:type_name -> atelet.Volume - 52, // 15: atelet.ExternalVolume.volume_context:type_name -> atelet.ExternalVolume.VolumeContextEntry - 53, // 16: atelet.ExternalVolume.publish_context:type_name -> atelet.ExternalVolume.PublishContextEntry + 51, // 11: atelet.ArchAssets.files:type_name -> atelet.ArchAssets.FilesEntry + 52, // 12: atelet.SandboxAssets.assets:type_name -> atelet.SandboxAssets.AssetsEntry + 34, // 13: atelet.WorkloadSpec.containers:type_name -> atelet.Container + 32, // 14: atelet.WorkloadSpec.volumes:type_name -> atelet.Volume + 53, // 15: atelet.ExternalVolume.volume_context:type_name -> atelet.ExternalVolume.VolumeContextEntry + 54, // 16: atelet.ExternalVolume.publish_context:type_name -> atelet.ExternalVolume.PublishContextEntry 0, // 17: atelet.ActorMetadataItem.field:type_name -> atelet.ActorMetadataField - 26, // 18: atelet.ActorMetadataDataSource.items:type_name -> atelet.ActorMetadataItem - 27, // 19: atelet.SystemInfoDataSource.actor_metadata:type_name -> atelet.ActorMetadataDataSource - 28, // 20: atelet.SystemInfoDataSource.trust_bundle:type_name -> atelet.TrustBundleDataSource - 29, // 21: atelet.SystemInfoVolume.data_sources:type_name -> atelet.SystemInfoDataSource + 27, // 18: atelet.ActorMetadataDataSource.items:type_name -> atelet.ActorMetadataItem + 28, // 19: atelet.SystemInfoDataSource.actor_metadata:type_name -> atelet.ActorMetadataDataSource + 29, // 20: atelet.SystemInfoDataSource.trust_bundle:type_name -> atelet.TrustBundleDataSource + 30, // 21: atelet.SystemInfoVolume.data_sources:type_name -> atelet.SystemInfoDataSource 23, // 22: atelet.Volume.durable_dir:type_name -> atelet.DurableDirVolume - 24, // 23: atelet.Volume.external:type_name -> atelet.ExternalVolume - 30, // 24: atelet.Volume.system_info:type_name -> atelet.SystemInfoVolume - 25, // 25: atelet.Volume.image:type_name -> atelet.ImageVolumeSource - 37, // 26: atelet.Container.env:type_name -> atelet.EnvEntry - 38, // 27: atelet.Container.wakeup_probe:type_name -> atelet.WakeupProbe - 32, // 28: atelet.Container.volume_mounts:type_name -> atelet.VolumeMount - 34, // 29: atelet.Container.security_context:type_name -> atelet.SecurityContext - 36, // 30: atelet.Container.resources:type_name -> atelet.ResourceLimits - 35, // 31: atelet.SecurityContext.capabilities:type_name -> atelet.Capabilities - 39, // 32: atelet.WakeupProbe.http_get:type_name -> atelet.HttpGetAction - 22, // 33: atelet.CheckpointRequest.spec:type_name -> atelet.WorkloadSpec - 1, // 34: atelet.CheckpointRequest.type:type_name -> atelet.CheckpointType - 41, // 35: atelet.CheckpointRequest.local_config:type_name -> atelet.LocalCheckpointConfiguration - 42, // 36: atelet.CheckpointRequest.external_config:type_name -> atelet.ExternalCheckpointConfiguration - 2, // 37: atelet.CheckpointRequest.fidelity:type_name -> atelet.SnapshotFidelity - 2, // 38: atelet.UploadPausedCheckpointRequest.desired_fidelity:type_name -> atelet.SnapshotFidelity - 22, // 39: atelet.RestoreRequest.spec:type_name -> atelet.WorkloadSpec - 1, // 40: atelet.RestoreRequest.type:type_name -> atelet.CheckpointType - 41, // 41: atelet.RestoreRequest.local_config:type_name -> atelet.LocalCheckpointConfiguration - 43, // 42: atelet.RestoreRequest.external_config:type_name -> atelet.ExternalRestoreConfiguration - 2, // 43: atelet.RestoreRequest.fidelity:type_name -> atelet.SnapshotFidelity - 18, // 44: atelet.RestoreRequest.egress_gateway:type_name -> atelet.EgressGateway - 21, // 45: atelet.RestoreRequest.sandbox_assets:type_name -> atelet.SandboxAssets - 19, // 46: atelet.ArchAssets.FilesEntry.value:type_name -> atelet.AssetFile - 20, // 47: atelet.SandboxAssets.AssetsEntry.value:type_name -> atelet.ArchAssets - 13, // 48: atelet.AteomSupport.MintActorCertificate:input_type -> atelet.MintActorCertificateRequest - 3, // 49: atelet.AteomSupport.RegisterWorker:input_type -> atelet.RegisterWorkerRequest - 11, // 50: atelet.AteomSupport.RequestActorSuspend:input_type -> atelet.RequestActorSuspendRequest - 17, // 51: atelet.AteomHerder.Run:input_type -> atelet.RunRequest - 44, // 52: atelet.AteomHerder.Checkpoint:input_type -> atelet.CheckpointRequest - 48, // 53: atelet.AteomHerder.Restore:input_type -> atelet.RestoreRequest - 46, // 54: atelet.AteomHerder.UploadPausedCheckpoint:input_type -> atelet.UploadPausedCheckpointRequest - 15, // 55: atelet.AteomHerder.Terminate:input_type -> atelet.TerminateRequest - 14, // 56: atelet.AteomSupport.MintActorCertificate:output_type -> atelet.MintActorCertificateResponse - 10, // 57: atelet.AteomSupport.RegisterWorker:output_type -> atelet.RegisterWorkerResponse - 12, // 58: atelet.AteomSupport.RequestActorSuspend:output_type -> atelet.RequestActorSuspendResponse - 40, // 59: atelet.AteomHerder.Run:output_type -> atelet.RunResponse - 45, // 60: atelet.AteomHerder.Checkpoint:output_type -> atelet.CheckpointResponse - 49, // 61: atelet.AteomHerder.Restore:output_type -> atelet.RestoreResponse - 47, // 62: atelet.AteomHerder.UploadPausedCheckpoint:output_type -> atelet.UploadPausedCheckpointResponse - 16, // 63: atelet.AteomHerder.Terminate:output_type -> atelet.TerminateResponse - 56, // [56:64] is the sub-list for method output_type - 48, // [48:56] is the sub-list for method input_type - 48, // [48:48] is the sub-list for extension type_name - 48, // [48:48] is the sub-list for extension extendee - 0, // [0:48] is the sub-list for field type_name + 25, // 23: atelet.Volume.external:type_name -> atelet.ExternalVolume + 31, // 24: atelet.Volume.system_info:type_name -> atelet.SystemInfoVolume + 26, // 25: atelet.Volume.image:type_name -> atelet.ImageVolumeSource + 24, // 26: atelet.Volume.empty_dir:type_name -> atelet.EmptyDirVolume + 38, // 27: atelet.Container.env:type_name -> atelet.EnvEntry + 39, // 28: atelet.Container.wakeup_probe:type_name -> atelet.WakeupProbe + 33, // 29: atelet.Container.volume_mounts:type_name -> atelet.VolumeMount + 35, // 30: atelet.Container.security_context:type_name -> atelet.SecurityContext + 37, // 31: atelet.Container.resources:type_name -> atelet.ResourceLimits + 36, // 32: atelet.SecurityContext.capabilities:type_name -> atelet.Capabilities + 40, // 33: atelet.WakeupProbe.http_get:type_name -> atelet.HttpGetAction + 22, // 34: atelet.CheckpointRequest.spec:type_name -> atelet.WorkloadSpec + 1, // 35: atelet.CheckpointRequest.type:type_name -> atelet.CheckpointType + 42, // 36: atelet.CheckpointRequest.local_config:type_name -> atelet.LocalCheckpointConfiguration + 43, // 37: atelet.CheckpointRequest.external_config:type_name -> atelet.ExternalCheckpointConfiguration + 2, // 38: atelet.CheckpointRequest.fidelity:type_name -> atelet.SnapshotFidelity + 2, // 39: atelet.UploadPausedCheckpointRequest.desired_fidelity:type_name -> atelet.SnapshotFidelity + 22, // 40: atelet.RestoreRequest.spec:type_name -> atelet.WorkloadSpec + 1, // 41: atelet.RestoreRequest.type:type_name -> atelet.CheckpointType + 42, // 42: atelet.RestoreRequest.local_config:type_name -> atelet.LocalCheckpointConfiguration + 44, // 43: atelet.RestoreRequest.external_config:type_name -> atelet.ExternalRestoreConfiguration + 2, // 44: atelet.RestoreRequest.fidelity:type_name -> atelet.SnapshotFidelity + 18, // 45: atelet.RestoreRequest.egress_gateway:type_name -> atelet.EgressGateway + 21, // 46: atelet.RestoreRequest.sandbox_assets:type_name -> atelet.SandboxAssets + 19, // 47: atelet.ArchAssets.FilesEntry.value:type_name -> atelet.AssetFile + 20, // 48: atelet.SandboxAssets.AssetsEntry.value:type_name -> atelet.ArchAssets + 13, // 49: atelet.AteomSupport.MintActorCertificate:input_type -> atelet.MintActorCertificateRequest + 3, // 50: atelet.AteomSupport.RegisterWorker:input_type -> atelet.RegisterWorkerRequest + 11, // 51: atelet.AteomSupport.RequestActorSuspend:input_type -> atelet.RequestActorSuspendRequest + 17, // 52: atelet.AteomHerder.Run:input_type -> atelet.RunRequest + 45, // 53: atelet.AteomHerder.Checkpoint:input_type -> atelet.CheckpointRequest + 49, // 54: atelet.AteomHerder.Restore:input_type -> atelet.RestoreRequest + 47, // 55: atelet.AteomHerder.UploadPausedCheckpoint:input_type -> atelet.UploadPausedCheckpointRequest + 15, // 56: atelet.AteomHerder.Terminate:input_type -> atelet.TerminateRequest + 14, // 57: atelet.AteomSupport.MintActorCertificate:output_type -> atelet.MintActorCertificateResponse + 10, // 58: atelet.AteomSupport.RegisterWorker:output_type -> atelet.RegisterWorkerResponse + 12, // 59: atelet.AteomSupport.RequestActorSuspend:output_type -> atelet.RequestActorSuspendResponse + 41, // 60: atelet.AteomHerder.Run:output_type -> atelet.RunResponse + 46, // 61: atelet.AteomHerder.Checkpoint:output_type -> atelet.CheckpointResponse + 50, // 62: atelet.AteomHerder.Restore:output_type -> atelet.RestoreResponse + 48, // 63: atelet.AteomHerder.UploadPausedCheckpoint:output_type -> atelet.UploadPausedCheckpointResponse + 16, // 64: atelet.AteomHerder.Terminate:output_type -> atelet.TerminateResponse + 57, // [57:65] is the sub-list for method output_type + 49, // [49:57] is the sub-list for method input_type + 49, // [49:49] is the sub-list for extension type_name + 49, // [49:49] is the sub-list for extension extendee + 0, // [0:49] is the sub-list for field type_name } func init() { file_atelet_proto_init() } @@ -3843,14 +3894,14 @@ func file_atelet_proto_init() { return } file_atelet_proto_msgTypes[14].OneofWrappers = []any{} - file_atelet_proto_msgTypes[45].OneofWrappers = []any{} + file_atelet_proto_msgTypes[46].OneofWrappers = []any{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_atelet_proto_rawDesc), len(file_atelet_proto_rawDesc)), NumEnums: 3, - NumMessages: 51, + NumMessages: 52, NumExtensions: 0, NumServices: 2, }, diff --git a/internal/proto/ateletpb/atelet.proto b/internal/proto/ateletpb/atelet.proto index 5b635efb77..1955e3dd7e 100644 --- a/internal/proto/ateletpb/atelet.proto +++ b/internal/proto/ateletpb/atelet.proto @@ -451,6 +451,10 @@ message WorkloadSpec { message DurableDirVolume { } +// EmptyDirVolume is an empty host directory at the external volume path. +message EmptyDirVolume { +} + message ExternalVolume { // Required, unlike the actor status counterpart: the control plane only // sends volumes that finished provisioning. @@ -582,7 +586,7 @@ message Volume { // +k8s:format=k8s-short-name string name = 1; - // Exactly one of durable_dir / external / system_info / image must be set. + // Exactly one of durable_dir / external / system_info / image / empty_dir must be set. // // +k8s:optional // +k8s:unionMember @@ -599,6 +603,10 @@ message Volume { // +k8s:optional // +k8s:unionMember ImageVolumeSource image = 5; + + // +k8s:optional + // +k8s:unionMember + EmptyDirVolume empty_dir = 6; } message VolumeMount { From 337473c00f6c04ad562dfe205b38e9ceb8287017 Mon Sep 17 00:00:00 2001 From: Elijah Rodriguez Date: Wed, 14 Oct 2026 10:34:51 -0700 Subject: [PATCH 03/12] ateapi: add the SharedVolume resource A SharedVolume is an atespace-scoped CSI volume whose lifetime is independent of any actor. It is provisioned from a StorageClass or registers a volume that already exists, carries an immutable access mode, and is removed either manually or when the last actor referencing it is deleted, according to its delete trigger. Deleting the record also deletes the storage. This adds the resource, its Postgres table and store methods, the create/get/list/update/delete RPCs, and kubectl-ate commands. Nothing references a volume yet; actor references arrive separately. Co-Authored-By: Claude Fable 5.1 --- .../internal/apivalidation/shared_volume.go | 124 + .../apivalidation/shared_volume_test.go | 117 + .../apivalidation/zz_generated.validation.go | 1056 ++++++- .../functionaltest/shared_volume_test.go | 271 ++ cmd/ateapi/internal/controlapi/service.go | 7 + .../internal/controlapi/shared_volume.go | 151 + .../internal/controlapi/shared_volume_test.go | 304 ++ cmd/ateapi/internal/controlapi/workflow.go | 4 + .../controlapi/workflow_shared_volume.go | 290 ++ cmd/ateapi/internal/defaults/defaults.go | 11 + cmd/ateapi/internal/defaults/defaults_test.go | 8 + .../internal/store/atepg/common_test.go | 2 +- .../migrations/000004_shared_volumes.sql | 27 + cmd/ateapi/internal/store/atepg/pagetoken.go | 1 + .../internal/store/atepg/partition_test.go | 2 +- .../internal/store/atepg/shared_volume.go | 297 ++ cmd/ateapi/internal/store/store.go | 20 + .../internal/store/storecontract/contract.go | 299 ++ .../internal/store/storetest/storetest.go | 13 + cmd/kubectl-ate/internal/cmd/shared_volume.go | 268 ++ .../internal/cmd/shared_volume_test.go | 138 + cmd/kubectl-ate/internal/printer/printer.go | 79 + .../internal/printer/printer_test.go | 110 + internal/resources/resourceref.go | 17 + pkg/proto/ateapipb/ateapi.pb.go | 2470 +++++++++++------ pkg/proto/ateapipb/ateapi.proto | 242 ++ pkg/proto/ateapipb/ateapi_grpc.pb.go | 200 ++ tools/apitool/internal/model/model.go | 1 + 28 files changed, 5660 insertions(+), 869 deletions(-) create mode 100644 cmd/ateapi/internal/apivalidation/shared_volume.go create mode 100644 cmd/ateapi/internal/apivalidation/shared_volume_test.go create mode 100644 cmd/ateapi/internal/controlapi/functionaltest/shared_volume_test.go create mode 100644 cmd/ateapi/internal/controlapi/shared_volume.go create mode 100644 cmd/ateapi/internal/controlapi/shared_volume_test.go create mode 100644 cmd/ateapi/internal/controlapi/workflow_shared_volume.go create mode 100644 cmd/ateapi/internal/store/atepg/migrations/000004_shared_volumes.sql create mode 100644 cmd/ateapi/internal/store/atepg/shared_volume.go create mode 100644 cmd/kubectl-ate/internal/cmd/shared_volume.go create mode 100644 cmd/kubectl-ate/internal/cmd/shared_volume_test.go diff --git a/cmd/ateapi/internal/apivalidation/shared_volume.go b/cmd/ateapi/internal/apivalidation/shared_volume.go new file mode 100644 index 0000000000..4d852b51cf --- /dev/null +++ b/cmd/ateapi/internal/apivalidation/shared_volume.go @@ -0,0 +1,124 @@ +// 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 apivalidation + +import ( + "context" + "fmt" + + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" + "k8s.io/apimachinery/pkg/api/operation" + "k8s.io/apimachinery/pkg/api/resource" + "k8s.io/apimachinery/pkg/api/validate" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +func ValidateCreateSharedVolumeRequest(ctx context.Context, req *ateapipb.CreateSharedVolumeRequest) field.ErrorList { + op := operation.Operation{Type: operation.Create} + return Validate_CreateSharedVolumeRequest(ctx, op, nil, req, nil) +} + +func ValidateGetSharedVolumeRequest(ctx context.Context, req *ateapipb.GetSharedVolumeRequest) field.ErrorList { + op := operation.Operation{Type: operation.Create} + return Validate_GetSharedVolumeRequest(ctx, op, nil, req, nil) +} + +func ValidateListSharedVolumesRequest(ctx context.Context, req *ateapipb.ListSharedVolumesRequest) field.ErrorList { + op := operation.Operation{Type: operation.Create} + return Validate_ListSharedVolumesRequest(ctx, op, nil, req, nil) +} + +// The request is validated as a create; the result is validated as an update +// once the stored value is known, like UpdateTagRequest. +func ValidateUpdateSharedVolumeRequest(ctx context.Context, req *ateapipb.UpdateSharedVolumeRequest) field.ErrorList { + op := operation.Operation{Type: operation.Create} + return Validate_UpdateSharedVolumeRequest(ctx, op, nil, req, nil) +} + +func ValidateDeleteSharedVolumeRequest(ctx context.Context, req *ateapipb.DeleteSharedVolumeRequest) field.ErrorList { + op := operation.Operation{Type: operation.Create} + return Validate_DeleteSharedVolumeRequest(ctx, op, nil, req, nil) +} + +func ValidateSharedVolumeUpdate(ctx context.Context, fldPath *field.Path, newVal, oldVal *ateapipb.SharedVolume) field.ErrorList { + op := operation.Operation{Type: operation.Update} + return Validate_SharedVolume(ctx, op, fldPath, newVal, oldVal) +} + +func ValidateCustom_CreateSharedVolumeRequest(_ context.Context, _ operation.Operation, p *field.Path, req, _ *ateapipb.CreateSharedVolumeRequest) field.ErrorList { + volume := req.GetSharedVolume() + if volume == nil { + return nil + } + volumePath := p.Child("shared_volume") + storageClassName, volumeID := volume.GetStorageClassName(), volume.GetVolumeId() + + var errs field.ErrorList + // TODO: accept READ_WRITE_MANY once concurrent holders are supported. + if mode := volume.GetAccessMode(); mode != ateapipb.AccessMode_ACCESS_MODE_UNSPECIFIED && mode != ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_ONCE { + errs = append(errs, field.NotSupported(volumePath.Child("access_mode"), mode.String(), []string{ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_ONCE.String()})) + } + switch { + case storageClassName == "" && volumeID == "": + errs = append(errs, field.Required(volumePath.Child("storage_class_name"), "one of storage_class_name or volume_id is required")) + case volumeID != "": + if volume.GetCapacity() != "" { + errs = append(errs, field.Forbidden(volumePath.Child("capacity"), "must not be set with volume_id")) + } + if volume.GetVolumeType() == "" && storageClassName == "" { + errs = append(errs, field.Required(volumePath.Child("volume_type"), "required with volume_id unless storage_class_name is set")) + } + default: + if volume.GetVolumeType() != "" { + errs = append(errs, field.Forbidden(volumePath.Child("volume_type"), "must not be set with storage_class_name; it is taken from the class's provisioner")) + } + if len(volume.GetVolumeContext()) > 0 { + errs = append(errs, field.Forbidden(volumePath.Child("volume_context"), "must not be set with storage_class_name; it is returned by the storage system")) + } + if volume.GetCapacity() == "" { + errs = append(errs, field.Required(volumePath.Child("capacity"), "required with storage_class_name")) + } + } + return errs +} + +func ValidateCustom_SharedVolume_Capacity(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ *string) field.ErrorList { + if value == nil || *value == "" { + return nil + } + if _, err := resource.ParseQuantity(*value); err != nil { + return field.ErrorList{field.Invalid(fldPath, *value, fmt.Sprintf("must be a Kubernetes resource quantity: %v", err))} + } + return nil +} + +// This exists only because nested subfield tags are not supported yet. +func ValidateCustom_UpdateSharedVolumeRequest_SharedVolume(ctx context.Context, op operation.Operation, fldPath *field.Path, volume, _ *ateapipb.SharedVolume) field.ErrorList { + if volume == nil || volume.Metadata == nil { + return nil + } + errs := Validate_ResourceMetadata(ctx, op, fldPath.Child("metadata"), volume.Metadata, nil) + errs = append(errs, validate.RequiredValue(ctx, op, fldPath.Child("metadata", "atespace"), &volume.Metadata.Atespace, nil)...) + return errs +} + +// An SharedVolume names its storage the same way an ExternalVolumeRef does. +func ValidateCustom_SharedVolume_VolumeType(ctx context.Context, op operation.Operation, fldPath *field.Path, value, oldValue *string) field.ErrorList { + return ValidateCustom_ExternalVolumeRef_VolumeType(ctx, op, fldPath, value, oldValue) +} + +func ValidateCustom_SharedVolume_VolumeId(ctx context.Context, op operation.Operation, fldPath *field.Path, value, oldValue *string) field.ErrorList { + return ValidateCustom_ExternalVolumeRef_StorageVolumeId(ctx, op, fldPath, value, oldValue) +} diff --git a/cmd/ateapi/internal/apivalidation/shared_volume_test.go b/cmd/ateapi/internal/apivalidation/shared_volume_test.go new file mode 100644 index 0000000000..c1554805a7 --- /dev/null +++ b/cmd/ateapi/internal/apivalidation/shared_volume_test.go @@ -0,0 +1,117 @@ +// 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 apivalidation + +import ( + "context" + "testing" + + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" + "github.com/google/go-cmp/cmp" + "k8s.io/apimachinery/pkg/api/operation" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +func TestValidateCustomCreateSharedVolumeRequest(t *testing.T) { + tests := []struct { + name string + volume *ateapipb.SharedVolume + wantFields []string + }{ + { + name: "provisioning from a class", + volume: &ateapipb.SharedVolume{StorageClassName: "standard", Capacity: "10Gi"}, + }, + { + name: "registering an existing volume", + volume: &ateapipb.SharedVolume{VolumeId: "disk-1", VolumeType: "mock"}, + }, + { + name: "registering an existing volume under a named class", + volume: &ateapipb.SharedVolume{VolumeId: "disk-1", StorageClassName: "standard"}, + }, + { + name: "neither a class nor an ID", + volume: &ateapipb.SharedVolume{}, + wantFields: []string{"shared_volume.storage_class_name"}, + }, + { + name: "a size for a volume that already exists", + volume: &ateapipb.SharedVolume{VolumeId: "disk-1", VolumeType: "mock", Capacity: "10Gi"}, + wantFields: []string{"shared_volume.capacity"}, + }, + { + name: "an ID with no driver to reach it through", + volume: &ateapipb.SharedVolume{VolumeId: "disk-1"}, + wantFields: []string{"shared_volume.volume_type"}, + }, + { + name: "a driver alongside the class that supplies one", + volume: &ateapipb.SharedVolume{StorageClassName: "standard", VolumeType: "mock", Capacity: "10Gi"}, + wantFields: []string{"shared_volume.volume_type"}, + }, + { + name: "driver metadata for a volume that does not exist yet", + volume: &ateapipb.SharedVolume{StorageClassName: "standard", Capacity: "10Gi", VolumeContext: map[string]string{"fsType": "ext4"}}, + wantFields: []string{"shared_volume.volume_context"}, + }, + { + name: "provisioning without a size", + volume: &ateapipb.SharedVolume{StorageClassName: "standard"}, + wantFields: []string{"shared_volume.capacity"}, + }, + { + name: "read write many is not supported yet", + volume: &ateapipb.SharedVolume{StorageClassName: "standard", Capacity: "10Gi", AccessMode: ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_MANY}, + wantFields: []string{"shared_volume.access_mode"}, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + req := &ateapipb.CreateSharedVolumeRequest{SharedVolume: tc.volume} + errs := ValidateCustom_CreateSharedVolumeRequest(context.Background(), operation.Operation{Type: operation.Create}, nil, req, nil) + + var gotFields []string + for _, err := range errs { + gotFields = append(gotFields, err.Field) + } + if diff := cmp.Diff(tc.wantFields, gotFields); diff != "" { + t.Errorf("offending fields mismatch (-want +got):\n%s", diff) + } + }) + } +} + +func TestValidateCustomSharedVolumeCapacity(t *testing.T) { + tests := []struct { + value string + wantErr bool + }{ + {value: ""}, + {value: "10Gi"}, + {value: "1500m"}, + {value: "ten gigs", wantErr: true}, + {value: "10GiB", wantErr: true}, + } + for _, tc := range tests { + t.Run(tc.value, func(t *testing.T) { + value := tc.value + errs := ValidateCustom_SharedVolume_Capacity(context.Background(), operation.Operation{Type: operation.Create}, field.NewPath("capacity"), &value, nil) + if gotErr := len(errs) > 0; gotErr != tc.wantErr { + t.Errorf("ValidateCustom_SharedVolume_Capacity(%q) errors = %v, wantErr %v", tc.value, errs, tc.wantErr) + } + }) + } +} diff --git a/cmd/ateapi/internal/apivalidation/zz_generated.validation.go b/cmd/ateapi/internal/apivalidation/zz_generated.validation.go index eb7fc53ed5..4e85fba18b 100644 --- a/cmd/ateapi/internal/apivalidation/zz_generated.validation.go +++ b/cmd/ateapi/internal/apivalidation/zz_generated.validation.go @@ -631,6 +631,107 @@ func Validate_ActorMetadataItem( return errs } +// Validate_ActorRef validates an instance of ActorRef according +// to declarative validation rules in the API schema. +func Validate_ActorRef( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *ateapipb.ActorRef) (errs field.ErrorList) { + + { // field ateapipb.ActorRef.ActorUid + 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.MaxLength(ctx, op, fldPath, obj, oldObj, 253); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.ActorRef) *string { + return &oldObj.ActorUid + }) + errs = append(errs, fn(fldPath.Child("actor_uid"), &obj.ActorUid, oldVal, oldObj != nil)...) + } + + { // field ateapipb.ActorRef.ActorName + 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.ActorRef) *string { + return &oldObj.ActorName + }) + errs = append(errs, fn(fldPath.Child("actor_name"), &obj.ActorName, oldVal, oldObj != nil)...) + } + + { // field ateapipb.ActorRef.Active + 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.ActorRef) *bool { + return &oldObj.Active + }) + errs = append(errs, fn(fldPath.Child("active"), &obj.Active, oldVal, oldObj != nil)...) + } + + return errs +} + // Validate_ActorStatus validates an instance of ActorStatus according // to declarative validation rules in the API schema. func Validate_ActorStatus( @@ -2312,6 +2413,51 @@ func Validate_CreateGlobalAccessPolicyRequest( return errs } +// Validate_CreateSharedVolumeRequest validates an instance of CreateSharedVolumeRequest according +// to declarative validation rules in the API schema. +func Validate_CreateSharedVolumeRequest( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *ateapipb.CreateSharedVolumeRequest) (errs field.ErrorList) { + + // custom validation + if e := ValidateCustom_CreateSharedVolumeRequest(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + } + + { // field ateapipb.CreateSharedVolumeRequest.SharedVolume + fn := func( + fldPath *field.Path, + obj, oldObj *ateapipb.SharedVolume, + 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.RequiredPointer(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + // call the type's validation function + errs = append(errs, Validate_SharedVolume(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.CreateSharedVolumeRequest) *ateapipb.SharedVolume { + return oldObj.SharedVolume + }) + errs = append(errs, fn(fldPath.Child("shared_volume"), obj.SharedVolume, oldVal, oldObj != nil)...) + } + + return errs +} + // Validate_CreateTagRequest validates an instance of CreateTagRequest according // to declarative validation rules in the API schema. func Validate_CreateTagRequest( @@ -3156,6 +3302,91 @@ func Validate_DeleteOptions( return errs } +// Validate_DeleteSharedVolumeRequest validates an instance of DeleteSharedVolumeRequest according +// to declarative validation rules in the API schema. +func Validate_DeleteSharedVolumeRequest( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *ateapipb.DeleteSharedVolumeRequest) (errs field.ErrorList) { + + { // field ateapipb.DeleteSharedVolumeRequest.SharedVolume + fn := func( + fldPath *field.Path, + obj, oldObj *ateapipb.ObjectRef, + 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.RequiredPointer(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + func() { // cohort = "atespace" + earlyReturn := false + if e := validate.Subfield(ctx, op, fldPath, obj, oldObj, "atespace", + func(o *ateapipb.ObjectRef) *string { return &o.Atespace }, validate.DirectEqual, validate.RequiredValue).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.Subfield(ctx, op, fldPath, obj, oldObj, "atespace", + func(o *ateapipb.ObjectRef) *string { return &o.Atespace }, validate.DirectEqual, validate.OptionalValue).MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + }() + // call the type's validation function + errs = append(errs, Validate_ObjectRef(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.DeleteSharedVolumeRequest) *ateapipb.ObjectRef { + return oldObj.SharedVolume + }) + errs = append(errs, fn(fldPath.Child("shared_volume"), obj.SharedVolume, oldVal, oldObj != nil)...) + } + + { // field ateapipb.DeleteSharedVolumeRequest.Options + fn := func( + fldPath *field.Path, + obj, oldObj *ateapipb.DeleteOptions, + 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 + } + // call the type's validation function + errs = append(errs, Validate_DeleteOptions(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.DeleteSharedVolumeRequest) *ateapipb.DeleteOptions { + return oldObj.Options + }) + errs = append(errs, fn(fldPath.Child("options"), obj.Options, oldVal, oldObj != nil)...) + } + + return errs +} + // Validate_DeleteTagRequest validates an instance of DeleteTagRequest according // to declarative validation rules in the API schema. func Validate_DeleteTagRequest( @@ -4416,6 +4647,61 @@ func Validate_GetGlobalAccessPolicyRequest( return errs } +// Validate_GetSharedVolumeRequest validates an instance of GetSharedVolumeRequest according +// to declarative validation rules in the API schema. +func Validate_GetSharedVolumeRequest( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *ateapipb.GetSharedVolumeRequest) (errs field.ErrorList) { + + { // field ateapipb.GetSharedVolumeRequest.SharedVolume + fn := func( + fldPath *field.Path, + obj, oldObj *ateapipb.ObjectRef, + 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.RequiredPointer(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + func() { // cohort = "atespace" + earlyReturn := false + if e := validate.Subfield(ctx, op, fldPath, obj, oldObj, "atespace", + func(o *ateapipb.ObjectRef) *string { return &o.Atespace }, validate.DirectEqual, validate.RequiredValue).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.Subfield(ctx, op, fldPath, obj, oldObj, "atespace", + func(o *ateapipb.ObjectRef) *string { return &o.Atespace }, validate.DirectEqual, validate.OptionalValue).MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + }() + // call the type's validation function + errs = append(errs, Validate_ObjectRef(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.GetSharedVolumeRequest) *ateapipb.ObjectRef { + return oldObj.SharedVolume + }) + errs = append(errs, fn(fldPath.Child("shared_volume"), obj.SharedVolume, oldVal, oldObj != nil)...) + } + + return errs +} + // Validate_GetTagRequest validates an instance of GetTagRequest according // to declarative validation rules in the API schema. func Validate_GetTagRequest( @@ -5445,13 +5731,13 @@ func Validate_ListAtespacesRequest( return errs } -// Validate_ListTagsRequest validates an instance of ListTagsRequest according +// Validate_ListSharedVolumesRequest validates an instance of ListSharedVolumesRequest according // to declarative validation rules in the API schema. -func Validate_ListTagsRequest( +func Validate_ListSharedVolumesRequest( ctx context.Context, op operation.Operation, fldPath *field.Path, - obj, oldObj *ateapipb.ListTagsRequest) (errs field.ErrorList) { + obj, oldObj *ateapipb.ListSharedVolumesRequest) (errs field.ErrorList) { - { // field ateapipb.ListTagsRequest.Atespace + { // field ateapipb.ListSharedVolumesRequest.Atespace fn := func( fldPath *field.Path, obj, oldObj *string, @@ -5476,13 +5762,13 @@ func Validate_ListTagsRequest( return } oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.ListTagsRequest) *string { + func(oldObj *ateapipb.ListSharedVolumesRequest) *string { return &oldObj.Atespace }) errs = append(errs, fn(fldPath.Child("atespace"), &obj.Atespace, oldVal, oldObj != nil)...) } - { // field ateapipb.ListTagsRequest.PageSize + { // field ateapipb.ListSharedVolumesRequest.PageSize fn := func( fldPath *field.Path, obj, oldObj *int32, @@ -5507,13 +5793,13 @@ func Validate_ListTagsRequest( return } oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.ListTagsRequest) *int32 { + func(oldObj *ateapipb.ListSharedVolumesRequest) *int32 { return &oldObj.PageSize }) errs = append(errs, fn(fldPath.Child("page_size"), &obj.PageSize, oldVal, oldObj != nil)...) } - { // field ateapipb.ListTagsRequest.PageToken + { // field ateapipb.ListSharedVolumesRequest.PageToken fn := func( fldPath *field.Path, obj, oldObj *string, @@ -5538,7 +5824,109 @@ func Validate_ListTagsRequest( return } oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.ListTagsRequest) *string { + func(oldObj *ateapipb.ListSharedVolumesRequest) *string { + return &oldObj.PageToken + }) + errs = append(errs, fn(fldPath.Child("page_token"), &obj.PageToken, oldVal, oldObj != nil)...) + } + + return errs +} + +// Validate_ListTagsRequest validates an instance of ListTagsRequest according +// to declarative validation rules in the API schema. +func Validate_ListTagsRequest( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *ateapipb.ListTagsRequest) (errs field.ErrorList) { + + { // field ateapipb.ListTagsRequest.Atespace + 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 + } + if e := validate.ShortName(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.ListTagsRequest) *string { + return &oldObj.Atespace + }) + errs = append(errs, fn(fldPath.Child("atespace"), &obj.Atespace, oldVal, oldObj != nil)...) + } + + { // field ateapipb.ListTagsRequest.PageSize + fn := func( + fldPath *field.Path, + obj, oldObj *int32, + 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 + } + if e := validate.Minimum(ctx, op, fldPath, obj, oldObj, 1); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.ListTagsRequest) *int32 { + return &oldObj.PageSize + }) + errs = append(errs, fn(fldPath.Child("page_size"), &obj.PageSize, oldVal, oldObj != nil)...) + } + + { // field ateapipb.ListTagsRequest.PageToken + 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 + } + 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.ListTagsRequest) *string { return &oldObj.PageToken }) errs = append(errs, fn(fldPath.Child("page_token"), &obj.PageToken, oldVal, oldObj != nil)...) @@ -7286,48 +7674,66 @@ func Validate_Selector( return errs } -// Validate_Snapshot validates an instance of Snapshot according +// Validate_SharedVolume validates an instance of SharedVolume according // to declarative validation rules in the API schema. -func Validate_Snapshot( +func Validate_SharedVolume( ctx context.Context, op operation.Operation, fldPath *field.Path, - obj, oldObj *ateapipb.Snapshot) (errs field.ErrorList) { + obj, oldObj *ateapipb.SharedVolume) (errs field.ErrorList) { - { // field ateapipb.Snapshot.Uuid + { // field ateapipb.SharedVolume.Metadata fn := func( fldPath *field.Path, - obj, oldObj *string, + obj, oldObj *ateapipb.ResourceMetadata, 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) { + if ateDeepEqual(obj, oldObj) { return nil } } // call field-attached validations earlyReturn := false - if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + if e := validate.RequiredPointer(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...) - } + func() { // cohort = "atespace" + earlyReturn := false + if e := validate.Subfield(ctx, op, fldPath, obj, oldObj, "atespace", + func(o *ateapipb.ResourceMetadata) *string { return &o.Atespace }, validate.DirectEqual, validate.RequiredValue).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.Subfield(ctx, op, fldPath, obj, oldObj, "atespace", + func(o *ateapipb.ResourceMetadata) *string { return &o.Atespace }, validate.DirectEqual, validate.Immutable).MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if e := validate.Subfield(ctx, op, fldPath, obj, oldObj, "atespace", + func(o *ateapipb.ResourceMetadata) *string { return &o.Atespace }, validate.DirectEqual, validate.OptionalValue).MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + }() + // call the type's validation function + errs = append(errs, Validate_ResourceMetadata(ctx, op, fldPath, obj, oldObj)...) return } oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.Snapshot) *string { - return &oldObj.Uuid + func(oldObj *ateapipb.SharedVolume) *ateapipb.ResourceMetadata { + return oldObj.Metadata }) - errs = append(errs, fn(fldPath.Child("uuid"), &obj.Uuid, oldVal, oldObj != nil)...) + errs = append(errs, fn(fldPath.Child("metadata"), obj.Metadata, oldVal, oldObj != nil)...) } - { // field ateapipb.Snapshot.Generation + { // field ateapipb.SharedVolume.DeleteTrigger fn := func( fldPath *field.Path, - obj, oldObj *int32, + obj, oldObj *ateapipb.DeleteTrigger, oldValueCorrelated bool) (errs field.ErrorList) { // don't revalidate unchanged data if oldValueCorrelated && op.Type == operation.Update { @@ -7337,29 +7743,31 @@ func Validate_Snapshot( } // call field-attached validations earlyReturn := false - if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { - errs = append(errs, e...) + if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { earlyReturn = true } if earlyReturn { return // do not proceed } + if e := validate.Maximum(ctx, op, fldPath, obj, oldObj, 2); len(e) != 0 { + errs = append(errs, e...) + } if e := validate.Minimum(ctx, op, fldPath, obj, oldObj, 1); len(e) != 0 { errs = append(errs, e...) } return } oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.Snapshot) *int32 { - return &oldObj.Generation + func(oldObj *ateapipb.SharedVolume) *ateapipb.DeleteTrigger { + return &oldObj.DeleteTrigger }) - errs = append(errs, fn(fldPath.Child("generation"), &obj.Generation, oldVal, oldObj != nil)...) + errs = append(errs, fn(fldPath.Child("delete_trigger"), &obj.DeleteTrigger, oldVal, oldObj != nil)...) } - { // field ateapipb.Snapshot.Owner + { // field ateapipb.SharedVolume.StorageClassName fn := func( fldPath *field.Path, - obj, oldObj *ateapipb.SnapshotOwner, + obj, oldObj *string, oldValueCorrelated bool) (errs field.ErrorList) { // don't revalidate unchanged data if oldValueCorrelated && op.Type == operation.Update { @@ -7369,32 +7777,33 @@ func Validate_Snapshot( } // call field-attached validations earlyReturn := false - if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if e := validate.UpdateValue(ctx, op, fldPath, obj, oldObj, + func(a string, b string) bool { return a == b }, validate.NoUnset, validate.NoModify).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, 2); len(e) != 0 { - errs = append(errs, e...) - } - if e := validate.Minimum(ctx, op, fldPath, obj, oldObj, 1); len(e) != 0 { + if e := validate.LongName(ctx, op, fldPath, obj, oldObj); len(e) != 0 { errs = append(errs, e...) } return } oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.Snapshot) *ateapipb.SnapshotOwner { - return &oldObj.Owner + func(oldObj *ateapipb.SharedVolume) *string { + return &oldObj.StorageClassName }) - errs = append(errs, fn(fldPath.Child("owner"), &obj.Owner, oldVal, oldObj != nil)...) + errs = append(errs, fn(fldPath.Child("storage_class_name"), &obj.StorageClassName, oldVal, oldObj != nil)...) } - { // field ateapipb.Snapshot.Fidelity + { // field ateapipb.SharedVolume.VolumeId fn := func( fldPath *field.Path, - obj, oldObj *ateapipb.SnapshotFidelity, + obj, oldObj *string, oldValueCorrelated bool) (errs field.ErrorList) { // don't revalidate unchanged data if oldValueCorrelated && op.Type == operation.Update { @@ -7404,29 +7813,34 @@ func Validate_Snapshot( } // call field-attached validations earlyReturn := false - if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if e := validate.UpdateValue(ctx, op, fldPath, obj, oldObj, + func(a string, b string) bool { return a == b }, validate.NoUnset, validate.NoModify).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 { + // custom validation + if e := ValidateCustom_SharedVolume_VolumeId(ctx, op, fldPath, obj, oldObj); len(e) != 0 { errs = append(errs, e...) } - if e := validate.Minimum(ctx, op, fldPath, obj, oldObj, 1); len(e) != 0 { + 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.Snapshot) *ateapipb.SnapshotFidelity { - return &oldObj.Fidelity + func(oldObj *ateapipb.SharedVolume) *string { + return &oldObj.VolumeId }) - errs = append(errs, fn(fldPath.Child("fidelity"), &obj.Fidelity, oldVal, oldObj != nil)...) + errs = append(errs, fn(fldPath.Child("volume_id"), &obj.VolumeId, oldVal, oldObj != nil)...) } - { // field ateapipb.Snapshot.ActorTemplateUid + { // field ateapipb.SharedVolume.VolumeType fn := func( fldPath *field.Path, obj, oldObj *string, @@ -7442,56 +7856,78 @@ func Validate_Snapshot( if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { earlyReturn = true } + if e := validate.UpdateValue(ctx, op, fldPath, obj, oldObj, + func(a string, b string) bool { return a == b }, validate.NoUnset, validate.NoModify).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } if earlyReturn { return // do not proceed } - if e := validate.UUID(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + // custom validation + if e := ValidateCustom_SharedVolume_VolumeType(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.Snapshot) *string { - return &oldObj.ActorTemplateUid + func(oldObj *ateapipb.SharedVolume) *string { + return &oldObj.VolumeType }) - errs = append(errs, fn(fldPath.Child("actor_template_uid"), &obj.ActorTemplateUid, oldVal, oldObj != nil)...) + errs = append(errs, fn(fldPath.Child("volume_type"), &obj.VolumeType, oldVal, oldObj != nil)...) } - { // field ateapipb.Snapshot.Locality + { // field ateapipb.SharedVolume.VolumeContext fn := func( fldPath *field.Path, - obj, oldObj *string, + obj, oldObj map[string]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) { + if ateDeepEqual(obj, oldObj) { return nil } } // call field-attached validations earlyReturn := false - if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + if e := validate.MaxProperties(ctx, op, fldPath, obj, oldObj, 32).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalMap(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { earlyReturn = true } if earlyReturn { return // do not proceed } - if e := validate.LongName(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + if e := validate.EachMapKey(ctx, op, fldPath, obj, oldObj, + func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList { + return validate.MaxLength(ctx, op, fldPath, obj, oldObj, 128) + }); len(e) != 0 { + errs = append(errs, e...) + } + if e := validate.EachMapVal(ctx, op, fldPath, obj, oldObj, validate.DirectEqual, + func(ctx context.Context, op operation.Operation, fldPath *field.Path, obj, oldObj *string) field.ErrorList { + return validate.MaxLength(ctx, op, fldPath, obj, oldObj, 256) + }); len(e) != 0 { errs = append(errs, e...) } return } oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.Snapshot) *string { - return &oldObj.Locality + func(oldObj *ateapipb.SharedVolume) map[string]string { + return oldObj.VolumeContext }) - errs = append(errs, fn(fldPath.Child("locality"), &obj.Locality, oldVal, oldObj != nil)...) + errs = append(errs, fn(fldPath.Child("volume_context"), obj.VolumeContext, oldVal, oldObj != nil)...) } - { // field ateapipb.Snapshot.DurableSnapshot + { // field ateapipb.SharedVolume.Status fn := func( fldPath *field.Path, - obj, oldObj *ateapipb.SnapshotStorage, + obj, oldObj *ateapipb.SharedVolumeStatus, oldValueCorrelated bool) (errs field.ErrorList) { // don't revalidate unchanged data if oldValueCorrelated && op.Type == operation.Update { @@ -7508,26 +7944,17 @@ func Validate_Snapshot( return // do not proceed } // call the type's validation function - errs = append(errs, Validate_SnapshotStorage(ctx, op, fldPath, obj, oldObj)...) + errs = append(errs, Validate_SharedVolumeStatus(ctx, op, fldPath, obj, oldObj)...) return } oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.Snapshot) *ateapipb.SnapshotStorage { - return oldObj.DurableSnapshot + func(oldObj *ateapipb.SharedVolume) *ateapipb.SharedVolumeStatus { + return oldObj.Status }) - errs = append(errs, fn(fldPath.Child("durable_snapshot"), obj.DurableSnapshot, oldVal, oldObj != nil)...) + errs = append(errs, fn(fldPath.Child("status"), obj.Status, oldVal, oldObj != nil)...) } - return errs -} - -// Validate_SnapshotConfig validates an instance of SnapshotConfig according -// to declarative validation rules in the API schema. -func Validate_SnapshotConfig( - ctx context.Context, op operation.Operation, fldPath *field.Path, - obj, oldObj *ateapipb.SnapshotConfig) (errs field.ErrorList) { - - { // field ateapipb.SnapshotConfig.StorageLocation + { // field ateapipb.SharedVolume.Capacity fn := func( fldPath *field.Path, obj, oldObj *string, @@ -7540,7 +7967,11 @@ func Validate_SnapshotConfig( } // call field-attached validations earlyReturn := false - if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if e := validate.UpdateValue(ctx, op, fldPath, obj, oldObj, + func(a string, b string) bool { return a == b }, validate.NoUnset, validate.NoModify).MarkShortCircuit(); len(e) != 0 { errs = append(errs, e...) earlyReturn = true } @@ -7548,19 +7979,427 @@ func Validate_SnapshotConfig( return // do not proceed } // custom validation - if e := ValidateCustom_SnapshotConfig_StorageLocation(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + if e := ValidateCustom_SharedVolume_Capacity(ctx, op, fldPath, obj, oldObj); len(e) != 0 { errs = append(errs, e...) } - if e := validate.MaxLength(ctx, op, fldPath, obj, oldObj, 1024); len(e) != 0 { + if e := validate.MaxLength(ctx, op, fldPath, obj, oldObj, 64); len(e) != 0 { errs = append(errs, e...) } return } oldVal := safe.Field(oldObj, - func(oldObj *ateapipb.SnapshotConfig) *string { - return &oldObj.StorageLocation + func(oldObj *ateapipb.SharedVolume) *string { + return &oldObj.Capacity }) - errs = append(errs, fn(fldPath.Child("storage_location"), &obj.StorageLocation, oldVal, oldObj != nil)...) + errs = append(errs, fn(fldPath.Child("capacity"), &obj.Capacity, oldVal, oldObj != nil)...) + } + + { // field ateapipb.SharedVolume.AccessMode + fn := func( + fldPath *field.Path, + obj, oldObj *ateapipb.AccessMode, + 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 e := validate.UpdateValue(ctx, op, fldPath, obj, oldObj, + func(a ateapipb.AccessMode, b ateapipb.AccessMode) bool { return a == b }, validate.NoUnset, validate.NoModify).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, 2); len(e) != 0 { + errs = append(errs, e...) + } + if e := validate.Minimum(ctx, op, fldPath, obj, oldObj, 1); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.SharedVolume) *ateapipb.AccessMode { + return &oldObj.AccessMode + }) + errs = append(errs, fn(fldPath.Child("access_mode"), &obj.AccessMode, oldVal, oldObj != nil)...) + } + + return errs +} + +// Validate_SharedVolumeStatus validates an instance of SharedVolumeStatus according +// to declarative validation rules in the API schema. +func Validate_SharedVolumeStatus( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *ateapipb.SharedVolumeStatus) (errs field.ErrorList) { + + { // field ateapipb.SharedVolumeStatus.State + fn := func( + fldPath *field.Path, + obj, oldObj *ateapipb.SharedVolumeState, + 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 + } + if e := validate.Maximum(ctx, op, fldPath, obj, oldObj, 2); len(e) != 0 { + errs = append(errs, e...) + } + if e := validate.Minimum(ctx, op, fldPath, obj, oldObj, 1); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.SharedVolumeStatus) *ateapipb.SharedVolumeState { + return &oldObj.State + }) + errs = append(errs, fn(fldPath.Child("state"), &obj.State, oldVal, oldObj != nil)...) + } + + { // field ateapipb.SharedVolumeStatus.Refs + fn := func( + fldPath *field.Path, + obj, oldObj []*ateapipb.ActorRef, + 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.ActorRef](ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.MaxItems(ctx, op, fldPath, obj, oldObj, 256).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.ActorRef, b *ateapipb.ActorRef) bool { return a.ActorUid == b.ActorUid }); 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.ActorRef, b *ateapipb.ActorRef) bool { return a.ActorUid == b.ActorUid }, ateDeepEqual, Validate_ActorRef); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.SharedVolumeStatus) []*ateapipb.ActorRef { + return oldObj.Refs + }) + errs = append(errs, fn(fldPath.Child("refs"), obj.Refs, oldVal, oldObj != nil)...) + } + + return errs +} + +// Validate_Snapshot validates an instance of Snapshot according +// to declarative validation rules in the API schema. +func Validate_Snapshot( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *ateapipb.Snapshot) (errs field.ErrorList) { + + { // field ateapipb.Snapshot.Uuid + 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.Snapshot) *string { + return &oldObj.Uuid + }) + errs = append(errs, fn(fldPath.Child("uuid"), &obj.Uuid, oldVal, oldObj != nil)...) + } + + { // field ateapipb.Snapshot.Generation + fn := func( + fldPath *field.Path, + obj, oldObj *int32, + 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.Minimum(ctx, op, fldPath, obj, oldObj, 1); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.Snapshot) *int32 { + return &oldObj.Generation + }) + errs = append(errs, fn(fldPath.Child("generation"), &obj.Generation, oldVal, oldObj != nil)...) + } + + { // field ateapipb.Snapshot.Owner + fn := func( + fldPath *field.Path, + obj, oldObj *ateapipb.SnapshotOwner, + 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, 2); len(e) != 0 { + errs = append(errs, e...) + } + if e := validate.Minimum(ctx, op, fldPath, obj, oldObj, 1); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.Snapshot) *ateapipb.SnapshotOwner { + return &oldObj.Owner + }) + errs = append(errs, fn(fldPath.Child("owner"), &obj.Owner, oldVal, oldObj != nil)...) + } + + { // field ateapipb.Snapshot.Fidelity + fn := func( + fldPath *field.Path, + obj, oldObj *ateapipb.SnapshotFidelity, + 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, 1); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.Snapshot) *ateapipb.SnapshotFidelity { + return &oldObj.Fidelity + }) + errs = append(errs, fn(fldPath.Child("fidelity"), &obj.Fidelity, oldVal, oldObj != nil)...) + } + + { // field ateapipb.Snapshot.ActorTemplateUid + 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 + } + if e := validate.UUID(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.Snapshot) *string { + return &oldObj.ActorTemplateUid + }) + errs = append(errs, fn(fldPath.Child("actor_template_uid"), &obj.ActorTemplateUid, oldVal, oldObj != nil)...) + } + + { // field ateapipb.Snapshot.Locality + 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 + } + if e := validate.LongName(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.Snapshot) *string { + return &oldObj.Locality + }) + errs = append(errs, fn(fldPath.Child("locality"), &obj.Locality, oldVal, oldObj != nil)...) + } + + { // field ateapipb.Snapshot.DurableSnapshot + fn := func( + fldPath *field.Path, + obj, oldObj *ateapipb.SnapshotStorage, + 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 + } + // call the type's validation function + errs = append(errs, Validate_SnapshotStorage(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.Snapshot) *ateapipb.SnapshotStorage { + return oldObj.DurableSnapshot + }) + errs = append(errs, fn(fldPath.Child("durable_snapshot"), obj.DurableSnapshot, oldVal, oldObj != nil)...) + } + + return errs +} + +// Validate_SnapshotConfig validates an instance of SnapshotConfig according +// to declarative validation rules in the API schema. +func Validate_SnapshotConfig( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *ateapipb.SnapshotConfig) (errs field.ErrorList) { + + { // field ateapipb.SnapshotConfig.StorageLocation + 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_SnapshotConfig_StorageLocation(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + } + if e := validate.MaxLength(ctx, op, fldPath, obj, oldObj, 1024); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.SnapshotConfig) *string { + return &oldObj.StorageLocation + }) + errs = append(errs, fn(fldPath.Child("storage_location"), &obj.StorageLocation, oldVal, oldObj != nil)...) } { // field ateapipb.SnapshotConfig.PreferredFidelity @@ -8616,6 +9455,59 @@ func Validate_UpdateGlobalAccessPolicyRequest( return errs } +// Validate_UpdateSharedVolumeRequest validates an instance of UpdateSharedVolumeRequest according +// to declarative validation rules in the API schema. +func Validate_UpdateSharedVolumeRequest( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *ateapipb.UpdateSharedVolumeRequest) (errs field.ErrorList) { + + { // field ateapipb.UpdateSharedVolumeRequest.SharedVolume + fn := func( + fldPath *field.Path, + obj, oldObj *ateapipb.SharedVolume, + 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.RequiredPointer(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_UpdateSharedVolumeRequest_SharedVolume(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + } + func() { // cohort = "metadata" + earlyReturn := false + if e := validate.Subfield(ctx, op, fldPath, obj, oldObj, "metadata", + func(o *ateapipb.SharedVolume) *ateapipb.ResourceMetadata { return o.Metadata }, ateDeepEqual, validate.RequiredPointer).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + }() + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.UpdateSharedVolumeRequest) *ateapipb.SharedVolume { + return oldObj.SharedVolume + }) + errs = append(errs, fn(fldPath.Child("shared_volume"), obj.SharedVolume, oldVal, oldObj != nil)...) + } + + return errs +} + // Validate_UpdateTagRequest validates an instance of UpdateTagRequest according // to declarative validation rules in the API schema. func Validate_UpdateTagRequest( diff --git a/cmd/ateapi/internal/controlapi/functionaltest/shared_volume_test.go b/cmd/ateapi/internal/controlapi/functionaltest/shared_volume_test.go new file mode 100644 index 0000000000..254bfaa213 --- /dev/null +++ b/cmd/ateapi/internal/controlapi/functionaltest/shared_volume_test.go @@ -0,0 +1,271 @@ +// 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 functionaltest + +import ( + "context" + "fmt" + "sync" + "testing" + + "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/protobuf/testing/protocmp" +) + +// sharedVolumePlugin records every storage operation the control plane makes. +type sharedVolumePlugin struct { + volume.VolumePluginControlPlane + + mu sync.Mutex + created []string + deleted []string + attached []string + detached []string +} + +func (p *sharedVolumePlugin) CreateVolume(_ context.Context, req volume.CreateVolumeRequest) (volume.CreateVolumeResponse, error) { + p.mu.Lock() + defer p.mu.Unlock() + p.created = append(p.created, req.Name) + return volume.CreateVolumeResponse{VolumeID: "disk/" + req.Name, VolumeContext: req.Parameters}, nil +} + +func (p *sharedVolumePlugin) DeleteVolume(_ context.Context, volumeID string) error { + p.mu.Lock() + defer p.mu.Unlock() + p.deleted = append(p.deleted, volumeID) + return nil +} + +func (p *sharedVolumePlugin) AttachVolume(_ context.Context, req volume.AttachVolumeRequest) (volume.AttachVolumeResponse, error) { + p.mu.Lock() + defer p.mu.Unlock() + p.attached = append(p.attached, req.VolumeID+"@"+req.Node) + return volume.AttachVolumeResponse{}, nil +} + +func (p *sharedVolumePlugin) DetachVolume(_ context.Context, volumeID, node string) error { + p.mu.Lock() + defer p.mu.Unlock() + p.detached = append(p.detached, volumeID+"@"+node) + return nil +} + +func (p *sharedVolumePlugin) snapshot() (created, deleted, attached, detached []string) { + p.mu.Lock() + defer p.mu.Unlock() + return append([]string(nil), p.created...), append([]string(nil), p.deleted...), + append([]string(nil), p.attached...), append([]string(nil), p.detached...) +} + +func setupSharedVolumeTest(t *testing.T, ns string) (*testContext, *sharedVolumePlugin) { + t.Helper() + plugin := &sharedVolumePlugin{} + tc := setupTestWithVolumePlugins(t, ns, map[string]volume.VolumePluginControlPlane{ + "substrate.io/mock": plugin, + }) + return tc, plugin +} + +func createSharedVolume(t *testing.T, tc *testContext, name string, trigger ateapipb.DeleteTrigger) *ateapipb.SharedVolume { + t.Helper() + created, err := tc.client.CreateSharedVolume(context.Background(), &ateapipb.CreateSharedVolumeRequest{ + SharedVolume: &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: name}, + StorageClassName: "standard", + Capacity: "10Gi", + DeleteTrigger: trigger, + }, + }) + if err != nil { + t.Fatalf("CreateSharedVolume(%s) failed: %v", name, err) + } + if got := created.GetStatus().GetState(); got != ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY { + t.Fatalf("CreateSharedVolume(%s) left the volume in %v, want READY", name, got) + } + return created +} + +func getSharedVolume(t *testing.T, tc *testContext, name string) *ateapipb.SharedVolume { + t.Helper() + stored, err := tc.client.GetSharedVolume(context.Background(), &ateapipb.GetSharedVolumeRequest{ + SharedVolume: &ateapipb.ObjectRef{Atespace: testAtespace, Name: name}, + }) + if err != nil { + t.Fatalf("GetSharedVolume(%s) failed: %v", name, err) + } + return stored +} + +func TestCreateSharedVolume_Provisioned(t *testing.T) { + ns := namespaceForTest("ns-extvol-provisioned") + tc, plugin := setupSharedVolumeTest(t, ns) + defer tc.cleanup() + + created := createSharedVolume(t, tc, "shared", ateapipb.DeleteTrigger_DELETE_TRIGGER_UNSPECIFIED) + + wantDiskName := "substrate-" + created.GetMetadata().GetUid() + gotCreated, _, _, _ := plugin.snapshot() + if diff := cmp.Diff([]string{wantDiskName}, gotCreated); diff != "" { + t.Errorf("provisioned disks mismatch (-want +got):\n%s", diff) + } + if got, want := created.GetVolumeId(), "disk/"+wantDiskName; got != want { + t.Errorf("volume_id = %q, want %q", got, want) + } + if got, want := created.GetVolumeType(), "substrate.io/mock"; got != want { + t.Errorf("volume_type = %q, want %q", got, want) + } + if got := created.GetDeleteTrigger(); got != ateapipb.DeleteTrigger_DELETE_TRIGGER_LAST_ACTOR { + t.Errorf("delete_trigger = %v, want LAST_ACTOR", got) + } + if got := created.GetAccessMode(); got != ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_ONCE { + t.Errorf("access_mode = %v, want READ_WRITE_ONCE", got) + } + + if diff := cmp.Diff(created, getSharedVolume(t, tc, "shared"), protocmp.Transform()); diff != "" { + t.Errorf("GetSharedVolume mismatch (-want +got):\n%s", diff) + } + listed, err := tc.client.ListSharedVolumes(context.Background(), &ateapipb.ListSharedVolumesRequest{Atespace: testAtespace}) + if err != nil { + t.Fatalf("ListSharedVolumes failed: %v", err) + } + if diff := cmp.Diff([]*ateapipb.SharedVolume{created}, listed.GetSharedVolumes(), protocmp.Transform()); diff != "" { + t.Errorf("ListSharedVolumes mismatch (-want +got):\n%s", diff) + } +} + +func TestCreateSharedVolume_Registered(t *testing.T) { + ns := namespaceForTest("ns-extvol-registered") + tc, plugin := setupSharedVolumeTest(t, ns) + defer tc.cleanup() + + created, err := tc.client.CreateSharedVolume(context.Background(), &ateapipb.CreateSharedVolumeRequest{ + SharedVolume: &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "adopted"}, + VolumeId: "disk/made-elsewhere", + VolumeType: "substrate.io/mock", + }, + }) + if err != nil { + t.Fatalf("CreateSharedVolume failed: %v", err) + } + if got := created.GetStatus().GetState(); got != ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY { + t.Errorf("state = %v, want READY", got) + } + if got := created.GetDeleteTrigger(); got != ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL { + t.Errorf("delete_trigger = %v, want MANUAL", got) + } + if gotCreated, _, _, _ := plugin.snapshot(); len(gotCreated) != 0 { + t.Errorf("provisioned %v, want nothing provisioned for a registered volume", gotCreated) + } +} + +func TestCreateSharedVolume_Rejected(t *testing.T) { + ns := namespaceForTest("ns-extvol-rejected") + tc, _ := setupSharedVolumeTest(t, ns) + defer tc.cleanup() + + first := createSharedVolume(t, tc, "shared", ateapipb.DeleteTrigger_DELETE_TRIGGER_UNSPECIFIED) + + _, err := tc.client.CreateSharedVolume(context.Background(), &ateapipb.CreateSharedVolumeRequest{ + SharedVolume: &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "shared"}, + StorageClassName: "fast", + Capacity: "20Gi", + }, + }) + assertGrpcError(t, err, codes.AlreadyExists, + fmt.Sprintf("SharedVolume %s/shared already exists; delete it and create it again to retry", testAtespace)) + if diff := cmp.Diff(first, getSharedVolume(t, tc, "shared"), protocmp.Transform()); diff != "" { + t.Errorf("the rejected create changed the stored volume (-want +got):\n%s", diff) + } + + _, err = tc.client.CreateSharedVolume(context.Background(), &ateapipb.CreateSharedVolumeRequest{ + SharedVolume: &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "many"}, + StorageClassName: "standard", + Capacity: "10Gi", + AccessMode: ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_MANY, + }, + }) + assertGrpcErrorRegex(t, err, codes.InvalidArgument, "access_mode") +} + +func TestUpdateSharedVolume(t *testing.T) { + ns := namespaceForTest("ns-extvol-update") + tc, _ := setupSharedVolumeTest(t, ns) + defer tc.cleanup() + + created := createSharedVolume(t, tc, "shared", ateapipb.DeleteTrigger_DELETE_TRIGGER_LAST_ACTOR) + toUpdate := func(in *ateapipb.SharedVolume) *ateapipb.SharedVolume { + return &ateapipb.SharedVolume{ + Metadata: in.GetMetadata(), + DeleteTrigger: in.GetDeleteTrigger(), + AccessMode: in.GetAccessMode(), + StorageClassName: in.GetStorageClassName(), + Capacity: in.GetCapacity(), + VolumeId: in.GetVolumeId(), + VolumeType: in.GetVolumeType(), + VolumeContext: in.GetVolumeContext(), + } + } + + req := toUpdate(created) + req.DeleteTrigger = ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL + updated, err := tc.client.UpdateSharedVolume(context.Background(), &ateapipb.UpdateSharedVolumeRequest{SharedVolume: req}) + if err != nil { + t.Fatalf("UpdateSharedVolume failed: %v", err) + } + if got := updated.GetDeleteTrigger(); got != ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL { + t.Errorf("delete_trigger = %v, want MANUAL", got) + } + + req = toUpdate(updated) + req.VolumeId = "disk/somewhere-else" + _, err = tc.client.UpdateSharedVolume(context.Background(), &ateapipb.UpdateSharedVolumeRequest{SharedVolume: req}) + assertGrpcErrorRegex(t, err, codes.InvalidArgument, "volume_id") + + req = toUpdate(updated) + req.AccessMode = ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_MANY + _, err = tc.client.UpdateSharedVolume(context.Background(), &ateapipb.UpdateSharedVolumeRequest{SharedVolume: req}) + assertGrpcErrorRegex(t, err, codes.InvalidArgument, "access_mode") +} + +func TestDeleteSharedVolume(t *testing.T) { + ns := namespaceForTest("ns-extvol-delete") + tc, plugin := setupSharedVolumeTest(t, ns) + defer tc.cleanup() + + created := createSharedVolume(t, tc, "shared", ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL) + ref := &ateapipb.ObjectRef{Atespace: testAtespace, Name: "shared"} + + _, err := tc.client.DeleteSharedVolume(context.Background(), &ateapipb.DeleteSharedVolumeRequest{ + SharedVolume: ref, + Options: &ateapipb.DeleteOptions{Version: created.GetMetadata().GetVersion() + 1}, + }) + assertGrpcError(t, err, codes.Aborted, "concurrent update conflict, please retry") + + if _, err := tc.client.DeleteSharedVolume(context.Background(), &ateapipb.DeleteSharedVolumeRequest{SharedVolume: ref}); err != nil { + t.Fatalf("DeleteSharedVolume failed: %v", err) + } + if _, deleted, _, _ := plugin.snapshot(); !cmp.Equal([]string{created.GetVolumeId()}, deleted) { + t.Errorf("deleted disks = %v, want %v", deleted, []string{created.GetVolumeId()}) + } + _, err = tc.client.DeleteSharedVolume(context.Background(), &ateapipb.DeleteSharedVolumeRequest{SharedVolume: ref}) + assertGrpcError(t, err, codes.NotFound, fmt.Sprintf("SharedVolume %s/shared not found", testAtespace)) +} diff --git a/cmd/ateapi/internal/controlapi/service.go b/cmd/ateapi/internal/controlapi/service.go index 0c3ae2fc85..089034c54c 100644 --- a/cmd/ateapi/internal/controlapi/service.go +++ b/cmd/ateapi/internal/controlapi/service.go @@ -46,6 +46,7 @@ type RPCService struct { csiDriverConfigLister listersv1alpha1.CSIDriverConfigLister actorWorkflow *ActorWorkflow workerWorkflow *WorkerWorkflow + sharedVolumeWorkflow *SharedVolumeWorkflow instruments *Instruments mu sync.RWMutex volumePlugins map[string]volume.VolumePluginControlPlane @@ -105,6 +106,7 @@ func NewRPCService( } s.actorWorkflow = NewActorWorkflow(impl, workerCache, dialer, sandboxConfigLister, storageClassLister, instruments, egressGatewayAddress, s, objectStorePlugin) s.workerWorkflow = NewWorkerWorkflow(impl) + s.sharedVolumeWorkflow = NewSharedVolumeWorkflow(impl, storageClassLister, s) return s } @@ -123,6 +125,11 @@ type serviceStore interface { ListTags(ctx context.Context, atespace string, opts store.ListOptions) (store.ListResponse[*ateapipb.Tag], error) UpdateTag(ctx context.Context, tagRef resources.TagRef, precondition store.Precondition, mutate func(toUpdate *ateapipb.Tag) error) (*ateapipb.Tag, error) DeleteTag(ctx context.Context, tagRef resources.TagRef, precondition store.DeletePreconditions) (*ateapipb.Tag, error) + CreateSharedVolume(ctx context.Context, volume *ateapipb.SharedVolume) (*ateapipb.SharedVolume, error) + GetSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef) (*ateapipb.SharedVolume, error) + ListSharedVolumes(ctx context.Context, atespace string, opts store.ListOptions) (store.ListResponse[*ateapipb.SharedVolume], error) + UpdateSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef, precondition store.Precondition, mutate func(toUpdate *ateapipb.SharedVolume) error) (*ateapipb.SharedVolume, error) + DeleteSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef, precondition store.DeletePreconditions) (*ateapipb.SharedVolume, error) CreateAtespace(ctx context.Context, atespace *ateapipb.Atespace) (*ateapipb.Atespace, error) GetAtespace(ctx context.Context, name string) (*ateapipb.Atespace, error) ListAtespaces(ctx context.Context, opts store.ListOptions) (store.ListResponse[*ateapipb.Atespace], error) diff --git a/cmd/ateapi/internal/controlapi/shared_volume.go b/cmd/ateapi/internal/controlapi/shared_volume.go new file mode 100644 index 0000000000..044cbbdb22 --- /dev/null +++ b/cmd/ateapi/internal/controlapi/shared_volume.go @@ -0,0 +1,151 @@ +// 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" + "errors" + "fmt" + + "github.com/agent-substrate/substrate/cmd/ateapi/internal/apivalidation" + "github.com/agent-substrate/substrate/cmd/ateapi/internal/defaults" + "github.com/agent-substrate/substrate/cmd/ateapi/internal/store" + "github.com/agent-substrate/substrate/internal/apierror" + "github.com/agent-substrate/substrate/internal/resources" + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" + "google.golang.org/protobuf/proto" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +func (s *RPCService) CreateSharedVolume(ctx context.Context, req *ateapipb.CreateSharedVolumeRequest) (*ateapipb.SharedVolume, error) { + inVolume := req.SharedVolume + if inVolume != nil { + scrubResourceMetadataForCreate(inVolume.Metadata) + inVolume.Status = nil + defaults.Apply(inVolume) + } + if errs := apivalidation.ValidateCreateSharedVolumeRequest(ctx, req); len(errs) > 0 { + return nil, resources.ToAPIError(errs) + } + return s.sharedVolumeWorkflow.CreateSharedVolume(ctx, inVolume) +} + +func (s *ServiceImpl) CreateSharedVolume(ctx context.Context, volume *ateapipb.SharedVolume) (*ateapipb.SharedVolume, error) { + return s.store.CreateSharedVolume(ctx, volume) +} + +func (s *RPCService) GetSharedVolume(ctx context.Context, req *ateapipb.GetSharedVolumeRequest) (*ateapipb.SharedVolume, error) { + if errs := apivalidation.ValidateGetSharedVolumeRequest(ctx, req); len(errs) > 0 { + return nil, resources.ToAPIError(errs) + } + volumeRef := resources.SharedVolumeRefFromObjectRef(req.GetSharedVolume()) + volume, err := s.impl.GetSharedVolume(ctx, volumeRef) + if err != nil { + if errors.Is(err, store.ErrNotFound) { + return nil, apierror.NotFound("SharedVolume %s not found", volumeRef) + } + return nil, fmt.Errorf("while getting shared volume: %w", err) + } + return volume, nil +} + +func (s *ServiceImpl) GetSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef) (*ateapipb.SharedVolume, error) { + return s.store.GetSharedVolume(ctx, volumeRef) +} + +func (s *RPCService) ListSharedVolumes(ctx context.Context, req *ateapipb.ListSharedVolumesRequest) (*ateapipb.ListSharedVolumesResponse, error) { + if errs := apivalidation.ValidateListSharedVolumesRequest(ctx, req); len(errs) > 0 { + return nil, resources.ToAPIError(errs) + } + page, err := s.impl.ListSharedVolumes(ctx, req.GetAtespace(), store.ListOptions{PageSize: effectivePageSize(req.GetPageSize()), PageToken: req.GetPageToken()}) + if err != nil { + return nil, mapListError(fmt.Errorf("while listing shared volumes: %w", err)) + } + return &ateapipb.ListSharedVolumesResponse{SharedVolumes: page.Items, NextPageToken: page.NextPageToken}, nil +} + +func (s *ServiceImpl) ListSharedVolumes(ctx context.Context, atespace string, opts store.ListOptions) (store.ListResponse[*ateapipb.SharedVolume], error) { + return s.store.ListSharedVolumes(ctx, atespace, opts) +} + +var errSharedVolumePending = errors.New("shared volume is still being created") + +func (s *RPCService) UpdateSharedVolume(ctx context.Context, req *ateapipb.UpdateSharedVolumeRequest) (*ateapipb.SharedVolume, error) { + inVolume := req.SharedVolume + if inVolume != nil { + scrubResourceMetadataForUpdate(inVolume.Metadata) + inVolume.Status = nil + } + if errs := apivalidation.ValidateUpdateSharedVolumeRequest(ctx, req); len(errs) > 0 { + return nil, resources.ToAPIError(errs) + } + in := req.GetSharedVolume() + volumeRef := resources.SharedVolumeRefFromSharedVolume(in) + + stored, err := s.impl.UpdateSharedVolume(ctx, volumeRef, store.PreconditionFrom(in), func(toUpdate *ateapipb.SharedVolume) error { + if toUpdate.GetStatus().GetState() != ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY { + return errSharedVolumePending + } + metadata, volumeStatus := toUpdate.GetMetadata(), toUpdate.GetStatus() + proto.Reset(toUpdate) + proto.Merge(toUpdate, in) + toUpdate.Metadata, toUpdate.Status = metadata, volumeStatus + defaults.Apply(toUpdate) + return nil + }) + if err != nil { + if errors.Is(err, errSharedVolumePending) { + return nil, apierror.FailedPrecondition("SharedVolume %s is still being created", volumeRef) + } + if errors.Is(err, store.ErrImmutableField) || errors.Is(err, store.ErrPreconditionRequired) { + return nil, apierror.InvalidArgument("while updating shared volume %s: %v", volumeRef, err) + } + if errors.Is(err, store.ErrVersionConflict) { + return nil, apierror.Aborted("concurrent update conflict, please retry") + } + if errors.Is(err, store.ErrUIDConflict) { + return nil, apierror.Aborted("SharedVolume %s not found with uid %s", volumeRef, in.GetMetadata().GetUid()) + } + if errors.Is(err, store.ErrNotFound) { + return nil, apierror.NotFound("SharedVolume %s not found", volumeRef) + } + return nil, fmt.Errorf("while updating shared volume: %w", err) + } + return stored, nil +} + +func (s *ServiceImpl) UpdateSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef, precondition store.Precondition, mutate func(toUpdate *ateapipb.SharedVolume) error) (*ateapipb.SharedVolume, error) { + return s.store.UpdateSharedVolume(ctx, volumeRef, precondition, func(toUpdate *ateapipb.SharedVolume) error { + oldVal := proto.CloneOf(toUpdate) + if err := mutate(toUpdate); err != nil { + return err + } + if errs := apivalidation.ValidateSharedVolumeUpdate(ctx, field.NewPath("shared_volume"), toUpdate, oldVal); len(errs) > 0 { + return resources.ToAPIError(errs) + } + return nil + }) +} + +func (s *RPCService) DeleteSharedVolume(ctx context.Context, req *ateapipb.DeleteSharedVolumeRequest) (*ateapipb.SharedVolume, error) { + if errs := apivalidation.ValidateDeleteSharedVolumeRequest(ctx, req); len(errs) > 0 { + return nil, resources.ToAPIError(errs) + } + return s.sharedVolumeWorkflow.DeleteSharedVolume(ctx, resources.SharedVolumeRefFromObjectRef(req.GetSharedVolume()), toDeletePreconditions(req.GetOptions())) +} + +func (s *ServiceImpl) DeleteSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef, precondition store.DeletePreconditions) (*ateapipb.SharedVolume, error) { + return s.store.DeleteSharedVolume(ctx, volumeRef, precondition) +} diff --git a/cmd/ateapi/internal/controlapi/shared_volume_test.go b/cmd/ateapi/internal/controlapi/shared_volume_test.go new file mode 100644 index 0000000000..a6a068a251 --- /dev/null +++ b/cmd/ateapi/internal/controlapi/shared_volume_test.go @@ -0,0 +1,304 @@ +// 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" + "testing" + + "github.com/agent-substrate/substrate/cmd/ateapi/internal/store" + "github.com/agent-substrate/substrate/internal/apierror" + "github.com/agent-substrate/substrate/internal/resources" + "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" + storagev1 "k8s.io/api/storage/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// recordingVolumePlugin answers CreateVolume with a handle derived from the +// name it was asked for, and records both calls so a test can assert on what +// the workflow asked the storage system to do. +type recordingVolumePlugin struct { + volume.VolumePluginControlPlane + + createErr error + deleteErr error + createdIDs []string + deletedIDs []string +} + +func (p *recordingVolumePlugin) CreateVolume(_ context.Context, req volume.CreateVolumeRequest) (volume.CreateVolumeResponse, error) { + if p.createErr != nil { + return volume.CreateVolumeResponse{}, p.createErr + } + p.createdIDs = append(p.createdIDs, req.Name) + return volume.CreateVolumeResponse{VolumeID: "disk/" + req.Name, VolumeContext: map[string]string{"capacity": req.Capacity}}, nil +} + +func (p *recordingVolumePlugin) DeleteVolume(_ context.Context, volumeID string) error { + if p.deleteErr != nil { + return p.deleteErr + } + p.deletedIDs = append(p.deletedIDs, volumeID) + return nil +} + +// newTestSharedVolumeWorkflow builds a SharedVolumeWorkflow over a real +// store, with one StorageClass named "standard" whose reclaim policy the caller +// chooses, and a plugin registered under that class's provisioner. +func newTestSharedVolumeWorkflow(t *testing.T) (*SharedVolumeWorkflow, store.Interface, *recordingVolumePlugin) { + t.Helper() + persistence := newTestPersistence(t) + plugin := &recordingVolumePlugin{} + scLister := &fakeStorageClassLister{ + storageClasses: map[string]*storagev1.StorageClass{ + "standard": { + ObjectMeta: metav1.ObjectMeta{Name: "standard"}, + Provisioner: "mock", + Parameters: map[string]string{"type": "pd-ssd"}, + }, + }, + } + registry := &mockPluginRegistry{plugins: map[string]volume.VolumePluginControlPlane{"mock": plugin}} + return NewSharedVolumeWorkflow(persistence, scLister, registry), persistence, plugin +} + +// TestCreateSharedVolume_Provisioned checks the whole create: the record is +// reserved, the disk is asked for under an ID derived from the record's UID, +// and the handle the driver returned is stamped back. +func TestCreateSharedVolume_Provisioned(t *testing.T) { + ctx := context.Background() + w, _, plugin := newTestSharedVolumeWorkflow(t) + + got, err := w.CreateSharedVolume(ctx, &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "shared"}, + StorageClassName: "standard", + Capacity: "10Gi", + }) + if err != nil { + t.Fatalf("CreateSharedVolume: %v", err) + } + + wantID := sharedVolumeID(got.GetMetadata().GetUid()) + if diff := cmp.Diff([]string{wantID}, plugin.createdIDs); diff != "" { + t.Errorf("provisioned volume names mismatch (-want +got):\n%s", diff) + } + if want := "disk/" + wantID; got.GetVolumeId() != want { + t.Errorf("volume_id = %q, want the handle the driver returned %q", got.GetVolumeId(), want) + } + if got.GetVolumeType() != "mock" { + t.Errorf("volume_type = %q, want the class's provisioner %q", got.GetVolumeType(), "mock") + } + if want := ateapipb.DeleteTrigger_DELETE_TRIGGER_LAST_ACTOR; got.GetDeleteTrigger() != want { + t.Errorf("delete_trigger = %v, want %v", got.GetDeleteTrigger(), want) + } + if want := ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY; got.GetStatus().GetState() != want { + t.Errorf("state = %v, want %v", got.GetStatus().GetState(), want) + } + if got.GetVolumeContext()["capacity"] != "10Gi" { + t.Errorf("volume_context = %v, want the context the driver returned for a 10Gi disk", got.GetVolumeContext()) + } +} + +func TestCreateSharedVolume_Registered(t *testing.T) { + ctx := context.Background() + w, _, plugin := newTestSharedVolumeWorkflow(t) + + got, err := w.CreateSharedVolume(ctx, &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "adopted"}, + VolumeId: "projects/p/zones/z/disks/preexisting", + VolumeType: "mock", + VolumeContext: map[string]string{"fsType": "ext4"}, + }) + if err != nil { + t.Fatalf("CreateSharedVolume: %v", err) + } + + if len(plugin.createdIDs) != 0 { + t.Errorf("provisioned %v, want nothing provisioned for a volume that already exists", plugin.createdIDs) + } + if want := "projects/p/zones/z/disks/preexisting"; got.GetVolumeId() != want { + t.Errorf("volume_id = %q, want the supplied %q", got.GetVolumeId(), want) + } + if want := ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY; got.GetStatus().GetState() != want { + t.Errorf("state = %v, want %v", got.GetStatus().GetState(), want) + } + if want := ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL; got.GetDeleteTrigger() != want { + t.Errorf("delete_trigger = %v, want %v", got.GetDeleteTrigger(), want) + } +} + +func TestCreateSharedVolume_Errors(t *testing.T) { + ctx := context.Background() + + tests := []struct { + name string + volume *ateapipb.SharedVolume + wantCode codes.Code + }{ + { + name: "unknown storage class", + volume: &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "vol"}, + StorageClassName: "nonexistent", + Capacity: "1Gi", + }, + wantCode: codes.FailedPrecondition, + }, + { + name: "unknown atespace", + volume: &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "no-such-space", Name: "vol"}, + StorageClassName: "standard", + Capacity: "1Gi", + }, + wantCode: codes.FailedPrecondition, + }, + { + name: "no source at all", + volume: &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "vol"}, + }, + wantCode: codes.InvalidArgument, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + w, _, _ := newTestSharedVolumeWorkflow(t) + _, err := w.CreateSharedVolume(ctx, tc.volume) + if got := apierror.Code(err); got != tc.wantCode { + t.Fatalf("CreateSharedVolume error = %v (code %v), want code %v", err, got, tc.wantCode) + } + }) + } +} + +func TestCreateSharedVolume_ReusedName(t *testing.T) { + ctx := context.Background() + w, _, plugin := newTestSharedVolumeWorkflow(t) + + toCreate := func() *ateapipb.SharedVolume { + return &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "shared"}, + StorageClassName: "standard", + Capacity: "10Gi", + } + } + if _, err := w.CreateSharedVolume(ctx, toCreate()); err != nil { + t.Fatalf("CreateSharedVolume: %v", err) + } + _, err := w.CreateSharedVolume(ctx, toCreate()) + if got := apierror.Code(err); got != codes.AlreadyExists { + t.Fatalf("second CreateSharedVolume error = %v (code %v), want code %v", err, got, codes.AlreadyExists) + } + if len(plugin.createdIDs) != 1 { + t.Errorf("provisioned %v, want only the first create to reach the storage system", plugin.createdIDs) + } +} + +func TestDeleteSharedVolume(t *testing.T) { + ctx := context.Background() + w, persistence, plugin := newTestSharedVolumeWorkflow(t) + created, err := w.CreateSharedVolume(ctx, &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "shared"}, + StorageClassName: "standard", + Capacity: "10Gi", + }) + if err != nil { + t.Fatalf("CreateSharedVolume: %v", err) + } + volumeRef := resources.SharedVolumeRefFromSharedVolume(created) + + if _, err := w.DeleteSharedVolume(ctx, volumeRef, store.DeletePreconditions{Version: created.GetMetadata().GetVersion() + 1}); apierror.Code(err) != codes.Aborted { + t.Fatalf("DeleteSharedVolume with a stale version error = %v, want code %v", err, codes.Aborted) + } + if len(plugin.deletedIDs) != 0 { + t.Fatalf("collected %v before the precondition check passed", plugin.deletedIDs) + } + + if _, err := w.DeleteSharedVolume(ctx, volumeRef, store.DeletePreconditions{UID: created.GetMetadata().GetUid()}); err != nil { + t.Fatalf("DeleteSharedVolume: %v", err) + } + if diff := cmp.Diff([]string{created.GetVolumeId()}, plugin.deletedIDs); diff != "" { + t.Errorf("collected disks mismatch (-want +got):\n%s", diff) + } + if _, err := persistence.GetSharedVolume(ctx, volumeRef); err == nil { + t.Errorf("GetSharedVolume after delete succeeded, want the row gone") + } +} + +func TestDeleteSharedVolume_StillReferenced(t *testing.T) { + ctx := context.Background() + w, persistence, plugin := newTestSharedVolumeWorkflow(t) + + created, err := w.CreateSharedVolume(ctx, &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "shared"}, + StorageClassName: "standard", + Capacity: "10Gi", + }) + if err != nil { + t.Fatalf("CreateSharedVolume: %v", err) + } + volumeRef := resources.SharedVolumeRefFromSharedVolume(created) + if _, err := persistence.UpdateSharedVolume(ctx, volumeRef, store.PreconditionFrom(created), func(toUpdate *ateapipb.SharedVolume) error { + toUpdate.Status.Refs = []*ateapipb.ActorRef{{ActorUid: "uid-1", ActorName: "producer"}} + return nil + }); err != nil { + t.Fatalf("UpdateSharedVolume: %v", err) + } + + _, err = w.DeleteSharedVolume(ctx, volumeRef, store.DeletePreconditions{}) + if got := apierror.Code(err); got != codes.FailedPrecondition { + t.Fatalf("DeleteSharedVolume error = %v (code %v), want code %v", err, got, codes.FailedPrecondition) + } + if len(plugin.deletedIDs) != 0 { + t.Errorf("collected %v, want the disk left alone while an actor holds it", plugin.deletedIDs) + } +} + +func TestDeleteSharedVolume_Pending(t *testing.T) { + ctx := context.Background() + w, persistence, plugin := newTestSharedVolumeWorkflow(t) + + pending, err := persistence.CreateSharedVolume(ctx, &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "stranded"}, + StorageClassName: "standard", + VolumeType: "mock", + Status: &ateapipb.SharedVolumeStatus{State: ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_PENDING}, + }) + if err != nil { + t.Fatalf("CreateSharedVolume: %v", err) + } + + if _, err := w.DeleteSharedVolume(ctx, resources.SharedVolumeRefFromSharedVolume(pending), store.DeletePreconditions{}); err != nil { + t.Fatalf("DeleteSharedVolume: %v", err) + } + want := []string{sharedVolumeID(pending.GetMetadata().GetUid())} + if diff := cmp.Diff(want, plugin.deletedIDs); diff != "" { + t.Errorf("collected disks mismatch (-want +got):\n%s", diff) + } +} + +func TestDeleteSharedVolume_NotFound(t *testing.T) { + ctx := context.Background() + w, _, _ := newTestSharedVolumeWorkflow(t) + + _, err := w.DeleteSharedVolume(ctx, resources.SharedVolumeRef{Atespace: "team-a", Name: "nope"}, store.DeletePreconditions{}) + if got := apierror.Code(err); got != codes.NotFound { + t.Fatalf("DeleteSharedVolume error = %v (code %v), want code %v", err, got, codes.NotFound) + } +} diff --git a/cmd/ateapi/internal/controlapi/workflow.go b/cmd/ateapi/internal/controlapi/workflow.go index 97d0b46209..fc40b265e9 100644 --- a/cmd/ateapi/internal/controlapi/workflow.go +++ b/cmd/ateapi/internal/controlapi/workflow.go @@ -241,3 +241,7 @@ func (w *ActorWorkflow) acquireActorLease(ctx context.Context, actorRef resource func acquireTagLease(ctx context.Context, holder leaseHolder, tagRef resources.TagRef) (context.Context, *store.Lease, error) { return acquireLease(ctx, holder, "lease:tag:"+tagRef.Atespace+":"+tagRef.Name, "Tag") } + +func acquireSharedVolumeLease(ctx context.Context, holder leaseHolder, volumeRef resources.SharedVolumeRef) (context.Context, *store.Lease, error) { + return acquireLease(ctx, holder, "lease:sharedvolume:"+volumeRef.Atespace+":"+volumeRef.Name, "SharedVolume") +} diff --git a/cmd/ateapi/internal/controlapi/workflow_shared_volume.go b/cmd/ateapi/internal/controlapi/workflow_shared_volume.go new file mode 100644 index 0000000000..25b124f919 --- /dev/null +++ b/cmd/ateapi/internal/controlapi/workflow_shared_volume.go @@ -0,0 +1,290 @@ +// 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" + "errors" + "fmt" + "log/slog" + + "github.com/agent-substrate/substrate/cmd/ateapi/internal/store" + "github.com/agent-substrate/substrate/internal/apierror" + "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" + storagev1 "k8s.io/api/storage/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + storagev1listers "k8s.io/client-go/listers/storage/v1" +) + +// SharedVolumeWorkflow handles the multi-step create and delete of an +// SharedVolume, each of which spans a store write and a CSI call. +type SharedVolumeWorkflow struct { + store sharedVolumeWorkflowStore + storageClassLister storagev1listers.StorageClassLister + pluginRegistry VolumePluginRegistry +} + +// NewSharedVolumeWorkflow creates a new SharedVolumeWorkflow. +func NewSharedVolumeWorkflow( + store sharedVolumeWorkflowStore, + storageClassLister storagev1listers.StorageClassLister, + pluginRegistry VolumePluginRegistry, +) *SharedVolumeWorkflow { + return &SharedVolumeWorkflow{ + store: store, + storageClassLister: storageClassLister, + pluginRegistry: pluginRegistry, + } +} + +type sharedVolumeWorkflowStore interface { + CreateSharedVolume(ctx context.Context, volume *ateapipb.SharedVolume) (*ateapipb.SharedVolume, error) + GetSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef) (*ateapipb.SharedVolume, error) + UpdateSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef, precondition store.Precondition, mutate func(toUpdate *ateapipb.SharedVolume) error) (*ateapipb.SharedVolume, error) + DeleteSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef, precondition store.DeletePreconditions) (*ateapipb.SharedVolume, error) + AcquireLease(ctx context.Context, key string) (*store.Lease, error) +} + +// CreateSharedVolume reserves the name, provisions the volume under an ID +// derived from the record's UID, and stamps the handle the driver returned. +// A create that dies leaves a PENDING record; delete it to retry. +func (w *SharedVolumeWorkflow) CreateSharedVolume(ctx context.Context, volume *ateapipb.SharedVolume) (*ateapipb.SharedVolume, error) { + volumeRef := resources.SharedVolumeRefFromSharedVolume(volume) + + ctx, lease, err := acquireSharedVolumeLease(ctx, w.store, volumeRef) + if err != nil { + return nil, err + } + defer lease.Close() + + toCreate, provisioning, err := w.resolveExternalVolumeSource(ctx, volume) + if err != nil { + return nil, err + } + reserved, err := w.ensureSharedVolumeReserved(ctx, volumeRef, toCreate) + if err != nil { + return nil, err + } + if provisioning == nil { + return reserved, nil + } + volumeID, volumeContext, err := w.ensureSharedVolumeProvisioned(ctx, reserved, provisioning) + if err != nil { + return nil, err + } + return w.ensureSharedVolumeFinalized(ctx, reserved, volumeID, volumeContext) +} + +type sharedVolumeProvisioning struct { + provisioner string + parameters map[string]string +} + +// resolveExternalVolumeSource returns the record to reserve and, unless the +// request registers an existing volume, what provisioning it needs. +func (w *SharedVolumeWorkflow) resolveExternalVolumeSource(ctx context.Context, volume *ateapipb.SharedVolume) (_ *ateapipb.SharedVolume, _ *sharedVolumeProvisioning, err error) { + _, done := stepSpan(ctx, "ResolveExternalVolumeSource") + defer func() { err = done(err) }() + + toCreate := &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{ + Atespace: volume.GetMetadata().GetAtespace(), + Name: volume.GetMetadata().GetName(), + }, + DeleteTrigger: volume.GetDeleteTrigger(), + AccessMode: volume.GetAccessMode(), + StorageClassName: volume.GetStorageClassName(), + VolumeId: volume.GetVolumeId(), + VolumeType: volume.GetVolumeType(), + VolumeContext: volume.GetVolumeContext(), + Capacity: volume.GetCapacity(), + Status: &ateapipb.SharedVolumeStatus{State: ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_PENDING}, + } + + var sc *storagev1.StorageClass + if scName := volume.GetStorageClassName(); scName != "" { + var err error + if sc, err = w.storageClassLister.Get(scName); err != nil { + if k8serrors.IsNotFound(err) { + return nil, nil, apierror.FailedPrecondition("StorageClass %q not found", scName) + } + return nil, nil, apierror.Internal("failed to get StorageClass %q: %v", scName, err) + } + } + + if toCreate.VolumeId != "" { + if toCreate.DeleteTrigger == ateapipb.DeleteTrigger_DELETE_TRIGGER_UNSPECIFIED { + toCreate.DeleteTrigger = ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL + } + if toCreate.VolumeType == "" && sc != nil { + toCreate.VolumeType = sc.Provisioner + } + toCreate.Status.State = ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY + return toCreate, nil, nil + } + if sc == nil { + return nil, nil, apierror.InvalidArgument("one of storage_class_name or volume_id is required") + } + if toCreate.DeleteTrigger == ateapipb.DeleteTrigger_DELETE_TRIGGER_UNSPECIFIED { + toCreate.DeleteTrigger = ateapipb.DeleteTrigger_DELETE_TRIGGER_LAST_ACTOR + } + toCreate.VolumeType = sc.Provisioner + return toCreate, &sharedVolumeProvisioning{provisioner: sc.Provisioner, parameters: sc.Parameters}, nil +} + +func (w *SharedVolumeWorkflow) ensureSharedVolumeReserved(ctx context.Context, volumeRef resources.SharedVolumeRef, toCreate *ateapipb.SharedVolume) (_ *ateapipb.SharedVolume, err error) { + ctx, done := stepSpan(ctx, "ReserveSharedVolume") + defer func() { err = done(err) }() + + stored, err := w.store.CreateSharedVolume(ctx, toCreate) + switch { + case err == nil: + return stored, nil + case errors.Is(err, store.ErrFailedPrecondition): + return nil, apierror.FailedPrecondition("Atespace %s not found", volumeRef.Atespace) + case errors.Is(err, store.ErrAlreadyExists): + return nil, apierror.AlreadyExists("SharedVolume %s already exists; delete it and create it again to retry", volumeRef) + } + return nil, fmt.Errorf("while reserving shared volume %s: %w", volumeRef, err) +} + +// TODO: pass access_mode to CreateVolume as the volume capability once +// READ_WRITE_MANY is accepted. +func (w *SharedVolumeWorkflow) ensureSharedVolumeProvisioned(ctx context.Context, volume *ateapipb.SharedVolume, provisioning *sharedVolumeProvisioning) (_ string, _ map[string]string, err error) { + ctx, done := stepSpan(ctx, "ProvisionSharedVolume") + defer func() { err = done(err) }() + + volumeRef := resources.SharedVolumeRefFromSharedVolume(volume) + plugin, err := w.pluginRegistry.GetPlugin(ctx, provisioning.provisioner) + if err != nil { + return "", nil, apierror.FailedPrecondition("failed to get volume plugin for driver %q (StorageClass %q): %v", provisioning.provisioner, volume.GetStorageClassName(), err) + } + resp, err := plugin.CreateVolume(ctx, createVolumeRequest(sharedVolumeID(volume.GetMetadata().GetUid()), volume.GetCapacity(), provisioning.parameters)) + if err != nil { + return "", nil, apierror.Internal("failed to create shared volume %s: %v", volumeRef, err) + } + return resp.VolumeID, resp.VolumeContext, nil +} + +// createVolumeRequest keeps the request construction out of callers whose +// parameters shadow the volume package. +func createVolumeRequest(name, capacity string, parameters map[string]string) volume.CreateVolumeRequest { + return volume.CreateVolumeRequest{Name: name, Capacity: capacity, Parameters: parameters} +} + +func (w *SharedVolumeWorkflow) ensureSharedVolumeFinalized(ctx context.Context, volume *ateapipb.SharedVolume, volumeID string, volumeContext map[string]string) (_ *ateapipb.SharedVolume, err error) { + ctx, done := stepSpan(ctx, "FinalizeSharedVolume") + defer func() { err = done(err) }() + + volumeRef := resources.SharedVolumeRefFromSharedVolume(volume) + stored, err := w.store.UpdateSharedVolume(ctx, volumeRef, store.PreconditionFrom(volume), func(toUpdate *ateapipb.SharedVolume) error { + toUpdate.VolumeId = volumeID + toUpdate.VolumeContext = volumeContext + toUpdate.Status.State = ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY + return nil + }) + if err != nil { + if errors.Is(err, store.ErrVersionConflict) { + return nil, apierror.Aborted("concurrent update conflict, please retry") + } + if errors.Is(err, store.ErrNotFound) || errors.Is(err, store.ErrUIDConflict) { + return nil, apierror.Aborted("SharedVolume %s was deleted while it was being created, please retry", volumeRef) + } + return nil, fmt.Errorf("while finalizing shared volume %s: %w", volumeRef, err) + } + return stored, nil +} + +// DeleteSharedVolume deletes the storage and then removes the record, so a +// failure part way is retried by deleting again. Rejected while any actor +// references the volume. +func (w *SharedVolumeWorkflow) DeleteSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef, precondition store.DeletePreconditions) (*ateapipb.SharedVolume, error) { + ctx, lease, err := acquireSharedVolumeLease(ctx, w.store, volumeRef) + if err != nil { + return nil, err + } + defer lease.Close() + + stored, err := w.store.GetSharedVolume(ctx, volumeRef) + if err != nil { + if errors.Is(err, store.ErrNotFound) { + return nil, apierror.NotFound("SharedVolume %s not found", volumeRef) + } + return nil, fmt.Errorf("while getting shared volume: %w", err) + } + if err := precondition.Check(stored.GetMetadata()); err != nil { + return nil, sharedVolumeDeleteConflict(err, volumeRef, precondition) + } + if refs := stored.GetStatus().GetRefs(); len(refs) > 0 { + return nil, apierror.FailedPrecondition("SharedVolume %s is still referenced by %d actor(s), starting with %q", volumeRef, len(refs), refs[0].GetActorName()) + } + if err := w.reclaimSharedVolume(ctx, stored); err != nil { + return nil, err + } + + volume, err := w.store.DeleteSharedVolume(ctx, volumeRef, precondition) + if err != nil { + if errors.Is(err, store.ErrNotFound) { + return nil, apierror.NotFound("SharedVolume %s not found", volumeRef) + } + if errors.Is(err, store.ErrUIDConflict) || errors.Is(err, store.ErrVersionConflict) { + return nil, sharedVolumeDeleteConflict(err, volumeRef, precondition) + } + return nil, fmt.Errorf("while deleting shared volume: %w", err) + } + return volume, nil +} + +func sharedVolumeDeleteConflict(err error, volumeRef resources.SharedVolumeRef, precondition store.DeletePreconditions) error { + if errors.Is(err, store.ErrUIDConflict) { + return apierror.Aborted("SharedVolume %s does not have uid %s", volumeRef, precondition.UID) + } + return apierror.Aborted("concurrent update conflict, please retry") +} + +// TODO: add a reclaim policy that leaves the storage in place. +func (w *SharedVolumeWorkflow) reclaimSharedVolume(ctx context.Context, volume *ateapipb.SharedVolume) (err error) { + ctx, done := stepSpan(ctx, "ReclaimSharedVolume") + defer func() { err = done(err) }() + + volumeRef := resources.SharedVolumeRefFromSharedVolume(volume) + if volume.GetVolumeType() == "" { + markSkipped(ctx, "volume names no driver") + return nil + } + volumeID := volume.GetVolumeId() + if volumeID == "" { + volumeID = sharedVolumeID(volume.GetMetadata().GetUid()) + } + plugin, err := w.pluginRegistry.GetPlugin(ctx, volume.GetVolumeType()) + if err != nil { + return fmt.Errorf("while getting the volume plugin for %q of shared volume %s: %w", volume.GetVolumeType(), volumeRef, err) + } + if err := plugin.DeleteVolume(ctx, volumeID); err != nil { + if apierror.Code(err) == codes.NotFound { + slog.WarnContext(ctx, "Volume not found during delete, assuming already deleted", slog.String("volume_id", volumeID)) + return nil + } + return fmt.Errorf("while reclaiming the storage %q of shared volume %s: %w", volumeID, volumeRef, err) + } + return nil +} + +func sharedVolumeID(volumeUID string) string { + return "substrate-" + volumeUID +} diff --git a/cmd/ateapi/internal/defaults/defaults.go b/cmd/ateapi/internal/defaults/defaults.go index ff31f792d4..ca36e794be 100644 --- a/cmd/ateapi/internal/defaults/defaults.go +++ b/cmd/ateapi/internal/defaults/defaults.go @@ -38,6 +38,8 @@ func Apply(m proto.Message) { applyAtespaceDefaults(v) case *ateapipb.EgressPolicy: applyEgressPolicyDefaults(v) + case *ateapipb.SharedVolume: + applySharedVolumeDefaults(v) case *ateapipb.Tag: applyTagDefaults(v) case *ateapipb.Worker: @@ -111,6 +113,15 @@ func applyEgressPolicyDefaults(p *ateapipb.EgressPolicy) { } } +func applySharedVolumeDefaults(v *ateapipb.SharedVolume) { + if v == nil { + return + } + if v.AccessMode == ateapipb.AccessMode_ACCESS_MODE_UNSPECIFIED { + v.AccessMode = ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_ONCE + } +} + func applyTagDefaults(*ateapipb.Tag) {} func applyWorkerDefaults(*ateapipb.Worker) {} diff --git a/cmd/ateapi/internal/defaults/defaults_test.go b/cmd/ateapi/internal/defaults/defaults_test.go index 0aa3646204..edb13f0f55 100644 --- a/cmd/ateapi/internal/defaults/defaults_test.go +++ b/cmd/ateapi/internal/defaults/defaults_test.go @@ -57,6 +57,14 @@ func TestApply(t *testing.T) { PreferredFidelity: scopeData, GoldenSnapshotConfig: &ateapipb.GoldenSnapshotConfig{Mode: ateapipb.GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_ENABLED}, }}, + }, { + name: "external volume without an access mode gets read write once", + in: &ateapipb.SharedVolume{}, + want: &ateapipb.SharedVolume{AccessMode: ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_ONCE}, + }, { + name: "external volume keeps its access mode", + in: &ateapipb.SharedVolume{AccessMode: ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_MANY}, + want: &ateapipb.SharedVolume{AccessMode: ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_MANY}, }, { name: "container without wakeup probe stays without one", in: &ateapipb.ActorTemplate{Containers: []*ateapipb.Container{{Name: "main"}}}, diff --git a/cmd/ateapi/internal/store/atepg/common_test.go b/cmd/ateapi/internal/store/atepg/common_test.go index 6edd774f3e..ef7ef4dd6e 100644 --- a/cmd/ateapi/internal/store/atepg/common_test.go +++ b/cmd/ateapi/internal/store/atepg/common_test.go @@ -27,7 +27,7 @@ import ( // state, so the statement lives here rather than on Persistence. func clearAll(t *testing.T, p *Persistence) { t.Helper() - if _, err := p.pool.Exec(context.Background(), `TRUNCATE atespaces, global_access_policy, atespace_access_policies, actors, actor_egress_policies, actor_templates, tags, workers, worker_assignments, leases, worker_outbox, worker_outbox_trim, tuple, changelog`); err != nil { + if _, err := p.pool.Exec(context.Background(), `TRUNCATE atespaces, global_access_policy, atespace_access_policies, actors, actor_egress_policies, actor_templates, tags, shared_volumes, workers, worker_assignments, leases, worker_outbox, worker_outbox_trim, tuple, changelog`); err != nil { t.Fatalf("truncating tables: %v", err) } } diff --git a/cmd/ateapi/internal/store/atepg/migrations/000004_shared_volumes.sql b/cmd/ateapi/internal/store/atepg/migrations/000004_shared_volumes.sql new file mode 100644 index 0000000000..c63c55dd8d --- /dev/null +++ b/cmd/ateapi/internal/store/atepg/migrations/000004_shared_volumes.sql @@ -0,0 +1,27 @@ +-- 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. + +-- +goose Up + +-- RESTRICT so that deleting an atespace cannot strand provisioned storage. +CREATE TABLE shared_volumes ( + atespace text NOT NULL, + name text NOT NULL, + uid text NOT NULL, + version bigint NOT NULL, + proto bytea NOT NULL, + PRIMARY KEY (atespace, name), + CONSTRAINT shared_volumes_atespace_fk + FOREIGN KEY (atespace) REFERENCES atespaces(name) ON DELETE RESTRICT +); diff --git a/cmd/ateapi/internal/store/atepg/pagetoken.go b/cmd/ateapi/internal/store/atepg/pagetoken.go index ebf56b5ae2..a282938339 100644 --- a/cmd/ateapi/internal/store/atepg/pagetoken.go +++ b/cmd/ateapi/internal/store/atepg/pagetoken.go @@ -35,6 +35,7 @@ const ( kindActor resourceKind = "actor" kindActorTemplate resourceKind = "actor-template" kindTag resourceKind = "tag" + kindExternalVol resourceKind = "external-volume" kindWorker resourceKind = "worker" kindWorkerAssign resourceKind = "worker-assignment" ) diff --git a/cmd/ateapi/internal/store/atepg/partition_test.go b/cmd/ateapi/internal/store/atepg/partition_test.go index 20ba51fd29..8c28668414 100644 --- a/cmd/ateapi/internal/store/atepg/partition_test.go +++ b/cmd/ateapi/internal/store/atepg/partition_test.go @@ -45,7 +45,7 @@ func TestActorsTablePartitionable(t *testing.T) { // by definition, under each partition key. spansPartitions := map[string][]string{ // A global list walks every atespace. - "atespace": {globalList("actors"), globalList("actor_templates"), globalList("tags")}, + "atespace": {globalList("actors"), globalList("actor_templates"), globalList("tags"), globalList("shared_volumes")}, // A global list walks every name, and a list within one atespace // spans every name hash. "name": {globalList("actors"), scopedActorList}, diff --git a/cmd/ateapi/internal/store/atepg/shared_volume.go b/cmd/ateapi/internal/store/atepg/shared_volume.go new file mode 100644 index 0000000000..84e77d6640 --- /dev/null +++ b/cmd/ateapi/internal/store/atepg/shared_volume.go @@ -0,0 +1,297 @@ +// 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 atepg + +import ( + "context" + "errors" + "fmt" + "maps" + + "github.com/agent-substrate/substrate/cmd/ateapi/internal/store" + "github.com/agent-substrate/substrate/internal/resources" + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" + "github.com/jackc/pgx/v5" + "google.golang.org/protobuf/proto" +) + +func (p *Persistence) GetSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef) (*ateapipb.SharedVolume, error) { + atespace, name := volumeRef.Atespace, volumeRef.Name + var protoBytes []byte + if err := p.pool.QueryRow(ctx, ` + SELECT proto FROM shared_volumes + WHERE atespace = $1 AND name = $2`, atespace, name).Scan(&protoBytes); err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return nil, store.ErrNotFound + } + return nil, fmt.Errorf("getting shared volume %s/%s: %w", atespace, name, err) + } + volume := &ateapipb.SharedVolume{} + if err := unmarshalStored(protoBytes, volume); err != nil { + return nil, fmt.Errorf("unmarshaling shared volume: %w", err) + } + return volume, nil +} + +func (p *Persistence) ListSharedVolumes(ctx context.Context, atespace string, opts store.ListOptions) (store.ListResponse[*ateapipb.SharedVolume], error) { + opts, err := store.NormalizeListOptions(opts) + if err != nil { + return store.ListResponse[*ateapipb.SharedVolume]{}, err + } + var items []*ateapipb.SharedVolume + var nextToken string + if atespace != "" { + items, nextToken, err = p.listSharedVolumesScoped(ctx, atespace, opts.PageSize, opts.PageToken) + } else { + items, nextToken, err = p.listSharedVolumesGlobal(ctx, opts.PageSize, opts.PageToken) + } + if err != nil { + return store.ListResponse[*ateapipb.SharedVolume]{}, err + } + return store.ListResponse[*ateapipb.SharedVolume]{Items: items, NextPageToken: nextToken}, nil +} + +func (p *Persistence) listSharedVolumesScoped(ctx context.Context, atespace string, pageSize int32, pageTokenStr string) ([]*ateapipb.SharedVolume, string, error) { + token, err := decodePageToken(pageTokenStr, kindExternalVol, atespace, 1) + if err != nil { + return nil, "", err + } + var last *string + if len(token.Last) > 0 { + last = &token.Last[0] + } + rows, err := p.pool.Query(ctx, ` + SELECT name, proto FROM shared_volumes + WHERE atespace = $1 AND ($2::text IS NULL OR name > $2) + ORDER BY name + LIMIT $3`, atespace, last, int64(pageSize)+1) + if err != nil { + return nil, "", fmt.Errorf("listing shared volumes in %q: %w", atespace, err) + } + defer rows.Close() + + var names []string + var result []*ateapipb.SharedVolume + for rows.Next() { + var name string + var protoBytes []byte + if err := rows.Scan(&name, &protoBytes); err != nil { + return nil, "", fmt.Errorf("scanning shared volume row: %w", err) + } + volume := &ateapipb.SharedVolume{} + if err := unmarshalStored(protoBytes, volume); err != nil { + return nil, "", fmt.Errorf("unmarshaling shared volume: %w", err) + } + result = append(result, volume) + names = append(names, name) + } + if err := rows.Err(); err != nil { + return nil, "", fmt.Errorf("listing shared volumes in %q: %w", atespace, err) + } + var nextToken string + if len(result) > int(pageSize) { + result = result[:pageSize] + nextToken = encodePageToken(kindExternalVol, atespace, []string{names[pageSize-1]}) + } + return result, nextToken, nil +} + +func (p *Persistence) listSharedVolumesGlobal(ctx context.Context, pageSize int32, pageTokenStr string) ([]*ateapipb.SharedVolume, string, error) { + token, err := decodePageToken(pageTokenStr, kindExternalVol, "", 2) + if err != nil { + return nil, "", err + } + var lastAtespace, lastName *string + if len(token.Last) == 2 { + lastAtespace, lastName = &token.Last[0], &token.Last[1] + } + rows, err := p.pool.Query(ctx, ` + SELECT atespace, name, proto FROM shared_volumes + WHERE $1::text IS NULL OR (atespace, name) > ($1, $2) + ORDER BY atespace, name + LIMIT $3`, lastAtespace, lastName, int64(pageSize)+1) + if err != nil { + return nil, "", fmt.Errorf("listing shared volumes: %w", err) + } + defer rows.Close() + + type key struct{ atespace, name string } + var keys []key + var result []*ateapipb.SharedVolume + for rows.Next() { + var k key + var protoBytes []byte + if err := rows.Scan(&k.atespace, &k.name, &protoBytes); err != nil { + return nil, "", fmt.Errorf("scanning shared volume row: %w", err) + } + volume := &ateapipb.SharedVolume{} + if err := unmarshalStored(protoBytes, volume); err != nil { + return nil, "", fmt.Errorf("unmarshaling shared volume: %w", err) + } + result = append(result, volume) + keys = append(keys, k) + } + if err := rows.Err(); err != nil { + return nil, "", fmt.Errorf("listing shared volumes: %w", err) + } + var nextToken string + if len(result) > int(pageSize) { + result = result[:pageSize] + last := keys[pageSize-1] + nextToken = encodePageToken(kindExternalVol, "", []string{last.atespace, last.name}) + } + return result, nextToken, nil +} + +func (p *Persistence) CreateSharedVolume(ctx context.Context, volume *ateapipb.SharedVolume) (*ateapipb.SharedVolume, error) { + atespace := volume.GetMetadata().GetAtespace() + name := volume.GetMetadata().GetName() + dbVolume := proto.CloneOf(volume) + setCreateMetadata(dbVolume.Metadata) + protoBytes, err := proto.Marshal(dbVolume) + if err != nil { + return nil, fmt.Errorf("marshaling shared volume: %w", err) + } + + _, err = p.pool.Exec(ctx, ` + INSERT INTO shared_volumes (atespace, name, uid, version, proto) + VALUES ($1, $2, $3, $4, $5)`, atespace, name, + dbVolume.GetMetadata().GetUid(), dbVolume.GetMetadata().GetVersion(), protoBytes) + if err != nil { + if isUniqueViolation(err) { + return nil, store.ErrAlreadyExists + } + if isForeignKeyViolation(err) { + switch pgErrConstraint(err) { + case "shared_volumes_atespace_fk": + return nil, store.ErrFailedPrecondition + default: + return nil, fmt.Errorf("inserting shared volume %s/%s violated unknown foreign key %q: %w", atespace, name, pgErrConstraint(err), err) + } + } + return nil, fmt.Errorf("inserting shared volume %s/%s: %w", atespace, name, err) + } + return dbVolume, nil +} + +func validateUpdateSharedVolumeMutation(storedVolume, mutatedVolume *ateapipb.SharedVolume) error { + if stored, mutated := storedVolume.GetMetadata().GetAtespace(), mutatedVolume.GetMetadata().GetAtespace(); stored != mutated { + return fmt.Errorf("metadata.atespace is immutable: mutation changed it from %q to %q", stored, mutated) + } + if stored, mutated := storedVolume.GetMetadata().GetName(), mutatedVolume.GetMetadata().GetName(); stored != mutated { + return fmt.Errorf("metadata.name is immutable: mutation changed it from %q to %q", stored, mutated) + } + if stored, mutated := storedVolume.GetAccessMode(), mutatedVolume.GetAccessMode(); stored != ateapipb.AccessMode_ACCESS_MODE_UNSPECIFIED && stored != mutated { + return fmt.Errorf("access_mode is immutable once set: mutation changed it from %v to %v", stored, mutated) + } + if stored, mutated := storedVolume.GetStorageClassName(), mutatedVolume.GetStorageClassName(); stored != "" && stored != mutated { + return fmt.Errorf("storage_class_name is immutable once set: mutation changed it from %q to %q", stored, mutated) + } + if stored, mutated := storedVolume.GetCapacity(), mutatedVolume.GetCapacity(); stored != "" && stored != mutated { + return fmt.Errorf("capacity is immutable once set: mutation changed it from %q to %q", stored, mutated) + } + if stored, mutated := storedVolume.GetVolumeId(), mutatedVolume.GetVolumeId(); stored != "" && stored != mutated { + return fmt.Errorf("volume_id is immutable once set: mutation changed it from %q to %q", stored, mutated) + } + if stored, mutated := storedVolume.GetVolumeType(), mutatedVolume.GetVolumeType(); stored != "" && stored != mutated { + return fmt.Errorf("volume_type is immutable once set: mutation changed it from %q to %q", stored, mutated) + } + if stored, mutated := storedVolume.GetVolumeContext(), mutatedVolume.GetVolumeContext(); len(stored) > 0 && !maps.Equal(stored, mutated) { + return fmt.Errorf("volume_context is immutable once set: mutation changed it from %v to %v", stored, mutated) + } + return nil +} + +func (p *Persistence) UpdateSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef, precondition store.Precondition, mutate func(*ateapipb.SharedVolume) error) (*ateapipb.SharedVolume, error) { + if err := precondition.Validate(); err != nil { + return nil, err + } + atespace, name := volumeRef.Atespace, volumeRef.Name + var currentUID string + var currentVersion int64 + var currentBytes []byte + if err := p.pool.QueryRow(ctx, ` + SELECT uid, version, proto FROM shared_volumes + WHERE atespace = $1 AND name = $2`, atespace, name).Scan(¤tUID, ¤tVersion, ¤tBytes); err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return nil, store.ErrNotFound + } + return nil, fmt.Errorf("getting shared volume %s/%s for update: %w", atespace, name, err) + } + + dbVolume := &ateapipb.SharedVolume{} + if err := unmarshalStored(currentBytes, dbVolume); err != nil { + return nil, fmt.Errorf("unmarshaling shared volume: %w", err) + } + if err := validateProtoMetadataMatchesColumns(fmt.Sprintf("shared volume %s/%s", atespace, name), dbVolume.GetMetadata(), currentUID, currentVersion); err != nil { + return nil, err + } + if err := precondition.Check(dbVolume.GetMetadata()); err != nil { + return nil, err + } + volumeBeforeMutation := proto.CloneOf(dbVolume) + if err := mutate(dbVolume); err != nil { + return nil, err + } + if err := validateUpdateSharedVolumeMutation(volumeBeforeMutation, dbVolume); err != nil { + return nil, fmt.Errorf("%w: %w", store.ErrImmutableField, err) + } + setUpdateMetadata(dbVolume.Metadata, volumeBeforeMutation.GetMetadata()) + + updatedBytes, err := proto.Marshal(dbVolume) + if err != nil { + return nil, fmt.Errorf("marshaling shared volume: %w", err) + } + commandTag, err := p.pool.Exec(ctx, ` + UPDATE shared_volumes + SET version = $1, proto = $2 + WHERE atespace = $3 AND name = $4 AND uid = $5 AND version = $6`, + dbVolume.GetMetadata().GetVersion(), updatedBytes, atespace, name, currentUID, currentVersion) + if err != nil { + return nil, fmt.Errorf("updating shared volume %s/%s: %w", atespace, name, err) + } + if commandTag.RowsAffected() == 0 { + return nil, store.ErrVersionConflict + } + if commandTag.RowsAffected() != 1 { + return nil, fmt.Errorf("updating shared volume %s/%s affected %d rows, want 1", atespace, name, commandTag.RowsAffected()) + } + return dbVolume, nil +} + +func (p *Persistence) DeleteSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef, precondition store.DeletePreconditions) (*ateapipb.SharedVolume, error) { + atespace, name := volumeRef.Atespace, volumeRef.Name + var protoBytes []byte + err := p.pool.QueryRow(ctx, ` + DELETE FROM shared_volumes + WHERE atespace = $1 AND name = $2 + AND ($3::text = '' OR uid = $3::text) + AND ($4::bigint = 0 OR version = $4::bigint) + RETURNING proto`, atespace, name, precondition.UID, precondition.Version).Scan(&protoBytes) + if errors.Is(err, pgx.ErrNoRows) { + var uid string + var version int64 + err := p.pool.QueryRow(ctx, `SELECT uid, version FROM shared_volumes WHERE atespace = $1 AND name = $2`, atespace, name).Scan(&uid, &version) + return nil, mapDeleteError(err, uid, version, precondition) + } + if err != nil { + return nil, fmt.Errorf("deleting shared volume %s/%s: %w", atespace, name, err) + } + volume := &ateapipb.SharedVolume{} + if err := unmarshalStored(protoBytes, volume); err != nil { + return nil, fmt.Errorf("unmarshaling deleted shared volume: %w", err) + } + return volume, nil +} diff --git a/cmd/ateapi/internal/store/store.go b/cmd/ateapi/internal/store/store.go index cc494082c1..162fee3fc1 100644 --- a/cmd/ateapi/internal/store/store.go +++ b/cmd/ateapi/internal/store/store.go @@ -159,6 +159,26 @@ type Interface interface { // tag the caller observed. DeleteTag(ctx context.Context, tagRef resources.TagRef, precondition DeletePreconditions) (*ateapipb.Tag, error) + // Stores a new external volume and returns it with server-assigned metadata. + // Returns ErrAlreadyExists if the name is taken, or ErrFailedPrecondition if + // the atespace does not exist. + CreateSharedVolume(ctx context.Context, volume *ateapipb.SharedVolume) (*ateapipb.SharedVolume, error) + + // Fetches an external volume by reference. Returns ErrNotFound if missing. + GetSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef) (*ateapipb.SharedVolume, error) + + // Lists external volumes in one atespace, or all atespaces when empty. + ListSharedVolumes(ctx context.Context, atespace string, opts ListOptions) (ListResponse[*ateapipb.SharedVolume], error) + + // UpdateSharedVolume performs a guarded read-modify-write like UpdateTag. + // Everything naming the storage, and access_mode, is set-once and returns + // ErrImmutableField when changed. + UpdateSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef, precondition Precondition, mutate func(toUpdate *ateapipb.SharedVolume) error) (*ateapipb.SharedVolume, error) + + // Deletes and returns an external volume record; the storage is the caller's + // job. + DeleteSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef, precondition DeletePreconditions) (*ateapipb.SharedVolume, error) + // Stores a new atespace and returns the stored resource with server-assigned // metadata (uid, version, timestamps). The input is not mutated. Returns // ErrAlreadyExists if the name is taken. diff --git a/cmd/ateapi/internal/store/storecontract/contract.go b/cmd/ateapi/internal/store/storecontract/contract.go index c573db9eef..a168a2df50 100644 --- a/cmd/ateapi/internal/store/storecontract/contract.go +++ b/cmd/ateapi/internal/store/storecontract/contract.go @@ -209,6 +209,7 @@ func RunContractTests(t *testing.T, setup func(t *testing.T) store.Interface) { runAtespaceContractTests(t, setup) runActorTemplateContractTests(t, setup) runTagContractTests(t, setup) + runSharedVolumeContractTests(t, setup) runLeaseContractTests(t, setup) runListOptionsContractTests(t, setup) runUnknownFieldContractTests(t, setup) @@ -394,6 +395,7 @@ func runListOptionsContractTests(t *testing.T, setup func(t *testing.T) store.In {"actors", func(opts store.ListOptions) error { _, err := s.ListActors(ctx, "", opts); return err }}, {"actor templates", func(opts store.ListOptions) error { _, err := s.ListActorTemplates(ctx, "", opts); return err }}, {"tags", func(opts store.ListOptions) error { _, err := s.ListTags(ctx, "", opts); return err }}, + {"external volumes", func(opts store.ListOptions) error { _, err := s.ListSharedVolumes(ctx, "", opts); return err }}, {"workers", func(opts store.ListOptions) error { _, err := s.ListWorkers(ctx, opts); return err }}, } for _, call := range calls { @@ -419,6 +421,7 @@ func runListOptionsContractTests(t *testing.T, setup func(t *testing.T) store.In {"actors", func(opts store.ListOptions) error { _, err := s.ListActors(ctx, "", opts); return err }}, {"actor templates", func(opts store.ListOptions) error { _, err := s.ListActorTemplates(ctx, "", opts); return err }}, {"tags", func(opts store.ListOptions) error { _, err := s.ListTags(ctx, "", opts); return err }}, + {"external volumes", func(opts store.ListOptions) error { _, err := s.ListSharedVolumes(ctx, "", opts); return err }}, {"workers", func(opts store.ListOptions) error { _, err := s.ListWorkers(ctx, opts); return err }}, } for _, call := range calls { @@ -1575,6 +1578,302 @@ func storeTag(t *testing.T, s store.Interface, tag *ateapipb.Tag) *ateapipb.Tag return stored } +func newTestPendingSharedVolume(atespace, name string) *ateapipb.SharedVolume { + return &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{Atespace: atespace, Name: name}, + DeleteTrigger: ateapipb.DeleteTrigger_DELETE_TRIGGER_LAST_ACTOR, + AccessMode: ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_ONCE, + StorageClassName: "standard-rwx", + Status: &ateapipb.SharedVolumeStatus{State: ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_PENDING}, + } +} + +func finalizeSharedVolume(toUpdate *ateapipb.SharedVolume) error { + toUpdate.VolumeId = "substrate-" + toUpdate.GetMetadata().GetUid() + toUpdate.VolumeType = "filestore.csi.storage.gke.io" + toUpdate.VolumeContext = map[string]string{"ip": "10.0.0.2"} + toUpdate.Status.State = ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY + return nil +} + +func storeSharedVolume(t *testing.T, s store.Interface, volume *ateapipb.SharedVolume) *ateapipb.SharedVolume { + t.Helper() + reserved, err := s.CreateSharedVolume(context.Background(), volume) + if err != nil { + t.Fatalf("CreateSharedVolume(%q) failed: %v", volume.GetMetadata().GetName(), err) + } + stored, err := s.UpdateSharedVolume(context.Background(), resources.SharedVolumeRefFromSharedVolume(reserved), store.PreconditionFrom(reserved), finalizeSharedVolume) + if err != nil { + t.Fatalf("finalizing external volume %q failed: %v", volume.GetMetadata().GetName(), err) + } + return stored +} + +func runSharedVolumeContractTests(t *testing.T, setup func(t *testing.T) store.Interface) { + t.Helper() + + t.Run("SharedVolume_Lifecycle", func(t *testing.T) { + s := setup(t) + ctx := context.Background() + mustCreateAtespace(t, s, "team-a") + + input := newTestPendingSharedVolume("team-a", "scratch") + pending, err := s.CreateSharedVolume(ctx, input) + if err != nil { + t.Fatalf("CreateSharedVolume failed: %v", err) + } + if pending.GetMetadata().GetVersion() != 1 || pending.GetMetadata().GetUid() == "" { + t.Errorf("created volume metadata = %v, want server-owned uid and version 1", pending.GetMetadata()) + } + if input.GetMetadata().GetUid() != "" || input.GetMetadata().GetVersion() != 0 { + t.Errorf("CreateSharedVolume mutated its input metadata: %v", input.GetMetadata()) + } + + volumeRef := resources.SharedVolumeRef{Atespace: "team-a", Name: "scratch"} + volume, err := s.GetSharedVolume(ctx, volumeRef) + if err != nil { + t.Fatalf("GetSharedVolume failed: %v", err) + } + if volume.GetVolumeId() != "" { + t.Errorf("reserved volume id = %q, want unset", volume.GetVolumeId()) + } + if diff := cmp.Diff(input, volume, protocmp.Transform(), ignoreUID, ignoreVersion, ignoreTimestamps); diff != "" { + t.Errorf("stored external volume mismatch (-want +got):\n%s", diff) + } + if _, err := s.GetSharedVolume(ctx, resources.SharedVolumeRef{Atespace: "team-a", Name: "missing"}); !errors.Is(err, store.ErrNotFound) { + t.Errorf("missing GetSharedVolume = %v, want ErrNotFound", err) + } + + ready, err := s.UpdateSharedVolume(ctx, volumeRef, store.PreconditionFrom(volume), finalizeSharedVolume) + if err != nil { + t.Fatalf("finalizing external volume failed: %v", err) + } + if got, want := ready.GetVolumeId(), "substrate-"+volume.GetMetadata().GetUid(); got != want { + t.Errorf("finalized volume id = %q, want %q", got, want) + } + if ready.GetStatus().GetState() != ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY { + t.Errorf("finalized volume state = %v, want READY", ready.GetStatus().GetState()) + } + + claimed, err := s.UpdateSharedVolume(ctx, volumeRef, store.PreconditionFrom(ready), func(toUpdate *ateapipb.SharedVolume) error { + toUpdate.DeleteTrigger = ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL + toUpdate.Status.Refs = append(toUpdate.Status.Refs, &ateapipb.ActorRef{ActorUid: "actor-uid-1", ActorName: "producer", Active: true}) + return nil + }) + if err != nil { + t.Fatalf("UpdateSharedVolume failed: %v", err) + } + if claimed.GetDeleteTrigger() != ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL || len(claimed.GetStatus().GetRefs()) != 1 { + t.Errorf("updated volume = %v, want MANUAL and one ref", claimed) + } + if claimed.GetMetadata().GetVersion() != ready.GetMetadata().GetVersion()+1 { + t.Errorf("updated volume version = %d, want %d", claimed.GetMetadata().GetVersion(), ready.GetMetadata().GetVersion()+1) + } + if _, err := s.UpdateSharedVolume(ctx, volumeRef, store.PreconditionFrom(ready), func(toUpdate *ateapipb.SharedVolume) error { + return nil + }); !errors.Is(err, store.ErrVersionConflict) { + t.Errorf("stale UpdateSharedVolume = %v, want ErrVersionConflict", err) + } + if _, err := s.DeleteAtespace(ctx, "team-a", store.DeletePreconditions{}); !errors.Is(err, store.ErrFailedPrecondition) { + t.Errorf("DeleteAtespace with an external volume = %v, want ErrFailedPrecondition", err) + } + + if _, err := s.DeleteSharedVolume(ctx, volumeRef, store.DeletePreconditions{Version: ready.GetMetadata().GetVersion()}); !errors.Is(err, store.ErrVersionConflict) { + t.Errorf("stale DeleteSharedVolume = %v, want ErrVersionConflict", err) + } + deleted, err := s.DeleteSharedVolume(ctx, volumeRef, store.DeletePreconditions{UID: claimed.GetMetadata().GetUid()}) + if err != nil || !proto.Equal(deleted, claimed) { + t.Errorf("DeleteSharedVolume = (%v, %v), want the claimed volume", deleted, err) + } + if _, err := s.GetSharedVolume(ctx, volumeRef); !errors.Is(err, store.ErrNotFound) { + t.Errorf("deleted GetSharedVolume = %v, want ErrNotFound", err) + } + }) + + t.Run("SharedVolume_ImmutableFields", func(t *testing.T) { + s := setup(t) + ctx := context.Background() + mustCreateAtespace(t, s, "team-a") + volume := storeSharedVolume(t, s, newTestPendingSharedVolume("team-a", "scratch")) + + tests := []struct { + name string + mutate func(*ateapipb.SharedVolume) + }{ + { + name: "access mode", + mutate: func(toUpdate *ateapipb.SharedVolume) { + toUpdate.AccessMode = ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_MANY + }, + }, + { + name: "storage class name", + mutate: func(toUpdate *ateapipb.SharedVolume) { toUpdate.StorageClassName = "premium-rwx" }, + }, + { + name: "clearing the storage class name", + mutate: func(toUpdate *ateapipb.SharedVolume) { toUpdate.StorageClassName = "" }, + }, + { + name: "volume id", + mutate: func(toUpdate *ateapipb.SharedVolume) { toUpdate.VolumeId = "substrate-somewhere-else" }, + }, + { + name: "clearing the volume id", + mutate: func(toUpdate *ateapipb.SharedVolume) { toUpdate.VolumeId = "" }, + }, + { + name: "volume type", + mutate: func(toUpdate *ateapipb.SharedVolume) { toUpdate.VolumeType = "pd.csi.storage.gke.io" }, + }, + { + name: "volume context", + mutate: func(toUpdate *ateapipb.SharedVolume) { toUpdate.VolumeContext = map[string]string{"ip": "10.0.0.3"} }, + }, + { + name: "clearing the volume context", + mutate: func(toUpdate *ateapipb.SharedVolume) { toUpdate.VolumeContext = nil }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := s.UpdateSharedVolume(ctx, resources.SharedVolumeRef{Atespace: "team-a", Name: "scratch"}, store.PreconditionFrom(volume), func(toUpdate *ateapipb.SharedVolume) error { + tt.mutate(toUpdate) + return nil + }) + if !errors.Is(err, store.ErrImmutableField) { + t.Errorf("UpdateSharedVolume error = %v, want one matching store.ErrImmutableField", err) + } + }) + } + }) + + t.Run("CreateSharedVolume_ReusedName", func(t *testing.T) { + s := setup(t) + ctx := context.Background() + mustCreateAtespace(t, s, "team-a") + input := newTestPendingSharedVolume("team-a", "scratch") + if _, err := s.CreateSharedVolume(ctx, input); err != nil { + t.Fatalf("CreateSharedVolume failed: %v", err) + } + if _, err := s.CreateSharedVolume(ctx, input); !errors.Is(err, store.ErrAlreadyExists) { + t.Errorf("duplicate CreateSharedVolume = %v, want ErrAlreadyExists", err) + } + + stored, err := s.GetSharedVolume(ctx, resources.SharedVolumeRef{Atespace: "team-a", Name: "scratch"}) + if err != nil { + t.Fatalf("GetSharedVolume failed: %v", err) + } + if stored.GetMetadata().GetVersion() != 1 { + t.Errorf("volume version after rejected create = %d, want 1", stored.GetMetadata().GetVersion()) + } + }) + + t.Run("CreateSharedVolume_UnknownAtespace", func(t *testing.T) { + s := setup(t) + ctx := context.Background() + + if _, err := s.CreateSharedVolume(ctx, newTestPendingSharedVolume("team-missing", "scratch")); !errors.Is(err, store.ErrFailedPrecondition) { + t.Errorf("CreateSharedVolume in an unknown atespace = %v, want ErrFailedPrecondition", err) + } + }) + + t.Run("UpdateSharedVolume_MissingPrecondition", func(t *testing.T) { + s := setup(t) + ctx := context.Background() + mustCreateAtespace(t, s, "team-a") + created := storeSharedVolume(t, s, newTestPendingSharedVolume("team-a", "scratch")) + + tests := []struct { + name string + precondition store.Precondition + }{ + { + name: "no precondition", + precondition: store.Precondition{}, + }, + { + name: "guarding on only a uid", + precondition: store.Precondition{UID: created.GetMetadata().GetUid()}, + }, + { + name: "guarding on only a version", + precondition: store.Precondition{Version: created.GetMetadata().GetVersion()}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := s.UpdateSharedVolume(ctx, resources.SharedVolumeRef{Atespace: "team-a", Name: "scratch"}, tt.precondition, func(toUpdate *ateapipb.SharedVolume) error { + t.Fatal("mutate ran for a blind write") + return nil + }) + if !errors.Is(err, store.ErrPreconditionRequired) { + t.Errorf("UpdateSharedVolume error = %v, want one matching store.ErrPreconditionRequired", err) + } + }) + } + }) + + t.Run("UpdateSharedVolume_NotFound", func(t *testing.T) { + s := setup(t) + ctx := context.Background() + mustCreateAtespace(t, s, "team-a") + + _, err := s.UpdateSharedVolume(ctx, resources.SharedVolumeRef{Atespace: "team-a", Name: "missing"}, store.Precondition{UID: "u", Version: 1}, func(*ateapipb.SharedVolume) error { return nil }) + if !errors.Is(err, store.ErrNotFound) { + t.Errorf("UpdateSharedVolume on a missing volume = %v, want ErrNotFound", err) + } + if _, err := s.DeleteSharedVolume(ctx, resources.SharedVolumeRef{Atespace: "team-a", Name: "missing"}, store.DeletePreconditions{}); !errors.Is(err, store.ErrNotFound) { + t.Errorf("DeleteSharedVolume on a missing volume = %v, want ErrNotFound", err) + } + }) + + t.Run("ListSharedVolumes_PaginationAndScope", func(t *testing.T) { + s := setup(t) + ctx := context.Background() + for _, atespace := range []string{"team-a", "team-b"} { + mustCreateAtespace(t, s, atespace) + for i := 0; i < 3; i++ { + storeSharedVolume(t, s, newTestPendingSharedVolume(atespace, fmt.Sprintf("volume-%d", i))) + } + } + + var scoped []*ateapipb.SharedVolume + for token := ""; ; { + page, err := s.ListSharedVolumes(ctx, "team-a", store.ListOptions{PageSize: 2, PageToken: token}) + if err != nil { + t.Fatalf("scoped ListSharedVolumes failed: %v", err) + } + scoped = append(scoped, page.Items...) + if page.NextPageToken == "" { + break + } + token = page.NextPageToken + } + if len(scoped) != 3 { + t.Errorf("scoped ListSharedVolumes returned %d volumes, want 3", len(scoped)) + } + + var global []*ateapipb.SharedVolume + for token := ""; ; { + page, err := s.ListSharedVolumes(ctx, "", store.ListOptions{PageSize: 2, PageToken: token}) + if err != nil { + t.Fatalf("global ListSharedVolumes failed: %v", err) + } + global = append(global, page.Items...) + if page.NextPageToken == "" { + break + } + token = page.NextPageToken + } + if len(global) != 6 { + t.Errorf("global ListSharedVolumes returned %d volumes, want 6", len(global)) + } + }) +} + func runWorkerContractTests(t *testing.T, setup func(t *testing.T) store.Interface) { t.Helper() diff --git a/cmd/ateapi/internal/store/storetest/storetest.go b/cmd/ateapi/internal/store/storetest/storetest.go index ed8e457d7b..6fd579c0ba 100644 --- a/cmd/ateapi/internal/store/storetest/storetest.go +++ b/cmd/ateapi/internal/store/storetest/storetest.go @@ -136,6 +136,19 @@ func MustCreateTag(t *testing.T, ctx context.Context, s store.Interface, tag *at return created } +// MustCreateSharedVolume ensures volume's parent atespace exists, then stores volume as given. +func MustCreateSharedVolume(t *testing.T, ctx context.Context, s store.Interface, volume *ateapipb.SharedVolume) *ateapipb.SharedVolume { + t.Helper() + atespace := volume.GetMetadata().GetAtespace() + name := volume.GetMetadata().GetName() + MustCreateAtespace(t, ctx, s, atespace) + created, err := s.CreateSharedVolume(ctx, volume) + if err != nil { + t.Fatalf("creating test external volume %q/%q: %v", atespace, name, err) + } + return created +} + // RunTests runs m and terminates the shared PostgreSQL container afterwards. // Packages with no other TestMain work should use it as their whole TestMain; // the rest must call [Shutdown] themselves. diff --git a/cmd/kubectl-ate/internal/cmd/shared_volume.go b/cmd/kubectl-ate/internal/cmd/shared_volume.go new file mode 100644 index 0000000000..742a12db8a --- /dev/null +++ b/cmd/kubectl-ate/internal/cmd/shared_volume.go @@ -0,0 +1,268 @@ +// 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 cmd + +import ( + "context" + "fmt" + "strings" + + "github.com/agent-substrate/substrate/cmd/kubectl-ate/internal/printer" + "github.com/agent-substrate/substrate/internal/ateclient" + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" + "github.com/spf13/cobra" + "google.golang.org/grpc" +) + +var ( + sharedVolumeAtespaceFlag string + sharedVolumeAllAtespacesFlag bool + createSharedVolumeAtespaceFlag string + createSharedVolumeClassFlag string + createSharedVolumeCapacityFlag string + createSharedVolumeVolumeIDFlag string + createSharedVolumeTypeFlag string + createSharedVolumeContextFlag map[string]string + createSharedVolumeDeleteTriggerFlag string + createSharedVolumeAccessModeFlag string + updateSharedVolumeAtespaceFlag string + updateSharedVolumeDeleteTriggerFlag string + deleteSharedVolumeAtespaceFlag string +) + +var getSharedVolumesCmd = &cobra.Command{ + Use: "sharedvolumes [volume-name ...]", + Aliases: []string{"sharedvolume", "sv"}, + Short: "List or get shared volumes", + RunE: func(cmd *cobra.Command, args []string) error { + if sharedVolumeAllAtespacesFlag && sharedVolumeAtespaceFlag != "" { + return fmt.Errorf("--atespace and -A/--all-atespaces are mutually exclusive") + } + if len(args) > 0 && sharedVolumeAtespaceFlag == "" { + return fmt.Errorf("--atespace is required when getting shared volumes") + } + if len(args) == 0 && !sharedVolumeAllAtespacesFlag && sharedVolumeAtespaceFlag == "" { + return fmt.Errorf("specify --atespace , or -A/--all-atespaces") + } + + ctx := cmd.Context() + client, err := ateclient.NewClient(ctx, kubeconfig, k8sContext, endpoint, tokenFile, traceEnabled) + if err != nil { + return fmt.Errorf("failed to connect to ate-api-server: %w", err) + } + defer client.Close() + + if len(args) > 0 { + volumes := make([]*ateapipb.SharedVolume, 0, len(args)) + for _, name := range args { + volume, err := client.GetSharedVolume(ctx, &ateapipb.GetSharedVolumeRequest{ + SharedVolume: &ateapipb.ObjectRef{Atespace: sharedVolumeAtespaceFlag, Name: name}, + }) + if err != nil { + return fmt.Errorf("failed to get shared volume %q: %w", name, err) + } + volumes = append(volumes, volume) + } + if len(volumes) == 1 { + return printer.PrintSharedVolumeTo(cmd.OutOrStdout(), volumes[0], outputFmt) + } + return printer.PrintSharedVolumesTo(cmd.OutOrStdout(), volumes, outputFmt) + } + + var volumes []*ateapipb.SharedVolume + pageToken := "" + for { + resp, err := client.ListSharedVolumes(ctx, &ateapipb.ListSharedVolumesRequest{ + Atespace: sharedVolumeAtespaceFlag, PageSize: 1000, PageToken: pageToken, + }) + if err != nil { + return fmt.Errorf("failed to list shared volumes: %w", err) + } + volumes = append(volumes, resp.GetSharedVolumes()...) + pageToken = resp.GetNextPageToken() + if pageToken == "" { + break + } + } + return printer.PrintSharedVolumesTo(cmd.OutOrStdout(), volumes, outputFmt) + }, +} + +var createSharedVolumeCmd = &cobra.Command{ + Use: "sharedvolume ", + Aliases: []string{"sharedvolumes", "sv"}, + Short: "Create an shared volume actors can share", + Long: "Create an shared volume actors can share.\n\n" + + "Name a storage class with --storage-class to provision a new volume, or\n" + + "supply --volume-id to register a volume that already exists, but not both.", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + trigger, err := parseDeleteTrigger(createSharedVolumeDeleteTriggerFlag) + if err != nil { + return err + } + mode, err := parseAccessMode(createSharedVolumeAccessModeFlag) + if err != nil { + return err + } + ctx := cmd.Context() + client, err := ateclient.NewClient(ctx, kubeconfig, k8sContext, endpoint, tokenFile, traceEnabled) + if err != nil { + return fmt.Errorf("failed to connect to ate-api-server: %w", err) + } + defer client.Close() + + volume, err := client.CreateSharedVolume(ctx, &ateapipb.CreateSharedVolumeRequest{ + SharedVolume: &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{Atespace: createSharedVolumeAtespaceFlag, Name: args[0]}, + DeleteTrigger: trigger, + AccessMode: mode, + StorageClassName: createSharedVolumeClassFlag, + Capacity: createSharedVolumeCapacityFlag, + VolumeId: createSharedVolumeVolumeIDFlag, + VolumeType: createSharedVolumeTypeFlag, + VolumeContext: createSharedVolumeContextFlag, + }, + }) + if err != nil { + return fmt.Errorf("failed to create shared volume: %w", err) + } + return printer.PrintSharedVolumeTo(cmd.OutOrStdout(), volume, outputFmt) + }, +} + +var updateSharedVolumeCmd = &cobra.Command{ + Use: "sharedvolume ", + Aliases: []string{"sharedvolumes", "sv"}, + Short: "Change an shared volume's delete trigger", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + trigger, err := parseDeleteTrigger(updateSharedVolumeDeleteTriggerFlag) + if err != nil { + return err + } + ctx := cmd.Context() + client, err := ateclient.NewClient(ctx, kubeconfig, k8sContext, endpoint, tokenFile, traceEnabled) + if err != nil { + return fmt.Errorf("failed to connect to ate-api-server: %w", err) + } + defer client.Close() + + ref := &ateapipb.ObjectRef{Atespace: updateSharedVolumeAtespaceFlag, Name: args[0]} + resp, err := updateSharedVolumeDeleteTrigger(ctx, client, ref, trigger) + if err != nil { + return err + } + return printer.PrintSharedVolumeTo(cmd.OutOrStdout(), resp, outputFmt) + }, +} + +var deleteSharedVolumeCmd = &cobra.Command{ + Use: "sharedvolume ", + Aliases: []string{"sharedvolumes", "sv"}, + Short: "Delete an shared volume and its storage", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() + client, err := ateclient.NewClient(ctx, kubeconfig, k8sContext, endpoint, tokenFile, traceEnabled) + if err != nil { + return fmt.Errorf("failed to connect to ate-api-server: %w", err) + } + defer client.Close() + + _, err = client.DeleteSharedVolume(ctx, &ateapipb.DeleteSharedVolumeRequest{ + SharedVolume: &ateapipb.ObjectRef{Atespace: deleteSharedVolumeAtespaceFlag, Name: args[0]}, + }) + if err != nil { + return fmt.Errorf("failed to delete shared volume: %w", err) + } + fmt.Fprintf(cmd.OutOrStdout(), "shared volume %q deleted\n", args[0]) + return nil + }, +} + +type sharedVolumeClient interface { + GetSharedVolume(ctx context.Context, in *ateapipb.GetSharedVolumeRequest, opts ...grpc.CallOption) (*ateapipb.SharedVolume, error) + UpdateSharedVolume(ctx context.Context, in *ateapipb.UpdateSharedVolumeRequest, opts ...grpc.CallOption) (*ateapipb.SharedVolume, error) +} + +// updateSharedVolumeDeleteTrigger reads the volume first so the update carries +// the uid and version the server requires as preconditions. +func updateSharedVolumeDeleteTrigger(ctx context.Context, client sharedVolumeClient, ref *ateapipb.ObjectRef, trigger ateapipb.DeleteTrigger) (*ateapipb.SharedVolume, error) { + volume, err := client.GetSharedVolume(ctx, &ateapipb.GetSharedVolumeRequest{SharedVolume: ref}) + if err != nil { + return nil, fmt.Errorf("failed to get shared volume %q: %w", ref.GetName(), err) + } + volume.DeleteTrigger = trigger + + resp, err := client.UpdateSharedVolume(ctx, &ateapipb.UpdateSharedVolumeRequest{SharedVolume: volume}) + if err != nil { + return nil, fmt.Errorf("failed to update shared volume: %w", err) + } + return resp, nil +} + +func parseDeleteTrigger(value string) (ateapipb.DeleteTrigger, error) { + switch strings.ToLower(value) { + case "": + return ateapipb.DeleteTrigger_DELETE_TRIGGER_UNSPECIFIED, nil + case "manual": + return ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL, nil + case "last-actor", "lastactor": + return ateapipb.DeleteTrigger_DELETE_TRIGGER_LAST_ACTOR, nil + default: + return ateapipb.DeleteTrigger_DELETE_TRIGGER_UNSPECIFIED, fmt.Errorf("invalid delete trigger %q; must be manual or last-actor", value) + } +} + +func parseAccessMode(value string) (ateapipb.AccessMode, error) { + switch strings.ToLower(value) { + case "": + return ateapipb.AccessMode_ACCESS_MODE_UNSPECIFIED, nil + case "rwo", "readwriteonce": + return ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_ONCE, nil + case "rwx", "readwritemany": + return ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_MANY, nil + default: + return ateapipb.AccessMode_ACCESS_MODE_UNSPECIFIED, fmt.Errorf("invalid access mode %q; must be rwo or rwx", value) + } +} + +func init() { + getSharedVolumesCmd.Flags().StringVarP(&sharedVolumeAtespaceFlag, "atespace", "a", "", "Atespace to list/get shared volumes in") + getSharedVolumesCmd.Flags().BoolVarP(&sharedVolumeAllAtespacesFlag, "all-atespaces", "A", false, "List shared volumes across all atespaces") + getCmd.AddCommand(getSharedVolumesCmd) + + createSharedVolumeCmd.Flags().StringVarP(&createSharedVolumeAtespaceFlag, "atespace", "a", "", "Atespace to create the shared volume in (required)") + _ = createSharedVolumeCmd.MarkFlagRequired("atespace") + createSharedVolumeCmd.Flags().StringVar(&createSharedVolumeClassFlag, "storage-class", "", "StorageClass to provision the volume from") + createSharedVolumeCmd.Flags().StringVar(&createSharedVolumeCapacityFlag, "capacity", "", "Size to provision, as a Kubernetes quantity (e.g. 10Gi); required with --storage-class") + createSharedVolumeCmd.Flags().StringVar(&createSharedVolumeVolumeIDFlag, "volume-id", "", "Volume ID of a volume that already exists, to register instead of provisioning") + createSharedVolumeCmd.Flags().StringVar(&createSharedVolumeTypeFlag, "volume-type", "", "CSI driver name; required with --volume-id unless --storage-class is set") + createSharedVolumeCmd.Flags().StringToStringVar(&createSharedVolumeContextFlag, "volume-context", nil, "Driver metadata for mounting, as key=value pairs; only valid with --volume-id") + createSharedVolumeCmd.Flags().StringVar(&createSharedVolumeDeleteTriggerFlag, "delete-trigger", "", "What removes the volume: manual or last-actor (default: last-actor when provisioned, manual when registered)") + createSharedVolumeCmd.Flags().StringVar(&createSharedVolumeAccessModeFlag, "access-mode", "", "How many resumed actors may hold the volume: rwo (default) or rwx") + createCmd.AddCommand(createSharedVolumeCmd) + + updateSharedVolumeCmd.Flags().StringVarP(&updateSharedVolumeAtespaceFlag, "atespace", "a", "", "Atespace owning the shared volume (required)") + updateSharedVolumeCmd.Flags().StringVar(&updateSharedVolumeDeleteTriggerFlag, "delete-trigger", "", "What removes the volume: manual or last-actor (required)") + _ = updateSharedVolumeCmd.MarkFlagRequired("atespace") + _ = updateSharedVolumeCmd.MarkFlagRequired("delete-trigger") + updateCmd.AddCommand(updateSharedVolumeCmd) + + deleteSharedVolumeCmd.Flags().StringVarP(&deleteSharedVolumeAtespaceFlag, "atespace", "a", "", "Atespace owning the shared volume (required)") + _ = deleteSharedVolumeCmd.MarkFlagRequired("atespace") + deleteCmd.AddCommand(deleteSharedVolumeCmd) +} diff --git a/cmd/kubectl-ate/internal/cmd/shared_volume_test.go b/cmd/kubectl-ate/internal/cmd/shared_volume_test.go new file mode 100644 index 0000000000..b4f4da47ff --- /dev/null +++ b/cmd/kubectl-ate/internal/cmd/shared_volume_test.go @@ -0,0 +1,138 @@ +// 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 cmd + +import ( + "context" + "testing" + + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" + "github.com/google/go-cmp/cmp" + "google.golang.org/grpc" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/testing/protocmp" +) + +type fakeSharedVolumeClient struct { + volume *ateapipb.SharedVolume + + getCalls int + updateReq *ateapipb.UpdateSharedVolumeRequest +} + +func (f *fakeSharedVolumeClient) GetSharedVolume(_ context.Context, _ *ateapipb.GetSharedVolumeRequest, _ ...grpc.CallOption) (*ateapipb.SharedVolume, error) { + f.getCalls++ + return proto.Clone(f.volume).(*ateapipb.SharedVolume), nil +} + +func (f *fakeSharedVolumeClient) UpdateSharedVolume(_ context.Context, in *ateapipb.UpdateSharedVolumeRequest, _ ...grpc.CallOption) (*ateapipb.SharedVolume, error) { + f.updateReq = in + updated := proto.Clone(in.GetSharedVolume()).(*ateapipb.SharedVolume) + updated.Metadata.Version++ + return updated, nil +} + +func testSharedVolume() *ateapipb.SharedVolume { + return &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{ + Atespace: "space-1", + Name: "vol-1", + Uid: "8ba9b6ee-2e1a-4c0f-9f4e-2f0a0f1c3d55", + Version: 1, + }, + DeleteTrigger: ateapipb.DeleteTrigger_DELETE_TRIGGER_LAST_ACTOR, + AccessMode: ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_ONCE, + VolumeId: "projects/p/zones/z/disks/substrate-8ba9b6ee", + VolumeType: "pd.csi.storage.gke.io", + Status: &ateapipb.SharedVolumeStatus{ + State: ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY, + }, + } +} + +func TestUpdateSharedVolumeDeleteTrigger(t *testing.T) { + client := &fakeSharedVolumeClient{volume: testSharedVolume()} + ref := &ateapipb.ObjectRef{Atespace: "space-1", Name: "vol-1"} + want := ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL + + resp, err := updateSharedVolumeDeleteTrigger(context.Background(), client, ref, want) + if err != nil { + t.Fatalf("updateSharedVolumeDeleteTrigger() error = %v", err) + } + + if client.getCalls != 1 { + t.Errorf("GetSharedVolume called %d times, want 1", client.getCalls) + } + + sent := client.updateReq.GetSharedVolume().GetMetadata() + if sent.GetUid() != "8ba9b6ee-2e1a-4c0f-9f4e-2f0a0f1c3d55" || sent.GetVersion() != 1 { + t.Errorf("update sent uid %q version %d, want the values just read", sent.GetUid(), sent.GetVersion()) + } + + wantResp := testSharedVolume() + wantResp.DeleteTrigger = want + wantResp.Metadata.Version = 2 + if diff := cmp.Diff(wantResp, resp, protocmp.Transform()); diff != "" { + t.Errorf("returned shared volume mismatch (-want +got):\n%s", diff) + } +} + +func TestParseDeleteTrigger(t *testing.T) { + tests := []struct { + value string + want ateapipb.DeleteTrigger + wantErr bool + }{ + {value: "", want: ateapipb.DeleteTrigger_DELETE_TRIGGER_UNSPECIFIED}, + {value: "manual", want: ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL}, + {value: "Last-Actor", want: ateapipb.DeleteTrigger_DELETE_TRIGGER_LAST_ACTOR}, + {value: "atespace", wantErr: true}, + } + for _, tc := range tests { + t.Run(tc.value, func(t *testing.T) { + got, err := parseDeleteTrigger(tc.value) + if (err != nil) != tc.wantErr { + t.Fatalf("parseDeleteTrigger(%q) error = %v, wantErr %v", tc.value, err, tc.wantErr) + } + if got != tc.want { + t.Errorf("parseDeleteTrigger(%q) = %v, want %v", tc.value, got, tc.want) + } + }) + } +} + +func TestParseAccessMode(t *testing.T) { + tests := []struct { + value string + want ateapipb.AccessMode + wantErr bool + }{ + {value: "", want: ateapipb.AccessMode_ACCESS_MODE_UNSPECIFIED}, + {value: "rwo", want: ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_ONCE}, + {value: "ReadWriteMany", want: ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_MANY}, + {value: "rox", wantErr: true}, + } + for _, tc := range tests { + t.Run(tc.value, func(t *testing.T) { + got, err := parseAccessMode(tc.value) + if (err != nil) != tc.wantErr { + t.Fatalf("parseAccessMode(%q) error = %v, wantErr %v", tc.value, err, tc.wantErr) + } + if got != tc.want { + t.Errorf("parseAccessMode(%q) = %v, want %v", tc.value, got, tc.want) + } + }) + } +} diff --git a/cmd/kubectl-ate/internal/printer/printer.go b/cmd/kubectl-ate/internal/printer/printer.go index f77cbcecf6..7db6332891 100644 --- a/cmd/kubectl-ate/internal/printer/printer.go +++ b/cmd/kubectl-ate/internal/printer/printer.go @@ -388,6 +388,85 @@ func PrintTagTo(out io.Writer, tag *ateapipb.Tag, format string) error { return PrintTagsTo(out, []*ateapipb.Tag{tag}, format) } +// PrintSharedVolumesTo prints external volumes to the provided writer. +func PrintSharedVolumesTo(out io.Writer, volumes []*ateapipb.SharedVolume, format string) error { + slices.SortFunc(volumes, func(a, b *ateapipb.SharedVolume) int { + if c := cmp.Compare(a.GetMetadata().GetAtespace(), b.GetMetadata().GetAtespace()); c != 0 { + return c + } + return cmp.Compare(a.GetMetadata().GetName(), b.GetMetadata().GetName()) + }) + switch format { + case "json", "yaml": + return printProto(out, &ateapipb.ListSharedVolumesResponse{SharedVolumes: volumes}, format) + case "table": + w := tabwriter.NewWriter(out, 0, 0, 3, ' ', 0) + fmt.Fprintln(w, "ATESPACE\tNAME\tSTATE\tVOLUME TYPE\tVOLUME ID\tACCESS MODE\tDELETE TRIGGER\tREFS\tAGE") + for _, volume := range volumes { + volumeType, volumeID := "", "" + if volume.GetVolumeId() != "" { + volumeType, volumeID = volume.GetVolumeType(), volume.GetVolumeId() + } + fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", + volume.GetMetadata().GetAtespace(), volume.GetMetadata().GetName(), + sharedVolumeState(volume), volumeType, volumeID, + accessModeLabel(volume.GetAccessMode()), deleteTriggerLabel(volume.GetDeleteTrigger()), + sharedVolumeRefs(volume), formatAge(volume.GetMetadata().GetCreateTime())) + } + return w.Flush() + default: + return fmt.Errorf("unsupported format %q", format) + } +} + +func sharedVolumeState(volume *ateapipb.SharedVolume) string { + if volume.GetStatus().GetState() != ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY { + return "Pending" + } + return "Ready" +} + +func accessModeLabel(mode ateapipb.AccessMode) string { + switch mode { + case ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_ONCE: + return "RWO" + case ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_MANY: + return "RWX" + default: + return "" + } +} + +func deleteTriggerLabel(trigger ateapipb.DeleteTrigger) string { + switch trigger { + case ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL: + return "Manual" + case ateapipb.DeleteTrigger_DELETE_TRIGGER_LAST_ACTOR: + return "LastActor" + default: + return "" + } +} + +// sharedVolumeRefs renders the reference count as active/total. +func sharedVolumeRefs(volume *ateapipb.SharedVolume) string { + active := 0 + for _, ref := range volume.GetStatus().GetRefs() { + if ref.GetActive() { + active++ + } + } + return fmt.Sprintf("%d/%d", active, len(volume.GetStatus().GetRefs())) +} + +// PrintSharedVolumeTo prints a single external volume to the provided writer. +func PrintSharedVolumeTo(out io.Writer, volume *ateapipb.SharedVolume, format string) error { + if format == "json" || format == "yaml" { + return printProto(out, volume, format) + } + return PrintSharedVolumesTo(out, []*ateapipb.SharedVolume{volume}, format) +} + func sortAtespaces(atespaces []*ateapipb.Atespace) { slices.SortFunc(atespaces, func(a, b *ateapipb.Atespace) int { return cmp.Compare(a.GetMetadata().GetName(), b.GetMetadata().GetName()) diff --git a/cmd/kubectl-ate/internal/printer/printer_test.go b/cmd/kubectl-ate/internal/printer/printer_test.go index eded1c9b5a..58962e8513 100644 --- a/cmd/kubectl-ate/internal/printer/printer_test.go +++ b/cmd/kubectl-ate/internal/printer/printer_test.go @@ -717,6 +717,116 @@ func TestPrintTagTo_YAML(t *testing.T) { } } +func TestPrintSharedVolumesTo_Table(t *testing.T) { + now := time.Date(2026, 1, 1, 12, 0, 0, 0, time.UTC) + pinNow(t, now) + + var buf bytes.Buffer + volumes := []*ateapipb.SharedVolume{ + { + Metadata: &ateapipb.ResourceMetadata{ + Atespace: "team-a", + Name: "shared", + CreateTime: timestamppb.New(now.Add(-5 * time.Minute)), + }, + DeleteTrigger: ateapipb.DeleteTrigger_DELETE_TRIGGER_LAST_ACTOR, + AccessMode: ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_ONCE, + VolumeId: "projects/p/zones/z/disks/substrate-1", + VolumeType: "pd.csi.storage.gke.io", + Status: &ateapipb.SharedVolumeStatus{ + State: ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY, + Refs: []*ateapipb.ActorRef{ + {ActorUid: "uid-1", ActorName: "producer", Active: true}, + {ActorUid: "uid-2", ActorName: "consumer"}, + }, + }, + }, + { + Metadata: &ateapipb.ResourceMetadata{ + Atespace: "team-a", + Name: "adopted", + CreateTime: timestamppb.New(now.Add(-5 * time.Hour)), + }, + DeleteTrigger: ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL, + AccessMode: ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_ONCE, + VolumeId: "projects/p/zones/z/disks/preexisting", + VolumeType: "pd.csi.storage.gke.io", + Status: &ateapipb.SharedVolumeStatus{ + State: ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY, + }, + }, + { + Metadata: &ateapipb.ResourceMetadata{ + Atespace: "team-a", + Name: "stranded", + CreateTime: timestamppb.New(now.Add(-30 * time.Second)), + }, + DeleteTrigger: ateapipb.DeleteTrigger_DELETE_TRIGGER_LAST_ACTOR, + AccessMode: ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_ONCE, + Status: &ateapipb.SharedVolumeStatus{ + State: ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_PENDING, + }, + }, + } + + if err := PrintSharedVolumesTo(&buf, volumes, "table"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + + expected := `ATESPACE NAME STATE VOLUME TYPE VOLUME ID ACCESS MODE DELETE TRIGGER REFS AGE +team-a adopted Ready pd.csi.storage.gke.io projects/p/zones/z/disks/preexisting RWO Manual 0/0 5h +team-a shared Ready pd.csi.storage.gke.io projects/p/zones/z/disks/substrate-1 RWO LastActor 1/2 5m +team-a stranded Pending RWO LastActor 0/0 30s +` + if diff := cmp.Diff(expected, buf.String()); diff != "" { + t.Errorf("output mismatch (-want +got):\n%s", diff) + } +} + +func TestPrintSharedVolumesTo_Invalid(t *testing.T) { + var buf bytes.Buffer + if err := PrintSharedVolumesTo(&buf, nil, "xml"); err == nil { + t.Errorf("expected error for invalid format, got nil") + } +} + +func TestPrintSharedVolumeTo_JSON(t *testing.T) { + var buf bytes.Buffer + volume := &ateapipb.SharedVolume{Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "shared"}} + + if err := PrintSharedVolumeTo(&buf, volume, "json"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + + expected := `{ + "metadata": { + "atespace": "team-a", + "name": "shared" + } +} +` + if diff := cmp.Diff(expected, buf.String()); diff != "" { + t.Errorf("output mismatch (-want +got):\n%s", diff) + } +} + +func TestPrintSharedVolumeTo_YAML(t *testing.T) { + var buf bytes.Buffer + volume := &ateapipb.SharedVolume{Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "shared"}} + + if err := PrintSharedVolumeTo(&buf, volume, "yaml"); err != nil { + t.Fatalf("unexpected error: %v", err) + } + + expected := `metadata: + atespace: team-a + name: shared +` + if diff := cmp.Diff(expected, buf.String()); diff != "" { + t.Errorf("output mismatch (-want +got):\n%s", diff) + } +} + func TestPrintAtespacesTo_Table(t *testing.T) { now := time.Date(2026, 1, 1, 12, 0, 0, 0, time.UTC) pinNow(t, now) diff --git a/internal/resources/resourceref.go b/internal/resources/resourceref.go index a14d079d75..92ba75186a 100644 --- a/internal/resources/resourceref.go +++ b/internal/resources/resourceref.go @@ -107,3 +107,20 @@ func TagRefFromTag(t *ateapipb.Tag) TagRef { Name: t.GetMetadata().GetName(), } } + +// SharedVolumeRef identifies a SharedVolume by the (atespace, name). +type SharedVolumeRef = ResourceRef[*ateapipb.SharedVolume] + +// SharedVolumeRefFromObjectRef converts an ObjectRef to a SharedVolumeRef. +func SharedVolumeRefFromObjectRef(ref *ateapipb.ObjectRef) SharedVolumeRef { + return resourceRefFromObjectRef[*ateapipb.SharedVolume](ref) +} + +// SharedVolumeRefFromSharedVolume returns the reference addressing the +// given volume. +func SharedVolumeRefFromSharedVolume(v *ateapipb.SharedVolume) SharedVolumeRef { + return SharedVolumeRef{ + Atespace: v.GetMetadata().GetAtespace(), + Name: v.GetMetadata().GetName(), + } +} diff --git a/pkg/proto/ateapipb/ateapi.pb.go b/pkg/proto/ateapipb/ateapi.pb.go index d75b9ec9cc..2fe3a7dd30 100644 --- a/pkg/proto/ateapipb/ateapi.pb.go +++ b/pkg/proto/ateapipb/ateapi.pb.go @@ -324,6 +324,163 @@ func (ActorState) EnumDescriptor() ([]byte, []int) { return file_ateapi_proto_rawDescGZIP(), []int{4} } +// DeleteTrigger is what removes a SharedVolume and its storage. +// TODO: add an ATESPACE trigger that removes the volume with its atespace. +type DeleteTrigger int32 + +const ( + DeleteTrigger_DELETE_TRIGGER_UNSPECIFIED DeleteTrigger = 0 + // Only an explicit DeleteSharedVolume removes the volume. + DeleteTrigger_DELETE_TRIGGER_MANUAL DeleteTrigger = 1 + // The volume is removed when the last actor referencing it is deleted. + DeleteTrigger_DELETE_TRIGGER_LAST_ACTOR DeleteTrigger = 2 +) + +// Enum value maps for DeleteTrigger. +var ( + DeleteTrigger_name = map[int32]string{ + 0: "DELETE_TRIGGER_UNSPECIFIED", + 1: "DELETE_TRIGGER_MANUAL", + 2: "DELETE_TRIGGER_LAST_ACTOR", + } + DeleteTrigger_value = map[string]int32{ + "DELETE_TRIGGER_UNSPECIFIED": 0, + "DELETE_TRIGGER_MANUAL": 1, + "DELETE_TRIGGER_LAST_ACTOR": 2, + } +) + +func (x DeleteTrigger) Enum() *DeleteTrigger { + p := new(DeleteTrigger) + *p = x + return p +} + +func (x DeleteTrigger) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (DeleteTrigger) Descriptor() protoreflect.EnumDescriptor { + return file_ateapi_proto_enumTypes[5].Descriptor() +} + +func (DeleteTrigger) Type() protoreflect.EnumType { + return &file_ateapi_proto_enumTypes[5] +} + +func (x DeleteTrigger) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use DeleteTrigger.Descriptor instead. +func (DeleteTrigger) EnumDescriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{5} +} + +// AccessMode is how many resumed actors may hold the volume at once. +type AccessMode int32 + +const ( + AccessMode_ACCESS_MODE_UNSPECIFIED AccessMode = 0 + // At most one resumed actor holds the volume. + AccessMode_ACCESS_MODE_READ_WRITE_ONCE AccessMode = 1 + // Any number of resumed actors hold the volume, on any node. + AccessMode_ACCESS_MODE_READ_WRITE_MANY AccessMode = 2 +) + +// Enum value maps for AccessMode. +var ( + AccessMode_name = map[int32]string{ + 0: "ACCESS_MODE_UNSPECIFIED", + 1: "ACCESS_MODE_READ_WRITE_ONCE", + 2: "ACCESS_MODE_READ_WRITE_MANY", + } + AccessMode_value = map[string]int32{ + "ACCESS_MODE_UNSPECIFIED": 0, + "ACCESS_MODE_READ_WRITE_ONCE": 1, + "ACCESS_MODE_READ_WRITE_MANY": 2, + } +) + +func (x AccessMode) Enum() *AccessMode { + p := new(AccessMode) + *p = x + return p +} + +func (x AccessMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (AccessMode) Descriptor() protoreflect.EnumDescriptor { + return file_ateapi_proto_enumTypes[6].Descriptor() +} + +func (AccessMode) Type() protoreflect.EnumType { + return &file_ateapi_proto_enumTypes[6] +} + +func (x AccessMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use AccessMode.Descriptor instead. +func (AccessMode) EnumDescriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{6} +} + +// SharedVolumeState is where a SharedVolume is in its own lifecycle. +type SharedVolumeState int32 + +const ( + SharedVolumeState_SHARED_VOLUME_STATE_UNSPECIFIED SharedVolumeState = 0 + // The name is reserved but no volume handle is known yet. + SharedVolumeState_SHARED_VOLUME_STATE_PENDING SharedVolumeState = 1 + // The volume has a handle and can be referenced. + SharedVolumeState_SHARED_VOLUME_STATE_READY SharedVolumeState = 2 +) + +// Enum value maps for SharedVolumeState. +var ( + SharedVolumeState_name = map[int32]string{ + 0: "SHARED_VOLUME_STATE_UNSPECIFIED", + 1: "SHARED_VOLUME_STATE_PENDING", + 2: "SHARED_VOLUME_STATE_READY", + } + SharedVolumeState_value = map[string]int32{ + "SHARED_VOLUME_STATE_UNSPECIFIED": 0, + "SHARED_VOLUME_STATE_PENDING": 1, + "SHARED_VOLUME_STATE_READY": 2, + } +) + +func (x SharedVolumeState) Enum() *SharedVolumeState { + p := new(SharedVolumeState) + *p = x + return p +} + +func (x SharedVolumeState) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SharedVolumeState) Descriptor() protoreflect.EnumDescriptor { + return file_ateapi_proto_enumTypes[7].Descriptor() +} + +func (SharedVolumeState) Type() protoreflect.EnumType { + return &file_ateapi_proto_enumTypes[7] +} + +func (x SharedVolumeState) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SharedVolumeState.Descriptor instead. +func (SharedVolumeState) EnumDescriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{7} +} + // SandboxClass selects the sandbox runtime family. Snapshots are not portable // across classes. type SandboxClass int32 @@ -359,11 +516,11 @@ func (x SandboxClass) String() string { } func (SandboxClass) Descriptor() protoreflect.EnumDescriptor { - return file_ateapi_proto_enumTypes[5].Descriptor() + return file_ateapi_proto_enumTypes[8].Descriptor() } func (SandboxClass) Type() protoreflect.EnumType { - return &file_ateapi_proto_enumTypes[5] + return &file_ateapi_proto_enumTypes[8] } func (x SandboxClass) Number() protoreflect.EnumNumber { @@ -372,7 +529,7 @@ func (x SandboxClass) Number() protoreflect.EnumNumber { // Deprecated: Use SandboxClass.Descriptor instead. func (SandboxClass) EnumDescriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{5} + return file_ateapi_proto_rawDescGZIP(), []int{8} } // GoldenSnapshotMode selects whether a template builds a golden snapshot. @@ -409,11 +566,11 @@ func (x GoldenSnapshotMode) String() string { } func (GoldenSnapshotMode) Descriptor() protoreflect.EnumDescriptor { - return file_ateapi_proto_enumTypes[6].Descriptor() + return file_ateapi_proto_enumTypes[9].Descriptor() } func (GoldenSnapshotMode) Type() protoreflect.EnumType { - return &file_ateapi_proto_enumTypes[6] + return &file_ateapi_proto_enumTypes[9] } func (x GoldenSnapshotMode) Number() protoreflect.EnumNumber { @@ -422,7 +579,7 @@ func (x GoldenSnapshotMode) Number() protoreflect.EnumNumber { // Deprecated: Use GoldenSnapshotMode.Descriptor instead. func (GoldenSnapshotMode) EnumDescriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{6} + return file_ateapi_proto_rawDescGZIP(), []int{9} } // ActorMetadataField selects one identity field of the actor. @@ -462,11 +619,11 @@ func (x ActorMetadataField) String() string { } func (ActorMetadataField) Descriptor() protoreflect.EnumDescriptor { - return file_ateapi_proto_enumTypes[7].Descriptor() + return file_ateapi_proto_enumTypes[10].Descriptor() } func (ActorMetadataField) Type() protoreflect.EnumType { - return &file_ateapi_proto_enumTypes[7] + return &file_ateapi_proto_enumTypes[10] } func (x ActorMetadataField) Number() protoreflect.EnumNumber { @@ -475,7 +632,7 @@ func (x ActorMetadataField) Number() protoreflect.EnumNumber { // Deprecated: Use ActorMetadataField.Descriptor instead. func (ActorMetadataField) EnumDescriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{7} + return file_ateapi_proto_rawDescGZIP(), []int{10} } type WorkerState int32 @@ -513,11 +670,11 @@ func (x WorkerState) String() string { } func (WorkerState) Descriptor() protoreflect.EnumDescriptor { - return file_ateapi_proto_enumTypes[8].Descriptor() + return file_ateapi_proto_enumTypes[11].Descriptor() } func (WorkerState) Type() protoreflect.EnumType { - return &file_ateapi_proto_enumTypes[8] + return &file_ateapi_proto_enumTypes[11] } func (x WorkerState) Number() protoreflect.EnumNumber { @@ -526,7 +683,7 @@ func (x WorkerState) Number() protoreflect.EnumNumber { // Deprecated: Use WorkerState.Descriptor instead. func (WorkerState) EnumDescriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{8} + return file_ateapi_proto_rawDescGZIP(), []int{11} } // Status is the volume's lifecycle state in the storage system. @@ -569,11 +726,11 @@ func (x ExternalVolumeRef_Status) String() string { } func (ExternalVolumeRef_Status) Descriptor() protoreflect.EnumDescriptor { - return file_ateapi_proto_enumTypes[9].Descriptor() + return file_ateapi_proto_enumTypes[12].Descriptor() } func (ExternalVolumeRef_Status) Type() protoreflect.EnumType { - return &file_ateapi_proto_enumTypes[9] + return &file_ateapi_proto_enumTypes[12] } func (x ExternalVolumeRef_Status) Number() protoreflect.EnumNumber { @@ -2477,33 +2634,99 @@ func (x *Tag) GetSourceActor() *ObjectRef { return nil } -// Atespace is the isolation boundary an Actor is created into. Global-scoped: -// metadata.atespace is always empty; the atespace's identity is metadata.name. -type Atespace struct { +// SharedVolume is an atespace-scoped CSI volume whose lifetime is independent +// of any actor. Identity is (atespace, name); the storage-level ID is derived +// from the record's UID. +type SharedVolume struct { state protoimpl.MessageState `protogen:"open.v1"` - // Common resource metadata: name, uid, version, timestamps. + // Common resource metadata: atespace, name, uid, version, timestamps. // // +k8s:required - // +k8s:beta(since: "0.0")=+k8s:subfield(atespace)=+k8s:forbidden # TODO: get rid of beta prefix - Metadata *ResourceMetadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + // +k8s:subfield(atespace)=+k8s:required + Metadata *ResourceMetadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + // delete_trigger decides what removes the volume. Defaults to LAST_ACTOR when + // provisioned and MANUAL when registered. + // + // +k8s:optional + // +k8s:minimum=1 + // +k8s:maximum=2 # keep this in sync with the DeleteTrigger enum + // +k8s:mutable + DeleteTrigger DeleteTrigger `protobuf:"varint,2,opt,name=delete_trigger,json=deleteTrigger,proto3,enum=ateapi.DeleteTrigger" json:"delete_trigger,omitempty"` + // storage_class_name names the StorageClass to provision from, or documents + // the class of a registered volume. + // + // +k8s:optional + // +k8s:format=k8s-long-name + // +k8s:update=NoModify + // +k8s:update=NoUnset + StorageClassName string `protobuf:"bytes,3,opt,name=storage_class_name,json=storageClassName,proto3" json:"storage_class_name,omitempty"` + // volume_id is the storage system's volume ID. Supplied to register an + // existing volume, otherwise stamped once provisioning completes. Bounded and + // checked for control characters only. + // + // +k8s:optional + // +k8s:maxLength=256 + // +k8s:update=NoModify + // +k8s:update=NoUnset + // +k8s:customValidation # no control characters + VolumeId string `protobuf:"bytes,4,opt,name=volume_id,json=volumeId,proto3" json:"volume_id,omitempty"` + // volume_type is the CSI driver name. Required alongside volume_id when no + // StorageClass is named; otherwise taken from the class's provisioner. + // + // +k8s:optional + // +k8s:maxLength=253 + // +k8s:update=NoModify + // +k8s:update=NoUnset + // +k8s:customValidation + VolumeType string `protobuf:"bytes,5,opt,name=volume_type,json=volumeType,proto3" json:"volume_type,omitempty"` + // volume_context is driver metadata needed by the node plugin for mounting. + // Attachment metadata is per-node and deliberately not recorded here. + // + // +k8s:optional + // +k8s:maxProperties=32 + // +k8s:eachKey=+k8s:maxLength=128 + // +k8s:eachVal=+k8s:maxLength=256 + VolumeContext map[string]string `protobuf:"bytes,6,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"` + // status is set by the control plane; it is ignored on write. + // + // +k8s:optional + Status *SharedVolumeStatus `protobuf:"bytes,7,opt,name=status,proto3" json:"status,omitempty"` + // capacity to provision, as a Kubernetes resource.Quantity string (e.g. + // "10Gi"). Required when provisioning, forbidden alongside volume_id. + // + // +k8s:optional + // +k8s:maxLength=64 + // +k8s:update=NoModify + // +k8s:update=NoUnset + // +k8s:customValidation # must parse as a resource.Quantity + Capacity string `protobuf:"bytes,8,opt,name=capacity,proto3" json:"capacity,omitempty"` + // access_mode is fixed at create and defaults to READ_WRITE_ONCE. + // TODO: accept READ_WRITE_MANY once concurrent holders are supported. + // + // +k8s:optional + // +k8s:minimum=1 + // +k8s:maximum=2 # keep this in sync with the AccessMode enum + // +k8s:update=NoModify + // +k8s:update=NoUnset + AccessMode AccessMode `protobuf:"varint,9,opt,name=access_mode,json=accessMode,proto3,enum=ateapi.AccessMode" json:"access_mode,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *Atespace) Reset() { - *x = Atespace{} +func (x *SharedVolume) Reset() { + *x = SharedVolume{} mi := &file_ateapi_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *Atespace) String() string { +func (x *SharedVolume) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Atespace) ProtoMessage() {} +func (*SharedVolume) ProtoMessage() {} -func (x *Atespace) ProtoReflect() protoreflect.Message { +func (x *SharedVolume) ProtoReflect() protoreflect.Message { mi := &file_ateapi_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2515,53 +2738,109 @@ func (x *Atespace) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Atespace.ProtoReflect.Descriptor instead. -func (*Atespace) Descriptor() ([]byte, []int) { +// Deprecated: Use SharedVolume.ProtoReflect.Descriptor instead. +func (*SharedVolume) Descriptor() ([]byte, []int) { return file_ateapi_proto_rawDescGZIP(), []int{22} } -func (x *Atespace) GetMetadata() *ResourceMetadata { +func (x *SharedVolume) GetMetadata() *ResourceMetadata { if x != nil { return x.Metadata } return nil } -// ObjectRef references a Substrate resource by its atespace and name. -type ObjectRef struct { +func (x *SharedVolume) GetDeleteTrigger() DeleteTrigger { + if x != nil { + return x.DeleteTrigger + } + return DeleteTrigger_DELETE_TRIGGER_UNSPECIFIED +} + +func (x *SharedVolume) GetStorageClassName() string { + if x != nil { + return x.StorageClassName + } + return "" +} + +func (x *SharedVolume) GetVolumeId() string { + if x != nil { + return x.VolumeId + } + return "" +} + +func (x *SharedVolume) GetVolumeType() string { + if x != nil { + return x.VolumeType + } + return "" +} + +func (x *SharedVolume) GetVolumeContext() map[string]string { + if x != nil { + return x.VolumeContext + } + return nil +} + +func (x *SharedVolume) GetStatus() *SharedVolumeStatus { + if x != nil { + return x.Status + } + return nil +} + +func (x *SharedVolume) GetCapacity() string { + if x != nil { + return x.Capacity + } + return "" +} + +func (x *SharedVolume) GetAccessMode() AccessMode { + if x != nil { + return x.AccessMode + } + return AccessMode_ACCESS_MODE_UNSPECIFIED +} + +// SharedVolumeStatus is the part of a SharedVolume the control plane owns. +type SharedVolumeStatus struct { state protoimpl.MessageState `protogen:"open.v1"` - // The atespace of the referenced resource. This field should be empty if the - // target resource is global-scoped, but references to objects in the same - // atespace as the referrer must still populate this field. + // state is where the volume is in its lifecycle. // - // References to atespaced resources should add `+k8s:subfield(atespace)=+k8s:required` - // References to non-atespaced resources should add `+k8s:subfield(atespace)=+k8s:forbidden` // +k8s:optional - // +k8s:format=k8s-short-name - Atespace string `protobuf:"bytes,1,opt,name=atespace,proto3" json:"atespace,omitempty"` - // The name of the referenced resource. This field is required. + // +k8s:minimum=1 + // +k8s:maximum=2 # keep this in sync with the SharedVolumeState enum + State SharedVolumeState `protobuf:"varint,1,opt,name=state,proto3,enum=ateapi.SharedVolumeState" json:"state,omitempty"` + // refs are the actors referencing the volume, resumed or not. + // TODO: move references to their own table before lifting the bound. // - // +k8s:required - // +k8s:format=k8s-short-name - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + // +k8s:optional + // +k8s:maxItems=256 + // +k8s:listType=map + // +k8s:listMapKey=actor_uid + Refs []*ActorRef `protobuf:"bytes,2,rep,name=refs,proto3" json:"refs,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *ObjectRef) Reset() { - *x = ObjectRef{} +func (x *SharedVolumeStatus) Reset() { + *x = SharedVolumeStatus{} mi := &file_ateapi_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *ObjectRef) String() string { +func (x *SharedVolumeStatus) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ObjectRef) ProtoMessage() {} +func (*SharedVolumeStatus) ProtoMessage() {} -func (x *ObjectRef) ProtoReflect() protoreflect.Message { +func (x *SharedVolumeStatus) ProtoReflect() protoreflect.Message { mi := &file_ateapi_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -2573,50 +2852,237 @@ func (x *ObjectRef) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ObjectRef.ProtoReflect.Descriptor instead. -func (*ObjectRef) Descriptor() ([]byte, []int) { +// Deprecated: Use SharedVolumeStatus.ProtoReflect.Descriptor instead. +func (*SharedVolumeStatus) Descriptor() ([]byte, []int) { return file_ateapi_proto_rawDescGZIP(), []int{23} } -func (x *ObjectRef) GetAtespace() string { +func (x *SharedVolumeStatus) GetState() SharedVolumeState { if x != nil { - return x.Atespace + return x.State } - return "" + return SharedVolumeState_SHARED_VOLUME_STATE_UNSPECIFIED } -func (x *ObjectRef) GetName() string { +func (x *SharedVolumeStatus) GetRefs() []*ActorRef { if x != nil { - return x.Name + return x.Refs } - return "" + return nil } -type ActorTemplate struct { +// ActorRef is one actor's reference to a SharedVolume. +type ActorRef struct { state protoimpl.MessageState `protogen:"open.v1"` - // Common resource metadata: atespace, name, uid, version, timestamps. + // actor_uid identifies the actor, so a recreated namesake does not inherit it. // // +k8s:required - // +k8s:subfield(atespace)=+k8s:required - Metadata *ResourceMetadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` - // worker_selector restricts which worker pools actors from this template - // may use. + // +k8s:maxLength=253 + ActorUid string `protobuf:"bytes,1,opt,name=actor_uid,json=actorUid,proto3" json:"actor_uid,omitempty"` + // actor_name is the actor's name, for readers. // - // +k8s:optional - WorkerSelector *Selector `protobuf:"bytes,2,opt,name=worker_selector,json=workerSelector,proto3" json:"worker_selector,omitempty"` - // +k8s:required # at least one container - // +k8s:maxItems=10 - // +k8s:listType=map - // +k8s:listMapKey=name - Containers []*Container `protobuf:"bytes,3,rep,name=containers,proto3" json:"containers,omitempty"` - // +k8s:optional - // +k8s:maxItems=32 - // +k8s:listType=map - // +k8s:listMapKey=name - Volumes []*Volume `protobuf:"bytes,4,rep,name=volumes,proto3" json:"volumes,omitempty"` // +k8s:required - SnapshotConfig *SnapshotConfig `protobuf:"bytes,5,opt,name=snapshot_config,json=snapshotConfig,proto3" json:"snapshot_config,omitempty"` - // sandbox_config selects the sandbox runtime this version's actors run on. + // +k8s:format=k8s-short-name + ActorName string `protobuf:"bytes,2,opt,name=actor_name,json=actorName,proto3" json:"actor_name,omitempty"` + // active is true while the actor is resumed and holds the volume mounted. + // + // +k8s:optional + Active bool `protobuf:"varint,3,opt,name=active,proto3" json:"active,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ActorRef) Reset() { + *x = ActorRef{} + mi := &file_ateapi_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ActorRef) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ActorRef) ProtoMessage() {} + +func (x *ActorRef) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[24] + 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 ActorRef.ProtoReflect.Descriptor instead. +func (*ActorRef) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{24} +} + +func (x *ActorRef) GetActorUid() string { + if x != nil { + return x.ActorUid + } + return "" +} + +func (x *ActorRef) GetActorName() string { + if x != nil { + return x.ActorName + } + return "" +} + +func (x *ActorRef) GetActive() bool { + if x != nil { + return x.Active + } + return false +} + +// Atespace is the isolation boundary an Actor is created into. Global-scoped: +// metadata.atespace is always empty; the atespace's identity is metadata.name. +type Atespace struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Common resource metadata: name, uid, version, timestamps. + // + // +k8s:required + // +k8s:beta(since: "0.0")=+k8s:subfield(atespace)=+k8s:forbidden # TODO: get rid of beta prefix + Metadata *ResourceMetadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Atespace) Reset() { + *x = Atespace{} + mi := &file_ateapi_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Atespace) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Atespace) ProtoMessage() {} + +func (x *Atespace) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[25] + 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 Atespace.ProtoReflect.Descriptor instead. +func (*Atespace) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{25} +} + +func (x *Atespace) GetMetadata() *ResourceMetadata { + if x != nil { + return x.Metadata + } + return nil +} + +// ObjectRef references a Substrate resource by its atespace and name. +type ObjectRef struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The atespace of the referenced resource. This field should be empty if the + // target resource is global-scoped, but references to objects in the same + // atespace as the referrer must still populate this field. + // + // References to atespaced resources should add `+k8s:subfield(atespace)=+k8s:required` + // References to non-atespaced resources should add `+k8s:subfield(atespace)=+k8s:forbidden` + // +k8s:optional + // +k8s:format=k8s-short-name + Atespace string `protobuf:"bytes,1,opt,name=atespace,proto3" json:"atespace,omitempty"` + // The name of the referenced resource. This field is required. + // + // +k8s:required + // +k8s:format=k8s-short-name + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ObjectRef) Reset() { + *x = ObjectRef{} + mi := &file_ateapi_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ObjectRef) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ObjectRef) ProtoMessage() {} + +func (x *ObjectRef) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[26] + 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 ObjectRef.ProtoReflect.Descriptor instead. +func (*ObjectRef) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{26} +} + +func (x *ObjectRef) GetAtespace() string { + if x != nil { + return x.Atespace + } + return "" +} + +func (x *ObjectRef) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type ActorTemplate struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Common resource metadata: atespace, name, uid, version, timestamps. + // + // +k8s:required + // +k8s:subfield(atespace)=+k8s:required + Metadata *ResourceMetadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + // worker_selector restricts which worker pools actors from this template + // may use. + // + // +k8s:optional + WorkerSelector *Selector `protobuf:"bytes,2,opt,name=worker_selector,json=workerSelector,proto3" json:"worker_selector,omitempty"` + // +k8s:required # at least one container + // +k8s:maxItems=10 + // +k8s:listType=map + // +k8s:listMapKey=name + Containers []*Container `protobuf:"bytes,3,rep,name=containers,proto3" json:"containers,omitempty"` + // +k8s:optional + // +k8s:maxItems=32 + // +k8s:listType=map + // +k8s:listMapKey=name + Volumes []*Volume `protobuf:"bytes,4,rep,name=volumes,proto3" json:"volumes,omitempty"` + // +k8s:required + SnapshotConfig *SnapshotConfig `protobuf:"bytes,5,opt,name=snapshot_config,json=snapshotConfig,proto3" json:"snapshot_config,omitempty"` + // sandbox_config selects the sandbox runtime this version's actors run on. // // +k8s:required SandboxConfig *SandboxConfig `protobuf:"bytes,6,opt,name=sandbox_config,json=sandboxConfig,proto3" json:"sandbox_config,omitempty"` @@ -2632,7 +3098,7 @@ type ActorTemplate struct { func (x *ActorTemplate) Reset() { *x = ActorTemplate{} - mi := &file_ateapi_proto_msgTypes[24] + mi := &file_ateapi_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2644,7 +3110,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[27] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2657,7 +3123,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{27} } func (x *ActorTemplate) GetMetadata() *ResourceMetadata { @@ -2733,7 +3199,7 @@ type Resources struct { func (x *Resources) Reset() { *x = Resources{} - mi := &file_ateapi_proto_msgTypes[25] + mi := &file_ateapi_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2745,7 +3211,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[28] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2758,7 +3224,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{28} } func (x *Resources) GetLimits() []*Limits { @@ -2786,7 +3252,7 @@ type Limits struct { func (x *Limits) Reset() { *x = Limits{} - mi := &file_ateapi_proto_msgTypes[26] + mi := &file_ateapi_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2798,7 +3264,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[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2811,7 +3277,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{29} } func (x *Limits) GetName() string { @@ -2852,7 +3318,7 @@ type GoldenSnapshotStatus struct { func (x *GoldenSnapshotStatus) Reset() { *x = GoldenSnapshotStatus{} - mi := &file_ateapi_proto_msgTypes[27] + mi := &file_ateapi_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2864,7 +3330,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[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2877,7 +3343,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{30} } func (x *GoldenSnapshotStatus) GetGoldenTag() *ObjectRef { @@ -2911,7 +3377,7 @@ type ActorTemplateStatus struct { func (x *ActorTemplateStatus) Reset() { *x = ActorTemplateStatus{} - mi := &file_ateapi_proto_msgTypes[28] + mi := &file_ateapi_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2923,7 +3389,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[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2936,7 +3402,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{31} } func (x *ActorTemplateStatus) GetGoldenSnapshotStatus() *GoldenSnapshotStatus { @@ -2967,7 +3433,7 @@ type SandboxConfig struct { func (x *SandboxConfig) Reset() { *x = SandboxConfig{} - mi := &file_ateapi_proto_msgTypes[29] + mi := &file_ateapi_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2979,7 +3445,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[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2992,7 +3458,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{32} } func (x *SandboxConfig) GetSandboxClass() SandboxClass { @@ -3045,7 +3511,7 @@ type SnapshotConfig struct { func (x *SnapshotConfig) Reset() { *x = SnapshotConfig{} - mi := &file_ateapi_proto_msgTypes[30] + mi := &file_ateapi_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3057,7 +3523,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[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3070,7 +3536,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{33} } func (x *SnapshotConfig) GetStorageLocation() string { @@ -3110,7 +3576,7 @@ type GoldenSnapshotConfig struct { func (x *GoldenSnapshotConfig) Reset() { *x = GoldenSnapshotConfig{} - mi := &file_ateapi_proto_msgTypes[31] + mi := &file_ateapi_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3122,7 +3588,7 @@ func (x *GoldenSnapshotConfig) String() string { func (*GoldenSnapshotConfig) ProtoMessage() {} func (x *GoldenSnapshotConfig) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[31] + mi := &file_ateapi_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3135,7 +3601,7 @@ func (x *GoldenSnapshotConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use GoldenSnapshotConfig.ProtoReflect.Descriptor instead. func (*GoldenSnapshotConfig) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{31} + return file_ateapi_proto_rawDescGZIP(), []int{34} } func (x *GoldenSnapshotConfig) GetMode() GoldenSnapshotMode { @@ -3215,7 +3681,7 @@ type Container struct { func (x *Container) Reset() { *x = Container{} - mi := &file_ateapi_proto_msgTypes[32] + mi := &file_ateapi_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3227,7 +3693,7 @@ func (x *Container) String() string { func (*Container) ProtoMessage() {} func (x *Container) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[32] + mi := &file_ateapi_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3240,7 +3706,7 @@ func (x *Container) ProtoReflect() protoreflect.Message { // Deprecated: Use Container.ProtoReflect.Descriptor instead. func (*Container) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{32} + return file_ateapi_proto_rawDescGZIP(), []int{35} } func (x *Container) GetName() string { @@ -3320,7 +3786,7 @@ type SecurityContext struct { func (x *SecurityContext) Reset() { *x = SecurityContext{} - mi := &file_ateapi_proto_msgTypes[33] + mi := &file_ateapi_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3332,7 +3798,7 @@ func (x *SecurityContext) String() string { func (*SecurityContext) ProtoMessage() {} func (x *SecurityContext) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[33] + mi := &file_ateapi_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3345,7 +3811,7 @@ func (x *SecurityContext) ProtoReflect() protoreflect.Message { // Deprecated: Use SecurityContext.ProtoReflect.Descriptor instead. func (*SecurityContext) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{33} + return file_ateapi_proto_rawDescGZIP(), []int{36} } func (x *SecurityContext) GetCapabilities() *Capabilities { @@ -3383,7 +3849,7 @@ type Capabilities struct { func (x *Capabilities) Reset() { *x = Capabilities{} - mi := &file_ateapi_proto_msgTypes[34] + mi := &file_ateapi_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3395,7 +3861,7 @@ func (x *Capabilities) String() string { func (*Capabilities) ProtoMessage() {} func (x *Capabilities) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[34] + mi := &file_ateapi_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3408,7 +3874,7 @@ func (x *Capabilities) ProtoReflect() protoreflect.Message { // Deprecated: Use Capabilities.ProtoReflect.Descriptor instead. func (*Capabilities) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{34} + return file_ateapi_proto_rawDescGZIP(), []int{37} } func (x *Capabilities) GetAdd() []string { @@ -3446,7 +3912,7 @@ type EnvVar struct { func (x *EnvVar) Reset() { *x = EnvVar{} - mi := &file_ateapi_proto_msgTypes[35] + mi := &file_ateapi_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3458,7 +3924,7 @@ func (x *EnvVar) String() string { func (*EnvVar) ProtoMessage() {} func (x *EnvVar) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[35] + mi := &file_ateapi_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3471,7 +3937,7 @@ func (x *EnvVar) ProtoReflect() protoreflect.Message { // Deprecated: Use EnvVar.ProtoReflect.Descriptor instead. func (*EnvVar) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{35} + return file_ateapi_proto_rawDescGZIP(), []int{38} } func (x *EnvVar) GetName() string { @@ -3511,7 +3977,7 @@ type ContainerWakeupProbe struct { func (x *ContainerWakeupProbe) Reset() { *x = ContainerWakeupProbe{} - mi := &file_ateapi_proto_msgTypes[36] + mi := &file_ateapi_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3523,7 +3989,7 @@ func (x *ContainerWakeupProbe) String() string { func (*ContainerWakeupProbe) ProtoMessage() {} func (x *ContainerWakeupProbe) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[36] + mi := &file_ateapi_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3536,7 +4002,7 @@ func (x *ContainerWakeupProbe) ProtoReflect() protoreflect.Message { // Deprecated: Use ContainerWakeupProbe.ProtoReflect.Descriptor instead. func (*ContainerWakeupProbe) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{36} + return file_ateapi_proto_rawDescGZIP(), []int{39} } func (x *ContainerWakeupProbe) GetHttpGet() *HttpGetAction { @@ -3576,7 +4042,7 @@ type HttpGetAction struct { func (x *HttpGetAction) Reset() { *x = HttpGetAction{} - mi := &file_ateapi_proto_msgTypes[37] + mi := &file_ateapi_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3588,7 +4054,7 @@ func (x *HttpGetAction) String() string { func (*HttpGetAction) ProtoMessage() {} func (x *HttpGetAction) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[37] + mi := &file_ateapi_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3601,7 +4067,7 @@ func (x *HttpGetAction) ProtoReflect() protoreflect.Message { // Deprecated: Use HttpGetAction.ProtoReflect.Descriptor instead. func (*HttpGetAction) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{37} + return file_ateapi_proto_rawDescGZIP(), []int{40} } func (x *HttpGetAction) GetPath() string { @@ -3651,7 +4117,7 @@ type Volume struct { func (x *Volume) Reset() { *x = Volume{} - mi := &file_ateapi_proto_msgTypes[38] + mi := &file_ateapi_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3663,7 +4129,7 @@ func (x *Volume) String() string { func (*Volume) ProtoMessage() {} func (x *Volume) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[38] + mi := &file_ateapi_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3676,7 +4142,7 @@ func (x *Volume) ProtoReflect() protoreflect.Message { // Deprecated: Use Volume.ProtoReflect.Descriptor instead. func (*Volume) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{38} + return file_ateapi_proto_rawDescGZIP(), []int{41} } func (x *Volume) GetName() string { @@ -3729,7 +4195,7 @@ type ExternalVolumeSource struct { func (x *ExternalVolumeSource) Reset() { *x = ExternalVolumeSource{} - mi := &file_ateapi_proto_msgTypes[39] + mi := &file_ateapi_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3741,7 +4207,7 @@ func (x *ExternalVolumeSource) String() string { func (*ExternalVolumeSource) ProtoMessage() {} func (x *ExternalVolumeSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[39] + mi := &file_ateapi_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3754,7 +4220,7 @@ func (x *ExternalVolumeSource) ProtoReflect() protoreflect.Message { // Deprecated: Use ExternalVolumeSource.ProtoReflect.Descriptor instead. func (*ExternalVolumeSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{39} + return file_ateapi_proto_rawDescGZIP(), []int{42} } func (x *ExternalVolumeSource) GetTemplate() *ExternalVolumeTemplate { @@ -3782,7 +4248,7 @@ type ImageVolumeSource struct { func (x *ImageVolumeSource) Reset() { *x = ImageVolumeSource{} - mi := &file_ateapi_proto_msgTypes[40] + mi := &file_ateapi_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3794,7 +4260,7 @@ func (x *ImageVolumeSource) String() string { func (*ImageVolumeSource) ProtoMessage() {} func (x *ImageVolumeSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[40] + mi := &file_ateapi_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3807,7 +4273,7 @@ func (x *ImageVolumeSource) ProtoReflect() protoreflect.Message { // Deprecated: Use ImageVolumeSource.ProtoReflect.Descriptor instead. func (*ImageVolumeSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{40} + return file_ateapi_proto_rawDescGZIP(), []int{43} } func (x *ImageVolumeSource) GetReference() string { @@ -3827,7 +4293,7 @@ type DurableDirVolumeSource struct { func (x *DurableDirVolumeSource) Reset() { *x = DurableDirVolumeSource{} - mi := &file_ateapi_proto_msgTypes[41] + mi := &file_ateapi_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3839,7 +4305,7 @@ func (x *DurableDirVolumeSource) String() string { func (*DurableDirVolumeSource) ProtoMessage() {} func (x *DurableDirVolumeSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[41] + mi := &file_ateapi_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3852,7 +4318,7 @@ func (x *DurableDirVolumeSource) ProtoReflect() protoreflect.Message { // Deprecated: Use DurableDirVolumeSource.ProtoReflect.Descriptor instead. func (*DurableDirVolumeSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{41} + return file_ateapi_proto_rawDescGZIP(), []int{44} } // ExternalVolumeTemplate provisions an external volume per actor; the volume @@ -3878,7 +4344,7 @@ type ExternalVolumeTemplate struct { func (x *ExternalVolumeTemplate) Reset() { *x = ExternalVolumeTemplate{} - mi := &file_ateapi_proto_msgTypes[42] + mi := &file_ateapi_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3890,7 +4356,7 @@ func (x *ExternalVolumeTemplate) String() string { func (*ExternalVolumeTemplate) ProtoMessage() {} func (x *ExternalVolumeTemplate) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[42] + mi := &file_ateapi_proto_msgTypes[45] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3903,7 +4369,7 @@ func (x *ExternalVolumeTemplate) ProtoReflect() protoreflect.Message { // Deprecated: Use ExternalVolumeTemplate.ProtoReflect.Descriptor instead. func (*ExternalVolumeTemplate) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{42} + return file_ateapi_proto_rawDescGZIP(), []int{45} } func (x *ExternalVolumeTemplate) GetCapacity() string { @@ -3940,7 +4406,7 @@ type SystemInfoVolumeSource struct { func (x *SystemInfoVolumeSource) Reset() { *x = SystemInfoVolumeSource{} - mi := &file_ateapi_proto_msgTypes[43] + mi := &file_ateapi_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3952,7 +4418,7 @@ func (x *SystemInfoVolumeSource) String() string { func (*SystemInfoVolumeSource) ProtoMessage() {} func (x *SystemInfoVolumeSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[43] + mi := &file_ateapi_proto_msgTypes[46] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3965,7 +4431,7 @@ func (x *SystemInfoVolumeSource) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemInfoVolumeSource.ProtoReflect.Descriptor instead. func (*SystemInfoVolumeSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{43} + return file_ateapi_proto_rawDescGZIP(), []int{46} } func (x *SystemInfoVolumeSource) GetDataSources() []*SystemInfoDataSource { @@ -3991,7 +4457,7 @@ type SystemInfoDataSource struct { func (x *SystemInfoDataSource) Reset() { *x = SystemInfoDataSource{} - mi := &file_ateapi_proto_msgTypes[44] + mi := &file_ateapi_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4003,7 +4469,7 @@ func (x *SystemInfoDataSource) String() string { func (*SystemInfoDataSource) ProtoMessage() {} func (x *SystemInfoDataSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[44] + mi := &file_ateapi_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4016,7 +4482,7 @@ func (x *SystemInfoDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemInfoDataSource.ProtoReflect.Descriptor instead. func (*SystemInfoDataSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{44} + return file_ateapi_proto_rawDescGZIP(), []int{47} } func (x *SystemInfoDataSource) GetActorMetadata() *ActorMetadataDataSource { @@ -4053,7 +4519,7 @@ type ActorMetadataDataSource struct { func (x *ActorMetadataDataSource) Reset() { *x = ActorMetadataDataSource{} - mi := &file_ateapi_proto_msgTypes[45] + mi := &file_ateapi_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4065,7 +4531,7 @@ func (x *ActorMetadataDataSource) String() string { func (*ActorMetadataDataSource) ProtoMessage() {} func (x *ActorMetadataDataSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[45] + mi := &file_ateapi_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4078,7 +4544,7 @@ func (x *ActorMetadataDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorMetadataDataSource.ProtoReflect.Descriptor instead. func (*ActorMetadataDataSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{45} + return file_ateapi_proto_rawDescGZIP(), []int{48} } func (x *ActorMetadataDataSource) GetItems() []*ActorMetadataItem { @@ -4110,7 +4576,7 @@ type ActorMetadataItem struct { func (x *ActorMetadataItem) Reset() { *x = ActorMetadataItem{} - mi := &file_ateapi_proto_msgTypes[46] + mi := &file_ateapi_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4122,7 +4588,7 @@ func (x *ActorMetadataItem) String() string { func (*ActorMetadataItem) ProtoMessage() {} func (x *ActorMetadataItem) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[46] + mi := &file_ateapi_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4135,7 +4601,7 @@ func (x *ActorMetadataItem) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorMetadataItem.ProtoReflect.Descriptor instead. func (*ActorMetadataItem) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{46} + return file_ateapi_proto_rawDescGZIP(), []int{49} } func (x *ActorMetadataItem) GetField() ActorMetadataField { @@ -4187,7 +4653,7 @@ type TrustBundleDataSource struct { func (x *TrustBundleDataSource) Reset() { *x = TrustBundleDataSource{} - mi := &file_ateapi_proto_msgTypes[47] + mi := &file_ateapi_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4199,7 +4665,7 @@ func (x *TrustBundleDataSource) String() string { func (*TrustBundleDataSource) ProtoMessage() {} func (x *TrustBundleDataSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[47] + mi := &file_ateapi_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4212,7 +4678,7 @@ func (x *TrustBundleDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use TrustBundleDataSource.ProtoReflect.Descriptor instead. func (*TrustBundleDataSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{47} + return file_ateapi_proto_rawDescGZIP(), []int{50} } func (x *TrustBundleDataSource) GetNames() []string { @@ -4251,7 +4717,7 @@ type VolumeMount struct { func (x *VolumeMount) Reset() { *x = VolumeMount{} - mi := &file_ateapi_proto_msgTypes[48] + mi := &file_ateapi_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4263,7 +4729,7 @@ func (x *VolumeMount) String() string { func (*VolumeMount) ProtoMessage() {} func (x *VolumeMount) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[48] + mi := &file_ateapi_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4276,7 +4742,7 @@ func (x *VolumeMount) ProtoReflect() protoreflect.Message { // Deprecated: Use VolumeMount.ProtoReflect.Descriptor instead. func (*VolumeMount) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{48} + return file_ateapi_proto_rawDescGZIP(), []int{51} } func (x *VolumeMount) GetName() string { @@ -4305,7 +4771,7 @@ type CreateAtespaceRequest struct { func (x *CreateAtespaceRequest) Reset() { *x = CreateAtespaceRequest{} - mi := &file_ateapi_proto_msgTypes[49] + mi := &file_ateapi_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4317,7 +4783,7 @@ func (x *CreateAtespaceRequest) String() string { func (*CreateAtespaceRequest) ProtoMessage() {} func (x *CreateAtespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[49] + mi := &file_ateapi_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4330,7 +4796,7 @@ func (x *CreateAtespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateAtespaceRequest.ProtoReflect.Descriptor instead. func (*CreateAtespaceRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{49} + return file_ateapi_proto_rawDescGZIP(), []int{52} } func (x *CreateAtespaceRequest) GetAtespace() *Atespace { @@ -4351,7 +4817,7 @@ type GetAtespaceRequest struct { func (x *GetAtespaceRequest) Reset() { *x = GetAtespaceRequest{} - mi := &file_ateapi_proto_msgTypes[50] + mi := &file_ateapi_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4363,7 +4829,7 @@ func (x *GetAtespaceRequest) String() string { func (*GetAtespaceRequest) ProtoMessage() {} func (x *GetAtespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[50] + mi := &file_ateapi_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4376,7 +4842,7 @@ func (x *GetAtespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAtespaceRequest.ProtoReflect.Descriptor instead. func (*GetAtespaceRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{50} + return file_ateapi_proto_rawDescGZIP(), []int{53} } func (x *GetAtespaceRequest) GetAtespace() *ObjectRef { @@ -4407,7 +4873,7 @@ type ListAtespacesRequest struct { func (x *ListAtespacesRequest) Reset() { *x = ListAtespacesRequest{} - mi := &file_ateapi_proto_msgTypes[51] + mi := &file_ateapi_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4419,7 +4885,7 @@ func (x *ListAtespacesRequest) String() string { func (*ListAtespacesRequest) ProtoMessage() {} func (x *ListAtespacesRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[51] + mi := &file_ateapi_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4432,7 +4898,7 @@ func (x *ListAtespacesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAtespacesRequest.ProtoReflect.Descriptor instead. func (*ListAtespacesRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{51} + return file_ateapi_proto_rawDescGZIP(), []int{54} } func (x *ListAtespacesRequest) GetPageSize() int32 { @@ -4461,7 +4927,7 @@ type ListAtespacesResponse struct { func (x *ListAtespacesResponse) Reset() { *x = ListAtespacesResponse{} - mi := &file_ateapi_proto_msgTypes[52] + mi := &file_ateapi_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4473,7 +4939,7 @@ func (x *ListAtespacesResponse) String() string { func (*ListAtespacesResponse) ProtoMessage() {} func (x *ListAtespacesResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[52] + mi := &file_ateapi_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4486,7 +4952,7 @@ func (x *ListAtespacesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAtespacesResponse.ProtoReflect.Descriptor instead. func (*ListAtespacesResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{52} + return file_ateapi_proto_rawDescGZIP(), []int{55} } func (x *ListAtespacesResponse) GetAtespaces() []*Atespace { @@ -4518,7 +4984,7 @@ type DeleteAtespaceRequest struct { func (x *DeleteAtespaceRequest) Reset() { *x = DeleteAtespaceRequest{} - mi := &file_ateapi_proto_msgTypes[53] + mi := &file_ateapi_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4530,7 +4996,7 @@ func (x *DeleteAtespaceRequest) String() string { func (*DeleteAtespaceRequest) ProtoMessage() {} func (x *DeleteAtespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[53] + mi := &file_ateapi_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4543,7 +5009,7 @@ func (x *DeleteAtespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteAtespaceRequest.ProtoReflect.Descriptor instead. func (*DeleteAtespaceRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{53} + return file_ateapi_proto_rawDescGZIP(), []int{56} } func (x *DeleteAtespaceRequest) GetAtespace() *ObjectRef { @@ -4574,7 +5040,7 @@ type CreateActorTemplateRequest struct { func (x *CreateActorTemplateRequest) Reset() { *x = CreateActorTemplateRequest{} - mi := &file_ateapi_proto_msgTypes[54] + mi := &file_ateapi_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4586,7 +5052,7 @@ func (x *CreateActorTemplateRequest) String() string { func (*CreateActorTemplateRequest) ProtoMessage() {} func (x *CreateActorTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[54] + mi := &file_ateapi_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4599,7 +5065,7 @@ func (x *CreateActorTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateActorTemplateRequest.ProtoReflect.Descriptor instead. func (*CreateActorTemplateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{54} + return file_ateapi_proto_rawDescGZIP(), []int{57} } func (x *CreateActorTemplateRequest) GetActorTemplate() *ActorTemplate { @@ -4620,7 +5086,7 @@ type GetActorTemplateRequest struct { func (x *GetActorTemplateRequest) Reset() { *x = GetActorTemplateRequest{} - mi := &file_ateapi_proto_msgTypes[55] + mi := &file_ateapi_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4632,7 +5098,7 @@ func (x *GetActorTemplateRequest) String() string { func (*GetActorTemplateRequest) ProtoMessage() {} func (x *GetActorTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[55] + mi := &file_ateapi_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4645,7 +5111,7 @@ func (x *GetActorTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorTemplateRequest.ProtoReflect.Descriptor instead. func (*GetActorTemplateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{55} + return file_ateapi_proto_rawDescGZIP(), []int{58} } func (x *GetActorTemplateRequest) GetActorTemplate() *ObjectRef { @@ -4682,7 +5148,7 @@ type ListActorTemplatesRequest struct { func (x *ListActorTemplatesRequest) Reset() { *x = ListActorTemplatesRequest{} - mi := &file_ateapi_proto_msgTypes[56] + mi := &file_ateapi_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4694,7 +5160,7 @@ func (x *ListActorTemplatesRequest) String() string { func (*ListActorTemplatesRequest) ProtoMessage() {} func (x *ListActorTemplatesRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[56] + mi := &file_ateapi_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4707,7 +5173,7 @@ func (x *ListActorTemplatesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorTemplatesRequest.ProtoReflect.Descriptor instead. func (*ListActorTemplatesRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{56} + return file_ateapi_proto_rawDescGZIP(), []int{59} } func (x *ListActorTemplatesRequest) GetAtespace() string { @@ -4744,7 +5210,7 @@ type ListActorTemplatesResponse struct { func (x *ListActorTemplatesResponse) Reset() { *x = ListActorTemplatesResponse{} - mi := &file_ateapi_proto_msgTypes[57] + mi := &file_ateapi_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4756,7 +5222,7 @@ func (x *ListActorTemplatesResponse) String() string { func (*ListActorTemplatesResponse) ProtoMessage() {} func (x *ListActorTemplatesResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[57] + mi := &file_ateapi_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4769,7 +5235,7 @@ func (x *ListActorTemplatesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorTemplatesResponse.ProtoReflect.Descriptor instead. func (*ListActorTemplatesResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{57} + return file_ateapi_proto_rawDescGZIP(), []int{60} } func (x *ListActorTemplatesResponse) GetActorTemplates() []*ActorTemplate { @@ -4801,7 +5267,7 @@ type DeleteActorTemplateRequest struct { func (x *DeleteActorTemplateRequest) Reset() { *x = DeleteActorTemplateRequest{} - mi := &file_ateapi_proto_msgTypes[58] + mi := &file_ateapi_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4813,7 +5279,7 @@ func (x *DeleteActorTemplateRequest) String() string { func (*DeleteActorTemplateRequest) ProtoMessage() {} func (x *DeleteActorTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[58] + mi := &file_ateapi_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4826,7 +5292,7 @@ func (x *DeleteActorTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteActorTemplateRequest.ProtoReflect.Descriptor instead. func (*DeleteActorTemplateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{58} + return file_ateapi_proto_rawDescGZIP(), []int{61} } func (x *DeleteActorTemplateRequest) GetActorTemplate() *ObjectRef { @@ -4854,7 +5320,7 @@ type GetActorRequest struct { func (x *GetActorRequest) Reset() { *x = GetActorRequest{} - mi := &file_ateapi_proto_msgTypes[59] + mi := &file_ateapi_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4866,7 +5332,7 @@ func (x *GetActorRequest) String() string { func (*GetActorRequest) ProtoMessage() {} func (x *GetActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[59] + mi := &file_ateapi_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4879,7 +5345,7 @@ func (x *GetActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorRequest.ProtoReflect.Descriptor instead. func (*GetActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{59} + return file_ateapi_proto_rawDescGZIP(), []int{62} } func (x *GetActorRequest) GetActor() *ObjectRef { @@ -4902,7 +5368,7 @@ type CreateActorRequest struct { func (x *CreateActorRequest) Reset() { *x = CreateActorRequest{} - mi := &file_ateapi_proto_msgTypes[60] + mi := &file_ateapi_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4914,7 +5380,7 @@ func (x *CreateActorRequest) String() string { func (*CreateActorRequest) ProtoMessage() {} func (x *CreateActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[60] + mi := &file_ateapi_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4927,7 +5393,7 @@ func (x *CreateActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateActorRequest.ProtoReflect.Descriptor instead. func (*CreateActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{60} + return file_ateapi_proto_rawDescGZIP(), []int{63} } func (x *CreateActorRequest) GetActor() *Actor { @@ -4958,7 +5424,7 @@ type UpdateActorRequest struct { func (x *UpdateActorRequest) Reset() { *x = UpdateActorRequest{} - mi := &file_ateapi_proto_msgTypes[61] + mi := &file_ateapi_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4970,7 +5436,7 @@ func (x *UpdateActorRequest) String() string { func (*UpdateActorRequest) ProtoMessage() {} func (x *UpdateActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[61] + mi := &file_ateapi_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4983,7 +5449,7 @@ func (x *UpdateActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateActorRequest.ProtoReflect.Descriptor instead. func (*UpdateActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{61} + return file_ateapi_proto_rawDescGZIP(), []int{64} } func (x *UpdateActorRequest) GetActor() *Actor { @@ -5004,7 +5470,7 @@ type SuspendActorRequest struct { func (x *SuspendActorRequest) Reset() { *x = SuspendActorRequest{} - mi := &file_ateapi_proto_msgTypes[62] + mi := &file_ateapi_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5016,7 +5482,7 @@ func (x *SuspendActorRequest) String() string { func (*SuspendActorRequest) ProtoMessage() {} func (x *SuspendActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[62] + mi := &file_ateapi_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5029,7 +5495,7 @@ func (x *SuspendActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SuspendActorRequest.ProtoReflect.Descriptor instead. func (*SuspendActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{62} + return file_ateapi_proto_rawDescGZIP(), []int{65} } func (x *SuspendActorRequest) GetActor() *ObjectRef { @@ -5048,7 +5514,7 @@ type SuspendActorResponse struct { func (x *SuspendActorResponse) Reset() { *x = SuspendActorResponse{} - mi := &file_ateapi_proto_msgTypes[63] + mi := &file_ateapi_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5060,7 +5526,7 @@ func (x *SuspendActorResponse) String() string { func (*SuspendActorResponse) ProtoMessage() {} func (x *SuspendActorResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[63] + mi := &file_ateapi_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5073,7 +5539,7 @@ func (x *SuspendActorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SuspendActorResponse.ProtoReflect.Descriptor instead. func (*SuspendActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{63} + return file_ateapi_proto_rawDescGZIP(), []int{66} } func (x *SuspendActorResponse) GetActor() *Actor { @@ -5094,7 +5560,7 @@ type PauseActorRequest struct { func (x *PauseActorRequest) Reset() { *x = PauseActorRequest{} - mi := &file_ateapi_proto_msgTypes[64] + mi := &file_ateapi_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5106,7 +5572,7 @@ func (x *PauseActorRequest) String() string { func (*PauseActorRequest) ProtoMessage() {} func (x *PauseActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[64] + mi := &file_ateapi_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5119,7 +5585,7 @@ func (x *PauseActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PauseActorRequest.ProtoReflect.Descriptor instead. func (*PauseActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{64} + return file_ateapi_proto_rawDescGZIP(), []int{67} } func (x *PauseActorRequest) GetActor() *ObjectRef { @@ -5138,7 +5604,7 @@ type PauseActorResponse struct { func (x *PauseActorResponse) Reset() { *x = PauseActorResponse{} - mi := &file_ateapi_proto_msgTypes[65] + mi := &file_ateapi_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5150,7 +5616,7 @@ func (x *PauseActorResponse) String() string { func (*PauseActorResponse) ProtoMessage() {} func (x *PauseActorResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[65] + mi := &file_ateapi_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5163,7 +5629,7 @@ func (x *PauseActorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PauseActorResponse.ProtoReflect.Descriptor instead. func (*PauseActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{65} + return file_ateapi_proto_rawDescGZIP(), []int{68} } func (x *PauseActorResponse) GetActor() *Actor { @@ -5184,7 +5650,7 @@ type ResumeActorRequest struct { func (x *ResumeActorRequest) Reset() { *x = ResumeActorRequest{} - mi := &file_ateapi_proto_msgTypes[66] + mi := &file_ateapi_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5196,7 +5662,7 @@ func (x *ResumeActorRequest) String() string { func (*ResumeActorRequest) ProtoMessage() {} func (x *ResumeActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[66] + mi := &file_ateapi_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5209,7 +5675,7 @@ func (x *ResumeActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ResumeActorRequest.ProtoReflect.Descriptor instead. func (*ResumeActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{66} + return file_ateapi_proto_rawDescGZIP(), []int{69} } func (x *ResumeActorRequest) GetActor() *ObjectRef { @@ -5231,7 +5697,7 @@ type ResumeActorResponse struct { func (x *ResumeActorResponse) Reset() { *x = ResumeActorResponse{} - mi := &file_ateapi_proto_msgTypes[67] + mi := &file_ateapi_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5243,7 +5709,7 @@ func (x *ResumeActorResponse) String() string { func (*ResumeActorResponse) ProtoMessage() {} func (x *ResumeActorResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[67] + mi := &file_ateapi_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5256,7 +5722,7 @@ func (x *ResumeActorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ResumeActorResponse.ProtoReflect.Descriptor instead. func (*ResumeActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{67} + return file_ateapi_proto_rawDescGZIP(), []int{70} } func (x *ResumeActorResponse) GetActor() *Actor { @@ -5286,7 +5752,7 @@ type RevertActorRequest struct { func (x *RevertActorRequest) Reset() { *x = RevertActorRequest{} - mi := &file_ateapi_proto_msgTypes[68] + mi := &file_ateapi_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5298,7 +5764,7 @@ func (x *RevertActorRequest) String() string { func (*RevertActorRequest) ProtoMessage() {} func (x *RevertActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[68] + mi := &file_ateapi_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5311,7 +5777,7 @@ func (x *RevertActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RevertActorRequest.ProtoReflect.Descriptor instead. func (*RevertActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{68} + return file_ateapi_proto_rawDescGZIP(), []int{71} } func (x *RevertActorRequest) GetActor() *ObjectRef { @@ -5333,7 +5799,7 @@ type RevertActorResponse struct { func (x *RevertActorResponse) Reset() { *x = RevertActorResponse{} - mi := &file_ateapi_proto_msgTypes[69] + mi := &file_ateapi_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5345,7 +5811,7 @@ func (x *RevertActorResponse) String() string { func (*RevertActorResponse) ProtoMessage() {} func (x *RevertActorResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[69] + mi := &file_ateapi_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5358,7 +5824,7 @@ func (x *RevertActorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RevertActorResponse.ProtoReflect.Descriptor instead. func (*RevertActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{69} + return file_ateapi_proto_rawDescGZIP(), []int{72} } func (x *RevertActorResponse) GetActor() *Actor { @@ -5387,7 +5853,7 @@ type DeleteActorRequest struct { func (x *DeleteActorRequest) Reset() { *x = DeleteActorRequest{} - mi := &file_ateapi_proto_msgTypes[70] + mi := &file_ateapi_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5399,7 +5865,7 @@ func (x *DeleteActorRequest) String() string { func (*DeleteActorRequest) ProtoMessage() {} func (x *DeleteActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[70] + mi := &file_ateapi_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5412,7 +5878,7 @@ func (x *DeleteActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteActorRequest.ProtoReflect.Descriptor instead. func (*DeleteActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{70} + return file_ateapi_proto_rawDescGZIP(), []int{73} } func (x *DeleteActorRequest) GetActor() *ObjectRef { @@ -5456,7 +5922,7 @@ type GetActorEgressPolicyRequest struct { func (x *GetActorEgressPolicyRequest) Reset() { *x = GetActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[71] + mi := &file_ateapi_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5468,7 +5934,7 @@ func (x *GetActorEgressPolicyRequest) String() string { func (*GetActorEgressPolicyRequest) ProtoMessage() {} func (x *GetActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[71] + mi := &file_ateapi_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5481,7 +5947,7 @@ func (x *GetActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*GetActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{71} + return file_ateapi_proto_rawDescGZIP(), []int{74} } func (x *GetActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -5519,7 +5985,7 @@ type CreateActorEgressPolicyRequest struct { func (x *CreateActorEgressPolicyRequest) Reset() { *x = CreateActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[72] + mi := &file_ateapi_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5531,7 +5997,7 @@ func (x *CreateActorEgressPolicyRequest) String() string { func (*CreateActorEgressPolicyRequest) ProtoMessage() {} func (x *CreateActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[72] + mi := &file_ateapi_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5544,7 +6010,7 @@ func (x *CreateActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*CreateActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{72} + return file_ateapi_proto_rawDescGZIP(), []int{75} } func (x *CreateActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -5582,7 +6048,7 @@ type UpdateActorEgressPolicyRequest struct { func (x *UpdateActorEgressPolicyRequest) Reset() { *x = UpdateActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[73] + mi := &file_ateapi_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5594,7 +6060,7 @@ func (x *UpdateActorEgressPolicyRequest) String() string { func (*UpdateActorEgressPolicyRequest) ProtoMessage() {} func (x *UpdateActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[73] + mi := &file_ateapi_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5607,7 +6073,7 @@ func (x *UpdateActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*UpdateActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{73} + return file_ateapi_proto_rawDescGZIP(), []int{76} } func (x *UpdateActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -5648,7 +6114,7 @@ type DeleteActorEgressPolicyRequest struct { func (x *DeleteActorEgressPolicyRequest) Reset() { *x = DeleteActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[74] + mi := &file_ateapi_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5660,7 +6126,7 @@ func (x *DeleteActorEgressPolicyRequest) String() string { func (*DeleteActorEgressPolicyRequest) ProtoMessage() {} func (x *DeleteActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[74] + mi := &file_ateapi_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5673,7 +6139,7 @@ func (x *DeleteActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*DeleteActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{74} + return file_ateapi_proto_rawDescGZIP(), []int{77} } func (x *DeleteActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -5708,7 +6174,7 @@ type GetTagRequest struct { func (x *GetTagRequest) Reset() { *x = GetTagRequest{} - mi := &file_ateapi_proto_msgTypes[75] + mi := &file_ateapi_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5720,7 +6186,7 @@ func (x *GetTagRequest) String() string { func (*GetTagRequest) ProtoMessage() {} func (x *GetTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[75] + mi := &file_ateapi_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5733,7 +6199,7 @@ func (x *GetTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTagRequest.ProtoReflect.Descriptor instead. func (*GetTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{75} + return file_ateapi_proto_rawDescGZIP(), []int{78} } func (x *GetTagRequest) GetTag() *ObjectRef { @@ -5772,7 +6238,7 @@ type MintActorJwtRequest struct { func (x *MintActorJwtRequest) Reset() { *x = MintActorJwtRequest{} - mi := &file_ateapi_proto_msgTypes[76] + mi := &file_ateapi_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5784,7 +6250,7 @@ func (x *MintActorJwtRequest) String() string { func (*MintActorJwtRequest) ProtoMessage() {} func (x *MintActorJwtRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[76] + mi := &file_ateapi_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5797,7 +6263,7 @@ func (x *MintActorJwtRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorJwtRequest.ProtoReflect.Descriptor instead. func (*MintActorJwtRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{76} + return file_ateapi_proto_rawDescGZIP(), []int{79} } func (x *MintActorJwtRequest) GetActor() *ObjectRef { @@ -5847,7 +6313,7 @@ type MintActorJwtResponse struct { func (x *MintActorJwtResponse) Reset() { *x = MintActorJwtResponse{} - mi := &file_ateapi_proto_msgTypes[77] + mi := &file_ateapi_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5859,7 +6325,7 @@ func (x *MintActorJwtResponse) String() string { func (*MintActorJwtResponse) ProtoMessage() {} func (x *MintActorJwtResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[77] + mi := &file_ateapi_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5872,7 +6338,7 @@ func (x *MintActorJwtResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorJwtResponse.ProtoReflect.Descriptor instead. func (*MintActorJwtResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{77} + return file_ateapi_proto_rawDescGZIP(), []int{80} } func (x *MintActorJwtResponse) GetActorJwt() string { @@ -5917,7 +6383,7 @@ type MintActorCertificateRequest struct { func (x *MintActorCertificateRequest) Reset() { *x = MintActorCertificateRequest{} - mi := &file_ateapi_proto_msgTypes[78] + mi := &file_ateapi_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5929,7 +6395,7 @@ func (x *MintActorCertificateRequest) String() string { func (*MintActorCertificateRequest) ProtoMessage() {} func (x *MintActorCertificateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[78] + mi := &file_ateapi_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5942,7 +6408,7 @@ func (x *MintActorCertificateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorCertificateRequest.ProtoReflect.Descriptor instead. func (*MintActorCertificateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{78} + return file_ateapi_proto_rawDescGZIP(), []int{81} } func (x *MintActorCertificateRequest) GetActor() *ObjectRef { @@ -5979,7 +6445,7 @@ type MintActorCertificateResponse struct { func (x *MintActorCertificateResponse) Reset() { *x = MintActorCertificateResponse{} - mi := &file_ateapi_proto_msgTypes[79] + mi := &file_ateapi_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5991,7 +6457,7 @@ func (x *MintActorCertificateResponse) String() string { func (*MintActorCertificateResponse) ProtoMessage() {} func (x *MintActorCertificateResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[79] + mi := &file_ateapi_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6004,7 +6470,7 @@ func (x *MintActorCertificateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorCertificateResponse.ProtoReflect.Descriptor instead. func (*MintActorCertificateResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{79} + return file_ateapi_proto_rawDescGZIP(), []int{82} } func (x *MintActorCertificateResponse) GetActorCertificates() [][]byte { @@ -6040,7 +6506,7 @@ type ListTagsRequest struct { func (x *ListTagsRequest) Reset() { *x = ListTagsRequest{} - mi := &file_ateapi_proto_msgTypes[80] + mi := &file_ateapi_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6052,7 +6518,7 @@ func (x *ListTagsRequest) String() string { func (*ListTagsRequest) ProtoMessage() {} func (x *ListTagsRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[80] + mi := &file_ateapi_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6065,7 +6531,7 @@ func (x *ListTagsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListTagsRequest.ProtoReflect.Descriptor instead. func (*ListTagsRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{80} + return file_ateapi_proto_rawDescGZIP(), []int{83} } func (x *ListTagsRequest) GetAtespace() string { @@ -6099,7 +6565,7 @@ type ListTagsResponse struct { func (x *ListTagsResponse) Reset() { *x = ListTagsResponse{} - mi := &file_ateapi_proto_msgTypes[81] + mi := &file_ateapi_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6111,7 +6577,7 @@ func (x *ListTagsResponse) String() string { func (*ListTagsResponse) ProtoMessage() {} func (x *ListTagsResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[81] + mi := &file_ateapi_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6124,7 +6590,7 @@ func (x *ListTagsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListTagsResponse.ProtoReflect.Descriptor instead. func (*ListTagsResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{81} + return file_ateapi_proto_rawDescGZIP(), []int{84} } func (x *ListTagsResponse) GetTags() []*Tag { @@ -6167,21 +6633,354 @@ type CreateTagRequest struct { sizeCache protoimpl.SizeCache } -func (x *CreateTagRequest) Reset() { - *x = CreateTagRequest{} - mi := &file_ateapi_proto_msgTypes[82] +func (x *CreateTagRequest) Reset() { + *x = CreateTagRequest{} + mi := &file_ateapi_proto_msgTypes[85] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateTagRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateTagRequest) ProtoMessage() {} + +func (x *CreateTagRequest) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[85] + 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 CreateTagRequest.ProtoReflect.Descriptor instead. +func (*CreateTagRequest) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{85} +} + +func (x *CreateTagRequest) GetTag() *Tag { + if x != nil { + return x.Tag + } + return nil +} + +// Request to update mutable fields on an existing Tag. +// The tag keeps its address: the snapshot it points at cannot be changed. +type UpdateTagRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The tag to update. + // tag.metadata.atespace and tag.metadata.name identify which resource to + // update. + // tag.metadata.version and tag.metadata.uid are required preconditions + // + // +k8s:required + // +k8s:opaqueType # updates are handled in 2 steps, do not descend + // +k8s:subfield(metadata)=+k8s:required + // +k8s:customValidation # TODO: when we get nested subfields, require metadata.atespace + Tag *Tag `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *UpdateTagRequest) Reset() { + *x = UpdateTagRequest{} + mi := &file_ateapi_proto_msgTypes[86] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateTagRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateTagRequest) ProtoMessage() {} + +func (x *UpdateTagRequest) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[86] + 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 UpdateTagRequest.ProtoReflect.Descriptor instead. +func (*UpdateTagRequest) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{86} +} + +func (x *UpdateTagRequest) GetTag() *Tag { + if x != nil { + return x.Tag + } + return nil +} + +type DeleteTagRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // +k8s:required + // +k8s:subfield(atespace)=+k8s:required + Tag *ObjectRef `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"` + // Optional per-delete preconditions. + // + // +k8s:optional + Options *DeleteOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *DeleteTagRequest) Reset() { + *x = DeleteTagRequest{} + mi := &file_ateapi_proto_msgTypes[87] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DeleteTagRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteTagRequest) ProtoMessage() {} + +func (x *DeleteTagRequest) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[87] + 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 DeleteTagRequest.ProtoReflect.Descriptor instead. +func (*DeleteTagRequest) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{87} +} + +func (x *DeleteTagRequest) GetTag() *ObjectRef { + if x != nil { + return x.Tag + } + return nil +} + +func (x *DeleteTagRequest) GetOptions() *DeleteOptions { + if x != nil { + return x.Options + } + return nil +} + +// Request to create a SharedVolume. +// +// +k8s:customValidation # exactly one of storage_class_name and volume_id +type CreateSharedVolumeRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The volume to create. Name a storage class to provision a new volume, or + // supply a volume ID to register one that already exists. status is ignored. + // + // +k8s:required + SharedVolume *SharedVolume `protobuf:"bytes,1,opt,name=shared_volume,json=sharedVolume,proto3" json:"shared_volume,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *CreateSharedVolumeRequest) Reset() { + *x = CreateSharedVolumeRequest{} + mi := &file_ateapi_proto_msgTypes[88] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *CreateSharedVolumeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateSharedVolumeRequest) ProtoMessage() {} + +func (x *CreateSharedVolumeRequest) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[88] + 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 CreateSharedVolumeRequest.ProtoReflect.Descriptor instead. +func (*CreateSharedVolumeRequest) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{88} +} + +func (x *CreateSharedVolumeRequest) GetSharedVolume() *SharedVolume { + if x != nil { + return x.SharedVolume + } + return nil +} + +// GetSharedVolumeRequest identifies one SharedVolume. +type GetSharedVolumeRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The volume to get. + // + // +k8s:required + // +k8s:subfield(atespace)=+k8s:required + SharedVolume *ObjectRef `protobuf:"bytes,1,opt,name=shared_volume,json=sharedVolume,proto3" json:"shared_volume,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *GetSharedVolumeRequest) Reset() { + *x = GetSharedVolumeRequest{} + mi := &file_ateapi_proto_msgTypes[89] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *GetSharedVolumeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetSharedVolumeRequest) ProtoMessage() {} + +func (x *GetSharedVolumeRequest) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[89] + 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 GetSharedVolumeRequest.ProtoReflect.Descriptor instead. +func (*GetSharedVolumeRequest) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{89} +} + +func (x *GetSharedVolumeRequest) GetSharedVolume() *ObjectRef { + if x != nil { + return x.SharedVolume + } + return nil +} + +// ListSharedVolumesRequest selects a page of ExternalVolumes. +type ListSharedVolumesRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The atespace to list from. Empty lists across all atespaces. + // + // +k8s:optional + // +k8s:format=k8s-short-name + Atespace string `protobuf:"bytes,1,opt,name=atespace,proto3" json:"atespace,omitempty"` + // Requested page size; values above 1000 are coerced to 1000. + // + // +k8s:optional + // +k8s:minimum=1 + PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + // Pagination token from a previous ListSharedVolumes response. + // + // +k8s:optional + // +k8s:maxLength=256 + PageToken string `protobuf:"bytes,3,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListSharedVolumesRequest) Reset() { + *x = ListSharedVolumesRequest{} + mi := &file_ateapi_proto_msgTypes[90] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ListSharedVolumesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ListSharedVolumesRequest) ProtoMessage() {} + +func (x *ListSharedVolumesRequest) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[90] + 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 ListSharedVolumesRequest.ProtoReflect.Descriptor instead. +func (*ListSharedVolumesRequest) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{90} +} + +func (x *ListSharedVolumesRequest) GetAtespace() string { + if x != nil { + return x.Atespace + } + return "" +} + +func (x *ListSharedVolumesRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ListSharedVolumesRequest) GetPageToken() string { + if x != nil { + return x.PageToken + } + return "" +} + +// ListSharedVolumesResponse is one page of ExternalVolumes. +type ListSharedVolumesResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The volumes in this page. + SharedVolumes []*SharedVolume `protobuf:"bytes,1,rep,name=shared_volumes,json=sharedVolumes,proto3" json:"shared_volumes,omitempty"` + // Pagination token for the next page. Empty on the last page. + NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ListSharedVolumesResponse) Reset() { + *x = ListSharedVolumesResponse{} + mi := &file_ateapi_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *CreateTagRequest) String() string { +func (x *ListSharedVolumesResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*CreateTagRequest) ProtoMessage() {} +func (*ListSharedVolumesResponse) ProtoMessage() {} -func (x *CreateTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[82] +func (x *ListSharedVolumesResponse) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6192,51 +6991,55 @@ func (x *CreateTagRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use CreateTagRequest.ProtoReflect.Descriptor instead. -func (*CreateTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{82} +// Deprecated: Use ListSharedVolumesResponse.ProtoReflect.Descriptor instead. +func (*ListSharedVolumesResponse) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{91} } -func (x *CreateTagRequest) GetTag() *Tag { +func (x *ListSharedVolumesResponse) GetSharedVolumes() []*SharedVolume { if x != nil { - return x.Tag + return x.SharedVolumes } return nil } -// Request to update mutable fields on an existing Tag. -// The tag keeps its address: the snapshot it points at cannot be changed. -type UpdateTagRequest struct { +func (x *ListSharedVolumesResponse) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + +// Request to update the mutable fields of a SharedVolume. +type UpdateSharedVolumeRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - // The tag to update. - // tag.metadata.atespace and tag.metadata.name identify which resource to - // update. - // tag.metadata.version and tag.metadata.uid are required preconditions + // The volume to update. metadata.atespace and metadata.name identify it; + // metadata.version and metadata.uid are required preconditions. // // +k8s:required // +k8s:opaqueType # updates are handled in 2 steps, do not descend // +k8s:subfield(metadata)=+k8s:required // +k8s:customValidation # TODO: when we get nested subfields, require metadata.atespace - Tag *Tag `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"` + SharedVolume *SharedVolume `protobuf:"bytes,1,opt,name=shared_volume,json=sharedVolume,proto3" json:"shared_volume,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *UpdateTagRequest) Reset() { - *x = UpdateTagRequest{} - mi := &file_ateapi_proto_msgTypes[83] +func (x *UpdateSharedVolumeRequest) Reset() { + *x = UpdateSharedVolumeRequest{} + mi := &file_ateapi_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *UpdateTagRequest) String() string { +func (x *UpdateSharedVolumeRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*UpdateTagRequest) ProtoMessage() {} +func (*UpdateSharedVolumeRequest) ProtoMessage() {} -func (x *UpdateTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[83] +func (x *UpdateSharedVolumeRequest) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6247,23 +7050,26 @@ func (x *UpdateTagRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use UpdateTagRequest.ProtoReflect.Descriptor instead. -func (*UpdateTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{83} +// Deprecated: Use UpdateSharedVolumeRequest.ProtoReflect.Descriptor instead. +func (*UpdateSharedVolumeRequest) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{92} } -func (x *UpdateTagRequest) GetTag() *Tag { +func (x *UpdateSharedVolumeRequest) GetSharedVolume() *SharedVolume { if x != nil { - return x.Tag + return x.SharedVolume } return nil } -type DeleteTagRequest struct { +// DeleteSharedVolumeRequest identifies one SharedVolume to delete. +type DeleteSharedVolumeRequest struct { state protoimpl.MessageState `protogen:"open.v1"` + // The volume to delete. + // // +k8s:required // +k8s:subfield(atespace)=+k8s:required - Tag *ObjectRef `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"` + SharedVolume *ObjectRef `protobuf:"bytes,1,opt,name=shared_volume,json=sharedVolume,proto3" json:"shared_volume,omitempty"` // Optional per-delete preconditions. // // +k8s:optional @@ -6272,21 +7078,21 @@ type DeleteTagRequest struct { sizeCache protoimpl.SizeCache } -func (x *DeleteTagRequest) Reset() { - *x = DeleteTagRequest{} - mi := &file_ateapi_proto_msgTypes[84] +func (x *DeleteSharedVolumeRequest) Reset() { + *x = DeleteSharedVolumeRequest{} + mi := &file_ateapi_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *DeleteTagRequest) String() string { +func (x *DeleteSharedVolumeRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*DeleteTagRequest) ProtoMessage() {} +func (*DeleteSharedVolumeRequest) ProtoMessage() {} -func (x *DeleteTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[84] +func (x *DeleteSharedVolumeRequest) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6297,19 +7103,19 @@ func (x *DeleteTagRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use DeleteTagRequest.ProtoReflect.Descriptor instead. -func (*DeleteTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{84} +// Deprecated: Use DeleteSharedVolumeRequest.ProtoReflect.Descriptor instead. +func (*DeleteSharedVolumeRequest) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{93} } -func (x *DeleteTagRequest) GetTag() *ObjectRef { +func (x *DeleteSharedVolumeRequest) GetSharedVolume() *ObjectRef { if x != nil { - return x.Tag + return x.SharedVolume } return nil } -func (x *DeleteTagRequest) GetOptions() *DeleteOptions { +func (x *DeleteSharedVolumeRequest) GetOptions() *DeleteOptions { if x != nil { return x.Options } @@ -6338,7 +7144,7 @@ type DeleteOptions struct { func (x *DeleteOptions) Reset() { *x = DeleteOptions{} - mi := &file_ateapi_proto_msgTypes[85] + mi := &file_ateapi_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6350,7 +7156,7 @@ func (x *DeleteOptions) String() string { func (*DeleteOptions) ProtoMessage() {} func (x *DeleteOptions) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[85] + mi := &file_ateapi_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6363,7 +7169,7 @@ func (x *DeleteOptions) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteOptions.ProtoReflect.Descriptor instead. func (*DeleteOptions) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{85} + return file_ateapi_proto_rawDescGZIP(), []int{94} } func (x *DeleteOptions) GetVersion() int64 { @@ -6407,7 +7213,7 @@ type ListWorkerActorAssignmentsRequest struct { func (x *ListWorkerActorAssignmentsRequest) Reset() { *x = ListWorkerActorAssignmentsRequest{} - mi := &file_ateapi_proto_msgTypes[86] + mi := &file_ateapi_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6419,7 +7225,7 @@ func (x *ListWorkerActorAssignmentsRequest) String() string { func (*ListWorkerActorAssignmentsRequest) ProtoMessage() {} func (x *ListWorkerActorAssignmentsRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[86] + mi := &file_ateapi_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6432,7 +7238,7 @@ func (x *ListWorkerActorAssignmentsRequest) ProtoReflect() protoreflect.Message // Deprecated: Use ListWorkerActorAssignmentsRequest.ProtoReflect.Descriptor instead. func (*ListWorkerActorAssignmentsRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{86} + return file_ateapi_proto_rawDescGZIP(), []int{95} } func (x *ListWorkerActorAssignmentsRequest) GetWorker() *ObjectRef { @@ -6469,7 +7275,7 @@ type ListWorkerActorAssignmentsResponse struct { func (x *ListWorkerActorAssignmentsResponse) Reset() { *x = ListWorkerActorAssignmentsResponse{} - mi := &file_ateapi_proto_msgTypes[87] + mi := &file_ateapi_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6481,7 +7287,7 @@ func (x *ListWorkerActorAssignmentsResponse) String() string { func (*ListWorkerActorAssignmentsResponse) ProtoMessage() {} func (x *ListWorkerActorAssignmentsResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[87] + mi := &file_ateapi_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6494,7 +7300,7 @@ func (x *ListWorkerActorAssignmentsResponse) ProtoReflect() protoreflect.Message // Deprecated: Use ListWorkerActorAssignmentsResponse.ProtoReflect.Descriptor instead. func (*ListWorkerActorAssignmentsResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{87} + return file_ateapi_proto_rawDescGZIP(), []int{96} } func (x *ListWorkerActorAssignmentsResponse) GetActorAssignments() []*ActorAssignment { @@ -6532,7 +7338,7 @@ type ListWorkersRequest struct { func (x *ListWorkersRequest) Reset() { *x = ListWorkersRequest{} - mi := &file_ateapi_proto_msgTypes[88] + mi := &file_ateapi_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6544,7 +7350,7 @@ func (x *ListWorkersRequest) String() string { func (*ListWorkersRequest) ProtoMessage() {} func (x *ListWorkersRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[88] + mi := &file_ateapi_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6557,7 +7363,7 @@ func (x *ListWorkersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkersRequest.ProtoReflect.Descriptor instead. func (*ListWorkersRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{88} + return file_ateapi_proto_rawDescGZIP(), []int{97} } func (x *ListWorkersRequest) GetPageSize() int32 { @@ -6586,7 +7392,7 @@ type ListWorkersResponse struct { func (x *ListWorkersResponse) Reset() { *x = ListWorkersResponse{} - mi := &file_ateapi_proto_msgTypes[89] + mi := &file_ateapi_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6598,7 +7404,7 @@ func (x *ListWorkersResponse) String() string { func (*ListWorkersResponse) ProtoMessage() {} func (x *ListWorkersResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[89] + mi := &file_ateapi_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6611,7 +7417,7 @@ func (x *ListWorkersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkersResponse.ProtoReflect.Descriptor instead. func (*ListWorkersResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{89} + return file_ateapi_proto_rawDescGZIP(), []int{98} } func (x *ListWorkersResponse) GetWorkers() []*Worker { @@ -6641,7 +7447,7 @@ type GetWorkerRequest struct { func (x *GetWorkerRequest) Reset() { *x = GetWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[90] + mi := &file_ateapi_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6653,7 +7459,7 @@ func (x *GetWorkerRequest) String() string { func (*GetWorkerRequest) ProtoMessage() {} func (x *GetWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[90] + mi := &file_ateapi_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6666,7 +7472,7 @@ func (x *GetWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkerRequest.ProtoReflect.Descriptor instead. func (*GetWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{90} + return file_ateapi_proto_rawDescGZIP(), []int{99} } func (x *GetWorkerRequest) GetWorker() *ObjectRef { @@ -6688,7 +7494,7 @@ type CreateWorkerRequest struct { func (x *CreateWorkerRequest) Reset() { *x = CreateWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[91] + mi := &file_ateapi_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6700,7 +7506,7 @@ func (x *CreateWorkerRequest) String() string { func (*CreateWorkerRequest) ProtoMessage() {} func (x *CreateWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[91] + mi := &file_ateapi_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6713,7 +7519,7 @@ func (x *CreateWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkerRequest.ProtoReflect.Descriptor instead. func (*CreateWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{91} + return file_ateapi_proto_rawDescGZIP(), []int{100} } func (x *CreateWorkerRequest) GetWorker() *Worker { @@ -6748,7 +7554,7 @@ type UpdateWorkerRequest struct { func (x *UpdateWorkerRequest) Reset() { *x = UpdateWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[92] + mi := &file_ateapi_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6760,7 +7566,7 @@ func (x *UpdateWorkerRequest) String() string { func (*UpdateWorkerRequest) ProtoMessage() {} func (x *UpdateWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[92] + mi := &file_ateapi_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6773,7 +7579,7 @@ func (x *UpdateWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateWorkerRequest.ProtoReflect.Descriptor instead. func (*UpdateWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{92} + return file_ateapi_proto_rawDescGZIP(), []int{101} } func (x *UpdateWorkerRequest) GetWorker() *Worker { @@ -6800,7 +7606,7 @@ type DeleteWorkerRequest struct { func (x *DeleteWorkerRequest) Reset() { *x = DeleteWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[93] + mi := &file_ateapi_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6812,7 +7618,7 @@ func (x *DeleteWorkerRequest) String() string { func (*DeleteWorkerRequest) ProtoMessage() {} func (x *DeleteWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[93] + mi := &file_ateapi_proto_msgTypes[102] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6825,7 +7631,7 @@ func (x *DeleteWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkerRequest.ProtoReflect.Descriptor instead. func (*DeleteWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{93} + return file_ateapi_proto_rawDescGZIP(), []int{102} } func (x *DeleteWorkerRequest) GetWorker() *ObjectRef { @@ -6855,7 +7661,7 @@ type DrainWorkerRequest struct { func (x *DrainWorkerRequest) Reset() { *x = DrainWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[94] + mi := &file_ateapi_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6867,7 +7673,7 @@ func (x *DrainWorkerRequest) String() string { func (*DrainWorkerRequest) ProtoMessage() {} func (x *DrainWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[94] + mi := &file_ateapi_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6880,7 +7686,7 @@ func (x *DrainWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DrainWorkerRequest.ProtoReflect.Descriptor instead. func (*DrainWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{94} + return file_ateapi_proto_rawDescGZIP(), []int{103} } func (x *DrainWorkerRequest) GetWorker() *ObjectRef { @@ -6901,7 +7707,7 @@ type DrainWorkerResponse struct { func (x *DrainWorkerResponse) Reset() { *x = DrainWorkerResponse{} - mi := &file_ateapi_proto_msgTypes[95] + mi := &file_ateapi_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6913,7 +7719,7 @@ func (x *DrainWorkerResponse) String() string { func (*DrainWorkerResponse) ProtoMessage() {} func (x *DrainWorkerResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[95] + mi := &file_ateapi_proto_msgTypes[104] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6926,7 +7732,7 @@ func (x *DrainWorkerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DrainWorkerResponse.ProtoReflect.Descriptor instead. func (*DrainWorkerResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{95} + return file_ateapi_proto_rawDescGZIP(), []int{104} } func (x *DrainWorkerResponse) GetWorker() *Worker { @@ -6964,7 +7770,7 @@ type ListActorsRequest struct { func (x *ListActorsRequest) Reset() { *x = ListActorsRequest{} - mi := &file_ateapi_proto_msgTypes[96] + mi := &file_ateapi_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6976,7 +7782,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[105] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6989,7 +7795,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{105} } func (x *ListActorsRequest) GetAtespace() string { @@ -7025,7 +7831,7 @@ type ListActorsResponse struct { func (x *ListActorsResponse) Reset() { *x = ListActorsResponse{} - mi := &file_ateapi_proto_msgTypes[97] + mi := &file_ateapi_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7037,7 +7843,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[106] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7050,7 +7856,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{106} } func (x *ListActorsResponse) GetActors() []*Actor { @@ -7157,7 +7963,7 @@ type Worker struct { func (x *Worker) Reset() { *x = Worker{} - mi := &file_ateapi_proto_msgTypes[98] + mi := &file_ateapi_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7169,7 +7975,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[107] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7182,7 +7988,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{107} } func (x *Worker) GetMetadata() *ResourceMetadata { @@ -7311,7 +8117,7 @@ type WorkerStatus struct { func (x *WorkerStatus) Reset() { *x = WorkerStatus{} - mi := &file_ateapi_proto_msgTypes[99] + mi := &file_ateapi_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7323,7 +8129,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[108] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7336,7 +8142,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{108} } func (x *WorkerStatus) GetState() WorkerState { @@ -7403,7 +8209,7 @@ type SandboxRuntime struct { func (x *SandboxRuntime) Reset() { *x = SandboxRuntime{} - mi := &file_ateapi_proto_msgTypes[100] + mi := &file_ateapi_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7415,7 +8221,7 @@ func (x *SandboxRuntime) String() string { func (*SandboxRuntime) ProtoMessage() {} func (x *SandboxRuntime) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[100] + mi := &file_ateapi_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7428,7 +8234,7 @@ func (x *SandboxRuntime) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxRuntime.ProtoReflect.Descriptor instead. func (*SandboxRuntime) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{100} + return file_ateapi_proto_rawDescGZIP(), []int{109} } func (x *SandboxRuntime) GetSandboxClass() string { @@ -7476,7 +8282,7 @@ type VersionedSandboxCompat struct { func (x *VersionedSandboxCompat) Reset() { *x = VersionedSandboxCompat{} - mi := &file_ateapi_proto_msgTypes[101] + mi := &file_ateapi_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7488,7 +8294,7 @@ func (x *VersionedSandboxCompat) String() string { func (*VersionedSandboxCompat) ProtoMessage() {} func (x *VersionedSandboxCompat) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[101] + mi := &file_ateapi_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7501,7 +8307,7 @@ func (x *VersionedSandboxCompat) ProtoReflect() protoreflect.Message { // Deprecated: Use VersionedSandboxCompat.ProtoReflect.Descriptor instead. func (*VersionedSandboxCompat) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{101} + return file_ateapi_proto_rawDescGZIP(), []int{110} } func (x *VersionedSandboxCompat) GetSchemaVersion() string { @@ -7537,7 +8343,7 @@ type AttributeEntry struct { func (x *AttributeEntry) Reset() { *x = AttributeEntry{} - mi := &file_ateapi_proto_msgTypes[102] + mi := &file_ateapi_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7549,7 +8355,7 @@ func (x *AttributeEntry) String() string { func (*AttributeEntry) ProtoMessage() {} func (x *AttributeEntry) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[102] + mi := &file_ateapi_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7562,7 +8368,7 @@ func (x *AttributeEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use AttributeEntry.ProtoReflect.Descriptor instead. func (*AttributeEntry) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{102} + return file_ateapi_proto_rawDescGZIP(), []int{111} } func (x *AttributeEntry) GetKey() string { @@ -7601,7 +8407,7 @@ type WorkerResources struct { func (x *WorkerResources) Reset() { *x = WorkerResources{} - mi := &file_ateapi_proto_msgTypes[103] + mi := &file_ateapi_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7613,7 +8419,7 @@ func (x *WorkerResources) String() string { func (*WorkerResources) ProtoMessage() {} func (x *WorkerResources) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[103] + mi := &file_ateapi_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7626,7 +8432,7 @@ func (x *WorkerResources) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkerResources.ProtoReflect.Descriptor instead. func (*WorkerResources) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{103} + return file_ateapi_proto_rawDescGZIP(), []int{112} } func (x *WorkerResources) GetResources() *Resources { @@ -7679,7 +8485,7 @@ type ActorAssignment struct { func (x *ActorAssignment) Reset() { *x = ActorAssignment{} - mi := &file_ateapi_proto_msgTypes[104] + mi := &file_ateapi_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7691,7 +8497,7 @@ func (x *ActorAssignment) String() string { func (*ActorAssignment) ProtoMessage() {} func (x *ActorAssignment) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[104] + mi := &file_ateapi_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7704,7 +8510,7 @@ func (x *ActorAssignment) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorAssignment.ProtoReflect.Descriptor instead. func (*ActorAssignment) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{104} + return file_ateapi_proto_rawDescGZIP(), []int{113} } func (x *ActorAssignment) GetMetadata() *ResourceMetadata { @@ -7775,7 +8581,7 @@ type RegisterWorkerRequest struct { func (x *RegisterWorkerRequest) Reset() { *x = RegisterWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[105] + mi := &file_ateapi_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7787,7 +8593,7 @@ func (x *RegisterWorkerRequest) String() string { func (*RegisterWorkerRequest) ProtoMessage() {} func (x *RegisterWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[105] + mi := &file_ateapi_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7800,7 +8606,7 @@ func (x *RegisterWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterWorkerRequest.ProtoReflect.Descriptor instead. func (*RegisterWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{105} + return file_ateapi_proto_rawDescGZIP(), []int{114} } func (x *RegisterWorkerRequest) GetWorker() *ObjectRef { @@ -7841,7 +8647,7 @@ type RegisterWorkerResponse struct { func (x *RegisterWorkerResponse) Reset() { *x = RegisterWorkerResponse{} - mi := &file_ateapi_proto_msgTypes[106] + mi := &file_ateapi_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7853,7 +8659,7 @@ func (x *RegisterWorkerResponse) String() string { func (*RegisterWorkerResponse) ProtoMessage() {} func (x *RegisterWorkerResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[106] + mi := &file_ateapi_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7866,7 +8672,7 @@ func (x *RegisterWorkerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterWorkerResponse.ProtoReflect.Descriptor instead. func (*RegisterWorkerResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{106} + return file_ateapi_proto_rawDescGZIP(), []int{115} } func (x *RegisterWorkerResponse) GetWorker() *Worker { @@ -7905,7 +8711,7 @@ type MintAteomActorCertificateRequest struct { func (x *MintAteomActorCertificateRequest) Reset() { *x = MintAteomActorCertificateRequest{} - mi := &file_ateapi_proto_msgTypes[107] + mi := &file_ateapi_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7917,7 +8723,7 @@ func (x *MintAteomActorCertificateRequest) String() string { func (*MintAteomActorCertificateRequest) ProtoMessage() {} func (x *MintAteomActorCertificateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[107] + mi := &file_ateapi_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7930,7 +8736,7 @@ func (x *MintAteomActorCertificateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintAteomActorCertificateRequest.ProtoReflect.Descriptor instead. func (*MintAteomActorCertificateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{107} + return file_ateapi_proto_rawDescGZIP(), []int{116} } func (x *MintAteomActorCertificateRequest) GetActor() *ObjectRef { @@ -7967,7 +8773,7 @@ type MintAteomActorCertificateResponse struct { func (x *MintAteomActorCertificateResponse) Reset() { *x = MintAteomActorCertificateResponse{} - mi := &file_ateapi_proto_msgTypes[108] + mi := &file_ateapi_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7979,7 +8785,7 @@ func (x *MintAteomActorCertificateResponse) String() string { func (*MintAteomActorCertificateResponse) ProtoMessage() {} func (x *MintAteomActorCertificateResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[108] + mi := &file_ateapi_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7992,7 +8798,7 @@ func (x *MintAteomActorCertificateResponse) ProtoReflect() protoreflect.Message // Deprecated: Use MintAteomActorCertificateResponse.ProtoReflect.Descriptor instead. func (*MintAteomActorCertificateResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{108} + return file_ateapi_proto_rawDescGZIP(), []int{117} } func (x *MintAteomActorCertificateResponse) GetActorCertificates() [][]byte { @@ -8030,7 +8836,7 @@ type RequestActorSuspendRequest struct { func (x *RequestActorSuspendRequest) Reset() { *x = RequestActorSuspendRequest{} - mi := &file_ateapi_proto_msgTypes[109] + mi := &file_ateapi_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8042,7 +8848,7 @@ func (x *RequestActorSuspendRequest) String() string { func (*RequestActorSuspendRequest) ProtoMessage() {} func (x *RequestActorSuspendRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[109] + mi := &file_ateapi_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8055,7 +8861,7 @@ func (x *RequestActorSuspendRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestActorSuspendRequest.ProtoReflect.Descriptor instead. func (*RequestActorSuspendRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{109} + return file_ateapi_proto_rawDescGZIP(), []int{118} } func (x *RequestActorSuspendRequest) GetWorker() *ObjectRef { @@ -8089,7 +8895,7 @@ type RequestActorSuspendResponse struct { func (x *RequestActorSuspendResponse) Reset() { *x = RequestActorSuspendResponse{} - mi := &file_ateapi_proto_msgTypes[110] + mi := &file_ateapi_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8101,7 +8907,7 @@ func (x *RequestActorSuspendResponse) String() string { func (*RequestActorSuspendResponse) ProtoMessage() {} func (x *RequestActorSuspendResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[110] + mi := &file_ateapi_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8114,7 +8920,7 @@ func (x *RequestActorSuspendResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestActorSuspendResponse.ProtoReflect.Descriptor instead. func (*RequestActorSuspendResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{110} + return file_ateapi_proto_rawDescGZIP(), []int{119} } func (x *RequestActorSuspendResponse) GetActor() *Actor { @@ -8149,7 +8955,7 @@ type AccessPolicy struct { func (x *AccessPolicy) Reset() { *x = AccessPolicy{} - mi := &file_ateapi_proto_msgTypes[111] + mi := &file_ateapi_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8161,7 +8967,7 @@ func (x *AccessPolicy) String() string { func (*AccessPolicy) ProtoMessage() {} func (x *AccessPolicy) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[111] + mi := &file_ateapi_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8174,7 +8980,7 @@ func (x *AccessPolicy) ProtoReflect() protoreflect.Message { // Deprecated: Use AccessPolicy.ProtoReflect.Descriptor instead. func (*AccessPolicy) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{111} + return file_ateapi_proto_rawDescGZIP(), []int{120} } func (x *AccessPolicy) GetMetadata() *ResourceMetadata { @@ -8216,7 +9022,7 @@ type Binding struct { func (x *Binding) Reset() { *x = Binding{} - mi := &file_ateapi_proto_msgTypes[112] + mi := &file_ateapi_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8228,7 +9034,7 @@ func (x *Binding) String() string { func (*Binding) ProtoMessage() {} func (x *Binding) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[112] + mi := &file_ateapi_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8241,7 +9047,7 @@ func (x *Binding) ProtoReflect() protoreflect.Message { // Deprecated: Use Binding.ProtoReflect.Descriptor instead. func (*Binding) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{112} + return file_ateapi_proto_rawDescGZIP(), []int{121} } func (x *Binding) GetRole() string { @@ -8273,7 +9079,7 @@ type GetGlobalAccessPolicyRequest struct { func (x *GetGlobalAccessPolicyRequest) Reset() { *x = GetGlobalAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[113] + mi := &file_ateapi_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8285,7 +9091,7 @@ func (x *GetGlobalAccessPolicyRequest) String() string { func (*GetGlobalAccessPolicyRequest) ProtoMessage() {} func (x *GetGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[113] + mi := &file_ateapi_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8298,7 +9104,7 @@ func (x *GetGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGlobalAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*GetGlobalAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{113} + return file_ateapi_proto_rawDescGZIP(), []int{122} } func (x *GetGlobalAccessPolicyRequest) GetName() string { @@ -8322,7 +9128,7 @@ type CreateGlobalAccessPolicyRequest struct { func (x *CreateGlobalAccessPolicyRequest) Reset() { *x = CreateGlobalAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[114] + mi := &file_ateapi_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8334,7 +9140,7 @@ func (x *CreateGlobalAccessPolicyRequest) String() string { func (*CreateGlobalAccessPolicyRequest) ProtoMessage() {} func (x *CreateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[114] + mi := &file_ateapi_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8347,7 +9153,7 @@ func (x *CreateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateGlobalAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*CreateGlobalAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{114} + return file_ateapi_proto_rawDescGZIP(), []int{123} } func (x *CreateGlobalAccessPolicyRequest) GetAccessPolicy() *AccessPolicy { @@ -8371,7 +9177,7 @@ type UpdateGlobalAccessPolicyRequest struct { func (x *UpdateGlobalAccessPolicyRequest) Reset() { *x = UpdateGlobalAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[115] + mi := &file_ateapi_proto_msgTypes[124] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8383,7 +9189,7 @@ func (x *UpdateGlobalAccessPolicyRequest) String() string { func (*UpdateGlobalAccessPolicyRequest) ProtoMessage() {} func (x *UpdateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[115] + mi := &file_ateapi_proto_msgTypes[124] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8396,7 +9202,7 @@ func (x *UpdateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateGlobalAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*UpdateGlobalAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{115} + return file_ateapi_proto_rawDescGZIP(), []int{124} } func (x *UpdateGlobalAccessPolicyRequest) GetAccessPolicy() *AccessPolicy { @@ -8426,7 +9232,7 @@ type GetAtespaceAccessPolicyRequest struct { func (x *GetAtespaceAccessPolicyRequest) Reset() { *x = GetAtespaceAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[116] + mi := &file_ateapi_proto_msgTypes[125] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8438,7 +9244,7 @@ func (x *GetAtespaceAccessPolicyRequest) String() string { func (*GetAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *GetAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[116] + mi := &file_ateapi_proto_msgTypes[125] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8451,7 +9257,7 @@ func (x *GetAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*GetAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{116} + return file_ateapi_proto_rawDescGZIP(), []int{125} } func (x *GetAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -8487,7 +9293,7 @@ type CreateAtespaceAccessPolicyRequest struct { func (x *CreateAtespaceAccessPolicyRequest) Reset() { *x = CreateAtespaceAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[117] + mi := &file_ateapi_proto_msgTypes[126] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8499,7 +9305,7 @@ func (x *CreateAtespaceAccessPolicyRequest) String() string { func (*CreateAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *CreateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[117] + mi := &file_ateapi_proto_msgTypes[126] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8512,7 +9318,7 @@ func (x *CreateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message // Deprecated: Use CreateAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*CreateAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{117} + return file_ateapi_proto_rawDescGZIP(), []int{126} } func (x *CreateAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -8548,7 +9354,7 @@ type UpdateAtespaceAccessPolicyRequest struct { func (x *UpdateAtespaceAccessPolicyRequest) Reset() { *x = UpdateAtespaceAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[118] + mi := &file_ateapi_proto_msgTypes[127] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8560,7 +9366,7 @@ func (x *UpdateAtespaceAccessPolicyRequest) String() string { func (*UpdateAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *UpdateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[118] + mi := &file_ateapi_proto_msgTypes[127] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8573,7 +9379,7 @@ func (x *UpdateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message // Deprecated: Use UpdateAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*UpdateAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{118} + return file_ateapi_proto_rawDescGZIP(), []int{127} } func (x *UpdateAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -8614,7 +9420,7 @@ type DeleteAtespaceAccessPolicyRequest struct { func (x *DeleteAtespaceAccessPolicyRequest) Reset() { *x = DeleteAtespaceAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[119] + mi := &file_ateapi_proto_msgTypes[128] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8626,7 +9432,7 @@ func (x *DeleteAtespaceAccessPolicyRequest) String() string { func (*DeleteAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *DeleteAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[119] + mi := &file_ateapi_proto_msgTypes[128] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8639,7 +9445,7 @@ func (x *DeleteAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message // Deprecated: Use DeleteAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*DeleteAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{119} + return file_ateapi_proto_rawDescGZIP(), []int{128} } func (x *DeleteAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -8785,7 +9591,30 @@ const file_ateapi_proto_rawDesc = "" + "\bmetadata\x18\x01 \x01(\v2\x18.ateapi.ResourceMetadataR\bmetadata\x12)\n" + "\x06status\x18\x02 \x01(\v2\x11.ateapi.TagStatusR\x06status\x12&\n" + "\x05scope\x18\x03 \x01(\x0e2\x10.ateapi.TagScopeR\x05scope\x124\n" + - "\fsource_actor\x18\x04 \x01(\v2\x11.ateapi.ObjectRefR\vsourceActor\"@\n" + + "\fsource_actor\x18\x04 \x01(\v2\x11.ateapi.ObjectRefR\vsourceActor\"\x85\x04\n" + + "\fSharedVolume\x124\n" + + "\bmetadata\x18\x01 \x01(\v2\x18.ateapi.ResourceMetadataR\bmetadata\x12<\n" + + "\x0edelete_trigger\x18\x02 \x01(\x0e2\x15.ateapi.DeleteTriggerR\rdeleteTrigger\x12,\n" + + "\x12storage_class_name\x18\x03 \x01(\tR\x10storageClassName\x12\x1b\n" + + "\tvolume_id\x18\x04 \x01(\tR\bvolumeId\x12\x1f\n" + + "\vvolume_type\x18\x05 \x01(\tR\n" + + "volumeType\x12N\n" + + "\x0evolume_context\x18\x06 \x03(\v2'.ateapi.SharedVolume.VolumeContextEntryR\rvolumeContext\x122\n" + + "\x06status\x18\a \x01(\v2\x1a.ateapi.SharedVolumeStatusR\x06status\x12\x1a\n" + + "\bcapacity\x18\b \x01(\tR\bcapacity\x123\n" + + "\vaccess_mode\x18\t \x01(\x0e2\x12.ateapi.AccessModeR\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\"k\n" + + "\x12SharedVolumeStatus\x12/\n" + + "\x05state\x18\x01 \x01(\x0e2\x19.ateapi.SharedVolumeStateR\x05state\x12$\n" + + "\x04refs\x18\x02 \x03(\v2\x10.ateapi.ActorRefR\x04refs\"^\n" + + "\bActorRef\x12\x1b\n" + + "\tactor_uid\x18\x01 \x01(\tR\bactorUid\x12\x1d\n" + + "\n" + + "actor_name\x18\x02 \x01(\tR\tactorName\x12\x16\n" + + "\x06active\x18\x03 \x01(\bR\x06active\"@\n" + "\bAtespace\x124\n" + "\bmetadata\x18\x01 \x01(\v2\x18.ateapi.ResourceMetadataR\bmetadata\";\n" + "\tObjectRef\x12\x1a\n" + @@ -8980,6 +9809,23 @@ const file_ateapi_proto_rawDesc = "" + "\x03tag\x18\x01 \x01(\v2\v.ateapi.TagR\x03tag\"h\n" + "\x10DeleteTagRequest\x12#\n" + "\x03tag\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\x03tag\x12/\n" + + "\aoptions\x18\x02 \x01(\v2\x15.ateapi.DeleteOptionsR\aoptions\"V\n" + + "\x19CreateSharedVolumeRequest\x129\n" + + "\rshared_volume\x18\x01 \x01(\v2\x14.ateapi.SharedVolumeR\fsharedVolume\"P\n" + + "\x16GetSharedVolumeRequest\x126\n" + + "\rshared_volume\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\fsharedVolume\"r\n" + + "\x18ListSharedVolumesRequest\x12\x1a\n" + + "\batespace\x18\x01 \x01(\tR\batespace\x12\x1b\n" + + "\tpage_size\x18\x02 \x01(\x05R\bpageSize\x12\x1d\n" + + "\n" + + "page_token\x18\x03 \x01(\tR\tpageToken\"\x80\x01\n" + + "\x19ListSharedVolumesResponse\x12;\n" + + "\x0eshared_volumes\x18\x01 \x03(\v2\x14.ateapi.SharedVolumeR\rsharedVolumes\x12&\n" + + "\x0fnext_page_token\x18\x02 \x01(\tR\rnextPageToken\"V\n" + + "\x19UpdateSharedVolumeRequest\x129\n" + + "\rshared_volume\x18\x01 \x01(\v2\x14.ateapi.SharedVolumeR\fsharedVolume\"\x84\x01\n" + + "\x19DeleteSharedVolumeRequest\x126\n" + + "\rshared_volume\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\fsharedVolume\x12/\n" + "\aoptions\x18\x02 \x01(\v2\x15.ateapi.DeleteOptionsR\aoptions\";\n" + "\rDeleteOptions\x12\x18\n" + "\aversion\x18\x01 \x01(\x03R\aversion\x12\x10\n" + @@ -9136,7 +9982,20 @@ const file_ateapi_proto_rawDesc = "" + "\x12ACTOR_STATE_PAUSED\x10\x06\x12\x17\n" + "\x13ACTOR_STATE_CRASHED\x10\a\x12\x18\n" + "\x14ACTOR_STATE_DELETING\x10\b\x12\x19\n" + - "\x15ACTOR_STATE_REVERTING\x10\t*b\n" + + "\x15ACTOR_STATE_REVERTING\x10\t*i\n" + + "\rDeleteTrigger\x12\x1e\n" + + "\x1aDELETE_TRIGGER_UNSPECIFIED\x10\x00\x12\x19\n" + + "\x15DELETE_TRIGGER_MANUAL\x10\x01\x12\x1d\n" + + "\x19DELETE_TRIGGER_LAST_ACTOR\x10\x02*k\n" + + "\n" + + "AccessMode\x12\x1b\n" + + "\x17ACCESS_MODE_UNSPECIFIED\x10\x00\x12\x1f\n" + + "\x1bACCESS_MODE_READ_WRITE_ONCE\x10\x01\x12\x1f\n" + + "\x1bACCESS_MODE_READ_WRITE_MANY\x10\x02*x\n" + + "\x11SharedVolumeState\x12#\n" + + "\x1fSHARED_VOLUME_STATE_UNSPECIFIED\x10\x00\x12\x1f\n" + + "\x1bSHARED_VOLUME_STATE_PENDING\x10\x01\x12\x1d\n" + + "\x19SHARED_VOLUME_STATE_READY\x10\x02*b\n" + "\fSandboxClass\x12\x1d\n" + "\x19SANDBOX_CLASS_UNSPECIFIED\x10\x00\x12\x18\n" + "\x14SANDBOX_CLASS_GVISOR\x10\x01\x12\x19\n" + @@ -9153,7 +10012,7 @@ const file_ateapi_proto_rawDesc = "" + "\vWorkerState\x12\x1c\n" + "\x18WORKER_STATE_UNSPECIFIED\x10\x00\x12\x17\n" + "\x13WORKER_STATE_ACTIVE\x10\x01\x12\x19\n" + - "\x15WORKER_STATE_DRAINING\x10\x022\x8b\x19\n" + + "\x15WORKER_STATE_DRAINING\x10\x022\xa5\x1c\n" + "\aControl\x124\n" + "\bGetActor\x12\x17.ateapi.GetActorRequest\x1a\r.ateapi.Actor\"\x00\x12:\n" + "\vCreateActor\x12\x1a.ateapi.CreateActorRequest\x1a\r.ateapi.Actor\"\x00\x12:\n" + @@ -9174,7 +10033,12 @@ const file_ateapi_proto_rawDesc = "" + "\x06GetTag\x12\x15.ateapi.GetTagRequest\x1a\v.ateapi.Tag\"\x00\x12?\n" + "\bListTags\x12\x17.ateapi.ListTagsRequest\x1a\x18.ateapi.ListTagsResponse\"\x00\x124\n" + "\tUpdateTag\x12\x18.ateapi.UpdateTagRequest\x1a\v.ateapi.Tag\"\x00\x124\n" + - "\tDeleteTag\x12\x18.ateapi.DeleteTagRequest\x1a\v.ateapi.Tag\"\x00\x12H\n" + + "\tDeleteTag\x12\x18.ateapi.DeleteTagRequest\x1a\v.ateapi.Tag\"\x00\x12O\n" + + "\x12CreateSharedVolume\x12!.ateapi.CreateSharedVolumeRequest\x1a\x14.ateapi.SharedVolume\"\x00\x12I\n" + + "\x0fGetSharedVolume\x12\x1e.ateapi.GetSharedVolumeRequest\x1a\x14.ateapi.SharedVolume\"\x00\x12Z\n" + + "\x11ListSharedVolumes\x12 .ateapi.ListSharedVolumesRequest\x1a!.ateapi.ListSharedVolumesResponse\"\x00\x12O\n" + + "\x12UpdateSharedVolume\x12!.ateapi.UpdateSharedVolumeRequest\x1a\x14.ateapi.SharedVolume\"\x00\x12O\n" + + "\x12DeleteSharedVolume\x12!.ateapi.DeleteSharedVolumeRequest\x1a\x14.ateapi.SharedVolume\"\x00\x12H\n" + "\vListWorkers\x12\x1a.ateapi.ListWorkersRequest\x1a\x1b.ateapi.ListWorkersResponse\"\x00\x127\n" + "\tGetWorker\x12\x18.ateapi.GetWorkerRequest\x1a\x0e.ateapi.Worker\"\x00\x12=\n" + "\fCreateWorker\x12\x1b.ateapi.CreateWorkerRequest\x1a\x0e.ateapi.Worker\"\x00\x12=\n" + @@ -9216,398 +10080,434 @@ func file_ateapi_proto_rawDescGZIP() []byte { return file_ateapi_proto_rawDescData } -var file_ateapi_proto_enumTypes = make([]protoimpl.EnumInfo, 10) -var file_ateapi_proto_msgTypes = make([]protoimpl.MessageInfo, 123) +var file_ateapi_proto_enumTypes = make([]protoimpl.EnumInfo, 13) +var file_ateapi_proto_msgTypes = make([]protoimpl.MessageInfo, 133) var file_ateapi_proto_goTypes = []any{ (SnapshotOwner)(0), // 0: ateapi.SnapshotOwner (SnapshotStorageStatus)(0), // 1: ateapi.SnapshotStorageStatus (SnapshotFidelity)(0), // 2: ateapi.SnapshotFidelity (TagScope)(0), // 3: ateapi.TagScope (ActorState)(0), // 4: ateapi.ActorState - (SandboxClass)(0), // 5: ateapi.SandboxClass - (GoldenSnapshotMode)(0), // 6: ateapi.GoldenSnapshotMode - (ActorMetadataField)(0), // 7: ateapi.ActorMetadataField - (WorkerState)(0), // 8: ateapi.WorkerState - (ExternalVolumeRef_Status)(0), // 9: ateapi.ExternalVolumeRef.Status - (*ObjectSnapshot)(nil), // 10: ateapi.ObjectSnapshot - (*SnapshotStorage)(nil), // 11: ateapi.SnapshotStorage - (*Snapshot)(nil), // 12: ateapi.Snapshot - (*Selector)(nil), // 13: ateapi.Selector - (*ResourceMetadata)(nil), // 14: ateapi.ResourceMetadata - (*ExternalVolumeRef)(nil), // 15: ateapi.ExternalVolumeRef - (*Actor)(nil), // 16: ateapi.Actor - (*EgressPolicy)(nil), // 17: ateapi.EgressPolicy - (*EgressRule)(nil), // 18: ateapi.EgressRule - (*HttpRule)(nil), // 19: ateapi.HttpRule - (*HttpsRule)(nil), // 20: ateapi.HttpsRule - (*TlsPassthroughRule)(nil), // 21: ateapi.TlsPassthroughRule - (*Ports)(nil), // 22: ateapi.Ports - (*AllPorts)(nil), // 23: ateapi.AllPorts - (*HttpRuleEffects)(nil), // 24: ateapi.HttpRuleEffects - (*CredentialHeader)(nil), // 25: ateapi.CredentialHeader - (*ActorJwtSource)(nil), // 26: ateapi.ActorJwtSource - (*ActorStatus)(nil), // 27: ateapi.ActorStatus - (*ActorCrash)(nil), // 28: ateapi.ActorCrash - (*WorkerAssignment)(nil), // 29: ateapi.WorkerAssignment - (*TagStatus)(nil), // 30: ateapi.TagStatus - (*Tag)(nil), // 31: ateapi.Tag - (*Atespace)(nil), // 32: ateapi.Atespace - (*ObjectRef)(nil), // 33: ateapi.ObjectRef - (*ActorTemplate)(nil), // 34: ateapi.ActorTemplate - (*Resources)(nil), // 35: ateapi.Resources - (*Limits)(nil), // 36: ateapi.Limits - (*GoldenSnapshotStatus)(nil), // 37: ateapi.GoldenSnapshotStatus - (*ActorTemplateStatus)(nil), // 38: ateapi.ActorTemplateStatus - (*SandboxConfig)(nil), // 39: ateapi.SandboxConfig - (*SnapshotConfig)(nil), // 40: ateapi.SnapshotConfig - (*GoldenSnapshotConfig)(nil), // 41: ateapi.GoldenSnapshotConfig - (*Container)(nil), // 42: ateapi.Container - (*SecurityContext)(nil), // 43: ateapi.SecurityContext - (*Capabilities)(nil), // 44: ateapi.Capabilities - (*EnvVar)(nil), // 45: ateapi.EnvVar - (*ContainerWakeupProbe)(nil), // 46: ateapi.ContainerWakeupProbe - (*HttpGetAction)(nil), // 47: ateapi.HttpGetAction - (*Volume)(nil), // 48: ateapi.Volume - (*ExternalVolumeSource)(nil), // 49: ateapi.ExternalVolumeSource - (*ImageVolumeSource)(nil), // 50: ateapi.ImageVolumeSource - (*DurableDirVolumeSource)(nil), // 51: ateapi.DurableDirVolumeSource - (*ExternalVolumeTemplate)(nil), // 52: ateapi.ExternalVolumeTemplate - (*SystemInfoVolumeSource)(nil), // 53: ateapi.SystemInfoVolumeSource - (*SystemInfoDataSource)(nil), // 54: ateapi.SystemInfoDataSource - (*ActorMetadataDataSource)(nil), // 55: ateapi.ActorMetadataDataSource - (*ActorMetadataItem)(nil), // 56: ateapi.ActorMetadataItem - (*TrustBundleDataSource)(nil), // 57: ateapi.TrustBundleDataSource - (*VolumeMount)(nil), // 58: ateapi.VolumeMount - (*CreateAtespaceRequest)(nil), // 59: ateapi.CreateAtespaceRequest - (*GetAtespaceRequest)(nil), // 60: ateapi.GetAtespaceRequest - (*ListAtespacesRequest)(nil), // 61: ateapi.ListAtespacesRequest - (*ListAtespacesResponse)(nil), // 62: ateapi.ListAtespacesResponse - (*DeleteAtespaceRequest)(nil), // 63: ateapi.DeleteAtespaceRequest - (*CreateActorTemplateRequest)(nil), // 64: ateapi.CreateActorTemplateRequest - (*GetActorTemplateRequest)(nil), // 65: ateapi.GetActorTemplateRequest - (*ListActorTemplatesRequest)(nil), // 66: ateapi.ListActorTemplatesRequest - (*ListActorTemplatesResponse)(nil), // 67: ateapi.ListActorTemplatesResponse - (*DeleteActorTemplateRequest)(nil), // 68: ateapi.DeleteActorTemplateRequest - (*GetActorRequest)(nil), // 69: ateapi.GetActorRequest - (*CreateActorRequest)(nil), // 70: ateapi.CreateActorRequest - (*UpdateActorRequest)(nil), // 71: ateapi.UpdateActorRequest - (*SuspendActorRequest)(nil), // 72: ateapi.SuspendActorRequest - (*SuspendActorResponse)(nil), // 73: ateapi.SuspendActorResponse - (*PauseActorRequest)(nil), // 74: ateapi.PauseActorRequest - (*PauseActorResponse)(nil), // 75: ateapi.PauseActorResponse - (*ResumeActorRequest)(nil), // 76: ateapi.ResumeActorRequest - (*ResumeActorResponse)(nil), // 77: ateapi.ResumeActorResponse - (*RevertActorRequest)(nil), // 78: ateapi.RevertActorRequest - (*RevertActorResponse)(nil), // 79: ateapi.RevertActorResponse - (*DeleteActorRequest)(nil), // 80: ateapi.DeleteActorRequest - (*GetActorEgressPolicyRequest)(nil), // 81: ateapi.GetActorEgressPolicyRequest - (*CreateActorEgressPolicyRequest)(nil), // 82: ateapi.CreateActorEgressPolicyRequest - (*UpdateActorEgressPolicyRequest)(nil), // 83: ateapi.UpdateActorEgressPolicyRequest - (*DeleteActorEgressPolicyRequest)(nil), // 84: ateapi.DeleteActorEgressPolicyRequest - (*GetTagRequest)(nil), // 85: ateapi.GetTagRequest - (*MintActorJwtRequest)(nil), // 86: ateapi.MintActorJwtRequest - (*MintActorJwtResponse)(nil), // 87: ateapi.MintActorJwtResponse - (*MintActorCertificateRequest)(nil), // 88: ateapi.MintActorCertificateRequest - (*MintActorCertificateResponse)(nil), // 89: ateapi.MintActorCertificateResponse - (*ListTagsRequest)(nil), // 90: ateapi.ListTagsRequest - (*ListTagsResponse)(nil), // 91: ateapi.ListTagsResponse - (*CreateTagRequest)(nil), // 92: ateapi.CreateTagRequest - (*UpdateTagRequest)(nil), // 93: ateapi.UpdateTagRequest - (*DeleteTagRequest)(nil), // 94: ateapi.DeleteTagRequest - (*DeleteOptions)(nil), // 95: ateapi.DeleteOptions - (*ListWorkerActorAssignmentsRequest)(nil), // 96: ateapi.ListWorkerActorAssignmentsRequest - (*ListWorkerActorAssignmentsResponse)(nil), // 97: ateapi.ListWorkerActorAssignmentsResponse - (*ListWorkersRequest)(nil), // 98: ateapi.ListWorkersRequest - (*ListWorkersResponse)(nil), // 99: ateapi.ListWorkersResponse - (*GetWorkerRequest)(nil), // 100: ateapi.GetWorkerRequest - (*CreateWorkerRequest)(nil), // 101: ateapi.CreateWorkerRequest - (*UpdateWorkerRequest)(nil), // 102: ateapi.UpdateWorkerRequest - (*DeleteWorkerRequest)(nil), // 103: ateapi.DeleteWorkerRequest - (*DrainWorkerRequest)(nil), // 104: ateapi.DrainWorkerRequest - (*DrainWorkerResponse)(nil), // 105: ateapi.DrainWorkerResponse - (*ListActorsRequest)(nil), // 106: ateapi.ListActorsRequest - (*ListActorsResponse)(nil), // 107: ateapi.ListActorsResponse - (*Worker)(nil), // 108: ateapi.Worker - (*WorkerStatus)(nil), // 109: ateapi.WorkerStatus - (*SandboxRuntime)(nil), // 110: ateapi.SandboxRuntime - (*VersionedSandboxCompat)(nil), // 111: ateapi.VersionedSandboxCompat - (*AttributeEntry)(nil), // 112: ateapi.AttributeEntry - (*WorkerResources)(nil), // 113: ateapi.WorkerResources - (*ActorAssignment)(nil), // 114: ateapi.ActorAssignment - (*RegisterWorkerRequest)(nil), // 115: ateapi.RegisterWorkerRequest - (*RegisterWorkerResponse)(nil), // 116: ateapi.RegisterWorkerResponse - (*MintAteomActorCertificateRequest)(nil), // 117: ateapi.MintAteomActorCertificateRequest - (*MintAteomActorCertificateResponse)(nil), // 118: ateapi.MintAteomActorCertificateResponse - (*RequestActorSuspendRequest)(nil), // 119: ateapi.RequestActorSuspendRequest - (*RequestActorSuspendResponse)(nil), // 120: ateapi.RequestActorSuspendResponse - (*AccessPolicy)(nil), // 121: ateapi.AccessPolicy - (*Binding)(nil), // 122: ateapi.Binding - (*GetGlobalAccessPolicyRequest)(nil), // 123: ateapi.GetGlobalAccessPolicyRequest - (*CreateGlobalAccessPolicyRequest)(nil), // 124: ateapi.CreateGlobalAccessPolicyRequest - (*UpdateGlobalAccessPolicyRequest)(nil), // 125: ateapi.UpdateGlobalAccessPolicyRequest - (*GetAtespaceAccessPolicyRequest)(nil), // 126: ateapi.GetAtespaceAccessPolicyRequest - (*CreateAtespaceAccessPolicyRequest)(nil), // 127: ateapi.CreateAtespaceAccessPolicyRequest - (*UpdateAtespaceAccessPolicyRequest)(nil), // 128: ateapi.UpdateAtespaceAccessPolicyRequest - (*DeleteAtespaceAccessPolicyRequest)(nil), // 129: ateapi.DeleteAtespaceAccessPolicyRequest - nil, // 130: ateapi.Selector.MatchLabelsEntry - nil, // 131: ateapi.ExternalVolumeRef.VolumeContextEntry - nil, // 132: ateapi.Worker.LabelsEntry - (*timestamppb.Timestamp)(nil), // 133: google.protobuf.Timestamp + (DeleteTrigger)(0), // 5: ateapi.DeleteTrigger + (AccessMode)(0), // 6: ateapi.AccessMode + (SharedVolumeState)(0), // 7: ateapi.SharedVolumeState + (SandboxClass)(0), // 8: ateapi.SandboxClass + (GoldenSnapshotMode)(0), // 9: ateapi.GoldenSnapshotMode + (ActorMetadataField)(0), // 10: ateapi.ActorMetadataField + (WorkerState)(0), // 11: ateapi.WorkerState + (ExternalVolumeRef_Status)(0), // 12: ateapi.ExternalVolumeRef.Status + (*ObjectSnapshot)(nil), // 13: ateapi.ObjectSnapshot + (*SnapshotStorage)(nil), // 14: ateapi.SnapshotStorage + (*Snapshot)(nil), // 15: ateapi.Snapshot + (*Selector)(nil), // 16: ateapi.Selector + (*ResourceMetadata)(nil), // 17: ateapi.ResourceMetadata + (*ExternalVolumeRef)(nil), // 18: ateapi.ExternalVolumeRef + (*Actor)(nil), // 19: ateapi.Actor + (*EgressPolicy)(nil), // 20: ateapi.EgressPolicy + (*EgressRule)(nil), // 21: ateapi.EgressRule + (*HttpRule)(nil), // 22: ateapi.HttpRule + (*HttpsRule)(nil), // 23: ateapi.HttpsRule + (*TlsPassthroughRule)(nil), // 24: ateapi.TlsPassthroughRule + (*Ports)(nil), // 25: ateapi.Ports + (*AllPorts)(nil), // 26: ateapi.AllPorts + (*HttpRuleEffects)(nil), // 27: ateapi.HttpRuleEffects + (*CredentialHeader)(nil), // 28: ateapi.CredentialHeader + (*ActorJwtSource)(nil), // 29: ateapi.ActorJwtSource + (*ActorStatus)(nil), // 30: ateapi.ActorStatus + (*ActorCrash)(nil), // 31: ateapi.ActorCrash + (*WorkerAssignment)(nil), // 32: ateapi.WorkerAssignment + (*TagStatus)(nil), // 33: ateapi.TagStatus + (*Tag)(nil), // 34: ateapi.Tag + (*SharedVolume)(nil), // 35: ateapi.SharedVolume + (*SharedVolumeStatus)(nil), // 36: ateapi.SharedVolumeStatus + (*ActorRef)(nil), // 37: ateapi.ActorRef + (*Atespace)(nil), // 38: ateapi.Atespace + (*ObjectRef)(nil), // 39: ateapi.ObjectRef + (*ActorTemplate)(nil), // 40: ateapi.ActorTemplate + (*Resources)(nil), // 41: ateapi.Resources + (*Limits)(nil), // 42: ateapi.Limits + (*GoldenSnapshotStatus)(nil), // 43: ateapi.GoldenSnapshotStatus + (*ActorTemplateStatus)(nil), // 44: ateapi.ActorTemplateStatus + (*SandboxConfig)(nil), // 45: ateapi.SandboxConfig + (*SnapshotConfig)(nil), // 46: ateapi.SnapshotConfig + (*GoldenSnapshotConfig)(nil), // 47: ateapi.GoldenSnapshotConfig + (*Container)(nil), // 48: ateapi.Container + (*SecurityContext)(nil), // 49: ateapi.SecurityContext + (*Capabilities)(nil), // 50: ateapi.Capabilities + (*EnvVar)(nil), // 51: ateapi.EnvVar + (*ContainerWakeupProbe)(nil), // 52: ateapi.ContainerWakeupProbe + (*HttpGetAction)(nil), // 53: ateapi.HttpGetAction + (*Volume)(nil), // 54: ateapi.Volume + (*ExternalVolumeSource)(nil), // 55: ateapi.ExternalVolumeSource + (*ImageVolumeSource)(nil), // 56: ateapi.ImageVolumeSource + (*DurableDirVolumeSource)(nil), // 57: ateapi.DurableDirVolumeSource + (*ExternalVolumeTemplate)(nil), // 58: ateapi.ExternalVolumeTemplate + (*SystemInfoVolumeSource)(nil), // 59: ateapi.SystemInfoVolumeSource + (*SystemInfoDataSource)(nil), // 60: ateapi.SystemInfoDataSource + (*ActorMetadataDataSource)(nil), // 61: ateapi.ActorMetadataDataSource + (*ActorMetadataItem)(nil), // 62: ateapi.ActorMetadataItem + (*TrustBundleDataSource)(nil), // 63: ateapi.TrustBundleDataSource + (*VolumeMount)(nil), // 64: ateapi.VolumeMount + (*CreateAtespaceRequest)(nil), // 65: ateapi.CreateAtespaceRequest + (*GetAtespaceRequest)(nil), // 66: ateapi.GetAtespaceRequest + (*ListAtespacesRequest)(nil), // 67: ateapi.ListAtespacesRequest + (*ListAtespacesResponse)(nil), // 68: ateapi.ListAtespacesResponse + (*DeleteAtespaceRequest)(nil), // 69: ateapi.DeleteAtespaceRequest + (*CreateActorTemplateRequest)(nil), // 70: ateapi.CreateActorTemplateRequest + (*GetActorTemplateRequest)(nil), // 71: ateapi.GetActorTemplateRequest + (*ListActorTemplatesRequest)(nil), // 72: ateapi.ListActorTemplatesRequest + (*ListActorTemplatesResponse)(nil), // 73: ateapi.ListActorTemplatesResponse + (*DeleteActorTemplateRequest)(nil), // 74: ateapi.DeleteActorTemplateRequest + (*GetActorRequest)(nil), // 75: ateapi.GetActorRequest + (*CreateActorRequest)(nil), // 76: ateapi.CreateActorRequest + (*UpdateActorRequest)(nil), // 77: ateapi.UpdateActorRequest + (*SuspendActorRequest)(nil), // 78: ateapi.SuspendActorRequest + (*SuspendActorResponse)(nil), // 79: ateapi.SuspendActorResponse + (*PauseActorRequest)(nil), // 80: ateapi.PauseActorRequest + (*PauseActorResponse)(nil), // 81: ateapi.PauseActorResponse + (*ResumeActorRequest)(nil), // 82: ateapi.ResumeActorRequest + (*ResumeActorResponse)(nil), // 83: ateapi.ResumeActorResponse + (*RevertActorRequest)(nil), // 84: ateapi.RevertActorRequest + (*RevertActorResponse)(nil), // 85: ateapi.RevertActorResponse + (*DeleteActorRequest)(nil), // 86: ateapi.DeleteActorRequest + (*GetActorEgressPolicyRequest)(nil), // 87: ateapi.GetActorEgressPolicyRequest + (*CreateActorEgressPolicyRequest)(nil), // 88: ateapi.CreateActorEgressPolicyRequest + (*UpdateActorEgressPolicyRequest)(nil), // 89: ateapi.UpdateActorEgressPolicyRequest + (*DeleteActorEgressPolicyRequest)(nil), // 90: ateapi.DeleteActorEgressPolicyRequest + (*GetTagRequest)(nil), // 91: ateapi.GetTagRequest + (*MintActorJwtRequest)(nil), // 92: ateapi.MintActorJwtRequest + (*MintActorJwtResponse)(nil), // 93: ateapi.MintActorJwtResponse + (*MintActorCertificateRequest)(nil), // 94: ateapi.MintActorCertificateRequest + (*MintActorCertificateResponse)(nil), // 95: ateapi.MintActorCertificateResponse + (*ListTagsRequest)(nil), // 96: ateapi.ListTagsRequest + (*ListTagsResponse)(nil), // 97: ateapi.ListTagsResponse + (*CreateTagRequest)(nil), // 98: ateapi.CreateTagRequest + (*UpdateTagRequest)(nil), // 99: ateapi.UpdateTagRequest + (*DeleteTagRequest)(nil), // 100: ateapi.DeleteTagRequest + (*CreateSharedVolumeRequest)(nil), // 101: ateapi.CreateSharedVolumeRequest + (*GetSharedVolumeRequest)(nil), // 102: ateapi.GetSharedVolumeRequest + (*ListSharedVolumesRequest)(nil), // 103: ateapi.ListSharedVolumesRequest + (*ListSharedVolumesResponse)(nil), // 104: ateapi.ListSharedVolumesResponse + (*UpdateSharedVolumeRequest)(nil), // 105: ateapi.UpdateSharedVolumeRequest + (*DeleteSharedVolumeRequest)(nil), // 106: ateapi.DeleteSharedVolumeRequest + (*DeleteOptions)(nil), // 107: ateapi.DeleteOptions + (*ListWorkerActorAssignmentsRequest)(nil), // 108: ateapi.ListWorkerActorAssignmentsRequest + (*ListWorkerActorAssignmentsResponse)(nil), // 109: ateapi.ListWorkerActorAssignmentsResponse + (*ListWorkersRequest)(nil), // 110: ateapi.ListWorkersRequest + (*ListWorkersResponse)(nil), // 111: ateapi.ListWorkersResponse + (*GetWorkerRequest)(nil), // 112: ateapi.GetWorkerRequest + (*CreateWorkerRequest)(nil), // 113: ateapi.CreateWorkerRequest + (*UpdateWorkerRequest)(nil), // 114: ateapi.UpdateWorkerRequest + (*DeleteWorkerRequest)(nil), // 115: ateapi.DeleteWorkerRequest + (*DrainWorkerRequest)(nil), // 116: ateapi.DrainWorkerRequest + (*DrainWorkerResponse)(nil), // 117: ateapi.DrainWorkerResponse + (*ListActorsRequest)(nil), // 118: ateapi.ListActorsRequest + (*ListActorsResponse)(nil), // 119: ateapi.ListActorsResponse + (*Worker)(nil), // 120: ateapi.Worker + (*WorkerStatus)(nil), // 121: ateapi.WorkerStatus + (*SandboxRuntime)(nil), // 122: ateapi.SandboxRuntime + (*VersionedSandboxCompat)(nil), // 123: ateapi.VersionedSandboxCompat + (*AttributeEntry)(nil), // 124: ateapi.AttributeEntry + (*WorkerResources)(nil), // 125: ateapi.WorkerResources + (*ActorAssignment)(nil), // 126: ateapi.ActorAssignment + (*RegisterWorkerRequest)(nil), // 127: ateapi.RegisterWorkerRequest + (*RegisterWorkerResponse)(nil), // 128: ateapi.RegisterWorkerResponse + (*MintAteomActorCertificateRequest)(nil), // 129: ateapi.MintAteomActorCertificateRequest + (*MintAteomActorCertificateResponse)(nil), // 130: ateapi.MintAteomActorCertificateResponse + (*RequestActorSuspendRequest)(nil), // 131: ateapi.RequestActorSuspendRequest + (*RequestActorSuspendResponse)(nil), // 132: ateapi.RequestActorSuspendResponse + (*AccessPolicy)(nil), // 133: ateapi.AccessPolicy + (*Binding)(nil), // 134: ateapi.Binding + (*GetGlobalAccessPolicyRequest)(nil), // 135: ateapi.GetGlobalAccessPolicyRequest + (*CreateGlobalAccessPolicyRequest)(nil), // 136: ateapi.CreateGlobalAccessPolicyRequest + (*UpdateGlobalAccessPolicyRequest)(nil), // 137: ateapi.UpdateGlobalAccessPolicyRequest + (*GetAtespaceAccessPolicyRequest)(nil), // 138: ateapi.GetAtespaceAccessPolicyRequest + (*CreateAtespaceAccessPolicyRequest)(nil), // 139: ateapi.CreateAtespaceAccessPolicyRequest + (*UpdateAtespaceAccessPolicyRequest)(nil), // 140: ateapi.UpdateAtespaceAccessPolicyRequest + (*DeleteAtespaceAccessPolicyRequest)(nil), // 141: ateapi.DeleteAtespaceAccessPolicyRequest + nil, // 142: ateapi.Selector.MatchLabelsEntry + nil, // 143: ateapi.ExternalVolumeRef.VolumeContextEntry + nil, // 144: ateapi.SharedVolume.VolumeContextEntry + nil, // 145: ateapi.Worker.LabelsEntry + (*timestamppb.Timestamp)(nil), // 146: google.protobuf.Timestamp } var file_ateapi_proto_depIdxs = []int32{ 1, // 0: ateapi.SnapshotStorage.status:type_name -> ateapi.SnapshotStorageStatus - 10, // 1: ateapi.SnapshotStorage.object:type_name -> ateapi.ObjectSnapshot + 13, // 1: ateapi.SnapshotStorage.object:type_name -> ateapi.ObjectSnapshot 0, // 2: ateapi.Snapshot.owner:type_name -> ateapi.SnapshotOwner 2, // 3: ateapi.Snapshot.fidelity:type_name -> ateapi.SnapshotFidelity - 11, // 4: ateapi.Snapshot.durable_snapshot:type_name -> ateapi.SnapshotStorage - 130, // 5: ateapi.Selector.match_labels:type_name -> ateapi.Selector.MatchLabelsEntry - 133, // 6: ateapi.ResourceMetadata.create_time:type_name -> google.protobuf.Timestamp - 133, // 7: ateapi.ResourceMetadata.update_time:type_name -> google.protobuf.Timestamp - 9, // 8: ateapi.ExternalVolumeRef.status:type_name -> ateapi.ExternalVolumeRef.Status - 131, // 9: ateapi.ExternalVolumeRef.volume_context:type_name -> ateapi.ExternalVolumeRef.VolumeContextEntry - 14, // 10: ateapi.Actor.metadata:type_name -> ateapi.ResourceMetadata - 33, // 11: ateapi.Actor.actor_template:type_name -> ateapi.ObjectRef - 13, // 12: ateapi.Actor.worker_selector:type_name -> ateapi.Selector - 33, // 13: ateapi.Actor.source_tag:type_name -> ateapi.ObjectRef - 27, // 14: ateapi.Actor.status:type_name -> ateapi.ActorStatus - 14, // 15: ateapi.EgressPolicy.metadata:type_name -> ateapi.ResourceMetadata - 18, // 16: ateapi.EgressPolicy.rules:type_name -> ateapi.EgressRule - 19, // 17: ateapi.EgressRule.http:type_name -> ateapi.HttpRule - 20, // 18: ateapi.EgressRule.https:type_name -> ateapi.HttpsRule - 21, // 19: ateapi.EgressRule.tls_passthrough:type_name -> ateapi.TlsPassthroughRule - 22, // 20: ateapi.HttpRule.ports:type_name -> ateapi.Ports - 24, // 21: ateapi.HttpRule.effects:type_name -> ateapi.HttpRuleEffects - 22, // 22: ateapi.HttpsRule.ports:type_name -> ateapi.Ports - 24, // 23: ateapi.HttpsRule.effects:type_name -> ateapi.HttpRuleEffects - 22, // 24: ateapi.TlsPassthroughRule.ports:type_name -> ateapi.Ports - 23, // 25: ateapi.Ports.all:type_name -> ateapi.AllPorts - 25, // 26: ateapi.HttpRuleEffects.replace_headers:type_name -> ateapi.CredentialHeader - 26, // 27: ateapi.CredentialHeader.actor_jwt:type_name -> ateapi.ActorJwtSource + 14, // 4: ateapi.Snapshot.durable_snapshot:type_name -> ateapi.SnapshotStorage + 142, // 5: ateapi.Selector.match_labels:type_name -> ateapi.Selector.MatchLabelsEntry + 146, // 6: ateapi.ResourceMetadata.create_time:type_name -> google.protobuf.Timestamp + 146, // 7: ateapi.ResourceMetadata.update_time:type_name -> google.protobuf.Timestamp + 12, // 8: ateapi.ExternalVolumeRef.status:type_name -> ateapi.ExternalVolumeRef.Status + 143, // 9: ateapi.ExternalVolumeRef.volume_context:type_name -> ateapi.ExternalVolumeRef.VolumeContextEntry + 17, // 10: ateapi.Actor.metadata:type_name -> ateapi.ResourceMetadata + 39, // 11: ateapi.Actor.actor_template:type_name -> ateapi.ObjectRef + 16, // 12: ateapi.Actor.worker_selector:type_name -> ateapi.Selector + 39, // 13: ateapi.Actor.source_tag:type_name -> ateapi.ObjectRef + 30, // 14: ateapi.Actor.status:type_name -> ateapi.ActorStatus + 17, // 15: ateapi.EgressPolicy.metadata:type_name -> ateapi.ResourceMetadata + 21, // 16: ateapi.EgressPolicy.rules:type_name -> ateapi.EgressRule + 22, // 17: ateapi.EgressRule.http:type_name -> ateapi.HttpRule + 23, // 18: ateapi.EgressRule.https:type_name -> ateapi.HttpsRule + 24, // 19: ateapi.EgressRule.tls_passthrough:type_name -> ateapi.TlsPassthroughRule + 25, // 20: ateapi.HttpRule.ports:type_name -> ateapi.Ports + 27, // 21: ateapi.HttpRule.effects:type_name -> ateapi.HttpRuleEffects + 25, // 22: ateapi.HttpsRule.ports:type_name -> ateapi.Ports + 27, // 23: ateapi.HttpsRule.effects:type_name -> ateapi.HttpRuleEffects + 25, // 24: ateapi.TlsPassthroughRule.ports:type_name -> ateapi.Ports + 26, // 25: ateapi.Ports.all:type_name -> ateapi.AllPorts + 28, // 26: ateapi.HttpRuleEffects.replace_headers:type_name -> ateapi.CredentialHeader + 29, // 27: ateapi.CredentialHeader.actor_jwt:type_name -> ateapi.ActorJwtSource 4, // 28: ateapi.ActorStatus.state:type_name -> ateapi.ActorState - 29, // 29: ateapi.ActorStatus.worker_assignment:type_name -> ateapi.WorkerAssignment - 15, // 30: ateapi.ActorStatus.external_volumes:type_name -> ateapi.ExternalVolumeRef - 28, // 31: ateapi.ActorStatus.crash:type_name -> ateapi.ActorCrash - 12, // 32: ateapi.ActorStatus.snapshots:type_name -> ateapi.Snapshot - 133, // 33: ateapi.ActorCrash.crash_time:type_name -> google.protobuf.Timestamp - 33, // 34: ateapi.WorkerAssignment.worker:type_name -> ateapi.ObjectRef - 12, // 35: ateapi.TagStatus.snapshot:type_name -> ateapi.Snapshot - 14, // 36: ateapi.Tag.metadata:type_name -> ateapi.ResourceMetadata - 30, // 37: ateapi.Tag.status:type_name -> ateapi.TagStatus + 32, // 29: ateapi.ActorStatus.worker_assignment:type_name -> ateapi.WorkerAssignment + 18, // 30: ateapi.ActorStatus.external_volumes:type_name -> ateapi.ExternalVolumeRef + 31, // 31: ateapi.ActorStatus.crash:type_name -> ateapi.ActorCrash + 15, // 32: ateapi.ActorStatus.snapshots:type_name -> ateapi.Snapshot + 146, // 33: ateapi.ActorCrash.crash_time:type_name -> google.protobuf.Timestamp + 39, // 34: ateapi.WorkerAssignment.worker:type_name -> ateapi.ObjectRef + 15, // 35: ateapi.TagStatus.snapshot:type_name -> ateapi.Snapshot + 17, // 36: ateapi.Tag.metadata:type_name -> ateapi.ResourceMetadata + 33, // 37: ateapi.Tag.status:type_name -> ateapi.TagStatus 3, // 38: ateapi.Tag.scope:type_name -> ateapi.TagScope - 33, // 39: ateapi.Tag.source_actor:type_name -> ateapi.ObjectRef - 14, // 40: ateapi.Atespace.metadata:type_name -> ateapi.ResourceMetadata - 14, // 41: ateapi.ActorTemplate.metadata:type_name -> ateapi.ResourceMetadata - 13, // 42: ateapi.ActorTemplate.worker_selector:type_name -> ateapi.Selector - 42, // 43: ateapi.ActorTemplate.containers:type_name -> ateapi.Container - 48, // 44: ateapi.ActorTemplate.volumes:type_name -> ateapi.Volume - 40, // 45: ateapi.ActorTemplate.snapshot_config:type_name -> ateapi.SnapshotConfig - 39, // 46: ateapi.ActorTemplate.sandbox_config:type_name -> ateapi.SandboxConfig - 35, // 47: ateapi.ActorTemplate.resources:type_name -> ateapi.Resources - 38, // 48: ateapi.ActorTemplate.status:type_name -> ateapi.ActorTemplateStatus - 36, // 49: ateapi.Resources.limits:type_name -> ateapi.Limits - 33, // 50: ateapi.GoldenSnapshotStatus.golden_tag:type_name -> ateapi.ObjectRef - 133, // 51: ateapi.GoldenSnapshotStatus.take_golden_snapshot_at:type_name -> google.protobuf.Timestamp - 37, // 52: ateapi.ActorTemplateStatus.golden_snapshot_status:type_name -> ateapi.GoldenSnapshotStatus - 5, // 53: ateapi.SandboxConfig.sandbox_class:type_name -> ateapi.SandboxClass - 2, // 54: ateapi.SnapshotConfig.preferred_fidelity:type_name -> ateapi.SnapshotFidelity - 41, // 55: ateapi.SnapshotConfig.golden_snapshot_config:type_name -> ateapi.GoldenSnapshotConfig - 6, // 56: ateapi.GoldenSnapshotConfig.mode:type_name -> ateapi.GoldenSnapshotMode - 45, // 57: ateapi.Container.env:type_name -> ateapi.EnvVar - 46, // 58: ateapi.Container.wakeup_probe:type_name -> ateapi.ContainerWakeupProbe - 58, // 59: ateapi.Container.volume_mounts:type_name -> ateapi.VolumeMount - 43, // 60: ateapi.Container.security_context:type_name -> ateapi.SecurityContext - 35, // 61: ateapi.Container.resources:type_name -> ateapi.Resources - 44, // 62: ateapi.SecurityContext.capabilities:type_name -> ateapi.Capabilities - 47, // 63: ateapi.ContainerWakeupProbe.http_get:type_name -> ateapi.HttpGetAction - 51, // 64: ateapi.Volume.durable_dir:type_name -> ateapi.DurableDirVolumeSource - 49, // 65: ateapi.Volume.external:type_name -> ateapi.ExternalVolumeSource - 53, // 66: ateapi.Volume.system_info:type_name -> ateapi.SystemInfoVolumeSource - 50, // 67: ateapi.Volume.image:type_name -> ateapi.ImageVolumeSource - 52, // 68: ateapi.ExternalVolumeSource.template:type_name -> ateapi.ExternalVolumeTemplate - 54, // 69: ateapi.SystemInfoVolumeSource.data_sources:type_name -> ateapi.SystemInfoDataSource - 55, // 70: ateapi.SystemInfoDataSource.actor_metadata:type_name -> ateapi.ActorMetadataDataSource - 57, // 71: ateapi.SystemInfoDataSource.trust_bundle:type_name -> ateapi.TrustBundleDataSource - 56, // 72: ateapi.ActorMetadataDataSource.items:type_name -> ateapi.ActorMetadataItem - 7, // 73: ateapi.ActorMetadataItem.field:type_name -> ateapi.ActorMetadataField - 32, // 74: ateapi.CreateAtespaceRequest.atespace:type_name -> ateapi.Atespace - 33, // 75: ateapi.GetAtespaceRequest.atespace:type_name -> ateapi.ObjectRef - 32, // 76: ateapi.ListAtespacesResponse.atespaces:type_name -> ateapi.Atespace - 33, // 77: ateapi.DeleteAtespaceRequest.atespace:type_name -> ateapi.ObjectRef - 95, // 78: ateapi.DeleteAtespaceRequest.options:type_name -> ateapi.DeleteOptions - 34, // 79: ateapi.CreateActorTemplateRequest.actor_template:type_name -> ateapi.ActorTemplate - 33, // 80: ateapi.GetActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef - 34, // 81: ateapi.ListActorTemplatesResponse.actor_templates:type_name -> ateapi.ActorTemplate - 33, // 82: ateapi.DeleteActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef - 95, // 83: ateapi.DeleteActorTemplateRequest.options:type_name -> ateapi.DeleteOptions - 33, // 84: ateapi.GetActorRequest.actor:type_name -> ateapi.ObjectRef - 16, // 85: ateapi.CreateActorRequest.actor:type_name -> ateapi.Actor - 16, // 86: ateapi.UpdateActorRequest.actor:type_name -> ateapi.Actor - 33, // 87: ateapi.SuspendActorRequest.actor:type_name -> ateapi.ObjectRef - 16, // 88: ateapi.SuspendActorResponse.actor:type_name -> ateapi.Actor - 33, // 89: ateapi.PauseActorRequest.actor:type_name -> ateapi.ObjectRef - 16, // 90: ateapi.PauseActorResponse.actor:type_name -> ateapi.Actor - 33, // 91: ateapi.ResumeActorRequest.actor:type_name -> ateapi.ObjectRef - 16, // 92: ateapi.ResumeActorResponse.actor:type_name -> ateapi.Actor - 33, // 93: ateapi.RevertActorRequest.actor:type_name -> ateapi.ObjectRef - 16, // 94: ateapi.RevertActorResponse.actor:type_name -> ateapi.Actor - 33, // 95: ateapi.DeleteActorRequest.actor:type_name -> ateapi.ObjectRef - 95, // 96: ateapi.DeleteActorRequest.options:type_name -> ateapi.DeleteOptions - 33, // 97: ateapi.GetActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 33, // 98: ateapi.CreateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 17, // 99: ateapi.CreateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy - 33, // 100: ateapi.UpdateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 17, // 101: ateapi.UpdateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy - 33, // 102: ateapi.DeleteActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 95, // 103: ateapi.DeleteActorEgressPolicyRequest.options:type_name -> ateapi.DeleteOptions - 33, // 104: ateapi.GetTagRequest.tag:type_name -> ateapi.ObjectRef - 33, // 105: ateapi.MintActorJwtRequest.actor:type_name -> ateapi.ObjectRef - 133, // 106: ateapi.MintActorJwtResponse.expires_at:type_name -> google.protobuf.Timestamp - 33, // 107: ateapi.MintActorCertificateRequest.actor:type_name -> ateapi.ObjectRef - 31, // 108: ateapi.ListTagsResponse.tags:type_name -> ateapi.Tag - 31, // 109: ateapi.CreateTagRequest.tag:type_name -> ateapi.Tag - 31, // 110: ateapi.UpdateTagRequest.tag:type_name -> ateapi.Tag - 33, // 111: ateapi.DeleteTagRequest.tag:type_name -> ateapi.ObjectRef - 95, // 112: ateapi.DeleteTagRequest.options:type_name -> ateapi.DeleteOptions - 33, // 113: ateapi.ListWorkerActorAssignmentsRequest.worker:type_name -> ateapi.ObjectRef - 114, // 114: ateapi.ListWorkerActorAssignmentsResponse.actor_assignments:type_name -> ateapi.ActorAssignment - 108, // 115: ateapi.ListWorkersResponse.workers:type_name -> ateapi.Worker - 33, // 116: ateapi.GetWorkerRequest.worker:type_name -> ateapi.ObjectRef - 108, // 117: ateapi.CreateWorkerRequest.worker:type_name -> ateapi.Worker - 108, // 118: ateapi.UpdateWorkerRequest.worker:type_name -> ateapi.Worker - 33, // 119: ateapi.DeleteWorkerRequest.worker:type_name -> ateapi.ObjectRef - 95, // 120: ateapi.DeleteWorkerRequest.options:type_name -> ateapi.DeleteOptions - 33, // 121: ateapi.DrainWorkerRequest.worker:type_name -> ateapi.ObjectRef - 108, // 122: ateapi.DrainWorkerResponse.worker:type_name -> ateapi.Worker - 16, // 123: ateapi.ListActorsResponse.actors:type_name -> ateapi.Actor - 14, // 124: ateapi.Worker.metadata:type_name -> ateapi.ResourceMetadata - 132, // 125: ateapi.Worker.labels:type_name -> ateapi.Worker.LabelsEntry - 109, // 126: ateapi.Worker.status:type_name -> ateapi.WorkerStatus - 8, // 127: ateapi.WorkerStatus.state:type_name -> ateapi.WorkerState - 113, // 128: ateapi.WorkerStatus.capacity:type_name -> ateapi.WorkerResources - 113, // 129: ateapi.WorkerStatus.allocated:type_name -> ateapi.WorkerResources - 110, // 130: ateapi.WorkerStatus.default_runtime:type_name -> ateapi.SandboxRuntime - 110, // 131: ateapi.WorkerStatus.restorable_runtimes:type_name -> ateapi.SandboxRuntime - 111, // 132: ateapi.SandboxRuntime.version:type_name -> ateapi.VersionedSandboxCompat - 112, // 133: ateapi.VersionedSandboxCompat.attributes:type_name -> ateapi.AttributeEntry - 35, // 134: ateapi.WorkerResources.resources:type_name -> ateapi.Resources - 14, // 135: ateapi.ActorAssignment.metadata:type_name -> ateapi.ResourceMetadata - 33, // 136: ateapi.ActorAssignment.actor:type_name -> ateapi.ObjectRef - 35, // 137: ateapi.ActorAssignment.resources:type_name -> ateapi.Resources - 33, // 138: ateapi.RegisterWorkerRequest.worker:type_name -> ateapi.ObjectRef - 113, // 139: ateapi.RegisterWorkerRequest.capacity:type_name -> ateapi.WorkerResources - 110, // 140: ateapi.RegisterWorkerRequest.default_runtime:type_name -> ateapi.SandboxRuntime - 110, // 141: ateapi.RegisterWorkerRequest.restorable_runtimes:type_name -> ateapi.SandboxRuntime - 108, // 142: ateapi.RegisterWorkerResponse.worker:type_name -> ateapi.Worker - 33, // 143: ateapi.MintAteomActorCertificateRequest.actor:type_name -> ateapi.ObjectRef - 33, // 144: ateapi.RequestActorSuspendRequest.worker:type_name -> ateapi.ObjectRef - 33, // 145: ateapi.RequestActorSuspendRequest.actor:type_name -> ateapi.ObjectRef - 16, // 146: ateapi.RequestActorSuspendResponse.actor:type_name -> ateapi.Actor - 14, // 147: ateapi.AccessPolicy.metadata:type_name -> ateapi.ResourceMetadata - 122, // 148: ateapi.AccessPolicy.bindings:type_name -> ateapi.Binding - 121, // 149: ateapi.CreateGlobalAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy - 121, // 150: ateapi.UpdateGlobalAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy - 33, // 151: ateapi.GetAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef - 33, // 152: ateapi.CreateAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef - 121, // 153: ateapi.CreateAtespaceAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy - 33, // 154: ateapi.UpdateAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef - 121, // 155: ateapi.UpdateAtespaceAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy - 33, // 156: ateapi.DeleteAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef - 95, // 157: ateapi.DeleteAtespaceAccessPolicyRequest.options:type_name -> ateapi.DeleteOptions - 69, // 158: ateapi.Control.GetActor:input_type -> ateapi.GetActorRequest - 70, // 159: ateapi.Control.CreateActor:input_type -> ateapi.CreateActorRequest - 71, // 160: ateapi.Control.UpdateActor:input_type -> ateapi.UpdateActorRequest - 72, // 161: ateapi.Control.SuspendActor:input_type -> ateapi.SuspendActorRequest - 74, // 162: ateapi.Control.PauseActor:input_type -> ateapi.PauseActorRequest - 76, // 163: ateapi.Control.ResumeActor:input_type -> ateapi.ResumeActorRequest - 78, // 164: ateapi.Control.RevertActor:input_type -> ateapi.RevertActorRequest - 80, // 165: ateapi.Control.DeleteActor:input_type -> ateapi.DeleteActorRequest - 81, // 166: ateapi.Control.GetActorEgressPolicy:input_type -> ateapi.GetActorEgressPolicyRequest - 82, // 167: ateapi.Control.CreateActorEgressPolicy:input_type -> ateapi.CreateActorEgressPolicyRequest - 83, // 168: ateapi.Control.UpdateActorEgressPolicy:input_type -> ateapi.UpdateActorEgressPolicyRequest - 84, // 169: ateapi.Control.DeleteActorEgressPolicy:input_type -> ateapi.DeleteActorEgressPolicyRequest - 86, // 170: ateapi.Control.MintActorJwt:input_type -> ateapi.MintActorJwtRequest - 88, // 171: ateapi.Control.MintActorCertificate:input_type -> ateapi.MintActorCertificateRequest - 92, // 172: ateapi.Control.CreateTag:input_type -> ateapi.CreateTagRequest - 85, // 173: ateapi.Control.GetTag:input_type -> ateapi.GetTagRequest - 90, // 174: ateapi.Control.ListTags:input_type -> ateapi.ListTagsRequest - 93, // 175: ateapi.Control.UpdateTag:input_type -> ateapi.UpdateTagRequest - 94, // 176: ateapi.Control.DeleteTag:input_type -> ateapi.DeleteTagRequest - 98, // 177: ateapi.Control.ListWorkers:input_type -> ateapi.ListWorkersRequest - 100, // 178: ateapi.Control.GetWorker:input_type -> ateapi.GetWorkerRequest - 101, // 179: ateapi.Control.CreateWorker:input_type -> ateapi.CreateWorkerRequest - 102, // 180: ateapi.Control.UpdateWorker:input_type -> ateapi.UpdateWorkerRequest - 103, // 181: ateapi.Control.DeleteWorker:input_type -> ateapi.DeleteWorkerRequest - 104, // 182: ateapi.Control.DrainWorker:input_type -> ateapi.DrainWorkerRequest - 96, // 183: ateapi.Control.ListWorkerActorAssignments:input_type -> ateapi.ListWorkerActorAssignmentsRequest - 106, // 184: ateapi.Control.ListActors:input_type -> ateapi.ListActorsRequest - 59, // 185: ateapi.Control.CreateAtespace:input_type -> ateapi.CreateAtespaceRequest - 60, // 186: ateapi.Control.GetAtespace:input_type -> ateapi.GetAtespaceRequest - 61, // 187: ateapi.Control.ListAtespaces:input_type -> ateapi.ListAtespacesRequest - 63, // 188: ateapi.Control.DeleteAtespace:input_type -> ateapi.DeleteAtespaceRequest - 64, // 189: ateapi.Control.CreateActorTemplate:input_type -> ateapi.CreateActorTemplateRequest - 65, // 190: ateapi.Control.GetActorTemplate:input_type -> ateapi.GetActorTemplateRequest - 66, // 191: ateapi.Control.ListActorTemplates:input_type -> ateapi.ListActorTemplatesRequest - 68, // 192: ateapi.Control.DeleteActorTemplate:input_type -> ateapi.DeleteActorTemplateRequest - 123, // 193: ateapi.Control.GetGlobalAccessPolicy:input_type -> ateapi.GetGlobalAccessPolicyRequest - 124, // 194: ateapi.Control.CreateGlobalAccessPolicy:input_type -> ateapi.CreateGlobalAccessPolicyRequest - 125, // 195: ateapi.Control.UpdateGlobalAccessPolicy:input_type -> ateapi.UpdateGlobalAccessPolicyRequest - 126, // 196: ateapi.Control.GetAtespaceAccessPolicy:input_type -> ateapi.GetAtespaceAccessPolicyRequest - 127, // 197: ateapi.Control.CreateAtespaceAccessPolicy:input_type -> ateapi.CreateAtespaceAccessPolicyRequest - 128, // 198: ateapi.Control.UpdateAtespaceAccessPolicy:input_type -> ateapi.UpdateAtespaceAccessPolicyRequest - 129, // 199: ateapi.Control.DeleteAtespaceAccessPolicy:input_type -> ateapi.DeleteAtespaceAccessPolicyRequest - 115, // 200: ateapi.WorkerService.RegisterWorker:input_type -> ateapi.RegisterWorkerRequest - 117, // 201: ateapi.WorkerService.MintAteomActorCertificate:input_type -> ateapi.MintAteomActorCertificateRequest - 119, // 202: ateapi.WorkerService.RequestActorSuspend:input_type -> ateapi.RequestActorSuspendRequest - 16, // 203: ateapi.Control.GetActor:output_type -> ateapi.Actor - 16, // 204: ateapi.Control.CreateActor:output_type -> ateapi.Actor - 16, // 205: ateapi.Control.UpdateActor:output_type -> ateapi.Actor - 73, // 206: ateapi.Control.SuspendActor:output_type -> ateapi.SuspendActorResponse - 75, // 207: ateapi.Control.PauseActor:output_type -> ateapi.PauseActorResponse - 77, // 208: ateapi.Control.ResumeActor:output_type -> ateapi.ResumeActorResponse - 79, // 209: ateapi.Control.RevertActor:output_type -> ateapi.RevertActorResponse - 16, // 210: ateapi.Control.DeleteActor:output_type -> ateapi.Actor - 17, // 211: ateapi.Control.GetActorEgressPolicy:output_type -> ateapi.EgressPolicy - 17, // 212: ateapi.Control.CreateActorEgressPolicy:output_type -> ateapi.EgressPolicy - 17, // 213: ateapi.Control.UpdateActorEgressPolicy:output_type -> ateapi.EgressPolicy - 17, // 214: ateapi.Control.DeleteActorEgressPolicy:output_type -> ateapi.EgressPolicy - 87, // 215: ateapi.Control.MintActorJwt:output_type -> ateapi.MintActorJwtResponse - 89, // 216: ateapi.Control.MintActorCertificate:output_type -> ateapi.MintActorCertificateResponse - 31, // 217: ateapi.Control.CreateTag:output_type -> ateapi.Tag - 31, // 218: ateapi.Control.GetTag:output_type -> ateapi.Tag - 91, // 219: ateapi.Control.ListTags:output_type -> ateapi.ListTagsResponse - 31, // 220: ateapi.Control.UpdateTag:output_type -> ateapi.Tag - 31, // 221: ateapi.Control.DeleteTag:output_type -> ateapi.Tag - 99, // 222: ateapi.Control.ListWorkers:output_type -> ateapi.ListWorkersResponse - 108, // 223: ateapi.Control.GetWorker:output_type -> ateapi.Worker - 108, // 224: ateapi.Control.CreateWorker:output_type -> ateapi.Worker - 108, // 225: ateapi.Control.UpdateWorker:output_type -> ateapi.Worker - 108, // 226: ateapi.Control.DeleteWorker:output_type -> ateapi.Worker - 105, // 227: ateapi.Control.DrainWorker:output_type -> ateapi.DrainWorkerResponse - 97, // 228: ateapi.Control.ListWorkerActorAssignments:output_type -> ateapi.ListWorkerActorAssignmentsResponse - 107, // 229: ateapi.Control.ListActors:output_type -> ateapi.ListActorsResponse - 32, // 230: ateapi.Control.CreateAtespace:output_type -> ateapi.Atespace - 32, // 231: ateapi.Control.GetAtespace:output_type -> ateapi.Atespace - 62, // 232: ateapi.Control.ListAtespaces:output_type -> ateapi.ListAtespacesResponse - 32, // 233: ateapi.Control.DeleteAtespace:output_type -> ateapi.Atespace - 34, // 234: ateapi.Control.CreateActorTemplate:output_type -> ateapi.ActorTemplate - 34, // 235: ateapi.Control.GetActorTemplate:output_type -> ateapi.ActorTemplate - 67, // 236: ateapi.Control.ListActorTemplates:output_type -> ateapi.ListActorTemplatesResponse - 34, // 237: ateapi.Control.DeleteActorTemplate:output_type -> ateapi.ActorTemplate - 121, // 238: ateapi.Control.GetGlobalAccessPolicy:output_type -> ateapi.AccessPolicy - 121, // 239: ateapi.Control.CreateGlobalAccessPolicy:output_type -> ateapi.AccessPolicy - 121, // 240: ateapi.Control.UpdateGlobalAccessPolicy:output_type -> ateapi.AccessPolicy - 121, // 241: ateapi.Control.GetAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy - 121, // 242: ateapi.Control.CreateAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy - 121, // 243: ateapi.Control.UpdateAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy - 121, // 244: ateapi.Control.DeleteAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy - 116, // 245: ateapi.WorkerService.RegisterWorker:output_type -> ateapi.RegisterWorkerResponse - 118, // 246: ateapi.WorkerService.MintAteomActorCertificate:output_type -> ateapi.MintAteomActorCertificateResponse - 120, // 247: ateapi.WorkerService.RequestActorSuspend:output_type -> ateapi.RequestActorSuspendResponse - 203, // [203:248] is the sub-list for method output_type - 158, // [158:203] 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 + 39, // 39: ateapi.Tag.source_actor:type_name -> ateapi.ObjectRef + 17, // 40: ateapi.SharedVolume.metadata:type_name -> ateapi.ResourceMetadata + 5, // 41: ateapi.SharedVolume.delete_trigger:type_name -> ateapi.DeleteTrigger + 144, // 42: ateapi.SharedVolume.volume_context:type_name -> ateapi.SharedVolume.VolumeContextEntry + 36, // 43: ateapi.SharedVolume.status:type_name -> ateapi.SharedVolumeStatus + 6, // 44: ateapi.SharedVolume.access_mode:type_name -> ateapi.AccessMode + 7, // 45: ateapi.SharedVolumeStatus.state:type_name -> ateapi.SharedVolumeState + 37, // 46: ateapi.SharedVolumeStatus.refs:type_name -> ateapi.ActorRef + 17, // 47: ateapi.Atespace.metadata:type_name -> ateapi.ResourceMetadata + 17, // 48: ateapi.ActorTemplate.metadata:type_name -> ateapi.ResourceMetadata + 16, // 49: ateapi.ActorTemplate.worker_selector:type_name -> ateapi.Selector + 48, // 50: ateapi.ActorTemplate.containers:type_name -> ateapi.Container + 54, // 51: ateapi.ActorTemplate.volumes:type_name -> ateapi.Volume + 46, // 52: ateapi.ActorTemplate.snapshot_config:type_name -> ateapi.SnapshotConfig + 45, // 53: ateapi.ActorTemplate.sandbox_config:type_name -> ateapi.SandboxConfig + 41, // 54: ateapi.ActorTemplate.resources:type_name -> ateapi.Resources + 44, // 55: ateapi.ActorTemplate.status:type_name -> ateapi.ActorTemplateStatus + 42, // 56: ateapi.Resources.limits:type_name -> ateapi.Limits + 39, // 57: ateapi.GoldenSnapshotStatus.golden_tag:type_name -> ateapi.ObjectRef + 146, // 58: ateapi.GoldenSnapshotStatus.take_golden_snapshot_at:type_name -> google.protobuf.Timestamp + 43, // 59: ateapi.ActorTemplateStatus.golden_snapshot_status:type_name -> ateapi.GoldenSnapshotStatus + 8, // 60: ateapi.SandboxConfig.sandbox_class:type_name -> ateapi.SandboxClass + 2, // 61: ateapi.SnapshotConfig.preferred_fidelity:type_name -> ateapi.SnapshotFidelity + 47, // 62: ateapi.SnapshotConfig.golden_snapshot_config:type_name -> ateapi.GoldenSnapshotConfig + 9, // 63: ateapi.GoldenSnapshotConfig.mode:type_name -> ateapi.GoldenSnapshotMode + 51, // 64: ateapi.Container.env:type_name -> ateapi.EnvVar + 52, // 65: ateapi.Container.wakeup_probe:type_name -> ateapi.ContainerWakeupProbe + 64, // 66: ateapi.Container.volume_mounts:type_name -> ateapi.VolumeMount + 49, // 67: ateapi.Container.security_context:type_name -> ateapi.SecurityContext + 41, // 68: ateapi.Container.resources:type_name -> ateapi.Resources + 50, // 69: ateapi.SecurityContext.capabilities:type_name -> ateapi.Capabilities + 53, // 70: ateapi.ContainerWakeupProbe.http_get:type_name -> ateapi.HttpGetAction + 57, // 71: ateapi.Volume.durable_dir:type_name -> ateapi.DurableDirVolumeSource + 55, // 72: ateapi.Volume.external:type_name -> ateapi.ExternalVolumeSource + 59, // 73: ateapi.Volume.system_info:type_name -> ateapi.SystemInfoVolumeSource + 56, // 74: ateapi.Volume.image:type_name -> ateapi.ImageVolumeSource + 58, // 75: ateapi.ExternalVolumeSource.template:type_name -> ateapi.ExternalVolumeTemplate + 60, // 76: ateapi.SystemInfoVolumeSource.data_sources:type_name -> ateapi.SystemInfoDataSource + 61, // 77: ateapi.SystemInfoDataSource.actor_metadata:type_name -> ateapi.ActorMetadataDataSource + 63, // 78: ateapi.SystemInfoDataSource.trust_bundle:type_name -> ateapi.TrustBundleDataSource + 62, // 79: ateapi.ActorMetadataDataSource.items:type_name -> ateapi.ActorMetadataItem + 10, // 80: ateapi.ActorMetadataItem.field:type_name -> ateapi.ActorMetadataField + 38, // 81: ateapi.CreateAtespaceRequest.atespace:type_name -> ateapi.Atespace + 39, // 82: ateapi.GetAtespaceRequest.atespace:type_name -> ateapi.ObjectRef + 38, // 83: ateapi.ListAtespacesResponse.atespaces:type_name -> ateapi.Atespace + 39, // 84: ateapi.DeleteAtespaceRequest.atespace:type_name -> ateapi.ObjectRef + 107, // 85: ateapi.DeleteAtespaceRequest.options:type_name -> ateapi.DeleteOptions + 40, // 86: ateapi.CreateActorTemplateRequest.actor_template:type_name -> ateapi.ActorTemplate + 39, // 87: ateapi.GetActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef + 40, // 88: ateapi.ListActorTemplatesResponse.actor_templates:type_name -> ateapi.ActorTemplate + 39, // 89: ateapi.DeleteActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef + 107, // 90: ateapi.DeleteActorTemplateRequest.options:type_name -> ateapi.DeleteOptions + 39, // 91: ateapi.GetActorRequest.actor:type_name -> ateapi.ObjectRef + 19, // 92: ateapi.CreateActorRequest.actor:type_name -> ateapi.Actor + 19, // 93: ateapi.UpdateActorRequest.actor:type_name -> ateapi.Actor + 39, // 94: ateapi.SuspendActorRequest.actor:type_name -> ateapi.ObjectRef + 19, // 95: ateapi.SuspendActorResponse.actor:type_name -> ateapi.Actor + 39, // 96: ateapi.PauseActorRequest.actor:type_name -> ateapi.ObjectRef + 19, // 97: ateapi.PauseActorResponse.actor:type_name -> ateapi.Actor + 39, // 98: ateapi.ResumeActorRequest.actor:type_name -> ateapi.ObjectRef + 19, // 99: ateapi.ResumeActorResponse.actor:type_name -> ateapi.Actor + 39, // 100: ateapi.RevertActorRequest.actor:type_name -> ateapi.ObjectRef + 19, // 101: ateapi.RevertActorResponse.actor:type_name -> ateapi.Actor + 39, // 102: ateapi.DeleteActorRequest.actor:type_name -> ateapi.ObjectRef + 107, // 103: ateapi.DeleteActorRequest.options:type_name -> ateapi.DeleteOptions + 39, // 104: ateapi.GetActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 39, // 105: ateapi.CreateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 20, // 106: ateapi.CreateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy + 39, // 107: ateapi.UpdateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 20, // 108: ateapi.UpdateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy + 39, // 109: ateapi.DeleteActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 107, // 110: ateapi.DeleteActorEgressPolicyRequest.options:type_name -> ateapi.DeleteOptions + 39, // 111: ateapi.GetTagRequest.tag:type_name -> ateapi.ObjectRef + 39, // 112: ateapi.MintActorJwtRequest.actor:type_name -> ateapi.ObjectRef + 146, // 113: ateapi.MintActorJwtResponse.expires_at:type_name -> google.protobuf.Timestamp + 39, // 114: ateapi.MintActorCertificateRequest.actor:type_name -> ateapi.ObjectRef + 34, // 115: ateapi.ListTagsResponse.tags:type_name -> ateapi.Tag + 34, // 116: ateapi.CreateTagRequest.tag:type_name -> ateapi.Tag + 34, // 117: ateapi.UpdateTagRequest.tag:type_name -> ateapi.Tag + 39, // 118: ateapi.DeleteTagRequest.tag:type_name -> ateapi.ObjectRef + 107, // 119: ateapi.DeleteTagRequest.options:type_name -> ateapi.DeleteOptions + 35, // 120: ateapi.CreateSharedVolumeRequest.shared_volume:type_name -> ateapi.SharedVolume + 39, // 121: ateapi.GetSharedVolumeRequest.shared_volume:type_name -> ateapi.ObjectRef + 35, // 122: ateapi.ListSharedVolumesResponse.shared_volumes:type_name -> ateapi.SharedVolume + 35, // 123: ateapi.UpdateSharedVolumeRequest.shared_volume:type_name -> ateapi.SharedVolume + 39, // 124: ateapi.DeleteSharedVolumeRequest.shared_volume:type_name -> ateapi.ObjectRef + 107, // 125: ateapi.DeleteSharedVolumeRequest.options:type_name -> ateapi.DeleteOptions + 39, // 126: ateapi.ListWorkerActorAssignmentsRequest.worker:type_name -> ateapi.ObjectRef + 126, // 127: ateapi.ListWorkerActorAssignmentsResponse.actor_assignments:type_name -> ateapi.ActorAssignment + 120, // 128: ateapi.ListWorkersResponse.workers:type_name -> ateapi.Worker + 39, // 129: ateapi.GetWorkerRequest.worker:type_name -> ateapi.ObjectRef + 120, // 130: ateapi.CreateWorkerRequest.worker:type_name -> ateapi.Worker + 120, // 131: ateapi.UpdateWorkerRequest.worker:type_name -> ateapi.Worker + 39, // 132: ateapi.DeleteWorkerRequest.worker:type_name -> ateapi.ObjectRef + 107, // 133: ateapi.DeleteWorkerRequest.options:type_name -> ateapi.DeleteOptions + 39, // 134: ateapi.DrainWorkerRequest.worker:type_name -> ateapi.ObjectRef + 120, // 135: ateapi.DrainWorkerResponse.worker:type_name -> ateapi.Worker + 19, // 136: ateapi.ListActorsResponse.actors:type_name -> ateapi.Actor + 17, // 137: ateapi.Worker.metadata:type_name -> ateapi.ResourceMetadata + 145, // 138: ateapi.Worker.labels:type_name -> ateapi.Worker.LabelsEntry + 121, // 139: ateapi.Worker.status:type_name -> ateapi.WorkerStatus + 11, // 140: ateapi.WorkerStatus.state:type_name -> ateapi.WorkerState + 125, // 141: ateapi.WorkerStatus.capacity:type_name -> ateapi.WorkerResources + 125, // 142: ateapi.WorkerStatus.allocated:type_name -> ateapi.WorkerResources + 122, // 143: ateapi.WorkerStatus.default_runtime:type_name -> ateapi.SandboxRuntime + 122, // 144: ateapi.WorkerStatus.restorable_runtimes:type_name -> ateapi.SandboxRuntime + 123, // 145: ateapi.SandboxRuntime.version:type_name -> ateapi.VersionedSandboxCompat + 124, // 146: ateapi.VersionedSandboxCompat.attributes:type_name -> ateapi.AttributeEntry + 41, // 147: ateapi.WorkerResources.resources:type_name -> ateapi.Resources + 17, // 148: ateapi.ActorAssignment.metadata:type_name -> ateapi.ResourceMetadata + 39, // 149: ateapi.ActorAssignment.actor:type_name -> ateapi.ObjectRef + 41, // 150: ateapi.ActorAssignment.resources:type_name -> ateapi.Resources + 39, // 151: ateapi.RegisterWorkerRequest.worker:type_name -> ateapi.ObjectRef + 125, // 152: ateapi.RegisterWorkerRequest.capacity:type_name -> ateapi.WorkerResources + 122, // 153: ateapi.RegisterWorkerRequest.default_runtime:type_name -> ateapi.SandboxRuntime + 122, // 154: ateapi.RegisterWorkerRequest.restorable_runtimes:type_name -> ateapi.SandboxRuntime + 120, // 155: ateapi.RegisterWorkerResponse.worker:type_name -> ateapi.Worker + 39, // 156: ateapi.MintAteomActorCertificateRequest.actor:type_name -> ateapi.ObjectRef + 39, // 157: ateapi.RequestActorSuspendRequest.worker:type_name -> ateapi.ObjectRef + 39, // 158: ateapi.RequestActorSuspendRequest.actor:type_name -> ateapi.ObjectRef + 19, // 159: ateapi.RequestActorSuspendResponse.actor:type_name -> ateapi.Actor + 17, // 160: ateapi.AccessPolicy.metadata:type_name -> ateapi.ResourceMetadata + 134, // 161: ateapi.AccessPolicy.bindings:type_name -> ateapi.Binding + 133, // 162: ateapi.CreateGlobalAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy + 133, // 163: ateapi.UpdateGlobalAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy + 39, // 164: ateapi.GetAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef + 39, // 165: ateapi.CreateAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef + 133, // 166: ateapi.CreateAtespaceAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy + 39, // 167: ateapi.UpdateAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef + 133, // 168: ateapi.UpdateAtespaceAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy + 39, // 169: ateapi.DeleteAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef + 107, // 170: ateapi.DeleteAtespaceAccessPolicyRequest.options:type_name -> ateapi.DeleteOptions + 75, // 171: ateapi.Control.GetActor:input_type -> ateapi.GetActorRequest + 76, // 172: ateapi.Control.CreateActor:input_type -> ateapi.CreateActorRequest + 77, // 173: ateapi.Control.UpdateActor:input_type -> ateapi.UpdateActorRequest + 78, // 174: ateapi.Control.SuspendActor:input_type -> ateapi.SuspendActorRequest + 80, // 175: ateapi.Control.PauseActor:input_type -> ateapi.PauseActorRequest + 82, // 176: ateapi.Control.ResumeActor:input_type -> ateapi.ResumeActorRequest + 84, // 177: ateapi.Control.RevertActor:input_type -> ateapi.RevertActorRequest + 86, // 178: ateapi.Control.DeleteActor:input_type -> ateapi.DeleteActorRequest + 87, // 179: ateapi.Control.GetActorEgressPolicy:input_type -> ateapi.GetActorEgressPolicyRequest + 88, // 180: ateapi.Control.CreateActorEgressPolicy:input_type -> ateapi.CreateActorEgressPolicyRequest + 89, // 181: ateapi.Control.UpdateActorEgressPolicy:input_type -> ateapi.UpdateActorEgressPolicyRequest + 90, // 182: ateapi.Control.DeleteActorEgressPolicy:input_type -> ateapi.DeleteActorEgressPolicyRequest + 92, // 183: ateapi.Control.MintActorJwt:input_type -> ateapi.MintActorJwtRequest + 94, // 184: ateapi.Control.MintActorCertificate:input_type -> ateapi.MintActorCertificateRequest + 98, // 185: ateapi.Control.CreateTag:input_type -> ateapi.CreateTagRequest + 91, // 186: ateapi.Control.GetTag:input_type -> ateapi.GetTagRequest + 96, // 187: ateapi.Control.ListTags:input_type -> ateapi.ListTagsRequest + 99, // 188: ateapi.Control.UpdateTag:input_type -> ateapi.UpdateTagRequest + 100, // 189: ateapi.Control.DeleteTag:input_type -> ateapi.DeleteTagRequest + 101, // 190: ateapi.Control.CreateSharedVolume:input_type -> ateapi.CreateSharedVolumeRequest + 102, // 191: ateapi.Control.GetSharedVolume:input_type -> ateapi.GetSharedVolumeRequest + 103, // 192: ateapi.Control.ListSharedVolumes:input_type -> ateapi.ListSharedVolumesRequest + 105, // 193: ateapi.Control.UpdateSharedVolume:input_type -> ateapi.UpdateSharedVolumeRequest + 106, // 194: ateapi.Control.DeleteSharedVolume:input_type -> ateapi.DeleteSharedVolumeRequest + 110, // 195: ateapi.Control.ListWorkers:input_type -> ateapi.ListWorkersRequest + 112, // 196: ateapi.Control.GetWorker:input_type -> ateapi.GetWorkerRequest + 113, // 197: ateapi.Control.CreateWorker:input_type -> ateapi.CreateWorkerRequest + 114, // 198: ateapi.Control.UpdateWorker:input_type -> ateapi.UpdateWorkerRequest + 115, // 199: ateapi.Control.DeleteWorker:input_type -> ateapi.DeleteWorkerRequest + 116, // 200: ateapi.Control.DrainWorker:input_type -> ateapi.DrainWorkerRequest + 108, // 201: ateapi.Control.ListWorkerActorAssignments:input_type -> ateapi.ListWorkerActorAssignmentsRequest + 118, // 202: ateapi.Control.ListActors:input_type -> ateapi.ListActorsRequest + 65, // 203: ateapi.Control.CreateAtespace:input_type -> ateapi.CreateAtespaceRequest + 66, // 204: ateapi.Control.GetAtespace:input_type -> ateapi.GetAtespaceRequest + 67, // 205: ateapi.Control.ListAtespaces:input_type -> ateapi.ListAtespacesRequest + 69, // 206: ateapi.Control.DeleteAtespace:input_type -> ateapi.DeleteAtespaceRequest + 70, // 207: ateapi.Control.CreateActorTemplate:input_type -> ateapi.CreateActorTemplateRequest + 71, // 208: ateapi.Control.GetActorTemplate:input_type -> ateapi.GetActorTemplateRequest + 72, // 209: ateapi.Control.ListActorTemplates:input_type -> ateapi.ListActorTemplatesRequest + 74, // 210: ateapi.Control.DeleteActorTemplate:input_type -> ateapi.DeleteActorTemplateRequest + 135, // 211: ateapi.Control.GetGlobalAccessPolicy:input_type -> ateapi.GetGlobalAccessPolicyRequest + 136, // 212: ateapi.Control.CreateGlobalAccessPolicy:input_type -> ateapi.CreateGlobalAccessPolicyRequest + 137, // 213: ateapi.Control.UpdateGlobalAccessPolicy:input_type -> ateapi.UpdateGlobalAccessPolicyRequest + 138, // 214: ateapi.Control.GetAtespaceAccessPolicy:input_type -> ateapi.GetAtespaceAccessPolicyRequest + 139, // 215: ateapi.Control.CreateAtespaceAccessPolicy:input_type -> ateapi.CreateAtespaceAccessPolicyRequest + 140, // 216: ateapi.Control.UpdateAtespaceAccessPolicy:input_type -> ateapi.UpdateAtespaceAccessPolicyRequest + 141, // 217: ateapi.Control.DeleteAtespaceAccessPolicy:input_type -> ateapi.DeleteAtespaceAccessPolicyRequest + 127, // 218: ateapi.WorkerService.RegisterWorker:input_type -> ateapi.RegisterWorkerRequest + 129, // 219: ateapi.WorkerService.MintAteomActorCertificate:input_type -> ateapi.MintAteomActorCertificateRequest + 131, // 220: ateapi.WorkerService.RequestActorSuspend:input_type -> ateapi.RequestActorSuspendRequest + 19, // 221: ateapi.Control.GetActor:output_type -> ateapi.Actor + 19, // 222: ateapi.Control.CreateActor:output_type -> ateapi.Actor + 19, // 223: ateapi.Control.UpdateActor:output_type -> ateapi.Actor + 79, // 224: ateapi.Control.SuspendActor:output_type -> ateapi.SuspendActorResponse + 81, // 225: ateapi.Control.PauseActor:output_type -> ateapi.PauseActorResponse + 83, // 226: ateapi.Control.ResumeActor:output_type -> ateapi.ResumeActorResponse + 85, // 227: ateapi.Control.RevertActor:output_type -> ateapi.RevertActorResponse + 19, // 228: ateapi.Control.DeleteActor:output_type -> ateapi.Actor + 20, // 229: ateapi.Control.GetActorEgressPolicy:output_type -> ateapi.EgressPolicy + 20, // 230: ateapi.Control.CreateActorEgressPolicy:output_type -> ateapi.EgressPolicy + 20, // 231: ateapi.Control.UpdateActorEgressPolicy:output_type -> ateapi.EgressPolicy + 20, // 232: ateapi.Control.DeleteActorEgressPolicy:output_type -> ateapi.EgressPolicy + 93, // 233: ateapi.Control.MintActorJwt:output_type -> ateapi.MintActorJwtResponse + 95, // 234: ateapi.Control.MintActorCertificate:output_type -> ateapi.MintActorCertificateResponse + 34, // 235: ateapi.Control.CreateTag:output_type -> ateapi.Tag + 34, // 236: ateapi.Control.GetTag:output_type -> ateapi.Tag + 97, // 237: ateapi.Control.ListTags:output_type -> ateapi.ListTagsResponse + 34, // 238: ateapi.Control.UpdateTag:output_type -> ateapi.Tag + 34, // 239: ateapi.Control.DeleteTag:output_type -> ateapi.Tag + 35, // 240: ateapi.Control.CreateSharedVolume:output_type -> ateapi.SharedVolume + 35, // 241: ateapi.Control.GetSharedVolume:output_type -> ateapi.SharedVolume + 104, // 242: ateapi.Control.ListSharedVolumes:output_type -> ateapi.ListSharedVolumesResponse + 35, // 243: ateapi.Control.UpdateSharedVolume:output_type -> ateapi.SharedVolume + 35, // 244: ateapi.Control.DeleteSharedVolume:output_type -> ateapi.SharedVolume + 111, // 245: ateapi.Control.ListWorkers:output_type -> ateapi.ListWorkersResponse + 120, // 246: ateapi.Control.GetWorker:output_type -> ateapi.Worker + 120, // 247: ateapi.Control.CreateWorker:output_type -> ateapi.Worker + 120, // 248: ateapi.Control.UpdateWorker:output_type -> ateapi.Worker + 120, // 249: ateapi.Control.DeleteWorker:output_type -> ateapi.Worker + 117, // 250: ateapi.Control.DrainWorker:output_type -> ateapi.DrainWorkerResponse + 109, // 251: ateapi.Control.ListWorkerActorAssignments:output_type -> ateapi.ListWorkerActorAssignmentsResponse + 119, // 252: ateapi.Control.ListActors:output_type -> ateapi.ListActorsResponse + 38, // 253: ateapi.Control.CreateAtespace:output_type -> ateapi.Atespace + 38, // 254: ateapi.Control.GetAtespace:output_type -> ateapi.Atespace + 68, // 255: ateapi.Control.ListAtespaces:output_type -> ateapi.ListAtespacesResponse + 38, // 256: ateapi.Control.DeleteAtespace:output_type -> ateapi.Atespace + 40, // 257: ateapi.Control.CreateActorTemplate:output_type -> ateapi.ActorTemplate + 40, // 258: ateapi.Control.GetActorTemplate:output_type -> ateapi.ActorTemplate + 73, // 259: ateapi.Control.ListActorTemplates:output_type -> ateapi.ListActorTemplatesResponse + 40, // 260: ateapi.Control.DeleteActorTemplate:output_type -> ateapi.ActorTemplate + 133, // 261: ateapi.Control.GetGlobalAccessPolicy:output_type -> ateapi.AccessPolicy + 133, // 262: ateapi.Control.CreateGlobalAccessPolicy:output_type -> ateapi.AccessPolicy + 133, // 263: ateapi.Control.UpdateGlobalAccessPolicy:output_type -> ateapi.AccessPolicy + 133, // 264: ateapi.Control.GetAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy + 133, // 265: ateapi.Control.CreateAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy + 133, // 266: ateapi.Control.UpdateAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy + 133, // 267: ateapi.Control.DeleteAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy + 128, // 268: ateapi.WorkerService.RegisterWorker:output_type -> ateapi.RegisterWorkerResponse + 130, // 269: ateapi.WorkerService.MintAteomActorCertificate:output_type -> ateapi.MintAteomActorCertificateResponse + 132, // 270: ateapi.WorkerService.RequestActorSuspend:output_type -> ateapi.RequestActorSuspendResponse + 221, // [221:271] is the sub-list for method output_type + 171, // [171:221] is the sub-list for method input_type + 171, // [171:171] is the sub-list for extension type_name + 171, // [171:171] is the sub-list for extension extendee + 0, // [0:171] is the sub-list for field type_name } func init() { file_ateapi_proto_init() } @@ -9620,8 +10520,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: 10, - NumMessages: 123, + NumEnums: 13, + NumMessages: 133, NumExtensions: 0, NumServices: 2, }, diff --git a/pkg/proto/ateapipb/ateapi.proto b/pkg/proto/ateapipb/ateapi.proto index f2a018e9fb..bd8cdc7d69 100644 --- a/pkg/proto/ateapipb/ateapi.proto +++ b/pkg/proto/ateapipb/ateapi.proto @@ -94,6 +94,21 @@ service Control { // and become unrecoverable, so do not delete a tag while such Actors exist. rpc DeleteTag(DeleteTagRequest) returns (Tag) {} + // Create a SharedVolume, provisioning it or registering an existing volume. + rpc CreateSharedVolume(CreateSharedVolumeRequest) returns (SharedVolume) {} + + // Get a SharedVolume. + rpc GetSharedVolume(GetSharedVolumeRequest) returns (SharedVolume) {} + + // List ExternalVolumes. + rpc ListSharedVolumes(ListSharedVolumesRequest) returns (ListSharedVolumesResponse) {} + + // Update a SharedVolume's delete trigger. + rpc UpdateSharedVolume(UpdateSharedVolumeRequest) returns (SharedVolume) {} + + // Delete a SharedVolume and its storage. Rejected while any Actor references it. + rpc DeleteSharedVolume(DeleteSharedVolumeRequest) returns (SharedVolume) {} + // List Workers. rpc ListWorkers(ListWorkersRequest) returns (ListWorkersResponse) {} @@ -957,6 +972,157 @@ message Tag { ObjectRef source_actor = 4; } +// DeleteTrigger is what removes a SharedVolume and its storage. +// TODO: add an ATESPACE trigger that removes the volume with its atespace. +enum DeleteTrigger { + DELETE_TRIGGER_UNSPECIFIED = 0; + // Only an explicit DeleteSharedVolume removes the volume. + DELETE_TRIGGER_MANUAL = 1; + // The volume is removed when the last actor referencing it is deleted. + DELETE_TRIGGER_LAST_ACTOR = 2; +} + +// AccessMode is how many resumed actors may hold the volume at once. +enum AccessMode { + ACCESS_MODE_UNSPECIFIED = 0; + // At most one resumed actor holds the volume. + ACCESS_MODE_READ_WRITE_ONCE = 1; + // Any number of resumed actors hold the volume, on any node. + ACCESS_MODE_READ_WRITE_MANY = 2; +} + +// SharedVolumeState is where a SharedVolume is in its own lifecycle. +enum SharedVolumeState { + SHARED_VOLUME_STATE_UNSPECIFIED = 0; + // The name is reserved but no volume handle is known yet. + SHARED_VOLUME_STATE_PENDING = 1; + // The volume has a handle and can be referenced. + SHARED_VOLUME_STATE_READY = 2; +} + +// SharedVolume is an atespace-scoped CSI volume whose lifetime is independent +// of any actor. Identity is (atespace, name); the storage-level ID is derived +// from the record's UID. +message SharedVolume { + // Common resource metadata: atespace, name, uid, version, timestamps. + // + // +k8s:required + // +k8s:subfield(atespace)=+k8s:required + ResourceMetadata metadata = 1; + + // delete_trigger decides what removes the volume. Defaults to LAST_ACTOR when + // provisioned and MANUAL when registered. + // + // +k8s:optional + // +k8s:minimum=1 + // +k8s:maximum=2 # keep this in sync with the DeleteTrigger enum + // +k8s:mutable + DeleteTrigger delete_trigger = 2; + + // storage_class_name names the StorageClass to provision from, or documents + // the class of a registered volume. + // + // +k8s:optional + // +k8s:format=k8s-long-name + // +k8s:update=NoModify + // +k8s:update=NoUnset + string storage_class_name = 3; + + // volume_id is the storage system's volume ID. Supplied to register an + // existing volume, otherwise stamped once provisioning completes. Bounded and + // checked for control characters only. + // + // +k8s:optional + // +k8s:maxLength=256 + // +k8s:update=NoModify + // +k8s:update=NoUnset + // +k8s:customValidation # no control characters + string volume_id = 4; + + // volume_type is the CSI driver name. Required alongside volume_id when no + // StorageClass is named; otherwise taken from the class's provisioner. + // + // +k8s:optional + // +k8s:maxLength=253 + // +k8s:update=NoModify + // +k8s:update=NoUnset + // +k8s:customValidation + string volume_type = 5; + + // volume_context is driver metadata needed by the node plugin for mounting. + // Attachment metadata is per-node and deliberately not recorded here. + // + // +k8s:optional + // +k8s:maxProperties=32 + // +k8s:eachKey=+k8s:maxLength=128 + // +k8s:eachVal=+k8s:maxLength=256 + map volume_context = 6; + + // status is set by the control plane; it is ignored on write. + // + // +k8s:optional + SharedVolumeStatus status = 7; + + // capacity to provision, as a Kubernetes resource.Quantity string (e.g. + // "10Gi"). Required when provisioning, forbidden alongside volume_id. + // + // +k8s:optional + // +k8s:maxLength=64 + // +k8s:update=NoModify + // +k8s:update=NoUnset + // +k8s:customValidation # must parse as a resource.Quantity + string capacity = 8; + + // access_mode is fixed at create and defaults to READ_WRITE_ONCE. + // TODO: accept READ_WRITE_MANY once concurrent holders are supported. + // + // +k8s:optional + // +k8s:minimum=1 + // +k8s:maximum=2 # keep this in sync with the AccessMode enum + // +k8s:update=NoModify + // +k8s:update=NoUnset + AccessMode access_mode = 9; +} + +// SharedVolumeStatus is the part of a SharedVolume the control plane owns. +message SharedVolumeStatus { + // state is where the volume is in its lifecycle. + // + // +k8s:optional + // +k8s:minimum=1 + // +k8s:maximum=2 # keep this in sync with the SharedVolumeState enum + SharedVolumeState state = 1; + + // refs are the actors referencing the volume, resumed or not. + // TODO: move references to their own table before lifting the bound. + // + // +k8s:optional + // +k8s:maxItems=256 + // +k8s:listType=map + // +k8s:listMapKey=actor_uid + repeated ActorRef refs = 2; +} + +// ActorRef is one actor's reference to a SharedVolume. +message ActorRef { + // actor_uid identifies the actor, so a recreated namesake does not inherit it. + // + // +k8s:required + // +k8s:maxLength=253 + string actor_uid = 1; + + // actor_name is the actor's name, for readers. + // + // +k8s:required + // +k8s:format=k8s-short-name + string actor_name = 2; + + // active is true while the actor is resumed and holds the volume mounted. + // + // +k8s:optional + bool active = 3; +} + // Atespace is the isolation boundary an Actor is created into. Global-scoped: // metadata.atespace is always empty; the atespace's identity is metadata.name. message Atespace { @@ -1955,6 +2121,82 @@ message DeleteTagRequest { DeleteOptions options = 2; } +// Request to create a SharedVolume. +// +// +k8s:customValidation # exactly one of storage_class_name and volume_id +message CreateSharedVolumeRequest { + // The volume to create. Name a storage class to provision a new volume, or + // supply a volume ID to register one that already exists. status is ignored. + // + // +k8s:required + SharedVolume shared_volume = 1; +} + +// GetSharedVolumeRequest identifies one SharedVolume. +message GetSharedVolumeRequest { + // The volume to get. + // + // +k8s:required + // +k8s:subfield(atespace)=+k8s:required + ObjectRef shared_volume = 1; +} + +// ListSharedVolumesRequest selects a page of ExternalVolumes. +message ListSharedVolumesRequest { + // The atespace to list from. Empty lists across all atespaces. + // + // +k8s:optional + // +k8s:format=k8s-short-name + string atespace = 1; + + // Requested page size; values above 1000 are coerced to 1000. + // + // +k8s:optional + // +k8s:minimum=1 + int32 page_size = 2; + + // Pagination token from a previous ListSharedVolumes response. + // + // +k8s:optional + // +k8s:maxLength=256 + string page_token = 3; +} + +// ListSharedVolumesResponse is one page of ExternalVolumes. +message ListSharedVolumesResponse { + // The volumes in this page. + repeated SharedVolume shared_volumes = 1; + + // Pagination token for the next page. Empty on the last page. + string next_page_token = 2; +} + +// Request to update the mutable fields of a SharedVolume. +message UpdateSharedVolumeRequest { + // The volume to update. metadata.atespace and metadata.name identify it; + // metadata.version and metadata.uid are required preconditions. + // + // +k8s:required + // +k8s:opaqueType # updates are handled in 2 steps, do not descend + // +k8s:subfield(metadata)=+k8s:required + // +k8s:customValidation # TODO: when we get nested subfields, require metadata.atespace + SharedVolume shared_volume = 1; +} + +// DeleteSharedVolumeRequest identifies one SharedVolume to delete. +message DeleteSharedVolumeRequest { + // The volume to delete. + // + // +k8s:required + // +k8s:subfield(atespace)=+k8s:required + ObjectRef shared_volume = 1; + + // Optional per-delete preconditions. + // + // +k8s:optional + DeleteOptions options = 2; +} + // DeleteOptions are the optional guards a Delete request may carry. message DeleteOptions { // Delete only if the resource is still at this version, that is, unchanged diff --git a/pkg/proto/ateapipb/ateapi_grpc.pb.go b/pkg/proto/ateapipb/ateapi_grpc.pb.go index b43217ac5d..93feb13261 100644 --- a/pkg/proto/ateapipb/ateapi_grpc.pb.go +++ b/pkg/proto/ateapipb/ateapi_grpc.pb.go @@ -52,6 +52,11 @@ const ( Control_ListTags_FullMethodName = "/ateapi.Control/ListTags" Control_UpdateTag_FullMethodName = "/ateapi.Control/UpdateTag" Control_DeleteTag_FullMethodName = "/ateapi.Control/DeleteTag" + Control_CreateSharedVolume_FullMethodName = "/ateapi.Control/CreateSharedVolume" + Control_GetSharedVolume_FullMethodName = "/ateapi.Control/GetSharedVolume" + Control_ListSharedVolumes_FullMethodName = "/ateapi.Control/ListSharedVolumes" + Control_UpdateSharedVolume_FullMethodName = "/ateapi.Control/UpdateSharedVolume" + Control_DeleteSharedVolume_FullMethodName = "/ateapi.Control/DeleteSharedVolume" Control_ListWorkers_FullMethodName = "/ateapi.Control/ListWorkers" Control_GetWorker_FullMethodName = "/ateapi.Control/GetWorker" Control_CreateWorker_FullMethodName = "/ateapi.Control/CreateWorker" @@ -136,6 +141,16 @@ type ControlClient interface { // tag that have not yet been suspended still point at that external snapshot // and become unrecoverable, so do not delete a tag while such Actors exist. DeleteTag(ctx context.Context, in *DeleteTagRequest, opts ...grpc.CallOption) (*Tag, error) + // Create a SharedVolume, provisioning it or registering an existing volume. + CreateSharedVolume(ctx context.Context, in *CreateSharedVolumeRequest, opts ...grpc.CallOption) (*SharedVolume, error) + // Get a SharedVolume. + GetSharedVolume(ctx context.Context, in *GetSharedVolumeRequest, opts ...grpc.CallOption) (*SharedVolume, error) + // List ExternalVolumes. + ListSharedVolumes(ctx context.Context, in *ListSharedVolumesRequest, opts ...grpc.CallOption) (*ListSharedVolumesResponse, error) + // Update a SharedVolume's delete trigger. + UpdateSharedVolume(ctx context.Context, in *UpdateSharedVolumeRequest, opts ...grpc.CallOption) (*SharedVolume, error) + // Delete a SharedVolume and its storage. Rejected while any Actor references it. + DeleteSharedVolume(ctx context.Context, in *DeleteSharedVolumeRequest, opts ...grpc.CallOption) (*SharedVolume, error) // List Workers. ListWorkers(ctx context.Context, in *ListWorkersRequest, opts ...grpc.CallOption) (*ListWorkersResponse, error) // Get a Worker. @@ -389,6 +404,56 @@ func (c *controlClient) DeleteTag(ctx context.Context, in *DeleteTagRequest, opt return out, nil } +func (c *controlClient) CreateSharedVolume(ctx context.Context, in *CreateSharedVolumeRequest, opts ...grpc.CallOption) (*SharedVolume, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SharedVolume) + err := c.cc.Invoke(ctx, Control_CreateSharedVolume_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *controlClient) GetSharedVolume(ctx context.Context, in *GetSharedVolumeRequest, opts ...grpc.CallOption) (*SharedVolume, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SharedVolume) + err := c.cc.Invoke(ctx, Control_GetSharedVolume_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *controlClient) ListSharedVolumes(ctx context.Context, in *ListSharedVolumesRequest, opts ...grpc.CallOption) (*ListSharedVolumesResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListSharedVolumesResponse) + err := c.cc.Invoke(ctx, Control_ListSharedVolumes_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *controlClient) UpdateSharedVolume(ctx context.Context, in *UpdateSharedVolumeRequest, opts ...grpc.CallOption) (*SharedVolume, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SharedVolume) + err := c.cc.Invoke(ctx, Control_UpdateSharedVolume_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *controlClient) DeleteSharedVolume(ctx context.Context, in *DeleteSharedVolumeRequest, opts ...grpc.CallOption) (*SharedVolume, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(SharedVolume) + err := c.cc.Invoke(ctx, Control_DeleteSharedVolume_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *controlClient) ListWorkers(ctx context.Context, in *ListWorkersRequest, opts ...grpc.CallOption) (*ListWorkersResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListWorkersResponse) @@ -678,6 +743,16 @@ type ControlServer interface { // tag that have not yet been suspended still point at that external snapshot // and become unrecoverable, so do not delete a tag while such Actors exist. DeleteTag(context.Context, *DeleteTagRequest) (*Tag, error) + // Create a SharedVolume, provisioning it or registering an existing volume. + CreateSharedVolume(context.Context, *CreateSharedVolumeRequest) (*SharedVolume, error) + // Get a SharedVolume. + GetSharedVolume(context.Context, *GetSharedVolumeRequest) (*SharedVolume, error) + // List ExternalVolumes. + ListSharedVolumes(context.Context, *ListSharedVolumesRequest) (*ListSharedVolumesResponse, error) + // Update a SharedVolume's delete trigger. + UpdateSharedVolume(context.Context, *UpdateSharedVolumeRequest) (*SharedVolume, error) + // Delete a SharedVolume and its storage. Rejected while any Actor references it. + DeleteSharedVolume(context.Context, *DeleteSharedVolumeRequest) (*SharedVolume, error) // List Workers. ListWorkers(context.Context, *ListWorkersRequest) (*ListWorkersResponse, error) // Get a Worker. @@ -798,6 +873,21 @@ func (UnimplementedControlServer) UpdateTag(context.Context, *UpdateTagRequest) func (UnimplementedControlServer) DeleteTag(context.Context, *DeleteTagRequest) (*Tag, error) { return nil, status.Error(codes.Unimplemented, "method DeleteTag not implemented") } +func (UnimplementedControlServer) CreateSharedVolume(context.Context, *CreateSharedVolumeRequest) (*SharedVolume, error) { + return nil, status.Error(codes.Unimplemented, "method CreateSharedVolume not implemented") +} +func (UnimplementedControlServer) GetSharedVolume(context.Context, *GetSharedVolumeRequest) (*SharedVolume, error) { + return nil, status.Error(codes.Unimplemented, "method GetSharedVolume not implemented") +} +func (UnimplementedControlServer) ListSharedVolumes(context.Context, *ListSharedVolumesRequest) (*ListSharedVolumesResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ListSharedVolumes not implemented") +} +func (UnimplementedControlServer) UpdateSharedVolume(context.Context, *UpdateSharedVolumeRequest) (*SharedVolume, error) { + return nil, status.Error(codes.Unimplemented, "method UpdateSharedVolume not implemented") +} +func (UnimplementedControlServer) DeleteSharedVolume(context.Context, *DeleteSharedVolumeRequest) (*SharedVolume, error) { + return nil, status.Error(codes.Unimplemented, "method DeleteSharedVolume not implemented") +} func (UnimplementedControlServer) ListWorkers(context.Context, *ListWorkersRequest) (*ListWorkersResponse, error) { return nil, status.Error(codes.Unimplemented, "method ListWorkers not implemented") } @@ -1230,6 +1320,96 @@ func _Control_DeleteTag_Handler(srv interface{}, ctx context.Context, dec func(i return interceptor(ctx, in, info, handler) } +func _Control_CreateSharedVolume_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateSharedVolumeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ControlServer).CreateSharedVolume(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Control_CreateSharedVolume_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ControlServer).CreateSharedVolume(ctx, req.(*CreateSharedVolumeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Control_GetSharedVolume_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetSharedVolumeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ControlServer).GetSharedVolume(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Control_GetSharedVolume_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ControlServer).GetSharedVolume(ctx, req.(*GetSharedVolumeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Control_ListSharedVolumes_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListSharedVolumesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ControlServer).ListSharedVolumes(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Control_ListSharedVolumes_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ControlServer).ListSharedVolumes(ctx, req.(*ListSharedVolumesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Control_UpdateSharedVolume_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateSharedVolumeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ControlServer).UpdateSharedVolume(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Control_UpdateSharedVolume_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ControlServer).UpdateSharedVolume(ctx, req.(*UpdateSharedVolumeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Control_DeleteSharedVolume_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteSharedVolumeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ControlServer).DeleteSharedVolume(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Control_DeleteSharedVolume_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ControlServer).DeleteSharedVolume(ctx, req.(*DeleteSharedVolumeRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Control_ListWorkers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ListWorkersRequest) if err := dec(in); err != nil { @@ -1727,6 +1907,26 @@ var Control_ServiceDesc = grpc.ServiceDesc{ MethodName: "DeleteTag", Handler: _Control_DeleteTag_Handler, }, + { + MethodName: "CreateSharedVolume", + Handler: _Control_CreateSharedVolume_Handler, + }, + { + MethodName: "GetSharedVolume", + Handler: _Control_GetSharedVolume_Handler, + }, + { + MethodName: "ListSharedVolumes", + Handler: _Control_ListSharedVolumes_Handler, + }, + { + MethodName: "UpdateSharedVolume", + Handler: _Control_UpdateSharedVolume_Handler, + }, + { + MethodName: "DeleteSharedVolume", + Handler: _Control_DeleteSharedVolume_Handler, + }, { MethodName: "ListWorkers", Handler: _Control_ListWorkers_Handler, diff --git a/tools/apitool/internal/model/model.go b/tools/apitool/internal/model/model.go index 70105cfd59..20bca123b4 100644 --- a/tools/apitool/internal/model/model.go +++ b/tools/apitool/internal/model/model.go @@ -558,6 +558,7 @@ var resourceNames = []string{ "Tag", "ActorTemplate", "Atespace", + "SharedVolume", "Worker", } From 065ae3e4c5a30e34c8e5abfd1edde87f882aa89d Mon Sep 17 00:00:00 2001 From: Elijah Rodriguez Date: Wed, 14 Oct 2026 10:36:11 -0700 Subject: [PATCH 04/12] ateapi: let actors reference SharedVolumes A template volume whose external source names a shared_volume mounts a SharedVolume instead of provisioning one per actor. The reference names the volume, or leaves the name empty so each actor binds it at creation through Actor.shared_volume_bindings. Every actor referencing a volume is recorded in the volume's refs, with active set while the actor is resumed. Resume refuses a READ_WRITE_ONCE volume another actor holds active, pause and suspend mark the reference inactive, crash leaves it as is, and delete removes it and deletes a LAST_ACTOR volume that no actor references any more. Golden actors never reference a volume; they warm up against an empty directory at the same mount path. Depends on the empty_dir volume source and the SharedVolume resource. Co-Authored-By: Claude Fable 5.1 --- .../apivalidation/zz_generated.validation.go | 156 +- cmd/ateapi/internal/controlapi/actor.go | 16 + .../functionaltest/shared_volume_test.go | 226 +++ cmd/ateapi/internal/controlapi/service.go | 4 +- .../internal/controlapi/shared_volume_refs.go | 255 ++++ .../controlapi/shared_volume_refs_test.go | 294 ++++ cmd/ateapi/internal/controlapi/volumes.go | 10 +- .../internal/controlapi/volumes_test.go | 40 + cmd/ateapi/internal/controlapi/workflow.go | 4 + .../internal/controlapi/workflow_delete.go | 13 + .../controlapi/workflow_delete_test.go | 4 +- .../internal/controlapi/workflow_resume.go | 12 +- .../internal/controlapi/workflow_suspend.go | 12 +- .../controlapi/workflow_testutil_test.go | 2 +- .../internal/controlapi/workload_spec.go | 24 +- .../internal/controlapi/workload_spec_test.go | 94 +- cmd/kubectl-ate/internal/cmd/actor.go | 9 +- cmd/kubectl-ate/internal/cmd/actor_test.go | 13 +- docs/csi-volumes.md | 41 + .../combinedvolumes/combinedvolumes_test.go | 177 +++ pkg/proto/ateapipb/ateapi.pb.go | 1341 +++++++++-------- pkg/proto/ateapipb/ateapi.proto | 38 + 22 files changed, 2143 insertions(+), 642 deletions(-) create mode 100644 cmd/ateapi/internal/controlapi/shared_volume_refs.go create mode 100644 cmd/ateapi/internal/controlapi/shared_volume_refs_test.go diff --git a/cmd/ateapi/internal/apivalidation/zz_generated.validation.go b/cmd/ateapi/internal/apivalidation/zz_generated.validation.go index 4e85fba18b..0261d0895a 100644 --- a/cmd/ateapi/internal/apivalidation/zz_generated.validation.go +++ b/cmd/ateapi/internal/apivalidation/zz_generated.validation.go @@ -325,6 +325,48 @@ func Validate_Actor( errs = append(errs, fn(fldPath.Child("status"), obj.Status, oldVal, oldObj != nil)...) } + { // field ateapipb.Actor.SharedVolumeBindings + fn := func( + fldPath *field.Path, + obj, oldObj map[string]string, + 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.Immutable(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.MaxProperties(ctx, op, fldPath, obj, oldObj, 32).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.OptionalMap(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + if e := validate.EachMapKey(ctx, op, fldPath, obj, oldObj, validate.ShortName); len(e) != 0 { + errs = append(errs, e...) + } + if e := validate.EachMapVal(ctx, op, fldPath, obj, oldObj, validate.DirectEqual, validate.ShortName); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.Actor) map[string]string { + return oldObj.SharedVolumeBindings + }) + errs = append(errs, fn(fldPath.Child("shared_volume_bindings"), obj.SharedVolumeBindings, oldVal, oldObj != nil)...) + } + return errs } @@ -4116,10 +4158,46 @@ func Validate_ExternalVolumeRef( errs = append(errs, fn(fldPath.Child("volume_context"), obj.VolumeContext, oldVal, oldObj != nil)...) } + { // field ateapipb.ExternalVolumeRef.SharedVolumeName + 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 e := validate.UpdateValue(ctx, op, fldPath, obj, oldObj, + func(a string, b string) bool { return a == b }, validate.NoUnset, validate.NoModify).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.ExternalVolumeRef) *string { + return &oldObj.SharedVolumeName + }) + errs = append(errs, fn(fldPath.Child("shared_volume_name"), &obj.SharedVolumeName, oldVal, oldObj != nil)...) + } + return errs } -var unionMembershipFor_github_com_agent_substrate_substrate_pkg_proto_ateapipb_ExternalVolumeSource_ = validate.NewUnionMembership(validate.NewUnionMember("template")) +var unionMembershipFor_github_com_agent_substrate_substrate_pkg_proto_ateapipb_ExternalVolumeSource_ = validate.NewUnionMembership(validate.NewUnionMember("template"), validate.NewUnionMember("shared_volume")) // Validate_ExternalVolumeSource validates an instance of ExternalVolumeSource according // to declarative validation rules in the API schema. @@ -4133,6 +4211,12 @@ func Validate_ExternalVolumeSource( return false } return obj.Template != nil + }, + func(obj *ateapipb.ExternalVolumeSource) bool { + if obj == nil { + return false + } + return obj.SharedVolume != nil }); len(e) != 0 { errs = append(errs, e...) } @@ -4167,6 +4251,36 @@ func Validate_ExternalVolumeSource( errs = append(errs, fn(fldPath.Child("template"), obj.Template, oldVal, oldObj != nil)...) } + { // field ateapipb.ExternalVolumeSource.SharedVolume + fn := func( + fldPath *field.Path, + obj, oldObj *ateapipb.SharedVolumeRef, + 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 + } + // call the type's validation function + errs = append(errs, Validate_SharedVolumeRef(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.ExternalVolumeSource) *ateapipb.SharedVolumeRef { + return oldObj.SharedVolume + }) + errs = append(errs, fn(fldPath.Child("shared_volume"), obj.SharedVolume, oldVal, oldObj != nil)...) + } + return errs } @@ -8036,6 +8150,46 @@ func Validate_SharedVolume( return errs } +// Validate_SharedVolumeRef validates an instance of SharedVolumeRef according +// to declarative validation rules in the API schema. +func Validate_SharedVolumeRef( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *ateapipb.SharedVolumeRef) (errs field.ErrorList) { + + { // field ateapipb.SharedVolumeRef.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.OptionalValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + 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.SharedVolumeRef) *string { + return &oldObj.Name + }) + errs = append(errs, fn(fldPath.Child("name"), &obj.Name, oldVal, oldObj != nil)...) + } + + return errs +} + // Validate_SharedVolumeStatus validates an instance of SharedVolumeStatus according // to declarative validation rules in the API schema. func Validate_SharedVolumeStatus( diff --git a/cmd/ateapi/internal/controlapi/actor.go b/cmd/ateapi/internal/controlapi/actor.go index f875b7b065..985b704916 100644 --- a/cmd/ateapi/internal/controlapi/actor.go +++ b/cmd/ateapi/internal/controlapi/actor.go @@ -120,6 +120,13 @@ func (s *ServiceImpl) CreateActor(ctx context.Context, inActor *ateapipb.Actor) if err != nil { return nil, err } + if !isGoldenActor(inActor) { + refVols, err := resolveSharedVolumeRefs(ctx, s.store, inActor, template) + if err != nil { + return nil, err + } + initVols = append(initVols, refVols...) + } // Verify that the result is properly valid before storing it. outActor := proto.CloneOf(inActor) @@ -158,6 +165,11 @@ func (s *ServiceImpl) CreateActor(ctx context.Context, inActor *ateapipb.Actor) return nil, fmt.Errorf("while recording actor: %w", err) } + // Resume re-takes any reference missed here, so this does not fail the create. + if err := bindSharedVolumes(ctx, s.store, stored); err != nil { + slog.WarnContext(ctx, "Failed to bind external volumes to new actor", slog.Any("actor", resources.ActorRefFromActor(stored)), slog.Any("err", err)) + } + // Without this an actor that is created and never resumed has no record at // all, at any retention. logActorStateChanged(ctx, stored, ateattr.OperationCreate) @@ -165,6 +177,10 @@ func (s *ServiceImpl) CreateActor(ctx context.Context, inActor *ateapipb.Actor) return stored, nil } +func isGoldenActor(actor *ateapipb.Actor) bool { + return actor.GetMetadata().GetAtespace() == resources.GoldenActorAtespace +} + // resolveTagSource resolves a CreateActor request's source tag // and checks that the tag is usable for creating an Actor in actorAtespace // from template. diff --git a/cmd/ateapi/internal/controlapi/functionaltest/shared_volume_test.go b/cmd/ateapi/internal/controlapi/functionaltest/shared_volume_test.go index 254bfaa213..c0938a9d2c 100644 --- a/cmd/ateapi/internal/controlapi/functionaltest/shared_volume_test.go +++ b/cmd/ateapi/internal/controlapi/functionaltest/shared_volume_test.go @@ -269,3 +269,229 @@ func TestDeleteSharedVolume(t *testing.T) { _, err = tc.client.DeleteSharedVolume(context.Background(), &ateapipb.DeleteSharedVolumeRequest{SharedVolume: ref}) assertGrpcError(t, err, codes.NotFound, fmt.Sprintf("SharedVolume %s/shared not found", testAtespace)) } + +// refStates maps each actor referencing volumeName to whether its reference is active. +func refStates(t *testing.T, tc *testContext, volumeName string) map[string]bool { + t.Helper() + states := make(map[string]bool) + for _, ref := range getSharedVolume(t, tc, volumeName).GetStatus().GetRefs() { + states[ref.GetActorName()] = ref.GetActive() + } + return states +} + +func borrowedMount(t *testing.T, tc *testContext, actorName, volumeName string) *ateapipb.ExternalVolumeRef { + t.Helper() + actor, err := tc.client.GetActor(context.Background(), &ateapipb.GetActorRequest{ + Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: actorName}, + }) + if err != nil { + t.Fatalf("GetActor(%s) failed: %v", actorName, err) + } + for _, vol := range actor.GetStatus().GetExternalVolumes() { + if vol.GetName() == volumeName { + return vol + } + } + return nil +} + +func createBorrowingActor(t *testing.T, tc *testContext, name string, bindings map[string]string) { + t.Helper() + if _, err := tc.client.CreateActor(context.Background(), &ateapipb.CreateActorRequest{Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: name}, + ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"}, + SharedVolumeBindings: bindings, + }}); err != nil { + t.Fatalf("CreateActor(%s) failed: %v", name, err) + } +} + +func actorState(t *testing.T, tc *testContext, name string) ateapipb.ActorState { + t.Helper() + actor, err := tc.client.GetActor(context.Background(), &ateapipb.GetActorRequest{ + Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: name}, + }) + if err != nil { + t.Fatalf("GetActor(%s) failed: %v", name, err) + } + return actor.GetStatus().GetState() +} + +func TestSharedVolume_SequentialHandoff(t *testing.T) { + ns := namespaceForTest("ns-extvol-handoff") + tc, plugin := setupSharedVolumeTest(t, ns) + defer tc.cleanup() + + shared := createSharedVolume(t, tc, "handoff", ateapipb.DeleteTrigger_DELETE_TRIGGER_LAST_ACTOR) + createTemplateWithVolumes(t, tc, ns, + []*ateapipb.Volume{{Name: "work", External: &ateapipb.ExternalVolumeSource{SharedVolume: &ateapipb.SharedVolumeRef{Name: "handoff"}}}}, + []*ateapipb.VolumeMount{{Name: "work", MountPath: "/mnt/work"}}) + workerName := createWorkerPod(t, tc, ns, "worker-1", "node1", "pool1") + ctx := context.Background() + + createBorrowingActor(t, tc, "producer", nil) + createBorrowingActor(t, tc, "consumer", nil) + if diff := cmp.Diff(map[string]bool{"producer": false, "consumer": false}, refStates(t, tc, "handoff")); diff != "" { + t.Errorf("refs after create mismatch (-want +got):\n%s", diff) + } + + waitForWorkerAvailable(t, tc, workerName) + if _, err := tc.client.ResumeActor(ctx, &ateapipb.ResumeActorRequest{Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "producer"}}); err != nil { + t.Fatalf("ResumeActor(producer) failed: %v", err) + } + if diff := cmp.Diff(map[string]bool{"producer": true, "consumer": false}, refStates(t, tc, "handoff")); diff != "" { + t.Errorf("refs while the producer runs mismatch (-want +got):\n%s", diff) + } + if _, err := tc.client.SuspendActor(ctx, &ateapipb.SuspendActorRequest{Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "producer"}}); err != nil { + t.Fatalf("SuspendActor(producer) failed: %v", err) + } + if diff := cmp.Diff(map[string]bool{"producer": false, "consumer": false}, refStates(t, tc, "handoff")); diff != "" { + t.Errorf("refs after the producer stops mismatch (-want +got):\n%s", diff) + } + + waitForWorkerAvailable(t, tc, workerName) + if _, err := tc.client.ResumeActor(ctx, &ateapipb.ResumeActorRequest{Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "consumer"}}); err != nil { + t.Fatalf("ResumeActor(consumer) failed: %v", err) + } + if diff := cmp.Diff(map[string]bool{"producer": false, "consumer": true}, refStates(t, tc, "handoff")); diff != "" { + t.Errorf("refs while the consumer runs mismatch (-want +got):\n%s", diff) + } + for _, name := range []string{"producer", "consumer"} { + if got, want := borrowedMount(t, tc, name, "work").GetStorageVolumeId(), shared.GetVolumeId(); got != want { + t.Errorf("actor %s mounted %q, want the shared volume %q", name, got, want) + } + } + created, deleted, attached, detached := plugin.snapshot() + if diff := cmp.Diff([]string{shared.GetVolumeId() + "@node1", shared.GetVolumeId() + "@node1"}, attached); diff != "" { + t.Errorf("attached volumes mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff([]string{shared.GetVolumeId() + "@node1"}, detached); diff != "" { + t.Errorf("detached volumes mismatch (-want +got):\n%s", diff) + } + if len(created) != 1 || len(deleted) != 0 { + t.Errorf("created %v deleted %v, want one provisioning and no deletion", created, deleted) + } + + if _, err := tc.client.SuspendActor(ctx, &ateapipb.SuspendActorRequest{Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "consumer"}}); err != nil { + t.Fatalf("SuspendActor(consumer) failed: %v", err) + } + for _, name := range []string{"producer", "consumer"} { + if _, err := tc.client.DeleteActor(ctx, &ateapipb.DeleteActorRequest{Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: name}}); err != nil { + t.Fatalf("DeleteActor(%s) failed: %v", name, err) + } + } + _, err := tc.client.GetSharedVolume(ctx, &ateapipb.GetSharedVolumeRequest{SharedVolume: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "handoff"}}) + assertGrpcError(t, err, codes.NotFound, fmt.Sprintf("SharedVolume %s/handoff not found", testAtespace)) + if _, deleted, _, _ := plugin.snapshot(); !cmp.Equal([]string{shared.GetVolumeId()}, deleted) { + t.Errorf("deleted volumes = %v, want the LAST_ACTOR trigger to delete %q", deleted, shared.GetVolumeId()) + } +} + +func TestSharedVolume_HeldByAnotherActor(t *testing.T) { + ns := namespaceForTest("ns-extvol-held") + tc, plugin := setupSharedVolumeTest(t, ns) + defer tc.cleanup() + + shared := createSharedVolume(t, tc, "held", ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL) + createTemplateWithVolumes(t, tc, ns, + []*ateapipb.Volume{{Name: "work", External: &ateapipb.ExternalVolumeSource{SharedVolume: &ateapipb.SharedVolumeRef{Name: "held"}}}}, + []*ateapipb.VolumeMount{{Name: "work", MountPath: "/mnt/work"}}) + firstWorker := createWorkerPod(t, tc, ns, "worker-1", "node1", "pool1") + ctx := context.Background() + + createBorrowingActor(t, tc, "producer", nil) + createBorrowingActor(t, tc, "consumer", nil) + waitForWorkerAvailable(t, tc, firstWorker) + if _, err := tc.client.ResumeActor(ctx, &ateapipb.ResumeActorRequest{Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "producer"}}); err != nil { + t.Fatalf("ResumeActor(producer) failed: %v", err) + } + + secondWorker := createWorkerPod(t, tc, ns, "worker-2", "node1", "pool1") + waitForWorkerAvailable(t, tc, secondWorker) + _, err := tc.client.ResumeActor(ctx, &ateapipb.ResumeActorRequest{Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "consumer"}}) + assertGrpcErrorRegex(t, err, codes.FailedPrecondition, `SharedVolume .*held is already held by actor "producer"`) + if diff := cmp.Diff(map[string]bool{"producer": true, "consumer": false}, refStates(t, tc, "held")); diff != "" { + t.Errorf("refs after the refused resume mismatch (-want +got):\n%s", diff) + } + if got := actorState(t, tc, "consumer"); got != ateapipb.ActorState_ACTOR_STATE_SUSPENDED { + t.Errorf("consumer is in %v, want it left SUSPENDED", got) + } + if _, _, attached, _ := plugin.snapshot(); !cmp.Equal([]string{shared.GetVolumeId() + "@node1"}, attached) { + t.Errorf("attached volumes = %v, want only the producer's attach", attached) + } + + if _, err := tc.client.PauseActor(ctx, &ateapipb.PauseActorRequest{Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "producer"}}); err != nil { + t.Fatalf("PauseActor(producer) failed: %v", err) + } + if _, err := tc.client.ResumeActor(ctx, &ateapipb.ResumeActorRequest{Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "consumer"}}); err != nil { + t.Fatalf("ResumeActor(consumer) after the handoff failed: %v", err) + } + if diff := cmp.Diff(map[string]bool{"producer": false, "consumer": true}, refStates(t, tc, "held")); diff != "" { + t.Errorf("refs after the handoff mismatch (-want +got):\n%s", diff) + } +} + +func TestDeleteSharedVolume_Referenced(t *testing.T) { + ns := namespaceForTest("ns-extvol-referenced") + tc, plugin := setupSharedVolumeTest(t, ns) + defer tc.cleanup() + + createSharedVolume(t, tc, "shared", ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL) + createTemplateWithVolumes(t, tc, ns, + []*ateapipb.Volume{{Name: "work", External: &ateapipb.ExternalVolumeSource{SharedVolume: &ateapipb.SharedVolumeRef{Name: "shared"}}}}, + []*ateapipb.VolumeMount{{Name: "work", MountPath: "/mnt/work"}}) + ctx := context.Background() + ref := &ateapipb.ObjectRef{Atespace: testAtespace, Name: "shared"} + + createBorrowingActor(t, tc, "borrower", nil) + _, err := tc.client.DeleteSharedVolume(ctx, &ateapipb.DeleteSharedVolumeRequest{SharedVolume: ref}) + assertGrpcErrorRegex(t, err, codes.FailedPrecondition, `SharedVolume .*shared is still referenced by 1 actor\(s\), starting with "borrower"`) + + if _, err := tc.client.DeleteActor(ctx, &ateapipb.DeleteActorRequest{Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "borrower"}}); err != nil { + t.Fatalf("DeleteActor failed: %v", err) + } + if got := refStates(t, tc, "shared"); len(got) != 0 { + t.Errorf("refs after the actor is deleted = %v, want none", got) + } + if _, deleted, _, _ := plugin.snapshot(); len(deleted) != 0 { + t.Errorf("deleted %v, want a MANUAL volume left in place", deleted) + } + if _, err := tc.client.DeleteSharedVolume(ctx, &ateapipb.DeleteSharedVolumeRequest{SharedVolume: ref}); err != nil { + t.Fatalf("DeleteSharedVolume failed: %v", err) + } +} + +func TestCreateActor_SharedVolumeBindings(t *testing.T) { + ns := namespaceForTest("ns-extvol-bindings") + tc, _ := setupSharedVolumeTest(t, ns) + defer tc.cleanup() + + shared := createSharedVolume(t, tc, "ctx-42", ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL) + createTemplateWithVolumes(t, tc, ns, + []*ateapipb.Volume{{Name: "work", External: &ateapipb.ExternalVolumeSource{SharedVolume: &ateapipb.SharedVolumeRef{}}}}, + []*ateapipb.VolumeMount{{Name: "work", MountPath: "/mnt/work"}}) + ctx := context.Background() + create := func(name string, bindings map[string]string) error { + _, err := tc.client.CreateActor(ctx, &ateapipb.CreateActorRequest{Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: name}, + ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"}, + SharedVolumeBindings: bindings, + }}) + return err + } + + assertGrpcErrorRegex(t, create("unbound", nil), codes.InvalidArgument, `shared_volume_bindings must bind volume "work"`) + assertGrpcErrorRegex(t, create("stray", map[string]string{"work": "ctx-42", "other": "ctx-42"}), codes.InvalidArgument, `shared_volume_bindings\["other"\]`) + assertGrpcErrorRegex(t, create("missing", map[string]string{"work": "ctx-41"}), codes.FailedPrecondition, fmt.Sprintf("SharedVolume %s/ctx-41 not found", testAtespace)) + + if err := create("bound", map[string]string{"work": "ctx-42"}); err != nil { + t.Fatalf("CreateActor(bound) failed: %v", err) + } + if got, want := borrowedMount(t, tc, "bound", "work").GetStorageVolumeId(), shared.GetVolumeId(); got != want { + t.Errorf("bound actor mounts %q, want %q", got, want) + } + if diff := cmp.Diff(map[string]bool{"bound": false}, refStates(t, tc, "ctx-42")); diff != "" { + t.Errorf("refs mismatch (-want +got):\n%s", diff) + } +} diff --git a/cmd/ateapi/internal/controlapi/service.go b/cmd/ateapi/internal/controlapi/service.go index 089034c54c..aec129698f 100644 --- a/cmd/ateapi/internal/controlapi/service.go +++ b/cmd/ateapi/internal/controlapi/service.go @@ -104,9 +104,9 @@ func NewRPCService( actorIDJWTPool: actorIDJWTPool, actorIDCAPool: actorIDCAPool, } - s.actorWorkflow = NewActorWorkflow(impl, workerCache, dialer, sandboxConfigLister, storageClassLister, instruments, egressGatewayAddress, s, objectStorePlugin) - s.workerWorkflow = NewWorkerWorkflow(impl) s.sharedVolumeWorkflow = NewSharedVolumeWorkflow(impl, storageClassLister, s) + s.actorWorkflow = NewActorWorkflow(impl, workerCache, dialer, sandboxConfigLister, storageClassLister, instruments, egressGatewayAddress, s, objectStorePlugin, s.sharedVolumeWorkflow) + s.workerWorkflow = NewWorkerWorkflow(impl) return s } diff --git a/cmd/ateapi/internal/controlapi/shared_volume_refs.go b/cmd/ateapi/internal/controlapi/shared_volume_refs.go new file mode 100644 index 0000000000..2670c096ae --- /dev/null +++ b/cmd/ateapi/internal/controlapi/shared_volume_refs.go @@ -0,0 +1,255 @@ +// 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" + "errors" + "fmt" + "slices" + + "github.com/agent-substrate/substrate/cmd/ateapi/internal/store" + "github.com/agent-substrate/substrate/internal/apierror" + "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" +) + +type sharedVolumeRefStore interface { + GetSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef) (*ateapipb.SharedVolume, error) + UpdateSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef, precondition store.Precondition, mutate func(toUpdate *ateapipb.SharedVolume) error) (*ateapipb.SharedVolume, error) +} + +type sharedVolumeDeleter interface { + DeleteSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef, precondition store.DeletePreconditions) (*ateapipb.SharedVolume, error) +} + +// resolveSharedVolumeRefs checks the actor's bindings against the template +// and returns a mount for every SharedVolume the actor references. +func resolveSharedVolumeRefs(ctx context.Context, st sharedVolumeRefStore, actor *ateapipb.Actor, template *ateapipb.ActorTemplate) ([]*ateapipb.ExternalVolumeRef, error) { + bindings := actor.GetSharedVolumeBindings() + unnamed := make(map[string]bool) + for _, vol := range template.GetVolumes() { + if vol.GetExternal().GetSharedVolume() != nil && vol.GetExternal().GetSharedVolume().GetName() == "" { + unnamed[vol.GetName()] = true + } + } + for slot := range bindings { + if !unnamed[slot] { + return nil, apierror.InvalidArgument("shared_volume_bindings[%q] does not name an unnamed external.shared_volume in the template", slot) + } + } + + var mounts []*ateapipb.ExternalVolumeRef + for _, vol := range template.GetVolumes() { + ref := vol.GetExternal().GetSharedVolume() + if ref == nil { + continue + } + name := ref.GetName() + if name == "" { + if name = bindings[vol.GetName()]; name == "" { + return nil, apierror.InvalidArgument("shared_volume_bindings must bind volume %q", vol.GetName()) + } + } + volume, err := getReadySharedVolume(ctx, st, resources.SharedVolumeRef{Atespace: actor.GetMetadata().GetAtespace(), Name: name}) + if err != nil { + return nil, err + } + mounts = append(mounts, sharedVolumeMount(vol.GetName(), volume)) + } + return mounts, nil +} + +func getReadySharedVolume(ctx context.Context, st sharedVolumeRefStore, volumeRef resources.SharedVolumeRef) (*ateapipb.SharedVolume, error) { + volume, err := st.GetSharedVolume(ctx, volumeRef) + if err != nil { + if errors.Is(err, store.ErrNotFound) { + return nil, apierror.FailedPrecondition("SharedVolume %s not found", volumeRef) + } + return nil, fmt.Errorf("while getting shared volume %s: %w", volumeRef, err) + } + if state := volume.GetStatus().GetState(); state != ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY { + return nil, apierror.FailedPrecondition("SharedVolume %s is not ready (state %s)", volumeRef, state) + } + return volume, nil +} + +func sharedVolumeMount(templateVolumeName string, volume *ateapipb.SharedVolume) *ateapipb.ExternalVolumeRef { + return &ateapipb.ExternalVolumeRef{ + Name: templateVolumeName, + SharedVolumeName: volume.GetMetadata().GetName(), + StorageVolumeId: volume.GetVolumeId(), + VolumeType: volume.GetVolumeType(), + VolumeContext: volume.GetVolumeContext(), + Status: ateapipb.ExternalVolumeRef_STATUS_CREATED, + } +} + +func borrowedVolumeRefs(actor *ateapipb.Actor) []resources.SharedVolumeRef { + var refs []resources.SharedVolumeRef + for _, vol := range actor.GetStatus().GetExternalVolumes() { + if vol.GetSharedVolumeName() != "" { + refs = append(refs, resources.SharedVolumeRef{Atespace: actor.GetMetadata().GetAtespace(), Name: vol.GetSharedVolumeName()}) + } + } + return refs +} + +func actorRefOf(actor *ateapipb.Actor, active bool) *ateapipb.ActorRef { + return &ateapipb.ActorRef{ + ActorUid: actor.GetMetadata().GetUid(), + ActorName: actor.GetMetadata().GetName(), + Active: active, + } +} + +func findActorRef(volume *ateapipb.SharedVolume, actorUID string) *ateapipb.ActorRef { + for _, ref := range volume.GetStatus().GetRefs() { + if ref.GetActorUid() == actorUID { + return ref + } + } + return nil +} + +func setActorRef(volume *ateapipb.SharedVolume, ref *ateapipb.ActorRef) { + if existing := findActorRef(volume, ref.GetActorUid()); existing != nil { + existing.ActorName, existing.Active = ref.GetActorName(), ref.GetActive() + return + } + if volume.Status == nil { + volume.Status = &ateapipb.SharedVolumeStatus{} + } + volume.Status.Refs = append(volume.Status.Refs, ref) +} + +// updateSharedVolumeRefs applies mutate under the volume's version guard. +// TODO: move references to their own table so claims do not contend on one row. +func updateSharedVolumeRefs(ctx context.Context, st sharedVolumeRefStore, volumeRef resources.SharedVolumeRef, mutate func(*ateapipb.SharedVolume) error) (*ateapipb.SharedVolume, error) { + volume, err := st.GetSharedVolume(ctx, volumeRef) + if err != nil { + return nil, err + } + return st.UpdateSharedVolume(ctx, volumeRef, store.PreconditionFrom(volume), mutate) +} + +// bindSharedVolumes records an inactive reference for every SharedVolume +// the actor mounts. +func bindSharedVolumes(ctx context.Context, st sharedVolumeRefStore, actor *ateapipb.Actor) error { + var errs []error + for _, volumeRef := range borrowedVolumeRefs(actor) { + _, err := updateSharedVolumeRefs(ctx, st, volumeRef, func(toUpdate *ateapipb.SharedVolume) error { + if findActorRef(toUpdate, actor.GetMetadata().GetUid()) == nil { + setActorRef(toUpdate, actorRefOf(actor, false)) + } + return nil + }) + if err != nil { + errs = append(errs, fmt.Errorf("while binding shared volume %s: %w", volumeRef, err)) + } + } + return errors.Join(errs...) +} + +var errSharedVolumeHeld = errors.New("shared volume is held by another actor") + +// claimSharedVolumes marks the actor's references active and refreshes the +// recorded mounts. A READ_WRITE_ONCE volume another actor holds is refused. +// TODO: let READ_WRITE_MANY volumes carry several active references. +func claimSharedVolumes(ctx context.Context, st sharedVolumeRefStore, actor *ateapipb.Actor) ([]*ateapipb.ExternalVolumeRef, error) { + volumes := slices.Clone(actor.GetStatus().GetExternalVolumes()) + actorUID := actor.GetMetadata().GetUid() + for i, mount := range volumes { + if mount.GetSharedVolumeName() == "" { + continue + } + volumeRef := resources.SharedVolumeRef{Atespace: actor.GetMetadata().GetAtespace(), Name: mount.GetSharedVolumeName()} + var holder string + claimed, err := updateSharedVolumeRefs(ctx, st, volumeRef, func(toUpdate *ateapipb.SharedVolume) error { + if toUpdate.GetStatus().GetState() != ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY { + return fmt.Errorf("shared volume is not ready (state %s)", toUpdate.GetStatus().GetState()) + } + for _, ref := range toUpdate.GetStatus().GetRefs() { + if ref.GetActive() && ref.GetActorUid() != actorUID { + holder = ref.GetActorName() + return errSharedVolumeHeld + } + } + setActorRef(toUpdate, actorRefOf(actor, true)) + return nil + }) + switch { + case err == nil: + case errors.Is(err, errSharedVolumeHeld): + return nil, apierror.FailedPrecondition("SharedVolume %s is already held by actor %q; pause or suspend it before resuming another actor", volumeRef, holder) + case errors.Is(err, store.ErrNotFound): + return nil, apierror.FailedPrecondition("SharedVolume %s not found", volumeRef) + case errors.Is(err, store.ErrVersionConflict), errors.Is(err, store.ErrUIDConflict): + return nil, apierror.Aborted("concurrent update conflict, please retry") + default: + return nil, apierror.FailedPrecondition("SharedVolume %s: %v", volumeRef, err) + } + volumes[i] = sharedVolumeMount(mount.GetName(), claimed) + } + return volumes, nil +} + +// deactivateSharedVolumes marks the actor's references inactive. +func deactivateSharedVolumes(ctx context.Context, st sharedVolumeRefStore, actor *ateapipb.Actor) error { + var errs []error + for _, volumeRef := range borrowedVolumeRefs(actor) { + _, err := updateSharedVolumeRefs(ctx, st, volumeRef, func(toUpdate *ateapipb.SharedVolume) error { + if ref := findActorRef(toUpdate, actor.GetMetadata().GetUid()); ref != nil { + ref.Active = false + } + return nil + }) + if err != nil && !errors.Is(err, store.ErrNotFound) { + errs = append(errs, fmt.Errorf("while deactivating shared volume %s: %w", volumeRef, err)) + } + } + return errors.Join(errs...) +} + +// releaseSharedVolumes drops the actor's references and deletes each volume +// left without references whose delete trigger is LAST_ACTOR. +func releaseSharedVolumes(ctx context.Context, st sharedVolumeRefStore, deleter sharedVolumeDeleter, actor *ateapipb.Actor) error { + var errs []error + for _, volumeRef := range borrowedVolumeRefs(actor) { + released, err := updateSharedVolumeRefs(ctx, st, volumeRef, func(toUpdate *ateapipb.SharedVolume) error { + toUpdate.Status.Refs = slices.DeleteFunc(toUpdate.GetStatus().GetRefs(), func(ref *ateapipb.ActorRef) bool { + return ref.GetActorUid() == actor.GetMetadata().GetUid() + }) + return nil + }) + if errors.Is(err, store.ErrNotFound) { + continue + } + if err != nil { + errs = append(errs, fmt.Errorf("while releasing shared volume %s: %w", volumeRef, err)) + continue + } + if released.GetDeleteTrigger() != ateapipb.DeleteTrigger_DELETE_TRIGGER_LAST_ACTOR || len(released.GetStatus().GetRefs()) > 0 { + continue + } + _, err = deleter.DeleteSharedVolume(ctx, volumeRef, store.DeletePreconditions{UID: released.GetMetadata().GetUid()}) + if code := status.Code(err); err != nil && code != codes.NotFound && code != codes.FailedPrecondition { + errs = append(errs, fmt.Errorf("while deleting shared volume %s: %w", volumeRef, err)) + } + } + return errors.Join(errs...) +} diff --git a/cmd/ateapi/internal/controlapi/shared_volume_refs_test.go b/cmd/ateapi/internal/controlapi/shared_volume_refs_test.go new file mode 100644 index 0000000000..a6aab44092 --- /dev/null +++ b/cmd/ateapi/internal/controlapi/shared_volume_refs_test.go @@ -0,0 +1,294 @@ +// 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/cmd/ateapi/internal/store" + "github.com/agent-substrate/substrate/cmd/ateapi/internal/store/storetest" + "github.com/agent-substrate/substrate/internal/apierror" + "github.com/agent-substrate/substrate/internal/resources" + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" + "github.com/google/go-cmp/cmp" + "google.golang.org/grpc/codes" + "google.golang.org/protobuf/testing/protocmp" +) + +const ( + refTestAtespace = "team-refs" + refTestActorUID = "11111111-1111-1111-1111-111111111111" + refTestOtherUID = "22222222-2222-2222-2222-222222222222" +) + +func refTestTemplate(volumes ...*ateapipb.Volume) *ateapipb.ActorTemplate { + return &ateapipb.ActorTemplate{ + Metadata: &ateapipb.ResourceMetadata{Atespace: refTestAtespace, Name: "tmpl"}, + Volumes: volumes, + } +} + +func refTestActor(volumes ...*ateapipb.ExternalVolumeRef) *ateapipb.Actor { + return &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: refTestAtespace, Name: "consumer", Uid: refTestActorUID}, + Status: &ateapipb.ActorStatus{ExternalVolumes: volumes}, + } +} + +func borrowedMount(volumeName string) *ateapipb.ExternalVolumeRef { + return &ateapipb.ExternalVolumeRef{ + Name: "shared-data", + SharedVolumeName: volumeName, + StorageVolumeId: "disk/" + volumeName, + VolumeType: "mock", + VolumeContext: map[string]string{"type": "pd-ssd"}, + Status: ateapipb.ExternalVolumeRef_STATUS_CREATED, + } +} + +func mustStoreReadyVolume(t *testing.T, ctx context.Context, st store.Interface, name string, trigger ateapipb.DeleteTrigger, refs ...*ateapipb.ActorRef) *ateapipb.SharedVolume { + t.Helper() + return storetest.MustCreateSharedVolume(t, ctx, st, &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{Atespace: refTestAtespace, Name: name}, + DeleteTrigger: trigger, + AccessMode: ateapipb.AccessMode_ACCESS_MODE_READ_WRITE_ONCE, + VolumeId: "disk/" + name, + VolumeType: "mock", + VolumeContext: map[string]string{"type": "pd-ssd"}, + Status: &ateapipb.SharedVolumeStatus{ + State: ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY, + Refs: refs, + }, + }) +} + +func mustGetVolume(t *testing.T, ctx context.Context, st store.Interface, name string) *ateapipb.SharedVolume { + t.Helper() + got, err := st.GetSharedVolume(ctx, resources.SharedVolumeRef{Atespace: refTestAtespace, Name: name}) + if err != nil { + t.Fatalf("GetSharedVolume(%q): %v", name, err) + } + return got +} + +// refStates maps each referencing actor's UID to whether its reference is active. +func refStates(volume *ateapipb.SharedVolume) map[string]bool { + states := make(map[string]bool, len(volume.GetStatus().GetRefs())) + for _, ref := range volume.GetStatus().GetRefs() { + states[ref.GetActorUid()] = ref.GetActive() + } + return states +} + +func TestResolveSharedVolumeRefs(t *testing.T) { + ctx := context.Background() + st := newTestPersistence(t) + mustStoreReadyVolume(t, ctx, st, "shared", ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL) + mustStoreReadyVolume(t, ctx, st, "bound", ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL) + storetest.MustCreateSharedVolume(t, ctx, st, &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{Atespace: refTestAtespace, Name: "pending"}, + StorageClassName: "standard", + Status: &ateapipb.SharedVolumeStatus{State: ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_PENDING}, + }) + named := &ateapipb.Volume{Name: "shared-data", External: &ateapipb.ExternalVolumeSource{SharedVolume: &ateapipb.SharedVolumeRef{Name: "shared"}}} + unnamed := &ateapipb.Volume{Name: "slot", External: &ateapipb.ExternalVolumeSource{SharedVolume: &ateapipb.SharedVolumeRef{}}} + + tests := []struct { + name string + template *ateapipb.ActorTemplate + bindings map[string]string + want []string + wantCode codes.Code + }{ + {name: "named ref", template: refTestTemplate(named), want: []string{"shared"}}, + {name: "bound slot", template: refTestTemplate(named, unnamed), bindings: map[string]string{"slot": "bound"}, want: []string{"shared", "bound"}}, + {name: "unbound slot", template: refTestTemplate(unnamed), wantCode: codes.InvalidArgument}, + {name: "binding for a named ref", template: refTestTemplate(named), bindings: map[string]string{"shared-data": "bound"}, wantCode: codes.InvalidArgument}, + {name: "binding for an unknown volume", template: refTestTemplate(unnamed), bindings: map[string]string{"slot": "bound", "other": "bound"}, wantCode: codes.InvalidArgument}, + {name: "missing volume", template: refTestTemplate(unnamed), bindings: map[string]string{"slot": "absent"}, wantCode: codes.FailedPrecondition}, + {name: "pending volume", template: refTestTemplate(unnamed), bindings: map[string]string{"slot": "pending"}, wantCode: codes.FailedPrecondition}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + actor := refTestActor() + actor.SharedVolumeBindings = tc.bindings + mounts, err := resolveSharedVolumeRefs(ctx, st, actor, tc.template) + if apierror.Code(err) != tc.wantCode { + t.Fatalf("resolveSharedVolumeRefs() error = %v, want code %v", err, tc.wantCode) + } + var got []string + for _, mount := range mounts { + if mount.GetStorageVolumeId() != "disk/"+mount.GetSharedVolumeName() || mount.GetStatus() != ateapipb.ExternalVolumeRef_STATUS_CREATED { + t.Errorf("mount %v does not carry the volume's handle", mount) + } + got = append(got, mount.GetSharedVolumeName()) + } + if diff := cmp.Diff(tc.want, got); diff != "" { + t.Errorf("resolved volumes mismatch (-want +got):\n%s", diff) + } + }) + } +} + +func TestBindClaimDeactivateRelease(t *testing.T) { + ctx := context.Background() + st := newTestPersistence(t) + mustStoreReadyVolume(t, ctx, st, "shared", ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL) + actor := refTestActor(borrowedMount("shared")) + volumeRef := resources.SharedVolumeRef{Atespace: refTestAtespace, Name: "shared"} + + if err := bindSharedVolumes(ctx, st, actor); err != nil { + t.Fatalf("bindSharedVolumes: %v", err) + } + if diff := cmp.Diff(map[string]bool{refTestActorUID: false}, refStates(mustGetVolume(t, ctx, st, "shared"))); diff != "" { + t.Errorf("refs after bind mismatch (-want +got):\n%s", diff) + } + + claimed, err := claimSharedVolumes(ctx, st, actor) + if err != nil { + t.Fatalf("claimSharedVolumes: %v", err) + } + if diff := cmp.Diff(actor.GetStatus().GetExternalVolumes(), claimed, protocmp.Transform()); diff != "" { + t.Errorf("claimed mounts mismatch (-want +got):\n%s", diff) + } + if diff := cmp.Diff(map[string]bool{refTestActorUID: true}, refStates(mustGetVolume(t, ctx, st, "shared"))); diff != "" { + t.Errorf("refs after claim mismatch (-want +got):\n%s", diff) + } + if _, err := claimSharedVolumes(ctx, st, actor); err != nil { + t.Fatalf("second claimSharedVolumes: %v", err) + } + + if err := deactivateSharedVolumes(ctx, st, actor); err != nil { + t.Fatalf("deactivateSharedVolumes: %v", err) + } + if diff := cmp.Diff(map[string]bool{refTestActorUID: false}, refStates(mustGetVolume(t, ctx, st, "shared"))); diff != "" { + t.Errorf("refs after deactivate mismatch (-want +got):\n%s", diff) + } + + deleter := &recordingSharedVolumeDeleter{} + if err := releaseSharedVolumes(ctx, st, deleter, actor); err != nil { + t.Fatalf("releaseSharedVolumes: %v", err) + } + if got := refStates(mustGetVolume(t, ctx, st, "shared")); len(got) != 0 { + t.Errorf("refs after release = %v, want none", got) + } + if len(deleter.deleted) != 0 { + t.Errorf("deleted %v, want a MANUAL volume left in place", deleter.deleted) + } + if err := releaseSharedVolumes(ctx, st, deleter, actor); err != nil { + t.Fatalf("second releaseSharedVolumes: %v", err) + } + if _, err := st.GetSharedVolume(ctx, volumeRef); err != nil { + t.Errorf("GetSharedVolume after release: %v", err) + } +} + +func TestClaimSharedVolumes_Exclusion(t *testing.T) { + ctx := context.Background() + other := &ateapipb.ActorRef{ActorUid: refTestOtherUID, ActorName: "producer"} + + t.Run("active holder blocks", func(t *testing.T) { + st := newTestPersistence(t) + other := &ateapipb.ActorRef{ActorUid: other.ActorUid, ActorName: other.ActorName, Active: true} + mustStoreReadyVolume(t, ctx, st, "shared", ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL, other) + + _, err := claimSharedVolumes(ctx, st, refTestActor(borrowedMount("shared"))) + if apierror.Code(err) != codes.FailedPrecondition || !strings.Contains(err.Error(), "producer") { + t.Fatalf("claimSharedVolumes() = %v, want FailedPrecondition naming the holder", err) + } + if diff := cmp.Diff(map[string]bool{refTestOtherUID: true}, refStates(mustGetVolume(t, ctx, st, "shared"))); diff != "" { + t.Errorf("refs after refused claim mismatch (-want +got):\n%s", diff) + } + }) + + t.Run("inactive holder does not block", func(t *testing.T) { + st := newTestPersistence(t) + mustStoreReadyVolume(t, ctx, st, "shared", ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL, other) + + if _, err := claimSharedVolumes(ctx, st, refTestActor(borrowedMount("shared"))); err != nil { + t.Fatalf("claimSharedVolumes: %v", err) + } + if diff := cmp.Diff(map[string]bool{refTestOtherUID: false, refTestActorUID: true}, refStates(mustGetVolume(t, ctx, st, "shared"))); diff != "" { + t.Errorf("refs mismatch (-want +got):\n%s", diff) + } + }) + + t.Run("missing volume", func(t *testing.T) { + st := newTestPersistence(t) + storetest.MustCreateAtespace(t, ctx, st, refTestAtespace) + + _, err := claimSharedVolumes(ctx, st, refTestActor(borrowedMount("absent"))) + if apierror.Code(err) != codes.FailedPrecondition { + t.Fatalf("claimSharedVolumes() = %v, want FailedPrecondition", err) + } + }) +} + +func TestReleaseSharedVolumes_LastActorDeletes(t *testing.T) { + ctx := context.Background() + st := newTestPersistence(t) + other := &ateapipb.ActorRef{ActorUid: refTestOtherUID, ActorName: "other"} + mustStoreReadyVolume(t, ctx, st, "shared", ateapipb.DeleteTrigger_DELETE_TRIGGER_LAST_ACTOR, + &ateapipb.ActorRef{ActorUid: refTestActorUID, ActorName: "consumer"}, other) + actor := refTestActor(borrowedMount("shared")) + deleter := &recordingSharedVolumeDeleter{} + + if err := releaseSharedVolumes(ctx, st, deleter, actor); err != nil { + t.Fatalf("releaseSharedVolumes: %v", err) + } + if len(deleter.deleted) != 0 { + t.Fatalf("deleted %v while another actor still references the volume", deleter.deleted) + } + + otherActor := refTestActor(borrowedMount("shared")) + otherActor.Metadata.Uid = refTestOtherUID + if err := releaseSharedVolumes(ctx, st, deleter, otherActor); err != nil { + t.Fatalf("releaseSharedVolumes(other): %v", err) + } + if diff := cmp.Diff([]string{refTestAtespace + "/shared"}, deleter.deleted); diff != "" { + t.Errorf("deleted volumes mismatch (-want +got):\n%s", diff) + } +} + +func TestCrashActorKeepsSharedVolumeRefs(t *testing.T) { + ctx := context.Background() + st := newTestPersistence(t) + + created := storetest.MustCreateActor(t, ctx, st, refTestActor()) + mustStoreReadyVolume(t, ctx, st, "shared", ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL, + &ateapipb.ActorRef{ActorUid: created.GetMetadata().GetUid(), ActorName: "consumer", Active: true}) + mustUpdateActorStatus(t, ctx, st, created, func(s *ateapipb.ActorStatus) { + s.State = ateapipb.ActorState_ACTOR_STATE_RUNNING + s.ExternalVolumes = []*ateapipb.ExternalVolumeRef{borrowedMount("shared")} + }) + + if err := crashActor(ctx, st, resources.ActorRef{Atespace: refTestAtespace, Name: "consumer"}, "resume", "worker lost"); err != nil { + t.Fatalf("crashActor: %v", err) + } + if diff := cmp.Diff(map[string]bool{created.GetMetadata().GetUid(): true}, refStates(mustGetVolume(t, ctx, st, "shared"))); diff != "" { + t.Errorf("refs after crash mismatch (-want +got):\n%s", diff) + } +} + +type recordingSharedVolumeDeleter struct { + deleted []string +} + +func (d *recordingSharedVolumeDeleter) DeleteSharedVolume(_ context.Context, volumeRef resources.SharedVolumeRef, _ store.DeletePreconditions) (*ateapipb.SharedVolume, error) { + d.deleted = append(d.deleted, volumeRef.String()) + return nil, nil +} diff --git a/cmd/ateapi/internal/controlapi/volumes.go b/cmd/ateapi/internal/controlapi/volumes.go index a85a5d3f8c..7eadb74c79 100644 --- a/cmd/ateapi/internal/controlapi/volumes.go +++ b/cmd/ateapi/internal/controlapi/volumes.go @@ -74,6 +74,11 @@ func createActorVolumes(ctx context.Context, registry VolumePluginRegistry, scLi for idx, vol := range volumesToCreate { currentIdx = idx + if vol.GetSharedVolumeName() != "" { + resultVolumes = append(resultVolumes, vol) + continue + } + var specVol *ateapipb.Volume volName := vol.GetName() for _, tVol := range template.GetVolumes() { @@ -138,13 +143,16 @@ func createActorVolumes(ctx context.Context, registry VolumePluginRegistry, scLi return resultVolumes, nil } -// deleteActorVolumes deletes all external volumes in the list. +// deleteActorVolumes deletes the external volumes the actor owns. func deleteActorVolumes(ctx context.Context, registry VolumePluginRegistry, actorUID string, volumes []*ateapipb.ExternalVolumeRef) error { if actorUID == "" { return errors.New("actorUID is required") } var errs []error for _, vol := range volumes { + if vol.GetSharedVolumeName() != "" { + continue + } volID := vol.GetStorageVolumeId() if volID == "" { // If the volume hasn't been successfully created yet, it's possible diff --git a/cmd/ateapi/internal/controlapi/volumes_test.go b/cmd/ateapi/internal/controlapi/volumes_test.go index 95e0d1b986..a2676b758b 100644 --- a/cmd/ateapi/internal/controlapi/volumes_test.go +++ b/cmd/ateapi/internal/controlapi/volumes_test.go @@ -698,3 +698,43 @@ func TestDetachActorVolumes(t *testing.T) { }) } } + +func TestBorrowedVolumesAreNotProvisionedOrDeleted(t *testing.T) { + ctx := context.Background() + template := &ateapipb.ActorTemplate{ + Volumes: []*ateapipb.Volume{{Name: "shared-data", External: &ateapipb.ExternalVolumeSource{SharedVolume: &ateapipb.SharedVolumeRef{Name: "shared"}}}}, + } + scLister := &fakeStorageClassLister{storageClasses: map[string]*storagev1.StorageClass{}} + + initial, err := initialActorVolumes(ctx, scLister, template) + if err != nil { + t.Fatalf("initialActorVolumes: %v", err) + } + if len(initial) != 0 { + t.Errorf("initialActorVolumes() = %v, want no entry for a borrowed volume", initial) + } + + borrowed := []*ateapipb.ExternalVolumeRef{{ + Name: "shared-data", + SharedVolumeName: "shared", + StorageVolumeId: "disk/shared", + VolumeType: "mock", + Status: ateapipb.ExternalVolumeRef_STATUS_CREATED, + }} + plugin := &trackingVolumePlugin{} + registry := &mockPluginRegistry{plugins: map[string]volume.VolumePluginControlPlane{"mock": plugin}} + + got, err := createActorVolumes(ctx, registry, scLister, "actor-uid-123", template, borrowed) + if err != nil { + t.Fatalf("createActorVolumes: %v", err) + } + if diff := cmp.Diff(borrowed, got, protocmp.Transform()); diff != "" { + t.Errorf("createActorVolumes() mismatch (-want +got):\n%s", diff) + } + if err := deleteActorVolumes(ctx, registry, "actor-uid-123", borrowed); err != nil { + t.Fatalf("deleteActorVolumes: %v", err) + } + if len(plugin.deletedIDs) != 0 { + t.Errorf("deleted %v, want the borrowed volume left alone", plugin.deletedIDs) + } +} diff --git a/cmd/ateapi/internal/controlapi/workflow.go b/cmd/ateapi/internal/controlapi/workflow.go index fc40b265e9..2b3165d3e4 100644 --- a/cmd/ateapi/internal/controlapi/workflow.go +++ b/cmd/ateapi/internal/controlapi/workflow.go @@ -102,6 +102,7 @@ func logActorState(ctx context.Context, actor *ateapipb.Actor, opName, state str // ActorWorkflow handles the workflows for actor's resume / suspend operations. type ActorWorkflow struct { store actorWorkflowStore + sharedVolumes sharedVolumeDeleter workerCache *workercache.Cache scheduler scheduling.Scheduler dialer *AteletDialer @@ -128,9 +129,11 @@ func NewActorWorkflow( egressGatewayAddress string, pluginRegistry VolumePluginRegistry, objectStorePlugin objectstorev1.ControlProviderClient, + sharedVolumes sharedVolumeDeleter, ) *ActorWorkflow { return &ActorWorkflow{ store: store, + sharedVolumes: sharedVolumes, workerCache: workerCache, scheduler: scheduling.New(workerCache), dialer: dialer, @@ -179,6 +182,7 @@ type actorWorkflowStore interface { GetActorTemplate(ctx context.Context, templateRef resources.ActorTemplateRef) (*ateapipb.ActorTemplate, error) DeleteActorTemplate(ctx context.Context, templateRef resources.ActorTemplateRef, precondition store.DeletePreconditions) (*ateapipb.ActorTemplate, error) AcquireLease(ctx context.Context, key string) (*store.Lease, error) + sharedVolumeRefStore } // WorkerWorkflow handles the multi-step operations on a Worker. diff --git a/cmd/ateapi/internal/controlapi/workflow_delete.go b/cmd/ateapi/internal/controlapi/workflow_delete.go index 71643d1a7b..96ceff1110 100644 --- a/cmd/ateapi/internal/controlapi/workflow_delete.go +++ b/cmd/ateapi/internal/controlapi/workflow_delete.go @@ -95,6 +95,10 @@ func (w *ActorWorkflow) DeleteActor(ctx context.Context, actorRef resources.Acto errs = append(errs, fmt.Errorf("while deleting volumes: %w", err)) } + if err := w.ensureSharedVolumeRefsReleased(ctx, actor); err != nil { + errs = append(errs, fmt.Errorf("while releasing external volume references: %w", err)) + } + if err := w.ensureExternalSnapshotsReleased(ctx, actor); err != nil { errs = append(errs, fmt.Errorf("while releasing external snapshots: %w", err)) } @@ -363,6 +367,15 @@ func (w *ActorWorkflow) ensureVolumesDeleted(ctx context.Context, actor *ateapip return nil } +// ensureSharedVolumeRefsReleased drops the actor's SharedVolume references +// and deletes any volume that reached its LAST_ACTOR trigger. +func (w *ActorWorkflow) ensureSharedVolumeRefsReleased(ctx context.Context, actor *ateapipb.Actor) (err error) { + ctx, done := stepSpan(ctx, "ReleaseSharedVolumeRefs") + defer func() { err = done(err) }() + + return releaseSharedVolumes(ctx, w.store, w.sharedVolumes, actor) +} + // ensureExternalSnapshotsReleased collects everything the actor wrote to // object storage, by deleting its own prefix. It runs before the actor is // removed, so a failed attempt is still rediscoverable on the retry. diff --git a/cmd/ateapi/internal/controlapi/workflow_delete_test.go b/cmd/ateapi/internal/controlapi/workflow_delete_test.go index 4b84fa6fa5..5fbdf120d8 100644 --- a/cmd/ateapi/internal/controlapi/workflow_delete_test.go +++ b/cmd/ateapi/internal/controlapi/workflow_delete_test.go @@ -347,7 +347,7 @@ func TestDeleteActor_CollectsInFlightSnapshotWithoutTemplate(t *testing.T) { ctx := context.Background() persistence := newTestPersistence(t) objects := objectstoretest.New() - w := NewActorWorkflow(persistence, nil, nil, nil, nil, nil, "", nil, objectstoreplugintest.ControlClient(objects)) + w := NewActorWorkflow(persistence, nil, nil, nil, nil, nil, "", nil, objectstoreplugintest.ControlClient(objects), nil) actorRef := resources.ActorRef{Atespace: "team-a", Name: "actor-1"} actor := storetest.MustCreateActor(t, ctx, persistence, &ateapipb.Actor{ @@ -500,7 +500,7 @@ func TestDeleteActor_CollectsSnapshotsAfterWorkerDelete(t *testing.T) { }) } - actorWorkflow := NewActorWorkflow(persistence, nil, nil, nil, nil, nil, "", nil, objectstoreplugintest.ControlClient(objects)) + actorWorkflow := NewActorWorkflow(persistence, nil, nil, nil, nil, nil, "", nil, objectstoreplugintest.ControlClient(objects), nil) // Suspend the actor as far as it gets: MarkSuspending mints the // in-progress URI, and the checkpoint writes under it actor, err := actorWorkflow.ensureMarkedSuspending(ctx, actorRef, actor, template) diff --git a/cmd/ateapi/internal/controlapi/workflow_resume.go b/cmd/ateapi/internal/controlapi/workflow_resume.go index d43f8a793f..c1b0e27d37 100644 --- a/cmd/ateapi/internal/controlapi/workflow_resume.go +++ b/cmd/ateapi/internal/controlapi/workflow_resume.go @@ -199,12 +199,20 @@ func (w *ActorWorkflow) ensureVolumesCreated(ctx context.Context, actorRef resou break } } - if !pending { + borrows := len(borrowedVolumeRefs(actor)) > 0 + if !pending && !borrows { markSkipped(ctx, "no volumes awaiting creation") return actor, nil } - volumes, createErr := createActorVolumes(ctx, w.pluginRegistry, w.storageClassLister, actor.GetMetadata().GetUid(), actorTemplate, actor.GetStatus().GetExternalVolumes()) + volumes := actor.GetStatus().GetExternalVolumes() + if borrows { + var err error + if volumes, err = claimSharedVolumes(ctx, w.store, actor); err != nil { + return nil, err + } + } + volumes, createErr := createActorVolumes(ctx, w.pluginRegistry, w.storageClassLister, actor.GetMetadata().GetUid(), actorTemplate, volumes) // createActorVolumes reports the state it got to even when it fails, so both // paths persist the same field. updatePrecondition := store.PreconditionFrom(actor) diff --git a/cmd/ateapi/internal/controlapi/workflow_suspend.go b/cmd/ateapi/internal/controlapi/workflow_suspend.go index ec2612202b..41aa2c13ca 100644 --- a/cmd/ateapi/internal/controlapi/workflow_suspend.go +++ b/cmd/ateapi/internal/controlapi/workflow_suspend.go @@ -337,16 +337,18 @@ func newInProgressSnapshotURI(actorTemplate *ateapipb.ActorTemplate, actor *atea return uri, nil } -// ensureVolumesDetached detaches the actor's mounted external volumes from -// its worker node. Detachment is idempotent, so a re-entered workflow safely -// runs it again. spanName distinguishes the suspend and pause steps in -// traces; op labels the volume metrics. +// ensureVolumesDetached detaches the actor's mounted external volumes from its +// worker node and marks its SharedVolume references inactive. Both steps are +// idempotent; spanName distinguishes suspend from pause and op labels metrics. // TODO replace re-execution with a proper check on the volumes' attach state. func (w *ActorWorkflow) ensureVolumesDetached(ctx context.Context, actor *ateapipb.Actor, actorTemplate *ateapipb.ActorTemplate, spanName, op string) (err error) { ctx, done := stepSpan(ctx, spanName) defer func() { err = done(err) }() - return detachActorVolumes(ctx, w.pluginRegistry, actor, actorTemplate, op) + if err := detachActorVolumes(ctx, w.pluginRegistry, actor, actorTemplate, op); err != nil { + return err + } + return deactivateSharedVolumes(ctx, w.store, actor) } // ensureSuspendedFinalized releases the actor's worker (only when it is still diff --git a/cmd/ateapi/internal/controlapi/workflow_testutil_test.go b/cmd/ateapi/internal/controlapi/workflow_testutil_test.go index 52971405cb..a9ee4f5bcc 100644 --- a/cmd/ateapi/internal/controlapi/workflow_testutil_test.go +++ b/cmd/ateapi/internal/controlapi/workflow_testutil_test.go @@ -58,7 +58,7 @@ func newTestActorWorkflow(t *testing.T, st store.Interface, tmplAtespace, tmplNa }); err != nil && !errors.Is(err, store.ErrAlreadyExists) { t.Fatalf("create test ActorTemplate: %v", err) } - return NewActorWorkflow(st, nil, nil, nil, nil, nil, "", nil, objectstoreplugintest.ControlClient(objectstoretest.New())) + return NewActorWorkflow(st, nil, nil, nil, nil, nil, "", nil, objectstoreplugintest.ControlClient(objectstoretest.New()), nil) } // newFinalizeWorkflow builds an ActorWorkflow over persistence with an diff --git a/cmd/ateapi/internal/controlapi/workload_spec.go b/cmd/ateapi/internal/controlapi/workload_spec.go index 399816b818..102bf0286f 100644 --- a/cmd/ateapi/internal/controlapi/workload_spec.go +++ b/cmd/ateapi/internal/controlapi/workload_spec.go @@ -55,6 +55,12 @@ func workloadSpecFromActorTemplate(actorTemplate *ateapipb.ActorTemplate, actor // already ensured that only one source is set. for _, vol := range actorTemplate.GetVolumes() { switch { + case vol.GetExternal().GetSharedVolume() != nil && isGoldenActor(actor): + workloadSpec.Volumes = append(workloadSpec.Volumes, &ateletpb.Volume{ + Name: vol.GetName(), + EmptyDir: &ateletpb.EmptyDirVolume{}, + }) + case vol.GetDurableDir() != nil: workloadSpec.Volumes = append(workloadSpec.Volumes, &ateletpb.Volume{ Name: vol.GetName(), @@ -102,8 +108,11 @@ func workloadSpecFromActorTemplate(actorTemplate *ateapipb.ActorTemplate, actor }, }) + case vol.GetExternal().GetTemplate() != nil, vol.GetExternal().GetSharedVolume() != nil: + continue // appended by appendExternalVolumes from the actor's status + default: - continue // Drop unrecognized volumes. + return nil, fmt.Errorf("volume %q has no supported source", vol.GetName()) } } @@ -145,19 +154,22 @@ func workloadSpecFromActorTemplate(actorTemplate *ateapipb.ActorTemplate, actor return workloadSpec, nil } -// appendExternalVolumes maps template external volumes to resolved actor volumes -// and appends them to workloadSpec if they are referenced in container -// volumeMounts. volumePublishContexts carries the attachment metadata of the current -// resume by volume name; it is nil on paths that do not mount. +// appendExternalVolumes maps mounted external volumes, owned or referenced, to +// the handles recorded on the actor and appends them to workloadSpec. +// volumePublishContexts carries the attachment metadata of the current resume +// by volume name; it is nil on paths that do not mount. func appendExternalVolumes(workloadSpec *ateletpb.WorkloadSpec, template *ateapipb.ActorTemplate, actor *ateapipb.Actor, volumePublishContexts map[string]map[string]string) error { if template == nil { return nil } for _, vol := range template.GetVolumes() { - if vol.GetExternal().GetTemplate() != nil { + if vol.GetExternal().GetTemplate() != nil || vol.GetExternal().GetSharedVolume() != nil { if !isVolumeMounted(vol.GetName(), template) { continue } + if vol.GetExternal().GetSharedVolume() != nil && isGoldenActor(actor) { + continue + } if actor == nil { return fmt.Errorf("actor is required when an external volume is present") } diff --git a/cmd/ateapi/internal/controlapi/workload_spec_test.go b/cmd/ateapi/internal/controlapi/workload_spec_test.go index b6382e559f..924b3e44e0 100644 --- a/cmd/ateapi/internal/controlapi/workload_spec_test.go +++ b/cmd/ateapi/internal/controlapi/workload_spec_test.go @@ -15,9 +15,11 @@ package controlapi import ( + "strings" "testing" "github.com/agent-substrate/substrate/internal/proto/ateletpb" + "github.com/agent-substrate/substrate/internal/resources" "github.com/agent-substrate/substrate/pkg/proto/ateapipb" "github.com/google/go-cmp/cmp" "google.golang.org/protobuf/testing/protocmp" @@ -215,11 +217,12 @@ func TestWorkloadSpecFromActorTemplate(t *testing.T) { }, }, { - name: "skips non-DurableDir volumes", + name: "leaves unmounted external volumes out", template: &ateapipb.ActorTemplate{ Metadata: &ateapipb.ResourceMetadata{Atespace: "agent-ns", Name: "tmpl1"}, Volumes: []*ateapipb.Volume{ - {Name: "unsupported"}, + {Name: "borrowed", External: &ateapipb.ExternalVolumeSource{SharedVolume: &ateapipb.SharedVolumeRef{Name: "shared"}}}, + {Name: "owned", External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{StorageClassName: "standard"}}}, {Name: "home", DurableDir: &ateapipb.DurableDirVolumeSource{}}, }, Containers: []*ateapipb.Container{ @@ -642,3 +645,90 @@ func TestWorkloadSpecFromActorTemplatePropagatesResources(t *testing.T) { t.Errorf("unlimited container Resources = %v, want nil", r) } } + +func TestWorkloadSpecFromActorTemplateRejectsUnknownVolumeSource(t *testing.T) { + _, err := workloadSpecFromActorTemplate(&ateapipb.ActorTemplate{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "agent-ns", Name: "tmpl-unknown"}, + Volumes: []*ateapipb.Volume{{Name: "unsupported"}}, + }, nil, nil) + if err == nil || !strings.Contains(err.Error(), "unsupported") { + t.Fatalf("workloadSpecFromActorTemplate() error = %v, want one naming the volume", err) + } +} + +func TestWorkloadSpecBorrowedVolume(t *testing.T) { + template := &ateapipb.ActorTemplate{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "space-abc", Name: "tmpl1"}, + Volumes: []*ateapipb.Volume{ + {Name: "borrowed", External: &ateapipb.ExternalVolumeSource{SharedVolume: &ateapipb.SharedVolumeRef{}}}, + {Name: "owned", External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{StorageClassName: "standard"}}}, + }, + Containers: []*ateapipb.Container{{ + Name: "main", + VolumeMounts: []*ateapipb.VolumeMount{ + {Name: "borrowed", MountPath: "/mnt/shared"}, + {Name: "owned", MountPath: "/mnt/owned"}, + }, + }}, + } + owned := &ateletpb.Volume{ + Name: "owned", + External: &ateletpb.ExternalVolume{ + StorageVolumeId: "disk-1", + VolumeType: "pd.csi.storage.gke.io", + }, + } + + tests := []struct { + name string + actor *ateapipb.Actor + want []*ateletpb.Volume + }{ + { + name: "golden actor gets an empty dir in place of the shared volume", + actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: resources.GoldenActorAtespace, Name: "tmpl1-uid"}, + Status: &ateapipb.ActorStatus{ExternalVolumes: []*ateapipb.ExternalVolumeRef{ + {Name: "owned", StorageVolumeId: "disk-1", VolumeType: "pd.csi.storage.gke.io"}, + }}, + }, + want: []*ateletpb.Volume{ + {Name: "borrowed", EmptyDir: &ateletpb.EmptyDirVolume{}}, + owned, + }, + }, + { + name: "user actor mounts the shared volume's handle", + actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "space-abc", Name: "consumer"}, + SharedVolumeBindings: map[string]string{"borrowed": "shared"}, + Status: &ateapipb.ActorStatus{ExternalVolumes: []*ateapipb.ExternalVolumeRef{ + {Name: "borrowed", SharedVolumeName: "shared", StorageVolumeId: "disk-shared", VolumeType: "nfs.csi.k8s.io", VolumeContext: map[string]string{"server": "10.0.0.2"}}, + {Name: "owned", StorageVolumeId: "disk-1", VolumeType: "pd.csi.storage.gke.io"}, + }}, + }, + want: []*ateletpb.Volume{ + { + Name: "borrowed", + External: &ateletpb.ExternalVolume{ + StorageVolumeId: "disk-shared", + VolumeType: "nfs.csi.k8s.io", + VolumeContext: map[string]string{"server": "10.0.0.2"}, + }, + }, + owned, + }, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got, err := workloadSpecFromActorTemplate(template, tc.actor, nil) + if err != nil { + t.Fatalf("workloadSpecFromActorTemplate: %v", err) + } + if diff := cmp.Diff(tc.want, got.GetVolumes(), protocmp.Transform()); diff != "" { + t.Errorf("volumes mismatch (-want +got):\n%s", diff) + } + }) + } +} diff --git a/cmd/kubectl-ate/internal/cmd/actor.go b/cmd/kubectl-ate/internal/cmd/actor.go index 5cb3bacebf..ce2fcdef46 100644 --- a/cmd/kubectl-ate/internal/cmd/actor.go +++ b/cmd/kubectl-ate/internal/cmd/actor.go @@ -47,6 +47,7 @@ var ( createActorAtespaceFlag string createActorTemplateFlag string createActorTagFlag string + createActorVolumeFlag map[string]string deleteActorAtespaceFlag string deleteActorAnyStateFlag bool pauseActorAtespaceFlag string @@ -134,7 +135,7 @@ var createActorCmd = &cobra.Command{ Short: "Create an actor", Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - request, err := buildCreateActorRequest(args[0], createActorAtespaceFlag, createActorTemplateFlag, createActorTagFlag) + request, err := buildCreateActorRequest(args[0], createActorAtespaceFlag, createActorTemplateFlag, createActorTagFlag, createActorVolumeFlag) if err != nil { return err } @@ -260,7 +261,7 @@ var logsActorsCmd = &cobra.Command{ RunE: runLogsActor, } -func buildCreateActorRequest(actorName, atespace, template, tag string) (*ateapipb.CreateActorRequest, error) { +func buildCreateActorRequest(actorName, atespace, template, tag string, volumes map[string]string) (*ateapipb.CreateActorRequest, error) { templateRef, err := parseAtespacedName(template, atespace) if err != nil { return nil, err @@ -272,6 +273,9 @@ func buildCreateActorRequest(actorName, atespace, template, tag string) (*ateapi }, ActorTemplate: templateRef, } + if len(volumes) > 0 { + actor.SharedVolumeBindings = volumes + } if tag != "" { ref, err := parseAtespacedName(tag, atespace) @@ -735,6 +739,7 @@ func init() { createActorCmd.Flags().StringVarP(&createActorAtespaceFlag, "atespace", "a", "", "Atespace to create the actor in") _ = createActorCmd.MarkFlagRequired("atespace") createActorCmd.Flags().StringVar(&createActorTagFlag, "tag", "", "The name of a Tag to initialize the actor from, as /, or just to use the actor's own atespace (--atespace)") + createActorCmd.Flags().StringToStringVar(&createActorVolumeFlag, "volume", nil, "Bind an unnamed external.sharedVolume in the template to a SharedVolume, as =; repeatable") createCmd.AddCommand(createActorCmd) deleteActorCmd.Flags().StringVarP(&deleteActorAtespaceFlag, "atespace", "a", "", "Atespace the actor lives in") diff --git a/cmd/kubectl-ate/internal/cmd/actor_test.go b/cmd/kubectl-ate/internal/cmd/actor_test.go index 2c3f36cf4a..795114d8d3 100644 --- a/cmd/kubectl-ate/internal/cmd/actor_test.go +++ b/cmd/kubectl-ate/internal/cmd/actor_test.go @@ -48,6 +48,7 @@ func TestBuildCreateActorRequest(t *testing.T) { name string templateRef string tag string + volumes map[string]string want *ateapipb.Actor wantErr bool }{ @@ -87,13 +88,23 @@ func TestBuildCreateActorRequest(t *testing.T) { ActorTemplate: &ateapipb.ObjectRef{Atespace: "shared-templates", Name: "counter"}, }, }, + { + name: "volume bindings", + templateRef: "counter", + volumes: map[string]string{"shared": "ctx-42"}, + want: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "demo", Name: "my-counter"}, + ActorTemplate: &ateapipb.ObjectRef{Atespace: "demo", Name: "counter"}, + SharedVolumeBindings: map[string]string{"shared": "ctx-42"}, + }, + }, {name: "malformed template ref", templateRef: "a/b/c", wantErr: true}, {name: "malformed tag", templateRef: "counter", tag: "a/b/c", wantErr: true}, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got, err := buildCreateActorRequest("my-counter", "demo", test.templateRef, test.tag) + got, err := buildCreateActorRequest("my-counter", "demo", test.templateRef, test.tag, test.volumes) if (err != nil) != test.wantErr { t.Fatalf("buildCreateActorRequest error = %v, wantErr %t", err, test.wantErr) } diff --git a/docs/csi-volumes.md b/docs/csi-volumes.md index 347a98c87d..4120dcf903 100644 --- a/docs/csi-volumes.md +++ b/docs/csi-volumes.md @@ -192,3 +192,44 @@ volumes: capacity: 5Gi storageClassName: csi-nfs-sc ``` + +## 5. Shared Volumes + +A `SharedVolume` is an atespace-scoped CSI volume whose lifetime is +independent of any actor, so several actors can mount the same storage in turn. +Create one from a StorageClass, or register a volume that already exists: + +```bash +kubectl ate create sharedvolume ctx-42 -a demo --storage-class csi-nfs-sc --capacity 10Gi +kubectl ate create sharedvolume imported -a demo --volume-id --volume-type nfs.csi.k8s.io +``` + +Each volume records: + +- `accessMode`: fixed at create. Only `READ_WRITE_ONCE` is accepted today, so + at most one resumed actor holds the volume; a resume that would take a held + volume fails and names the holder. +- `deleteTrigger`: `MANUAL` removes the volume only on an explicit delete; + `LAST_ACTOR` removes it when the last actor referencing it is deleted. + Provisioned volumes default to `LAST_ACTOR`, registered ones to `MANUAL`. + Deleting the volume also deletes the storage. +- `status.refs`: every actor referencing the volume, with `active` set while + the actor is resumed. A referenced volume cannot be deleted. + +A template mounts a `SharedVolume` with `external.sharedVolume`. Name the volume +in the template, or leave the name empty and bind it per actor at creation: + +```yaml +volumes: +- name: shared + external: {sharedVolume: {}} +``` + +```bash +kubectl ate create actor producer-42 -a demo --template producer --volume shared=ctx-42 +kubectl ate create actor consumer-42 -a demo --template consumer --volume shared=ctx-42 +``` + +Bindings are validated and recorded when the actor is created and cannot change +afterwards. Golden actors never reference a shared volume; they warm up against +an empty directory at the same mount path. diff --git a/internal/e2e/suites/combinedvolumes/combinedvolumes_test.go b/internal/e2e/suites/combinedvolumes/combinedvolumes_test.go index 7fed2c5938..a03f62253d 100644 --- a/internal/e2e/suites/combinedvolumes/combinedvolumes_test.go +++ b/internal/e2e/suites/combinedvolumes/combinedvolumes_test.go @@ -40,6 +40,8 @@ import ( "github.com/google/go-containerregistry/pkg/v1/mutate" "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/google/go-containerregistry/pkg/v1/tarball" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -68,6 +70,10 @@ const ( // probeWrittenContent is the fixed string the probe's /writefile writes. probeWrittenContent = "written by probe" + sharedVolume = "shared" + sharedPath = "/mnt/ate-shared" + sharedFile = "handoff.txt" + payloadName = "payload.txt" payloadContent = "delivered by an image volume" // shadowedName is written by two layers; the upper one must win. @@ -461,3 +467,174 @@ func TestCombinedVolumes(t *testing.T) { }) }) } + +// createHandoffTemplate builds a probe ActorTemplate that references the +// SharedVolume named volumeName. +func createHandoffTemplate(ctx context.Context, t *testing.T, clients *e2e.Clients, ns *e2e.Namespace, volumeName string) *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"], "combinedvolumes") + src := e2e.SubstrateFixture{ + Atespace: probeAtespace, + Name: probeName, + PoolNamespace: probeAtespace, + PoolName: probeName, + DeployWith: "the combinedvolumes suite's own DeployProbe", + } + return e2e.CreateSubstrateTemplateFrom(ctx, t, clients, ns.Name, src, e2e.SubstrateTemplateOptions{ + Atespace: atespace, + Name: "handoff-" + ns.Name, + PoolName: probeName, + PoolReplicas: 2, + Labels: map[string]string{"combinedvolumes": 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: sharedVolume, MountPath: sharedPath}) + tmpl.Volumes = append(tmpl.Volumes, &ateapipb.Volume{ + Name: sharedVolume, + External: &ateapipb.ExternalVolumeSource{SharedVolume: &ateapipb.SharedVolumeRef{Name: volumeName}}, + }) + }, + }) +} + +// createHandoffActor creates a suspended actor from tmpl and registers its +// teardown, which must run before the shared volume's. +func createHandoffActor(ctx context.Context, t *testing.T, clients *e2e.Clients, tmpl *ateapipb.ActorTemplate, name string) resources.ActorRef { + t.Helper() + + actorRef := resources.ActorRef{Atespace: atespace, Name: name} + if _, err := clients.SubstrateAPI.CreateActor(ctx, &ateapipb.CreateActorRequest{ + Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: actorRef.Atespace, Name: actorRef.Name}, + ActorTemplate: e2e.TemplateRef(tmpl), + }, + }); err != nil { + t.Fatalf("CreateActor(%s): %v", name, err) + } + t.Cleanup(func() { + cleanupCtx := context.Background() + _, _ = clients.SubstrateAPI.SuspendActor(cleanupCtx, &ateapipb.SuspendActorRequest{Actor: actorRef.ToObjectRef()}) + _, _ = clients.SubstrateAPI.DeleteActor(cleanupCtx, &ateapipb.DeleteActorRequest{Actor: actorRef.ToObjectRef()}) + }) + return actorRef +} + +func TestSharedVolumeHandoff(t *testing.T) { + ctx := context.Background() + clients := e2e.GetClients() + ns := e2e.CreateNamespace(t) + + if storageClassOrEmpty(ctx, t, clients) == "" { + t.Skipf("StorageClass %q is not installed", e2e.StorageClass) + } + + volumeName := "shared-" + ns.Name + // The template is created first because it creates the suite's atespace. + tmpl := createHandoffTemplate(ctx, t, clients, ns, volumeName) + + volumeRef := &ateapipb.ObjectRef{Atespace: atespace, Name: volumeName} + if _, err := clients.SubstrateAPI.CreateSharedVolume(ctx, &ateapipb.CreateSharedVolumeRequest{ + SharedVolume: &ateapipb.SharedVolume{ + Metadata: &ateapipb.ResourceMetadata{Atespace: atespace, Name: volumeName}, + StorageClassName: e2e.StorageClass, + Capacity: extCapacity, + DeleteTrigger: ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL, + }, + }); err != nil { + t.Fatalf("CreateSharedVolume: %v", err) + } + t.Cleanup(func() { + if _, err := clients.SubstrateAPI.DeleteSharedVolume(context.Background(), &ateapipb.DeleteSharedVolumeRequest{SharedVolume: volumeRef}); err != nil { + t.Errorf("DeleteSharedVolume: %v", err) + } + }) + + producer := createHandoffActor(ctx, t, clients, tmpl, "producer-"+ns.Name) + consumer := createHandoffActor(ctx, t, clients, tmpl, "consumer-"+ns.Name) + + router, err := e2e.NewRouterClient(ctx) + if err != nil { + t.Fatalf("NewRouterClient: %v", err) + } + defer router.Close() + + handoffFile := sharedPath + "/" + sharedFile + if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapipb.ResumeActorRequest{Actor: producer.ToObjectRef()}); err != nil { + t.Fatalf("ResumeActor(producer): %v", err) + } + requireUnreadable(ctx, t, router, producer, handoffFile) + if got := probeJSON(ctx, t, router, producer, "/writefile?path="+handoffFile); got["error"] != "" { + t.Fatalf("writing %s: %s", handoffFile, got["error"]) + } + requireContent(ctx, t, router, producer, handoffFile, probeWrittenContent) + + _, err = e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapipb.ResumeActorRequest{Actor: consumer.ToObjectRef()}) + if status.Code(err) != codes.FailedPrecondition || !strings.Contains(err.Error(), producer.Name) { + t.Fatalf("ResumeActor(consumer) while the producer holds the volume = %v, want FailedPrecondition naming %q", err, producer.Name) + } + blocked, err := clients.SubstrateAPI.GetActor(ctx, &ateapipb.GetActorRequest{Actor: consumer.ToObjectRef()}) + if err != nil { + t.Fatalf("GetActor(consumer): %v", err) + } + if got := blocked.GetStatus().GetState(); got != ateapipb.ActorState_ACTOR_STATE_SUSPENDED { + t.Errorf("consumer state after a refused claim = %s, want ACTOR_STATE_SUSPENDED", got) + } + + if _, err := clients.SubstrateAPI.SuspendActor(ctx, &ateapipb.SuspendActorRequest{Actor: producer.ToObjectRef()}); err != nil { + t.Fatalf("SuspendActor(producer): %v", err) + } + if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapipb.ResumeActorRequest{Actor: consumer.ToObjectRef()}); err != nil { + t.Fatalf("ResumeActor(consumer): %v", err) + } + requireContent(ctx, t, router, consumer, handoffFile, probeWrittenContent) + + if _, err := clients.SubstrateAPI.DeleteSharedVolume(ctx, &ateapipb.DeleteSharedVolumeRequest{SharedVolume: volumeRef}); status.Code(err) != codes.FailedPrecondition { + t.Errorf("DeleteSharedVolume while referenced = %v, want FailedPrecondition", err) + } + stored, err := clients.SubstrateAPI.GetSharedVolume(ctx, &ateapipb.GetSharedVolumeRequest{SharedVolume: volumeRef}) + if err != nil { + t.Fatalf("GetSharedVolume: %v", err) + } + actor, err := clients.SubstrateAPI.GetActor(ctx, &ateapipb.GetActorRequest{Actor: consumer.ToObjectRef()}) + if err != nil { + t.Fatalf("GetActor(consumer): %v", err) + } + var mounted string + for _, vol := range actor.GetStatus().GetExternalVolumes() { + if vol.GetName() == sharedVolume { + mounted = vol.GetStorageVolumeId() + } + } + if mounted != stored.GetVolumeId() { + t.Errorf("the consumer mounted %q, want the shared volume %q", mounted, stored.GetVolumeId()) + } +} + +func TestSharedVolumeMissing(t *testing.T) { + ctx := context.Background() + clients := e2e.GetClients() + ns := e2e.CreateNamespace(t) + + if storageClassOrEmpty(ctx, t, clients) == "" { + t.Skipf("StorageClass %q is not installed", e2e.StorageClass) + } + + tmpl := createHandoffTemplate(ctx, t, clients, ns, "absent-"+ns.Name) + _, err := clients.SubstrateAPI.CreateActor(ctx, &ateapipb.CreateActorRequest{ + Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: atespace, Name: "orphan-" + ns.Name}, + ActorTemplate: e2e.TemplateRef(tmpl), + }, + }) + if status.Code(err) != codes.FailedPrecondition { + t.Fatalf("CreateActor with an unresolvable volume reference = %v, want FailedPrecondition", err) + } +} diff --git a/pkg/proto/ateapipb/ateapi.pb.go b/pkg/proto/ateapipb/ateapi.pb.go index 2fe3a7dd30..edfdb214d0 100644 --- a/pkg/proto/ateapipb/ateapi.pb.go +++ b/pkg/proto/ateapipb/ateapi.pb.go @@ -1216,8 +1216,16 @@ type ExternalVolumeRef struct { // +k8s:optional // +k8s:customValidation # at most 40 KiB in total, ten times the CSI limit for map fields VolumeContext map[string]string `protobuf:"bytes,5,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 + // shared_volume_name names the SharedVolume this mount references, in the + // actor's atespace. Empty when the actor owns the volume itself. + // + // +k8s:optional + // +k8s:format=k8s-short-name + // +k8s:update=NoModify + // +k8s:update=NoUnset + SharedVolumeName string `protobuf:"bytes,6,opt,name=shared_volume_name,json=sharedVolumeName,proto3" json:"shared_volume_name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ExternalVolumeRef) Reset() { @@ -1285,6 +1293,13 @@ func (x *ExternalVolumeRef) GetVolumeContext() map[string]string { return nil } +func (x *ExternalVolumeRef) GetSharedVolumeName() string { + if x != nil { + return x.SharedVolumeName + } + return "" +} + type Actor struct { state protoimpl.MessageState `protogen:"open.v1"` // Common resource metadata: atespace, name, uid, version, timestamps. @@ -1316,9 +1331,19 @@ 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"` + // shared_volume_bindings maps each unnamed external.shared_volume in the + // template, by volume name, to the SharedVolume this actor mounts. Every + // unnamed ref must be bound; a named ref cannot be rebound. Set at creation. + // + // +k8s:optional + // +k8s:maxProperties=32 + // +k8s:eachKey=+k8s:format=k8s-short-name + // +k8s:eachVal=+k8s:format=k8s-short-name + // +k8s:immutable + SharedVolumeBindings map[string]string `protobuf:"bytes,8,rep,name=shared_volume_bindings,json=sharedVolumeBindings,proto3" json:"shared_volume_bindings,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Actor) Reset() { @@ -1386,6 +1411,13 @@ func (x *Actor) GetStatus() *ActorStatus { return nil } +func (x *Actor) GetSharedVolumeBindings() map[string]string { + if x != nil { + return x.SharedVolumeBindings + } + return nil +} + // EgressPolicy is an egress policy resource nested under an Actor. An Actor has // at most one egress policy resource, named "default". type EgressPolicy struct { @@ -4188,7 +4220,12 @@ type ExternalVolumeSource struct { // // +k8s:optional // +k8s:unionMember - Template *ExternalVolumeTemplate `protobuf:"bytes,1,opt,name=template,proto3" json:"template,omitempty"` + Template *ExternalVolumeTemplate `protobuf:"bytes,1,opt,name=template,proto3" json:"template,omitempty"` + // shared_volume mounts a SharedVolume that already exists. + // + // +k8s:optional + // +k8s:unionMember + SharedVolume *SharedVolumeRef `protobuf:"bytes,2,opt,name=shared_volume,json=sharedVolume,proto3" json:"shared_volume,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -4230,6 +4267,13 @@ func (x *ExternalVolumeSource) GetTemplate() *ExternalVolumeTemplate { return nil } +func (x *ExternalVolumeSource) GetSharedVolume() *SharedVolumeRef { + if x != nil { + return x.SharedVolume + } + return nil +} + // ImageVolumeSource mounts the contents of an OCI image, read-only. The // reference must include a digest: changing the image invalidates // snapshots. @@ -4386,6 +4430,57 @@ func (x *ExternalVolumeTemplate) GetStorageClassName() string { return "" } +// SharedVolumeRef mounts a SharedVolume in the actor's atespace. The +// volume outlives the actor, so several actors can mount it in turn. +type SharedVolumeRef struct { + state protoimpl.MessageState `protogen:"open.v1"` + // name of the SharedVolume. Left empty, the actor names it at creation in + // Actor.shared_volume_bindings. + // + // +k8s:optional + // +k8s:format=k8s-short-name + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SharedVolumeRef) Reset() { + *x = SharedVolumeRef{} + mi := &file_ateapi_proto_msgTypes[46] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SharedVolumeRef) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SharedVolumeRef) ProtoMessage() {} + +func (x *SharedVolumeRef) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[46] + 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 SharedVolumeRef.ProtoReflect.Descriptor instead. +func (*SharedVolumeRef) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{46} +} + +func (x *SharedVolumeRef) GetName() string { + if x != nil { + return x.Name + } + return "" +} + // SystemInfoVolumeSource is a read-only volume of substrate-generated // per-actor files (identity fields, projected trust bundles), regenerated by // atelet on every Run/Restore. @@ -4406,7 +4501,7 @@ type SystemInfoVolumeSource struct { func (x *SystemInfoVolumeSource) Reset() { *x = SystemInfoVolumeSource{} - mi := &file_ateapi_proto_msgTypes[46] + mi := &file_ateapi_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4418,7 +4513,7 @@ func (x *SystemInfoVolumeSource) String() string { func (*SystemInfoVolumeSource) ProtoMessage() {} func (x *SystemInfoVolumeSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[46] + mi := &file_ateapi_proto_msgTypes[47] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4431,7 +4526,7 @@ func (x *SystemInfoVolumeSource) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemInfoVolumeSource.ProtoReflect.Descriptor instead. func (*SystemInfoVolumeSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{46} + return file_ateapi_proto_rawDescGZIP(), []int{47} } func (x *SystemInfoVolumeSource) GetDataSources() []*SystemInfoDataSource { @@ -4457,7 +4552,7 @@ type SystemInfoDataSource struct { func (x *SystemInfoDataSource) Reset() { *x = SystemInfoDataSource{} - mi := &file_ateapi_proto_msgTypes[47] + mi := &file_ateapi_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4469,7 +4564,7 @@ func (x *SystemInfoDataSource) String() string { func (*SystemInfoDataSource) ProtoMessage() {} func (x *SystemInfoDataSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[47] + mi := &file_ateapi_proto_msgTypes[48] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4482,7 +4577,7 @@ func (x *SystemInfoDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemInfoDataSource.ProtoReflect.Descriptor instead. func (*SystemInfoDataSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{47} + return file_ateapi_proto_rawDescGZIP(), []int{48} } func (x *SystemInfoDataSource) GetActorMetadata() *ActorMetadataDataSource { @@ -4519,7 +4614,7 @@ type ActorMetadataDataSource struct { func (x *ActorMetadataDataSource) Reset() { *x = ActorMetadataDataSource{} - mi := &file_ateapi_proto_msgTypes[48] + mi := &file_ateapi_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4531,7 +4626,7 @@ func (x *ActorMetadataDataSource) String() string { func (*ActorMetadataDataSource) ProtoMessage() {} func (x *ActorMetadataDataSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[48] + mi := &file_ateapi_proto_msgTypes[49] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4544,7 +4639,7 @@ func (x *ActorMetadataDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorMetadataDataSource.ProtoReflect.Descriptor instead. func (*ActorMetadataDataSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{48} + return file_ateapi_proto_rawDescGZIP(), []int{49} } func (x *ActorMetadataDataSource) GetItems() []*ActorMetadataItem { @@ -4576,7 +4671,7 @@ type ActorMetadataItem struct { func (x *ActorMetadataItem) Reset() { *x = ActorMetadataItem{} - mi := &file_ateapi_proto_msgTypes[49] + mi := &file_ateapi_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4588,7 +4683,7 @@ func (x *ActorMetadataItem) String() string { func (*ActorMetadataItem) ProtoMessage() {} func (x *ActorMetadataItem) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[49] + mi := &file_ateapi_proto_msgTypes[50] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4601,7 +4696,7 @@ func (x *ActorMetadataItem) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorMetadataItem.ProtoReflect.Descriptor instead. func (*ActorMetadataItem) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{49} + return file_ateapi_proto_rawDescGZIP(), []int{50} } func (x *ActorMetadataItem) GetField() ActorMetadataField { @@ -4653,7 +4748,7 @@ type TrustBundleDataSource struct { func (x *TrustBundleDataSource) Reset() { *x = TrustBundleDataSource{} - mi := &file_ateapi_proto_msgTypes[50] + mi := &file_ateapi_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4665,7 +4760,7 @@ func (x *TrustBundleDataSource) String() string { func (*TrustBundleDataSource) ProtoMessage() {} func (x *TrustBundleDataSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[50] + mi := &file_ateapi_proto_msgTypes[51] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4678,7 +4773,7 @@ func (x *TrustBundleDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use TrustBundleDataSource.ProtoReflect.Descriptor instead. func (*TrustBundleDataSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{50} + return file_ateapi_proto_rawDescGZIP(), []int{51} } func (x *TrustBundleDataSource) GetNames() []string { @@ -4717,7 +4812,7 @@ type VolumeMount struct { func (x *VolumeMount) Reset() { *x = VolumeMount{} - mi := &file_ateapi_proto_msgTypes[51] + mi := &file_ateapi_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4729,7 +4824,7 @@ func (x *VolumeMount) String() string { func (*VolumeMount) ProtoMessage() {} func (x *VolumeMount) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[51] + mi := &file_ateapi_proto_msgTypes[52] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4742,7 +4837,7 @@ func (x *VolumeMount) ProtoReflect() protoreflect.Message { // Deprecated: Use VolumeMount.ProtoReflect.Descriptor instead. func (*VolumeMount) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{51} + return file_ateapi_proto_rawDescGZIP(), []int{52} } func (x *VolumeMount) GetName() string { @@ -4771,7 +4866,7 @@ type CreateAtespaceRequest struct { func (x *CreateAtespaceRequest) Reset() { *x = CreateAtespaceRequest{} - mi := &file_ateapi_proto_msgTypes[52] + mi := &file_ateapi_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4783,7 +4878,7 @@ func (x *CreateAtespaceRequest) String() string { func (*CreateAtespaceRequest) ProtoMessage() {} func (x *CreateAtespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[52] + mi := &file_ateapi_proto_msgTypes[53] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4796,7 +4891,7 @@ func (x *CreateAtespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateAtespaceRequest.ProtoReflect.Descriptor instead. func (*CreateAtespaceRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{52} + return file_ateapi_proto_rawDescGZIP(), []int{53} } func (x *CreateAtespaceRequest) GetAtespace() *Atespace { @@ -4817,7 +4912,7 @@ type GetAtespaceRequest struct { func (x *GetAtespaceRequest) Reset() { *x = GetAtespaceRequest{} - mi := &file_ateapi_proto_msgTypes[53] + mi := &file_ateapi_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4829,7 +4924,7 @@ func (x *GetAtespaceRequest) String() string { func (*GetAtespaceRequest) ProtoMessage() {} func (x *GetAtespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[53] + mi := &file_ateapi_proto_msgTypes[54] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4842,7 +4937,7 @@ func (x *GetAtespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAtespaceRequest.ProtoReflect.Descriptor instead. func (*GetAtespaceRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{53} + return file_ateapi_proto_rawDescGZIP(), []int{54} } func (x *GetAtespaceRequest) GetAtespace() *ObjectRef { @@ -4873,7 +4968,7 @@ type ListAtespacesRequest struct { func (x *ListAtespacesRequest) Reset() { *x = ListAtespacesRequest{} - mi := &file_ateapi_proto_msgTypes[54] + mi := &file_ateapi_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4885,7 +4980,7 @@ func (x *ListAtespacesRequest) String() string { func (*ListAtespacesRequest) ProtoMessage() {} func (x *ListAtespacesRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[54] + mi := &file_ateapi_proto_msgTypes[55] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4898,7 +4993,7 @@ func (x *ListAtespacesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAtespacesRequest.ProtoReflect.Descriptor instead. func (*ListAtespacesRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{54} + return file_ateapi_proto_rawDescGZIP(), []int{55} } func (x *ListAtespacesRequest) GetPageSize() int32 { @@ -4927,7 +5022,7 @@ type ListAtespacesResponse struct { func (x *ListAtespacesResponse) Reset() { *x = ListAtespacesResponse{} - mi := &file_ateapi_proto_msgTypes[55] + mi := &file_ateapi_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4939,7 +5034,7 @@ func (x *ListAtespacesResponse) String() string { func (*ListAtespacesResponse) ProtoMessage() {} func (x *ListAtespacesResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[55] + mi := &file_ateapi_proto_msgTypes[56] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4952,7 +5047,7 @@ func (x *ListAtespacesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAtespacesResponse.ProtoReflect.Descriptor instead. func (*ListAtespacesResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{55} + return file_ateapi_proto_rawDescGZIP(), []int{56} } func (x *ListAtespacesResponse) GetAtespaces() []*Atespace { @@ -4984,7 +5079,7 @@ type DeleteAtespaceRequest struct { func (x *DeleteAtespaceRequest) Reset() { *x = DeleteAtespaceRequest{} - mi := &file_ateapi_proto_msgTypes[56] + mi := &file_ateapi_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4996,7 +5091,7 @@ func (x *DeleteAtespaceRequest) String() string { func (*DeleteAtespaceRequest) ProtoMessage() {} func (x *DeleteAtespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[56] + mi := &file_ateapi_proto_msgTypes[57] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5009,7 +5104,7 @@ func (x *DeleteAtespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteAtespaceRequest.ProtoReflect.Descriptor instead. func (*DeleteAtespaceRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{56} + return file_ateapi_proto_rawDescGZIP(), []int{57} } func (x *DeleteAtespaceRequest) GetAtespace() *ObjectRef { @@ -5040,7 +5135,7 @@ type CreateActorTemplateRequest struct { func (x *CreateActorTemplateRequest) Reset() { *x = CreateActorTemplateRequest{} - mi := &file_ateapi_proto_msgTypes[57] + mi := &file_ateapi_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5052,7 +5147,7 @@ func (x *CreateActorTemplateRequest) String() string { func (*CreateActorTemplateRequest) ProtoMessage() {} func (x *CreateActorTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[57] + mi := &file_ateapi_proto_msgTypes[58] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5065,7 +5160,7 @@ func (x *CreateActorTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateActorTemplateRequest.ProtoReflect.Descriptor instead. func (*CreateActorTemplateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{57} + return file_ateapi_proto_rawDescGZIP(), []int{58} } func (x *CreateActorTemplateRequest) GetActorTemplate() *ActorTemplate { @@ -5086,7 +5181,7 @@ type GetActorTemplateRequest struct { func (x *GetActorTemplateRequest) Reset() { *x = GetActorTemplateRequest{} - mi := &file_ateapi_proto_msgTypes[58] + mi := &file_ateapi_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5098,7 +5193,7 @@ func (x *GetActorTemplateRequest) String() string { func (*GetActorTemplateRequest) ProtoMessage() {} func (x *GetActorTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[58] + mi := &file_ateapi_proto_msgTypes[59] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5111,7 +5206,7 @@ func (x *GetActorTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorTemplateRequest.ProtoReflect.Descriptor instead. func (*GetActorTemplateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{58} + return file_ateapi_proto_rawDescGZIP(), []int{59} } func (x *GetActorTemplateRequest) GetActorTemplate() *ObjectRef { @@ -5148,7 +5243,7 @@ type ListActorTemplatesRequest struct { func (x *ListActorTemplatesRequest) Reset() { *x = ListActorTemplatesRequest{} - mi := &file_ateapi_proto_msgTypes[59] + mi := &file_ateapi_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5160,7 +5255,7 @@ func (x *ListActorTemplatesRequest) String() string { func (*ListActorTemplatesRequest) ProtoMessage() {} func (x *ListActorTemplatesRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[59] + mi := &file_ateapi_proto_msgTypes[60] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5173,7 +5268,7 @@ func (x *ListActorTemplatesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorTemplatesRequest.ProtoReflect.Descriptor instead. func (*ListActorTemplatesRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{59} + return file_ateapi_proto_rawDescGZIP(), []int{60} } func (x *ListActorTemplatesRequest) GetAtespace() string { @@ -5210,7 +5305,7 @@ type ListActorTemplatesResponse struct { func (x *ListActorTemplatesResponse) Reset() { *x = ListActorTemplatesResponse{} - mi := &file_ateapi_proto_msgTypes[60] + mi := &file_ateapi_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5222,7 +5317,7 @@ func (x *ListActorTemplatesResponse) String() string { func (*ListActorTemplatesResponse) ProtoMessage() {} func (x *ListActorTemplatesResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[60] + mi := &file_ateapi_proto_msgTypes[61] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5235,7 +5330,7 @@ func (x *ListActorTemplatesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorTemplatesResponse.ProtoReflect.Descriptor instead. func (*ListActorTemplatesResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{60} + return file_ateapi_proto_rawDescGZIP(), []int{61} } func (x *ListActorTemplatesResponse) GetActorTemplates() []*ActorTemplate { @@ -5267,7 +5362,7 @@ type DeleteActorTemplateRequest struct { func (x *DeleteActorTemplateRequest) Reset() { *x = DeleteActorTemplateRequest{} - mi := &file_ateapi_proto_msgTypes[61] + mi := &file_ateapi_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5279,7 +5374,7 @@ func (x *DeleteActorTemplateRequest) String() string { func (*DeleteActorTemplateRequest) ProtoMessage() {} func (x *DeleteActorTemplateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[61] + mi := &file_ateapi_proto_msgTypes[62] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5292,7 +5387,7 @@ func (x *DeleteActorTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteActorTemplateRequest.ProtoReflect.Descriptor instead. func (*DeleteActorTemplateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{61} + return file_ateapi_proto_rawDescGZIP(), []int{62} } func (x *DeleteActorTemplateRequest) GetActorTemplate() *ObjectRef { @@ -5320,7 +5415,7 @@ type GetActorRequest struct { func (x *GetActorRequest) Reset() { *x = GetActorRequest{} - mi := &file_ateapi_proto_msgTypes[62] + mi := &file_ateapi_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5332,7 +5427,7 @@ func (x *GetActorRequest) String() string { func (*GetActorRequest) ProtoMessage() {} func (x *GetActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[62] + mi := &file_ateapi_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5345,7 +5440,7 @@ func (x *GetActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorRequest.ProtoReflect.Descriptor instead. func (*GetActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{62} + return file_ateapi_proto_rawDescGZIP(), []int{63} } func (x *GetActorRequest) GetActor() *ObjectRef { @@ -5368,7 +5463,7 @@ type CreateActorRequest struct { func (x *CreateActorRequest) Reset() { *x = CreateActorRequest{} - mi := &file_ateapi_proto_msgTypes[63] + mi := &file_ateapi_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5380,7 +5475,7 @@ func (x *CreateActorRequest) String() string { func (*CreateActorRequest) ProtoMessage() {} func (x *CreateActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[63] + mi := &file_ateapi_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5393,7 +5488,7 @@ func (x *CreateActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateActorRequest.ProtoReflect.Descriptor instead. func (*CreateActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{63} + return file_ateapi_proto_rawDescGZIP(), []int{64} } func (x *CreateActorRequest) GetActor() *Actor { @@ -5424,7 +5519,7 @@ type UpdateActorRequest struct { func (x *UpdateActorRequest) Reset() { *x = UpdateActorRequest{} - mi := &file_ateapi_proto_msgTypes[64] + mi := &file_ateapi_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5436,7 +5531,7 @@ func (x *UpdateActorRequest) String() string { func (*UpdateActorRequest) ProtoMessage() {} func (x *UpdateActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[64] + mi := &file_ateapi_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5449,7 +5544,7 @@ func (x *UpdateActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateActorRequest.ProtoReflect.Descriptor instead. func (*UpdateActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{64} + return file_ateapi_proto_rawDescGZIP(), []int{65} } func (x *UpdateActorRequest) GetActor() *Actor { @@ -5470,7 +5565,7 @@ type SuspendActorRequest struct { func (x *SuspendActorRequest) Reset() { *x = SuspendActorRequest{} - mi := &file_ateapi_proto_msgTypes[65] + mi := &file_ateapi_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5482,7 +5577,7 @@ func (x *SuspendActorRequest) String() string { func (*SuspendActorRequest) ProtoMessage() {} func (x *SuspendActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[65] + mi := &file_ateapi_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5495,7 +5590,7 @@ func (x *SuspendActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SuspendActorRequest.ProtoReflect.Descriptor instead. func (*SuspendActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{65} + return file_ateapi_proto_rawDescGZIP(), []int{66} } func (x *SuspendActorRequest) GetActor() *ObjectRef { @@ -5514,7 +5609,7 @@ type SuspendActorResponse struct { func (x *SuspendActorResponse) Reset() { *x = SuspendActorResponse{} - mi := &file_ateapi_proto_msgTypes[66] + mi := &file_ateapi_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5526,7 +5621,7 @@ func (x *SuspendActorResponse) String() string { func (*SuspendActorResponse) ProtoMessage() {} func (x *SuspendActorResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[66] + mi := &file_ateapi_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5539,7 +5634,7 @@ func (x *SuspendActorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SuspendActorResponse.ProtoReflect.Descriptor instead. func (*SuspendActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{66} + return file_ateapi_proto_rawDescGZIP(), []int{67} } func (x *SuspendActorResponse) GetActor() *Actor { @@ -5560,7 +5655,7 @@ type PauseActorRequest struct { func (x *PauseActorRequest) Reset() { *x = PauseActorRequest{} - mi := &file_ateapi_proto_msgTypes[67] + mi := &file_ateapi_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5572,7 +5667,7 @@ func (x *PauseActorRequest) String() string { func (*PauseActorRequest) ProtoMessage() {} func (x *PauseActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[67] + mi := &file_ateapi_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5585,7 +5680,7 @@ func (x *PauseActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PauseActorRequest.ProtoReflect.Descriptor instead. func (*PauseActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{67} + return file_ateapi_proto_rawDescGZIP(), []int{68} } func (x *PauseActorRequest) GetActor() *ObjectRef { @@ -5604,7 +5699,7 @@ type PauseActorResponse struct { func (x *PauseActorResponse) Reset() { *x = PauseActorResponse{} - mi := &file_ateapi_proto_msgTypes[68] + mi := &file_ateapi_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5616,7 +5711,7 @@ func (x *PauseActorResponse) String() string { func (*PauseActorResponse) ProtoMessage() {} func (x *PauseActorResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[68] + mi := &file_ateapi_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5629,7 +5724,7 @@ func (x *PauseActorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PauseActorResponse.ProtoReflect.Descriptor instead. func (*PauseActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{68} + return file_ateapi_proto_rawDescGZIP(), []int{69} } func (x *PauseActorResponse) GetActor() *Actor { @@ -5650,7 +5745,7 @@ type ResumeActorRequest struct { func (x *ResumeActorRequest) Reset() { *x = ResumeActorRequest{} - mi := &file_ateapi_proto_msgTypes[69] + mi := &file_ateapi_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5662,7 +5757,7 @@ func (x *ResumeActorRequest) String() string { func (*ResumeActorRequest) ProtoMessage() {} func (x *ResumeActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[69] + mi := &file_ateapi_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5675,7 +5770,7 @@ func (x *ResumeActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ResumeActorRequest.ProtoReflect.Descriptor instead. func (*ResumeActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{69} + return file_ateapi_proto_rawDescGZIP(), []int{70} } func (x *ResumeActorRequest) GetActor() *ObjectRef { @@ -5697,7 +5792,7 @@ type ResumeActorResponse struct { func (x *ResumeActorResponse) Reset() { *x = ResumeActorResponse{} - mi := &file_ateapi_proto_msgTypes[70] + mi := &file_ateapi_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5709,7 +5804,7 @@ func (x *ResumeActorResponse) String() string { func (*ResumeActorResponse) ProtoMessage() {} func (x *ResumeActorResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[70] + mi := &file_ateapi_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5722,7 +5817,7 @@ func (x *ResumeActorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ResumeActorResponse.ProtoReflect.Descriptor instead. func (*ResumeActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{70} + return file_ateapi_proto_rawDescGZIP(), []int{71} } func (x *ResumeActorResponse) GetActor() *Actor { @@ -5752,7 +5847,7 @@ type RevertActorRequest struct { func (x *RevertActorRequest) Reset() { *x = RevertActorRequest{} - mi := &file_ateapi_proto_msgTypes[71] + mi := &file_ateapi_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5764,7 +5859,7 @@ func (x *RevertActorRequest) String() string { func (*RevertActorRequest) ProtoMessage() {} func (x *RevertActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[71] + mi := &file_ateapi_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5777,7 +5872,7 @@ func (x *RevertActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RevertActorRequest.ProtoReflect.Descriptor instead. func (*RevertActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{71} + return file_ateapi_proto_rawDescGZIP(), []int{72} } func (x *RevertActorRequest) GetActor() *ObjectRef { @@ -5799,7 +5894,7 @@ type RevertActorResponse struct { func (x *RevertActorResponse) Reset() { *x = RevertActorResponse{} - mi := &file_ateapi_proto_msgTypes[72] + mi := &file_ateapi_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5811,7 +5906,7 @@ func (x *RevertActorResponse) String() string { func (*RevertActorResponse) ProtoMessage() {} func (x *RevertActorResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[72] + mi := &file_ateapi_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5824,7 +5919,7 @@ func (x *RevertActorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RevertActorResponse.ProtoReflect.Descriptor instead. func (*RevertActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{72} + return file_ateapi_proto_rawDescGZIP(), []int{73} } func (x *RevertActorResponse) GetActor() *Actor { @@ -5853,7 +5948,7 @@ type DeleteActorRequest struct { func (x *DeleteActorRequest) Reset() { *x = DeleteActorRequest{} - mi := &file_ateapi_proto_msgTypes[73] + mi := &file_ateapi_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5865,7 +5960,7 @@ func (x *DeleteActorRequest) String() string { func (*DeleteActorRequest) ProtoMessage() {} func (x *DeleteActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[73] + mi := &file_ateapi_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5878,7 +5973,7 @@ func (x *DeleteActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteActorRequest.ProtoReflect.Descriptor instead. func (*DeleteActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{73} + return file_ateapi_proto_rawDescGZIP(), []int{74} } func (x *DeleteActorRequest) GetActor() *ObjectRef { @@ -5922,7 +6017,7 @@ type GetActorEgressPolicyRequest struct { func (x *GetActorEgressPolicyRequest) Reset() { *x = GetActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[74] + mi := &file_ateapi_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5934,7 +6029,7 @@ func (x *GetActorEgressPolicyRequest) String() string { func (*GetActorEgressPolicyRequest) ProtoMessage() {} func (x *GetActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[74] + mi := &file_ateapi_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5947,7 +6042,7 @@ func (x *GetActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*GetActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{74} + return file_ateapi_proto_rawDescGZIP(), []int{75} } func (x *GetActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -5985,7 +6080,7 @@ type CreateActorEgressPolicyRequest struct { func (x *CreateActorEgressPolicyRequest) Reset() { *x = CreateActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[75] + mi := &file_ateapi_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5997,7 +6092,7 @@ func (x *CreateActorEgressPolicyRequest) String() string { func (*CreateActorEgressPolicyRequest) ProtoMessage() {} func (x *CreateActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[75] + mi := &file_ateapi_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6010,7 +6105,7 @@ func (x *CreateActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*CreateActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{75} + return file_ateapi_proto_rawDescGZIP(), []int{76} } func (x *CreateActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -6048,7 +6143,7 @@ type UpdateActorEgressPolicyRequest struct { func (x *UpdateActorEgressPolicyRequest) Reset() { *x = UpdateActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[76] + mi := &file_ateapi_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6060,7 +6155,7 @@ func (x *UpdateActorEgressPolicyRequest) String() string { func (*UpdateActorEgressPolicyRequest) ProtoMessage() {} func (x *UpdateActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[76] + mi := &file_ateapi_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6073,7 +6168,7 @@ func (x *UpdateActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*UpdateActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{76} + return file_ateapi_proto_rawDescGZIP(), []int{77} } func (x *UpdateActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -6114,7 +6209,7 @@ type DeleteActorEgressPolicyRequest struct { func (x *DeleteActorEgressPolicyRequest) Reset() { *x = DeleteActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[77] + mi := &file_ateapi_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6126,7 +6221,7 @@ func (x *DeleteActorEgressPolicyRequest) String() string { func (*DeleteActorEgressPolicyRequest) ProtoMessage() {} func (x *DeleteActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[77] + mi := &file_ateapi_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6139,7 +6234,7 @@ func (x *DeleteActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*DeleteActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{77} + return file_ateapi_proto_rawDescGZIP(), []int{78} } func (x *DeleteActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -6174,7 +6269,7 @@ type GetTagRequest struct { func (x *GetTagRequest) Reset() { *x = GetTagRequest{} - mi := &file_ateapi_proto_msgTypes[78] + mi := &file_ateapi_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6186,7 +6281,7 @@ func (x *GetTagRequest) String() string { func (*GetTagRequest) ProtoMessage() {} func (x *GetTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[78] + mi := &file_ateapi_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6199,7 +6294,7 @@ func (x *GetTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTagRequest.ProtoReflect.Descriptor instead. func (*GetTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{78} + return file_ateapi_proto_rawDescGZIP(), []int{79} } func (x *GetTagRequest) GetTag() *ObjectRef { @@ -6238,7 +6333,7 @@ type MintActorJwtRequest struct { func (x *MintActorJwtRequest) Reset() { *x = MintActorJwtRequest{} - mi := &file_ateapi_proto_msgTypes[79] + mi := &file_ateapi_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6250,7 +6345,7 @@ func (x *MintActorJwtRequest) String() string { func (*MintActorJwtRequest) ProtoMessage() {} func (x *MintActorJwtRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[79] + mi := &file_ateapi_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6263,7 +6358,7 @@ func (x *MintActorJwtRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorJwtRequest.ProtoReflect.Descriptor instead. func (*MintActorJwtRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{79} + return file_ateapi_proto_rawDescGZIP(), []int{80} } func (x *MintActorJwtRequest) GetActor() *ObjectRef { @@ -6313,7 +6408,7 @@ type MintActorJwtResponse struct { func (x *MintActorJwtResponse) Reset() { *x = MintActorJwtResponse{} - mi := &file_ateapi_proto_msgTypes[80] + mi := &file_ateapi_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6325,7 +6420,7 @@ func (x *MintActorJwtResponse) String() string { func (*MintActorJwtResponse) ProtoMessage() {} func (x *MintActorJwtResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[80] + mi := &file_ateapi_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6338,7 +6433,7 @@ func (x *MintActorJwtResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorJwtResponse.ProtoReflect.Descriptor instead. func (*MintActorJwtResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{80} + return file_ateapi_proto_rawDescGZIP(), []int{81} } func (x *MintActorJwtResponse) GetActorJwt() string { @@ -6383,7 +6478,7 @@ type MintActorCertificateRequest struct { func (x *MintActorCertificateRequest) Reset() { *x = MintActorCertificateRequest{} - mi := &file_ateapi_proto_msgTypes[81] + mi := &file_ateapi_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6395,7 +6490,7 @@ func (x *MintActorCertificateRequest) String() string { func (*MintActorCertificateRequest) ProtoMessage() {} func (x *MintActorCertificateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[81] + mi := &file_ateapi_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6408,7 +6503,7 @@ func (x *MintActorCertificateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorCertificateRequest.ProtoReflect.Descriptor instead. func (*MintActorCertificateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{81} + return file_ateapi_proto_rawDescGZIP(), []int{82} } func (x *MintActorCertificateRequest) GetActor() *ObjectRef { @@ -6445,7 +6540,7 @@ type MintActorCertificateResponse struct { func (x *MintActorCertificateResponse) Reset() { *x = MintActorCertificateResponse{} - mi := &file_ateapi_proto_msgTypes[82] + mi := &file_ateapi_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6457,7 +6552,7 @@ func (x *MintActorCertificateResponse) String() string { func (*MintActorCertificateResponse) ProtoMessage() {} func (x *MintActorCertificateResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[82] + mi := &file_ateapi_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6470,7 +6565,7 @@ func (x *MintActorCertificateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorCertificateResponse.ProtoReflect.Descriptor instead. func (*MintActorCertificateResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{82} + return file_ateapi_proto_rawDescGZIP(), []int{83} } func (x *MintActorCertificateResponse) GetActorCertificates() [][]byte { @@ -6506,7 +6601,7 @@ type ListTagsRequest struct { func (x *ListTagsRequest) Reset() { *x = ListTagsRequest{} - mi := &file_ateapi_proto_msgTypes[83] + mi := &file_ateapi_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6518,7 +6613,7 @@ func (x *ListTagsRequest) String() string { func (*ListTagsRequest) ProtoMessage() {} func (x *ListTagsRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[83] + mi := &file_ateapi_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6531,7 +6626,7 @@ func (x *ListTagsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListTagsRequest.ProtoReflect.Descriptor instead. func (*ListTagsRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{83} + return file_ateapi_proto_rawDescGZIP(), []int{84} } func (x *ListTagsRequest) GetAtespace() string { @@ -6565,7 +6660,7 @@ type ListTagsResponse struct { func (x *ListTagsResponse) Reset() { *x = ListTagsResponse{} - mi := &file_ateapi_proto_msgTypes[84] + mi := &file_ateapi_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6577,7 +6672,7 @@ func (x *ListTagsResponse) String() string { func (*ListTagsResponse) ProtoMessage() {} func (x *ListTagsResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[84] + mi := &file_ateapi_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6590,7 +6685,7 @@ func (x *ListTagsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListTagsResponse.ProtoReflect.Descriptor instead. func (*ListTagsResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{84} + return file_ateapi_proto_rawDescGZIP(), []int{85} } func (x *ListTagsResponse) GetTags() []*Tag { @@ -6635,7 +6730,7 @@ type CreateTagRequest struct { func (x *CreateTagRequest) Reset() { *x = CreateTagRequest{} - mi := &file_ateapi_proto_msgTypes[85] + mi := &file_ateapi_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6647,7 +6742,7 @@ func (x *CreateTagRequest) String() string { func (*CreateTagRequest) ProtoMessage() {} func (x *CreateTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[85] + mi := &file_ateapi_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6660,7 +6755,7 @@ func (x *CreateTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateTagRequest.ProtoReflect.Descriptor instead. func (*CreateTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{85} + return file_ateapi_proto_rawDescGZIP(), []int{86} } func (x *CreateTagRequest) GetTag() *Tag { @@ -6690,7 +6785,7 @@ type UpdateTagRequest struct { func (x *UpdateTagRequest) Reset() { *x = UpdateTagRequest{} - mi := &file_ateapi_proto_msgTypes[86] + mi := &file_ateapi_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6702,7 +6797,7 @@ func (x *UpdateTagRequest) String() string { func (*UpdateTagRequest) ProtoMessage() {} func (x *UpdateTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[86] + mi := &file_ateapi_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6715,7 +6810,7 @@ func (x *UpdateTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateTagRequest.ProtoReflect.Descriptor instead. func (*UpdateTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{86} + return file_ateapi_proto_rawDescGZIP(), []int{87} } func (x *UpdateTagRequest) GetTag() *Tag { @@ -6740,7 +6835,7 @@ type DeleteTagRequest struct { func (x *DeleteTagRequest) Reset() { *x = DeleteTagRequest{} - mi := &file_ateapi_proto_msgTypes[87] + mi := &file_ateapi_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6752,7 +6847,7 @@ func (x *DeleteTagRequest) String() string { func (*DeleteTagRequest) ProtoMessage() {} func (x *DeleteTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[87] + mi := &file_ateapi_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6765,7 +6860,7 @@ func (x *DeleteTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteTagRequest.ProtoReflect.Descriptor instead. func (*DeleteTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{87} + return file_ateapi_proto_rawDescGZIP(), []int{88} } func (x *DeleteTagRequest) GetTag() *ObjectRef { @@ -6798,7 +6893,7 @@ type CreateSharedVolumeRequest struct { func (x *CreateSharedVolumeRequest) Reset() { *x = CreateSharedVolumeRequest{} - mi := &file_ateapi_proto_msgTypes[88] + mi := &file_ateapi_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6810,7 +6905,7 @@ func (x *CreateSharedVolumeRequest) String() string { func (*CreateSharedVolumeRequest) ProtoMessage() {} func (x *CreateSharedVolumeRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[88] + mi := &file_ateapi_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6823,7 +6918,7 @@ func (x *CreateSharedVolumeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateSharedVolumeRequest.ProtoReflect.Descriptor instead. func (*CreateSharedVolumeRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{88} + return file_ateapi_proto_rawDescGZIP(), []int{89} } func (x *CreateSharedVolumeRequest) GetSharedVolume() *SharedVolume { @@ -6847,7 +6942,7 @@ type GetSharedVolumeRequest struct { func (x *GetSharedVolumeRequest) Reset() { *x = GetSharedVolumeRequest{} - mi := &file_ateapi_proto_msgTypes[89] + mi := &file_ateapi_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6859,7 +6954,7 @@ func (x *GetSharedVolumeRequest) String() string { func (*GetSharedVolumeRequest) ProtoMessage() {} func (x *GetSharedVolumeRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[89] + mi := &file_ateapi_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6872,7 +6967,7 @@ func (x *GetSharedVolumeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetSharedVolumeRequest.ProtoReflect.Descriptor instead. func (*GetSharedVolumeRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{89} + return file_ateapi_proto_rawDescGZIP(), []int{90} } func (x *GetSharedVolumeRequest) GetSharedVolume() *ObjectRef { @@ -6906,7 +7001,7 @@ type ListSharedVolumesRequest struct { func (x *ListSharedVolumesRequest) Reset() { *x = ListSharedVolumesRequest{} - mi := &file_ateapi_proto_msgTypes[90] + mi := &file_ateapi_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6918,7 +7013,7 @@ func (x *ListSharedVolumesRequest) String() string { func (*ListSharedVolumesRequest) ProtoMessage() {} func (x *ListSharedVolumesRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[90] + mi := &file_ateapi_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6931,7 +7026,7 @@ func (x *ListSharedVolumesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSharedVolumesRequest.ProtoReflect.Descriptor instead. func (*ListSharedVolumesRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{90} + return file_ateapi_proto_rawDescGZIP(), []int{91} } func (x *ListSharedVolumesRequest) GetAtespace() string { @@ -6968,7 +7063,7 @@ type ListSharedVolumesResponse struct { func (x *ListSharedVolumesResponse) Reset() { *x = ListSharedVolumesResponse{} - mi := &file_ateapi_proto_msgTypes[91] + mi := &file_ateapi_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6980,7 +7075,7 @@ func (x *ListSharedVolumesResponse) String() string { func (*ListSharedVolumesResponse) ProtoMessage() {} func (x *ListSharedVolumesResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[91] + mi := &file_ateapi_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6993,7 +7088,7 @@ func (x *ListSharedVolumesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListSharedVolumesResponse.ProtoReflect.Descriptor instead. func (*ListSharedVolumesResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{91} + return file_ateapi_proto_rawDescGZIP(), []int{92} } func (x *ListSharedVolumesResponse) GetSharedVolumes() []*SharedVolume { @@ -7027,7 +7122,7 @@ type UpdateSharedVolumeRequest struct { func (x *UpdateSharedVolumeRequest) Reset() { *x = UpdateSharedVolumeRequest{} - mi := &file_ateapi_proto_msgTypes[92] + mi := &file_ateapi_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7039,7 +7134,7 @@ func (x *UpdateSharedVolumeRequest) String() string { func (*UpdateSharedVolumeRequest) ProtoMessage() {} func (x *UpdateSharedVolumeRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[92] + mi := &file_ateapi_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7052,7 +7147,7 @@ func (x *UpdateSharedVolumeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateSharedVolumeRequest.ProtoReflect.Descriptor instead. func (*UpdateSharedVolumeRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{92} + return file_ateapi_proto_rawDescGZIP(), []int{93} } func (x *UpdateSharedVolumeRequest) GetSharedVolume() *SharedVolume { @@ -7080,7 +7175,7 @@ type DeleteSharedVolumeRequest struct { func (x *DeleteSharedVolumeRequest) Reset() { *x = DeleteSharedVolumeRequest{} - mi := &file_ateapi_proto_msgTypes[93] + mi := &file_ateapi_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7092,7 +7187,7 @@ func (x *DeleteSharedVolumeRequest) String() string { func (*DeleteSharedVolumeRequest) ProtoMessage() {} func (x *DeleteSharedVolumeRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[93] + mi := &file_ateapi_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7105,7 +7200,7 @@ func (x *DeleteSharedVolumeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteSharedVolumeRequest.ProtoReflect.Descriptor instead. func (*DeleteSharedVolumeRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{93} + return file_ateapi_proto_rawDescGZIP(), []int{94} } func (x *DeleteSharedVolumeRequest) GetSharedVolume() *ObjectRef { @@ -7144,7 +7239,7 @@ type DeleteOptions struct { func (x *DeleteOptions) Reset() { *x = DeleteOptions{} - mi := &file_ateapi_proto_msgTypes[94] + mi := &file_ateapi_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7156,7 +7251,7 @@ func (x *DeleteOptions) String() string { func (*DeleteOptions) ProtoMessage() {} func (x *DeleteOptions) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[94] + mi := &file_ateapi_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7169,7 +7264,7 @@ func (x *DeleteOptions) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteOptions.ProtoReflect.Descriptor instead. func (*DeleteOptions) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{94} + return file_ateapi_proto_rawDescGZIP(), []int{95} } func (x *DeleteOptions) GetVersion() int64 { @@ -7213,7 +7308,7 @@ type ListWorkerActorAssignmentsRequest struct { func (x *ListWorkerActorAssignmentsRequest) Reset() { *x = ListWorkerActorAssignmentsRequest{} - mi := &file_ateapi_proto_msgTypes[95] + mi := &file_ateapi_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7225,7 +7320,7 @@ func (x *ListWorkerActorAssignmentsRequest) String() string { func (*ListWorkerActorAssignmentsRequest) ProtoMessage() {} func (x *ListWorkerActorAssignmentsRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[95] + mi := &file_ateapi_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7238,7 +7333,7 @@ func (x *ListWorkerActorAssignmentsRequest) ProtoReflect() protoreflect.Message // Deprecated: Use ListWorkerActorAssignmentsRequest.ProtoReflect.Descriptor instead. func (*ListWorkerActorAssignmentsRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{95} + return file_ateapi_proto_rawDescGZIP(), []int{96} } func (x *ListWorkerActorAssignmentsRequest) GetWorker() *ObjectRef { @@ -7275,7 +7370,7 @@ type ListWorkerActorAssignmentsResponse struct { func (x *ListWorkerActorAssignmentsResponse) Reset() { *x = ListWorkerActorAssignmentsResponse{} - mi := &file_ateapi_proto_msgTypes[96] + mi := &file_ateapi_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7287,7 +7382,7 @@ func (x *ListWorkerActorAssignmentsResponse) String() string { func (*ListWorkerActorAssignmentsResponse) ProtoMessage() {} func (x *ListWorkerActorAssignmentsResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[96] + mi := &file_ateapi_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7300,7 +7395,7 @@ func (x *ListWorkerActorAssignmentsResponse) ProtoReflect() protoreflect.Message // Deprecated: Use ListWorkerActorAssignmentsResponse.ProtoReflect.Descriptor instead. func (*ListWorkerActorAssignmentsResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{96} + return file_ateapi_proto_rawDescGZIP(), []int{97} } func (x *ListWorkerActorAssignmentsResponse) GetActorAssignments() []*ActorAssignment { @@ -7338,7 +7433,7 @@ type ListWorkersRequest struct { func (x *ListWorkersRequest) Reset() { *x = ListWorkersRequest{} - mi := &file_ateapi_proto_msgTypes[97] + mi := &file_ateapi_proto_msgTypes[98] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7350,7 +7445,7 @@ func (x *ListWorkersRequest) String() string { func (*ListWorkersRequest) ProtoMessage() {} func (x *ListWorkersRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[97] + mi := &file_ateapi_proto_msgTypes[98] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7363,7 +7458,7 @@ func (x *ListWorkersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkersRequest.ProtoReflect.Descriptor instead. func (*ListWorkersRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{97} + return file_ateapi_proto_rawDescGZIP(), []int{98} } func (x *ListWorkersRequest) GetPageSize() int32 { @@ -7392,7 +7487,7 @@ type ListWorkersResponse struct { func (x *ListWorkersResponse) Reset() { *x = ListWorkersResponse{} - mi := &file_ateapi_proto_msgTypes[98] + mi := &file_ateapi_proto_msgTypes[99] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7404,7 +7499,7 @@ func (x *ListWorkersResponse) String() string { func (*ListWorkersResponse) ProtoMessage() {} func (x *ListWorkersResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[98] + mi := &file_ateapi_proto_msgTypes[99] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7417,7 +7512,7 @@ func (x *ListWorkersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkersResponse.ProtoReflect.Descriptor instead. func (*ListWorkersResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{98} + return file_ateapi_proto_rawDescGZIP(), []int{99} } func (x *ListWorkersResponse) GetWorkers() []*Worker { @@ -7447,7 +7542,7 @@ type GetWorkerRequest struct { func (x *GetWorkerRequest) Reset() { *x = GetWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[99] + mi := &file_ateapi_proto_msgTypes[100] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7459,7 +7554,7 @@ func (x *GetWorkerRequest) String() string { func (*GetWorkerRequest) ProtoMessage() {} func (x *GetWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[99] + mi := &file_ateapi_proto_msgTypes[100] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7472,7 +7567,7 @@ func (x *GetWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkerRequest.ProtoReflect.Descriptor instead. func (*GetWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{99} + return file_ateapi_proto_rawDescGZIP(), []int{100} } func (x *GetWorkerRequest) GetWorker() *ObjectRef { @@ -7494,7 +7589,7 @@ type CreateWorkerRequest struct { func (x *CreateWorkerRequest) Reset() { *x = CreateWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[100] + mi := &file_ateapi_proto_msgTypes[101] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7506,7 +7601,7 @@ func (x *CreateWorkerRequest) String() string { func (*CreateWorkerRequest) ProtoMessage() {} func (x *CreateWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[100] + mi := &file_ateapi_proto_msgTypes[101] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7519,7 +7614,7 @@ func (x *CreateWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkerRequest.ProtoReflect.Descriptor instead. func (*CreateWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{100} + return file_ateapi_proto_rawDescGZIP(), []int{101} } func (x *CreateWorkerRequest) GetWorker() *Worker { @@ -7554,7 +7649,7 @@ type UpdateWorkerRequest struct { func (x *UpdateWorkerRequest) Reset() { *x = UpdateWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[101] + mi := &file_ateapi_proto_msgTypes[102] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7566,7 +7661,7 @@ func (x *UpdateWorkerRequest) String() string { func (*UpdateWorkerRequest) ProtoMessage() {} func (x *UpdateWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[101] + mi := &file_ateapi_proto_msgTypes[102] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7579,7 +7674,7 @@ func (x *UpdateWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateWorkerRequest.ProtoReflect.Descriptor instead. func (*UpdateWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{101} + return file_ateapi_proto_rawDescGZIP(), []int{102} } func (x *UpdateWorkerRequest) GetWorker() *Worker { @@ -7606,7 +7701,7 @@ type DeleteWorkerRequest struct { func (x *DeleteWorkerRequest) Reset() { *x = DeleteWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[102] + mi := &file_ateapi_proto_msgTypes[103] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7618,7 +7713,7 @@ func (x *DeleteWorkerRequest) String() string { func (*DeleteWorkerRequest) ProtoMessage() {} func (x *DeleteWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[102] + mi := &file_ateapi_proto_msgTypes[103] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7631,7 +7726,7 @@ func (x *DeleteWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkerRequest.ProtoReflect.Descriptor instead. func (*DeleteWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{102} + return file_ateapi_proto_rawDescGZIP(), []int{103} } func (x *DeleteWorkerRequest) GetWorker() *ObjectRef { @@ -7661,7 +7756,7 @@ type DrainWorkerRequest struct { func (x *DrainWorkerRequest) Reset() { *x = DrainWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[103] + mi := &file_ateapi_proto_msgTypes[104] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7673,7 +7768,7 @@ func (x *DrainWorkerRequest) String() string { func (*DrainWorkerRequest) ProtoMessage() {} func (x *DrainWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[103] + mi := &file_ateapi_proto_msgTypes[104] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7686,7 +7781,7 @@ func (x *DrainWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DrainWorkerRequest.ProtoReflect.Descriptor instead. func (*DrainWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{103} + return file_ateapi_proto_rawDescGZIP(), []int{104} } func (x *DrainWorkerRequest) GetWorker() *ObjectRef { @@ -7707,7 +7802,7 @@ type DrainWorkerResponse struct { func (x *DrainWorkerResponse) Reset() { *x = DrainWorkerResponse{} - mi := &file_ateapi_proto_msgTypes[104] + mi := &file_ateapi_proto_msgTypes[105] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7719,7 +7814,7 @@ func (x *DrainWorkerResponse) String() string { func (*DrainWorkerResponse) ProtoMessage() {} func (x *DrainWorkerResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[104] + mi := &file_ateapi_proto_msgTypes[105] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7732,7 +7827,7 @@ func (x *DrainWorkerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DrainWorkerResponse.ProtoReflect.Descriptor instead. func (*DrainWorkerResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{104} + return file_ateapi_proto_rawDescGZIP(), []int{105} } func (x *DrainWorkerResponse) GetWorker() *Worker { @@ -7770,7 +7865,7 @@ type ListActorsRequest struct { func (x *ListActorsRequest) Reset() { *x = ListActorsRequest{} - mi := &file_ateapi_proto_msgTypes[105] + mi := &file_ateapi_proto_msgTypes[106] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7782,7 +7877,7 @@ func (x *ListActorsRequest) String() string { func (*ListActorsRequest) ProtoMessage() {} func (x *ListActorsRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[105] + mi := &file_ateapi_proto_msgTypes[106] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7795,7 +7890,7 @@ func (x *ListActorsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorsRequest.ProtoReflect.Descriptor instead. func (*ListActorsRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{105} + return file_ateapi_proto_rawDescGZIP(), []int{106} } func (x *ListActorsRequest) GetAtespace() string { @@ -7831,7 +7926,7 @@ type ListActorsResponse struct { func (x *ListActorsResponse) Reset() { *x = ListActorsResponse{} - mi := &file_ateapi_proto_msgTypes[106] + mi := &file_ateapi_proto_msgTypes[107] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7843,7 +7938,7 @@ func (x *ListActorsResponse) String() string { func (*ListActorsResponse) ProtoMessage() {} func (x *ListActorsResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[106] + mi := &file_ateapi_proto_msgTypes[107] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7856,7 +7951,7 @@ func (x *ListActorsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorsResponse.ProtoReflect.Descriptor instead. func (*ListActorsResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{106} + return file_ateapi_proto_rawDescGZIP(), []int{107} } func (x *ListActorsResponse) GetActors() []*Actor { @@ -7963,7 +8058,7 @@ type Worker struct { func (x *Worker) Reset() { *x = Worker{} - mi := &file_ateapi_proto_msgTypes[107] + mi := &file_ateapi_proto_msgTypes[108] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -7975,7 +8070,7 @@ func (x *Worker) String() string { func (*Worker) ProtoMessage() {} func (x *Worker) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[107] + mi := &file_ateapi_proto_msgTypes[108] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -7988,7 +8083,7 @@ func (x *Worker) ProtoReflect() protoreflect.Message { // Deprecated: Use Worker.ProtoReflect.Descriptor instead. func (*Worker) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{107} + return file_ateapi_proto_rawDescGZIP(), []int{108} } func (x *Worker) GetMetadata() *ResourceMetadata { @@ -8117,7 +8212,7 @@ type WorkerStatus struct { func (x *WorkerStatus) Reset() { *x = WorkerStatus{} - mi := &file_ateapi_proto_msgTypes[108] + mi := &file_ateapi_proto_msgTypes[109] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8129,7 +8224,7 @@ func (x *WorkerStatus) String() string { func (*WorkerStatus) ProtoMessage() {} func (x *WorkerStatus) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[108] + mi := &file_ateapi_proto_msgTypes[109] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8142,7 +8237,7 @@ func (x *WorkerStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkerStatus.ProtoReflect.Descriptor instead. func (*WorkerStatus) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{108} + return file_ateapi_proto_rawDescGZIP(), []int{109} } func (x *WorkerStatus) GetState() WorkerState { @@ -8209,7 +8304,7 @@ type SandboxRuntime struct { func (x *SandboxRuntime) Reset() { *x = SandboxRuntime{} - mi := &file_ateapi_proto_msgTypes[109] + mi := &file_ateapi_proto_msgTypes[110] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8221,7 +8316,7 @@ func (x *SandboxRuntime) String() string { func (*SandboxRuntime) ProtoMessage() {} func (x *SandboxRuntime) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[109] + mi := &file_ateapi_proto_msgTypes[110] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8234,7 +8329,7 @@ func (x *SandboxRuntime) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxRuntime.ProtoReflect.Descriptor instead. func (*SandboxRuntime) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{109} + return file_ateapi_proto_rawDescGZIP(), []int{110} } func (x *SandboxRuntime) GetSandboxClass() string { @@ -8282,7 +8377,7 @@ type VersionedSandboxCompat struct { func (x *VersionedSandboxCompat) Reset() { *x = VersionedSandboxCompat{} - mi := &file_ateapi_proto_msgTypes[110] + mi := &file_ateapi_proto_msgTypes[111] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8294,7 +8389,7 @@ func (x *VersionedSandboxCompat) String() string { func (*VersionedSandboxCompat) ProtoMessage() {} func (x *VersionedSandboxCompat) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[110] + mi := &file_ateapi_proto_msgTypes[111] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8307,7 +8402,7 @@ func (x *VersionedSandboxCompat) ProtoReflect() protoreflect.Message { // Deprecated: Use VersionedSandboxCompat.ProtoReflect.Descriptor instead. func (*VersionedSandboxCompat) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{110} + return file_ateapi_proto_rawDescGZIP(), []int{111} } func (x *VersionedSandboxCompat) GetSchemaVersion() string { @@ -8343,7 +8438,7 @@ type AttributeEntry struct { func (x *AttributeEntry) Reset() { *x = AttributeEntry{} - mi := &file_ateapi_proto_msgTypes[111] + mi := &file_ateapi_proto_msgTypes[112] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8355,7 +8450,7 @@ func (x *AttributeEntry) String() string { func (*AttributeEntry) ProtoMessage() {} func (x *AttributeEntry) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[111] + mi := &file_ateapi_proto_msgTypes[112] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8368,7 +8463,7 @@ func (x *AttributeEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use AttributeEntry.ProtoReflect.Descriptor instead. func (*AttributeEntry) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{111} + return file_ateapi_proto_rawDescGZIP(), []int{112} } func (x *AttributeEntry) GetKey() string { @@ -8407,7 +8502,7 @@ type WorkerResources struct { func (x *WorkerResources) Reset() { *x = WorkerResources{} - mi := &file_ateapi_proto_msgTypes[112] + mi := &file_ateapi_proto_msgTypes[113] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8419,7 +8514,7 @@ func (x *WorkerResources) String() string { func (*WorkerResources) ProtoMessage() {} func (x *WorkerResources) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[112] + mi := &file_ateapi_proto_msgTypes[113] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8432,7 +8527,7 @@ func (x *WorkerResources) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkerResources.ProtoReflect.Descriptor instead. func (*WorkerResources) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{112} + return file_ateapi_proto_rawDescGZIP(), []int{113} } func (x *WorkerResources) GetResources() *Resources { @@ -8485,7 +8580,7 @@ type ActorAssignment struct { func (x *ActorAssignment) Reset() { *x = ActorAssignment{} - mi := &file_ateapi_proto_msgTypes[113] + mi := &file_ateapi_proto_msgTypes[114] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8497,7 +8592,7 @@ func (x *ActorAssignment) String() string { func (*ActorAssignment) ProtoMessage() {} func (x *ActorAssignment) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[113] + mi := &file_ateapi_proto_msgTypes[114] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8510,7 +8605,7 @@ func (x *ActorAssignment) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorAssignment.ProtoReflect.Descriptor instead. func (*ActorAssignment) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{113} + return file_ateapi_proto_rawDescGZIP(), []int{114} } func (x *ActorAssignment) GetMetadata() *ResourceMetadata { @@ -8581,7 +8676,7 @@ type RegisterWorkerRequest struct { func (x *RegisterWorkerRequest) Reset() { *x = RegisterWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[114] + mi := &file_ateapi_proto_msgTypes[115] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8593,7 +8688,7 @@ func (x *RegisterWorkerRequest) String() string { func (*RegisterWorkerRequest) ProtoMessage() {} func (x *RegisterWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[114] + mi := &file_ateapi_proto_msgTypes[115] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8606,7 +8701,7 @@ func (x *RegisterWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterWorkerRequest.ProtoReflect.Descriptor instead. func (*RegisterWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{114} + return file_ateapi_proto_rawDescGZIP(), []int{115} } func (x *RegisterWorkerRequest) GetWorker() *ObjectRef { @@ -8647,7 +8742,7 @@ type RegisterWorkerResponse struct { func (x *RegisterWorkerResponse) Reset() { *x = RegisterWorkerResponse{} - mi := &file_ateapi_proto_msgTypes[115] + mi := &file_ateapi_proto_msgTypes[116] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8659,7 +8754,7 @@ func (x *RegisterWorkerResponse) String() string { func (*RegisterWorkerResponse) ProtoMessage() {} func (x *RegisterWorkerResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[115] + mi := &file_ateapi_proto_msgTypes[116] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8672,7 +8767,7 @@ func (x *RegisterWorkerResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RegisterWorkerResponse.ProtoReflect.Descriptor instead. func (*RegisterWorkerResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{115} + return file_ateapi_proto_rawDescGZIP(), []int{116} } func (x *RegisterWorkerResponse) GetWorker() *Worker { @@ -8711,7 +8806,7 @@ type MintAteomActorCertificateRequest struct { func (x *MintAteomActorCertificateRequest) Reset() { *x = MintAteomActorCertificateRequest{} - mi := &file_ateapi_proto_msgTypes[116] + mi := &file_ateapi_proto_msgTypes[117] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8723,7 +8818,7 @@ func (x *MintAteomActorCertificateRequest) String() string { func (*MintAteomActorCertificateRequest) ProtoMessage() {} func (x *MintAteomActorCertificateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[116] + mi := &file_ateapi_proto_msgTypes[117] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8736,7 +8831,7 @@ func (x *MintAteomActorCertificateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintAteomActorCertificateRequest.ProtoReflect.Descriptor instead. func (*MintAteomActorCertificateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{116} + return file_ateapi_proto_rawDescGZIP(), []int{117} } func (x *MintAteomActorCertificateRequest) GetActor() *ObjectRef { @@ -8773,7 +8868,7 @@ type MintAteomActorCertificateResponse struct { func (x *MintAteomActorCertificateResponse) Reset() { *x = MintAteomActorCertificateResponse{} - mi := &file_ateapi_proto_msgTypes[117] + mi := &file_ateapi_proto_msgTypes[118] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8785,7 +8880,7 @@ func (x *MintAteomActorCertificateResponse) String() string { func (*MintAteomActorCertificateResponse) ProtoMessage() {} func (x *MintAteomActorCertificateResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[117] + mi := &file_ateapi_proto_msgTypes[118] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8798,7 +8893,7 @@ func (x *MintAteomActorCertificateResponse) ProtoReflect() protoreflect.Message // Deprecated: Use MintAteomActorCertificateResponse.ProtoReflect.Descriptor instead. func (*MintAteomActorCertificateResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{117} + return file_ateapi_proto_rawDescGZIP(), []int{118} } func (x *MintAteomActorCertificateResponse) GetActorCertificates() [][]byte { @@ -8836,7 +8931,7 @@ type RequestActorSuspendRequest struct { func (x *RequestActorSuspendRequest) Reset() { *x = RequestActorSuspendRequest{} - mi := &file_ateapi_proto_msgTypes[118] + mi := &file_ateapi_proto_msgTypes[119] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8848,7 +8943,7 @@ func (x *RequestActorSuspendRequest) String() string { func (*RequestActorSuspendRequest) ProtoMessage() {} func (x *RequestActorSuspendRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[118] + mi := &file_ateapi_proto_msgTypes[119] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8861,7 +8956,7 @@ func (x *RequestActorSuspendRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestActorSuspendRequest.ProtoReflect.Descriptor instead. func (*RequestActorSuspendRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{118} + return file_ateapi_proto_rawDescGZIP(), []int{119} } func (x *RequestActorSuspendRequest) GetWorker() *ObjectRef { @@ -8895,7 +8990,7 @@ type RequestActorSuspendResponse struct { func (x *RequestActorSuspendResponse) Reset() { *x = RequestActorSuspendResponse{} - mi := &file_ateapi_proto_msgTypes[119] + mi := &file_ateapi_proto_msgTypes[120] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8907,7 +9002,7 @@ func (x *RequestActorSuspendResponse) String() string { func (*RequestActorSuspendResponse) ProtoMessage() {} func (x *RequestActorSuspendResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[119] + mi := &file_ateapi_proto_msgTypes[120] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8920,7 +9015,7 @@ func (x *RequestActorSuspendResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RequestActorSuspendResponse.ProtoReflect.Descriptor instead. func (*RequestActorSuspendResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{119} + return file_ateapi_proto_rawDescGZIP(), []int{120} } func (x *RequestActorSuspendResponse) GetActor() *Actor { @@ -8955,7 +9050,7 @@ type AccessPolicy struct { func (x *AccessPolicy) Reset() { *x = AccessPolicy{} - mi := &file_ateapi_proto_msgTypes[120] + mi := &file_ateapi_proto_msgTypes[121] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -8967,7 +9062,7 @@ func (x *AccessPolicy) String() string { func (*AccessPolicy) ProtoMessage() {} func (x *AccessPolicy) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[120] + mi := &file_ateapi_proto_msgTypes[121] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -8980,7 +9075,7 @@ func (x *AccessPolicy) ProtoReflect() protoreflect.Message { // Deprecated: Use AccessPolicy.ProtoReflect.Descriptor instead. func (*AccessPolicy) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{120} + return file_ateapi_proto_rawDescGZIP(), []int{121} } func (x *AccessPolicy) GetMetadata() *ResourceMetadata { @@ -9022,7 +9117,7 @@ type Binding struct { func (x *Binding) Reset() { *x = Binding{} - mi := &file_ateapi_proto_msgTypes[121] + mi := &file_ateapi_proto_msgTypes[122] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9034,7 +9129,7 @@ func (x *Binding) String() string { func (*Binding) ProtoMessage() {} func (x *Binding) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[121] + mi := &file_ateapi_proto_msgTypes[122] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9047,7 +9142,7 @@ func (x *Binding) ProtoReflect() protoreflect.Message { // Deprecated: Use Binding.ProtoReflect.Descriptor instead. func (*Binding) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{121} + return file_ateapi_proto_rawDescGZIP(), []int{122} } func (x *Binding) GetRole() string { @@ -9079,7 +9174,7 @@ type GetGlobalAccessPolicyRequest struct { func (x *GetGlobalAccessPolicyRequest) Reset() { *x = GetGlobalAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[122] + mi := &file_ateapi_proto_msgTypes[123] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9091,7 +9186,7 @@ func (x *GetGlobalAccessPolicyRequest) String() string { func (*GetGlobalAccessPolicyRequest) ProtoMessage() {} func (x *GetGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[122] + mi := &file_ateapi_proto_msgTypes[123] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9104,7 +9199,7 @@ func (x *GetGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetGlobalAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*GetGlobalAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{122} + return file_ateapi_proto_rawDescGZIP(), []int{123} } func (x *GetGlobalAccessPolicyRequest) GetName() string { @@ -9128,7 +9223,7 @@ type CreateGlobalAccessPolicyRequest struct { func (x *CreateGlobalAccessPolicyRequest) Reset() { *x = CreateGlobalAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[123] + mi := &file_ateapi_proto_msgTypes[124] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9140,7 +9235,7 @@ func (x *CreateGlobalAccessPolicyRequest) String() string { func (*CreateGlobalAccessPolicyRequest) ProtoMessage() {} func (x *CreateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[123] + mi := &file_ateapi_proto_msgTypes[124] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9153,7 +9248,7 @@ func (x *CreateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateGlobalAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*CreateGlobalAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{123} + return file_ateapi_proto_rawDescGZIP(), []int{124} } func (x *CreateGlobalAccessPolicyRequest) GetAccessPolicy() *AccessPolicy { @@ -9177,7 +9272,7 @@ type UpdateGlobalAccessPolicyRequest struct { func (x *UpdateGlobalAccessPolicyRequest) Reset() { *x = UpdateGlobalAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[124] + mi := &file_ateapi_proto_msgTypes[125] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9189,7 +9284,7 @@ func (x *UpdateGlobalAccessPolicyRequest) String() string { func (*UpdateGlobalAccessPolicyRequest) ProtoMessage() {} func (x *UpdateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[124] + mi := &file_ateapi_proto_msgTypes[125] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9202,7 +9297,7 @@ func (x *UpdateGlobalAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateGlobalAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*UpdateGlobalAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{124} + return file_ateapi_proto_rawDescGZIP(), []int{125} } func (x *UpdateGlobalAccessPolicyRequest) GetAccessPolicy() *AccessPolicy { @@ -9232,7 +9327,7 @@ type GetAtespaceAccessPolicyRequest struct { func (x *GetAtespaceAccessPolicyRequest) Reset() { *x = GetAtespaceAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[125] + mi := &file_ateapi_proto_msgTypes[126] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9244,7 +9339,7 @@ func (x *GetAtespaceAccessPolicyRequest) String() string { func (*GetAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *GetAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[125] + mi := &file_ateapi_proto_msgTypes[126] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9257,7 +9352,7 @@ func (x *GetAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*GetAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{125} + return file_ateapi_proto_rawDescGZIP(), []int{126} } func (x *GetAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -9293,7 +9388,7 @@ type CreateAtespaceAccessPolicyRequest struct { func (x *CreateAtespaceAccessPolicyRequest) Reset() { *x = CreateAtespaceAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[126] + mi := &file_ateapi_proto_msgTypes[127] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9305,7 +9400,7 @@ func (x *CreateAtespaceAccessPolicyRequest) String() string { func (*CreateAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *CreateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[126] + mi := &file_ateapi_proto_msgTypes[127] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9318,7 +9413,7 @@ func (x *CreateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message // Deprecated: Use CreateAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*CreateAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{126} + return file_ateapi_proto_rawDescGZIP(), []int{127} } func (x *CreateAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -9354,7 +9449,7 @@ type UpdateAtespaceAccessPolicyRequest struct { func (x *UpdateAtespaceAccessPolicyRequest) Reset() { *x = UpdateAtespaceAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[127] + mi := &file_ateapi_proto_msgTypes[128] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9366,7 +9461,7 @@ func (x *UpdateAtespaceAccessPolicyRequest) String() string { func (*UpdateAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *UpdateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[127] + mi := &file_ateapi_proto_msgTypes[128] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9379,7 +9474,7 @@ func (x *UpdateAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message // Deprecated: Use UpdateAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*UpdateAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{127} + return file_ateapi_proto_rawDescGZIP(), []int{128} } func (x *UpdateAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -9420,7 +9515,7 @@ type DeleteAtespaceAccessPolicyRequest struct { func (x *DeleteAtespaceAccessPolicyRequest) Reset() { *x = DeleteAtespaceAccessPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[128] + mi := &file_ateapi_proto_msgTypes[129] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -9432,7 +9527,7 @@ func (x *DeleteAtespaceAccessPolicyRequest) String() string { func (*DeleteAtespaceAccessPolicyRequest) ProtoMessage() {} func (x *DeleteAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[128] + mi := &file_ateapi_proto_msgTypes[129] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -9445,7 +9540,7 @@ func (x *DeleteAtespaceAccessPolicyRequest) ProtoReflect() protoreflect.Message // Deprecated: Use DeleteAtespaceAccessPolicyRequest.ProtoReflect.Descriptor instead. func (*DeleteAtespaceAccessPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{128} + return file_ateapi_proto_rawDescGZIP(), []int{129} } func (x *DeleteAtespaceAccessPolicyRequest) GetAtespace() *ObjectRef { @@ -9502,14 +9597,15 @@ const file_ateapi_proto_rawDesc = "" + "\vcreate_time\x18\x05 \x01(\v2\x1a.google.protobuf.TimestampR\n" + "createTime\x12;\n" + "\vupdate_time\x18\x06 \x01(\v2\x1a.google.protobuf.TimestampR\n" + - "updateTime\"\xa4\x03\n" + + "updateTime\"\xd2\x03\n" + "\x11ExternalVolumeRef\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x12*\n" + "\x11storage_volume_id\x18\x02 \x01(\tR\x0fstorageVolumeId\x12\x1f\n" + "\vvolume_type\x18\x03 \x01(\tR\n" + "volumeType\x128\n" + "\x06status\x18\x04 \x01(\x0e2 .ateapi.ExternalVolumeRef.StatusR\x06status\x12S\n" + - "\x0evolume_context\x18\x05 \x03(\v2,.ateapi.ExternalVolumeRef.VolumeContextEntryR\rvolumeContext\x1a@\n" + + "\x0evolume_context\x18\x05 \x03(\v2,.ateapi.ExternalVolumeRef.VolumeContextEntryR\rvolumeContext\x12,\n" + + "\x12shared_volume_name\x18\x06 \x01(\tR\x10sharedVolumeName\x1a@\n" + "\x12VolumeContextEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"]\n" + @@ -9517,14 +9613,18 @@ 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\"\xb9\x03\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\x12]\n" + + "\x16shared_volume_bindings\x18\b \x03(\v2'.ateapi.Actor.SharedVolumeBindingsEntryR\x14sharedVolumeBindings\x1aG\n" + + "\x19SharedVolumeBindingsEntry\x12\x10\n" + + "\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" + + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"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\"\xa0\x01\n" + @@ -9684,15 +9784,18 @@ const file_ateapi_proto_rawDesc = "" + "\bexternal\x18\a \x01(\v2\x1c.ateapi.ExternalVolumeSourceR\bexternal\x12?\n" + "\vsystem_info\x18\x05 \x01(\v2\x1e.ateapi.SystemInfoVolumeSourceR\n" + "systemInfo\x12/\n" + - "\x05image\x18\x06 \x01(\v2\x19.ateapi.ImageVolumeSourceR\x05image\"R\n" + + "\x05image\x18\x06 \x01(\v2\x19.ateapi.ImageVolumeSourceR\x05image\"\x90\x01\n" + "\x14ExternalVolumeSource\x12:\n" + - "\btemplate\x18\x01 \x01(\v2\x1e.ateapi.ExternalVolumeTemplateR\btemplate\"1\n" + + "\btemplate\x18\x01 \x01(\v2\x1e.ateapi.ExternalVolumeTemplateR\btemplate\x12<\n" + + "\rshared_volume\x18\x02 \x01(\v2\x17.ateapi.SharedVolumeRefR\fsharedVolume\"1\n" + "\x11ImageVolumeSource\x12\x1c\n" + "\treference\x18\x01 \x01(\tR\treference\"\x18\n" + "\x16DurableDirVolumeSource\"b\n" + "\x16ExternalVolumeTemplate\x12\x1a\n" + "\bcapacity\x18\x01 \x01(\tR\bcapacity\x12,\n" + - "\x12storage_class_name\x18\x02 \x01(\tR\x10storageClassName\"Y\n" + + "\x12storage_class_name\x18\x02 \x01(\tR\x10storageClassName\"%\n" + + "\x0fSharedVolumeRef\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\"Y\n" + "\x16SystemInfoVolumeSource\x12?\n" + "\fdata_sources\x18\x01 \x03(\v2\x1c.ateapi.SystemInfoDataSourceR\vdataSources\"\xa0\x01\n" + "\x14SystemInfoDataSource\x12F\n" + @@ -10081,7 +10184,7 @@ func file_ateapi_proto_rawDescGZIP() []byte { } var file_ateapi_proto_enumTypes = make([]protoimpl.EnumInfo, 13) -var file_ateapi_proto_msgTypes = make([]protoimpl.MessageInfo, 133) +var file_ateapi_proto_msgTypes = make([]protoimpl.MessageInfo, 135) var file_ateapi_proto_goTypes = []any{ (SnapshotOwner)(0), // 0: ateapi.SnapshotOwner (SnapshotStorageStatus)(0), // 1: ateapi.SnapshotStorageStatus @@ -10142,94 +10245,96 @@ var file_ateapi_proto_goTypes = []any{ (*ImageVolumeSource)(nil), // 56: ateapi.ImageVolumeSource (*DurableDirVolumeSource)(nil), // 57: ateapi.DurableDirVolumeSource (*ExternalVolumeTemplate)(nil), // 58: ateapi.ExternalVolumeTemplate - (*SystemInfoVolumeSource)(nil), // 59: ateapi.SystemInfoVolumeSource - (*SystemInfoDataSource)(nil), // 60: ateapi.SystemInfoDataSource - (*ActorMetadataDataSource)(nil), // 61: ateapi.ActorMetadataDataSource - (*ActorMetadataItem)(nil), // 62: ateapi.ActorMetadataItem - (*TrustBundleDataSource)(nil), // 63: ateapi.TrustBundleDataSource - (*VolumeMount)(nil), // 64: ateapi.VolumeMount - (*CreateAtespaceRequest)(nil), // 65: ateapi.CreateAtespaceRequest - (*GetAtespaceRequest)(nil), // 66: ateapi.GetAtespaceRequest - (*ListAtespacesRequest)(nil), // 67: ateapi.ListAtespacesRequest - (*ListAtespacesResponse)(nil), // 68: ateapi.ListAtespacesResponse - (*DeleteAtespaceRequest)(nil), // 69: ateapi.DeleteAtespaceRequest - (*CreateActorTemplateRequest)(nil), // 70: ateapi.CreateActorTemplateRequest - (*GetActorTemplateRequest)(nil), // 71: ateapi.GetActorTemplateRequest - (*ListActorTemplatesRequest)(nil), // 72: ateapi.ListActorTemplatesRequest - (*ListActorTemplatesResponse)(nil), // 73: ateapi.ListActorTemplatesResponse - (*DeleteActorTemplateRequest)(nil), // 74: ateapi.DeleteActorTemplateRequest - (*GetActorRequest)(nil), // 75: ateapi.GetActorRequest - (*CreateActorRequest)(nil), // 76: ateapi.CreateActorRequest - (*UpdateActorRequest)(nil), // 77: ateapi.UpdateActorRequest - (*SuspendActorRequest)(nil), // 78: ateapi.SuspendActorRequest - (*SuspendActorResponse)(nil), // 79: ateapi.SuspendActorResponse - (*PauseActorRequest)(nil), // 80: ateapi.PauseActorRequest - (*PauseActorResponse)(nil), // 81: ateapi.PauseActorResponse - (*ResumeActorRequest)(nil), // 82: ateapi.ResumeActorRequest - (*ResumeActorResponse)(nil), // 83: ateapi.ResumeActorResponse - (*RevertActorRequest)(nil), // 84: ateapi.RevertActorRequest - (*RevertActorResponse)(nil), // 85: ateapi.RevertActorResponse - (*DeleteActorRequest)(nil), // 86: ateapi.DeleteActorRequest - (*GetActorEgressPolicyRequest)(nil), // 87: ateapi.GetActorEgressPolicyRequest - (*CreateActorEgressPolicyRequest)(nil), // 88: ateapi.CreateActorEgressPolicyRequest - (*UpdateActorEgressPolicyRequest)(nil), // 89: ateapi.UpdateActorEgressPolicyRequest - (*DeleteActorEgressPolicyRequest)(nil), // 90: ateapi.DeleteActorEgressPolicyRequest - (*GetTagRequest)(nil), // 91: ateapi.GetTagRequest - (*MintActorJwtRequest)(nil), // 92: ateapi.MintActorJwtRequest - (*MintActorJwtResponse)(nil), // 93: ateapi.MintActorJwtResponse - (*MintActorCertificateRequest)(nil), // 94: ateapi.MintActorCertificateRequest - (*MintActorCertificateResponse)(nil), // 95: ateapi.MintActorCertificateResponse - (*ListTagsRequest)(nil), // 96: ateapi.ListTagsRequest - (*ListTagsResponse)(nil), // 97: ateapi.ListTagsResponse - (*CreateTagRequest)(nil), // 98: ateapi.CreateTagRequest - (*UpdateTagRequest)(nil), // 99: ateapi.UpdateTagRequest - (*DeleteTagRequest)(nil), // 100: ateapi.DeleteTagRequest - (*CreateSharedVolumeRequest)(nil), // 101: ateapi.CreateSharedVolumeRequest - (*GetSharedVolumeRequest)(nil), // 102: ateapi.GetSharedVolumeRequest - (*ListSharedVolumesRequest)(nil), // 103: ateapi.ListSharedVolumesRequest - (*ListSharedVolumesResponse)(nil), // 104: ateapi.ListSharedVolumesResponse - (*UpdateSharedVolumeRequest)(nil), // 105: ateapi.UpdateSharedVolumeRequest - (*DeleteSharedVolumeRequest)(nil), // 106: ateapi.DeleteSharedVolumeRequest - (*DeleteOptions)(nil), // 107: ateapi.DeleteOptions - (*ListWorkerActorAssignmentsRequest)(nil), // 108: ateapi.ListWorkerActorAssignmentsRequest - (*ListWorkerActorAssignmentsResponse)(nil), // 109: ateapi.ListWorkerActorAssignmentsResponse - (*ListWorkersRequest)(nil), // 110: ateapi.ListWorkersRequest - (*ListWorkersResponse)(nil), // 111: ateapi.ListWorkersResponse - (*GetWorkerRequest)(nil), // 112: ateapi.GetWorkerRequest - (*CreateWorkerRequest)(nil), // 113: ateapi.CreateWorkerRequest - (*UpdateWorkerRequest)(nil), // 114: ateapi.UpdateWorkerRequest - (*DeleteWorkerRequest)(nil), // 115: ateapi.DeleteWorkerRequest - (*DrainWorkerRequest)(nil), // 116: ateapi.DrainWorkerRequest - (*DrainWorkerResponse)(nil), // 117: ateapi.DrainWorkerResponse - (*ListActorsRequest)(nil), // 118: ateapi.ListActorsRequest - (*ListActorsResponse)(nil), // 119: ateapi.ListActorsResponse - (*Worker)(nil), // 120: ateapi.Worker - (*WorkerStatus)(nil), // 121: ateapi.WorkerStatus - (*SandboxRuntime)(nil), // 122: ateapi.SandboxRuntime - (*VersionedSandboxCompat)(nil), // 123: ateapi.VersionedSandboxCompat - (*AttributeEntry)(nil), // 124: ateapi.AttributeEntry - (*WorkerResources)(nil), // 125: ateapi.WorkerResources - (*ActorAssignment)(nil), // 126: ateapi.ActorAssignment - (*RegisterWorkerRequest)(nil), // 127: ateapi.RegisterWorkerRequest - (*RegisterWorkerResponse)(nil), // 128: ateapi.RegisterWorkerResponse - (*MintAteomActorCertificateRequest)(nil), // 129: ateapi.MintAteomActorCertificateRequest - (*MintAteomActorCertificateResponse)(nil), // 130: ateapi.MintAteomActorCertificateResponse - (*RequestActorSuspendRequest)(nil), // 131: ateapi.RequestActorSuspendRequest - (*RequestActorSuspendResponse)(nil), // 132: ateapi.RequestActorSuspendResponse - (*AccessPolicy)(nil), // 133: ateapi.AccessPolicy - (*Binding)(nil), // 134: ateapi.Binding - (*GetGlobalAccessPolicyRequest)(nil), // 135: ateapi.GetGlobalAccessPolicyRequest - (*CreateGlobalAccessPolicyRequest)(nil), // 136: ateapi.CreateGlobalAccessPolicyRequest - (*UpdateGlobalAccessPolicyRequest)(nil), // 137: ateapi.UpdateGlobalAccessPolicyRequest - (*GetAtespaceAccessPolicyRequest)(nil), // 138: ateapi.GetAtespaceAccessPolicyRequest - (*CreateAtespaceAccessPolicyRequest)(nil), // 139: ateapi.CreateAtespaceAccessPolicyRequest - (*UpdateAtespaceAccessPolicyRequest)(nil), // 140: ateapi.UpdateAtespaceAccessPolicyRequest - (*DeleteAtespaceAccessPolicyRequest)(nil), // 141: ateapi.DeleteAtespaceAccessPolicyRequest - nil, // 142: ateapi.Selector.MatchLabelsEntry - nil, // 143: ateapi.ExternalVolumeRef.VolumeContextEntry - nil, // 144: ateapi.SharedVolume.VolumeContextEntry - nil, // 145: ateapi.Worker.LabelsEntry - (*timestamppb.Timestamp)(nil), // 146: google.protobuf.Timestamp + (*SharedVolumeRef)(nil), // 59: ateapi.SharedVolumeRef + (*SystemInfoVolumeSource)(nil), // 60: ateapi.SystemInfoVolumeSource + (*SystemInfoDataSource)(nil), // 61: ateapi.SystemInfoDataSource + (*ActorMetadataDataSource)(nil), // 62: ateapi.ActorMetadataDataSource + (*ActorMetadataItem)(nil), // 63: ateapi.ActorMetadataItem + (*TrustBundleDataSource)(nil), // 64: ateapi.TrustBundleDataSource + (*VolumeMount)(nil), // 65: ateapi.VolumeMount + (*CreateAtespaceRequest)(nil), // 66: ateapi.CreateAtespaceRequest + (*GetAtespaceRequest)(nil), // 67: ateapi.GetAtespaceRequest + (*ListAtespacesRequest)(nil), // 68: ateapi.ListAtespacesRequest + (*ListAtespacesResponse)(nil), // 69: ateapi.ListAtespacesResponse + (*DeleteAtespaceRequest)(nil), // 70: ateapi.DeleteAtespaceRequest + (*CreateActorTemplateRequest)(nil), // 71: ateapi.CreateActorTemplateRequest + (*GetActorTemplateRequest)(nil), // 72: ateapi.GetActorTemplateRequest + (*ListActorTemplatesRequest)(nil), // 73: ateapi.ListActorTemplatesRequest + (*ListActorTemplatesResponse)(nil), // 74: ateapi.ListActorTemplatesResponse + (*DeleteActorTemplateRequest)(nil), // 75: ateapi.DeleteActorTemplateRequest + (*GetActorRequest)(nil), // 76: ateapi.GetActorRequest + (*CreateActorRequest)(nil), // 77: ateapi.CreateActorRequest + (*UpdateActorRequest)(nil), // 78: ateapi.UpdateActorRequest + (*SuspendActorRequest)(nil), // 79: ateapi.SuspendActorRequest + (*SuspendActorResponse)(nil), // 80: ateapi.SuspendActorResponse + (*PauseActorRequest)(nil), // 81: ateapi.PauseActorRequest + (*PauseActorResponse)(nil), // 82: ateapi.PauseActorResponse + (*ResumeActorRequest)(nil), // 83: ateapi.ResumeActorRequest + (*ResumeActorResponse)(nil), // 84: ateapi.ResumeActorResponse + (*RevertActorRequest)(nil), // 85: ateapi.RevertActorRequest + (*RevertActorResponse)(nil), // 86: ateapi.RevertActorResponse + (*DeleteActorRequest)(nil), // 87: ateapi.DeleteActorRequest + (*GetActorEgressPolicyRequest)(nil), // 88: ateapi.GetActorEgressPolicyRequest + (*CreateActorEgressPolicyRequest)(nil), // 89: ateapi.CreateActorEgressPolicyRequest + (*UpdateActorEgressPolicyRequest)(nil), // 90: ateapi.UpdateActorEgressPolicyRequest + (*DeleteActorEgressPolicyRequest)(nil), // 91: ateapi.DeleteActorEgressPolicyRequest + (*GetTagRequest)(nil), // 92: ateapi.GetTagRequest + (*MintActorJwtRequest)(nil), // 93: ateapi.MintActorJwtRequest + (*MintActorJwtResponse)(nil), // 94: ateapi.MintActorJwtResponse + (*MintActorCertificateRequest)(nil), // 95: ateapi.MintActorCertificateRequest + (*MintActorCertificateResponse)(nil), // 96: ateapi.MintActorCertificateResponse + (*ListTagsRequest)(nil), // 97: ateapi.ListTagsRequest + (*ListTagsResponse)(nil), // 98: ateapi.ListTagsResponse + (*CreateTagRequest)(nil), // 99: ateapi.CreateTagRequest + (*UpdateTagRequest)(nil), // 100: ateapi.UpdateTagRequest + (*DeleteTagRequest)(nil), // 101: ateapi.DeleteTagRequest + (*CreateSharedVolumeRequest)(nil), // 102: ateapi.CreateSharedVolumeRequest + (*GetSharedVolumeRequest)(nil), // 103: ateapi.GetSharedVolumeRequest + (*ListSharedVolumesRequest)(nil), // 104: ateapi.ListSharedVolumesRequest + (*ListSharedVolumesResponse)(nil), // 105: ateapi.ListSharedVolumesResponse + (*UpdateSharedVolumeRequest)(nil), // 106: ateapi.UpdateSharedVolumeRequest + (*DeleteSharedVolumeRequest)(nil), // 107: ateapi.DeleteSharedVolumeRequest + (*DeleteOptions)(nil), // 108: ateapi.DeleteOptions + (*ListWorkerActorAssignmentsRequest)(nil), // 109: ateapi.ListWorkerActorAssignmentsRequest + (*ListWorkerActorAssignmentsResponse)(nil), // 110: ateapi.ListWorkerActorAssignmentsResponse + (*ListWorkersRequest)(nil), // 111: ateapi.ListWorkersRequest + (*ListWorkersResponse)(nil), // 112: ateapi.ListWorkersResponse + (*GetWorkerRequest)(nil), // 113: ateapi.GetWorkerRequest + (*CreateWorkerRequest)(nil), // 114: ateapi.CreateWorkerRequest + (*UpdateWorkerRequest)(nil), // 115: ateapi.UpdateWorkerRequest + (*DeleteWorkerRequest)(nil), // 116: ateapi.DeleteWorkerRequest + (*DrainWorkerRequest)(nil), // 117: ateapi.DrainWorkerRequest + (*DrainWorkerResponse)(nil), // 118: ateapi.DrainWorkerResponse + (*ListActorsRequest)(nil), // 119: ateapi.ListActorsRequest + (*ListActorsResponse)(nil), // 120: ateapi.ListActorsResponse + (*Worker)(nil), // 121: ateapi.Worker + (*WorkerStatus)(nil), // 122: ateapi.WorkerStatus + (*SandboxRuntime)(nil), // 123: ateapi.SandboxRuntime + (*VersionedSandboxCompat)(nil), // 124: ateapi.VersionedSandboxCompat + (*AttributeEntry)(nil), // 125: ateapi.AttributeEntry + (*WorkerResources)(nil), // 126: ateapi.WorkerResources + (*ActorAssignment)(nil), // 127: ateapi.ActorAssignment + (*RegisterWorkerRequest)(nil), // 128: ateapi.RegisterWorkerRequest + (*RegisterWorkerResponse)(nil), // 129: ateapi.RegisterWorkerResponse + (*MintAteomActorCertificateRequest)(nil), // 130: ateapi.MintAteomActorCertificateRequest + (*MintAteomActorCertificateResponse)(nil), // 131: ateapi.MintAteomActorCertificateResponse + (*RequestActorSuspendRequest)(nil), // 132: ateapi.RequestActorSuspendRequest + (*RequestActorSuspendResponse)(nil), // 133: ateapi.RequestActorSuspendResponse + (*AccessPolicy)(nil), // 134: ateapi.AccessPolicy + (*Binding)(nil), // 135: ateapi.Binding + (*GetGlobalAccessPolicyRequest)(nil), // 136: ateapi.GetGlobalAccessPolicyRequest + (*CreateGlobalAccessPolicyRequest)(nil), // 137: ateapi.CreateGlobalAccessPolicyRequest + (*UpdateGlobalAccessPolicyRequest)(nil), // 138: ateapi.UpdateGlobalAccessPolicyRequest + (*GetAtespaceAccessPolicyRequest)(nil), // 139: ateapi.GetAtespaceAccessPolicyRequest + (*CreateAtespaceAccessPolicyRequest)(nil), // 140: ateapi.CreateAtespaceAccessPolicyRequest + (*UpdateAtespaceAccessPolicyRequest)(nil), // 141: ateapi.UpdateAtespaceAccessPolicyRequest + (*DeleteAtespaceAccessPolicyRequest)(nil), // 142: ateapi.DeleteAtespaceAccessPolicyRequest + nil, // 143: ateapi.Selector.MatchLabelsEntry + nil, // 144: ateapi.ExternalVolumeRef.VolumeContextEntry + nil, // 145: ateapi.Actor.SharedVolumeBindingsEntry + nil, // 146: ateapi.SharedVolume.VolumeContextEntry + nil, // 147: ateapi.Worker.LabelsEntry + (*timestamppb.Timestamp)(nil), // 148: google.protobuf.Timestamp } var file_ateapi_proto_depIdxs = []int32{ 1, // 0: ateapi.SnapshotStorage.status:type_name -> ateapi.SnapshotStorageStatus @@ -10237,277 +10342,279 @@ var file_ateapi_proto_depIdxs = []int32{ 0, // 2: ateapi.Snapshot.owner:type_name -> ateapi.SnapshotOwner 2, // 3: ateapi.Snapshot.fidelity:type_name -> ateapi.SnapshotFidelity 14, // 4: ateapi.Snapshot.durable_snapshot:type_name -> ateapi.SnapshotStorage - 142, // 5: ateapi.Selector.match_labels:type_name -> ateapi.Selector.MatchLabelsEntry - 146, // 6: ateapi.ResourceMetadata.create_time:type_name -> google.protobuf.Timestamp - 146, // 7: ateapi.ResourceMetadata.update_time:type_name -> google.protobuf.Timestamp + 143, // 5: ateapi.Selector.match_labels:type_name -> ateapi.Selector.MatchLabelsEntry + 148, // 6: ateapi.ResourceMetadata.create_time:type_name -> google.protobuf.Timestamp + 148, // 7: ateapi.ResourceMetadata.update_time:type_name -> google.protobuf.Timestamp 12, // 8: ateapi.ExternalVolumeRef.status:type_name -> ateapi.ExternalVolumeRef.Status - 143, // 9: ateapi.ExternalVolumeRef.volume_context:type_name -> ateapi.ExternalVolumeRef.VolumeContextEntry + 144, // 9: ateapi.ExternalVolumeRef.volume_context:type_name -> ateapi.ExternalVolumeRef.VolumeContextEntry 17, // 10: ateapi.Actor.metadata:type_name -> ateapi.ResourceMetadata 39, // 11: ateapi.Actor.actor_template:type_name -> ateapi.ObjectRef 16, // 12: ateapi.Actor.worker_selector:type_name -> ateapi.Selector 39, // 13: ateapi.Actor.source_tag:type_name -> ateapi.ObjectRef 30, // 14: ateapi.Actor.status:type_name -> ateapi.ActorStatus - 17, // 15: ateapi.EgressPolicy.metadata:type_name -> ateapi.ResourceMetadata - 21, // 16: ateapi.EgressPolicy.rules:type_name -> ateapi.EgressRule - 22, // 17: ateapi.EgressRule.http:type_name -> ateapi.HttpRule - 23, // 18: ateapi.EgressRule.https:type_name -> ateapi.HttpsRule - 24, // 19: ateapi.EgressRule.tls_passthrough:type_name -> ateapi.TlsPassthroughRule - 25, // 20: ateapi.HttpRule.ports:type_name -> ateapi.Ports - 27, // 21: ateapi.HttpRule.effects:type_name -> ateapi.HttpRuleEffects - 25, // 22: ateapi.HttpsRule.ports:type_name -> ateapi.Ports - 27, // 23: ateapi.HttpsRule.effects:type_name -> ateapi.HttpRuleEffects - 25, // 24: ateapi.TlsPassthroughRule.ports:type_name -> ateapi.Ports - 26, // 25: ateapi.Ports.all:type_name -> ateapi.AllPorts - 28, // 26: ateapi.HttpRuleEffects.replace_headers:type_name -> ateapi.CredentialHeader - 29, // 27: ateapi.CredentialHeader.actor_jwt:type_name -> ateapi.ActorJwtSource - 4, // 28: ateapi.ActorStatus.state:type_name -> ateapi.ActorState - 32, // 29: ateapi.ActorStatus.worker_assignment:type_name -> ateapi.WorkerAssignment - 18, // 30: ateapi.ActorStatus.external_volumes:type_name -> ateapi.ExternalVolumeRef - 31, // 31: ateapi.ActorStatus.crash:type_name -> ateapi.ActorCrash - 15, // 32: ateapi.ActorStatus.snapshots:type_name -> ateapi.Snapshot - 146, // 33: ateapi.ActorCrash.crash_time:type_name -> google.protobuf.Timestamp - 39, // 34: ateapi.WorkerAssignment.worker:type_name -> ateapi.ObjectRef - 15, // 35: ateapi.TagStatus.snapshot:type_name -> ateapi.Snapshot - 17, // 36: ateapi.Tag.metadata:type_name -> ateapi.ResourceMetadata - 33, // 37: ateapi.Tag.status:type_name -> ateapi.TagStatus - 3, // 38: ateapi.Tag.scope:type_name -> ateapi.TagScope - 39, // 39: ateapi.Tag.source_actor:type_name -> ateapi.ObjectRef - 17, // 40: ateapi.SharedVolume.metadata:type_name -> ateapi.ResourceMetadata - 5, // 41: ateapi.SharedVolume.delete_trigger:type_name -> ateapi.DeleteTrigger - 144, // 42: ateapi.SharedVolume.volume_context:type_name -> ateapi.SharedVolume.VolumeContextEntry - 36, // 43: ateapi.SharedVolume.status:type_name -> ateapi.SharedVolumeStatus - 6, // 44: ateapi.SharedVolume.access_mode:type_name -> ateapi.AccessMode - 7, // 45: ateapi.SharedVolumeStatus.state:type_name -> ateapi.SharedVolumeState - 37, // 46: ateapi.SharedVolumeStatus.refs:type_name -> ateapi.ActorRef - 17, // 47: ateapi.Atespace.metadata:type_name -> ateapi.ResourceMetadata - 17, // 48: ateapi.ActorTemplate.metadata:type_name -> ateapi.ResourceMetadata - 16, // 49: ateapi.ActorTemplate.worker_selector:type_name -> ateapi.Selector - 48, // 50: ateapi.ActorTemplate.containers:type_name -> ateapi.Container - 54, // 51: ateapi.ActorTemplate.volumes:type_name -> ateapi.Volume - 46, // 52: ateapi.ActorTemplate.snapshot_config:type_name -> ateapi.SnapshotConfig - 45, // 53: ateapi.ActorTemplate.sandbox_config:type_name -> ateapi.SandboxConfig - 41, // 54: ateapi.ActorTemplate.resources:type_name -> ateapi.Resources - 44, // 55: ateapi.ActorTemplate.status:type_name -> ateapi.ActorTemplateStatus - 42, // 56: ateapi.Resources.limits:type_name -> ateapi.Limits - 39, // 57: ateapi.GoldenSnapshotStatus.golden_tag:type_name -> ateapi.ObjectRef - 146, // 58: ateapi.GoldenSnapshotStatus.take_golden_snapshot_at:type_name -> google.protobuf.Timestamp - 43, // 59: ateapi.ActorTemplateStatus.golden_snapshot_status:type_name -> ateapi.GoldenSnapshotStatus - 8, // 60: ateapi.SandboxConfig.sandbox_class:type_name -> ateapi.SandboxClass - 2, // 61: ateapi.SnapshotConfig.preferred_fidelity:type_name -> ateapi.SnapshotFidelity - 47, // 62: ateapi.SnapshotConfig.golden_snapshot_config:type_name -> ateapi.GoldenSnapshotConfig - 9, // 63: ateapi.GoldenSnapshotConfig.mode:type_name -> ateapi.GoldenSnapshotMode - 51, // 64: ateapi.Container.env:type_name -> ateapi.EnvVar - 52, // 65: ateapi.Container.wakeup_probe:type_name -> ateapi.ContainerWakeupProbe - 64, // 66: ateapi.Container.volume_mounts:type_name -> ateapi.VolumeMount - 49, // 67: ateapi.Container.security_context:type_name -> ateapi.SecurityContext - 41, // 68: ateapi.Container.resources:type_name -> ateapi.Resources - 50, // 69: ateapi.SecurityContext.capabilities:type_name -> ateapi.Capabilities - 53, // 70: ateapi.ContainerWakeupProbe.http_get:type_name -> ateapi.HttpGetAction - 57, // 71: ateapi.Volume.durable_dir:type_name -> ateapi.DurableDirVolumeSource - 55, // 72: ateapi.Volume.external:type_name -> ateapi.ExternalVolumeSource - 59, // 73: ateapi.Volume.system_info:type_name -> ateapi.SystemInfoVolumeSource - 56, // 74: ateapi.Volume.image:type_name -> ateapi.ImageVolumeSource - 58, // 75: ateapi.ExternalVolumeSource.template:type_name -> ateapi.ExternalVolumeTemplate - 60, // 76: ateapi.SystemInfoVolumeSource.data_sources:type_name -> ateapi.SystemInfoDataSource - 61, // 77: ateapi.SystemInfoDataSource.actor_metadata:type_name -> ateapi.ActorMetadataDataSource - 63, // 78: ateapi.SystemInfoDataSource.trust_bundle:type_name -> ateapi.TrustBundleDataSource - 62, // 79: ateapi.ActorMetadataDataSource.items:type_name -> ateapi.ActorMetadataItem - 10, // 80: ateapi.ActorMetadataItem.field:type_name -> ateapi.ActorMetadataField - 38, // 81: ateapi.CreateAtespaceRequest.atespace:type_name -> ateapi.Atespace - 39, // 82: ateapi.GetAtespaceRequest.atespace:type_name -> ateapi.ObjectRef - 38, // 83: ateapi.ListAtespacesResponse.atespaces:type_name -> ateapi.Atespace - 39, // 84: ateapi.DeleteAtespaceRequest.atespace:type_name -> ateapi.ObjectRef - 107, // 85: ateapi.DeleteAtespaceRequest.options:type_name -> ateapi.DeleteOptions - 40, // 86: ateapi.CreateActorTemplateRequest.actor_template:type_name -> ateapi.ActorTemplate - 39, // 87: ateapi.GetActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef - 40, // 88: ateapi.ListActorTemplatesResponse.actor_templates:type_name -> ateapi.ActorTemplate - 39, // 89: ateapi.DeleteActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef - 107, // 90: ateapi.DeleteActorTemplateRequest.options:type_name -> ateapi.DeleteOptions - 39, // 91: ateapi.GetActorRequest.actor:type_name -> ateapi.ObjectRef - 19, // 92: ateapi.CreateActorRequest.actor:type_name -> ateapi.Actor - 19, // 93: ateapi.UpdateActorRequest.actor:type_name -> ateapi.Actor - 39, // 94: ateapi.SuspendActorRequest.actor:type_name -> ateapi.ObjectRef - 19, // 95: ateapi.SuspendActorResponse.actor:type_name -> ateapi.Actor - 39, // 96: ateapi.PauseActorRequest.actor:type_name -> ateapi.ObjectRef - 19, // 97: ateapi.PauseActorResponse.actor:type_name -> ateapi.Actor - 39, // 98: ateapi.ResumeActorRequest.actor:type_name -> ateapi.ObjectRef - 19, // 99: ateapi.ResumeActorResponse.actor:type_name -> ateapi.Actor - 39, // 100: ateapi.RevertActorRequest.actor:type_name -> ateapi.ObjectRef - 19, // 101: ateapi.RevertActorResponse.actor:type_name -> ateapi.Actor - 39, // 102: ateapi.DeleteActorRequest.actor:type_name -> ateapi.ObjectRef - 107, // 103: ateapi.DeleteActorRequest.options:type_name -> ateapi.DeleteOptions - 39, // 104: ateapi.GetActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 39, // 105: ateapi.CreateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 20, // 106: ateapi.CreateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy - 39, // 107: ateapi.UpdateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 20, // 108: ateapi.UpdateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy - 39, // 109: ateapi.DeleteActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 107, // 110: ateapi.DeleteActorEgressPolicyRequest.options:type_name -> ateapi.DeleteOptions - 39, // 111: ateapi.GetTagRequest.tag:type_name -> ateapi.ObjectRef - 39, // 112: ateapi.MintActorJwtRequest.actor:type_name -> ateapi.ObjectRef - 146, // 113: ateapi.MintActorJwtResponse.expires_at:type_name -> google.protobuf.Timestamp - 39, // 114: ateapi.MintActorCertificateRequest.actor:type_name -> ateapi.ObjectRef - 34, // 115: ateapi.ListTagsResponse.tags:type_name -> ateapi.Tag - 34, // 116: ateapi.CreateTagRequest.tag:type_name -> ateapi.Tag - 34, // 117: ateapi.UpdateTagRequest.tag:type_name -> ateapi.Tag - 39, // 118: ateapi.DeleteTagRequest.tag:type_name -> ateapi.ObjectRef - 107, // 119: ateapi.DeleteTagRequest.options:type_name -> ateapi.DeleteOptions - 35, // 120: ateapi.CreateSharedVolumeRequest.shared_volume:type_name -> ateapi.SharedVolume - 39, // 121: ateapi.GetSharedVolumeRequest.shared_volume:type_name -> ateapi.ObjectRef - 35, // 122: ateapi.ListSharedVolumesResponse.shared_volumes:type_name -> ateapi.SharedVolume - 35, // 123: ateapi.UpdateSharedVolumeRequest.shared_volume:type_name -> ateapi.SharedVolume - 39, // 124: ateapi.DeleteSharedVolumeRequest.shared_volume:type_name -> ateapi.ObjectRef - 107, // 125: ateapi.DeleteSharedVolumeRequest.options:type_name -> ateapi.DeleteOptions - 39, // 126: ateapi.ListWorkerActorAssignmentsRequest.worker:type_name -> ateapi.ObjectRef - 126, // 127: ateapi.ListWorkerActorAssignmentsResponse.actor_assignments:type_name -> ateapi.ActorAssignment - 120, // 128: ateapi.ListWorkersResponse.workers:type_name -> ateapi.Worker - 39, // 129: ateapi.GetWorkerRequest.worker:type_name -> ateapi.ObjectRef - 120, // 130: ateapi.CreateWorkerRequest.worker:type_name -> ateapi.Worker - 120, // 131: ateapi.UpdateWorkerRequest.worker:type_name -> ateapi.Worker - 39, // 132: ateapi.DeleteWorkerRequest.worker:type_name -> ateapi.ObjectRef - 107, // 133: ateapi.DeleteWorkerRequest.options:type_name -> ateapi.DeleteOptions - 39, // 134: ateapi.DrainWorkerRequest.worker:type_name -> ateapi.ObjectRef - 120, // 135: ateapi.DrainWorkerResponse.worker:type_name -> ateapi.Worker - 19, // 136: ateapi.ListActorsResponse.actors:type_name -> ateapi.Actor - 17, // 137: ateapi.Worker.metadata:type_name -> ateapi.ResourceMetadata - 145, // 138: ateapi.Worker.labels:type_name -> ateapi.Worker.LabelsEntry - 121, // 139: ateapi.Worker.status:type_name -> ateapi.WorkerStatus - 11, // 140: ateapi.WorkerStatus.state:type_name -> ateapi.WorkerState - 125, // 141: ateapi.WorkerStatus.capacity:type_name -> ateapi.WorkerResources - 125, // 142: ateapi.WorkerStatus.allocated:type_name -> ateapi.WorkerResources - 122, // 143: ateapi.WorkerStatus.default_runtime:type_name -> ateapi.SandboxRuntime - 122, // 144: ateapi.WorkerStatus.restorable_runtimes:type_name -> ateapi.SandboxRuntime - 123, // 145: ateapi.SandboxRuntime.version:type_name -> ateapi.VersionedSandboxCompat - 124, // 146: ateapi.VersionedSandboxCompat.attributes:type_name -> ateapi.AttributeEntry - 41, // 147: ateapi.WorkerResources.resources:type_name -> ateapi.Resources - 17, // 148: ateapi.ActorAssignment.metadata:type_name -> ateapi.ResourceMetadata - 39, // 149: ateapi.ActorAssignment.actor:type_name -> ateapi.ObjectRef - 41, // 150: ateapi.ActorAssignment.resources:type_name -> ateapi.Resources - 39, // 151: ateapi.RegisterWorkerRequest.worker:type_name -> ateapi.ObjectRef - 125, // 152: ateapi.RegisterWorkerRequest.capacity:type_name -> ateapi.WorkerResources - 122, // 153: ateapi.RegisterWorkerRequest.default_runtime:type_name -> ateapi.SandboxRuntime - 122, // 154: ateapi.RegisterWorkerRequest.restorable_runtimes:type_name -> ateapi.SandboxRuntime - 120, // 155: ateapi.RegisterWorkerResponse.worker:type_name -> ateapi.Worker - 39, // 156: ateapi.MintAteomActorCertificateRequest.actor:type_name -> ateapi.ObjectRef - 39, // 157: ateapi.RequestActorSuspendRequest.worker:type_name -> ateapi.ObjectRef - 39, // 158: ateapi.RequestActorSuspendRequest.actor:type_name -> ateapi.ObjectRef - 19, // 159: ateapi.RequestActorSuspendResponse.actor:type_name -> ateapi.Actor - 17, // 160: ateapi.AccessPolicy.metadata:type_name -> ateapi.ResourceMetadata - 134, // 161: ateapi.AccessPolicy.bindings:type_name -> ateapi.Binding - 133, // 162: ateapi.CreateGlobalAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy - 133, // 163: ateapi.UpdateGlobalAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy - 39, // 164: ateapi.GetAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef - 39, // 165: ateapi.CreateAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef - 133, // 166: ateapi.CreateAtespaceAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy - 39, // 167: ateapi.UpdateAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef - 133, // 168: ateapi.UpdateAtespaceAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy - 39, // 169: ateapi.DeleteAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef - 107, // 170: ateapi.DeleteAtespaceAccessPolicyRequest.options:type_name -> ateapi.DeleteOptions - 75, // 171: ateapi.Control.GetActor:input_type -> ateapi.GetActorRequest - 76, // 172: ateapi.Control.CreateActor:input_type -> ateapi.CreateActorRequest - 77, // 173: ateapi.Control.UpdateActor:input_type -> ateapi.UpdateActorRequest - 78, // 174: ateapi.Control.SuspendActor:input_type -> ateapi.SuspendActorRequest - 80, // 175: ateapi.Control.PauseActor:input_type -> ateapi.PauseActorRequest - 82, // 176: ateapi.Control.ResumeActor:input_type -> ateapi.ResumeActorRequest - 84, // 177: ateapi.Control.RevertActor:input_type -> ateapi.RevertActorRequest - 86, // 178: ateapi.Control.DeleteActor:input_type -> ateapi.DeleteActorRequest - 87, // 179: ateapi.Control.GetActorEgressPolicy:input_type -> ateapi.GetActorEgressPolicyRequest - 88, // 180: ateapi.Control.CreateActorEgressPolicy:input_type -> ateapi.CreateActorEgressPolicyRequest - 89, // 181: ateapi.Control.UpdateActorEgressPolicy:input_type -> ateapi.UpdateActorEgressPolicyRequest - 90, // 182: ateapi.Control.DeleteActorEgressPolicy:input_type -> ateapi.DeleteActorEgressPolicyRequest - 92, // 183: ateapi.Control.MintActorJwt:input_type -> ateapi.MintActorJwtRequest - 94, // 184: ateapi.Control.MintActorCertificate:input_type -> ateapi.MintActorCertificateRequest - 98, // 185: ateapi.Control.CreateTag:input_type -> ateapi.CreateTagRequest - 91, // 186: ateapi.Control.GetTag:input_type -> ateapi.GetTagRequest - 96, // 187: ateapi.Control.ListTags:input_type -> ateapi.ListTagsRequest - 99, // 188: ateapi.Control.UpdateTag:input_type -> ateapi.UpdateTagRequest - 100, // 189: ateapi.Control.DeleteTag:input_type -> ateapi.DeleteTagRequest - 101, // 190: ateapi.Control.CreateSharedVolume:input_type -> ateapi.CreateSharedVolumeRequest - 102, // 191: ateapi.Control.GetSharedVolume:input_type -> ateapi.GetSharedVolumeRequest - 103, // 192: ateapi.Control.ListSharedVolumes:input_type -> ateapi.ListSharedVolumesRequest - 105, // 193: ateapi.Control.UpdateSharedVolume:input_type -> ateapi.UpdateSharedVolumeRequest - 106, // 194: ateapi.Control.DeleteSharedVolume:input_type -> ateapi.DeleteSharedVolumeRequest - 110, // 195: ateapi.Control.ListWorkers:input_type -> ateapi.ListWorkersRequest - 112, // 196: ateapi.Control.GetWorker:input_type -> ateapi.GetWorkerRequest - 113, // 197: ateapi.Control.CreateWorker:input_type -> ateapi.CreateWorkerRequest - 114, // 198: ateapi.Control.UpdateWorker:input_type -> ateapi.UpdateWorkerRequest - 115, // 199: ateapi.Control.DeleteWorker:input_type -> ateapi.DeleteWorkerRequest - 116, // 200: ateapi.Control.DrainWorker:input_type -> ateapi.DrainWorkerRequest - 108, // 201: ateapi.Control.ListWorkerActorAssignments:input_type -> ateapi.ListWorkerActorAssignmentsRequest - 118, // 202: ateapi.Control.ListActors:input_type -> ateapi.ListActorsRequest - 65, // 203: ateapi.Control.CreateAtespace:input_type -> ateapi.CreateAtespaceRequest - 66, // 204: ateapi.Control.GetAtespace:input_type -> ateapi.GetAtespaceRequest - 67, // 205: ateapi.Control.ListAtespaces:input_type -> ateapi.ListAtespacesRequest - 69, // 206: ateapi.Control.DeleteAtespace:input_type -> ateapi.DeleteAtespaceRequest - 70, // 207: ateapi.Control.CreateActorTemplate:input_type -> ateapi.CreateActorTemplateRequest - 71, // 208: ateapi.Control.GetActorTemplate:input_type -> ateapi.GetActorTemplateRequest - 72, // 209: ateapi.Control.ListActorTemplates:input_type -> ateapi.ListActorTemplatesRequest - 74, // 210: ateapi.Control.DeleteActorTemplate:input_type -> ateapi.DeleteActorTemplateRequest - 135, // 211: ateapi.Control.GetGlobalAccessPolicy:input_type -> ateapi.GetGlobalAccessPolicyRequest - 136, // 212: ateapi.Control.CreateGlobalAccessPolicy:input_type -> ateapi.CreateGlobalAccessPolicyRequest - 137, // 213: ateapi.Control.UpdateGlobalAccessPolicy:input_type -> ateapi.UpdateGlobalAccessPolicyRequest - 138, // 214: ateapi.Control.GetAtespaceAccessPolicy:input_type -> ateapi.GetAtespaceAccessPolicyRequest - 139, // 215: ateapi.Control.CreateAtespaceAccessPolicy:input_type -> ateapi.CreateAtespaceAccessPolicyRequest - 140, // 216: ateapi.Control.UpdateAtespaceAccessPolicy:input_type -> ateapi.UpdateAtespaceAccessPolicyRequest - 141, // 217: ateapi.Control.DeleteAtespaceAccessPolicy:input_type -> ateapi.DeleteAtespaceAccessPolicyRequest - 127, // 218: ateapi.WorkerService.RegisterWorker:input_type -> ateapi.RegisterWorkerRequest - 129, // 219: ateapi.WorkerService.MintAteomActorCertificate:input_type -> ateapi.MintAteomActorCertificateRequest - 131, // 220: ateapi.WorkerService.RequestActorSuspend:input_type -> ateapi.RequestActorSuspendRequest - 19, // 221: ateapi.Control.GetActor:output_type -> ateapi.Actor - 19, // 222: ateapi.Control.CreateActor:output_type -> ateapi.Actor - 19, // 223: ateapi.Control.UpdateActor:output_type -> ateapi.Actor - 79, // 224: ateapi.Control.SuspendActor:output_type -> ateapi.SuspendActorResponse - 81, // 225: ateapi.Control.PauseActor:output_type -> ateapi.PauseActorResponse - 83, // 226: ateapi.Control.ResumeActor:output_type -> ateapi.ResumeActorResponse - 85, // 227: ateapi.Control.RevertActor:output_type -> ateapi.RevertActorResponse - 19, // 228: ateapi.Control.DeleteActor:output_type -> ateapi.Actor - 20, // 229: ateapi.Control.GetActorEgressPolicy:output_type -> ateapi.EgressPolicy - 20, // 230: ateapi.Control.CreateActorEgressPolicy:output_type -> ateapi.EgressPolicy - 20, // 231: ateapi.Control.UpdateActorEgressPolicy:output_type -> ateapi.EgressPolicy - 20, // 232: ateapi.Control.DeleteActorEgressPolicy:output_type -> ateapi.EgressPolicy - 93, // 233: ateapi.Control.MintActorJwt:output_type -> ateapi.MintActorJwtResponse - 95, // 234: ateapi.Control.MintActorCertificate:output_type -> ateapi.MintActorCertificateResponse - 34, // 235: ateapi.Control.CreateTag:output_type -> ateapi.Tag - 34, // 236: ateapi.Control.GetTag:output_type -> ateapi.Tag - 97, // 237: ateapi.Control.ListTags:output_type -> ateapi.ListTagsResponse - 34, // 238: ateapi.Control.UpdateTag:output_type -> ateapi.Tag - 34, // 239: ateapi.Control.DeleteTag:output_type -> ateapi.Tag - 35, // 240: ateapi.Control.CreateSharedVolume:output_type -> ateapi.SharedVolume - 35, // 241: ateapi.Control.GetSharedVolume:output_type -> ateapi.SharedVolume - 104, // 242: ateapi.Control.ListSharedVolumes:output_type -> ateapi.ListSharedVolumesResponse - 35, // 243: ateapi.Control.UpdateSharedVolume:output_type -> ateapi.SharedVolume - 35, // 244: ateapi.Control.DeleteSharedVolume:output_type -> ateapi.SharedVolume - 111, // 245: ateapi.Control.ListWorkers:output_type -> ateapi.ListWorkersResponse - 120, // 246: ateapi.Control.GetWorker:output_type -> ateapi.Worker - 120, // 247: ateapi.Control.CreateWorker:output_type -> ateapi.Worker - 120, // 248: ateapi.Control.UpdateWorker:output_type -> ateapi.Worker - 120, // 249: ateapi.Control.DeleteWorker:output_type -> ateapi.Worker - 117, // 250: ateapi.Control.DrainWorker:output_type -> ateapi.DrainWorkerResponse - 109, // 251: ateapi.Control.ListWorkerActorAssignments:output_type -> ateapi.ListWorkerActorAssignmentsResponse - 119, // 252: ateapi.Control.ListActors:output_type -> ateapi.ListActorsResponse - 38, // 253: ateapi.Control.CreateAtespace:output_type -> ateapi.Atespace - 38, // 254: ateapi.Control.GetAtespace:output_type -> ateapi.Atespace - 68, // 255: ateapi.Control.ListAtespaces:output_type -> ateapi.ListAtespacesResponse - 38, // 256: ateapi.Control.DeleteAtespace:output_type -> ateapi.Atespace - 40, // 257: ateapi.Control.CreateActorTemplate:output_type -> ateapi.ActorTemplate - 40, // 258: ateapi.Control.GetActorTemplate:output_type -> ateapi.ActorTemplate - 73, // 259: ateapi.Control.ListActorTemplates:output_type -> ateapi.ListActorTemplatesResponse - 40, // 260: ateapi.Control.DeleteActorTemplate:output_type -> ateapi.ActorTemplate - 133, // 261: ateapi.Control.GetGlobalAccessPolicy:output_type -> ateapi.AccessPolicy - 133, // 262: ateapi.Control.CreateGlobalAccessPolicy:output_type -> ateapi.AccessPolicy - 133, // 263: ateapi.Control.UpdateGlobalAccessPolicy:output_type -> ateapi.AccessPolicy - 133, // 264: ateapi.Control.GetAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy - 133, // 265: ateapi.Control.CreateAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy - 133, // 266: ateapi.Control.UpdateAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy - 133, // 267: ateapi.Control.DeleteAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy - 128, // 268: ateapi.WorkerService.RegisterWorker:output_type -> ateapi.RegisterWorkerResponse - 130, // 269: ateapi.WorkerService.MintAteomActorCertificate:output_type -> ateapi.MintAteomActorCertificateResponse - 132, // 270: ateapi.WorkerService.RequestActorSuspend:output_type -> ateapi.RequestActorSuspendResponse - 221, // [221:271] is the sub-list for method output_type - 171, // [171:221] is the sub-list for method input_type - 171, // [171:171] is the sub-list for extension type_name - 171, // [171:171] is the sub-list for extension extendee - 0, // [0:171] is the sub-list for field type_name + 145, // 15: ateapi.Actor.shared_volume_bindings:type_name -> ateapi.Actor.SharedVolumeBindingsEntry + 17, // 16: ateapi.EgressPolicy.metadata:type_name -> ateapi.ResourceMetadata + 21, // 17: ateapi.EgressPolicy.rules:type_name -> ateapi.EgressRule + 22, // 18: ateapi.EgressRule.http:type_name -> ateapi.HttpRule + 23, // 19: ateapi.EgressRule.https:type_name -> ateapi.HttpsRule + 24, // 20: ateapi.EgressRule.tls_passthrough:type_name -> ateapi.TlsPassthroughRule + 25, // 21: ateapi.HttpRule.ports:type_name -> ateapi.Ports + 27, // 22: ateapi.HttpRule.effects:type_name -> ateapi.HttpRuleEffects + 25, // 23: ateapi.HttpsRule.ports:type_name -> ateapi.Ports + 27, // 24: ateapi.HttpsRule.effects:type_name -> ateapi.HttpRuleEffects + 25, // 25: ateapi.TlsPassthroughRule.ports:type_name -> ateapi.Ports + 26, // 26: ateapi.Ports.all:type_name -> ateapi.AllPorts + 28, // 27: ateapi.HttpRuleEffects.replace_headers:type_name -> ateapi.CredentialHeader + 29, // 28: ateapi.CredentialHeader.actor_jwt:type_name -> ateapi.ActorJwtSource + 4, // 29: ateapi.ActorStatus.state:type_name -> ateapi.ActorState + 32, // 30: ateapi.ActorStatus.worker_assignment:type_name -> ateapi.WorkerAssignment + 18, // 31: ateapi.ActorStatus.external_volumes:type_name -> ateapi.ExternalVolumeRef + 31, // 32: ateapi.ActorStatus.crash:type_name -> ateapi.ActorCrash + 15, // 33: ateapi.ActorStatus.snapshots:type_name -> ateapi.Snapshot + 148, // 34: ateapi.ActorCrash.crash_time:type_name -> google.protobuf.Timestamp + 39, // 35: ateapi.WorkerAssignment.worker:type_name -> ateapi.ObjectRef + 15, // 36: ateapi.TagStatus.snapshot:type_name -> ateapi.Snapshot + 17, // 37: ateapi.Tag.metadata:type_name -> ateapi.ResourceMetadata + 33, // 38: ateapi.Tag.status:type_name -> ateapi.TagStatus + 3, // 39: ateapi.Tag.scope:type_name -> ateapi.TagScope + 39, // 40: ateapi.Tag.source_actor:type_name -> ateapi.ObjectRef + 17, // 41: ateapi.SharedVolume.metadata:type_name -> ateapi.ResourceMetadata + 5, // 42: ateapi.SharedVolume.delete_trigger:type_name -> ateapi.DeleteTrigger + 146, // 43: ateapi.SharedVolume.volume_context:type_name -> ateapi.SharedVolume.VolumeContextEntry + 36, // 44: ateapi.SharedVolume.status:type_name -> ateapi.SharedVolumeStatus + 6, // 45: ateapi.SharedVolume.access_mode:type_name -> ateapi.AccessMode + 7, // 46: ateapi.SharedVolumeStatus.state:type_name -> ateapi.SharedVolumeState + 37, // 47: ateapi.SharedVolumeStatus.refs:type_name -> ateapi.ActorRef + 17, // 48: ateapi.Atespace.metadata:type_name -> ateapi.ResourceMetadata + 17, // 49: ateapi.ActorTemplate.metadata:type_name -> ateapi.ResourceMetadata + 16, // 50: ateapi.ActorTemplate.worker_selector:type_name -> ateapi.Selector + 48, // 51: ateapi.ActorTemplate.containers:type_name -> ateapi.Container + 54, // 52: ateapi.ActorTemplate.volumes:type_name -> ateapi.Volume + 46, // 53: ateapi.ActorTemplate.snapshot_config:type_name -> ateapi.SnapshotConfig + 45, // 54: ateapi.ActorTemplate.sandbox_config:type_name -> ateapi.SandboxConfig + 41, // 55: ateapi.ActorTemplate.resources:type_name -> ateapi.Resources + 44, // 56: ateapi.ActorTemplate.status:type_name -> ateapi.ActorTemplateStatus + 42, // 57: ateapi.Resources.limits:type_name -> ateapi.Limits + 39, // 58: ateapi.GoldenSnapshotStatus.golden_tag:type_name -> ateapi.ObjectRef + 148, // 59: ateapi.GoldenSnapshotStatus.take_golden_snapshot_at:type_name -> google.protobuf.Timestamp + 43, // 60: ateapi.ActorTemplateStatus.golden_snapshot_status:type_name -> ateapi.GoldenSnapshotStatus + 8, // 61: ateapi.SandboxConfig.sandbox_class:type_name -> ateapi.SandboxClass + 2, // 62: ateapi.SnapshotConfig.preferred_fidelity:type_name -> ateapi.SnapshotFidelity + 47, // 63: ateapi.SnapshotConfig.golden_snapshot_config:type_name -> ateapi.GoldenSnapshotConfig + 9, // 64: ateapi.GoldenSnapshotConfig.mode:type_name -> ateapi.GoldenSnapshotMode + 51, // 65: ateapi.Container.env:type_name -> ateapi.EnvVar + 52, // 66: ateapi.Container.wakeup_probe:type_name -> ateapi.ContainerWakeupProbe + 65, // 67: ateapi.Container.volume_mounts:type_name -> ateapi.VolumeMount + 49, // 68: ateapi.Container.security_context:type_name -> ateapi.SecurityContext + 41, // 69: ateapi.Container.resources:type_name -> ateapi.Resources + 50, // 70: ateapi.SecurityContext.capabilities:type_name -> ateapi.Capabilities + 53, // 71: ateapi.ContainerWakeupProbe.http_get:type_name -> ateapi.HttpGetAction + 57, // 72: ateapi.Volume.durable_dir:type_name -> ateapi.DurableDirVolumeSource + 55, // 73: ateapi.Volume.external:type_name -> ateapi.ExternalVolumeSource + 60, // 74: ateapi.Volume.system_info:type_name -> ateapi.SystemInfoVolumeSource + 56, // 75: ateapi.Volume.image:type_name -> ateapi.ImageVolumeSource + 58, // 76: ateapi.ExternalVolumeSource.template:type_name -> ateapi.ExternalVolumeTemplate + 59, // 77: ateapi.ExternalVolumeSource.shared_volume:type_name -> ateapi.SharedVolumeRef + 61, // 78: ateapi.SystemInfoVolumeSource.data_sources:type_name -> ateapi.SystemInfoDataSource + 62, // 79: ateapi.SystemInfoDataSource.actor_metadata:type_name -> ateapi.ActorMetadataDataSource + 64, // 80: ateapi.SystemInfoDataSource.trust_bundle:type_name -> ateapi.TrustBundleDataSource + 63, // 81: ateapi.ActorMetadataDataSource.items:type_name -> ateapi.ActorMetadataItem + 10, // 82: ateapi.ActorMetadataItem.field:type_name -> ateapi.ActorMetadataField + 38, // 83: ateapi.CreateAtespaceRequest.atespace:type_name -> ateapi.Atespace + 39, // 84: ateapi.GetAtespaceRequest.atespace:type_name -> ateapi.ObjectRef + 38, // 85: ateapi.ListAtespacesResponse.atespaces:type_name -> ateapi.Atespace + 39, // 86: ateapi.DeleteAtespaceRequest.atespace:type_name -> ateapi.ObjectRef + 108, // 87: ateapi.DeleteAtespaceRequest.options:type_name -> ateapi.DeleteOptions + 40, // 88: ateapi.CreateActorTemplateRequest.actor_template:type_name -> ateapi.ActorTemplate + 39, // 89: ateapi.GetActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef + 40, // 90: ateapi.ListActorTemplatesResponse.actor_templates:type_name -> ateapi.ActorTemplate + 39, // 91: ateapi.DeleteActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef + 108, // 92: ateapi.DeleteActorTemplateRequest.options:type_name -> ateapi.DeleteOptions + 39, // 93: ateapi.GetActorRequest.actor:type_name -> ateapi.ObjectRef + 19, // 94: ateapi.CreateActorRequest.actor:type_name -> ateapi.Actor + 19, // 95: ateapi.UpdateActorRequest.actor:type_name -> ateapi.Actor + 39, // 96: ateapi.SuspendActorRequest.actor:type_name -> ateapi.ObjectRef + 19, // 97: ateapi.SuspendActorResponse.actor:type_name -> ateapi.Actor + 39, // 98: ateapi.PauseActorRequest.actor:type_name -> ateapi.ObjectRef + 19, // 99: ateapi.PauseActorResponse.actor:type_name -> ateapi.Actor + 39, // 100: ateapi.ResumeActorRequest.actor:type_name -> ateapi.ObjectRef + 19, // 101: ateapi.ResumeActorResponse.actor:type_name -> ateapi.Actor + 39, // 102: ateapi.RevertActorRequest.actor:type_name -> ateapi.ObjectRef + 19, // 103: ateapi.RevertActorResponse.actor:type_name -> ateapi.Actor + 39, // 104: ateapi.DeleteActorRequest.actor:type_name -> ateapi.ObjectRef + 108, // 105: ateapi.DeleteActorRequest.options:type_name -> ateapi.DeleteOptions + 39, // 106: ateapi.GetActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 39, // 107: ateapi.CreateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 20, // 108: ateapi.CreateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy + 39, // 109: ateapi.UpdateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 20, // 110: ateapi.UpdateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy + 39, // 111: ateapi.DeleteActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 108, // 112: ateapi.DeleteActorEgressPolicyRequest.options:type_name -> ateapi.DeleteOptions + 39, // 113: ateapi.GetTagRequest.tag:type_name -> ateapi.ObjectRef + 39, // 114: ateapi.MintActorJwtRequest.actor:type_name -> ateapi.ObjectRef + 148, // 115: ateapi.MintActorJwtResponse.expires_at:type_name -> google.protobuf.Timestamp + 39, // 116: ateapi.MintActorCertificateRequest.actor:type_name -> ateapi.ObjectRef + 34, // 117: ateapi.ListTagsResponse.tags:type_name -> ateapi.Tag + 34, // 118: ateapi.CreateTagRequest.tag:type_name -> ateapi.Tag + 34, // 119: ateapi.UpdateTagRequest.tag:type_name -> ateapi.Tag + 39, // 120: ateapi.DeleteTagRequest.tag:type_name -> ateapi.ObjectRef + 108, // 121: ateapi.DeleteTagRequest.options:type_name -> ateapi.DeleteOptions + 35, // 122: ateapi.CreateSharedVolumeRequest.shared_volume:type_name -> ateapi.SharedVolume + 39, // 123: ateapi.GetSharedVolumeRequest.shared_volume:type_name -> ateapi.ObjectRef + 35, // 124: ateapi.ListSharedVolumesResponse.shared_volumes:type_name -> ateapi.SharedVolume + 35, // 125: ateapi.UpdateSharedVolumeRequest.shared_volume:type_name -> ateapi.SharedVolume + 39, // 126: ateapi.DeleteSharedVolumeRequest.shared_volume:type_name -> ateapi.ObjectRef + 108, // 127: ateapi.DeleteSharedVolumeRequest.options:type_name -> ateapi.DeleteOptions + 39, // 128: ateapi.ListWorkerActorAssignmentsRequest.worker:type_name -> ateapi.ObjectRef + 127, // 129: ateapi.ListWorkerActorAssignmentsResponse.actor_assignments:type_name -> ateapi.ActorAssignment + 121, // 130: ateapi.ListWorkersResponse.workers:type_name -> ateapi.Worker + 39, // 131: ateapi.GetWorkerRequest.worker:type_name -> ateapi.ObjectRef + 121, // 132: ateapi.CreateWorkerRequest.worker:type_name -> ateapi.Worker + 121, // 133: ateapi.UpdateWorkerRequest.worker:type_name -> ateapi.Worker + 39, // 134: ateapi.DeleteWorkerRequest.worker:type_name -> ateapi.ObjectRef + 108, // 135: ateapi.DeleteWorkerRequest.options:type_name -> ateapi.DeleteOptions + 39, // 136: ateapi.DrainWorkerRequest.worker:type_name -> ateapi.ObjectRef + 121, // 137: ateapi.DrainWorkerResponse.worker:type_name -> ateapi.Worker + 19, // 138: ateapi.ListActorsResponse.actors:type_name -> ateapi.Actor + 17, // 139: ateapi.Worker.metadata:type_name -> ateapi.ResourceMetadata + 147, // 140: ateapi.Worker.labels:type_name -> ateapi.Worker.LabelsEntry + 122, // 141: ateapi.Worker.status:type_name -> ateapi.WorkerStatus + 11, // 142: ateapi.WorkerStatus.state:type_name -> ateapi.WorkerState + 126, // 143: ateapi.WorkerStatus.capacity:type_name -> ateapi.WorkerResources + 126, // 144: ateapi.WorkerStatus.allocated:type_name -> ateapi.WorkerResources + 123, // 145: ateapi.WorkerStatus.default_runtime:type_name -> ateapi.SandboxRuntime + 123, // 146: ateapi.WorkerStatus.restorable_runtimes:type_name -> ateapi.SandboxRuntime + 124, // 147: ateapi.SandboxRuntime.version:type_name -> ateapi.VersionedSandboxCompat + 125, // 148: ateapi.VersionedSandboxCompat.attributes:type_name -> ateapi.AttributeEntry + 41, // 149: ateapi.WorkerResources.resources:type_name -> ateapi.Resources + 17, // 150: ateapi.ActorAssignment.metadata:type_name -> ateapi.ResourceMetadata + 39, // 151: ateapi.ActorAssignment.actor:type_name -> ateapi.ObjectRef + 41, // 152: ateapi.ActorAssignment.resources:type_name -> ateapi.Resources + 39, // 153: ateapi.RegisterWorkerRequest.worker:type_name -> ateapi.ObjectRef + 126, // 154: ateapi.RegisterWorkerRequest.capacity:type_name -> ateapi.WorkerResources + 123, // 155: ateapi.RegisterWorkerRequest.default_runtime:type_name -> ateapi.SandboxRuntime + 123, // 156: ateapi.RegisterWorkerRequest.restorable_runtimes:type_name -> ateapi.SandboxRuntime + 121, // 157: ateapi.RegisterWorkerResponse.worker:type_name -> ateapi.Worker + 39, // 158: ateapi.MintAteomActorCertificateRequest.actor:type_name -> ateapi.ObjectRef + 39, // 159: ateapi.RequestActorSuspendRequest.worker:type_name -> ateapi.ObjectRef + 39, // 160: ateapi.RequestActorSuspendRequest.actor:type_name -> ateapi.ObjectRef + 19, // 161: ateapi.RequestActorSuspendResponse.actor:type_name -> ateapi.Actor + 17, // 162: ateapi.AccessPolicy.metadata:type_name -> ateapi.ResourceMetadata + 135, // 163: ateapi.AccessPolicy.bindings:type_name -> ateapi.Binding + 134, // 164: ateapi.CreateGlobalAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy + 134, // 165: ateapi.UpdateGlobalAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy + 39, // 166: ateapi.GetAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef + 39, // 167: ateapi.CreateAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef + 134, // 168: ateapi.CreateAtespaceAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy + 39, // 169: ateapi.UpdateAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef + 134, // 170: ateapi.UpdateAtespaceAccessPolicyRequest.access_policy:type_name -> ateapi.AccessPolicy + 39, // 171: ateapi.DeleteAtespaceAccessPolicyRequest.atespace:type_name -> ateapi.ObjectRef + 108, // 172: ateapi.DeleteAtespaceAccessPolicyRequest.options:type_name -> ateapi.DeleteOptions + 76, // 173: ateapi.Control.GetActor:input_type -> ateapi.GetActorRequest + 77, // 174: ateapi.Control.CreateActor:input_type -> ateapi.CreateActorRequest + 78, // 175: ateapi.Control.UpdateActor:input_type -> ateapi.UpdateActorRequest + 79, // 176: ateapi.Control.SuspendActor:input_type -> ateapi.SuspendActorRequest + 81, // 177: ateapi.Control.PauseActor:input_type -> ateapi.PauseActorRequest + 83, // 178: ateapi.Control.ResumeActor:input_type -> ateapi.ResumeActorRequest + 85, // 179: ateapi.Control.RevertActor:input_type -> ateapi.RevertActorRequest + 87, // 180: ateapi.Control.DeleteActor:input_type -> ateapi.DeleteActorRequest + 88, // 181: ateapi.Control.GetActorEgressPolicy:input_type -> ateapi.GetActorEgressPolicyRequest + 89, // 182: ateapi.Control.CreateActorEgressPolicy:input_type -> ateapi.CreateActorEgressPolicyRequest + 90, // 183: ateapi.Control.UpdateActorEgressPolicy:input_type -> ateapi.UpdateActorEgressPolicyRequest + 91, // 184: ateapi.Control.DeleteActorEgressPolicy:input_type -> ateapi.DeleteActorEgressPolicyRequest + 93, // 185: ateapi.Control.MintActorJwt:input_type -> ateapi.MintActorJwtRequest + 95, // 186: ateapi.Control.MintActorCertificate:input_type -> ateapi.MintActorCertificateRequest + 99, // 187: ateapi.Control.CreateTag:input_type -> ateapi.CreateTagRequest + 92, // 188: ateapi.Control.GetTag:input_type -> ateapi.GetTagRequest + 97, // 189: ateapi.Control.ListTags:input_type -> ateapi.ListTagsRequest + 100, // 190: ateapi.Control.UpdateTag:input_type -> ateapi.UpdateTagRequest + 101, // 191: ateapi.Control.DeleteTag:input_type -> ateapi.DeleteTagRequest + 102, // 192: ateapi.Control.CreateSharedVolume:input_type -> ateapi.CreateSharedVolumeRequest + 103, // 193: ateapi.Control.GetSharedVolume:input_type -> ateapi.GetSharedVolumeRequest + 104, // 194: ateapi.Control.ListSharedVolumes:input_type -> ateapi.ListSharedVolumesRequest + 106, // 195: ateapi.Control.UpdateSharedVolume:input_type -> ateapi.UpdateSharedVolumeRequest + 107, // 196: ateapi.Control.DeleteSharedVolume:input_type -> ateapi.DeleteSharedVolumeRequest + 111, // 197: ateapi.Control.ListWorkers:input_type -> ateapi.ListWorkersRequest + 113, // 198: ateapi.Control.GetWorker:input_type -> ateapi.GetWorkerRequest + 114, // 199: ateapi.Control.CreateWorker:input_type -> ateapi.CreateWorkerRequest + 115, // 200: ateapi.Control.UpdateWorker:input_type -> ateapi.UpdateWorkerRequest + 116, // 201: ateapi.Control.DeleteWorker:input_type -> ateapi.DeleteWorkerRequest + 117, // 202: ateapi.Control.DrainWorker:input_type -> ateapi.DrainWorkerRequest + 109, // 203: ateapi.Control.ListWorkerActorAssignments:input_type -> ateapi.ListWorkerActorAssignmentsRequest + 119, // 204: ateapi.Control.ListActors:input_type -> ateapi.ListActorsRequest + 66, // 205: ateapi.Control.CreateAtespace:input_type -> ateapi.CreateAtespaceRequest + 67, // 206: ateapi.Control.GetAtespace:input_type -> ateapi.GetAtespaceRequest + 68, // 207: ateapi.Control.ListAtespaces:input_type -> ateapi.ListAtespacesRequest + 70, // 208: ateapi.Control.DeleteAtespace:input_type -> ateapi.DeleteAtespaceRequest + 71, // 209: ateapi.Control.CreateActorTemplate:input_type -> ateapi.CreateActorTemplateRequest + 72, // 210: ateapi.Control.GetActorTemplate:input_type -> ateapi.GetActorTemplateRequest + 73, // 211: ateapi.Control.ListActorTemplates:input_type -> ateapi.ListActorTemplatesRequest + 75, // 212: ateapi.Control.DeleteActorTemplate:input_type -> ateapi.DeleteActorTemplateRequest + 136, // 213: ateapi.Control.GetGlobalAccessPolicy:input_type -> ateapi.GetGlobalAccessPolicyRequest + 137, // 214: ateapi.Control.CreateGlobalAccessPolicy:input_type -> ateapi.CreateGlobalAccessPolicyRequest + 138, // 215: ateapi.Control.UpdateGlobalAccessPolicy:input_type -> ateapi.UpdateGlobalAccessPolicyRequest + 139, // 216: ateapi.Control.GetAtespaceAccessPolicy:input_type -> ateapi.GetAtespaceAccessPolicyRequest + 140, // 217: ateapi.Control.CreateAtespaceAccessPolicy:input_type -> ateapi.CreateAtespaceAccessPolicyRequest + 141, // 218: ateapi.Control.UpdateAtespaceAccessPolicy:input_type -> ateapi.UpdateAtespaceAccessPolicyRequest + 142, // 219: ateapi.Control.DeleteAtespaceAccessPolicy:input_type -> ateapi.DeleteAtespaceAccessPolicyRequest + 128, // 220: ateapi.WorkerService.RegisterWorker:input_type -> ateapi.RegisterWorkerRequest + 130, // 221: ateapi.WorkerService.MintAteomActorCertificate:input_type -> ateapi.MintAteomActorCertificateRequest + 132, // 222: ateapi.WorkerService.RequestActorSuspend:input_type -> ateapi.RequestActorSuspendRequest + 19, // 223: ateapi.Control.GetActor:output_type -> ateapi.Actor + 19, // 224: ateapi.Control.CreateActor:output_type -> ateapi.Actor + 19, // 225: ateapi.Control.UpdateActor:output_type -> ateapi.Actor + 80, // 226: ateapi.Control.SuspendActor:output_type -> ateapi.SuspendActorResponse + 82, // 227: ateapi.Control.PauseActor:output_type -> ateapi.PauseActorResponse + 84, // 228: ateapi.Control.ResumeActor:output_type -> ateapi.ResumeActorResponse + 86, // 229: ateapi.Control.RevertActor:output_type -> ateapi.RevertActorResponse + 19, // 230: ateapi.Control.DeleteActor:output_type -> ateapi.Actor + 20, // 231: ateapi.Control.GetActorEgressPolicy:output_type -> ateapi.EgressPolicy + 20, // 232: ateapi.Control.CreateActorEgressPolicy:output_type -> ateapi.EgressPolicy + 20, // 233: ateapi.Control.UpdateActorEgressPolicy:output_type -> ateapi.EgressPolicy + 20, // 234: ateapi.Control.DeleteActorEgressPolicy:output_type -> ateapi.EgressPolicy + 94, // 235: ateapi.Control.MintActorJwt:output_type -> ateapi.MintActorJwtResponse + 96, // 236: ateapi.Control.MintActorCertificate:output_type -> ateapi.MintActorCertificateResponse + 34, // 237: ateapi.Control.CreateTag:output_type -> ateapi.Tag + 34, // 238: ateapi.Control.GetTag:output_type -> ateapi.Tag + 98, // 239: ateapi.Control.ListTags:output_type -> ateapi.ListTagsResponse + 34, // 240: ateapi.Control.UpdateTag:output_type -> ateapi.Tag + 34, // 241: ateapi.Control.DeleteTag:output_type -> ateapi.Tag + 35, // 242: ateapi.Control.CreateSharedVolume:output_type -> ateapi.SharedVolume + 35, // 243: ateapi.Control.GetSharedVolume:output_type -> ateapi.SharedVolume + 105, // 244: ateapi.Control.ListSharedVolumes:output_type -> ateapi.ListSharedVolumesResponse + 35, // 245: ateapi.Control.UpdateSharedVolume:output_type -> ateapi.SharedVolume + 35, // 246: ateapi.Control.DeleteSharedVolume:output_type -> ateapi.SharedVolume + 112, // 247: ateapi.Control.ListWorkers:output_type -> ateapi.ListWorkersResponse + 121, // 248: ateapi.Control.GetWorker:output_type -> ateapi.Worker + 121, // 249: ateapi.Control.CreateWorker:output_type -> ateapi.Worker + 121, // 250: ateapi.Control.UpdateWorker:output_type -> ateapi.Worker + 121, // 251: ateapi.Control.DeleteWorker:output_type -> ateapi.Worker + 118, // 252: ateapi.Control.DrainWorker:output_type -> ateapi.DrainWorkerResponse + 110, // 253: ateapi.Control.ListWorkerActorAssignments:output_type -> ateapi.ListWorkerActorAssignmentsResponse + 120, // 254: ateapi.Control.ListActors:output_type -> ateapi.ListActorsResponse + 38, // 255: ateapi.Control.CreateAtespace:output_type -> ateapi.Atespace + 38, // 256: ateapi.Control.GetAtespace:output_type -> ateapi.Atespace + 69, // 257: ateapi.Control.ListAtespaces:output_type -> ateapi.ListAtespacesResponse + 38, // 258: ateapi.Control.DeleteAtespace:output_type -> ateapi.Atespace + 40, // 259: ateapi.Control.CreateActorTemplate:output_type -> ateapi.ActorTemplate + 40, // 260: ateapi.Control.GetActorTemplate:output_type -> ateapi.ActorTemplate + 74, // 261: ateapi.Control.ListActorTemplates:output_type -> ateapi.ListActorTemplatesResponse + 40, // 262: ateapi.Control.DeleteActorTemplate:output_type -> ateapi.ActorTemplate + 134, // 263: ateapi.Control.GetGlobalAccessPolicy:output_type -> ateapi.AccessPolicy + 134, // 264: ateapi.Control.CreateGlobalAccessPolicy:output_type -> ateapi.AccessPolicy + 134, // 265: ateapi.Control.UpdateGlobalAccessPolicy:output_type -> ateapi.AccessPolicy + 134, // 266: ateapi.Control.GetAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy + 134, // 267: ateapi.Control.CreateAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy + 134, // 268: ateapi.Control.UpdateAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy + 134, // 269: ateapi.Control.DeleteAtespaceAccessPolicy:output_type -> ateapi.AccessPolicy + 129, // 270: ateapi.WorkerService.RegisterWorker:output_type -> ateapi.RegisterWorkerResponse + 131, // 271: ateapi.WorkerService.MintAteomActorCertificate:output_type -> ateapi.MintAteomActorCertificateResponse + 133, // 272: ateapi.WorkerService.RequestActorSuspend:output_type -> ateapi.RequestActorSuspendResponse + 223, // [223:273] is the sub-list for method output_type + 173, // [173:223] is the sub-list for method input_type + 173, // [173:173] is the sub-list for extension type_name + 173, // [173:173] is the sub-list for extension extendee + 0, // [0:173] is the sub-list for field type_name } func init() { file_ateapi_proto_init() } @@ -10521,7 +10628,7 @@ func file_ateapi_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_ateapi_proto_rawDesc), len(file_ateapi_proto_rawDesc)), NumEnums: 13, - NumMessages: 133, + NumMessages: 135, NumExtensions: 0, NumServices: 2, }, diff --git a/pkg/proto/ateapipb/ateapi.proto b/pkg/proto/ateapipb/ateapi.proto index bd8cdc7d69..073f1f3c32 100644 --- a/pkg/proto/ateapipb/ateapi.proto +++ b/pkg/proto/ateapipb/ateapi.proto @@ -450,6 +450,15 @@ message ExternalVolumeRef { // +k8s:optional // +k8s:customValidation # at most 40 KiB in total, ten times the CSI limit for map fields map volume_context = 5; + + // shared_volume_name names the SharedVolume this mount references, in the + // actor's atespace. Empty when the actor owns the volume itself. + // + // +k8s:optional + // +k8s:format=k8s-short-name + // +k8s:update=NoModify + // +k8s:update=NoUnset + string shared_volume_name = 6; } message Actor { @@ -487,6 +496,17 @@ message Actor { // // +k8s:optional ActorStatus status = 7; + + // shared_volume_bindings maps each unnamed external.shared_volume in the + // template, by volume name, to the SharedVolume this actor mounts. Every + // unnamed ref must be bound; a named ref cannot be rebound. Set at creation. + // + // +k8s:optional + // +k8s:maxProperties=32 + // +k8s:eachKey=+k8s:format=k8s-short-name + // +k8s:eachVal=+k8s:format=k8s-short-name + // +k8s:immutable + map shared_volume_bindings = 8; } // EgressPolicy is an egress policy resource nested under an Actor. An Actor has @@ -1505,6 +1525,7 @@ message Volume { // +k8s:unionMember ExternalVolumeSource external = 7; + // +k8s:optional // +k8s:unionMember SystemInfoVolumeSource system_info = 5; @@ -1524,6 +1545,12 @@ message ExternalVolumeSource { // +k8s:optional // +k8s:unionMember ExternalVolumeTemplate template = 1; + + // shared_volume mounts a SharedVolume that already exists. + // + // +k8s:optional + // +k8s:unionMember + SharedVolumeRef shared_volume = 2; } // ImageVolumeSource mounts the contents of an OCI image, read-only. The @@ -1562,6 +1589,17 @@ message ExternalVolumeTemplate { string storage_class_name = 2; } +// SharedVolumeRef mounts a SharedVolume in the actor's atespace. The +// volume outlives the actor, so several actors can mount it in turn. +message SharedVolumeRef { + // name of the SharedVolume. Left empty, the actor names it at creation in + // Actor.shared_volume_bindings. + // + // +k8s:optional + // +k8s:format=k8s-short-name + string name = 1; +} + // SystemInfoVolumeSource is a read-only volume of substrate-generated // per-actor files (identity fields, projected trust bundles), regenerated by // atelet on every Run/Restore. From 21adc9a3b56a6b7542b076dc9a517949746186b5 Mon Sep 17 00:00:00 2001 From: Elijah Rodriguez Date: Wed, 14 Oct 2026 10:37:35 -0700 Subject: [PATCH 05/12] ateapi: cold-boot actors whose template references a SharedVolume The golden actor warms up against a local empty directory in place of a shared volume, but runsc derives the disable_file_handle_sharing mount option from the bind source's filesystem and refuses a restore whose mount options differ from the checkpoint's. On NFS the first resume of every such actor therefore failed with "Mounts" does not match across checkpoint restore. Actors created from a template that references a SharedVolume no longer seed from the golden tag: the first resume boots from the image and later resumes restore the actor's own snapshot, which was taken over the real volume. An explicit source tag is refused for these templates. Golden restores for shared volumes remain follow-up work, tracked by TODO(shared-volumes). Co-Authored-By: Claude Fable 5.1 --- cmd/ateapi/internal/controlapi/actor.go | 12 +- .../shared_volume_golden_test.go | 151 ++++++++++++++++++ .../controlapi/shared_volume_golden_test.go | 45 ++++++ .../internal/controlapi/shared_volume_refs.go | 9 ++ docs/csi-volumes.md | 15 +- pkg/proto/ateapipb/ateapi.pb.go | 4 + pkg/proto/ateapipb/ateapi.proto | 4 + 7 files changed, 235 insertions(+), 5 deletions(-) create mode 100644 cmd/ateapi/internal/controlapi/functionaltest/shared_volume_golden_test.go create mode 100644 cmd/ateapi/internal/controlapi/shared_volume_golden_test.go diff --git a/cmd/ateapi/internal/controlapi/actor.go b/cmd/ateapi/internal/controlapi/actor.go index 985b704916..d85025e812 100644 --- a/cmd/ateapi/internal/controlapi/actor.go +++ b/cmd/ateapi/internal/controlapi/actor.go @@ -89,15 +89,21 @@ func (s *ServiceImpl) CreateActor(ctx context.Context, inActor *ateapipb.Actor) // Resolve the explicit tag, or freeze the template's current golden default. tagRef := inActor.GetSourceTag() - if tagRef == nil { - tagRef = template.GetStatus().GetGoldenSnapshotStatus().GetGoldenTag() - } else { + switch { + case tagRef != nil: for _, volume := range template.GetVolumes() { if volume.GetExternal().GetTemplate() != nil { // TODO: Permit cloning after CSI volume snapshots are supported. return nil, apierror.FailedPrecondition("Tag cloning does not support ActorTemplates with external volumes") } + if volume.GetExternal().GetSharedVolume() != nil { + return nil, apierror.FailedPrecondition("Tag cloning does not support ActorTemplates that reference a SharedVolume") + } } + case templateHasSharedVolumeRef(template): + // TODO(shared-volumes): restore from the golden once checkpoint and restore mount options agree for external volume refs; see docs/csi-volumes.md. + default: + tagRef = template.GetStatus().GetGoldenSnapshotStatus().GetGoldenTag() } var sourceTag *ateapipb.Tag if tagRef != nil { diff --git a/cmd/ateapi/internal/controlapi/functionaltest/shared_volume_golden_test.go b/cmd/ateapi/internal/controlapi/functionaltest/shared_volume_golden_test.go new file mode 100644 index 0000000000..b907193c11 --- /dev/null +++ b/cmd/ateapi/internal/controlapi/functionaltest/shared_volume_golden_test.go @@ -0,0 +1,151 @@ +// 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 functionaltest + +import ( + "context" + "testing" + + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" + "google.golang.org/grpc/codes" +) + +func resetAteletCalls(tc *testContext) { + tc.fakeAtelet.Lock.Lock() + defer tc.fakeAtelet.Lock.Unlock() + tc.fakeAtelet.RunCalled, tc.fakeAtelet.RunRequest = false, nil + tc.fakeAtelet.RestoreCalled, tc.fakeAtelet.RestoreRequest = false, nil +} + +func ateletCalls(tc *testContext) (run, restore bool) { + tc.fakeAtelet.Lock.Lock() + defer tc.fakeAtelet.Lock.Unlock() + return tc.fakeAtelet.RunCalled, tc.fakeAtelet.RestoreCalled +} + +func getActor(t *testing.T, tc *testContext, name string) *ateapipb.Actor { + t.Helper() + actor, err := tc.client.GetActor(context.Background(), &ateapipb.GetActorRequest{ + Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: name}, + }) + if err != nil { + t.Fatalf("GetActor(%s) failed: %v", name, err) + } + return actor +} + +func TestSharedVolumeRef_ColdBootsThenRestoresOwnSnapshot(t *testing.T) { + ns := namespaceForTest("ns-extvol-coldboot") + tc, _ := setupSharedVolumeTest(t, ns) + defer tc.cleanup() + + createSharedVolume(t, tc, "shared", ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL) + tmpl := createTemplateWithVolumes(t, tc, ns, + []*ateapipb.Volume{{Name: "work", External: &ateapipb.ExternalVolumeSource{SharedVolume: &ateapipb.SharedVolumeRef{Name: "shared"}}}}, + []*ateapipb.VolumeMount{{Name: "work", MountPath: "/mnt/work"}}) + if tmpl.GetStatus().GetGoldenSnapshotStatus().GetGoldenTag() == nil { + t.Fatal("test template has no golden tag; the case needs one to prove it is bypassed") + } + workerName := createWorkerPod(t, tc, ns, "worker-1", "node1", "pool1") + ctx := context.Background() + ref := &ateapipb.ObjectRef{Atespace: testAtespace, Name: "borrower"} + + createBorrowingActor(t, tc, "borrower", nil) + if snaps := getActor(t, tc, "borrower").GetStatus().GetSnapshots(); len(snaps) != 0 { + t.Fatalf("new actor carries snapshots %v, want none: it must not seed from the golden", snaps) + } + + waitForWorkerAvailable(t, tc, workerName) + resetAteletCalls(tc) + if _, err := tc.client.ResumeActor(ctx, &ateapipb.ResumeActorRequest{Actor: ref}); err != nil { + t.Fatalf("first ResumeActor failed: %v", err) + } + if run, restore := ateletCalls(tc); !run || restore { + t.Fatalf("first resume: Run=%v Restore=%v, want a cold boot through Run", run, restore) + } + + if _, err := tc.client.SuspendActor(ctx, &ateapipb.SuspendActorRequest{Actor: ref}); err != nil { + t.Fatalf("SuspendActor failed: %v", err) + } + own := durableSnapshotURI(getActor(t, tc, "borrower").GetStatus()) + if own == "" || own == goldenSnapshotURI(t) { + t.Fatalf("snapshot after suspend = %q, want the actor's own", own) + } + + waitForWorkerAvailable(t, tc, workerName) + resetAteletCalls(tc) + if _, err := tc.client.ResumeActor(ctx, &ateapipb.ResumeActorRequest{Actor: ref}); err != nil { + t.Fatalf("second ResumeActor failed: %v", err) + } + if run, restore := ateletCalls(tc); run || !restore { + t.Fatalf("second resume: Run=%v Restore=%v, want a restore", run, restore) + } + if got := tc.fakeAtelet.lastRestoreRequest().GetExternalConfig().GetSnapshotUri(); got != own { + t.Errorf("second resume restored %q, want the actor's own snapshot %q", got, own) + } +} + +func TestSharedVolumeRef_RejectsSourceTag(t *testing.T) { + ns := namespaceForTest("ns-extvol-sourcetag") + tc, _ := setupSharedVolumeTest(t, ns) + defer tc.cleanup() + + createSharedVolume(t, tc, "shared", ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL) + tmpl := createTemplateWithVolumes(t, tc, ns, + []*ateapipb.Volume{{Name: "work", External: &ateapipb.ExternalVolumeSource{SharedVolume: &ateapipb.SharedVolumeRef{Name: "shared"}}}}, + []*ateapipb.VolumeMount{{Name: "work", MountPath: "/mnt/work"}}) + + _, err := tc.client.CreateActor(context.Background(), &ateapipb.CreateActorRequest{Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "clone"}, + ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"}, + SourceTag: tmpl.GetStatus().GetGoldenSnapshotStatus().GetGoldenTag(), + }}) + assertGrpcError(t, err, codes.FailedPrecondition, "Tag cloning does not support ActorTemplates that reference a SharedVolume") +} + +func TestExternalVolumeTemplate_FirstResumeRestoresGolden(t *testing.T) { + ns := namespaceForTest("ns-extvol-owned-golden") + tc, _ := setupSharedVolumeTest(t, ns) + defer tc.cleanup() + + createTemplateWithVolumes(t, tc, ns, + []*ateapipb.Volume{{Name: "work", External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{StorageClassName: "standard", Capacity: "1Gi"}}}}, + []*ateapipb.VolumeMount{{Name: "work", MountPath: "/mnt/work"}}) + workerName := createWorkerPod(t, tc, ns, "worker-1", "node1", "pool1") + ctx := context.Background() + ref := &ateapipb.ObjectRef{Atespace: testAtespace, Name: "owner"} + + if _, err := tc.client.CreateActor(ctx, &ateapipb.CreateActorRequest{Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "owner"}, + ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"}, + }}); err != nil { + t.Fatalf("CreateActor failed: %v", err) + } + if got := durableSnapshotURI(getActor(t, tc, "owner").GetStatus()); got != goldenSnapshotURI(t) { + t.Fatalf("new actor snapshot = %q, want the golden %q", got, goldenSnapshotURI(t)) + } + + waitForWorkerAvailable(t, tc, workerName) + resetAteletCalls(tc) + if _, err := tc.client.ResumeActor(ctx, &ateapipb.ResumeActorRequest{Actor: ref}); err != nil { + t.Fatalf("ResumeActor failed: %v", err) + } + if run, restore := ateletCalls(tc); run || !restore { + t.Fatalf("first resume: Run=%v Restore=%v, want a restore from the golden", run, restore) + } + if got := tc.fakeAtelet.lastRestoreRequest().GetExternalConfig().GetSnapshotUri(); got != goldenSnapshotURI(t) { + t.Errorf("first resume restored %q, want the golden %q", got, goldenSnapshotURI(t)) + } +} diff --git a/cmd/ateapi/internal/controlapi/shared_volume_golden_test.go b/cmd/ateapi/internal/controlapi/shared_volume_golden_test.go new file mode 100644 index 0000000000..d292dea526 --- /dev/null +++ b/cmd/ateapi/internal/controlapi/shared_volume_golden_test.go @@ -0,0 +1,45 @@ +// 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 ( + "testing" + + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" +) + +func TestTemplateHasSharedVolumeRef(t *testing.T) { + tests := []struct { + name string + volumes []*ateapipb.Volume + want bool + }{ + {name: "no volumes"}, + {name: "durable dir only", volumes: []*ateapipb.Volume{{Name: "home", DurableDir: &ateapipb.DurableDirVolumeSource{}}}}, + {name: "shared volume template", volumes: []*ateapipb.Volume{{Name: "owned", External: &ateapipb.ExternalVolumeSource{Template: &ateapipb.ExternalVolumeTemplate{StorageClassName: "standard"}}}}}, + {name: "named ref", volumes: []*ateapipb.Volume{{Name: "shared", External: &ateapipb.ExternalVolumeSource{SharedVolume: &ateapipb.SharedVolumeRef{Name: "ctx"}}}}, want: true}, + {name: "unnamed ref after other volumes", volumes: []*ateapipb.Volume{ + {Name: "home", DurableDir: &ateapipb.DurableDirVolumeSource{}}, + {Name: "shared", External: &ateapipb.ExternalVolumeSource{SharedVolume: &ateapipb.SharedVolumeRef{}}}, + }, want: true}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + if got := templateHasSharedVolumeRef(&ateapipb.ActorTemplate{Volumes: tc.volumes}); got != tc.want { + t.Errorf("templateHasSharedVolumeRef() = %v, want %v", got, tc.want) + } + }) + } +} diff --git a/cmd/ateapi/internal/controlapi/shared_volume_refs.go b/cmd/ateapi/internal/controlapi/shared_volume_refs.go index 2670c096ae..cb67abb13d 100644 --- a/cmd/ateapi/internal/controlapi/shared_volume_refs.go +++ b/cmd/ateapi/internal/controlapi/shared_volume_refs.go @@ -37,6 +37,15 @@ type sharedVolumeDeleter interface { DeleteSharedVolume(ctx context.Context, volumeRef resources.SharedVolumeRef, precondition store.DeletePreconditions) (*ateapipb.SharedVolume, error) } +func templateHasSharedVolumeRef(template *ateapipb.ActorTemplate) bool { + for _, vol := range template.GetVolumes() { + if vol.GetExternal().GetSharedVolume() != nil { + return true + } + } + return false +} + // resolveSharedVolumeRefs checks the actor's bindings against the template // and returns a mount for every SharedVolume the actor references. func resolveSharedVolumeRefs(ctx context.Context, st sharedVolumeRefStore, actor *ateapipb.Actor, template *ateapipb.ActorTemplate) ([]*ateapipb.ExternalVolumeRef, error) { diff --git a/docs/csi-volumes.md b/docs/csi-volumes.md index 4120dcf903..9a4d501d78 100644 --- a/docs/csi-volumes.md +++ b/docs/csi-volumes.md @@ -231,5 +231,16 @@ kubectl ate create actor consumer-42 -a demo --template consumer --volume shared ``` Bindings are validated and recorded when the actor is created and cannot change -afterwards. Golden actors never reference a shared volume; they warm up against -an empty directory at the same mount path. +afterwards. + +The golden snapshot is not used for templates that reference a `SharedVolume`. The +first resume of such an actor is a cold boot from the image, and later resumes +restore the actor's own snapshot, which was taken over the real volume. An +explicit `sourceTag` is refused at actor creation. The reason is in gVisor: +the golden actor warms up against a local empty directory at the mount path, +but runsc derives the `disable_file_handle_sharing` mount option from the bind +source's filesystem (NFS and FUSE get it, local disks do not) and refuses a +restore whose mount options differ from the checkpoint's. Supporting golden +restores here is follow-up work; the candidate approaches are a golden actor +that warms up on a scratch volume from the same driver, or an upstream runsc +change that excludes host-derived mount options from restore validation. diff --git a/pkg/proto/ateapipb/ateapi.pb.go b/pkg/proto/ateapipb/ateapi.pb.go index edfdb214d0..021f4cfdd4 100644 --- a/pkg/proto/ateapipb/ateapi.pb.go +++ b/pkg/proto/ateapipb/ateapi.pb.go @@ -4432,6 +4432,10 @@ func (x *ExternalVolumeTemplate) GetStorageClassName() string { // SharedVolumeRef mounts a SharedVolume in the actor's atespace. The // volume outlives the actor, so several actors can mount it in turn. +// +// Actors created from a template with a SharedVolumeRef do not start from +// the template's golden snapshot: the first resume boots from the image, and +// later resumes restore the actor's own snapshot. type SharedVolumeRef struct { state protoimpl.MessageState `protogen:"open.v1"` // name of the SharedVolume. Left empty, the actor names it at creation in diff --git a/pkg/proto/ateapipb/ateapi.proto b/pkg/proto/ateapipb/ateapi.proto index 073f1f3c32..0feca0f918 100644 --- a/pkg/proto/ateapipb/ateapi.proto +++ b/pkg/proto/ateapipb/ateapi.proto @@ -1591,6 +1591,10 @@ message ExternalVolumeTemplate { // SharedVolumeRef mounts a SharedVolume in the actor's atespace. The // volume outlives the actor, so several actors can mount it in turn. +// +// Actors created from a template with a SharedVolumeRef do not start from +// the template's golden snapshot: the first resume boots from the image, and +// later resumes restore the actor's own snapshot. message SharedVolumeRef { // name of the SharedVolume. Left empty, the actor names it at creation in // Actor.shared_volume_bindings. From 4bd64f53baa96f3772f0845a7b3ec9cc20915a85 Mon Sep 17 00:00:00 2001 From: Salah Date: Wed, 14 Oct 2026 22:35:10 +0400 Subject: [PATCH 06/12] Add a probe for filesystem state retained across snapshots --- internal/e2e/fixtures/probe/main.go | 1 + internal/e2e/fixtures/probe/volume-state.md | 56 +++++ internal/e2e/fixtures/probe/volume_state.go | 191 ++++++++++++++++++ .../e2e/fixtures/probe/volume_state_test.go | 187 +++++++++++++++++ 4 files changed, 435 insertions(+) create mode 100644 internal/e2e/fixtures/probe/volume-state.md create mode 100644 internal/e2e/fixtures/probe/volume_state.go create mode 100644 internal/e2e/fixtures/probe/volume_state_test.go diff --git a/internal/e2e/fixtures/probe/main.go b/internal/e2e/fixtures/probe/main.go index 9db51f30db..69b9840cc6 100644 --- a/internal/e2e/fixtures/probe/main.go +++ b/internal/e2e/fixtures/probe/main.go @@ -452,6 +452,7 @@ func main() { mux := http.NewServeMux() mux.HandleFunc("/whoami", whoami) mux.HandleFunc("/fetch", fetch) + mux.HandleFunc("/volume-state", (&volumeStateProbe{}).serveHTTP) mux.HandleFunc("/readfile", readfile) mux.HandleFunc("/writefile", writefile) mux.HandleFunc("/resources", resources) diff --git a/internal/e2e/fixtures/probe/volume-state.md b/internal/e2e/fixtures/probe/volume-state.md new file mode 100644 index 0000000000..e4f9641a25 --- /dev/null +++ b/internal/e2e/fixtures/probe/volume-state.md @@ -0,0 +1,56 @@ +# Filesystem state across snapshots + +`/volume-state` is an opt-in, destructive probe for a **disposable writable +fixture directory**. It observes process memory and retained descriptors. It +does not enable external-volume golden restores or assert that a restore is safe. + +Before capture, provision these small fixtures (each file at most 4096 bytes): + +- `cached.txt`: distinguishable source content copied into process memory. +- `held.txt`: a file kept open and read before capture. +- `unlinked.txt`: a file opened, read, and unlinked by the probe before capture. +- `directory/`: a directory kept open and enumerated before capture. +- `negative.txt`: must be absent; priming performs a negative lookup. + +Use different sentinel contents for the source, actor A and actor B. Keep +expected values in the test controller, outside the captured process. + +1. POST `/volume-state?root=&challenge=`. + Expect 204. Priming unlinks `unlinked.txt`; it must be on writable scratch + storage. A second POST returns 409, even after a successful memory restore. +2. GET `/volume-state` and record the response before capturing the snapshot. + The response includes the challenge, an increasing read count, application + memory (`cached`), a fresh read of `cached.txt` (`by_path`), retained file + reads (`held`, `unlinked`), a fresh lookup (`negative`), and enumeration through + the retained directory descriptor (`directory`). Errors are reported separately + and must be asserted by the test; HTTP 200 alone is not success. +3. Restore the captured snapshot, then GET only. Do not POST to the clone. + An unprimed process returns 409, so a cold fallback cannot silently pass this + continuity check. Require the original challenge and a count greater than + the pre-capture count. Independently verify the source snapshot ID and runtime + restore path; a live source process also retains the challenge. +4. After an own-snapshot capture, check the challenge and count again. This + catches loss of probe state in second-generation captures. +5. DELETE `/volume-state` closes descriptors and clears state. It does not + recreate the unlinked file. It returns 204 even when already unprimed. + +For substitution experiments, seed the target backing tree from the host while +workloads are stopped. Create `negative.txt`, use distinct `cached.txt` and +`held.txt` contents, and give `directory/` different entries. Preserve all raw +responses, including read errors. An open deleted file may not be reconstructible +by path. A successful VM resume, EIO, or continued source content is not evidence +of safe substitution. In particular, the `cached` field is a deliberate copy in +application memory: host path rewrites or kernel cache invalidation cannot turn +it into target content. + +An empty production placeholder needs a separate negative-lookup-only test. +These populated fixtures intentionally stress a more demanding contract; they +must not be described as the existing empty-placeholder golden workflow. +This endpoint is not yet wired into a cluster test or the automatic golden +capture lifecycle. It is a building block for that test, not an end-to-end result. + +The local tests replace files and directories on the host. They verify that the +probe distinguishes path reads, retained descriptors and application memory, +rejects unprimed reads/re-priming, cleans up failed priming, and serializes reads. +They do not test NFS, virtio-fs migration, mmap, read-only enforcement, actor +isolation or a restored VM. Those require separate runtime integration tests. diff --git a/internal/e2e/fixtures/probe/volume_state.go b/internal/e2e/fixtures/probe/volume_state.go new file mode 100644 index 0000000000..866a941ebe --- /dev/null +++ b/internal/e2e/fixtures/probe/volume_state.go @@ -0,0 +1,191 @@ +// 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 main + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "sort" + "sync" +) + +// volumeStateProbe retains guest process state across snapshots. A controller +// primes it once before capture and only GETs after restore. Re-priming a +// restored process would hide cold-boot fallbacks and stale filesystem state. +// Use only a disposable writable fixture directory containing cached.txt, +// held.txt, unlinked.txt and directory/, with negative.txt absent. +type volumeStateProbe struct { + mu sync.Mutex + root, challenge string + cached string + held, unlinked, directory *os.File + reads uint64 +} + +type volumeObservation struct { + Data string `json:"data"` + Error string `json:"error,omitempty"` + NotExist bool `json:"not_exist,omitempty"` +} + +type volumeStateResponse struct { + Challenge string `json:"challenge"` + Reads uint64 `json:"reads"` + Cached string `json:"cached"` + ByPath volumeObservation `json:"by_path"` + Held volumeObservation `json:"held"` + Unlinked volumeObservation `json:"unlinked"` + Negative volumeObservation `json:"negative"` + Directory []string `json:"directory"` + DirectoryError string `json:"directory_error,omitempty"` +} + +func volumeResult(data []byte, err error) volumeObservation { + if err != nil { + return volumeObservation{Error: err.Error(), NotExist: errors.Is(err, os.ErrNotExist)} + } + return volumeObservation{Data: string(data)} +} + +// Fixtures are deliberately small; oversized data is an error, never a +// truncated success that could hide the distinguishing part of a sentinel. +func volumeRead(f *os.File) volumeObservation { + b := make([]byte, 4097) + n, err := f.ReadAt(b, 0) + if err == io.EOF { + err = nil + } + if n > 4096 { + err = fmt.Errorf("fixture exceeds 4096 bytes") + } + return volumeResult(b[:n], err) +} + +func volumeReadPath(path string) volumeObservation { + f, err := os.Open(path) + if err != nil { + return volumeResult(nil, err) + } + defer f.Close() + return volumeRead(f) +} + +func (p *volumeStateProbe) close() { + for _, f := range []*os.File{p.held, p.unlinked, p.directory} { + if f != nil { + _ = f.Close() + } + } + p.held, p.unlinked, p.directory = nil, nil, nil + p.root, p.challenge, p.cached, p.reads = "", "", "", 0 +} + +func (p *volumeStateProbe) prime(root, challenge string) (err error) { + if !filepath.IsAbs(root) || challenge == "" || len(challenge) > 256 { + return fmt.Errorf("absolute root and challenge of 1..256 bytes required") + } + defer func() { + if err != nil { + p.close() + } + }() + cached := volumeReadPath(filepath.Join(root, "cached.txt")) + if cached.Error != "" { + return fmt.Errorf("cached.txt: %s", cached.Error) + } + if _, err = os.Stat(filepath.Join(root, "negative.txt")); !errors.Is(err, os.ErrNotExist) { + return fmt.Errorf("negative.txt must be absent (stat: %v)", err) + } + if p.held, err = os.Open(filepath.Join(root, "held.txt")); err != nil { + return err + } + if p.directory, err = os.Open(filepath.Join(root, "directory")); err != nil { + return err + } + if _, err = p.directory.Readdirnames(-1); err != nil { + return err + } + if p.unlinked, err = os.Open(filepath.Join(root, "unlinked.txt")); err != nil { + return err + } + // Warm the kernel's file data while retaining descriptors. The response + // separately exposes an application-memory copy that remounting cannot reset. + for _, f := range []*os.File{p.held, p.unlinked} { + if v := volumeRead(f); v.Error != "" { + return fmt.Errorf("warming fixture: %s", v.Error) + } + } + if err = os.Remove(filepath.Join(root, "unlinked.txt")); err != nil { + return err + } + p.root, p.challenge, p.cached = root, challenge, cached.Data + return nil +} + +func (p *volumeStateProbe) observe() volumeStateResponse { + p.reads++ + out := volumeStateResponse{ + Challenge: p.challenge, Reads: p.reads, Cached: p.cached, + ByPath: volumeReadPath(filepath.Join(p.root, "cached.txt")), + Held: volumeRead(p.held), Unlinked: volumeRead(p.unlinked), + Negative: volumeReadPath(filepath.Join(p.root, "negative.txt")), + } + if _, err := p.directory.Seek(0, io.SeekStart); err != nil { + out.DirectoryError = err.Error() + } else { + names, err := p.directory.Readdirnames(-1) + out.Directory = names + sort.Strings(out.Directory) + if err != nil { + out.DirectoryError = err.Error() + } + } + return out +} + +func (p *volumeStateProbe) serveHTTP(w http.ResponseWriter, r *http.Request) { + p.mu.Lock() + defer p.mu.Unlock() + switch r.Method { + case http.MethodPost: + if p.challenge != "" { + http.Error(w, "already primed", http.StatusConflict) + return + } + if err := p.prime(r.URL.Query().Get("root"), r.URL.Query().Get("challenge")); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + w.WriteHeader(http.StatusNoContent) + case http.MethodGet: + if p.challenge == "" { + http.Error(w, "not primed", http.StatusConflict) + return + } + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(p.observe()) + case http.MethodDelete: + p.close() + w.WriteHeader(http.StatusNoContent) + default: + w.Header().Set("Allow", "POST, GET, DELETE") + http.Error(w, "method not allowed", http.StatusMethodNotAllowed) + } +} diff --git a/internal/e2e/fixtures/probe/volume_state_test.go b/internal/e2e/fixtures/probe/volume_state_test.go new file mode 100644 index 0000000000..a898862102 --- /dev/null +++ b/internal/e2e/fixtures/probe/volume_state_test.go @@ -0,0 +1,187 @@ +// 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 main + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "net/url" + "os" + "path/filepath" + "strings" + "sync" + "testing" +) + +func volumeFixture(t *testing.T) string { + t.Helper() + root := t.TempDir() + if err := os.Mkdir(filepath.Join(root, "directory"), 0700); err != nil { + t.Fatal(err) + } + for _, name := range []string{"cached.txt", "held.txt", "unlinked.txt", "directory/old"} { + volumeWrite(t, filepath.Join(root, name), "source-"+name) + } + return root +} + +func volumeWrite(t *testing.T, path, value string) { + t.Helper() + if err := os.WriteFile(path, []byte(value), 0600); err != nil { + t.Fatal(err) + } +} + +func volumeRequest(p *volumeStateProbe, method, target string) *httptest.ResponseRecorder { + w := httptest.NewRecorder() + p.serveHTTP(w, httptest.NewRequest(method, target, nil)) + return w +} + +func volumePrime(t *testing.T, p *volumeStateProbe, root string) { + t.Helper() + w := volumeRequest(p, http.MethodPost, "/volume-state?root="+url.QueryEscape(root)+"&challenge=capture-unique-token") + if w.Code != http.StatusNoContent { + t.Fatalf("prime: %d %s", w.Code, w.Body.String()) + } + t.Cleanup(p.close) +} + +func volumeObserve(t *testing.T, p *volumeStateProbe) volumeStateResponse { + t.Helper() + w := volumeRequest(p, http.MethodGet, "/volume-state") + if w.Code != http.StatusOK { + t.Fatalf("observe: %d %s", w.Code, w.Body.String()) + } + var out volumeStateResponse + if err := json.Unmarshal(w.Body.Bytes(), &out); err != nil { + t.Fatal(err) + } + return out +} + +// Ordinary host file replacement validates the probe's ability to distinguish +// path reads, open descriptors and application memory. It is not a VM restore. +func TestVolumeStateDistinguishesRetainedState(t *testing.T) { + p := &volumeStateProbe{} + root := volumeFixture(t) + volumePrime(t, p, root) + first := volumeObserve(t, p) + if !first.Negative.NotExist { + t.Fatalf("negative lookup: %+v", first.Negative) + } + if _, err := os.Stat(filepath.Join(root, "unlinked.txt")); !os.IsNotExist(err) { + t.Fatalf("unlink: %v", err) + } + volumeWrite(t, filepath.Join(root, "replacement"), "target-held") + if err := os.Rename(filepath.Join(root, "replacement"), filepath.Join(root, "held.txt")); err != nil { + t.Fatal(err) + } + volumeWrite(t, filepath.Join(root, "cached.txt"), "target-cached") + volumeWrite(t, filepath.Join(root, "negative.txt"), "target-negative") + if err := os.Rename(filepath.Join(root, "directory"), filepath.Join(root, "old-directory")); err != nil { + t.Fatal(err) + } + if err := os.Mkdir(filepath.Join(root, "directory"), 0700); err != nil { + t.Fatal(err) + } + volumeWrite(t, filepath.Join(root, "directory/new"), "target-directory") + got := volumeObserve(t, p) + if got.Challenge != "capture-unique-token" || got.Reads != 2 { + t.Fatalf("state continuity: %+v", got) + } + if got.Cached != "source-cached.txt" || got.ByPath.Data != "target-cached" || got.ByPath.Error != "" { + t.Fatalf("cache vs path: %+v", got) + } + if got.Held.Data != "source-held.txt" || got.Held.Error != "" { + t.Fatalf("held descriptor: %+v", got.Held) + } + if got.Unlinked.Data != "source-unlinked.txt" || got.Unlinked.Error != "" { + t.Fatalf("unlinked descriptor: %+v", got.Unlinked) + } + if got.Negative.Data != "target-negative" || got.Negative.Error != "" { + t.Fatalf("negative lookup: %+v", got.Negative) + } + if got.DirectoryError != "" || strings.Join(got.Directory, ",") != "old" { + t.Fatalf("held directory: %+v", got) + } +} + +func TestVolumeStateColdBootAndReprimeFail(t *testing.T) { + p := &volumeStateProbe{} + if w := volumeRequest(p, http.MethodGet, "/volume-state"); w.Code != http.StatusConflict { + t.Fatalf("unprimed returned %d", w.Code) + } + root := volumeFixture(t) + volumePrime(t, p, root) + if w := volumeRequest(p, http.MethodPost, "/volume-state"); w.Code != http.StatusConflict { + t.Fatalf("reprime returned %d", w.Code) + } + if w := volumeRequest(p, http.MethodDelete, "/volume-state"); w.Code != http.StatusNoContent { + t.Fatalf("release returned %d", w.Code) + } + if w := volumeRequest(p, http.MethodGet, "/volume-state"); w.Code != http.StatusConflict { + t.Fatalf("released returned %d", w.Code) + } +} + +func TestVolumeStatePrimeFailureClosesDescriptors(t *testing.T) { + p := &volumeStateProbe{} + root := volumeFixture(t) + if err := os.Remove(filepath.Join(root, "unlinked.txt")); err != nil { + t.Fatal(err) + } + w := volumeRequest(p, http.MethodPost, "/volume-state?root="+url.QueryEscape(root)+"&challenge=test") + if w.Code != http.StatusBadRequest { + t.Fatalf("missing fixture returned %d", w.Code) + } + if p.held != nil || p.directory != nil || p.unlinked != nil || p.challenge != "" { + t.Fatal("failed prime retained state") + } + volumeWrite(t, filepath.Join(root, "unlinked.txt"), "repaired") + volumePrime(t, p, root) +} + +func TestVolumeStateOversizeAndUnexpectedNegativeFail(t *testing.T) { + for _, name := range []string{"cached.txt", "negative.txt"} { + t.Run(name, func(t *testing.T) { + root := volumeFixture(t) + volumeWrite(t, filepath.Join(root, name), strings.Repeat("x", 4097)) + p := &volumeStateProbe{} + defer p.close() + if err := p.prime(root, "test"); err == nil { + t.Fatal("invalid fixture accepted") + } + }) + } +} + +func TestVolumeStateConcurrentReads(t *testing.T) { + p := &volumeStateProbe{} + volumePrime(t, p, volumeFixture(t)) + var wg sync.WaitGroup + for range 16 { + wg.Go(func() { + if w := volumeRequest(p, http.MethodGet, "/volume-state"); w.Code != http.StatusOK { + t.Errorf("read returned %d", w.Code) + } + }) + } + wg.Wait() + if got := volumeObserve(t, p); got.Reads != 17 { + t.Fatalf("reads = %d", got.Reads) + } +} From 922f2499c76b991e8d73ba3a04812585208109a7 Mon Sep 17 00:00:00 2001 From: Salah Date: Thu, 15 Oct 2026 00:48:36 +0400 Subject: [PATCH 07/12] Add opt-in pre-application microVM golden snapshots --- .../internal/apivalidation/actor_template.go | 3 + .../apivalidation/actor_template_test.go | 14 +- .../apivalidation/zz_generated.validation.go | 2 +- cmd/ateapi/internal/controlapi/actor.go | 2 +- .../internal/controlapi/workload_spec.go | 4 +- .../internal/controlapi/workload_spec_test.go | 19 ++ .../apivalidation/zz_generated.validation.go | 28 ++ cmd/atelet/main.go | 2 +- cmd/ateom-gvisor/main.go | 3 + cmd/ateom-microvm/checkpoint.go | 9 + cmd/ateom-microvm/restore.go | 12 + cmd/ateom-microvm/run.go | 36 +- cmd/ateom-microvm/runtime_golden.go | 40 +++ cmd/ateom-microvm/runtime_golden_test.go | 57 ++++ docs/csi-volumes.md | 33 +- internal/e2e/fixtures/probe/main.go | 2 + internal/e2e/fixtures/probe/runtime_state.go | 90 +++++ .../e2e/fixtures/probe/runtime_state_test.go | 50 +++ .../combinedvolumes/runtime_golden_test.go | 318 ++++++++++++++++++ internal/proto/ateletpb/atelet.pb.go | 17 +- internal/proto/ateletpb/atelet.proto | 4 + internal/proto/ateompb/ateom.pb.go | 19 +- internal/proto/ateompb/ateom.proto | 3 + pkg/proto/ateapipb/ateapi.pb.go | 18 +- pkg/proto/ateapipb/ateapi.proto | 11 +- 25 files changed, 755 insertions(+), 41 deletions(-) create mode 100644 cmd/ateom-microvm/runtime_golden.go create mode 100644 cmd/ateom-microvm/runtime_golden_test.go create mode 100644 internal/e2e/fixtures/probe/runtime_state.go create mode 100644 internal/e2e/fixtures/probe/runtime_state_test.go create mode 100644 internal/e2e/suites/combinedvolumes/runtime_golden_test.go diff --git a/cmd/ateapi/internal/apivalidation/actor_template.go b/cmd/ateapi/internal/apivalidation/actor_template.go index 483861fe91..af93bee274 100644 --- a/cmd/ateapi/internal/apivalidation/actor_template.go +++ b/cmd/ateapi/internal/apivalidation/actor_template.go @@ -63,6 +63,9 @@ func ValidateActorTemplateUpdate(ctx context.Context, fldPath *field.Path, newVa // today is the micro-VM class alone. func ValidateCustom_CreateActorTemplateRequest_ActorTemplate(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ *ateapipb.ActorTemplate) field.ErrorList { var errs field.ErrorList + if value.GetSnapshotConfig().GetGoldenSnapshotConfig().GetMode() == ateapipb.GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_RUNTIME && value.GetSandboxConfig().GetSandboxClass() != ateapipb.SandboxClass_SANDBOX_CLASS_MICROVM { + errs = append(errs, field.Invalid(fldPath.Child("snapshot_config", "golden_snapshot_config", "mode"), "RUNTIME", "runtime golden snapshots require MICROVM")) + } if value.GetSnapshotConfig().GetPreferredFidelity() == ateapipb.SnapshotFidelity_SNAPSHOT_FIDELITY_ROOTFS && value.GetSandboxConfig().GetSandboxClass() != ateapipb.SandboxClass_SANDBOX_CLASS_MICROVM { errs = append(errs, field.Invalid( diff --git a/cmd/ateapi/internal/apivalidation/actor_template_test.go b/cmd/ateapi/internal/apivalidation/actor_template_test.go index 41ab3a32b5..e97c14289f 100644 --- a/cmd/ateapi/internal/apivalidation/actor_template_test.go +++ b/cmd/ateapi/internal/apivalidation/actor_template_test.go @@ -34,6 +34,18 @@ func TestValidateCreateActorTemplateRequest(t *testing.T) { "valid", &ateapipb.CreateActorTemplateRequest{ActorTemplate: validActorTemplate()}, nil, + }, { + "runtime golden requires microvm", + &ateapipb.CreateActorTemplateRequest{ActorTemplate: validActorTemplate(func(x *ateapipb.ActorTemplate) { + x.SnapshotConfig.GoldenSnapshotConfig = &ateapipb.GoldenSnapshotConfig{Mode: ateapipb.GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_RUNTIME} + })}, + field.ErrorList{field.Invalid(field.NewPath("actor_template", "snapshot_config", "golden_snapshot_config", "mode"), "RUNTIME", "")}, + }, { + "runtime golden microvm", + &ateapipb.CreateActorTemplateRequest{ActorTemplate: validActorTemplate(func(x *ateapipb.ActorTemplate) { + x.SnapshotConfig.GoldenSnapshotConfig = &ateapipb.GoldenSnapshotConfig{Mode: ateapipb.GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_RUNTIME} + x.SandboxConfig.SandboxClass = ateapipb.SandboxClass_SANDBOX_CLASS_MICROVM + })}, nil, }, { "missing actor_template", &ateapipb.CreateActorTemplateRequest{}, @@ -312,7 +324,7 @@ func TestValidateActorTemplate(t *testing.T) { }, { name: "golden snapshot mode unknown", mutate: func(tmpl *ateapipb.ActorTemplate) { - tmpl.SnapshotConfig.GoldenSnapshotConfig = &ateapipb.GoldenSnapshotConfig{Mode: ateapipb.GoldenSnapshotMode(3)} + tmpl.SnapshotConfig.GoldenSnapshotConfig = &ateapipb.GoldenSnapshotConfig{Mode: ateapipb.GoldenSnapshotMode(4)} }, want: field.ErrorList{field.Invalid(field.NewPath("snapshot_config", "golden_snapshot_config", "mode"), nil, "").WithOrigin("maximum")}, }, { diff --git a/cmd/ateapi/internal/apivalidation/zz_generated.validation.go b/cmd/ateapi/internal/apivalidation/zz_generated.validation.go index 0261d0895a..cfa4f0bc41 100644 --- a/cmd/ateapi/internal/apivalidation/zz_generated.validation.go +++ b/cmd/ateapi/internal/apivalidation/zz_generated.validation.go @@ -4956,7 +4956,7 @@ func Validate_GoldenSnapshotConfig( if earlyReturn { return // do not proceed } - if e := validate.Maximum(ctx, op, fldPath, obj, oldObj, 2); len(e) != 0 { + 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, 1); len(e) != 0 { diff --git a/cmd/ateapi/internal/controlapi/actor.go b/cmd/ateapi/internal/controlapi/actor.go index d85025e812..353c93b47e 100644 --- a/cmd/ateapi/internal/controlapi/actor.go +++ b/cmd/ateapi/internal/controlapi/actor.go @@ -100,7 +100,7 @@ func (s *ServiceImpl) CreateActor(ctx context.Context, inActor *ateapipb.Actor) return nil, apierror.FailedPrecondition("Tag cloning does not support ActorTemplates that reference a SharedVolume") } } - case templateHasSharedVolumeRef(template): + case templateHasSharedVolumeRef(template) && template.GetSnapshotConfig().GetGoldenSnapshotConfig().GetMode() != ateapipb.GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_RUNTIME: // TODO(shared-volumes): restore from the golden once checkpoint and restore mount options agree for external volume refs; see docs/csi-volumes.md. default: tagRef = template.GetStatus().GetGoldenSnapshotStatus().GetGoldenTag() diff --git a/cmd/ateapi/internal/controlapi/workload_spec.go b/cmd/ateapi/internal/controlapi/workload_spec.go index 102bf0286f..5fd80bde2c 100644 --- a/cmd/ateapi/internal/controlapi/workload_spec.go +++ b/cmd/ateapi/internal/controlapi/workload_spec.go @@ -49,7 +49,9 @@ func toAteletResources(r *ateapipb.Resources) (*ateletpb.ResourceLimits, error) // workloadSpecFromActorTemplate builds a WorkloadSpec from the template; // container env is copied verbatim. func workloadSpecFromActorTemplate(actorTemplate *ateapipb.ActorTemplate, actor *ateapipb.Actor, volumePublishContexts map[string]map[string]string) (*ateletpb.WorkloadSpec, error) { - workloadSpec := &ateletpb.WorkloadSpec{} + workloadSpec := &ateletpb.WorkloadSpec{ + RuntimeGolden: isGoldenActor(actor) && actorTemplate.GetSnapshotConfig().GetGoldenSnapshotConfig().GetMode() == ateapipb.GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_RUNTIME, + } // Convert volumes to atelet's representation. ActorTemplate validation has // already ensured that only one source is set. diff --git a/cmd/ateapi/internal/controlapi/workload_spec_test.go b/cmd/ateapi/internal/controlapi/workload_spec_test.go index 924b3e44e0..de9446e765 100644 --- a/cmd/ateapi/internal/controlapi/workload_spec_test.go +++ b/cmd/ateapi/internal/controlapi/workload_spec_test.go @@ -732,3 +732,22 @@ func TestWorkloadSpecBorrowedVolume(t *testing.T) { }) } } + +func TestRuntimeGoldenWorkloadBoundary(t *testing.T) { + for _, golden := range []bool{false, true} { + for _, mode := range []ateapipb.GoldenSnapshotMode{ateapipb.GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_ENABLED, ateapipb.GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_RUNTIME} { + a := &ateapipb.Actor{Metadata: &ateapipb.ResourceMetadata{Atespace: "users"}} + if golden { + a.Metadata.Atespace = resources.GoldenActorAtespace + } + tmpl := &ateapipb.ActorTemplate{SnapshotConfig: &ateapipb.SnapshotConfig{GoldenSnapshotConfig: &ateapipb.GoldenSnapshotConfig{Mode: mode}}} + spec, err := workloadSpecFromActorTemplate(tmpl, a, nil) + if err != nil { + t.Fatal(err) + } + if spec.GetRuntimeGolden() != (golden && mode == ateapipb.GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_RUNTIME) { + t.Fatalf("incorrect boundary: golden=%v mode=%v spec=%v", golden, mode, spec) + } + } + } +} diff --git a/cmd/atelet/internal/apivalidation/zz_generated.validation.go b/cmd/atelet/internal/apivalidation/zz_generated.validation.go index 24d49d0da7..2d980539fc 100644 --- a/cmd/atelet/internal/apivalidation/zz_generated.validation.go +++ b/cmd/atelet/internal/apivalidation/zz_generated.validation.go @@ -4748,5 +4748,33 @@ func Validate_WorkloadSpec( errs = append(errs, fn(fldPath.Child("volumes"), obj.Volumes, oldVal, oldObj != nil)...) } + { // field ateletpb.WorkloadSpec.RuntimeGolden + 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 *ateletpb.WorkloadSpec) *bool { + return &oldObj.RuntimeGolden + }) + errs = append(errs, fn(fldPath.Child("runtime_golden"), &obj.RuntimeGolden, oldVal, oldObj != nil)...) + } + return errs } diff --git a/cmd/atelet/main.go b/cmd/atelet/main.go index 46731542c0..379b6a4d4c 100644 --- a/cmd/atelet/main.go +++ b/cmd/atelet/main.go @@ -1568,7 +1568,7 @@ func buildAteomWorkloadSpec(spec *ateletpb.WorkloadSpec, containerSpecs []*ateom volumes[name] = vol } - out := &ateompb.WorkloadSpec{} + out := &ateompb.WorkloadSpec{RuntimeGolden: spec.GetRuntimeGolden()} for i, ctr := range spec.GetContainers() { var ddMounts []*ateompb.DurableDirVolumeMount var csiMounts []*ateompb.VolumeMount diff --git a/cmd/ateom-gvisor/main.go b/cmd/ateom-gvisor/main.go index b5b3229815..aa905975c7 100644 --- a/cmd/ateom-gvisor/main.go +++ b/cmd/ateom-gvisor/main.go @@ -563,6 +563,9 @@ func validateFidelity(fidelity ateompb.SnapshotFidelity) error { } func (s *AteomService) RunWorkload(ctx context.Context, req *ateompb.RunWorkloadRequest) (resp *ateompb.RunWorkloadResponse, retErr error) { + if req.GetSpec().GetRuntimeGolden() { + return nil, fmt.Errorf("runtime golden snapshots require the microVM runtime") + } if err := validateActorDirs(req.GetActorDirs()); err != nil { return nil, err } diff --git a/cmd/ateom-microvm/checkpoint.go b/cmd/ateom-microvm/checkpoint.go index bd04c97d85..4468c0b15a 100644 --- a/cmd/ateom-microvm/checkpoint.go +++ b/cmd/ateom-microvm/checkpoint.go @@ -171,6 +171,15 @@ func (s *AteomService) CheckpointWorkload(ctx context.Context, req *ateompb.Chec return nil, fmt.Errorf("while creating checkpoint dir %q: %w", checkpointDir, err) } + if ra != nil && ra.runtimeGolden { + if scope != ateompb.SnapshotFidelity_SNAPSHOT_FIDELITY_MEMORY { + return nil, apierror.FailedPrecondition("runtime golden requires MEMORY fidelity") + } + if err := os.WriteFile(filepath.Join(checkpointDir, runtimeGoldenFile), []byte(runtimeGoldenFormat), 0o600); err != nil { + return nil, err + } + } + // Capture the snapshot's pieces CONCURRENTLY: the CH snapshot, the // durable-dir tars, and the rootfs upper tars read independent data from a // quiesced guest and write distinct files into checkpointDir, so the paused diff --git a/cmd/ateom-microvm/restore.go b/cmd/ateom-microvm/restore.go index caae2478bf..a0467f1f08 100644 --- a/cmd/ateom-microvm/restore.go +++ b/cmd/ateom-microvm/restore.go @@ -233,6 +233,10 @@ func (s *AteomService) RestoreWorkload(ctx context.Context, req *ateompb.Restore // comes back from the memory snapshot; the durable-dir volumes were restored by the // caller from their tar. func (s *AteomService) restoreMemoryFidelity(ctx context.Context, p actorBootParams, scope ateompb.SnapshotFidelity, restoreDir string, preserveRestoreDir bool, tStart time.Time) (retErr error) { + runtimeGolden, err := readRuntimeGolden(restoreDir) + if err != nil { + return err + } actorUID := p.actorUID rr := s.resolveRuntime(p.assetPaths) @@ -440,6 +444,14 @@ func (s *AteomService) restoreMemoryFidelity(ctx context.Context, p actorBootPar return fmt.Errorf("while reseeding guest CRNG: %w", err) } + if runtimeGolden { + // The restored kernel has never mounted the share. The host has now + // staged this actor's real volumes; create its sandbox and processes. + if err := s.startActorContainers(ctx, guestAC, actorUID, kata.VsockSocketPath(actorUID), ctrs); err != nil { + return err + } + } + // Block until every wakeup-probe-enabled container reports 200. if err := wakeupprobe.WaitAll(ctx, containers, ateomnet.ActorVethIP, wakeupprobe.DialFunc(s.sandboxDialer(actorUID))); err != nil { return fmt.Errorf("while waiting for container wakeup probe: %w", err) diff --git a/cmd/ateom-microvm/run.go b/cmd/ateom-microvm/run.go index 1bdbfe186f..c0522d95ec 100644 --- a/cmd/ateom-microvm/run.go +++ b/cmd/ateom-microvm/run.go @@ -18,6 +18,7 @@ package main import ( "context" + "crypto/rand" "errors" "fmt" "io/fs" @@ -51,6 +52,8 @@ import ( // cloud-hypervisor process directly (booted by RunWorkload or relaunched by // RestoreWorkload), so it tracks that process and its api-socket for teardown. type runningActor struct { + runtimeGolden bool + // baseID is the FROZEN base sandbox id propagated across this actor's restore // lineage. For a cold-run actor this is the actor's own id; for a restored // actor it is the id read from the snapshot's base-id file (the golden id, @@ -232,6 +235,9 @@ func (s *AteomService) resolveRuntime(paths map[string]string) resolvedRuntime { // - Each container's bundle holds the overlay spec its rootfs/ is composed // from. ateom builds the OCI spec itself. func (s *AteomService) RunWorkload(ctx context.Context, req *ateompb.RunWorkloadRequest) (resp *ateompb.RunWorkloadResponse, retErr error) { + if req.GetSpec().GetRuntimeGolden() && req.GetAtespace() != resources.GoldenActorAtespace { + return nil, apierror.InvalidArgument("runtime golden capture requires a golden actor") + } if err := validateActorDirs(req.GetActorDirs()); err != nil { return nil, err } @@ -256,6 +262,7 @@ func (s *AteomService) RunWorkload(ctx context.Context, req *ateompb.RunWorkload } p := actorBootParams{ + runtimeGolden: req.GetSpec().GetRuntimeGolden(), actorRef: resources.ActorRef{Atespace: req.GetAtespace(), Name: req.GetActorName()}, actorUID: req.GetActorUid(), actorDirs: req.GetActorDirs(), @@ -298,6 +305,8 @@ func (s *AteomService) RunWorkload(ctx context.Context, req *ateompb.RunWorkload // request, or from a Restore request whose snapshot fidelity covers only the // durable-dir volumes (the workload itself cold-starts). type actorBootParams struct { + runtimeGolden bool + actorRef resources.ActorRef actorUID string actorDirs *ateompb.ActorDirs @@ -536,6 +545,9 @@ func (s *AteomService) coldBootActor(ctx context.Context, p actorBootParams) (re consoleLog := kata.ConsoleLogPath(actorUID) vmCfg := buildVMConfig(actorUID, kernel, image, kparams, consoleLog, memMiB, vcpus, agentInit(ctx, client.Info()), s.guestDebug) + // A cold boot gets a new marker; memory restores retain the kernel's + // original command line. Unlike Linux boot_id this is not lazily created. + vmCfg.Payload.Cmdline += " ate.boot_id=" + rand.Text() if err := client.CreateVM(ctx, vmCfg); err != nil { return fmt.Errorf("while creating VM: %w", err) } @@ -591,15 +603,18 @@ func (s *AteomService) coldBootActor(ctx context.Context, p actorBootParams) (re } }() - // Post-boot kata-agent setup: sandbox, guest networking, start each container. - if err := s.startActorContainers(ctx, ac, actorUID, vsockPath, ctrs); err != nil { - return err + // Runtime goldens stop before CreateSandbox mounts virtio-fs. No guest + // inode, application cache or open handle can reference a placeholder. + if !p.runtimeGolden { + if err := s.startActorContainers(ctx, ac, actorUID, vsockPath, ctrs); err != nil { + return err + } } tContainers := time.Now() - - // Block until every wakeup-probe-enabled container reports 200. - if err := wakeupprobe.WaitAll(ctx, containers, ateomnet.ActorVethIP, wakeupprobe.DialFunc(s.sandboxDialer(actorUID))); err != nil { - return fmt.Errorf("while waiting for container wakeup probe: %w", err) + if !p.runtimeGolden { + if err := wakeupprobe.WaitAll(ctx, containers, ateomnet.ActorVethIP, wakeupprobe.DialFunc(s.sandboxDialer(actorUID))); err != nil { + return fmt.Errorf("while waiting for container wakeup probe: %w", err) + } } // Everything from BootVM onward, split. ateom used to log only the total, which @@ -611,10 +626,15 @@ func (s *AteomService) coldBootActor(ctx context.Context, p actorBootParams) (re slog.Duration("wakeup_probe", time.Since(tContainers)), slog.Duration("since_boot", time.Since(tBooted))) - ra := &runningActor{chCmd: chCmd, vfsdCmd: vfsdCmd, apiSocket: apiSocket, baseID: actorUID, guestAgent: ac, workloadIDs: workloadIDs(ctrs)} + ra := &runningActor{runtimeGolden: p.runtimeGolden, chCmd: chCmd, vfsdCmd: vfsdCmd, apiSocket: apiSocket, baseID: actorUID, guestAgent: ac, workloadIDs: workloadIDs(ctrs)} if err := s.tunnel.Activate(p.attribution(), s.sandboxDialer(p.actorUID), egress); err != nil { return err } + if p.runtimeGolden { + ra.workloadIDs = nil + s.setRunningVM(actorUID, ra) + return nil + } s.setRunningVM(actorUID, ra) // Forward each container's stdout/stderr into the pod logs, keyed by the diff --git a/cmd/ateom-microvm/runtime_golden.go b/cmd/ateom-microvm/runtime_golden.go new file mode 100644 index 0000000000..a384f03e41 --- /dev/null +++ b/cmd/ateom-microvm/runtime_golden.go @@ -0,0 +1,40 @@ +//go:build linux + +// 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 main + +import ( + "fmt" + "os" + "path/filepath" +) + +const runtimeGoldenFile = "runtime-golden" +const runtimeGoldenFormat = "microvm-before-create-sandbox-v1\n" + +func readRuntimeGolden(dir string) (bool, error) { + b, err := os.ReadFile(filepath.Join(dir, runtimeGoldenFile)) + if os.IsNotExist(err) { + return false, nil + } + if err != nil { + return false, err + } + if string(b) != runtimeGoldenFormat { + return false, fmt.Errorf("invalid runtime golden marker") + } + return true, nil +} diff --git a/cmd/ateom-microvm/runtime_golden_test.go b/cmd/ateom-microvm/runtime_golden_test.go new file mode 100644 index 0000000000..3a2228a268 --- /dev/null +++ b/cmd/ateom-microvm/runtime_golden_test.go @@ -0,0 +1,57 @@ +//go:build linux + +// 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 main + +import ( + "context" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/agent-substrate/substrate/internal/proto/ateompb" +) + +func TestRuntimeGoldenMarker(t *testing.T) { + for _, tc := range []struct { + name, content string + exists, want, bad bool + }{ + {name: "ordinary"}, {name: "runtime", content: runtimeGoldenFormat, exists: true, want: true}, {name: "empty", exists: true, bad: true}, {name: "unknown", content: "different", exists: true, bad: true}, + } { + t.Run(tc.name, func(t *testing.T) { + d := t.TempDir() + if tc.exists { + if err := os.WriteFile(filepath.Join(d, runtimeGoldenFile), []byte(tc.content), 0600); err != nil { + t.Fatal(err) + } + } + got, err := readRuntimeGolden(d) + if got != tc.want || (err != nil) != tc.bad { + t.Fatalf("got %v,%v", got, err) + } + }) + } +} + +func TestRuntimeGoldenRejectsOrdinaryActorBeforeActivation(t *testing.T) { + s := &AteomService{} + _, err := s.RunWorkload(context.Background(), &ateompb.RunWorkloadRequest{Atespace: "user", Spec: &ateompb.WorkloadSpec{RuntimeGolden: true}}) + if err == nil || !strings.Contains(err.Error(), "requires a golden actor") { + t.Fatalf("got %v", err) + } +} diff --git a/docs/csi-volumes.md b/docs/csi-volumes.md index 9a4d501d78..f8e2a3eb7b 100644 --- a/docs/csi-volumes.md +++ b/docs/csi-volumes.md @@ -233,14 +233,25 @@ kubectl ate create actor consumer-42 -a demo --template consumer --volume shared Bindings are validated and recorded when the actor is created and cannot change afterwards. -The golden snapshot is not used for templates that reference a `SharedVolume`. The -first resume of such an actor is a cold boot from the image, and later resumes -restore the actor's own snapshot, which was taken over the real volume. An -explicit `sourceTag` is refused at actor creation. The reason is in gVisor: -the golden actor warms up against a local empty directory at the mount path, -but runsc derives the `disable_file_handle_sharing` mount option from the bind -source's filesystem (NFS and FUSE get it, local disks do not) and refuses a -restore whose mount options differ from the checkpoint's. Supporting golden -restores here is follow-up work; the candidate approaches are a golden actor -that warms up on a scratch volume from the same driver, or an upstream runsc -change that excludes host-derived mount options from restore validation. +Templates referencing a `SharedVolume` cold-boot by default and restore their own +snapshots on later resumes. Explicit `sourceTag` cloning remains refused. + +MicroVM templates can opt into `snapshotConfig.goldenSnapshotConfig.mode: +GOLDEN_SNAPSHOT_MODE_RUNTIME`. This snapshots a booted kernel and agent **before +CreateSandbox mounts virtio-fs and before any application process exists**. +On restore, the host stages the actor-selected real volumes, resumes the kernel, +reseeds its random generator, and only then creates the sandbox and application +containers. Readiness is published after the application probes succeed. This +warms VM startup, not application memory. Ordinary own snapshots continue to +capture the running application; the runtime-only marker is not propagated to +those snapshots. + +Application-warm goldens cannot transparently substitute arbitrary filesystem +state: applications may retain bytes from the source volume in their heap. +Ordinary own-snapshot handoffs also retain application memory; changed backing +data and deleted-open handles need application-specific semantics. Runtime +goldens do not change those semantics or claim to repair those cases. + +The runtime mode is rejected for gVisor. Its existing cold-start guard remains: +runsc derives `disable_file_handle_sharing` from the source filesystem, and a +local placeholder and NFS volume can produce incompatible restore options. diff --git a/internal/e2e/fixtures/probe/main.go b/internal/e2e/fixtures/probe/main.go index 69b9840cc6..388ffdaabf 100644 --- a/internal/e2e/fixtures/probe/main.go +++ b/internal/e2e/fixtures/probe/main.go @@ -452,6 +452,8 @@ func main() { mux := http.NewServeMux() mux.HandleFunc("/whoami", whoami) mux.HandleFunc("/fetch", fetch) + mux.HandleFunc("/runtime-state", runtimeState) + mux.HandleFunc("/volume-fixture", seedVolumeFixture) mux.HandleFunc("/volume-state", (&volumeStateProbe{}).serveHTTP) mux.HandleFunc("/readfile", readfile) mux.HandleFunc("/writefile", writefile) diff --git a/internal/e2e/fixtures/probe/runtime_state.go b/internal/e2e/fixtures/probe/runtime_state.go new file mode 100644 index 0000000000..1655bb0f87 --- /dev/null +++ b/internal/e2e/fixtures/probe/runtime_state.go @@ -0,0 +1,90 @@ +// 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 main + +import ( + "crypto/rand" + "encoding/hex" + "encoding/json" + "net/http" + "os" + "path/filepath" + "strings" +) + +// Generated once per process; unlike boot_id, runtime-only clones must differ. +var processNonce = func() string { + b := make([]byte, 32) + if _, err := rand.Read(b); err != nil { + panic(err) + } + return hex.EncodeToString(b) +}() + +func runtimeState(w http.ResponseWriter, _ *http.Request) { + b, err := os.ReadFile("/proc/sys/kernel/random/boot_id") + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + cmdline, err := os.ReadFile("/proc/cmdline") + if err != nil { + http.Error(w, err.Error(), 500) + return + } + var marker string + for _, arg := range strings.Fields(string(cmdline)) { + if value, ok := strings.CutPrefix(arg, "ate.boot_id="); ok { + marker = value + } + } + if marker == "" { + http.Error(w, "guest boot marker missing", 500) + return + } + writeJSON(w, map[string]string{"boot_id": marker, "kernel_boot_id": strings.TrimSpace(string(b)), "process_nonce": processNonce}) +} + +// seedVolumeFixture seeds a disposable fixture before the retained-state probe is +// primed. Never call it after restore: that would conceal stale volume state. +func seedVolumeFixture(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodPost { + w.WriteHeader(http.StatusMethodNotAllowed) + return + } + var req struct { + Root string `json:"root"` + Value string `json:"value"` + } + if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 8192)).Decode(&req); err != nil { + http.Error(w, err.Error(), 400) + return + } + if !filepath.IsAbs(req.Root) || req.Root == "/" || req.Value == "" { + http.Error(w, "absolute disposable root and value required", 400) + return + } + if err := os.MkdirAll(filepath.Join(req.Root, "directory"), 0755); err != nil { + http.Error(w, err.Error(), 500) + return + } + for _, name := range []string{"cached.txt", "held.txt", "unlinked.txt", "directory/entry"} { + if err := os.WriteFile(filepath.Join(req.Root, name), []byte(req.Value), 0644); err != nil { + http.Error(w, err.Error(), 500) + return + } + } + writeJSON(w, map[string]string{"ok": "true"}) +} diff --git a/internal/e2e/fixtures/probe/runtime_state_test.go b/internal/e2e/fixtures/probe/runtime_state_test.go new file mode 100644 index 0000000000..850d63920b --- /dev/null +++ b/internal/e2e/fixtures/probe/runtime_state_test.go @@ -0,0 +1,50 @@ +// 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 main + +import ( + "bytes" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" +) + +func TestSeedVolumeFixture(t *testing.T) { + root := t.TempDir() + body, _ := json.Marshal(map[string]string{"root": root, "value": "actor-a"}) + w := httptest.NewRecorder() + seedVolumeFixture(w, httptest.NewRequest(http.MethodPost, "/volume-fixture", bytes.NewReader(body))) + if w.Code != http.StatusOK { + t.Fatalf("seed: %d %s", w.Code, w.Body.String()) + } + p := &volumeStateProbe{} + volumePrime(t, p, root) + got := volumeObserve(t, p) + if got.Cached != "actor-a" || got.Held.Data != "actor-a" || got.Unlinked.Data != "actor-a" || !got.Negative.NotExist { + t.Fatalf("fixture contents: %+v", got) + } +} + +func TestSeedVolumeFixtureRejectsUnsafeRoot(t *testing.T) { + for _, root := range []string{"", "/", "relative"} { + body, _ := json.Marshal(map[string]string{"root": root, "value": "a"}) + w := httptest.NewRecorder() + seedVolumeFixture(w, httptest.NewRequest(http.MethodPost, "/volume-fixture", bytes.NewReader(body))) + if w.Code != http.StatusBadRequest { + t.Fatalf("root %q: %d", root, w.Code) + } + } +} diff --git a/internal/e2e/suites/combinedvolumes/runtime_golden_test.go b/internal/e2e/suites/combinedvolumes/runtime_golden_test.go new file mode 100644 index 0000000000..41201e8643 --- /dev/null +++ b/internal/e2e/suites/combinedvolumes/runtime_golden_test.go @@ -0,0 +1,318 @@ +// 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 combinedvolumes + +import ( + "context" + "encoding/json" + "fmt" + "math/rand/v2" + "net/http" + "net/url" + "os" + "os/exec" + "path/filepath" + "strconv" + "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/protobuf/proto" +) + +type latencySample struct { + Mode string `json:"mode"` + Index int `json:"index"` + Warmup bool `json:"warmup"` + Milliseconds float64 `json:"milliseconds"` + Success bool `json:"success"` + Actor string `json:"actor"` + BootID string `json:"boot_id,omitempty"` + ProcessNonce string `json:"process_nonce,omitempty"` + Snapshots json.RawMessage `json:"source_snapshots"` +} + +// TestRuntimeGoldenVolumes is an explicit real-cluster experiment. It must fail +// without microVM/NFS, rather than count a skipped precondition as evidence. +func TestRuntimeGoldenVolumes(t *testing.T) { + if os.Getenv("E2E_RUNTIME_GOLDEN") != "true" { + t.Skip("opt in with E2E_RUNTIME_GOLDEN=true") + } + if os.Getenv("E2E_SANDBOX_CLASS") != "microvm" { + t.Fatal("microvm required") + } + ctx := context.Background() + clients := e2e.GetClients() + if storageClassOrEmpty(ctx, t, clients) == "" { + t.Fatal("real NFS CSI required") + } + ns := e2e.CreateNamespace(t) + env, err := e2e.CheckEnv("BUCKET_NAME") + if err != nil { + t.Fatal(err) + } + probeAtespace, _ := e2e.DeployProbe(t, env["BUCKET_NAME"], "runtimegolden") + src := e2e.SubstrateFixture{Atespace: probeAtespace, Name: probeName, PoolNamespace: probeAtespace, PoolName: probeName} + golden := e2e.CreateSubstrateTemplateFrom(ctx, t, clients, ns.Name, src, e2e.SubstrateTemplateOptions{ + Atespace: atespace, Name: "runtime-" + ns.Name, PoolName: probeName, PoolReplicas: 2, + Labels: map[string]string{"runtimegolden": ns.Name}, + SnapshotConfig: &ateapipb.SnapshotConfig{StorageLocation: fmt.Sprintf("gs://%s/%s/", env["BUCKET_NAME"], ns.Name), GoldenSnapshotConfig: &ateapipb.GoldenSnapshotConfig{Mode: ateapipb.GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_RUNTIME}}, + Modify: func(x *ateapipb.ActorTemplate) { + x.Containers[0].VolumeMounts = append(x.Containers[0].VolumeMounts, &ateapipb.VolumeMount{Name: sharedVolume, MountPath: sharedPath}) + x.Volumes = append(x.Volumes, &ateapipb.Volume{Name: sharedVolume, External: &ateapipb.ExternalVolumeSource{SharedVolume: &ateapipb.SharedVolumeRef{}}}) + }, + }) + cold := proto.Clone(golden).(*ateapipb.ActorTemplate) + cold.Metadata = &ateapipb.ResourceMetadata{Atespace: atespace, Name: "cold-" + ns.Name} + cold.Status = nil + cold.SnapshotConfig.GoldenSnapshotConfig.Mode = ateapipb.GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_DISABLED + cold, err = clients.SubstrateAPI.CreateActorTemplate(ctx, &ateapipb.CreateActorTemplateRequest{ActorTemplate: cold}) + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { + _, _ = clients.SubstrateAPI.DeleteActorTemplate(context.Background(), &ateapipb.DeleteActorTemplateRequest{ActorTemplate: e2e.TemplateRef(cold)}) + }) + volumes := []string{"a-" + ns.Name, "b-" + ns.Name} + for _, v := range volumes { + _, err := clients.SubstrateAPI.CreateSharedVolume(ctx, &ateapipb.CreateSharedVolumeRequest{SharedVolume: &ateapipb.SharedVolume{Metadata: &ateapipb.ResourceMetadata{Atespace: atespace, Name: v}, StorageClassName: e2e.StorageClass, Capacity: extCapacity, DeleteTrigger: ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL}}) + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { + _, err := clients.SubstrateAPI.DeleteSharedVolume(context.Background(), &ateapipb.DeleteSharedVolumeRequest{SharedVolume: &ateapipb.ObjectRef{Atespace: atespace, Name: v}}) + if err != nil { + t.Error(err) + } + }) + } + t.Cleanup(func() { + dir := os.Getenv("E2E_RUNTIME_LOG_DIR") + if dir == "" { + t.Error("E2E_RUNTIME_LOG_DIR required to preserve runtime evidence") + return + } + if err := os.MkdirAll(dir, 0755); err != nil { + t.Error(err) + return + } + kctx := os.Getenv("KUBECTL_CONTEXT") + pods, err := exec.Command("kubectl", "--context="+kctx, "-n", ns.Name, "get", "pods", "-o", "name").Output() + if err != nil { + t.Error(err) + return + } + for _, pod := range strings.Fields(string(pods)) { + logs, err := exec.Command("kubectl", "--context="+kctx, "-n", ns.Name, "logs", pod, "--all-containers=true", "--prefix=true", "--tail=-1").CombinedOutput() + if err != nil { + t.Errorf("collect %s: %v", pod, err) + } + if err := os.WriteFile(filepath.Join(dir, ns.Name+"-"+strings.TrimPrefix(pod, "pod/")+".log"), logs, 0644); err != nil { + t.Error(err) + } + } + }) + router, err := e2e.NewRouterClient(ctx) + if err != nil { + t.Fatal(err) + } + defer router.Close() + create := func(t *testing.T, tmpl *ateapipb.ActorTemplate, name, vol string) *ateapipb.Actor { + t.Helper() + a, err := clients.SubstrateAPI.CreateActor(ctx, &ateapipb.CreateActorRequest{Actor: &ateapipb.Actor{Metadata: &ateapipb.ResourceMetadata{Atespace: atespace, Name: name}, ActorTemplate: e2e.TemplateRef(tmpl), SharedVolumeBindings: map[string]string{sharedVolume: vol}}}) + if err != nil { + t.Fatal(err) + } + return a + } + remove := func(a *ateapipb.Actor) { + ref := resources.ActorRefFromActor(a).ToObjectRef() + _, _ = clients.SubstrateAPI.SuspendActor(context.Background(), &ateapipb.SuspendActorRequest{Actor: ref}) + _, _ = clients.SubstrateAPI.DeleteActor(context.Background(), &ateapipb.DeleteActorRequest{Actor: ref}) + } + resume := func(t *testing.T, a *ateapipb.Actor) { + t.Helper() + if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapipb.ResumeActorRequest{Actor: resources.ActorRefFromActor(a).ToObjectRef()}); err != nil { + t.Fatal(err) + } + } + suspend := func(t *testing.T, a *ateapipb.Actor) *ateapipb.Actor { + t.Helper() + r, err := clients.SubstrateAPI.SuspendActor(ctx, &ateapipb.SuspendActorRequest{Actor: resources.ActorRefFromActor(a).ToObjectRef()}) + if err != nil { + t.Fatal(err) + } + return r.GetActor() + } + post := func(t *testing.T, a *ateapipb.Actor, path string, body any) { + t.Helper() + b, _ := json.Marshal(body) + resp, err := router.PostJSON(ctx, resources.ActorRefFromActor(a), path, b) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent { + t.Fatalf("%s status %d", path, resp.StatusCode) + } + } + // Distinct actor-selected volumes must receive no placeholder/application + // state. The same boot ID across clones proves a resumed kernel; distinct + // process nonces prove applications start after the snapshot boundary. + var goldenBoot, firstNonce string + for i, v := range volumes { + a := create(t, golden, fmt.Sprintf("check-%d-%s", i, ns.Name), v) + func() { + defer remove(a) + if len(a.GetStatus().GetSnapshots()) == 0 { + t.Fatal("runtime actor has no source snapshot") + } + resume(t, a) + ref := resources.ActorRefFromActor(a) + state := probeJSON(ctx, t, router, ref, "/runtime-state") + if state["boot_id"] == "" || state["process_nonce"] == "" { + t.Fatal("missing runtime identity") + } + if i == 0 { + goldenBoot = state["boot_id"] + firstNonce = state["process_nonce"] + } else if state["boot_id"] != goldenBoot || state["process_nonce"] == firstNonce { + t.Fatalf("not distinct processes from one resumed kernel: %v", state) + } + requireUnreadable(ctx, t, router, ref, sharedPath+"/actor-"+strconv.Itoa(1-i)) + requireWrite(ctx, t, router, ref, sharedPath+"/actor-"+strconv.Itoa(i)) + root := sharedPath + "/state" + challenge := "challenge-" + v + post(t, a, "/volume-fixture", map[string]string{"root": root, "value": v}) + post(t, a, "/volume-state?root="+url.QueryEscape(root)+"&challenge="+url.QueryEscape(challenge), nil) + for generation := 1; generation <= 2; generation++ { + a = suspend(t, a) + resume(t, a) + after := probeJSON(ctx, t, router, ref, "/runtime-state") + if after["boot_id"] != goldenBoot || after["process_nonce"] != state["process_nonce"] { + t.Fatal("own restore restarted application or guest") + } + resp, err := router.Get(ctx, ref, "/volume-state") + if err != nil { + t.Fatal(err) + } + var obs struct { + Challenge string `json:"challenge"` + Cached string `json:"cached"` + ByPath struct{ Data, Error string } `json:"by_path"` + Held struct{ Data, Error string } + Unlinked struct{ Data, Error string } + Directory []string + DirectoryError string `json:"directory_error"` + } + err = json.NewDecoder(resp.Body).Decode(&obs) + resp.Body.Close() + if err != nil { + t.Fatal(err) + } + t.Logf("retained state actor=%s generation=%d: %+v", v, generation, obs) + if obs.Challenge != challenge || obs.Cached != v || obs.ByPath.Data != v || obs.Held.Data != v || obs.DirectoryError != "" { + t.Fatalf("retained-state mismatch: %+v", obs) + } + // Deleted-open-file recovery is observed explicitly; not silently treated + // as a correctness pass for that unsupported ordinary-restore case. + if obs.Unlinked.Error != "" { + t.Logf("LIMITATION: deleted-open file restore: %s", obs.Unlinked.Error) + } else if obs.Unlinked.Data != v { + t.Fatal("incorrect deleted-open contents") + } + } + }() + } + samples := 100 + if v := os.Getenv("E2E_LATENCY_SAMPLES"); v != "" { + samples, err = strconv.Atoi(v) + if err != nil || samples < 0 { + t.Fatal("invalid sample count") + } + } + // Zero runs the correctness cases without collecting latency. + if samples == 0 { + return + } + output := os.Getenv("E2E_LATENCY_OUTPUT") + if output == "" { + t.Fatal("E2E_LATENCY_OUTPUT required") + } + f, err := os.Create(output) + if err != nil { + t.Fatal(err) + } + defer f.Close() + enc := json.NewEncoder(f) + rng := rand.New(rand.NewPCG(42, 91)) + for i := -5; i < samples; i++ { + modes := []string{"cold", "runtime-golden", "own"} + rng.Shuffle(len(modes), func(a, b int) { modes[a], modes[b] = modes[b], modes[a] }) + for _, mode := range modes { + t.Run(fmt.Sprintf("%s/%d", mode, i), func(t *testing.T) { + tmpl := golden + if mode == "cold" { + tmpl = cold + } + a := create(t, tmpl, fmt.Sprintf("sample-%s-%d-%s", mode, i+5, ns.Name), volumes[0]) + defer remove(a) + var ownNonce string + if mode == "own" { + resume(t, a) + ownNonce = probeJSON(ctx, t, router, resources.ActorRefFromActor(a), "/runtime-state")["process_nonce"] + a = suspend(t, a) + } + snap, _ := json.Marshal(a.GetStatus().GetSnapshots()) + sample := latencySample{Mode: mode, Index: i, Warmup: i < 0, Actor: a.GetMetadata().GetName(), Snapshots: snap} + start := time.Now() + defer func() { + sample.Milliseconds = float64(time.Since(start).Microseconds()) / 1000 + sample.Success = !t.Failed() + if err := enc.Encode(sample); err != nil { + t.Error(err) + } + f.Sync() + }() + if mode == "cold" && len(a.GetStatus().GetSnapshots()) != 0 { + t.Fatal("cold sample has snapshot") + } + if mode != "cold" && len(a.GetStatus().GetSnapshots()) == 0 { + t.Fatal("restore sample has no snapshot") + } + resume(t, a) + ref := resources.ActorRefFromActor(a) + state := probeJSON(ctx, t, router, ref, "/runtime-state") + sample.BootID = state["boot_id"] + sample.ProcessNonce = state["process_nonce"] + if mode == "cold" && sample.BootID == goldenBoot { + t.Fatal("cold sample restored golden") + } + if mode != "cold" && sample.BootID != goldenBoot { + t.Fatal("restore sample cold-booted") + } + if mode == "own" && sample.ProcessNonce != ownNonce { + t.Fatal("own restore restarted process") + } + path := sharedPath + "/" + sample.Actor + requireWrite(ctx, t, router, ref, path) + requireContent(ctx, t, router, ref, path, probeWrittenContent) + }) + } + } +} diff --git a/internal/proto/ateletpb/atelet.pb.go b/internal/proto/ateletpb/atelet.pb.go index 41bb14e210..a81451c59f 100644 --- a/internal/proto/ateletpb/atelet.pb.go +++ b/internal/proto/ateletpb/atelet.pb.go @@ -1496,7 +1496,10 @@ type WorkloadSpec struct { // +k8s:maxItems=32 # matches the template's volumes bound // +k8s:listType=map // +k8s:listMapKey=name - Volumes []*Volume `protobuf:"bytes,2,rep,name=volumes,proto3" json:"volumes,omitempty"` + Volumes []*Volume `protobuf:"bytes,2,rep,name=volumes,proto3" json:"volumes,omitempty"` + // Capture only the pre-application microVM runtime; golden actors only. + // +k8s:optional + RuntimeGolden bool `protobuf:"varint,3,opt,name=runtime_golden,json=runtimeGolden,proto3" json:"runtime_golden,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -1545,6 +1548,13 @@ func (x *WorkloadSpec) GetVolumes() []*Volume { return nil } +func (x *WorkloadSpec) GetRuntimeGolden() bool { + if x != nil { + return x.RuntimeGolden + } + return false +} + type DurableDirVolume struct { state protoimpl.MessageState `protogen:"open.v1"` unknownFields protoimpl.UnknownFields @@ -3589,12 +3599,13 @@ const file_atelet_proto_rawDesc = "" + "pauseImage\x1aM\n" + "\vAssetsEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12(\n" + - "\x05value\x18\x02 \x01(\v2\x12.atelet.ArchAssetsR\x05value:\x028\x01\"k\n" + + "\x05value\x18\x02 \x01(\v2\x12.atelet.ArchAssetsR\x05value:\x028\x01\"\x92\x01\n" + "\fWorkloadSpec\x121\n" + "\n" + "containers\x18\x01 \x03(\v2\x11.atelet.ContainerR\n" + "containers\x12(\n" + - "\avolumes\x18\x02 \x03(\v2\x0e.atelet.VolumeR\avolumes\"\x12\n" + + "\avolumes\x18\x02 \x03(\v2\x0e.atelet.VolumeR\avolumes\x12%\n" + + "\x0eruntime_golden\x18\x03 \x01(\bR\rruntimeGolden\"\x12\n" + "\x10DurableDirVolume\"\x10\n" + "\x0eEmptyDirVolume\"\x89\x03\n" + "\x0eExternalVolume\x12*\n" + diff --git a/internal/proto/ateletpb/atelet.proto b/internal/proto/ateletpb/atelet.proto index 1955e3dd7e..fd59eaa593 100644 --- a/internal/proto/ateletpb/atelet.proto +++ b/internal/proto/ateletpb/atelet.proto @@ -446,6 +446,10 @@ message WorkloadSpec { // +k8s:listType=map // +k8s:listMapKey=name repeated Volume volumes = 2; + + // Capture only the pre-application microVM runtime; golden actors only. + // +k8s:optional + bool runtime_golden = 3; } message DurableDirVolume { diff --git a/internal/proto/ateompb/ateom.pb.go b/internal/proto/ateompb/ateom.pb.go index bfadf9f340..6af1bb5dc3 100644 --- a/internal/proto/ateompb/ateom.pb.go +++ b/internal/proto/ateompb/ateom.pb.go @@ -640,8 +640,11 @@ func (x *EgressGateway) GetAddress() string { // WorkloadSpec parallels Pod, but with far fewer configurable fields. type WorkloadSpec struct { - state protoimpl.MessageState `protogen:"open.v1"` - Containers []*Container `protobuf:"bytes,1,rep,name=containers,proto3" json:"containers,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + Containers []*Container `protobuf:"bytes,1,rep,name=containers,proto3" json:"containers,omitempty"` + // Boot the runtime without creating a guest sandbox or application processes. + // Valid only for a microVM golden actor. + RuntimeGolden bool `protobuf:"varint,2,opt,name=runtime_golden,json=runtimeGolden,proto3" json:"runtime_golden,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -683,6 +686,13 @@ func (x *WorkloadSpec) GetContainers() []*Container { return nil } +func (x *WorkloadSpec) GetRuntimeGolden() bool { + if x != nil { + return x.RuntimeGolden + } + return false +} + type Container struct { state protoimpl.MessageState `protogen:"open.v1"` Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` @@ -2084,11 +2094,12 @@ const file_ateom_proto_rawDesc = "" + "\x05value\x18\x02 \x01(\tR\x05value:\x028\x01B\x11\n" + "\x0f_egress_gateway\")\n" + "\rEgressGateway\x12\x18\n" + - "\aaddress\x18\x01 \x01(\tR\aaddress\"@\n" + + "\aaddress\x18\x01 \x01(\tR\aaddress\"g\n" + "\fWorkloadSpec\x120\n" + "\n" + "containers\x18\x01 \x03(\v2\x10.ateom.ContainerR\n" + - "containers\"\xce\x03\n" + + "containers\x12%\n" + + "\x0eruntime_golden\x18\x02 \x01(\bR\rruntimeGolden\"\xce\x03\n" + "\tContainer\x12\x12\n" + "\x04name\x18\x01 \x01(\tR\x04name\x125\n" + "\fwakeup_probe\x18\x02 \x01(\v2\x12.ateom.WakeupProbeR\vwakeupProbe\x12W\n" + diff --git a/internal/proto/ateompb/ateom.proto b/internal/proto/ateompb/ateom.proto index 22002d1df0..eb6016ecbb 100644 --- a/internal/proto/ateompb/ateom.proto +++ b/internal/proto/ateompb/ateom.proto @@ -179,6 +179,9 @@ message EgressGateway { // WorkloadSpec parallels Pod, but with far fewer configurable fields. message WorkloadSpec { repeated Container containers = 1; + // Boot the runtime without creating a guest sandbox or application processes. + // Valid only for a microVM golden actor. + bool runtime_golden = 2; } message Container { diff --git a/pkg/proto/ateapipb/ateapi.pb.go b/pkg/proto/ateapipb/ateapi.pb.go index 021f4cfdd4..cf46b37108 100644 --- a/pkg/proto/ateapipb/ateapi.pb.go +++ b/pkg/proto/ateapipb/ateapi.pb.go @@ -539,6 +539,10 @@ const ( GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_UNSPECIFIED GoldenSnapshotMode = 0 GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_ENABLED GoldenSnapshotMode = 1 GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_DISABLED GoldenSnapshotMode = 2 + // Capture the microVM before creating the guest sandbox or application + // processes. Restore attaches real volumes before starting applications. + // Does not preserve application warmup. Requires MICROVM. + GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_RUNTIME GoldenSnapshotMode = 3 ) // Enum value maps for GoldenSnapshotMode. @@ -547,11 +551,13 @@ var ( 0: "GOLDEN_SNAPSHOT_MODE_UNSPECIFIED", 1: "GOLDEN_SNAPSHOT_MODE_ENABLED", 2: "GOLDEN_SNAPSHOT_MODE_DISABLED", + 3: "GOLDEN_SNAPSHOT_MODE_RUNTIME", } GoldenSnapshotMode_value = map[string]int32{ "GOLDEN_SNAPSHOT_MODE_UNSPECIFIED": 0, "GOLDEN_SNAPSHOT_MODE_ENABLED": 1, "GOLDEN_SNAPSHOT_MODE_DISABLED": 2, + "GOLDEN_SNAPSHOT_MODE_RUNTIME": 3, } ) @@ -3600,7 +3606,7 @@ type GoldenSnapshotConfig struct { // // +k8s:required // +k8s:minimum=1 - // +k8s:maximum=2 # keep this in sync with the GoldenSnapshotMode enum + // +k8s:maximum=3 # keep this in sync with the GoldenSnapshotMode enum Mode GoldenSnapshotMode `protobuf:"varint,1,opt,name=mode,proto3,enum=ateapi.GoldenSnapshotMode" json:"mode,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -4433,9 +4439,8 @@ func (x *ExternalVolumeTemplate) GetStorageClassName() string { // SharedVolumeRef mounts a SharedVolume in the actor's atespace. The // volume outlives the actor, so several actors can mount it in turn. // -// Actors created from a template with a SharedVolumeRef do not start from -// the template's golden snapshot: the first resume boots from the image, and -// later resumes restore the actor's own snapshot. +// SharedVolume actors cold-boot initially unless their microVM template opts +// into GOLDEN_SNAPSHOT_MODE_RUNTIME. Later resumes use their own snapshots. type SharedVolumeRef struct { state protoimpl.MessageState `protogen:"open.v1"` // name of the SharedVolume. Left empty, the actor names it at creation in @@ -10106,11 +10111,12 @@ const file_ateapi_proto_rawDesc = "" + "\fSandboxClass\x12\x1d\n" + "\x19SANDBOX_CLASS_UNSPECIFIED\x10\x00\x12\x18\n" + "\x14SANDBOX_CLASS_GVISOR\x10\x01\x12\x19\n" + - "\x15SANDBOX_CLASS_MICROVM\x10\x02*\x7f\n" + + "\x15SANDBOX_CLASS_MICROVM\x10\x02*\xa1\x01\n" + "\x12GoldenSnapshotMode\x12$\n" + " GOLDEN_SNAPSHOT_MODE_UNSPECIFIED\x10\x00\x12 \n" + "\x1cGOLDEN_SNAPSHOT_MODE_ENABLED\x10\x01\x12!\n" + - "\x1dGOLDEN_SNAPSHOT_MODE_DISABLED\x10\x02*\x9a\x01\n" + + "\x1dGOLDEN_SNAPSHOT_MODE_DISABLED\x10\x02\x12 \n" + + "\x1cGOLDEN_SNAPSHOT_MODE_RUNTIME\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" + diff --git a/pkg/proto/ateapipb/ateapi.proto b/pkg/proto/ateapipb/ateapi.proto index 0feca0f918..3912b22caa 100644 --- a/pkg/proto/ateapipb/ateapi.proto +++ b/pkg/proto/ateapipb/ateapi.proto @@ -1330,6 +1330,10 @@ enum GoldenSnapshotMode { GOLDEN_SNAPSHOT_MODE_UNSPECIFIED = 0; GOLDEN_SNAPSHOT_MODE_ENABLED = 1; GOLDEN_SNAPSHOT_MODE_DISABLED = 2; + // Capture the microVM before creating the guest sandbox or application + // processes. Restore attaches real volumes before starting applications. + // Does not preserve application warmup. Requires MICROVM. + GOLDEN_SNAPSHOT_MODE_RUNTIME = 3; } // GoldenSnapshotConfig controls automated golden snapshot creation for a template. @@ -1339,7 +1343,7 @@ message GoldenSnapshotConfig { // // +k8s:required // +k8s:minimum=1 - // +k8s:maximum=2 # keep this in sync with the GoldenSnapshotMode enum + // +k8s:maximum=3 # keep this in sync with the GoldenSnapshotMode enum GoldenSnapshotMode mode = 1; } @@ -1592,9 +1596,8 @@ message ExternalVolumeTemplate { // SharedVolumeRef mounts a SharedVolume in the actor's atespace. The // volume outlives the actor, so several actors can mount it in turn. // -// Actors created from a template with a SharedVolumeRef do not start from -// the template's golden snapshot: the first resume boots from the image, and -// later resumes restore the actor's own snapshot. +// SharedVolume actors cold-boot initially unless their microVM template opts +// into GOLDEN_SNAPSHOT_MODE_RUNTIME. Later resumes use their own snapshots. message SharedVolumeRef { // name of the SharedVolume. Left empty, the actor names it at creation in // Actor.shared_volume_bindings. From fa20e529419a4ba78e5319e00da71624f2be17e1 Mon Sep 17 00:00:00 2001 From: Salah Date: Thu, 15 Oct 2026 01:46:17 +0400 Subject: [PATCH 08/12] Separate guest boot from application activation and enforce restore regressions --- .github/workflows/pr-workflow.yaml | 1 + cmd/ateom-microvm/application.go | 175 +++++++++++ cmd/ateom-microvm/checkpoint.go | 13 +- cmd/ateom-microvm/restore.go | 29 +- cmd/ateom-microvm/run.go | 176 +----------- cmd/ateom-microvm/runtime_golden_test.go | 33 +++ docs/csi-volumes.md | 19 ++ internal/e2e/fixtures/probe/volume_state.go | 38 +-- .../e2e/fixtures/probe/volume_state_test.go | 17 +- internal/e2e/probeapi/volume.go | 67 +++++ internal/e2e/probeapi/volume_test.go | 50 ++++ internal/e2e/runtimegoldenenv/env.go | 36 +++ internal/e2e/runtimegoldenenv/env_test.go | 69 +++++ .../runtime_golden_env_test.go | 30 ++ .../runtime_golden_fixture_test.go | 166 +++++++++++ .../runtime_golden_latency_test.go | 129 +++++++++ .../combinedvolumes/runtime_golden_test.go | 271 ++---------------- 17 files changed, 848 insertions(+), 471 deletions(-) create mode 100644 cmd/ateom-microvm/application.go create mode 100644 internal/e2e/probeapi/volume.go create mode 100644 internal/e2e/probeapi/volume_test.go create mode 100644 internal/e2e/runtimegoldenenv/env.go create mode 100644 internal/e2e/runtimegoldenenv/env_test.go create mode 100644 internal/e2e/suites/combinedvolumes/runtime_golden_env_test.go create mode 100644 internal/e2e/suites/combinedvolumes/runtime_golden_fixture_test.go create mode 100644 internal/e2e/suites/combinedvolumes/runtime_golden_latency_test.go diff --git a/.github/workflows/pr-workflow.yaml b/.github/workflows/pr-workflow.yaml index be08a8dd70..b7609ed487 100644 --- a/.github/workflows/pr-workflow.yaml +++ b/.github/workflows/pr-workflow.yaml @@ -269,6 +269,7 @@ jobs: # variant by the single E2E_SANDBOX_CLASS knob (see internal/e2e/sandbox.go). env: E2E_SANDBOX_CLASS: microvm + E2E_RUNTIME_LOG_DIR: ${{ github.workspace }}/_artifacts/runtime-golden E2E_PARALLELISM: 8 E2E_JUNIT_FILE: ${{ github.workspace }}/_artifacts/e2e-microvm.xml run: hack/run-e2e-kind.sh -v -args --no-color diff --git a/cmd/ateom-microvm/application.go b/cmd/ateom-microvm/application.go new file mode 100644 index 0000000000..12bab9aac4 --- /dev/null +++ b/cmd/ateom-microvm/application.go @@ -0,0 +1,175 @@ +//go:build linux + +// 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 main + +import ( + "context" + "fmt" + "log/slog" + "time" + + "github.com/agent-substrate/substrate/cmd/ateom-microvm/internal/third_party/kata/agentpb" + "golang.org/x/sys/unix" + + "github.com/agent-substrate/substrate/cmd/ateom-microvm/internal/kata" + "github.com/agent-substrate/substrate/internal/ateomnet" + "github.com/agent-substrate/substrate/internal/resources" + "github.com/agent-substrate/substrate/internal/wakeupprobe" +) + +// guestPhase distinguishes a booted kernel from a guest with live applications. +// Existing ordinary activations use the zero value. +type guestPhase uint8 + +const ( + applicationRunning guestPhase = iota + guestBooted +) + +func (s *AteomService) waitActorReady(ctx context.Context, p actorBootParams) error { + if err := wakeupprobe.WaitAll(ctx, p.containers, ateomnet.ActorVethIP, wakeupprobe.DialFunc(s.sandboxDialer(p.actorUID))); err != nil { + return fmt.Errorf("while waiting for container wakeup probe: %w", err) + } + return nil +} + +// publishActorApplication runs only after readiness and the last fallible step. +// Until then the caller owns cleanup of the guest connection and VM processes. +func (s *AteomService) publishActorApplication(ctx context.Context, p actorBootParams, ra *runningActor, ctrs []actorContainer) { + ra.phase = applicationRunning + ra.workloadIDs = workloadIDs(ctrs) + s.setRunningVM(p.actorUID, ra) + attribution := p.actorAttribution() + for _, id := range ra.workloadIDs { + s.startActorLogForwarding(ra.guestAgent, attribution, id, id) + } + s.setGuestStats(p.actorUID, &guestStatsTarget{actorUID: p.actorUID, agent: ra.guestAgent, workloadIDs: ra.workloadIDs}) + if hosted := s.lookupActor(p.actorUID); hosted != nil { + go s.recordInitial(context.WithoutCancel(ctx), hosted) + } +} + +func (s *AteomService) startActorContainers(ctx context.Context, ac *kata.AgentClient, id, vsockPath string, ctrs []actorContainer) error { + // Establish the agent sandbox + the kataShared virtio-fs mount (every + // container's merged rootfs, durable volumes, CSI volumes, and system-info + // volumes). All containers share it, so use the first container's hostname. + tStart := time.Now() + sbCtx, sbCancel := context.WithTimeout(ctx, 20*time.Second) + err := ac.CreateSandboxForActor(sbCtx, kata.CreateSandboxOpts{ + SandboxID: id, + Hostname: ctrs[0].spec.Hostname, + }) + sbCancel() + if err != nil { + return fmt.Errorf("while creating agent sandbox: %w", err) + } + tSandbox := time.Now() + + // Configure guest networking (the shim's job): eth0 IP/MAC/MTU, routes, ARP. + mtu := uint64(actorTapMTUOf(ctx, s.sandboxNetNS(id), "tap0_kata")) + netCtx, netCancel := context.WithTimeout(ctx, 20*time.Second) + err = s.configureGuestNetwork(netCtx, ac, mtu) + netCancel() + if err != nil { + if s.guestDebug { + dump := kata.DebugConsoleDump(ctx, vsockPath, "ip addr 2>&1; echo '== route =='; ip route 2>&1; echo '== neigh =='; ip neigh 2>&1") + slog.ErrorContext(ctx, "guest network config failed; dump", slog.String("dump", dump)) + } + return fmt.Errorf("while configuring guest network: %w", err) + } + + tNetwork := time.Now() + + for _, c := range ctrs { + if err := s.startRootfsContainer(ctx, ac, vsockPath, c); err != nil { + return err + } + } + slog.InfoContext(ctx, "Agent setup phases", slog.String("id", id), + slog.Duration("sandbox", tSandbox.Sub(tStart)), + slog.Duration("network", tNetwork.Sub(tSandbox)), + slog.Duration("containers", time.Since(tNetwork)), + slog.Int("container_count", len(ctrs))) + return nil +} + +// startRootfsContainer brings up one container on its host-merged rootfs (the +// stock kata flow: create + start against shared//rootfs). On failure it +// dumps the guest's view of the shared tree. +// +// Its spec binds every declared volume at its mount path. +func (s *AteomService) startRootfsContainer(ctx context.Context, ac *kata.AgentClient, vsockPath string, c actorContainer) error { + cCtx, cancel := context.WithTimeout(ctx, 30*time.Second) + err := ac.StartRootfsContainer(cCtx, c.name, c.spec) + cancel() + if err != nil { + if s.guestDebug { + dump := kata.DebugConsoleDump(ctx, vsockPath, + "echo '== shared/containers =='; ls -la /run/kata-containers/shared/containers/ 2>&1 | head -40; "+ + "echo '== rootfs =='; ls /run/kata-containers/shared/containers/"+c.name+"/rootfs/ 2>&1 | head; "+ + "echo '== mounts =='; grep -E 'kata|virtiofs' /proc/mounts 2>&1") + slog.ErrorContext(ctx, "rootfs container failed; dump", slog.String("container", c.name), slog.String("dump", dump)) + } + return fmt.Errorf("while starting rootfs container %q: %w", c.name, err) + } + return nil +} + +// startActorLogForwarding spawns two goroutines that pump the actor container's +// stdout and stderr (read over the kata-agent ttrpc client ac via repeated +// ReadStdout/ReadStderr) through the shared actorlog forwarder, which annotates +// each line with the actor's ate.dev/* labels and writes it to the pod's stdout. +// +// The streams are keyed by streamID == the kata containerID==execID (the overlay +// workload id); lines are tagged with actorName + containerName +// (ate.actor.container.name) so a multi-container actor demultiplexes. +// The reader contexts are context.Background() — the goroutines are NOT bound to the +// RPC that started them; they terminate when ac is closed (by teardownActor), which +// makes the in-flight ReadStdout/ReadStderr fail and the StreamReader return io.EOF, +// ending WrapContainerLogs. This keeps the agent connection (which ttrpc allows +// concurrent Calls on) alive for forwarding while guaranteeing no goroutine outlives +// the connection. +func (s *AteomService) startActorLogForwarding(ac *kata.AgentClient, a resources.ActorAttribution, streamID, containerName string) { + go s.actorLogger.WrapContainerLogs(kata.NewStdioReader(context.Background(), ac, streamID, streamID, false), a, containerName) + go s.actorLogger.WrapContainerLogs(kata.NewStdioReader(context.Background(), ac, streamID, streamID, true), a, containerName) +} + +func (s *AteomService) configureGuestNetwork(ctx context.Context, ac *kata.AgentClient, mtu uint64) error { + if err := ac.UpdateInterface(ctx, &agentpb.Interface{ + Device: ateomnet.ActorVethName, + Name: ateomnet.ActorVethName, + HwAddr: actorGuestMAC, + Mtu: mtu, + IPAddresses: []*agentpb.IPAddress{ + {Family: agentpb.IPFamily_v4, Address: ateomnet.ActorVethIP, Mask: "30"}, + }, + }); err != nil { + return err + } + if err := ac.UpdateRoutes(ctx, []*agentpb.Route{ + {Dest: ateomnet.ActorVethSubnet, Device: ateomnet.ActorVethName, Scope: uint32(unix.RT_SCOPE_LINK), Family: agentpb.IPFamily_v4}, + {Dest: "", Gateway: ateomnet.ActorVethGateway, Device: ateomnet.ActorVethName, Family: agentpb.IPFamily_v4}, + }); err != nil { + return err + } + return ac.AddARPNeighbors(ctx, []*agentpb.ARPNeighbor{{ + ToIPAddress: &agentpb.IPAddress{Family: agentpb.IPFamily_v4, Address: ateomnet.ActorVethGateway}, + Device: ateomnet.ActorVethName, + Lladdr: gatewayMAC, + State: 0x80, // NUD_PERMANENT + }}) +} diff --git a/cmd/ateom-microvm/checkpoint.go b/cmd/ateom-microvm/checkpoint.go index 4468c0b15a..91afe690a6 100644 --- a/cmd/ateom-microvm/checkpoint.go +++ b/cmd/ateom-microvm/checkpoint.go @@ -103,6 +103,13 @@ func (s *AteomService) CheckpointWorkload(ctx context.Context, req *ateompb.Chec }) }() + // Reject impossible captures before disconnecting traffic, pausing the guest, + // or replacing any existing checkpoint files. + ra := s.runningVM(req.GetActorUid()) + if ra != nil && ra.phase == guestBooted && scope != ateompb.SnapshotFidelity_SNAPSHOT_FIDELITY_MEMORY { + return nil, apierror.FailedPrecondition("runtime golden requires MEMORY fidelity") + } + if err := s.tunnel.Deactivate(ctx, attribution); err != nil { return nil, err } @@ -140,7 +147,6 @@ func (s *AteomService) CheckpointWorkload(ctx context.Context, req *ateompb.Chec // The actor's CH was booted by RunWorkload or relaunched by RestoreWorkload; // either way ateom owns it and tracks its api-socket. - ra := s.runningVM(actorUID) chSocket := kata.CLHSocketPath(actorUID) if ra != nil && ra.apiSocket != "" { chSocket = ra.apiSocket @@ -171,10 +177,7 @@ func (s *AteomService) CheckpointWorkload(ctx context.Context, req *ateompb.Chec return nil, fmt.Errorf("while creating checkpoint dir %q: %w", checkpointDir, err) } - if ra != nil && ra.runtimeGolden { - if scope != ateompb.SnapshotFidelity_SNAPSHOT_FIDELITY_MEMORY { - return nil, apierror.FailedPrecondition("runtime golden requires MEMORY fidelity") - } + if ra != nil && ra.phase == guestBooted { if err := os.WriteFile(filepath.Join(checkpointDir, runtimeGoldenFile), []byte(runtimeGoldenFormat), 0o600); err != nil { return nil, err } diff --git a/cmd/ateom-microvm/restore.go b/cmd/ateom-microvm/restore.go index a0467f1f08..597fdecca9 100644 --- a/cmd/ateom-microvm/restore.go +++ b/cmd/ateom-microvm/restore.go @@ -31,15 +31,12 @@ import ( "github.com/agent-substrate/substrate/internal/ateomphaselog" "github.com/agent-substrate/substrate/internal/ateomstats" - "github.com/agent-substrate/substrate/internal/ateomnet" - "github.com/agent-substrate/substrate/cmd/ateom-microvm/internal/ch" "github.com/agent-substrate/substrate/cmd/ateom-microvm/internal/kata" "github.com/agent-substrate/substrate/internal/imagecache" "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/wakeupprobe" ) // restoreMemMode picks how cloud-hypervisor should load guest RAM, from what the VMM @@ -453,8 +450,8 @@ func (s *AteomService) restoreMemoryFidelity(ctx context.Context, p actorBootPar } // Block until every wakeup-probe-enabled container reports 200. - if err := wakeupprobe.WaitAll(ctx, containers, ateomnet.ActorVethIP, wakeupprobe.DialFunc(s.sandboxDialer(actorUID))); err != nil { - return fmt.Errorf("while waiting for container wakeup probe: %w", err) + if err := s.waitActorReady(ctx, p); err != nil { + return err } // Where a resume goes. Like the boot phases, this used to be a single total, @@ -503,31 +500,11 @@ func (s *AteomService) restoreMemoryFidelity(ctx context.Context, p actorBootPar guestAgent: guestAC, } - // Re-attach stdout/stderr forwarding for each container over the agent - // connection dialed after resume: the restored guest's containers are alive, so - // ReadStdout/ReadStderr pick up where they left off. - attribution := p.actorAttribution() - for _, c := range containers { - s.startActorLogForwarding(guestAC, attribution, c.GetName(), c.GetName()) - } - if err := s.tunnel.Activate(p.attribution(), s.sandboxDialer(p.actorUID), egress); err != nil { return err } - s.setRunningVM(actorUID, ra) - - // After the last error return, so a failed restore stays retryable. maybeDropStagedMemoryImage(ctx, restoreDir, memMode, preserveRestoreDir) - - // Publish the guest to GetWorkloadStats, past the last error return above - // for the same reason as in coldBootActor. Same client the forwarding above - // reads over. - s.setGuestStats(actorUID, &guestStatsTarget{actorUID: actorUID, agent: guestAC, workloadIDs: ra.workloadIDs}) - // Looked up while the caller holds the actor's lock, so it is this - // activation. - if hosted := s.lookupActor(actorUID); hosted != nil { - go s.recordInitial(context.WithoutCancel(ctx), hosted) - } + s.publishActorApplication(ctx, p, ra, ctrs) slog.InfoContext(ctx, "Actor restored (overlay rootfs)", slog.String("id", actorUID), slog.Duration("total", time.Since(tStart))) diff --git a/cmd/ateom-microvm/run.go b/cmd/ateom-microvm/run.go index c0522d95ec..3b530bead3 100644 --- a/cmd/ateom-microvm/run.go +++ b/cmd/ateom-microvm/run.go @@ -33,26 +33,21 @@ import ( "github.com/agent-substrate/substrate/internal/apierror" "github.com/agent-substrate/substrate/internal/ateomstats" - "github.com/agent-substrate/substrate/internal/ateomnet" - "github.com/agent-substrate/substrate/cmd/ateom-microvm/internal/ch" "github.com/agent-substrate/substrate/cmd/ateom-microvm/internal/kata" - "github.com/agent-substrate/substrate/cmd/ateom-microvm/internal/third_party/kata/agentpb" "github.com/agent-substrate/substrate/internal/imagecache" "github.com/agent-substrate/substrate/internal/ocispec" "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/wakeupprobe" specs "github.com/opencontainers/runtime-spec/specs-go" - "golang.org/x/sys/unix" ) // runningActor holds the live state for one actor's micro-VM. ateom owns the // cloud-hypervisor process directly (booted by RunWorkload or relaunched by // RestoreWorkload), so it tracks that process and its api-socket for teardown. type runningActor struct { - runtimeGolden bool + phase guestPhase // baseID is the FROZEN base sandbox id propagated across this actor's restore // lineage. For a cold-run actor this is the actor's own id; for a restored @@ -603,63 +598,29 @@ func (s *AteomService) coldBootActor(ctx context.Context, p actorBootParams) (re } }() - // Runtime goldens stop before CreateSandbox mounts virtio-fs. No guest - // inode, application cache or open handle can reference a placeholder. - if !p.runtimeGolden { - if err := s.startActorContainers(ctx, ac, actorUID, vsockPath, ctrs); err != nil { - return err - } + ra := &runningActor{phase: guestBooted, chCmd: chCmd, vfsdCmd: vfsdCmd, apiSocket: apiSocket, baseID: actorUID, guestAgent: ac} + // Capture at the one boundary before any guest sandbox or application exists. + if p.runtimeGolden { + s.setRunningVM(actorUID, ra) + return nil + } + if err := s.startActorContainers(ctx, ac, actorUID, vsockPath, ctrs); err != nil { + return err } tContainers := time.Now() - if !p.runtimeGolden { - if err := wakeupprobe.WaitAll(ctx, containers, ateomnet.ActorVethIP, wakeupprobe.DialFunc(s.sandboxDialer(actorUID))); err != nil { - return fmt.Errorf("while waiting for container wakeup probe: %w", err) - } + if err := s.waitActorReady(ctx, p); err != nil { + return err } - - // Everything from BootVM onward, split. ateom used to log only the total, which - // hid where a cold boot actually goes: it is not the guest booting. slog.InfoContext(ctx, "Actor boot phases", slog.String("id", actorUID), slog.Duration("vsock_wait", tVsock.Sub(tBooted)), slog.Duration("agent_dial", tDialed.Sub(tVsock)), slog.Duration("containers", tContainers.Sub(tDialed)), slog.Duration("wakeup_probe", time.Since(tContainers)), slog.Duration("since_boot", time.Since(tBooted))) - - ra := &runningActor{runtimeGolden: p.runtimeGolden, chCmd: chCmd, vfsdCmd: vfsdCmd, apiSocket: apiSocket, baseID: actorUID, guestAgent: ac, workloadIDs: workloadIDs(ctrs)} - if err := s.tunnel.Activate(p.attribution(), s.sandboxDialer(p.actorUID), egress); err != nil { + if err := s.tunnel.Activate(p.attribution(), s.sandboxDialer(actorUID), egress); err != nil { return err } - if p.runtimeGolden { - ra.workloadIDs = nil - s.setRunningVM(actorUID, ra) - return nil - } - s.setRunningVM(actorUID, ra) - - // Forward each container's stdout/stderr into the pod logs, keyed by the - // container id (== the name; see StartRootfsContainer). The goroutines read - // over ac for the actor's lifetime and exit (io.EOF) when teardownActor - // closes ac. - workloadIDs := make([]string, 0, len(ctrs)) - attribution := p.actorAttribution() - for _, c := range ctrs { - s.startActorLogForwarding(ac, attribution, c.name, c.name) - workloadIDs = append(workloadIDs, c.name) - } - - // Publish the guest to GetWorkloadStats, past every error return above: a - // failing attempt closes ac on its way out (and coldBootActorRetrying may - // then try the whole boot again), so a target published earlier would leave - // the handler polling a connection nobody owns. Same client the forwarding - // above reads over — ttrpc multiplexes, and teardownActor ends both. - s.setGuestStats(actorUID, &guestStatsTarget{actorUID: actorUID, agent: ac, workloadIDs: workloadIDs}) - // Looked up while the caller holds the actor's lock, so it is this - // activation even if the read below outlives the RPC. - if hosted := s.lookupActor(actorUID); hosted != nil { - go s.recordInitial(context.WithoutCancel(ctx), hosted) - } - + s.publishActorApplication(ctx, p, ra, ctrs) return nil } @@ -897,91 +858,6 @@ func buildFsConfigs(id string) []ch.FsConfig { // does at boot: establish the sandbox once (mounting the kataShared virtio-fs base), // configure guest networking (eth0 IP/MAC/MTU + routes) once, then start each // container on its own overlay rootfs. On failure it dumps guest diagnostics. -func (s *AteomService) startActorContainers(ctx context.Context, ac *kata.AgentClient, id, vsockPath string, ctrs []actorContainer) error { - // Establish the agent sandbox + the kataShared virtio-fs mount (every - // container's merged rootfs, durable volumes, CSI volumes, and system-info - // volumes). All containers share it, so use the first container's hostname. - tStart := time.Now() - sbCtx, sbCancel := context.WithTimeout(ctx, 20*time.Second) - err := ac.CreateSandboxForActor(sbCtx, kata.CreateSandboxOpts{ - SandboxID: id, - Hostname: ctrs[0].spec.Hostname, - }) - sbCancel() - if err != nil { - return fmt.Errorf("while creating agent sandbox: %w", err) - } - tSandbox := time.Now() - - // Configure guest networking (the shim's job): eth0 IP/MAC/MTU, routes, ARP. - mtu := uint64(actorTapMTUOf(ctx, s.sandboxNetNS(id), "tap0_kata")) - netCtx, netCancel := context.WithTimeout(ctx, 20*time.Second) - err = s.configureGuestNetwork(netCtx, ac, mtu) - netCancel() - if err != nil { - if s.guestDebug { - dump := kata.DebugConsoleDump(ctx, vsockPath, "ip addr 2>&1; echo '== route =='; ip route 2>&1; echo '== neigh =='; ip neigh 2>&1") - slog.ErrorContext(ctx, "guest network config failed; dump", slog.String("dump", dump)) - } - return fmt.Errorf("while configuring guest network: %w", err) - } - - tNetwork := time.Now() - - for _, c := range ctrs { - if err := s.startRootfsContainer(ctx, ac, vsockPath, c); err != nil { - return err - } - } - slog.InfoContext(ctx, "Agent setup phases", slog.String("id", id), - slog.Duration("sandbox", tSandbox.Sub(tStart)), - slog.Duration("network", tNetwork.Sub(tSandbox)), - slog.Duration("containers", time.Since(tNetwork)), - slog.Int("container_count", len(ctrs))) - return nil -} - -// startRootfsContainer brings up one container on its host-merged rootfs (the -// stock kata flow: create + start against shared//rootfs). On failure it -// dumps the guest's view of the shared tree. -// -// Its spec binds every declared volume at its mount path. -func (s *AteomService) startRootfsContainer(ctx context.Context, ac *kata.AgentClient, vsockPath string, c actorContainer) error { - cCtx, cancel := context.WithTimeout(ctx, 30*time.Second) - err := ac.StartRootfsContainer(cCtx, c.name, c.spec) - cancel() - if err != nil { - if s.guestDebug { - dump := kata.DebugConsoleDump(ctx, vsockPath, - "echo '== shared/containers =='; ls -la /run/kata-containers/shared/containers/ 2>&1 | head -40; "+ - "echo '== rootfs =='; ls /run/kata-containers/shared/containers/"+c.name+"/rootfs/ 2>&1 | head; "+ - "echo '== mounts =='; grep -E 'kata|virtiofs' /proc/mounts 2>&1") - slog.ErrorContext(ctx, "rootfs container failed; dump", slog.String("container", c.name), slog.String("dump", dump)) - } - return fmt.Errorf("while starting rootfs container %q: %w", c.name, err) - } - return nil -} - -// startActorLogForwarding spawns two goroutines that pump the actor container's -// stdout and stderr (read over the kata-agent ttrpc client ac via repeated -// ReadStdout/ReadStderr) through the shared actorlog forwarder, which annotates -// each line with the actor's ate.dev/* labels and writes it to the pod's stdout. -// -// The streams are keyed by streamID == the kata containerID==execID (the overlay -// workload id); lines are tagged with actorName + containerName -// (ate.actor.container.name) so a multi-container actor demultiplexes. -// The reader contexts are context.Background() — the goroutines are NOT bound to the -// RPC that started them; they terminate when ac is closed (by teardownActor), which -// makes the in-flight ReadStdout/ReadStderr fail and the StreamReader return io.EOF, -// ending WrapContainerLogs. This keeps the agent connection (which ttrpc allows -// concurrent Calls on) alive for forwarding while guaranteeing no goroutine outlives -// the connection. -func (s *AteomService) startActorLogForwarding(ac *kata.AgentClient, a resources.ActorAttribution, streamID, containerName string) { - go s.actorLogger.WrapContainerLogs(kata.NewStdioReader(context.Background(), ac, streamID, streamID, false), a, containerName) - go s.actorLogger.WrapContainerLogs(kata.NewStdioReader(context.Background(), ac, streamID, streamID, true), a, containerName) -} - // errGuestStopped reports that the micro-VM stopped before the kata-agent // answered. Callers that can start over (a cold boot has no observable side // effects until the agent runs the containers) retry on it. @@ -1082,32 +958,6 @@ func tailString(s string, n int) string { // agent: configure eth0 (IP/MAC/MTU), install the connected + default routes, and // pin the gateway's ARP entry to its fixed MAC (so a restored guest's frozen // neighbor entry stays valid). -func (s *AteomService) configureGuestNetwork(ctx context.Context, ac *kata.AgentClient, mtu uint64) error { - if err := ac.UpdateInterface(ctx, &agentpb.Interface{ - Device: ateomnet.ActorVethName, - Name: ateomnet.ActorVethName, - HwAddr: actorGuestMAC, - Mtu: mtu, - IPAddresses: []*agentpb.IPAddress{ - {Family: agentpb.IPFamily_v4, Address: ateomnet.ActorVethIP, Mask: "30"}, - }, - }); err != nil { - return err - } - if err := ac.UpdateRoutes(ctx, []*agentpb.Route{ - {Dest: ateomnet.ActorVethSubnet, Device: ateomnet.ActorVethName, Scope: uint32(unix.RT_SCOPE_LINK), Family: agentpb.IPFamily_v4}, - {Dest: "", Gateway: ateomnet.ActorVethGateway, Device: ateomnet.ActorVethName, Family: agentpb.IPFamily_v4}, - }); err != nil { - return err - } - return ac.AddARPNeighbors(ctx, []*agentpb.ARPNeighbor{{ - ToIPAddress: &agentpb.IPAddress{Family: agentpb.IPFamily_v4, Address: ateomnet.ActorVethGateway}, - Device: ateomnet.ActorVethName, - Lladdr: gatewayMAC, - State: 0x80, // NUD_PERMANENT - }}) -} - // waitForFile polls for path to exist, up to d. Used to wait for the kata-agent // hybrid-vsock socket the shim creates during VM boot before dialing it. func waitForFile(path string, d time.Duration) bool { diff --git a/cmd/ateom-microvm/runtime_golden_test.go b/cmd/ateom-microvm/runtime_golden_test.go index 3a2228a268..d07b0ee055 100644 --- a/cmd/ateom-microvm/runtime_golden_test.go +++ b/cmd/ateom-microvm/runtime_golden_test.go @@ -18,6 +18,7 @@ package main import ( "context" + "github.com/agent-substrate/substrate/internal/actorlock" "os" "path/filepath" "strings" @@ -55,3 +56,35 @@ func TestRuntimeGoldenRejectsOrdinaryActorBeforeActivation(t *testing.T) { t.Fatalf("got %v", err) } } + +func TestRuntimeGoldenCheckpointRejectsBeforeMutation(t *testing.T) { + for _, fidelity := range []ateompb.SnapshotFidelity{ateompb.SnapshotFidelity_SNAPSHOT_FIDELITY_VOLUMES, ateompb.SnapshotFidelity_SNAPSHOT_FIDELITY_ROOTFS} { + t.Run(fidelity.String(), func(t *testing.T) { + root := t.TempDir() + checkpoint := filepath.Join(root, "checkpoint") + if err := os.Mkdir(checkpoint, 0700); err != nil { + t.Fatal(err) + } + sentinel := filepath.Join(checkpoint, "existing") + if err := os.WriteFile(sentinel, []byte("keep"), 0600); err != nil { + t.Fatal(err) + } + ra := &runningActor{phase: guestBooted} + // No tunnel or CH client: crossing the mutation boundary would panic or + // fail to reach CH instead of returning the expected precondition error. + s := &AteomService{locks: actorlock.New(), inFlight: actorlock.NewInFlight(), actors: map[string]*hostedActor{"a": {vm: ra}}} + dirs := &ateompb.ActorDirs{RootDir: root, OciBundleDir: root, CheckpointDir: checkpoint, RestoreDir: root, DurableDirVolumeMountsDir: root, SystemInfoVolumeRootsDir: root, VolumesDir: root} + _, err := s.CheckpointWorkload(context.Background(), &ateompb.CheckpointWorkloadRequest{ActorUid: "a", ActorDirs: dirs, Fidelity: fidelity}) + if err == nil || !strings.Contains(err.Error(), "requires MEMORY") { + t.Fatalf("got %v", err) + } + data, err := os.ReadFile(sentinel) + if err != nil || string(data) != "keep" { + t.Fatalf("checkpoint changed: %s %v", data, err) + } + if s.runningVM("a") != ra || ra.phase != guestBooted { + t.Fatal("guest state changed") + } + }) + } +} diff --git a/docs/csi-volumes.md b/docs/csi-volumes.md index f8e2a3eb7b..c706876cbf 100644 --- a/docs/csi-volumes.md +++ b/docs/csi-volumes.md @@ -255,3 +255,22 @@ goldens do not change those semantics or claim to repair those cases. The runtime mode is rejected for gVisor. Its existing cold-start guard remains: runsc derives `disable_file_handle_sharing` from the source filesystem, and a local placeholder and NFS volume can produce incompatible restore options. + +### Runtime golden regression coverage + +The microVM CI lane requires the runtime golden correctness cases and NFS CSI; +missing prerequisites fail that lane. Local cluster runs opt in with +`E2E_RUNTIME_GOLDEN=true`, `E2E_SANDBOX_CLASS=microvm`, and +`E2E_RUNTIME_LOG_DIR` pointing to an evidence directory. Run +`TestRuntimeGoldenVolumes` in `internal/e2e/suites/combinedvolumes` through +`hack/run-e2e-kind.sh`. This checks distinct volume bindings, guest/process +identity, and retained state over two own-snapshot generations. + +The probe contract checks directory entries and negative lookups as well as +cached and open-file contents. Only the known deleted-open-file `EIO` on the +second generation is tolerated; other errors fail the test. + +Latency collection is separate: select `TestRuntimeGoldenLatency`, additionally +set `E2E_RUNTIME_GOLDEN_BENCHMARK=true` and `E2E_LATENCY_OUTPUT` to a JSONL file. +`E2E_LATENCY_SAMPLES` defaults to 100 positive measured samples per mode, with +five warmups. It does not disable or replace the correctness test. diff --git a/internal/e2e/fixtures/probe/volume_state.go b/internal/e2e/fixtures/probe/volume_state.go index 866a941ebe..dff4599edb 100644 --- a/internal/e2e/fixtures/probe/volume_state.go +++ b/internal/e2e/fixtures/probe/volume_state.go @@ -18,12 +18,14 @@ import ( "encoding/json" "errors" "fmt" + "github.com/agent-substrate/substrate/internal/e2e/probeapi" "io" "net/http" "os" "path/filepath" "sort" "sync" + "syscall" ) // volumeStateProbe retains guest process state across snapshots. A controller @@ -39,34 +41,20 @@ type volumeStateProbe struct { reads uint64 } -type volumeObservation struct { - Data string `json:"data"` - Error string `json:"error,omitempty"` - NotExist bool `json:"not_exist,omitempty"` -} - -type volumeStateResponse struct { - Challenge string `json:"challenge"` - Reads uint64 `json:"reads"` - Cached string `json:"cached"` - ByPath volumeObservation `json:"by_path"` - Held volumeObservation `json:"held"` - Unlinked volumeObservation `json:"unlinked"` - Negative volumeObservation `json:"negative"` - Directory []string `json:"directory"` - DirectoryError string `json:"directory_error,omitempty"` -} - -func volumeResult(data []byte, err error) volumeObservation { +func volumeResult(data []byte, err error) probeapi.VolumeObservation { if err != nil { - return volumeObservation{Error: err.Error(), NotExist: errors.Is(err, os.ErrNotExist)} + out := probeapi.VolumeObservation{Error: err.Error(), NotExist: errors.Is(err, os.ErrNotExist)} + if errors.Is(err, syscall.EIO) { + out.ErrorCode = "EIO" + } + return out } - return volumeObservation{Data: string(data)} + return probeapi.VolumeObservation{Data: string(data)} } // Fixtures are deliberately small; oversized data is an error, never a // truncated success that could hide the distinguishing part of a sentinel. -func volumeRead(f *os.File) volumeObservation { +func volumeRead(f *os.File) probeapi.VolumeObservation { b := make([]byte, 4097) n, err := f.ReadAt(b, 0) if err == io.EOF { @@ -78,7 +66,7 @@ func volumeRead(f *os.File) volumeObservation { return volumeResult(b[:n], err) } -func volumeReadPath(path string) volumeObservation { +func volumeReadPath(path string) probeapi.VolumeObservation { f, err := os.Open(path) if err != nil { return volumeResult(nil, err) @@ -139,9 +127,9 @@ func (p *volumeStateProbe) prime(root, challenge string) (err error) { return nil } -func (p *volumeStateProbe) observe() volumeStateResponse { +func (p *volumeStateProbe) observe() probeapi.VolumeStateResponse { p.reads++ - out := volumeStateResponse{ + out := probeapi.VolumeStateResponse{ Challenge: p.challenge, Reads: p.reads, Cached: p.cached, ByPath: volumeReadPath(filepath.Join(p.root, "cached.txt")), Held: volumeRead(p.held), Unlinked: volumeRead(p.unlinked), diff --git a/internal/e2e/fixtures/probe/volume_state_test.go b/internal/e2e/fixtures/probe/volume_state_test.go index a898862102..3c688ae9ba 100644 --- a/internal/e2e/fixtures/probe/volume_state_test.go +++ b/internal/e2e/fixtures/probe/volume_state_test.go @@ -16,6 +16,7 @@ package main import ( "encoding/json" + "github.com/agent-substrate/substrate/internal/e2e/probeapi" "net/http" "net/http/httptest" "net/url" @@ -23,6 +24,7 @@ import ( "path/filepath" "strings" "sync" + "syscall" "testing" ) @@ -60,13 +62,13 @@ func volumePrime(t *testing.T, p *volumeStateProbe, root string) { t.Cleanup(p.close) } -func volumeObserve(t *testing.T, p *volumeStateProbe) volumeStateResponse { +func volumeObserve(t *testing.T, p *volumeStateProbe) probeapi.VolumeStateResponse { t.Helper() w := volumeRequest(p, http.MethodGet, "/volume-state") if w.Code != http.StatusOK { t.Fatalf("observe: %d %s", w.Code, w.Body.String()) } - var out volumeStateResponse + var out probeapi.VolumeStateResponse if err := json.Unmarshal(w.Body.Bytes(), &out); err != nil { t.Fatal(err) } @@ -185,3 +187,14 @@ func TestVolumeStateConcurrentReads(t *testing.T) { t.Fatalf("reads = %d", got.Reads) } } + +func TestVolumeResultClassifiesWrappedIOError(t *testing.T) { + got := volumeResult(nil, &os.PathError{Op: "read", Path: "unlinked.txt", Err: syscall.EIO}) + if got.ErrorCode != "EIO" || got.Error == "" || got.NotExist { + t.Fatalf("unexpected observation: %+v", got) + } + other := volumeResult(nil, os.ErrPermission) + if other.ErrorCode != "" { + t.Fatalf("unrelated error classified as EIO: %+v", other) + } +} diff --git a/internal/e2e/probeapi/volume.go b/internal/e2e/probeapi/volume.go new file mode 100644 index 0000000000..597876183e --- /dev/null +++ b/internal/e2e/probeapi/volume.go @@ -0,0 +1,67 @@ +// 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 probeapi defines the HTTP contracts shared by the probe and its tests. +package probeapi + +import ( + "fmt" + "slices" +) + +type VolumeObservation struct { + Data string `json:"data"` + Error string `json:"error,omitempty"` + ErrorCode string `json:"error_code,omitempty"` + NotExist bool `json:"not_exist,omitempty"` +} + +type VolumeStateResponse struct { + Challenge string `json:"challenge"` + Reads uint64 `json:"reads"` + Cached string `json:"cached"` + ByPath VolumeObservation `json:"by_path"` + Held VolumeObservation `json:"held"` + Unlinked VolumeObservation `json:"unlinked"` + Negative VolumeObservation `json:"negative"` + Directory []string `json:"directory"` + DirectoryError string `json:"directory_error,omitempty"` +} + +// ValidateRetainedState checks the disposable fixture across an own-snapshot +// restore. Only the observed second-generation deleted-open EIO is tolerated. +func ValidateRetainedState(obs VolumeStateResponse, challenge, value string, generation int) error { + if obs.Challenge != challenge || obs.Cached != value { + return fmt.Errorf("application state mismatch: %+v", obs) + } + for name, got := range map[string]VolumeObservation{"path": obs.ByPath, "held": obs.Held} { + if got.Error != "" || got.ErrorCode != "" || got.NotExist || got.Data != value { + return fmt.Errorf("%s observation mismatch: %+v", name, got) + } + } + if obs.DirectoryError != "" || !slices.Equal(obs.Directory, []string{"entry"}) { + return fmt.Errorf("directory mismatch: %+v", obs) + } + if !obs.Negative.NotExist || obs.Negative.Error == "" || obs.Negative.Data != "" { + return fmt.Errorf("negative lookup mismatch: %+v", obs.Negative) + } + u := obs.Unlinked + if generation == 2 && u.ErrorCode == "EIO" && u.Error != "" && u.Data == "" && !u.NotExist { + return nil + } + if u.Error != "" || u.ErrorCode != "" || u.NotExist || u.Data != value { + return fmt.Errorf("deleted-open observation mismatch at generation %d: %+v", generation, u) + } + return nil +} diff --git a/internal/e2e/probeapi/volume_test.go b/internal/e2e/probeapi/volume_test.go new file mode 100644 index 0000000000..b9cd85180d --- /dev/null +++ b/internal/e2e/probeapi/volume_test.go @@ -0,0 +1,50 @@ +// 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 probeapi + +import "testing" + +func TestValidateRetainedState(t *testing.T) { + valid := VolumeStateResponse{Challenge: "c", Cached: "v", ByPath: VolumeObservation{Data: "v"}, Held: VolumeObservation{Data: "v"}, Unlinked: VolumeObservation{Data: "v"}, Negative: VolumeObservation{NotExist: true, Error: "not found"}, Directory: []string{"entry"}} + for _, tc := range []struct { + name string + generation int + mutate func(*VolumeStateResponse) + bad bool + }{ + {"first generation", 1, func(*VolumeStateResponse) {}, false}, + {"second generation", 2, func(*VolumeStateResponse) {}, false}, + {"known EIO", 2, func(v *VolumeStateResponse) { + v.Unlinked = VolumeObservation{Error: "read: input/output error", ErrorCode: "EIO"} + }, false}, + {"premature EIO", 1, func(v *VolumeStateResponse) { + v.Unlinked = VolumeObservation{Error: "read: input/output error", ErrorCode: "EIO"} + }, true}, + {"unrelated error", 2, func(v *VolumeStateResponse) { v.Unlinked = VolumeObservation{Error: "permission denied"} }, true}, + {"empty directory", 2, func(v *VolumeStateResponse) { v.Directory = nil }, true}, + {"wrong directory", 2, func(v *VolumeStateResponse) { v.Directory = []string{"other"} }, true}, + {"negative exists", 2, func(v *VolumeStateResponse) { v.Negative = VolumeObservation{Data: "leaked"} }, true}, + {"held error", 2, func(v *VolumeStateResponse) { v.Held.Error = "failed" }, true}, + {"cached mismatch", 2, func(v *VolumeStateResponse) { v.Cached = "other" }, true}, + } { + t.Run(tc.name, func(t *testing.T) { + v := valid + tc.mutate(&v) + if err := ValidateRetainedState(v, "c", "v", tc.generation); (err != nil) != tc.bad { + t.Fatalf("got %v, want bad=%v", err, tc.bad) + } + }) + } +} diff --git a/internal/e2e/runtimegoldenenv/env.go b/internal/e2e/runtimegoldenenv/env.go new file mode 100644 index 0000000000..795cd4a1a0 --- /dev/null +++ b/internal/e2e/runtimegoldenenv/env.go @@ -0,0 +1,36 @@ +// 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 runtimegoldenenv defines when runtime golden regression tests are required. +package runtimegoldenenv + +import ( + "fmt" + "os" +) + +func Required() bool { return os.Getenv("CI") == "true" && os.Getenv("E2E_SANDBOX_CLASS") == "microvm" } +func Enabled() bool { return Required() || os.Getenv("E2E_RUNTIME_GOLDEN") == "true" } +func Check() error { + if !Enabled() { + return nil + } + if os.Getenv("E2E_SANDBOX_CLASS") != "microvm" { + return fmt.Errorf("runtime golden tests require microvm") + } + if os.Getenv("E2E_RUNTIME_LOG_DIR") == "" { + return fmt.Errorf("runtime golden tests require E2E_RUNTIME_LOG_DIR") + } + return nil +} diff --git a/internal/e2e/runtimegoldenenv/env_test.go b/internal/e2e/runtimegoldenenv/env_test.go new file mode 100644 index 0000000000..8234d5ece1 --- /dev/null +++ b/internal/e2e/runtimegoldenenv/env_test.go @@ -0,0 +1,69 @@ +// 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 runtimegoldenenv + +import ( + "os" + "os/exec" + "strings" + "testing" +) + +func TestRequiredAndEnabled(t *testing.T) { + for _, tc := range []struct { + name, ci, sandbox, opt string + required, enabled bool + }{ + {"local", "", "microvm", "", false, false}, + {"opt in", "", "microvm", "true", false, true}, + {"microvm CI", "true", "microvm", "", true, true}, + {"gvisor CI", "true", "gvisor", "", false, false}, + } { + t.Run(tc.name, func(t *testing.T) { + t.Setenv("CI", tc.ci) + t.Setenv("E2E_SANDBOX_CLASS", tc.sandbox) + t.Setenv("E2E_RUNTIME_GOLDEN", tc.opt) + if Required() != tc.required || Enabled() != tc.enabled { + t.Fatal("incorrect requirement") + } + }) + } +} +func TestRequiredMissingEvidenceFails(t *testing.T) { + if os.Getenv("RUNTIME_GOLDEN_GUARD_CHILD") == "true" { + if err := Check(); err != nil { + t.Fatal(err) + } + return + } + t.Setenv("CI", "true") + t.Setenv("E2E_SANDBOX_CLASS", "microvm") + t.Setenv("E2E_RUNTIME_GOLDEN", "") + t.Setenv("E2E_RUNTIME_LOG_DIR", "") + t.Setenv("RUNTIME_GOLDEN_GUARD_CHILD", "true") + cmd := exec.Command(os.Args[0], "-test.run=^TestRequiredMissingEvidenceFails$") + out, err := cmd.CombinedOutput() + if err == nil || !strings.Contains(string(out), "require E2E_RUNTIME_LOG_DIR") { + t.Fatalf("strict child should fail: %v %s", err, out) + } +} +func TestCheckConfigured(t *testing.T) { + t.Setenv("CI", "true") + t.Setenv("E2E_SANDBOX_CLASS", "microvm") + t.Setenv("E2E_RUNTIME_LOG_DIR", t.TempDir()) + if err := Check(); err != nil { + t.Fatal(err) + } +} diff --git a/internal/e2e/suites/combinedvolumes/runtime_golden_env_test.go b/internal/e2e/suites/combinedvolumes/runtime_golden_env_test.go new file mode 100644 index 0000000000..178e93110b --- /dev/null +++ b/internal/e2e/suites/combinedvolumes/runtime_golden_env_test.go @@ -0,0 +1,30 @@ +// 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 combinedvolumes + +import ( + "github.com/agent-substrate/substrate/internal/e2e/runtimegoldenenv" + "testing" +) + +func requireRuntimeGolden(t *testing.T) { + t.Helper() + if err := runtimegoldenenv.Check(); err != nil { + t.Fatal(err) + } + if !runtimegoldenenv.Enabled() { + t.Skip("requires microVM CI or E2E_RUNTIME_GOLDEN=true") + } +} diff --git a/internal/e2e/suites/combinedvolumes/runtime_golden_fixture_test.go b/internal/e2e/suites/combinedvolumes/runtime_golden_fixture_test.go new file mode 100644 index 0000000000..9c3322cd46 --- /dev/null +++ b/internal/e2e/suites/combinedvolumes/runtime_golden_fixture_test.go @@ -0,0 +1,166 @@ +// 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 combinedvolumes + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + + "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/protobuf/proto" +) + +type runtimeGoldenFixture struct { + golden, cold *ateapipb.ActorTemplate + volumes []string + name string + router *e2e.RouterClient + ctx context.Context + clients *e2e.Clients +} + +func newRuntimeGoldenFixture(t *testing.T) *runtimeGoldenFixture { + t.Helper() + logDir := os.Getenv("E2E_RUNTIME_LOG_DIR") + if logDir == "" { + t.Fatal("E2E_RUNTIME_LOG_DIR required to preserve runtime evidence") + } + if err := os.MkdirAll(logDir, 0755); err != nil { + t.Fatal(err) + } + ctx := context.Background() + clients := e2e.GetClients() + if storageClassOrEmpty(ctx, t, clients) == "" { + t.Fatal("real NFS CSI required") + } + ns := e2e.CreateNamespace(t) + env, err := e2e.CheckEnv("BUCKET_NAME") + if err != nil { + t.Fatal(err) + } + probeAtespace, _ := e2e.DeployProbe(t, env["BUCKET_NAME"], "runtimegolden") + src := e2e.SubstrateFixture{Atespace: probeAtespace, Name: probeName, PoolNamespace: probeAtespace, PoolName: probeName} + golden := e2e.CreateSubstrateTemplateFrom(ctx, t, clients, ns.Name, src, e2e.SubstrateTemplateOptions{ + Atespace: atespace, Name: "runtime-" + ns.Name, PoolName: probeName, PoolReplicas: 2, + Labels: map[string]string{"runtimegolden": ns.Name}, + SnapshotConfig: &ateapipb.SnapshotConfig{StorageLocation: fmt.Sprintf("gs://%s/%s/", env["BUCKET_NAME"], ns.Name), GoldenSnapshotConfig: &ateapipb.GoldenSnapshotConfig{Mode: ateapipb.GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_RUNTIME}}, + Modify: func(x *ateapipb.ActorTemplate) { + x.Containers[0].VolumeMounts = append(x.Containers[0].VolumeMounts, &ateapipb.VolumeMount{Name: sharedVolume, MountPath: sharedPath}) + x.Volumes = append(x.Volumes, &ateapipb.Volume{Name: sharedVolume, External: &ateapipb.ExternalVolumeSource{SharedVolume: &ateapipb.SharedVolumeRef{}}}) + }, + }) + cold := proto.Clone(golden).(*ateapipb.ActorTemplate) + cold.Metadata = &ateapipb.ResourceMetadata{Atespace: atespace, Name: "cold-" + ns.Name} + cold.Status = nil + cold.SnapshotConfig.GoldenSnapshotConfig.Mode = ateapipb.GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_DISABLED + cold, err = clients.SubstrateAPI.CreateActorTemplate(ctx, &ateapipb.CreateActorTemplateRequest{ActorTemplate: cold}) + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { + _, _ = clients.SubstrateAPI.DeleteActorTemplate(context.Background(), &ateapipb.DeleteActorTemplateRequest{ActorTemplate: e2e.TemplateRef(cold)}) + }) + volumes := []string{"a-" + ns.Name, "b-" + ns.Name} + for _, v := range volumes { + _, err := clients.SubstrateAPI.CreateSharedVolume(ctx, &ateapipb.CreateSharedVolumeRequest{SharedVolume: &ateapipb.SharedVolume{Metadata: &ateapipb.ResourceMetadata{Atespace: atespace, Name: v}, StorageClassName: e2e.StorageClass, Capacity: extCapacity, DeleteTrigger: ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL}}) + if err != nil { + t.Fatal(err) + } + t.Cleanup(func() { + _, err := clients.SubstrateAPI.DeleteSharedVolume(context.Background(), &ateapipb.DeleteSharedVolumeRequest{SharedVolume: &ateapipb.ObjectRef{Atespace: atespace, Name: v}}) + if err != nil { + t.Error(err) + } + }) + } + t.Cleanup(func() { + dir := logDir + kctx := os.Getenv("KUBECTL_CONTEXT") + pods, err := exec.Command("kubectl", "--context="+kctx, "-n", ns.Name, "get", "pods", "-o", "name").Output() + if err != nil { + t.Error(err) + return + } + for _, pod := range strings.Fields(string(pods)) { + logs, err := exec.Command("kubectl", "--context="+kctx, "-n", ns.Name, "logs", pod, "--all-containers=true", "--prefix=true", "--tail=-1").CombinedOutput() + if err != nil { + t.Errorf("collect %s: %v", pod, err) + } + if err := os.WriteFile(filepath.Join(dir, ns.Name+"-"+strings.TrimPrefix(pod, "pod/")+".log"), logs, 0644); err != nil { + t.Error(err) + } + } + }) + router, err := e2e.NewRouterClient(ctx) + if err != nil { + t.Fatal(err) + } + t.Cleanup(router.Close) + return &runtimeGoldenFixture{golden: golden, cold: cold, volumes: volumes, name: ns.Name, router: router, ctx: ctx, clients: clients} +} + +func (f *runtimeGoldenFixture) create(t *testing.T, tmpl *ateapipb.ActorTemplate, name, vol string) *ateapipb.Actor { + t.Helper() + a, err := f.clients.SubstrateAPI.CreateActor(f.ctx, &ateapipb.CreateActorRequest{Actor: &ateapipb.Actor{Metadata: &ateapipb.ResourceMetadata{Atespace: atespace, Name: name}, ActorTemplate: e2e.TemplateRef(tmpl), SharedVolumeBindings: map[string]string{sharedVolume: vol}}}) + if err != nil { + t.Fatal(err) + } + return a +} +func (f *runtimeGoldenFixture) remove(t *testing.T, a *ateapipb.Actor) { + ref := resources.ActorRefFromActor(a).ToObjectRef() + _, _ = f.clients.SubstrateAPI.SuspendActor(context.Background(), &ateapipb.SuspendActorRequest{Actor: ref}) + if _, err := f.clients.SubstrateAPI.DeleteActor(context.Background(), &ateapipb.DeleteActorRequest{Actor: ref}); err != nil { + t.Errorf("delete actor: %v", err) + } +} +func (f *runtimeGoldenFixture) resume(t *testing.T, a *ateapipb.Actor) { + t.Helper() + if _, err := e2e.ResumeActorAwaitCapacity(t, f.ctx, f.clients, &ateapipb.ResumeActorRequest{Actor: resources.ActorRefFromActor(a).ToObjectRef()}); err != nil { + t.Fatal(err) + } +} +func (f *runtimeGoldenFixture) suspend(t *testing.T, a *ateapipb.Actor) *ateapipb.Actor { + t.Helper() + r, err := f.clients.SubstrateAPI.SuspendActor(f.ctx, &ateapipb.SuspendActorRequest{Actor: resources.ActorRefFromActor(a).ToObjectRef()}) + if err != nil { + t.Fatal(err) + } + return r.GetActor() +} +func (f *runtimeGoldenFixture) post(t *testing.T, a *ateapipb.Actor, path string, body any) { + t.Helper() + b, err := json.Marshal(body) + if err != nil { + t.Fatal(err) + } + resp, err := f.router.PostJSON(f.ctx, resources.ActorRefFromActor(a), path, b) + if err != nil { + t.Fatal(err) + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent { + t.Fatalf("%s status %d", path, resp.StatusCode) + } +} diff --git a/internal/e2e/suites/combinedvolumes/runtime_golden_latency_test.go b/internal/e2e/suites/combinedvolumes/runtime_golden_latency_test.go new file mode 100644 index 0000000000..2eb06c5be5 --- /dev/null +++ b/internal/e2e/suites/combinedvolumes/runtime_golden_latency_test.go @@ -0,0 +1,129 @@ +// 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 combinedvolumes + +import ( + "context" + "encoding/json" + "fmt" + "math/rand/v2" + "os" + "strconv" + "testing" + "time" + + "github.com/agent-substrate/substrate/internal/resources" +) + +type latencySample struct { + Mode string `json:"mode"` + Index int `json:"index"` + Warmup bool `json:"warmup"` + Milliseconds float64 `json:"milliseconds"` + Success bool `json:"success"` + Actor string `json:"actor"` + BootID string `json:"boot_id,omitempty"` + ProcessNonce string `json:"process_nonce,omitempty"` + Snapshots json.RawMessage `json:"source_snapshots"` +} + +func TestRuntimeGoldenLatency(t *testing.T) { + if os.Getenv("E2E_RUNTIME_GOLDEN_BENCHMARK") != "true" { + t.Skip("optional latency experiment") + } + requireRuntimeGolden(t) + var err error + samples := 100 + if v := os.Getenv("E2E_LATENCY_SAMPLES"); v != "" { + samples, err = strconv.Atoi(v) + if err != nil || samples <= 0 { + t.Fatal("invalid sample count") + } + } + output := os.Getenv("E2E_LATENCY_OUTPUT") + if output == "" { + t.Fatal("E2E_LATENCY_OUTPUT required") + } + outputFile, err := os.Create(output) + if err != nil { + t.Fatal(err) + } + defer outputFile.Close() + enc := json.NewEncoder(outputFile) + f := newRuntimeGoldenFixture(t) + ctx := context.Background() + // Identify the template kernel once, outside measured activations. + seed := f.create(t, f.golden, "identity-"+f.name, f.volumes[0]) + f.resume(t, seed) + goldenBoot := probeJSON(ctx, t, f.router, resources.ActorRefFromActor(seed), "/runtime-state")["boot_id"] + f.remove(t, seed) + rng := rand.New(rand.NewPCG(42, 91)) + for i := -5; i < samples; i++ { + modes := []string{"cold", "runtime-golden", "own"} + rng.Shuffle(len(modes), func(a, b int) { modes[a], modes[b] = modes[b], modes[a] }) + for _, mode := range modes { + t.Run(fmt.Sprintf("%s/%d", mode, i), func(t *testing.T) { + tmpl := f.golden + if mode == "cold" { + tmpl = f.cold + } + a := f.create(t, tmpl, fmt.Sprintf("sample-%s-%d-%s", mode, i+5, f.name), f.volumes[0]) + defer f.remove(t, a) + var ownNonce string + if mode == "own" { + f.resume(t, a) + ownNonce = probeJSON(ctx, t, f.router, resources.ActorRefFromActor(a), "/runtime-state")["process_nonce"] + a = f.suspend(t, a) + } + snap, _ := json.Marshal(a.GetStatus().GetSnapshots()) + sample := latencySample{Mode: mode, Index: i, Warmup: i < 0, Actor: a.GetMetadata().GetName(), Snapshots: snap} + start := time.Now() + defer func() { + sample.Milliseconds = float64(time.Since(start).Microseconds()) / 1000 + sample.Success = !t.Failed() + if err := enc.Encode(sample); err != nil { + t.Error(err) + } + if err := outputFile.Sync(); err != nil { + t.Error(err) + } + }() + if mode == "cold" && len(a.GetStatus().GetSnapshots()) != 0 { + t.Fatal("cold sample has snapshot") + } + if mode != "cold" && len(a.GetStatus().GetSnapshots()) == 0 { + t.Fatal("restore sample has no snapshot") + } + f.resume(t, a) + ref := resources.ActorRefFromActor(a) + state := probeJSON(ctx, t, f.router, ref, "/runtime-state") + sample.BootID = state["boot_id"] + sample.ProcessNonce = state["process_nonce"] + if mode == "cold" && sample.BootID == goldenBoot { + t.Fatal("cold sample restored golden") + } + if mode != "cold" && sample.BootID != goldenBoot { + t.Fatal("restore sample cold-booted") + } + if mode == "own" && sample.ProcessNonce != ownNonce { + t.Fatal("own restore restarted process") + } + path := sharedPath + "/" + sample.Actor + requireWrite(ctx, t, f.router, ref, path) + requireContent(ctx, t, f.router, ref, path, probeWrittenContent) + }) + } + } +} diff --git a/internal/e2e/suites/combinedvolumes/runtime_golden_test.go b/internal/e2e/suites/combinedvolumes/runtime_golden_test.go index 41201e8643..13a55f2165 100644 --- a/internal/e2e/suites/combinedvolumes/runtime_golden_test.go +++ b/internal/e2e/suites/combinedvolumes/runtime_golden_test.go @@ -18,173 +18,32 @@ import ( "context" "encoding/json" "fmt" - "math/rand/v2" - "net/http" "net/url" - "os" - "os/exec" - "path/filepath" "strconv" - "strings" "testing" - "time" - "github.com/agent-substrate/substrate/internal/e2e" + "github.com/agent-substrate/substrate/internal/e2e/probeapi" "github.com/agent-substrate/substrate/internal/resources" - "github.com/agent-substrate/substrate/pkg/proto/ateapipb" - "google.golang.org/protobuf/proto" ) -type latencySample struct { - Mode string `json:"mode"` - Index int `json:"index"` - Warmup bool `json:"warmup"` - Milliseconds float64 `json:"milliseconds"` - Success bool `json:"success"` - Actor string `json:"actor"` - BootID string `json:"boot_id,omitempty"` - ProcessNonce string `json:"process_nonce,omitempty"` - Snapshots json.RawMessage `json:"source_snapshots"` -} - -// TestRuntimeGoldenVolumes is an explicit real-cluster experiment. It must fail -// without microVM/NFS, rather than count a skipped precondition as evidence. func TestRuntimeGoldenVolumes(t *testing.T) { - if os.Getenv("E2E_RUNTIME_GOLDEN") != "true" { - t.Skip("opt in with E2E_RUNTIME_GOLDEN=true") - } - if os.Getenv("E2E_SANDBOX_CLASS") != "microvm" { - t.Fatal("microvm required") - } + requireRuntimeGolden(t) + f := newRuntimeGoldenFixture(t) ctx := context.Background() - clients := e2e.GetClients() - if storageClassOrEmpty(ctx, t, clients) == "" { - t.Fatal("real NFS CSI required") - } - ns := e2e.CreateNamespace(t) - env, err := e2e.CheckEnv("BUCKET_NAME") - if err != nil { - t.Fatal(err) - } - probeAtespace, _ := e2e.DeployProbe(t, env["BUCKET_NAME"], "runtimegolden") - src := e2e.SubstrateFixture{Atespace: probeAtespace, Name: probeName, PoolNamespace: probeAtespace, PoolName: probeName} - golden := e2e.CreateSubstrateTemplateFrom(ctx, t, clients, ns.Name, src, e2e.SubstrateTemplateOptions{ - Atespace: atespace, Name: "runtime-" + ns.Name, PoolName: probeName, PoolReplicas: 2, - Labels: map[string]string{"runtimegolden": ns.Name}, - SnapshotConfig: &ateapipb.SnapshotConfig{StorageLocation: fmt.Sprintf("gs://%s/%s/", env["BUCKET_NAME"], ns.Name), GoldenSnapshotConfig: &ateapipb.GoldenSnapshotConfig{Mode: ateapipb.GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_RUNTIME}}, - Modify: func(x *ateapipb.ActorTemplate) { - x.Containers[0].VolumeMounts = append(x.Containers[0].VolumeMounts, &ateapipb.VolumeMount{Name: sharedVolume, MountPath: sharedPath}) - x.Volumes = append(x.Volumes, &ateapipb.Volume{Name: sharedVolume, External: &ateapipb.ExternalVolumeSource{SharedVolume: &ateapipb.SharedVolumeRef{}}}) - }, - }) - cold := proto.Clone(golden).(*ateapipb.ActorTemplate) - cold.Metadata = &ateapipb.ResourceMetadata{Atespace: atespace, Name: "cold-" + ns.Name} - cold.Status = nil - cold.SnapshotConfig.GoldenSnapshotConfig.Mode = ateapipb.GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_DISABLED - cold, err = clients.SubstrateAPI.CreateActorTemplate(ctx, &ateapipb.CreateActorTemplateRequest{ActorTemplate: cold}) - if err != nil { - t.Fatal(err) - } - t.Cleanup(func() { - _, _ = clients.SubstrateAPI.DeleteActorTemplate(context.Background(), &ateapipb.DeleteActorTemplateRequest{ActorTemplate: e2e.TemplateRef(cold)}) - }) - volumes := []string{"a-" + ns.Name, "b-" + ns.Name} - for _, v := range volumes { - _, err := clients.SubstrateAPI.CreateSharedVolume(ctx, &ateapipb.CreateSharedVolumeRequest{SharedVolume: &ateapipb.SharedVolume{Metadata: &ateapipb.ResourceMetadata{Atespace: atespace, Name: v}, StorageClassName: e2e.StorageClass, Capacity: extCapacity, DeleteTrigger: ateapipb.DeleteTrigger_DELETE_TRIGGER_MANUAL}}) - if err != nil { - t.Fatal(err) - } - t.Cleanup(func() { - _, err := clients.SubstrateAPI.DeleteSharedVolume(context.Background(), &ateapipb.DeleteSharedVolumeRequest{SharedVolume: &ateapipb.ObjectRef{Atespace: atespace, Name: v}}) - if err != nil { - t.Error(err) - } - }) - } - t.Cleanup(func() { - dir := os.Getenv("E2E_RUNTIME_LOG_DIR") - if dir == "" { - t.Error("E2E_RUNTIME_LOG_DIR required to preserve runtime evidence") - return - } - if err := os.MkdirAll(dir, 0755); err != nil { - t.Error(err) - return - } - kctx := os.Getenv("KUBECTL_CONTEXT") - pods, err := exec.Command("kubectl", "--context="+kctx, "-n", ns.Name, "get", "pods", "-o", "name").Output() - if err != nil { - t.Error(err) - return - } - for _, pod := range strings.Fields(string(pods)) { - logs, err := exec.Command("kubectl", "--context="+kctx, "-n", ns.Name, "logs", pod, "--all-containers=true", "--prefix=true", "--tail=-1").CombinedOutput() - if err != nil { - t.Errorf("collect %s: %v", pod, err) - } - if err := os.WriteFile(filepath.Join(dir, ns.Name+"-"+strings.TrimPrefix(pod, "pod/")+".log"), logs, 0644); err != nil { - t.Error(err) - } - } - }) - router, err := e2e.NewRouterClient(ctx) - if err != nil { - t.Fatal(err) - } - defer router.Close() - create := func(t *testing.T, tmpl *ateapipb.ActorTemplate, name, vol string) *ateapipb.Actor { - t.Helper() - a, err := clients.SubstrateAPI.CreateActor(ctx, &ateapipb.CreateActorRequest{Actor: &ateapipb.Actor{Metadata: &ateapipb.ResourceMetadata{Atespace: atespace, Name: name}, ActorTemplate: e2e.TemplateRef(tmpl), SharedVolumeBindings: map[string]string{sharedVolume: vol}}}) - if err != nil { - t.Fatal(err) - } - return a - } - remove := func(a *ateapipb.Actor) { - ref := resources.ActorRefFromActor(a).ToObjectRef() - _, _ = clients.SubstrateAPI.SuspendActor(context.Background(), &ateapipb.SuspendActorRequest{Actor: ref}) - _, _ = clients.SubstrateAPI.DeleteActor(context.Background(), &ateapipb.DeleteActorRequest{Actor: ref}) - } - resume := func(t *testing.T, a *ateapipb.Actor) { - t.Helper() - if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapipb.ResumeActorRequest{Actor: resources.ActorRefFromActor(a).ToObjectRef()}); err != nil { - t.Fatal(err) - } - } - suspend := func(t *testing.T, a *ateapipb.Actor) *ateapipb.Actor { - t.Helper() - r, err := clients.SubstrateAPI.SuspendActor(ctx, &ateapipb.SuspendActorRequest{Actor: resources.ActorRefFromActor(a).ToObjectRef()}) - if err != nil { - t.Fatal(err) - } - return r.GetActor() - } - post := func(t *testing.T, a *ateapipb.Actor, path string, body any) { - t.Helper() - b, _ := json.Marshal(body) - resp, err := router.PostJSON(ctx, resources.ActorRefFromActor(a), path, b) - if err != nil { - t.Fatal(err) - } - defer resp.Body.Close() - if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent { - t.Fatalf("%s status %d", path, resp.StatusCode) - } - } // Distinct actor-selected volumes must receive no placeholder/application // state. The same boot ID across clones proves a resumed kernel; distinct // process nonces prove applications start after the snapshot boundary. var goldenBoot, firstNonce string - for i, v := range volumes { - a := create(t, golden, fmt.Sprintf("check-%d-%s", i, ns.Name), v) + for i, v := range f.volumes { + a := f.create(t, f.golden, fmt.Sprintf("check-%d-%s", i, f.name), v) func() { - defer remove(a) + defer f.remove(t, a) if len(a.GetStatus().GetSnapshots()) == 0 { t.Fatal("runtime actor has no source snapshot") } - resume(t, a) + f.resume(t, a) ref := resources.ActorRefFromActor(a) - state := probeJSON(ctx, t, router, ref, "/runtime-state") + state := probeJSON(ctx, t, f.router, ref, "/runtime-state") if state["boot_id"] == "" || state["process_nonce"] == "" { t.Fatal("missing runtime identity") } @@ -194,125 +53,37 @@ func TestRuntimeGoldenVolumes(t *testing.T) { } else if state["boot_id"] != goldenBoot || state["process_nonce"] == firstNonce { t.Fatalf("not distinct processes from one resumed kernel: %v", state) } - requireUnreadable(ctx, t, router, ref, sharedPath+"/actor-"+strconv.Itoa(1-i)) - requireWrite(ctx, t, router, ref, sharedPath+"/actor-"+strconv.Itoa(i)) + requireUnreadable(ctx, t, f.router, ref, sharedPath+"/actor-"+strconv.Itoa(1-i)) + requireWrite(ctx, t, f.router, ref, sharedPath+"/actor-"+strconv.Itoa(i)) root := sharedPath + "/state" challenge := "challenge-" + v - post(t, a, "/volume-fixture", map[string]string{"root": root, "value": v}) - post(t, a, "/volume-state?root="+url.QueryEscape(root)+"&challenge="+url.QueryEscape(challenge), nil) + f.post(t, a, "/volume-fixture", map[string]string{"root": root, "value": v}) + f.post(t, a, "/volume-state?root="+url.QueryEscape(root)+"&challenge="+url.QueryEscape(challenge), nil) for generation := 1; generation <= 2; generation++ { - a = suspend(t, a) - resume(t, a) - after := probeJSON(ctx, t, router, ref, "/runtime-state") + a = f.suspend(t, a) + f.resume(t, a) + after := probeJSON(ctx, t, f.router, ref, "/runtime-state") if after["boot_id"] != goldenBoot || after["process_nonce"] != state["process_nonce"] { t.Fatal("own restore restarted application or guest") } - resp, err := router.Get(ctx, ref, "/volume-state") + resp, err := f.router.Get(ctx, ref, "/volume-state") if err != nil { t.Fatal(err) } - var obs struct { - Challenge string `json:"challenge"` - Cached string `json:"cached"` - ByPath struct{ Data, Error string } `json:"by_path"` - Held struct{ Data, Error string } - Unlinked struct{ Data, Error string } - Directory []string - DirectoryError string `json:"directory_error"` - } + var obs probeapi.VolumeStateResponse err = json.NewDecoder(resp.Body).Decode(&obs) resp.Body.Close() if err != nil { t.Fatal(err) } t.Logf("retained state actor=%s generation=%d: %+v", v, generation, obs) - if obs.Challenge != challenge || obs.Cached != v || obs.ByPath.Data != v || obs.Held.Data != v || obs.DirectoryError != "" { - t.Fatalf("retained-state mismatch: %+v", obs) + if err := probeapi.ValidateRetainedState(obs, challenge, v, generation); err != nil { + t.Fatal(err) } - // Deleted-open-file recovery is observed explicitly; not silently treated - // as a correctness pass for that unsupported ordinary-restore case. - if obs.Unlinked.Error != "" { - t.Logf("LIMITATION: deleted-open file restore: %s", obs.Unlinked.Error) - } else if obs.Unlinked.Data != v { - t.Fatal("incorrect deleted-open contents") + if obs.Unlinked.ErrorCode == "EIO" { + t.Log("known limitation: deleted-open file returned EIO on generation two") } } }() } - samples := 100 - if v := os.Getenv("E2E_LATENCY_SAMPLES"); v != "" { - samples, err = strconv.Atoi(v) - if err != nil || samples < 0 { - t.Fatal("invalid sample count") - } - } - // Zero runs the correctness cases without collecting latency. - if samples == 0 { - return - } - output := os.Getenv("E2E_LATENCY_OUTPUT") - if output == "" { - t.Fatal("E2E_LATENCY_OUTPUT required") - } - f, err := os.Create(output) - if err != nil { - t.Fatal(err) - } - defer f.Close() - enc := json.NewEncoder(f) - rng := rand.New(rand.NewPCG(42, 91)) - for i := -5; i < samples; i++ { - modes := []string{"cold", "runtime-golden", "own"} - rng.Shuffle(len(modes), func(a, b int) { modes[a], modes[b] = modes[b], modes[a] }) - for _, mode := range modes { - t.Run(fmt.Sprintf("%s/%d", mode, i), func(t *testing.T) { - tmpl := golden - if mode == "cold" { - tmpl = cold - } - a := create(t, tmpl, fmt.Sprintf("sample-%s-%d-%s", mode, i+5, ns.Name), volumes[0]) - defer remove(a) - var ownNonce string - if mode == "own" { - resume(t, a) - ownNonce = probeJSON(ctx, t, router, resources.ActorRefFromActor(a), "/runtime-state")["process_nonce"] - a = suspend(t, a) - } - snap, _ := json.Marshal(a.GetStatus().GetSnapshots()) - sample := latencySample{Mode: mode, Index: i, Warmup: i < 0, Actor: a.GetMetadata().GetName(), Snapshots: snap} - start := time.Now() - defer func() { - sample.Milliseconds = float64(time.Since(start).Microseconds()) / 1000 - sample.Success = !t.Failed() - if err := enc.Encode(sample); err != nil { - t.Error(err) - } - f.Sync() - }() - if mode == "cold" && len(a.GetStatus().GetSnapshots()) != 0 { - t.Fatal("cold sample has snapshot") - } - if mode != "cold" && len(a.GetStatus().GetSnapshots()) == 0 { - t.Fatal("restore sample has no snapshot") - } - resume(t, a) - ref := resources.ActorRefFromActor(a) - state := probeJSON(ctx, t, router, ref, "/runtime-state") - sample.BootID = state["boot_id"] - sample.ProcessNonce = state["process_nonce"] - if mode == "cold" && sample.BootID == goldenBoot { - t.Fatal("cold sample restored golden") - } - if mode != "cold" && sample.BootID != goldenBoot { - t.Fatal("restore sample cold-booted") - } - if mode == "own" && sample.ProcessNonce != ownNonce { - t.Fatal("own restore restarted process") - } - path := sharedPath + "/" + sample.Actor - requireWrite(ctx, t, router, ref, path) - requireContent(ctx, t, router, ref, path, probeWrittenContent) - }) - } - } } From e33826287980a534c45675574af26e25d037c939 Mon Sep 17 00:00:00 2001 From: Salah Date: Thu, 15 Oct 2026 12:04:22 +0400 Subject: [PATCH 09/12] Support runtime-only gVisor snapshots and verify retained mappings --- .../internal/apivalidation/actor_template.go | 3 - .../apivalidation/actor_template_test.go | 4 +- cmd/ateom-gvisor/main.go | 371 ++---------------- cmd/ateom-gvisor/restore.go | 234 +++++++++++ cmd/ateom-gvisor/run.go | 165 ++++++++ cmd/ateom-gvisor/runtime_golden.go | 58 +++ cmd/ateom-gvisor/runtime_golden_test.go | 127 ++++++ docs/csi-volumes.md | 22 +- internal/e2e/fixtures/probe/runtime_state.go | 40 +- .../e2e/fixtures/probe/runtime_state_test.go | 21 + internal/e2e/fixtures/probe/volume_state.go | 17 + .../e2e/fixtures/probe/volume_state_test.go | 28 +- internal/e2e/probeapi/volume.go | 9 +- internal/e2e/probeapi/volume_test.go | 16 +- internal/e2e/runtimegoldenenv/env.go | 4 +- internal/e2e/runtimegoldenenv/env_test.go | 17 + .../runtime_golden_fixture_test.go | 8 + .../runtime_golden_latency_test.go | 10 +- .../combinedvolumes/runtime_golden_test.go | 17 +- pkg/proto/ateapipb/ateapi.pb.go | 6 +- pkg/proto/ateapipb/ateapi.proto | 7 +- 21 files changed, 790 insertions(+), 394 deletions(-) create mode 100644 cmd/ateom-gvisor/restore.go create mode 100644 cmd/ateom-gvisor/run.go create mode 100644 cmd/ateom-gvisor/runtime_golden.go create mode 100644 cmd/ateom-gvisor/runtime_golden_test.go diff --git a/cmd/ateapi/internal/apivalidation/actor_template.go b/cmd/ateapi/internal/apivalidation/actor_template.go index af93bee274..483861fe91 100644 --- a/cmd/ateapi/internal/apivalidation/actor_template.go +++ b/cmd/ateapi/internal/apivalidation/actor_template.go @@ -63,9 +63,6 @@ func ValidateActorTemplateUpdate(ctx context.Context, fldPath *field.Path, newVa // today is the micro-VM class alone. func ValidateCustom_CreateActorTemplateRequest_ActorTemplate(_ context.Context, _ operation.Operation, fldPath *field.Path, value, _ *ateapipb.ActorTemplate) field.ErrorList { var errs field.ErrorList - if value.GetSnapshotConfig().GetGoldenSnapshotConfig().GetMode() == ateapipb.GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_RUNTIME && value.GetSandboxConfig().GetSandboxClass() != ateapipb.SandboxClass_SANDBOX_CLASS_MICROVM { - errs = append(errs, field.Invalid(fldPath.Child("snapshot_config", "golden_snapshot_config", "mode"), "RUNTIME", "runtime golden snapshots require MICROVM")) - } if value.GetSnapshotConfig().GetPreferredFidelity() == ateapipb.SnapshotFidelity_SNAPSHOT_FIDELITY_ROOTFS && value.GetSandboxConfig().GetSandboxClass() != ateapipb.SandboxClass_SANDBOX_CLASS_MICROVM { errs = append(errs, field.Invalid( diff --git a/cmd/ateapi/internal/apivalidation/actor_template_test.go b/cmd/ateapi/internal/apivalidation/actor_template_test.go index e97c14289f..ec977b68c5 100644 --- a/cmd/ateapi/internal/apivalidation/actor_template_test.go +++ b/cmd/ateapi/internal/apivalidation/actor_template_test.go @@ -35,11 +35,11 @@ func TestValidateCreateActorTemplateRequest(t *testing.T) { &ateapipb.CreateActorTemplateRequest{ActorTemplate: validActorTemplate()}, nil, }, { - "runtime golden requires microvm", + "runtime golden gvisor", &ateapipb.CreateActorTemplateRequest{ActorTemplate: validActorTemplate(func(x *ateapipb.ActorTemplate) { x.SnapshotConfig.GoldenSnapshotConfig = &ateapipb.GoldenSnapshotConfig{Mode: ateapipb.GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_RUNTIME} })}, - field.ErrorList{field.Invalid(field.NewPath("actor_template", "snapshot_config", "golden_snapshot_config", "mode"), "RUNTIME", "")}, + nil, }, { "runtime golden microvm", &ateapipb.CreateActorTemplateRequest{ActorTemplate: validActorTemplate(func(x *ateapipb.ActorTemplate) { diff --git a/cmd/ateom-gvisor/main.go b/cmd/ateom-gvisor/main.go index aa905975c7..3dd92649e0 100644 --- a/cmd/ateom-gvisor/main.go +++ b/cmd/ateom-gvisor/main.go @@ -17,22 +17,10 @@ package main import ( + "cloud.google.com/go/compute/metadata" "context" "errors" "fmt" - "log/slog" - "net" - "os" - "os/signal" - "path/filepath" - "slices" - "sort" - "sync" - "sync/atomic" - "syscall" - "time" - - "cloud.google.com/go/compute/metadata" "github.com/agent-substrate/substrate/cmd/ateom-gvisor/internal/cgroupstats" "github.com/agent-substrate/substrate/internal/actorlock" "github.com/agent-substrate/substrate/internal/actorlog" @@ -52,15 +40,24 @@ import ( "github.com/agent-substrate/substrate/internal/proto/ateompb" "github.com/agent-substrate/substrate/internal/resources" "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/wakeupprobe" atev1alpha1 "github.com/agent-substrate/substrate/pkg/api/v1alpha1" "github.com/spf13/pflag" "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc" "google.golang.org/grpc" "google.golang.org/grpc/reflection" "k8s.io/apimachinery/pkg/util/validation/field" + "log/slog" + "net" + "os" + "os/signal" + "path/filepath" + "slices" + "sort" + "sync" + "sync/atomic" + "syscall" + "time" ) var ( @@ -291,8 +288,9 @@ const ( // in the sandbox, so the SIGTERM handler knows which containers to signal and // wait on during graceful shutdown. The sandbox runs one workload at a time. type workloadSession struct { - rcmd *runsc - containers []string + rcmd *runsc + containers []string + runtimeGolden bool } // AteomService is a service for shepherding single microvm. @@ -562,133 +560,6 @@ func validateFidelity(fidelity ateompb.SnapshotFidelity) error { return nil } -func (s *AteomService) RunWorkload(ctx context.Context, req *ateompb.RunWorkloadRequest) (resp *ateompb.RunWorkloadResponse, retErr error) { - if req.GetSpec().GetRuntimeGolden() { - return nil, fmt.Errorf("runtime golden snapshots require the microVM runtime") - } - if err := validateActorDirs(req.GetActorDirs()); err != nil { - return nil, err - } - if err := validateRunscPath(req.GetRunscPath()); err != nil { - return nil, err - } - if !s.locks.Lock(ctx, req.GetActorUid()) { - return nil, fmt.Errorf("gave up waiting for the actor's lock: %w", ctx.Err()) - } - defer s.locks.Unlock(req.GetActorUid()) - ctx, cancel := context.WithCancel(ctx) - defer cancel() - release, err := s.beginRPC(req.GetActorUid(), rpcRunWorkload, cancel) - if err != nil { - return nil, err - } - defer release() - if err := resetRunscStateAndPidFileDirs(req.GetActorDirs()); err != nil { - return nil, err - } - - if err := s.tunnel.Deactivate(ctx, ateomstats.ActorAttributionFromRequest(req)); err != nil { - return nil, err - } - - attribution := ateomstats.ActorAttributionFromRequest(req) - s.actorLogger.EmitLifecycleLog(ctx, "Actor starting", attribution) - - // Contract with atelet: - // - // * Correct runsc version is downloaded and placed on disk. - // * All OCI bundles are set up, including for the pause container. - - egress, err := s.tunnel.PrepareEgress(ctx, ateomstats.ActorAttributionFromRequest(req), req.GetEgressGateway()) - if err != nil { - return nil, err - } - // Publish attribution before boot so stats can include startup usage. - hosted, err := s.hostActor(ctx, attribution, req.GetActorDirs()) - if err != nil { - return nil, err - } - rcmd := &runsc{ - path: req.GetRunscPath(), - actorUID: req.GetActorUid(), - actorDirs: req.GetActorDirs(), - size: sizing.FromLimits(req.GetCpuMilli(), req.GetMemoryBytes()), - durableVolumes: durableVolumeNames(req.GetSpec()), - containers: req.GetSpec().GetContainers(), - } - var containersToDelete []string - defer func() { - if retErr != nil { - cleanupCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 30*time.Second) - defer cancel() - if err := s.tunnel.Deactivate(cleanupCtx, ateomstats.ActorAttributionFromRequest(req)); err != nil { - slog.WarnContext(cleanupCtx, "Failed to deactivate actor networking after Run failure", slog.Any("err", err)) - } - deleteContainers(cleanupCtx, rcmd, containersToDelete, "Run") - // Detach any bundle rootfs overlays a partially-completed setup - // mounted, mirroring the post-checkpoint cleanup — otherwise they - // linger in this namespace until atelet wipes the bundle dirs. - // Run before the network cleanup. - if err := imagecache.UnmountAllUnder(req.GetActorDirs().GetOciBundleDir()); err != nil { - slog.WarnContext(ctx, "Failed to unmount bundle rootfs overlays after Run failure", - "actorUID", req.GetActorUid(), "err", err) - } - if err := s.unhostActor(cleanupCtx, req.GetActorUid()); err != nil { - slog.WarnContext(cleanupCtx, "Failed to clean up actor network after Run failure", slog.Any("err", 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 - // capabilities); runsc's gofer resolves the mount in this pod's mount - // namespace. - if err := imagecache.SetupBundleRootfs(ociBundlePath(req.GetActorDirs(), ocispec.PauseContainer)); err != nil { - return nil, fmt.Errorf("while composing pause rootfs: %w", err) - } - containersToDelete = append(containersToDelete, ocispec.PauseContainer) - if err := rcmd.cmdCreate(ctx, os.Stdout, ocispec.PauseContainer, nil); err != nil { - return nil, fmt.Errorf("while creating pause container: %w", err) - } - if err := rcmd.cmdStart(ctx, os.Stdout, ocispec.PauseContainer); err != nil { - return nil, fmt.Errorf("while starting pause container: %w", err) - } - - // Create and start each application container, each with its own log pipe so - // every line is tagged with the originating container (ate.actor.container.name). - for _, ac := range req.GetSpec().GetContainers() { - pw, err := s.actorLogger.StartJSONLogPipe(attribution, ac.GetName()) - if err != nil { - return nil, fmt.Errorf("while starting json log pipe for %q: %w", ac.GetName(), err) - } - defer pw.Close() - if err := imagecache.SetupBundleRootfs(ociBundlePath(req.GetActorDirs(), ac.GetName())); err != nil { - return nil, fmt.Errorf("while composing %q rootfs: %w", ac.GetName(), err) - } - containersToDelete = append(containersToDelete, ac.GetName()) - if err := rcmd.cmdCreate(ctx, pw, ac.GetName(), nil); err != nil { - return nil, fmt.Errorf("while creating %q application container: %w", ac.GetName(), err) - } - if err := rcmd.cmdStart(ctx, pw, ac.GetName()); err != nil { - return nil, fmt.Errorf("while starting %q application container: %w", ac.GetName(), err) - } - } - - // Block until every wakeup-probe-enabled container reports 200. - if err := wakeupprobe.WaitAll(ctx, req.GetSpec().GetContainers(), ateomnet.ActorVethIP, wakeupprobe.DialFunc(s.sandboxDialer(req.GetActorUid()))); err != nil { - return nil, fmt.Errorf("while waiting for container wakeup probe: %w", err) - } - if err := s.tunnel.Activate(ateomstats.ActorAttributionFromRequest(req), s.sandboxDialer(req.GetActorUid()), egress); err != nil { - return nil, err - } - - s.actorLogger.EmitLifecycleLog(ctx, "Actor started", attribution) - s.setSession(req.GetActorUid(), &workloadSession{rcmd: rcmd, containers: containerNames(req.GetSpec().GetContainers())}) - s.recordInitial(ctx, hosted) - - return &ateompb.RunWorkloadResponse{}, nil -} - // Allow checkpointing even if the pod is shutting down. This will allow actors // (or the harness) to suspend on shutdown. func (s *AteomService) CheckpointWorkload(ctx context.Context, req *ateompb.CheckpointWorkloadRequest) (_ *ateompb.CheckpointWorkloadResponse, err error) { @@ -708,6 +579,11 @@ func (s *AteomService) CheckpointWorkload(ctx context.Context, req *ateompb.Chec } defer s.locks.Unlock(req.GetActorUid()) + runtimeGolden := s.isRuntimeGolden(req.GetActorUid()) + if runtimeGolden && req.GetFidelity() != ateompb.SnapshotFidelity_SNAPSHOT_FIDELITY_MEMORY { + return nil, fmt.Errorf("runtime golden capture requires MEMORY fidelity") + } + ctx, cancel := context.WithCancel(ctx) defer cancel() // Not cancelable: a checkpoint is saving the actor's state. @@ -758,6 +634,9 @@ func (s *AteomService) CheckpointWorkload(ctx context.Context, req *ateompb.Chec containers := req.GetSpec().GetContainers() durablePaths := durableFSCheckpointPaths(containers) + if runtimeGolden { + durablePaths = nil + } switch fidelity { case ateompb.SnapshotFidelity_SNAPSHOT_FIDELITY_VOLUMES: if len(durablePaths) == 0 { @@ -795,6 +674,11 @@ func (s *AteomService) CheckpointWorkload(ctx context.Context, req *ateompb.Chec // Report exactly the files runsc wrote so atelet ships precisely this set // (checkpoint.img plus any pages images and fs/ durable-dir files), rather // than a hardcoded list. + if runtimeGolden { + if err := os.WriteFile(filepath.Join(checkpointPath, runtimeGoldenFile), []byte(runtimeGoldenFormat), 0o600); err != nil { + return nil, fmt.Errorf("writing runtime golden marker: %w", err) + } + } snapshotFiles, err := listSnapshotFiles(checkpointPath) if err != nil { return nil, fmt.Errorf("while listing checkpoint files: %w", err) @@ -889,205 +773,6 @@ func isContainerAlreadyGone(ctx context.Context, rcmd containerRuntime, name str return !slices.Contains(ids, name), nil } -func (s *AteomService) RestoreWorkload(ctx context.Context, req *ateompb.RestoreWorkloadRequest) (resp *ateompb.RestoreWorkloadResponse, retErr error) { - // Taken before the lock, so prep covers the wait for it. - tStart := time.Now() - if err := validateActorDirs(req.GetActorDirs()); err != nil { - return nil, err - } - if err := validateFidelity(req.GetFidelity()); err != nil { - return nil, err - } - if err := validateRunscPath(req.GetRunscPath()); err != nil { - return nil, err - } - if !s.locks.Lock(ctx, req.GetActorUid()) { - return nil, fmt.Errorf("gave up waiting for the actor's lock: %w", ctx.Err()) - } - defer s.locks.Unlock(req.GetActorUid()) - ctx, cancel := context.WithCancel(ctx) - defer cancel() - - // Per-phase timing, recorded on the way out so a failed restore still - // reports the phases it completed, and the failing step its elapsed time. - // Registered ahead of the failure cleanup below, so on failure the total - // includes that cleanup; the record is marked by error.type either way. - attribution := ateomstats.ActorAttributionFromRequest(req) - fidelity := req.GetFidelity() - containers := req.GetSpec().GetContainers() - var timing restoreTiming - tLast := tStart - defer func() { - timing.total = time.Since(tStart) - attrs := ateomphaselog.SnapshotPhaseAttrs(attribution, fidelity, ateomphaselog.RestoreDurationKey, retErr, timing.phases()) - attrs = append(attrs, slog.Int(containerCountKey, len(containers))) - slog.LogAttrs(ctx, slog.LevelInfo, "Restore timing breakdown", attrs...) - }() - - release, err := s.beginRPC(req.GetActorUid(), rpcRestoreWorkload, cancel) - if err != nil { - return nil, err - } - defer release() - if err := resetRunscStateAndPidFileDirs(req.GetActorDirs()); err != nil { - return nil, err - } - - err = s.tunnel.Deactivate(ctx, attribution) - timing.prep = lap(&tLast) - if err != nil { - return nil, err - } - - s.actorLogger.EmitLifecycleLog(ctx, "Actor restoring", attribution) - - // Contract with atelet: - // - // * Correct runsc version is downloaded and placed on disk. - // * All OCI bundles are set up, including for the pause container. - // * Checkpoint downloaded and placed on disk - - egress, err := s.tunnel.PrepareEgress(ctx, attribution, req.GetEgressGateway()) - timing.egressPrepare = lap(&tLast) - if err != nil { - return nil, err - } - hosted, err := s.hostActor(ctx, attribution, req.GetActorDirs()) - timing.netSetup = lap(&tLast) - if err != nil { - return nil, err - } - rcmd := &runsc{ - path: req.GetRunscPath(), - actorUID: req.GetActorUid(), - actorDirs: req.GetActorDirs(), - size: sizing.FromLimits(req.GetCpuMilli(), req.GetMemoryBytes()), - durableVolumes: durableVolumeNames(req.GetSpec()), - containers: req.GetSpec().GetContainers(), - } - var containersToDelete []string - defer func() { - if retErr != nil { - cleanupCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 30*time.Second) - defer cancel() - if err := s.tunnel.Deactivate(cleanupCtx, attribution); err != nil { - slog.WarnContext(cleanupCtx, "Failed to deactivate actor networking after Restore failure", slog.Any("err", err)) - } - deleteContainers(cleanupCtx, rcmd, containersToDelete, "Restore") - // Same overlay detach as the Run-failure path above. - if err := imagecache.UnmountAllUnder(req.GetActorDirs().GetOciBundleDir()); err != nil { - slog.WarnContext(ctx, "Failed to unmount bundle rootfs overlays after Restore failure", - "actorUID", req.GetActorUid(), "err", err) - } - if err := s.unhostActor(cleanupCtx, req.GetActorUid()); err != nil { - slog.WarnContext(cleanupCtx, "Failed to clean up actor network after Restore failure", slog.Any("err", err)) - } - } - }() - checkpointDir := req.GetActorDirs().GetRestoreDir() - restoreArgs, err := fsRestoreArgs(checkpointDir) - if err != nil { - return nil, 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. - err = imagecache.SetupBundleRootfs(ociBundlePath(req.GetActorDirs(), ocispec.PauseContainer)) - timing.pauseRootfs = lap(&tLast) - if err != nil { - return nil, fmt.Errorf("while composing pause rootfs: %w", err) - } - - switch fidelity { - case ateompb.SnapshotFidelity_SNAPSHOT_FIDELITY_VOLUMES: - // Create and start pause container (cold boot with durable-dir volumes restored from fs/) - containersToDelete = append(containersToDelete, ocispec.PauseContainer) - err := rcmd.cmdCreate(ctx, os.Stdout, ocispec.PauseContainer, restoreArgs) - timing.pauseCreate = lap(&tLast) - if err != nil { - return nil, fmt.Errorf("while creating pause container: %w", err) - } - err = rcmd.cmdStart(ctx, os.Stdout, ocispec.PauseContainer) - timing.pauseRestore = lap(&tLast) - if err != nil { - return nil, fmt.Errorf("while starting pause container: %w", err) - } - case ateompb.SnapshotFidelity_SNAPSHOT_FIDELITY_MEMORY: - // Create and restore pause container (restores both process/rootfs and fs/ durable-dir volumes) - containersToDelete = append(containersToDelete, ocispec.PauseContainer) - err := rcmd.cmdCreate(ctx, os.Stdout, ocispec.PauseContainer, restoreArgs) - timing.pauseCreate = lap(&tLast) - if err != nil { - return nil, fmt.Errorf("while creating pause container: %w", err) - } - err = rcmd.cmdRestore(ctx, os.Stdout, ocispec.PauseContainer, checkpointDir) - timing.pauseRestore = lap(&tLast) - if err != nil { - return nil, fmt.Errorf("while restoring pause container: %w", err) - } - default: - return nil, fmt.Errorf("unexpected snapshot fidelity: %v", fidelity) - } - - // Create and restore each application container, each with its own log pipe so - // every line is tagged with the originating container (ate.actor.container.name). - // app_create includes starting that pipe. - for _, ac := range containers { - pw, err := s.actorLogger.StartJSONLogPipe(attribution, ac.GetName()) - timing.appCreate += lap(&tLast) - if err != nil { - return nil, fmt.Errorf("while starting json log pipe for %q: %w", ac.GetName(), err) - } - defer pw.Close() - err = imagecache.SetupBundleRootfs(ociBundlePath(req.GetActorDirs(), ac.GetName())) - timing.appRootfs += lap(&tLast) - if err != nil { - return nil, fmt.Errorf("while composing %q rootfs: %w", ac.GetName(), err) - } - containersToDelete = append(containersToDelete, ac.GetName()) - err = rcmd.cmdCreate(ctx, pw, ac.GetName(), nil) - timing.appCreate += lap(&tLast) - if err != nil { - return nil, fmt.Errorf("while creating %q application container: %w", ac.GetName(), err) - } - switch fidelity { - case ateompb.SnapshotFidelity_SNAPSHOT_FIDELITY_VOLUMES: - err = rcmd.cmdStart(ctx, pw, ac.GetName()) - timing.appRestore += lap(&tLast) - if err != nil { - return nil, fmt.Errorf("while starting %q application container: %w", ac.GetName(), err) - } - case ateompb.SnapshotFidelity_SNAPSHOT_FIDELITY_MEMORY: - err = rcmd.cmdRestore(ctx, pw, ac.GetName(), checkpointDir) - timing.appRestore += lap(&tLast) - if err != nil { - return nil, fmt.Errorf("while restoring %q application container: %w", ac.GetName(), err) - } - default: - return nil, fmt.Errorf("unexpected snapshot fidelity: %v", fidelity) - } - } - - // Block until every wakeup-probe-enabled container reports 200. - err = wakeupprobe.WaitAll(ctx, containers, ateomnet.ActorVethIP, wakeupprobe.DialFunc(s.sandboxDialer(req.GetActorUid()))) - timing.wakeupProbe = lap(&tLast) - if err != nil { - return nil, fmt.Errorf("while waiting for container wakeup probe: %w", err) - } - err = s.tunnel.Activate(attribution, s.sandboxDialer(req.GetActorUid()), egress) - timing.activate = lap(&tLast) - if err != nil { - return nil, err - } - - s.actorLogger.EmitLifecycleLog(ctx, "Actor restored", attribution) - s.setSession(req.GetActorUid(), &workloadSession{rcmd: rcmd, containers: containerNames(containers)}) - s.recordInitial(ctx, hosted) - - return &ateompb.RestoreWorkloadResponse{}, nil -} - func (s *AteomService) TerminateWorkload(ctx context.Context, req *ateompb.TerminateWorkloadRequest) (*ateompb.TerminateWorkloadResponse, error) { if err := validateActorDirs(req.GetActorDirs()); err != nil { return nil, err diff --git a/cmd/ateom-gvisor/restore.go b/cmd/ateom-gvisor/restore.go new file mode 100644 index 0000000000..78c136f8dc --- /dev/null +++ b/cmd/ateom-gvisor/restore.go @@ -0,0 +1,234 @@ +//go:build linux + +// 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 main + +import ( + "context" + "fmt" + "github.com/agent-substrate/substrate/internal/ateomnet" + "github.com/agent-substrate/substrate/internal/ateomphaselog" + "github.com/agent-substrate/substrate/internal/ateomstats" + "github.com/agent-substrate/substrate/internal/imagecache" + "github.com/agent-substrate/substrate/internal/ocispec" + "github.com/agent-substrate/substrate/internal/proto/ateompb" + "github.com/agent-substrate/substrate/internal/sizing" + "github.com/agent-substrate/substrate/internal/wakeupprobe" + "log/slog" + "os" + "time" +) + +func (s *AteomService) RestoreWorkload(ctx context.Context, req *ateompb.RestoreWorkloadRequest) (resp *ateompb.RestoreWorkloadResponse, retErr error) { + // Taken before the lock, so prep covers the wait for it. + tStart := time.Now() + if err := validateActorDirs(req.GetActorDirs()); err != nil { + return nil, err + } + if err := validateFidelity(req.GetFidelity()); err != nil { + return nil, err + } + if err := validateRunscPath(req.GetRunscPath()); err != nil { + return nil, err + } + if !s.locks.Lock(ctx, req.GetActorUid()) { + return nil, fmt.Errorf("gave up waiting for the actor's lock: %w", ctx.Err()) + } + defer s.locks.Unlock(req.GetActorUid()) + ctx, cancel := context.WithCancel(ctx) + defer cancel() + + // Per-phase timing, recorded on the way out so a failed restore still + // reports the phases it completed, and the failing step its elapsed time. + // Registered ahead of the failure cleanup below, so on failure the total + // includes that cleanup; the record is marked by error.type either way. + attribution := ateomstats.ActorAttributionFromRequest(req) + fidelity := req.GetFidelity() + containers := req.GetSpec().GetContainers() + var timing restoreTiming + tLast := tStart + defer func() { + timing.total = time.Since(tStart) + attrs := ateomphaselog.SnapshotPhaseAttrs(attribution, fidelity, ateomphaselog.RestoreDurationKey, retErr, timing.phases()) + attrs = append(attrs, slog.Int(containerCountKey, len(containers))) + slog.LogAttrs(ctx, slog.LevelInfo, "Restore timing breakdown", attrs...) + }() + + runtimeGolden, err := readRuntimeGolden(req.GetActorDirs().GetRestoreDir()) + if err != nil { + return nil, err + } + restoreAppMemory, err := restoreApplicationMemory(fidelity, runtimeGolden) + if err != nil { + return nil, err + } + + release, err := s.beginRPC(req.GetActorUid(), rpcRestoreWorkload, cancel) + if err != nil { + return nil, err + } + defer release() + if err := resetRunscStateAndPidFileDirs(req.GetActorDirs()); err != nil { + return nil, err + } + + err = s.tunnel.Deactivate(ctx, attribution) + timing.prep = lap(&tLast) + if err != nil { + return nil, err + } + + s.actorLogger.EmitLifecycleLog(ctx, "Actor restoring", attribution) + + // Contract with atelet: + // + // * Correct runsc version is downloaded and placed on disk. + // * All OCI bundles are set up, including for the pause container. + // * Checkpoint downloaded and placed on disk + + egress, err := s.tunnel.PrepareEgress(ctx, attribution, req.GetEgressGateway()) + timing.egressPrepare = lap(&tLast) + if err != nil { + return nil, err + } + hosted, err := s.hostActor(ctx, attribution, req.GetActorDirs()) + timing.netSetup = lap(&tLast) + if err != nil { + return nil, err + } + rcmd := &runsc{ + path: req.GetRunscPath(), + actorUID: req.GetActorUid(), + actorDirs: req.GetActorDirs(), + size: sizing.FromLimits(req.GetCpuMilli(), req.GetMemoryBytes()), + durableVolumes: durableVolumeNames(req.GetSpec()), + containers: req.GetSpec().GetContainers(), + } + var containersToDelete []string + defer func() { + if retErr != nil { + cleanupCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 30*time.Second) + defer cancel() + if err := s.tunnel.Deactivate(cleanupCtx, attribution); err != nil { + slog.WarnContext(cleanupCtx, "Failed to deactivate actor networking after Restore failure", slog.Any("err", err)) + } + deleteContainers(cleanupCtx, rcmd, containersToDelete, "Restore") + // Same overlay detach as the Run-failure path above. + if err := imagecache.UnmountAllUnder(req.GetActorDirs().GetOciBundleDir()); err != nil { + slog.WarnContext(ctx, "Failed to unmount bundle rootfs overlays after Restore failure", + "actorUID", req.GetActorUid(), "err", err) + } + if err := s.unhostActor(cleanupCtx, req.GetActorUid()); err != nil { + slog.WarnContext(cleanupCtx, "Failed to clean up actor network after Restore failure", slog.Any("err", err)) + } + } + }() + checkpointDir := req.GetActorDirs().GetRestoreDir() + restoreArgs, err := fsRestoreArgs(checkpointDir) + if err != nil { + return nil, 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. + err = imagecache.SetupBundleRootfs(ociBundlePath(req.GetActorDirs(), ocispec.PauseContainer)) + timing.pauseRootfs = lap(&tLast) + if err != nil { + return nil, fmt.Errorf("while composing pause rootfs: %w", err) + } + + switch fidelity { + case ateompb.SnapshotFidelity_SNAPSHOT_FIDELITY_VOLUMES: + // Create and start pause container (cold boot with durable-dir volumes restored from fs/) + containersToDelete = append(containersToDelete, ocispec.PauseContainer) + err := rcmd.cmdCreate(ctx, os.Stdout, ocispec.PauseContainer, restoreArgs) + timing.pauseCreate = lap(&tLast) + if err != nil { + return nil, fmt.Errorf("while creating pause container: %w", err) + } + err = rcmd.cmdStart(ctx, os.Stdout, ocispec.PauseContainer) + timing.pauseRestore = lap(&tLast) + if err != nil { + return nil, fmt.Errorf("while starting pause container: %w", err) + } + case ateompb.SnapshotFidelity_SNAPSHOT_FIDELITY_MEMORY: + // Create and restore pause container (restores both process/rootfs and fs/ durable-dir volumes) + containersToDelete = append(containersToDelete, ocispec.PauseContainer) + err := rcmd.cmdCreate(ctx, os.Stdout, ocispec.PauseContainer, restoreArgs) + timing.pauseCreate = lap(&tLast) + if err != nil { + return nil, fmt.Errorf("while creating pause container: %w", err) + } + err = rcmd.cmdRestore(ctx, os.Stdout, ocispec.PauseContainer, checkpointDir) + timing.pauseRestore = lap(&tLast) + if err != nil { + return nil, fmt.Errorf("while restoring pause container: %w", err) + } + default: + return nil, fmt.Errorf("unexpected snapshot fidelity: %v", fidelity) + } + + // Create and restore each application container, each with its own log pipe so + // every line is tagged with the originating container (ate.actor.container.name). + // app_create includes starting that pipe. + for _, ac := range containers { + pw, err := s.actorLogger.StartJSONLogPipe(attribution, ac.GetName()) + timing.appCreate += lap(&tLast) + if err != nil { + return nil, fmt.Errorf("while starting json log pipe for %q: %w", ac.GetName(), err) + } + defer pw.Close() + err = imagecache.SetupBundleRootfs(ociBundlePath(req.GetActorDirs(), ac.GetName())) + timing.appRootfs += lap(&tLast) + if err != nil { + return nil, fmt.Errorf("while composing %q rootfs: %w", ac.GetName(), err) + } + containersToDelete = append(containersToDelete, ac.GetName()) + err = rcmd.cmdCreate(ctx, pw, ac.GetName(), nil) + timing.appCreate += lap(&tLast) + if err != nil { + return nil, fmt.Errorf("while creating %q application container: %w", ac.GetName(), err) + } + if restoreAppMemory { + err = rcmd.cmdRestore(ctx, pw, ac.GetName(), checkpointDir) + } else { + err = rcmd.cmdStart(ctx, pw, ac.GetName()) + } + timing.appRestore += lap(&tLast) + if err != nil { + return nil, fmt.Errorf("while activating %q application container: %w", ac.GetName(), err) + } + } + + // Block until every wakeup-probe-enabled container reports 200. + err = wakeupprobe.WaitAll(ctx, containers, ateomnet.ActorVethIP, wakeupprobe.DialFunc(s.sandboxDialer(req.GetActorUid()))) + timing.wakeupProbe = lap(&tLast) + if err != nil { + return nil, fmt.Errorf("while waiting for container wakeup probe: %w", err) + } + err = s.tunnel.Activate(attribution, s.sandboxDialer(req.GetActorUid()), egress) + timing.activate = lap(&tLast) + if err != nil { + return nil, err + } + + s.actorLogger.EmitLifecycleLog(ctx, "Actor restored", attribution) + s.setSession(req.GetActorUid(), &workloadSession{rcmd: rcmd, containers: containerNames(containers)}) + s.recordInitial(ctx, hosted) + + return &ateompb.RestoreWorkloadResponse{}, nil +} diff --git a/cmd/ateom-gvisor/run.go b/cmd/ateom-gvisor/run.go new file mode 100644 index 0000000000..04112a645c --- /dev/null +++ b/cmd/ateom-gvisor/run.go @@ -0,0 +1,165 @@ +//go:build linux + +// 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 main + +import ( + "context" + "fmt" + "github.com/agent-substrate/substrate/internal/ateomnet" + "github.com/agent-substrate/substrate/internal/ateomstats" + "github.com/agent-substrate/substrate/internal/imagecache" + "github.com/agent-substrate/substrate/internal/ocispec" + "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/wakeupprobe" + "log/slog" + "os" + "time" +) + +func (s *AteomService) RunWorkload(ctx context.Context, req *ateompb.RunWorkloadRequest) (resp *ateompb.RunWorkloadResponse, retErr error) { + if req.GetSpec().GetRuntimeGolden() && req.GetAtespace() != resources.GoldenActorAtespace { + return nil, fmt.Errorf("runtime golden capture requires a golden actor") + } + if err := validateActorDirs(req.GetActorDirs()); err != nil { + return nil, err + } + if err := validateRunscPath(req.GetRunscPath()); err != nil { + return nil, err + } + if !s.locks.Lock(ctx, req.GetActorUid()) { + return nil, fmt.Errorf("gave up waiting for the actor's lock: %w", ctx.Err()) + } + defer s.locks.Unlock(req.GetActorUid()) + ctx, cancel := context.WithCancel(ctx) + defer cancel() + release, err := s.beginRPC(req.GetActorUid(), rpcRunWorkload, cancel) + if err != nil { + return nil, err + } + defer release() + if err := resetRunscStateAndPidFileDirs(req.GetActorDirs()); err != nil { + return nil, err + } + + if err := s.tunnel.Deactivate(ctx, ateomstats.ActorAttributionFromRequest(req)); err != nil { + return nil, err + } + + attribution := ateomstats.ActorAttributionFromRequest(req) + s.actorLogger.EmitLifecycleLog(ctx, "Actor starting", attribution) + + // Contract with atelet: + // + // * Correct runsc version is downloaded and placed on disk. + // * All OCI bundles are set up, including for the pause container. + + egress, err := s.tunnel.PrepareEgress(ctx, ateomstats.ActorAttributionFromRequest(req), req.GetEgressGateway()) + if err != nil { + return nil, err + } + // Publish attribution before boot so stats can include startup usage. + hosted, err := s.hostActor(ctx, attribution, req.GetActorDirs()) + if err != nil { + return nil, err + } + rcmd := &runsc{ + path: req.GetRunscPath(), + actorUID: req.GetActorUid(), + actorDirs: req.GetActorDirs(), + size: sizing.FromLimits(req.GetCpuMilli(), req.GetMemoryBytes()), + durableVolumes: durableVolumeNames(req.GetSpec()), + containers: req.GetSpec().GetContainers(), + } + var containersToDelete []string + defer func() { + if retErr != nil { + cleanupCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), 30*time.Second) + defer cancel() + if err := s.tunnel.Deactivate(cleanupCtx, ateomstats.ActorAttributionFromRequest(req)); err != nil { + slog.WarnContext(cleanupCtx, "Failed to deactivate actor networking after Run failure", slog.Any("err", err)) + } + deleteContainers(cleanupCtx, rcmd, containersToDelete, "Run") + // Detach any bundle rootfs overlays a partially-completed setup + // mounted, mirroring the post-checkpoint cleanup — otherwise they + // linger in this namespace until atelet wipes the bundle dirs. + // Run before the network cleanup. + if err := imagecache.UnmountAllUnder(req.GetActorDirs().GetOciBundleDir()); err != nil { + slog.WarnContext(ctx, "Failed to unmount bundle rootfs overlays after Run failure", + "actorUID", req.GetActorUid(), "err", err) + } + if err := s.unhostActor(cleanupCtx, req.GetActorUid()); err != nil { + slog.WarnContext(cleanupCtx, "Failed to clean up actor network after Run failure", slog.Any("err", 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 + // capabilities); runsc's gofer resolves the mount in this pod's mount + // namespace. + if err := imagecache.SetupBundleRootfs(ociBundlePath(req.GetActorDirs(), ocispec.PauseContainer)); err != nil { + return nil, fmt.Errorf("while composing pause rootfs: %w", err) + } + containersToDelete = append(containersToDelete, ocispec.PauseContainer) + if err := rcmd.cmdCreate(ctx, os.Stdout, ocispec.PauseContainer, nil); err != nil { + return nil, fmt.Errorf("while creating pause container: %w", err) + } + if err := rcmd.cmdStart(ctx, os.Stdout, ocispec.PauseContainer); err != nil { + return nil, fmt.Errorf("while starting pause container: %w", err) + } + + if req.GetSpec().GetRuntimeGolden() { + s.setSession(req.GetActorUid(), &workloadSession{rcmd: rcmd, runtimeGolden: true}) + return &ateompb.RunWorkloadResponse{}, nil + } + + // Create and start each application container, each with its own log pipe so + // every line is tagged with the originating container (ate.actor.container.name). + for _, ac := range req.GetSpec().GetContainers() { + pw, err := s.actorLogger.StartJSONLogPipe(attribution, ac.GetName()) + if err != nil { + return nil, fmt.Errorf("while starting json log pipe for %q: %w", ac.GetName(), err) + } + defer pw.Close() + if err := imagecache.SetupBundleRootfs(ociBundlePath(req.GetActorDirs(), ac.GetName())); err != nil { + return nil, fmt.Errorf("while composing %q rootfs: %w", ac.GetName(), err) + } + containersToDelete = append(containersToDelete, ac.GetName()) + if err := rcmd.cmdCreate(ctx, pw, ac.GetName(), nil); err != nil { + return nil, fmt.Errorf("while creating %q application container: %w", ac.GetName(), err) + } + if err := rcmd.cmdStart(ctx, pw, ac.GetName()); err != nil { + return nil, fmt.Errorf("while starting %q application container: %w", ac.GetName(), err) + } + } + + // Block until every wakeup-probe-enabled container reports 200. + if err := wakeupprobe.WaitAll(ctx, req.GetSpec().GetContainers(), ateomnet.ActorVethIP, wakeupprobe.DialFunc(s.sandboxDialer(req.GetActorUid()))); err != nil { + return nil, fmt.Errorf("while waiting for container wakeup probe: %w", err) + } + if err := s.tunnel.Activate(ateomstats.ActorAttributionFromRequest(req), s.sandboxDialer(req.GetActorUid()), egress); err != nil { + return nil, err + } + + s.actorLogger.EmitLifecycleLog(ctx, "Actor started", attribution) + s.setSession(req.GetActorUid(), &workloadSession{rcmd: rcmd, containers: containerNames(req.GetSpec().GetContainers())}) + s.recordInitial(ctx, hosted) + + return &ateompb.RunWorkloadResponse{}, nil +} diff --git a/cmd/ateom-gvisor/runtime_golden.go b/cmd/ateom-gvisor/runtime_golden.go new file mode 100644 index 0000000000..12feaf9205 --- /dev/null +++ b/cmd/ateom-gvisor/runtime_golden.go @@ -0,0 +1,58 @@ +//go:build linux + +// 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 main + +import ( + "fmt" + "github.com/agent-substrate/substrate/internal/proto/ateompb" + "os" + "path/filepath" +) + +const runtimeGoldenFile = "runtime-golden" +const runtimeGoldenFormat = "gvisor-pause-only-v1\n" + +func readRuntimeGolden(dir string) (bool, error) { + b, err := os.ReadFile(filepath.Join(dir, runtimeGoldenFile)) + if os.IsNotExist(err) { + return false, nil + } + if err != nil { + return false, err + } + if string(b) != runtimeGoldenFormat { + return false, fmt.Errorf("invalid runtime golden marker") + } + return true, nil +} + +// isRuntimeGolden reads the capture phase under the session publication lock. +func (s *AteomService) isRuntimeGolden(actorUID string) bool { + s.actorsMu.RLock() + defer s.actorsMu.RUnlock() + h := s.actors[actorUID] + return h != nil && h.session != nil && h.session.runtimeGolden +} + +// A pause-only checkpoint has no application state. Its applications start +// fresh after the sandbox restore and use the destination's mounted volumes. +func restoreApplicationMemory(fidelity ateompb.SnapshotFidelity, runtimeGolden bool) (bool, error) { + if runtimeGolden && fidelity != ateompb.SnapshotFidelity_SNAPSHOT_FIDELITY_MEMORY { + return false, fmt.Errorf("runtime golden restore requires MEMORY fidelity") + } + return fidelity == ateompb.SnapshotFidelity_SNAPSHOT_FIDELITY_MEMORY && !runtimeGolden, nil +} diff --git a/cmd/ateom-gvisor/runtime_golden_test.go b/cmd/ateom-gvisor/runtime_golden_test.go new file mode 100644 index 0000000000..9119bdc659 --- /dev/null +++ b/cmd/ateom-gvisor/runtime_golden_test.go @@ -0,0 +1,127 @@ +//go:build linux + +// 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 main + +import ( + "context" + "github.com/agent-substrate/substrate/internal/actorlock" + "github.com/agent-substrate/substrate/internal/nodepath" + "github.com/agent-substrate/substrate/internal/proto/ateompb" + "os" + "path/filepath" + "strings" + "testing" +) + +func TestRuntimeGoldenMarker(t *testing.T) { + for _, tc := range []struct { + name, content string + present, want, bad bool + }{ + {name: "ordinary snapshot"}, + {name: "pause only", content: runtimeGoldenFormat, present: true, want: true}, + {name: "wrong runtime", content: "microvm-before-create-sandbox-v1\n", present: true, bad: true}, + {name: "empty", present: true, bad: true}, + } { + t.Run(tc.name, func(t *testing.T) { + dir := t.TempDir() + if tc.present { + if err := os.WriteFile(filepath.Join(dir, runtimeGoldenFile), []byte(tc.content), 0600); err != nil { + t.Fatal(err) + } + } + got, err := readRuntimeGolden(dir) + if got != tc.want || (err != nil) != tc.bad { + t.Fatalf("got %v, %v", got, err) + } + }) + } +} + +func TestRuntimeGoldenApplicationRestore(t *testing.T) { + memory := ateompb.SnapshotFidelity_SNAPSHOT_FIDELITY_MEMORY + volumes := ateompb.SnapshotFidelity_SNAPSHOT_FIDELITY_VOLUMES + for _, tc := range []struct { + name string + capture bool + fidelity ateompb.SnapshotFidelity + want bool + bad bool + }{ + {"own memory restores apps", false, memory, true, false}, + {"own volumes starts apps", false, volumes, false, false}, + {"runtime memory starts apps", true, memory, false, false}, + {"runtime volumes rejected", true, volumes, false, true}, + } { + t.Run(tc.name, func(t *testing.T) { + got, err := restoreApplicationMemory(tc.fidelity, tc.capture) + if got != tc.want || (err != nil) != tc.bad { + t.Fatalf("got %v, %v", got, err) + } + }) + } +} + +func TestRuntimeGoldenSessionDoesNotSurviveApplicationPublication(t *testing.T) { + s := &AteomService{actors: map[string]*hostedActor{"a": {}}} + if s.isRuntimeGolden("missing") || s.isRuntimeGolden("a") { + t.Fatal("absent session marked runtime-only") + } + s.setSession("a", &workloadSession{runtimeGolden: true}) + if !s.isRuntimeGolden("a") { + t.Fatal("capture phase not recorded") + } + s.setSession("a", &workloadSession{containers: []string{"app"}}) + if s.isRuntimeGolden("a") { + t.Fatal("application snapshot would be mislabeled runtime-only") + } +} + +func TestRuntimeGoldenRejectsNormalActorBeforeMutation(t *testing.T) { + s := &AteomService{} + _, err := s.RunWorkload(context.Background(), &ateompb.RunWorkloadRequest{Spec: &ateompb.WorkloadSpec{RuntimeGolden: true}}) + if err == nil { + t.Fatal("normal actor allowed to capture runtime-only snapshot") + } +} + +func TestRuntimeGoldenCheckpointRejectsVolumesBeforeMutation(t *testing.T) { + originalStaticDir := nodepath.StaticFilesDir + nodepath.StaticFilesDir = t.TempDir() + t.Cleanup(func() { nodepath.StaticFilesDir = originalStaticDir }) + if err := os.WriteFile(filepath.Join(nodepath.StaticFilesDir, "runsc"), nil, 0700); err != nil { + t.Fatal(err) + } + s := &AteomService{locks: actorlock.New(), actors: map[string]*hostedActor{"a": {session: &workloadSession{runtimeGolden: true}}}} + dirs := &ateompb.ActorDirs{ + RootDir: "/node/actors/a", OciBundleDir: "/node/actors/a/bundle", + CheckpointDir: "/node/actors/a/checkpoint-state", RestoreDir: "/node/actors/a/restore-state", + DurableDirVolumeMountsDir: "/node/actors/a/durable-dirs", SystemInfoVolumeRootsDir: "/node/actors/a/system-info", + VolumesDir: "/node/actors/a/volumes", + } + // All mutation dependencies are nil; touching networking or runtime would panic. + _, err := s.CheckpointWorkload(context.Background(), &ateompb.CheckpointWorkloadRequest{ + ActorUid: "a", ActorDirs: dirs, RunscPath: filepath.Join(nodepath.StaticFilesDir, "runsc"), + Fidelity: ateompb.SnapshotFidelity_SNAPSHOT_FIDELITY_VOLUMES, + }) + if err == nil || !strings.Contains(err.Error(), "requires MEMORY") { + t.Fatalf("got %v", err) + } + if !s.isRuntimeGolden("a") { + t.Fatal("capture session lost on rejected checkpoint") + } +} diff --git a/docs/csi-volumes.md b/docs/csi-volumes.md index c706876cbf..c459a1619c 100644 --- a/docs/csi-volumes.md +++ b/docs/csi-volumes.md @@ -252,23 +252,31 @@ Ordinary own-snapshot handoffs also retain application memory; changed backing data and deleted-open handles need application-specific semantics. Runtime goldens do not change those semantics or claim to repair those cases. -The runtime mode is rejected for gVisor. Its existing cold-start guard remains: -runsc derives `disable_file_handle_sharing` from the source filesystem, and a -local placeholder and NFS volume can produce incompatible restore options. +gVisor templates also support `GOLDEN_SNAPSHOT_MODE_RUNTIME`. They capture only +the running pause container. Application containers and their filesystem handles +do not exist at capture time. Restore resumes that sandbox, then creates and +starts application containers against the actor-selected volumes. This avoids +carrying placeholder-filesystem options into an application restore. Later own +snapshots restore application memory normally. ### Runtime golden regression coverage The microVM CI lane requires the runtime golden correctness cases and NFS CSI; missing prerequisites fail that lane. Local cluster runs opt in with -`E2E_RUNTIME_GOLDEN=true`, `E2E_SANDBOX_CLASS=microvm`, and +`E2E_RUNTIME_GOLDEN=true`, `E2E_SANDBOX_CLASS=microvm` or `gvisor`, and `E2E_RUNTIME_LOG_DIR` pointing to an evidence directory. Run `TestRuntimeGoldenVolumes` in `internal/e2e/suites/combinedvolumes` through `hack/run-e2e-kind.sh`. This checks distinct volume bindings, guest/process -identity, and retained state over two own-snapshot generations. +identity, and retained state over two own-snapshot generations. The eager guest +boot marker is checked only for microVM: gVisor regenerates its procfs boot ID +on restore, so that ID is diagnostic rather than evidence of continuity. The probe contract checks directory entries and negative lookups as well as -cached and open-file contents. Only the known deleted-open-file `EIO` on the -second generation is tolerated; other errors fail the test. +cached, open-file, and memory-mapped contents. Only the known microVM +deleted-open-file `EIO` on the second generation is tolerated; other errors fail +the test. gVisor must preserve deleted-open contents in both generations. +MicroVM deleted-open recovery remains limited by virtiofsd's inode migration; +runtime-only capture does not repair a later own snapshot's orphaned inode. Latency collection is separate: select `TestRuntimeGoldenLatency`, additionally set `E2E_RUNTIME_GOLDEN_BENCHMARK=true` and `E2E_LATENCY_OUTPUT` to a JSONL file. diff --git a/internal/e2e/fixtures/probe/runtime_state.go b/internal/e2e/fixtures/probe/runtime_state.go index 1655bb0f87..6a1c98e3a8 100644 --- a/internal/e2e/fixtures/probe/runtime_state.go +++ b/internal/e2e/fixtures/probe/runtime_state.go @@ -18,6 +18,7 @@ import ( "crypto/rand" "encoding/hex" "encoding/json" + "fmt" "net/http" "os" "path/filepath" @@ -33,28 +34,47 @@ var processNonce = func() string { return hex.EncodeToString(b) }() -func runtimeState(w http.ResponseWriter, _ *http.Request) { +func runtimeState(w http.ResponseWriter, r *http.Request) { b, err := os.ReadFile("/proc/sys/kernel/random/boot_id") if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } - cmdline, err := os.ReadFile("/proc/cmdline") + kind := r.URL.Query().Get("runtime") + var cmdline []byte + if kind == "" || kind == "microvm" { + cmdline, err = os.ReadFile("/proc/cmdline") + if err != nil { + http.Error(w, err.Error(), 500) + return + } + } + marker, err := runtimeBootIdentity(kind, strings.TrimSpace(string(b)), string(cmdline)) if err != nil { http.Error(w, err.Error(), 500) return } - var marker string - for _, arg := range strings.Fields(string(cmdline)) { - if value, ok := strings.CutPrefix(arg, "ate.boot_id="); ok { - marker = value + writeJSON(w, map[string]string{"boot_id": marker, "kernel_boot_id": strings.TrimSpace(string(b)), "process_nonce": processNonce}) +} + +// gVisor supplies a diagnostic boot ID that changes on restore. MicroVM +// continuity uses our eager marker because Linux initializes boot_id lazily. +func runtimeBootIdentity(kind, kernelBoot, cmdline string) (string, error) { + if kind == "gvisor" { + if kernelBoot == "" { + return "", fmt.Errorf("sandbox boot identity missing") } + return kernelBoot, nil } - if marker == "" { - http.Error(w, "guest boot marker missing", 500) - return + if kind != "" && kind != "microvm" { + return "", fmt.Errorf("unsupported runtime %q", kind) } - writeJSON(w, map[string]string{"boot_id": marker, "kernel_boot_id": strings.TrimSpace(string(b)), "process_nonce": processNonce}) + for _, arg := range strings.Fields(cmdline) { + if marker, ok := strings.CutPrefix(arg, "ate.boot_id="); ok && marker != "" { + return marker, nil + } + } + return "", fmt.Errorf("guest boot marker missing") } // seedVolumeFixture seeds a disposable fixture before the retained-state probe is diff --git a/internal/e2e/fixtures/probe/runtime_state_test.go b/internal/e2e/fixtures/probe/runtime_state_test.go index 850d63920b..3745d54b5c 100644 --- a/internal/e2e/fixtures/probe/runtime_state_test.go +++ b/internal/e2e/fixtures/probe/runtime_state_test.go @@ -48,3 +48,24 @@ func TestSeedVolumeFixtureRejectsUnsafeRoot(t *testing.T) { } } } + +func TestRuntimeBootIdentity(t *testing.T) { + for _, tc := range []struct { + name, kind, kernel, cmdline, want string + bad bool + }{ + {"microvm eager marker", "microvm", "lazy", "quiet ate.boot_id=eager", "eager", false}, + {"default microvm", "", "lazy", "ate.boot_id=eager", "eager", false}, + {"microvm must not fall back", "microvm", "lazy", "", "", true}, + {"gvisor proc identity", "gvisor", "sandbox", "", "sandbox", false}, + {"missing gvisor identity", "gvisor", "", "", "", true}, + {"unsupported runtime", "other", "some", "ate.boot_id=some", "", true}, + } { + t.Run(tc.name, func(t *testing.T) { + got, err := runtimeBootIdentity(tc.kind, tc.kernel, tc.cmdline) + if got != tc.want || (err != nil) != tc.bad { + t.Fatalf("got %q, %v", got, err) + } + }) + } +} diff --git a/internal/e2e/fixtures/probe/volume_state.go b/internal/e2e/fixtures/probe/volume_state.go index dff4599edb..92594afad3 100644 --- a/internal/e2e/fixtures/probe/volume_state.go +++ b/internal/e2e/fixtures/probe/volume_state.go @@ -38,6 +38,7 @@ type volumeStateProbe struct { root, challenge string cached string held, unlinked, directory *os.File + mapped []byte reads uint64 } @@ -76,6 +77,10 @@ func volumeReadPath(path string) probeapi.VolumeObservation { } func (p *volumeStateProbe) close() { + if p.mapped != nil { + _ = syscall.Munmap(p.mapped) + p.mapped = nil + } for _, f := range []*os.File{p.held, p.unlinked, p.directory} { if f != nil { _ = f.Close() @@ -104,6 +109,17 @@ func (p *volumeStateProbe) prime(root, challenge string) (err error) { if p.held, err = os.Open(filepath.Join(root, "held.txt")); err != nil { return err } + info, err := p.held.Stat() + if err != nil { + return err + } + if info.Size() < 1 || info.Size() > 4096 { + return fmt.Errorf("held.txt must contain 1..4096 bytes for mmap") + } + p.mapped, err = syscall.Mmap(int(p.held.Fd()), 0, int(info.Size()), syscall.PROT_READ, syscall.MAP_SHARED) + if err != nil { + return fmt.Errorf("mapping held.txt: %w", err) + } if p.directory, err = os.Open(filepath.Join(root, "directory")); err != nil { return err } @@ -133,6 +149,7 @@ func (p *volumeStateProbe) observe() probeapi.VolumeStateResponse { Challenge: p.challenge, Reads: p.reads, Cached: p.cached, ByPath: volumeReadPath(filepath.Join(p.root, "cached.txt")), Held: volumeRead(p.held), Unlinked: volumeRead(p.unlinked), + Mapped: volumeResult(p.mapped, nil), Negative: volumeReadPath(filepath.Join(p.root, "negative.txt")), } if _, err := p.directory.Seek(0, io.SeekStart); err != nil { diff --git a/internal/e2e/fixtures/probe/volume_state_test.go b/internal/e2e/fixtures/probe/volume_state_test.go index 3c688ae9ba..b5b725a9dd 100644 --- a/internal/e2e/fixtures/probe/volume_state_test.go +++ b/internal/e2e/fixtures/probe/volume_state_test.go @@ -111,6 +111,9 @@ func TestVolumeStateDistinguishesRetainedState(t *testing.T) { if got.Held.Data != "source-held.txt" || got.Held.Error != "" { t.Fatalf("held descriptor: %+v", got.Held) } + if got.Mapped.Data != "source-held.txt" || got.Mapped.Error != "" { + t.Fatalf("retained mapping: %+v", got.Mapped) + } if got.Unlinked.Data != "source-unlinked.txt" || got.Unlinked.Error != "" { t.Fatalf("unlinked descriptor: %+v", got.Unlinked) } @@ -150,7 +153,7 @@ func TestVolumeStatePrimeFailureClosesDescriptors(t *testing.T) { if w.Code != http.StatusBadRequest { t.Fatalf("missing fixture returned %d", w.Code) } - if p.held != nil || p.directory != nil || p.unlinked != nil || p.challenge != "" { + if p.held != nil || p.directory != nil || p.unlinked != nil || p.challenge != "" || p.mapped != nil { t.Fatal("failed prime retained state") } volumeWrite(t, filepath.Join(root, "unlinked.txt"), "repaired") @@ -198,3 +201,26 @@ func TestVolumeResultClassifiesWrappedIOError(t *testing.T) { t.Fatalf("unrelated error classified as EIO: %+v", other) } } + +func TestVolumeStateMappingSeesInPlaceWrites(t *testing.T) { + p := &volumeStateProbe{} + root := volumeFixture(t) + volumePrime(t, p, root) + f, err := os.OpenFile(filepath.Join(root, "held.txt"), os.O_WRONLY, 0) + if err != nil { + t.Fatal(err) + } + defer f.Close() + value := "update-held.txt" + if _, err := f.WriteAt([]byte(value), 0); err != nil { + t.Fatal(err) + } + got := volumeObserve(t, p) + if got.Mapped.Data != value || got.Held.Data != value { + t.Fatalf("mapping did not observe backing inode update: %+v", got) + } + p.close() + if p.mapped != nil { + t.Fatal("mapping retained after close") + } +} diff --git a/internal/e2e/probeapi/volume.go b/internal/e2e/probeapi/volume.go index 597876183e..c02dfedfea 100644 --- a/internal/e2e/probeapi/volume.go +++ b/internal/e2e/probeapi/volume.go @@ -33,6 +33,7 @@ type VolumeStateResponse struct { Cached string `json:"cached"` ByPath VolumeObservation `json:"by_path"` Held VolumeObservation `json:"held"` + Mapped VolumeObservation `json:"mapped"` Unlinked VolumeObservation `json:"unlinked"` Negative VolumeObservation `json:"negative"` Directory []string `json:"directory"` @@ -40,12 +41,12 @@ type VolumeStateResponse struct { } // ValidateRetainedState checks the disposable fixture across an own-snapshot -// restore. Only the observed second-generation deleted-open EIO is tolerated. -func ValidateRetainedState(obs VolumeStateResponse, challenge, value string, generation int) error { +// restore. The microVM-only second-generation EIO exception must be explicit. +func ValidateRetainedState(obs VolumeStateResponse, challenge, value string, generation int, allowDeletedOpenEIO bool) error { if obs.Challenge != challenge || obs.Cached != value { return fmt.Errorf("application state mismatch: %+v", obs) } - for name, got := range map[string]VolumeObservation{"path": obs.ByPath, "held": obs.Held} { + for name, got := range map[string]VolumeObservation{"path": obs.ByPath, "held": obs.Held, "mapped": obs.Mapped} { if got.Error != "" || got.ErrorCode != "" || got.NotExist || got.Data != value { return fmt.Errorf("%s observation mismatch: %+v", name, got) } @@ -57,7 +58,7 @@ func ValidateRetainedState(obs VolumeStateResponse, challenge, value string, gen return fmt.Errorf("negative lookup mismatch: %+v", obs.Negative) } u := obs.Unlinked - if generation == 2 && u.ErrorCode == "EIO" && u.Error != "" && u.Data == "" && !u.NotExist { + if allowDeletedOpenEIO && generation == 2 && u.ErrorCode == "EIO" && u.Error != "" && u.Data == "" && !u.NotExist { return nil } if u.Error != "" || u.ErrorCode != "" || u.NotExist || u.Data != value { diff --git a/internal/e2e/probeapi/volume_test.go b/internal/e2e/probeapi/volume_test.go index b9cd85180d..5f0bed06a8 100644 --- a/internal/e2e/probeapi/volume_test.go +++ b/internal/e2e/probeapi/volume_test.go @@ -17,7 +17,7 @@ package probeapi import "testing" func TestValidateRetainedState(t *testing.T) { - valid := VolumeStateResponse{Challenge: "c", Cached: "v", ByPath: VolumeObservation{Data: "v"}, Held: VolumeObservation{Data: "v"}, Unlinked: VolumeObservation{Data: "v"}, Negative: VolumeObservation{NotExist: true, Error: "not found"}, Directory: []string{"entry"}} + valid := VolumeStateResponse{Challenge: "c", Cached: "v", ByPath: VolumeObservation{Data: "v"}, Held: VolumeObservation{Data: "v"}, Mapped: VolumeObservation{Data: "v"}, Unlinked: VolumeObservation{Data: "v"}, Negative: VolumeObservation{NotExist: true, Error: "not found"}, Directory: []string{"entry"}} for _, tc := range []struct { name string generation int @@ -36,15 +36,27 @@ func TestValidateRetainedState(t *testing.T) { {"empty directory", 2, func(v *VolumeStateResponse) { v.Directory = nil }, true}, {"wrong directory", 2, func(v *VolumeStateResponse) { v.Directory = []string{"other"} }, true}, {"negative exists", 2, func(v *VolumeStateResponse) { v.Negative = VolumeObservation{Data: "leaked"} }, true}, + {"mapped mismatch", 2, func(v *VolumeStateResponse) { v.Mapped.Data = "other" }, true}, {"held error", 2, func(v *VolumeStateResponse) { v.Held.Error = "failed" }, true}, {"cached mismatch", 2, func(v *VolumeStateResponse) { v.Cached = "other" }, true}, } { t.Run(tc.name, func(t *testing.T) { v := valid tc.mutate(&v) - if err := ValidateRetainedState(v, "c", "v", tc.generation); (err != nil) != tc.bad { + if err := ValidateRetainedState(v, "c", "v", tc.generation, true); (err != nil) != tc.bad { t.Fatalf("got %v, want bad=%v", err, tc.bad) } }) } } + +func TestValidateRetainedStateRejectsUnapprovedEIO(t *testing.T) { + obs := VolumeStateResponse{Challenge: "c", Cached: "v", ByPath: VolumeObservation{Data: "v"}, Held: VolumeObservation{Data: "v"}, Mapped: VolumeObservation{Data: "v"}, Unlinked: VolumeObservation{Data: "v"}, Negative: VolumeObservation{NotExist: true, Error: "not found"}, Directory: []string{"entry"}} + if err := ValidateRetainedState(obs, "c", "v", 2, false); err != nil { + t.Fatal(err) + } + obs.Unlinked = VolumeObservation{Error: "read: input/output error", ErrorCode: "EIO"} + if err := ValidateRetainedState(obs, "c", "v", 2, false); err == nil { + t.Fatal("unapproved deleted-open EIO accepted") + } +} diff --git a/internal/e2e/runtimegoldenenv/env.go b/internal/e2e/runtimegoldenenv/env.go index 795cd4a1a0..508476b284 100644 --- a/internal/e2e/runtimegoldenenv/env.go +++ b/internal/e2e/runtimegoldenenv/env.go @@ -26,8 +26,8 @@ func Check() error { if !Enabled() { return nil } - if os.Getenv("E2E_SANDBOX_CLASS") != "microvm" { - return fmt.Errorf("runtime golden tests require microvm") + if kind := os.Getenv("E2E_SANDBOX_CLASS"); kind != "microvm" && kind != "gvisor" { + return fmt.Errorf("runtime golden tests require microvm or gvisor") } if os.Getenv("E2E_RUNTIME_LOG_DIR") == "" { return fmt.Errorf("runtime golden tests require E2E_RUNTIME_LOG_DIR") diff --git a/internal/e2e/runtimegoldenenv/env_test.go b/internal/e2e/runtimegoldenenv/env_test.go index 8234d5ece1..783d82e195 100644 --- a/internal/e2e/runtimegoldenenv/env_test.go +++ b/internal/e2e/runtimegoldenenv/env_test.go @@ -67,3 +67,20 @@ func TestCheckConfigured(t *testing.T) { t.Fatal(err) } } + +func TestCheckRuntimeSelection(t *testing.T) { + for _, tc := range []struct { + kind string + bad bool + }{{"microvm", false}, {"gvisor", false}, {"other", true}, {"", true}} { + t.Run(tc.kind, func(t *testing.T) { + t.Setenv("CI", "") + t.Setenv("E2E_RUNTIME_GOLDEN", "true") + t.Setenv("E2E_SANDBOX_CLASS", tc.kind) + t.Setenv("E2E_RUNTIME_LOG_DIR", t.TempDir()) + if err := Check(); (err != nil) != tc.bad { + t.Fatalf("got %v", err) + } + }) + } +} diff --git a/internal/e2e/suites/combinedvolumes/runtime_golden_fixture_test.go b/internal/e2e/suites/combinedvolumes/runtime_golden_fixture_test.go index 9c3322cd46..7c13cc59ee 100644 --- a/internal/e2e/suites/combinedvolumes/runtime_golden_fixture_test.go +++ b/internal/e2e/suites/combinedvolumes/runtime_golden_fixture_test.go @@ -164,3 +164,11 @@ func (f *runtimeGoldenFixture) post(t *testing.T, a *ateapipb.Actor, path string t.Fatalf("%s status %d", path, resp.StatusCode) } } + +func runtimeStatePath() string { + return "/runtime-state?runtime=" + os.Getenv("E2E_SANDBOX_CLASS") +} + +// gVisor regenerates its procfs boot ID on restore. Its runtime-only boundary +// is checked with a retained pause-process nonce in the direct runsc test. +func usesGuestBootMarker() bool { return os.Getenv("E2E_SANDBOX_CLASS") == "microvm" } diff --git a/internal/e2e/suites/combinedvolumes/runtime_golden_latency_test.go b/internal/e2e/suites/combinedvolumes/runtime_golden_latency_test.go index 2eb06c5be5..370030b0ce 100644 --- a/internal/e2e/suites/combinedvolumes/runtime_golden_latency_test.go +++ b/internal/e2e/suites/combinedvolumes/runtime_golden_latency_test.go @@ -67,7 +67,7 @@ func TestRuntimeGoldenLatency(t *testing.T) { // Identify the template kernel once, outside measured activations. seed := f.create(t, f.golden, "identity-"+f.name, f.volumes[0]) f.resume(t, seed) - goldenBoot := probeJSON(ctx, t, f.router, resources.ActorRefFromActor(seed), "/runtime-state")["boot_id"] + goldenBoot := probeJSON(ctx, t, f.router, resources.ActorRefFromActor(seed), runtimeStatePath())["boot_id"] f.remove(t, seed) rng := rand.New(rand.NewPCG(42, 91)) for i := -5; i < samples; i++ { @@ -84,7 +84,7 @@ func TestRuntimeGoldenLatency(t *testing.T) { var ownNonce string if mode == "own" { f.resume(t, a) - ownNonce = probeJSON(ctx, t, f.router, resources.ActorRefFromActor(a), "/runtime-state")["process_nonce"] + ownNonce = probeJSON(ctx, t, f.router, resources.ActorRefFromActor(a), runtimeStatePath())["process_nonce"] a = f.suspend(t, a) } snap, _ := json.Marshal(a.GetStatus().GetSnapshots()) @@ -108,13 +108,13 @@ func TestRuntimeGoldenLatency(t *testing.T) { } f.resume(t, a) ref := resources.ActorRefFromActor(a) - state := probeJSON(ctx, t, f.router, ref, "/runtime-state") + state := probeJSON(ctx, t, f.router, ref, runtimeStatePath()) sample.BootID = state["boot_id"] sample.ProcessNonce = state["process_nonce"] - if mode == "cold" && sample.BootID == goldenBoot { + if usesGuestBootMarker() && mode == "cold" && sample.BootID == goldenBoot { t.Fatal("cold sample restored golden") } - if mode != "cold" && sample.BootID != goldenBoot { + if usesGuestBootMarker() && mode != "cold" && sample.BootID != goldenBoot { t.Fatal("restore sample cold-booted") } if mode == "own" && sample.ProcessNonce != ownNonce { diff --git a/internal/e2e/suites/combinedvolumes/runtime_golden_test.go b/internal/e2e/suites/combinedvolumes/runtime_golden_test.go index 13a55f2165..bec4991b49 100644 --- a/internal/e2e/suites/combinedvolumes/runtime_golden_test.go +++ b/internal/e2e/suites/combinedvolumes/runtime_golden_test.go @@ -19,6 +19,7 @@ import ( "encoding/json" "fmt" "net/url" + "os" "strconv" "testing" @@ -31,8 +32,8 @@ func TestRuntimeGoldenVolumes(t *testing.T) { f := newRuntimeGoldenFixture(t) ctx := context.Background() // Distinct actor-selected volumes must receive no placeholder/application - // state. The same boot ID across clones proves a resumed kernel; distinct - // process nonces prove applications start after the snapshot boundary. + // state. MicroVM clones retain the eager boot marker; on both runtimes, + // distinct process nonces verify fresh application starts. var goldenBoot, firstNonce string for i, v := range f.volumes { a := f.create(t, f.golden, fmt.Sprintf("check-%d-%s", i, f.name), v) @@ -43,15 +44,15 @@ func TestRuntimeGoldenVolumes(t *testing.T) { } f.resume(t, a) ref := resources.ActorRefFromActor(a) - state := probeJSON(ctx, t, f.router, ref, "/runtime-state") + state := probeJSON(ctx, t, f.router, ref, runtimeStatePath()) if state["boot_id"] == "" || state["process_nonce"] == "" { t.Fatal("missing runtime identity") } if i == 0 { goldenBoot = state["boot_id"] firstNonce = state["process_nonce"] - } else if state["boot_id"] != goldenBoot || state["process_nonce"] == firstNonce { - t.Fatalf("not distinct processes from one resumed kernel: %v", state) + } else if (usesGuestBootMarker() && state["boot_id"] != goldenBoot) || state["process_nonce"] == firstNonce { + t.Fatalf("unexpected runtime or process identity: %v", state) } requireUnreadable(ctx, t, f.router, ref, sharedPath+"/actor-"+strconv.Itoa(1-i)) requireWrite(ctx, t, f.router, ref, sharedPath+"/actor-"+strconv.Itoa(i)) @@ -62,8 +63,8 @@ func TestRuntimeGoldenVolumes(t *testing.T) { for generation := 1; generation <= 2; generation++ { a = f.suspend(t, a) f.resume(t, a) - after := probeJSON(ctx, t, f.router, ref, "/runtime-state") - if after["boot_id"] != goldenBoot || after["process_nonce"] != state["process_nonce"] { + after := probeJSON(ctx, t, f.router, ref, runtimeStatePath()) + if (usesGuestBootMarker() && after["boot_id"] != goldenBoot) || after["process_nonce"] != state["process_nonce"] { t.Fatal("own restore restarted application or guest") } resp, err := f.router.Get(ctx, ref, "/volume-state") @@ -77,7 +78,7 @@ func TestRuntimeGoldenVolumes(t *testing.T) { t.Fatal(err) } t.Logf("retained state actor=%s generation=%d: %+v", v, generation, obs) - if err := probeapi.ValidateRetainedState(obs, challenge, v, generation); err != nil { + if err := probeapi.ValidateRetainedState(obs, challenge, v, generation, os.Getenv("E2E_SANDBOX_CLASS") == "microvm"); err != nil { t.Fatal(err) } if obs.Unlinked.ErrorCode == "EIO" { diff --git a/pkg/proto/ateapipb/ateapi.pb.go b/pkg/proto/ateapipb/ateapi.pb.go index cf46b37108..e036c76850 100644 --- a/pkg/proto/ateapipb/ateapi.pb.go +++ b/pkg/proto/ateapipb/ateapi.pb.go @@ -539,9 +539,9 @@ const ( GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_UNSPECIFIED GoldenSnapshotMode = 0 GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_ENABLED GoldenSnapshotMode = 1 GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_DISABLED GoldenSnapshotMode = 2 - // Capture the microVM before creating the guest sandbox or application - // processes. Restore attaches real volumes before starting applications. - // Does not preserve application warmup. Requires MICROVM. + // Capture the runtime before creating application processes. Supported by + // MICROVM and GVISOR. Restore attaches real volumes before starting + // applications; application warmup is not preserved. GoldenSnapshotMode_GOLDEN_SNAPSHOT_MODE_RUNTIME GoldenSnapshotMode = 3 ) diff --git a/pkg/proto/ateapipb/ateapi.proto b/pkg/proto/ateapipb/ateapi.proto index 3912b22caa..4c5004d9a7 100644 --- a/pkg/proto/ateapipb/ateapi.proto +++ b/pkg/proto/ateapipb/ateapi.proto @@ -1330,9 +1330,9 @@ enum GoldenSnapshotMode { GOLDEN_SNAPSHOT_MODE_UNSPECIFIED = 0; GOLDEN_SNAPSHOT_MODE_ENABLED = 1; GOLDEN_SNAPSHOT_MODE_DISABLED = 2; - // Capture the microVM before creating the guest sandbox or application - // processes. Restore attaches real volumes before starting applications. - // Does not preserve application warmup. Requires MICROVM. + // Capture the runtime before creating application processes. Supported by + // MICROVM and GVISOR. Restore attaches real volumes before starting + // applications; application warmup is not preserved. GOLDEN_SNAPSHOT_MODE_RUNTIME = 3; } @@ -1529,7 +1529,6 @@ message Volume { // +k8s:unionMember ExternalVolumeSource external = 7; - // +k8s:optional // +k8s:unionMember SystemInfoVolumeSource system_info = 5; From 82b4075529274b027393283c5d0fff09e959e418 Mon Sep 17 00:00:00 2001 From: Salah Date: Thu, 15 Oct 2026 15:22:57 +0400 Subject: [PATCH 10/12] Preserve current volume metadata and upstream restore cleanup --- cmd/ateapi/internal/controlapi/shared_volume.go | 8 ++++---- cmd/ateapi/internal/controlapi/workflow_resume.go | 11 +++++++++-- cmd/ateworker-microvm/checkpoint.go | 2 +- cmd/ateworker-microvm/restore.go | 1 - 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/cmd/ateapi/internal/controlapi/shared_volume.go b/cmd/ateapi/internal/controlapi/shared_volume.go index 044cbbdb22..a78d40bbc1 100644 --- a/cmd/ateapi/internal/controlapi/shared_volume.go +++ b/cmd/ateapi/internal/controlapi/shared_volume.go @@ -80,7 +80,7 @@ func (s *ServiceImpl) ListSharedVolumes(ctx context.Context, atespace string, op return s.store.ListSharedVolumes(ctx, atespace, opts) } -var errSharedVolumePending = errors.New("shared volume is still being created") +var errSharedVolumeNotReady = errors.New("shared volume is not ready for updates") func (s *RPCService) UpdateSharedVolume(ctx context.Context, req *ateapipb.UpdateSharedVolumeRequest) (*ateapipb.SharedVolume, error) { inVolume := req.SharedVolume @@ -96,7 +96,7 @@ func (s *RPCService) UpdateSharedVolume(ctx context.Context, req *ateapipb.Updat stored, err := s.impl.UpdateSharedVolume(ctx, volumeRef, store.PreconditionFrom(in), func(toUpdate *ateapipb.SharedVolume) error { if toUpdate.GetStatus().GetState() != ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY { - return errSharedVolumePending + return errSharedVolumeNotReady } metadata, volumeStatus := toUpdate.GetMetadata(), toUpdate.GetStatus() proto.Reset(toUpdate) @@ -106,8 +106,8 @@ func (s *RPCService) UpdateSharedVolume(ctx context.Context, req *ateapipb.Updat return nil }) if err != nil { - if errors.Is(err, errSharedVolumePending) { - return nil, apierror.FailedPrecondition("SharedVolume %s is still being created", volumeRef) + if errors.Is(err, errSharedVolumeNotReady) { + return nil, apierror.FailedPrecondition("SharedVolume %s is not ready for updates", volumeRef) } if errors.Is(err, store.ErrImmutableField) || errors.Is(err, store.ErrPreconditionRequired) { return nil, apierror.InvalidArgument("while updating shared volume %s: %v", volumeRef, err) diff --git a/cmd/ateapi/internal/controlapi/workflow_resume.go b/cmd/ateapi/internal/controlapi/workflow_resume.go index d397fa4a74..dbe7ceda35 100644 --- a/cmd/ateapi/internal/controlapi/workflow_resume.go +++ b/cmd/ateapi/internal/controlapi/workflow_resume.go @@ -127,8 +127,9 @@ func (w *ActorWorkflow) ResumeActor(ctx context.Context, actorRef resources.Acto } actor = assigned if len(borrowedVolumeRefs(actor)) > 0 { - if _, err = claimSharedVolumes(leaseCtx, w.store, actor); err != nil { - return nil, false, err + mounts, claimErr := claimSharedVolumes(leaseCtx, w.store, actor) + if claimErr != nil { + return nil, false, claimErr } // After claiming, never release ownership until node access is gone. @@ -138,6 +139,12 @@ func (w *ActorWorkflow) ResumeActor(ctx context.Context, actorRef resources.Acto } err = errors.Join(err, w.releaseFailedResumeClaims(leaseCtx, actorRef, actor, actorTemplate)) }() + // Attachment uses the current driver context, not metadata frozen at create. + updated, updateErr := w.store.UpdateActor(leaseCtx, actorRef, store.PreconditionFrom(actor), func(a *ateapipb.Actor) error { a.Status.ExternalVolumes = mounts; return nil }) + if updateErr != nil { + return nil, false, updateErr + } + actor = updated } volumePublishContexts, err := w.ensureVolumesAttached(leaseCtx, actor, worker, actorTemplate) if err != nil { diff --git a/cmd/ateworker-microvm/checkpoint.go b/cmd/ateworker-microvm/checkpoint.go index 0c8e4b0b99..8dfe86f0ee 100644 --- a/cmd/ateworker-microvm/checkpoint.go +++ b/cmd/ateworker-microvm/checkpoint.go @@ -146,7 +146,7 @@ func (s *AteWorkerService) CheckpointWorkload(ctx context.Context, req *ateworke hosted := s.lookupActor(actorUID) // The actor's CH was booted by RunWorkload or relaunched by RestoreWorkload; - // either way ateom owns it and tracks its api-socket. + // either way ateworker owns it and tracks its api-socket. chSocket := kata.CLHSocketPath(actorUID) if ra != nil && ra.apiSocket != "" { chSocket = ra.apiSocket diff --git a/cmd/ateworker-microvm/restore.go b/cmd/ateworker-microvm/restore.go index 1e95c39393..6b5f1508a3 100644 --- a/cmd/ateworker-microvm/restore.go +++ b/cmd/ateworker-microvm/restore.go @@ -513,7 +513,6 @@ func (s *AteWorkerService) restoreMemoryFidelity(ctx context.Context, p actorBoo if err := s.tunnel.Activate(p.attribution(), s.sandboxDialer(p.actorUID), egress); err != nil { return err } - maybeDropStagedMemoryImage(ctx, restoreDir, memMode, preserveRestoreDir) s.publishActorApplication(ctx, p, ra, ctrs) slog.InfoContext(ctx, "Actor restored (overlay rootfs)", From 4d5b97661658e70889ab44ac707a21951ad4cb39 Mon Sep 17 00:00:00 2001 From: Salah Date: Thu, 15 Oct 2026 16:03:24 +0400 Subject: [PATCH 11/12] Test driver metadata refresh during failed resume recovery --- .../controlapi/functionaltest/shared_volume_test.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/cmd/ateapi/internal/controlapi/functionaltest/shared_volume_test.go b/cmd/ateapi/internal/controlapi/functionaltest/shared_volume_test.go index fc810ac75e..57597d8f96 100644 --- a/cmd/ateapi/internal/controlapi/functionaltest/shared_volume_test.go +++ b/cmd/ateapi/internal/controlapi/functionaltest/shared_volume_test.go @@ -566,12 +566,25 @@ func TestSharedVolumeFailedResumeReleasesClaimAfterCleanup(t *testing.T) { worker := createWorkerPod(t, tc, ns, "worker-1", "node1", "pool1") createBorrowingActor(t, tc, "consumer", nil) waitForWorkerAvailable(t, tc, worker) + current := getSharedVolume(t, tc, "data") + current.VolumeContext = map[string]string{"generation": "new-driver-context"} + if _, err := tc.client.UpdateSharedVolume(ctx, &ateapipb.UpdateSharedVolumeRequest{SharedVolume: current}); err != nil { + t.Fatal(err) + } + tc.fakeAtelet.Lock.Lock() tc.fakeAtelet.FailRun = errors.New("injected run failure") tc.fakeAtelet.Lock.Unlock() if _, err := tc.client.ResumeActor(ctx, &ateapipb.ResumeActorRequest{Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "consumer"}}); err == nil { t.Fatal("expected run failure") } + tc.fakeAtelet.Lock.Lock() + mounted := tc.fakeAtelet.RunRequest.GetSpec().GetVolumes()[0].GetExternal().GetVolumeContext()["generation"] + tc.fakeAtelet.Lock.Unlock() + if mounted != "new-driver-context" { + t.Fatalf("mounted stale driver context: %q", mounted) + } + refs := refStates(t, tc, "data") if active, ok := refs["consumer"]; !ok || active { t.Fatalf("want retained inactive reference: %v", refs) From c978b0d853f2187b298eae263e74b6813792dfbf Mon Sep 17 00:00:00 2001 From: Salah Date: Thu, 15 Oct 2026 16:10:11 +0400 Subject: [PATCH 12/12] Fix shared volume test lint and worker terminology --- cmd/ateapi/internal/store/atepg/actor_shared_volumes_test.go | 4 ++-- cmd/ateworker-microvm/run.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/ateapi/internal/store/atepg/actor_shared_volumes_test.go b/cmd/ateapi/internal/store/atepg/actor_shared_volumes_test.go index 171c875a77..2a5dfb8820 100644 --- a/cmd/ateapi/internal/store/atepg/actor_shared_volumes_test.go +++ b/cmd/ateapi/internal/store/atepg/actor_shared_volumes_test.go @@ -30,7 +30,7 @@ func TestCreateActorSharedVolumeTransaction(t *testing.T) { p := setupPostgresPersistence(t) ctx := context.Background() createTestAtespace(t, p, "team") - v, err := p.CreateSharedVolume(ctx, &ateapipb.SharedVolume{Metadata: &ateapipb.ResourceMetadata{Atespace: "team", Name: "data"}, VolumeId: "disk", VolumeType: "mock", Status: &ateapipb.SharedVolumeStatus{State: ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY}}) + _, err := p.CreateSharedVolume(ctx, &ateapipb.SharedVolume{Metadata: &ateapipb.ResourceMetadata{Atespace: "team", Name: "data"}, VolumeId: "disk", VolumeType: "mock", Status: &ateapipb.SharedVolumeStatus{State: ateapipb.SharedVolumeState_SHARED_VOLUME_STATE_READY}}) if err != nil { t.Fatal(err) } @@ -51,7 +51,7 @@ func TestCreateActorSharedVolumeTransaction(t *testing.T) { } } ref := resources.SharedVolumeRef{Atespace: "team", Name: "data"} - v, err = p.GetSharedVolume(ctx, ref) + v, err := p.GetSharedVolume(ctx, ref) if err != nil { t.Fatal(err) } diff --git a/cmd/ateworker-microvm/run.go b/cmd/ateworker-microvm/run.go index c114d9e57c..94b272b76b 100644 --- a/cmd/ateworker-microvm/run.go +++ b/cmd/ateworker-microvm/run.go @@ -227,7 +227,7 @@ func (s *AteWorkerService) resolveRuntime(paths map[string]string) resolvedRunti // - The runtime assets (guest kernel, guest OS image, cloud-hypervisor, virtiofsd) // are on disk and passed as runtime asset paths. // - Each container's bundle holds the overlay spec its rootfs/ is composed -// from. ateom builds the OCI spec itself. +// from. ateworker builds the OCI spec itself. func (s *AteWorkerService) RunWorkload(ctx context.Context, req *ateworkerpb.RunWorkloadRequest) (resp *ateworkerpb.RunWorkloadResponse, retErr error) { if req.GetSpec().GetRuntimeGolden() && req.GetAtespace() != resources.GoldenActorAtespace { return nil, apierror.InvalidArgument("runtime golden capture requires a golden actor")