From eceafa76d617d20ab5cac592a9a6bae2f2ee6dcc Mon Sep 17 00:00:00 2001 From: zoezhao Date: Wed, 2 Sep 2026 16:49:21 -0700 Subject: [PATCH 1/3] Record the SandboxConfigRef in snapshot storage instead of sandbox assets Snapshots used to be self-describing: the manifest written beside the checkpoint images carried the full sandbox asset set (binary URLs, hashes, pause image), and a restore rebuilt the sandbox from whatever the manifest said. That pins a snapshot to raw asset content with no way to tell which SandboxConfig it came from, or to notice that the config has been deleted or re-created since. Make the durable storage objects record a reference to the SandboxConfig Kubernetes object instead: - The snapshot manifest now carries only the SandboxConfig reference (name, UID, resourceVersion) alongside the identity, file list, and scope - never asset content. - Checkpoint reports the reference from the actor's on-node sandbox record (written at Run/Restore with the assets the sandbox actually booted with) in its response, and the pause and suspend finalizers stamp it onto the LocalSnapshotInfo / ActorSnapshot records. A paused-origin suspend takes the reference from LocalSnapshotInfo: no checkpoint runs on that path, and the pause that wrote it got the reference from its own checkpoint response. Every path reaching a finalizer holds a fresh response, since workflow retries re-send the Checkpoint RPC, so the reference never has to survive across invocations. - A resume resolves the restore's assets from the reference recorded on the snapshot whose sandbox runs the guest (the replacement template's golden config for a repointed actor, the golden snapshot's for a DATA_ON_GOLDEN restore, the actor's own snapshot's otherwise), erroring with FailedPrecondition when the object is gone or was re-created under the same name. Snapshots recorded before the reference existed report none and fall back to the pool's config. RestoreRequest therefore now requires sandbox_assets: the manifest is no longer a source of binaries. atelet's node-local flow is otherwise unchanged: Run/Restore write the per-actor on-node record (asset set plus, now, the reference) and Checkpoint/Terminate read it back, so those requests still carry no sandbox config. Checkpoint pins the record's reference into the manifest, and Restore cross-checks the manifest's reference against the request's assets as defense in depth. The update-sandbox-config e2e flow asserts provenance on the snapshots the suspends produce (where restores actually read it), and gains the WorkerPool SandboxConfig override hook it uses to point template B's pool at the copied config. --- benchmarking/locust/common/ateapi_pb2.py | 426 +++---- .../internal/controlapi/sandbox_assets.go | 50 + .../controlapi/sandbox_assets_test.go | 69 + .../controlapi/template_reconciler.go | 5 +- .../internal/controlapi/workflow_pause.go | 44 +- .../controlapi/workflow_pause_test.go | 11 +- .../internal/controlapi/workflow_resume.go | 73 +- .../controlapi/workflow_resume_test.go | 216 ++++ .../internal/controlapi/workflow_suspend.go | 42 +- .../controlapi/workflow_suspend_test.go | 53 +- .../controlapi/zz_generated.validation.go | 132 ++ cmd/atelet/lifecycle_test.go | 188 ++- cmd/atelet/main.go | 204 +-- cmd/atelet/main_test.go | 154 ++- cmd/atelet/metrics.go | 6 +- cmd/atelet/metrics_test.go | 12 +- cmd/atelet/sandbox_assets.go | 94 +- .../suites/demo/updatesandboxconfig_test.go | 277 +++++ internal/e2e/template.go | 7 + internal/proto/ateletpb/atelet.pb.go | 516 +++++--- internal/proto/ateletpb/atelet.proto | 48 +- pkg/proto/ateapipb/ateapi.pb.go | 1105 +++++++++-------- pkg/proto/ateapipb/ateapi.proto | 35 + 23 files changed, 2628 insertions(+), 1139 deletions(-) create mode 100644 internal/e2e/suites/demo/updatesandboxconfig_test.go diff --git a/benchmarking/locust/common/ateapi_pb2.py b/benchmarking/locust/common/ateapi_pb2.py index d6f87e1cd4..db70d2e828 100644 --- a/benchmarking/locust/common/ateapi_pb2.py +++ b/benchmarking/locust/common/ateapi_pb2.py @@ -40,7 +40,7 @@ from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2 -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x61teapi.proto\x12\x06\x61teapi\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x86\x01\n\x11LocalSnapshotInfo\x12\x15\n\rsnapshot_name\x18\x01 \x01(\t\x12%\n\x1dnode_vms_with_local_snapshots\x18\x02 \x03(\t\x12\x33\n\rcontent_scope\x18\x03 \x01(\x0e\x32\x1c.ateapi.SnapshotContentScope\"w\n\x08Selector\x12\x37\n\x0cmatch_labels\x18\x01 \x03(\x0b\x32!.ateapi.Selector.MatchLabelsEntry\x1a\x32\n\x10MatchLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xb2\x01\n\x10ResourceMetadata\x12\x10\n\x08\x61tespace\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0b\n\x03uid\x18\x03 \x01(\t\x12\x0f\n\x07version\x18\x04 \x01(\x03\x12/\n\x0b\x63reate_time\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12/\n\x0bupdate_time\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xdc\x02\n\x0e\x45xternalVolume\x12\x13\n\x0bvolume_name\x18\x01 \x01(\t\x12\x19\n\x11storage_volume_id\x18\x02 \x01(\t\x12\x13\n\x0bvolume_type\x18\x03 \x01(\t\x12-\n\x06status\x18\x04 \x01(\x0e\x32\x1d.ateapi.ExternalVolume.Status\x12\x41\n\x0evolume_context\x18\x05 \x03(\x0b\x32).ateapi.ExternalVolume.VolumeContextEntry\x1a\x34\n\x12VolumeContextEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"]\n\x06Status\x12\x16\n\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\"\xde\x01\n\x05\x41\x63tor\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12)\n\x0e\x61\x63tor_template\x18\x04 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12)\n\x0fworker_selector\x18\x05 \x01(\x0b\x32\x10.ateapi.Selector\x12.\n\x13source_snapshot_tag\x18\x06 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12#\n\x06status\x18\x07 \x01(\x0b\x32\x13.ateapi.ActorStatus\"]\n\x0c\x45gressPolicy\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12!\n\x05rules\x18\x02 \x03(\x0b\x32\x12.ateapi.EgressRule\"\x82\x01\n\nEgressRule\x12\'\n\thostnames\x18\x01 \x01(\x0b\x32\x14.ateapi.HostnameRule\x12&\n\tip_blocks\x18\x02 \x01(\x0b\x32\x13.ateapi.IPBlockRule\x12#\n\x03\x61ll\x18\x03 \x01(\x0b\x32\x16.google.protobuf.Empty\"L\n\x0cHostnameRule\x12\x10\n\x08patterns\x18\x01 \x03(\t\x12*\n\x07\x65\x66\x66\x65\x63ts\x18\x02 \x01(\x0b\x32\x19.ateapi.EgressRuleEffects\"\x1c\n\x0bIPBlockRule\x12\r\n\x05\x63idrs\x18\x01 \x03(\t\"U\n\x11\x45gressRuleEffects\x12@\n\x15inject_static_headers\x18\x01 \x03(\x0b\x32!.ateapi.CredentialHeaderInjection\"S\n\x19\x43redentialHeaderInjection\x12\x0e\n\x06header\x18\x01 \x01(\t\x12\x0e\n\x06prefix\x18\x02 \x01(\t\x12\x16\n\x0e\x63redential_uri\x18\x03 \x01(\t\"\x8a\x04\n\x0b\x41\x63torStatus\x12!\n\x05state\x18\x01 \x01(\x0e\x32\x12.ateapi.ActorState\x12\x33\n\x11worker_assignment\x18\x02 \x01(\x0b\x32\x18.ateapi.WorkerAssignment\x12!\n\x19in_progress_snapshot_name\x18\x03 \x01(\t\x12*\n\x0flatest_snapshot\x18\x04 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x36\n\x13local_snapshot_info\x18\x05 \x01(\x0b\x32\x19.ateapi.LocalSnapshotInfo\x12\x31\n)in_progress_snapshot_source_actor_version\x18\x06 \x01(\x03\x12-\n\ractor_volumes\x18\x07 \x03(\x0b\x32\x16.ateapi.ExternalVolume\x12\'\n\x1fin_progress_local_snapshot_name\x18\x08 \x01(\t\x12:\n\x0fsource_snapshot\x18\t \x01(\x0b\x32!.ateapi.ActorSourceSnapshotStatus\x12\x31\n\x16\x63urrent_actor_template\x18\n \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\"\n\x1a\x63urrent_actor_template_uid\x18\x0b \x01(\t\"V\n\x19\x41\x63torSourceSnapshotStatus\x12#\n\x08snapshot\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x14\n\x0csnapshot_uid\x18\x02 \x01(\t\"\xa7\x01\n\x10WorkerAssignment\x12!\n\x06worker\x18\x06 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x18\n\x10worker_namespace\x18\x01 \x01(\t\x12\x13\n\x0bworker_pool\x18\x02 \x01(\t\x12\x12\n\nworker_pod\x18\x03 \x01(\t\x12\x16\n\x0eworker_pod_uid\x18\x04 \x01(\t\x12\x15\n\rworker_pod_ip\x18\x05 \x01(\t\"h\n\rActorSnapshot\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12+\n\x06status\x18\x02 \x01(\x0b\x32\x1b.ateapi.ActorSnapshotStatus\"\x88\x02\n\x13\x41\x63torSnapshotStatus\x12\'\n\x0csource_actor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x18\n\x10source_actor_uid\x18\x02 \x01(\t\x12\x1c\n\x14source_actor_version\x18\x03 \x01(\x03\x12\x1a\n\x12\x61\x63tor_template_uid\x18\x06 \x01(\t\x12\x33\n\rcontent_scope\x18\x07 \x01(\x0e\x32\x1c.ateapi.SnapshotContentScope\x12\x14\n\x0csnapshot_uri\x18\x08 \x01(\t\x12)\n\x0e\x61\x63tor_template\x18\t \x01(\x0b\x32\x11.ateapi.ObjectRef\"\x91\x01\n\x10\x41\x63torSnapshotTag\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12#\n\x08snapshot\x18\x02 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12,\n\x05scope\x18\x03 \x01(\x0e\x32\x1d.ateapi.ActorSnapshotTagScope\"6\n\x08\x41tespace\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\"+\n\tObjectRef\x12\x10\n\x08\x61tespace\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\"\xe3\x02\n\rActorTemplate\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12)\n\x0fworker_selector\x18\x02 \x01(\x0b\x32\x10.ateapi.Selector\x12%\n\ncontainers\x18\x03 \x03(\x0b\x32\x11.ateapi.Container\x12\x1f\n\x07volumes\x18\x04 \x03(\x0b\x32\x0e.ateapi.Volume\x12\x31\n\x10snapshots_config\x18\x05 \x01(\x0b\x32\x17.ateapi.SnapshotsConfig\x12-\n\x0esandbox_config\x18\x06 \x01(\x0b\x32\x15.ateapi.SandboxConfig\x12$\n\tresources\x18\x07 \x01(\x0b\x32\x11.ateapi.Resources\x12+\n\x06status\x18\x08 \x01(\x0b\x32\x1b.ateapi.ActorTemplateStatus\"+\n\tResources\x12\x1e\n\x06limits\x18\x01 \x03(\x0b\x32\x0e.ateapi.Limits\"(\n\x06Limits\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x10\n\x08quantity\x18\x02 \x01(\t\"\x96\x01\n\x14GoldenSnapshotStatus\x12*\n\x0fgolden_snapshot\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12;\n\x17take_golden_snapshot_at\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x15\n\rerror_message\x18\x03 \x01(\t\"S\n\x13\x41\x63torTemplateStatus\x12<\n\x16golden_snapshot_status\x18\x01 \x01(\x0b\x32\x1c.ateapi.GoldenSnapshotStatus\"Q\n\rSandboxConfig\x12+\n\rsandbox_class\x18\x01 \x01(\x0e\x32\x14.ateapi.SandboxClass\x12\x13\n\x0b\x63onfig_name\x18\x02 \x01(\t\"\xb7\x01\n\x0fSnapshotsConfig\x12.\n\x08on_pause\x18\x01 \x01(\x0e\x32\x1c.ateapi.SnapshotContentScope\x12/\n\ton_commit\x18\x02 \x01(\x0e\x32\x1c.ateapi.SnapshotContentScope\x12)\n\ton_resume\x18\x03 \x01(\x0b\x32\x16.ateapi.OnResumeConfig\x12\x18\n\x10storage_location\x18\x04 \x01(\t\"9\n\x0eOnResumeConfig\x12\'\n\tfrom_data\x18\x01 \x01(\x0e\x32\x14.ateapi.ResumeSource\"\x92\x02\n\tContainer\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05image\x18\x02 \x01(\t\x12\x0f\n\x07\x63ommand\x18\x03 \x03(\t\x12\x0c\n\x04\x61rgs\x18\x04 \x03(\t\x12\x1b\n\x03\x65nv\x18\x05 \x03(\x0b\x32\x0e.ateapi.EnvVar\x12\'\n\x06readyz\x18\x06 \x01(\x0b\x32\x17.ateapi.ContainerReadyz\x12*\n\rvolume_mounts\x18\x07 \x03(\x0b\x32\x13.ateapi.VolumeMount\x12\x31\n\x10security_context\x18\x08 \x01(\x0b\x32\x17.ateapi.SecurityContext\x12$\n\tresources\x18\t \x01(\x0b\x32\x11.ateapi.Resources\"=\n\x0fSecurityContext\x12*\n\x0c\x63\x61pabilities\x18\x01 \x01(\x0b\x32\x14.ateapi.Capabilities\")\n\x0c\x43\x61pabilities\x12\x0b\n\x03\x61\x64\x64\x18\x01 \x03(\t\x12\x0c\n\x04\x64rop\x18\x02 \x03(\t\"%\n\x06\x45nvVar\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"S\n\x0f\x43ontainerReadyz\x12\'\n\x08http_get\x18\x01 \x01(\x0b\x32\x15.ateapi.HTTPGetAction\x12\x17\n\x0ftimeout_seconds\x18\x02 \x01(\x05\"+\n\rHTTPGetAction\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\"\xec\x01\n\x06Volume\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x33\n\x0b\x64urable_dir\x18\x02 \x01(\x0b\x32\x1e.ateapi.DurableDirVolumeSource\x12@\n\x18\x65xternal_volume_template\x18\x03 \x01(\x0b\x32\x1e.ateapi.ExternalVolumeTemplate\x12\x33\n\x0bsystem_info\x18\x05 \x01(\x0b\x32\x1e.ateapi.SystemInfoVolumeSource\x12(\n\x05image\x18\x06 \x01(\x0b\x32\x19.ateapi.ImageVolumeSource\"&\n\x11ImageVolumeSource\x12\x11\n\treference\x18\x01 \x01(\t\"\x18\n\x16\x44urableDirVolumeSource\"F\n\x16\x45xternalVolumeTemplate\x12\x10\n\x08\x63\x61pacity\x18\x01 \x01(\t\x12\x1a\n\x12storage_class_name\x18\x02 \x01(\t\"L\n\x16SystemInfoVolumeSource\x12\x32\n\x0c\x64\x61ta_sources\x18\x01 \x03(\x0b\x32\x1c.ateapi.SystemInfoDataSource\"\x84\x01\n\x14SystemInfoDataSource\x12\x37\n\x0e\x61\x63tor_metadata\x18\x01 \x01(\x0b\x32\x1f.ateapi.ActorMetadataDataSource\x12\x33\n\x0ctrust_bundle\x18\x02 \x01(\x0b\x32\x1d.ateapi.TrustBundleDataSource\"C\n\x17\x41\x63torMetadataDataSource\x12(\n\x05items\x18\x01 \x03(\x0b\x32\x19.ateapi.ActorMetadataItem\"L\n\x11\x41\x63torMetadataItem\x12)\n\x05\x66ield\x18\x01 \x01(\x0e\x32\x1a.ateapi.ActorMetadataField\x12\x0c\n\x04path\x18\x02 \x01(\t\"3\n\x15TrustBundleDataSource\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\t\"/\n\x0bVolumeMount\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\nmount_path\x18\x02 \x01(\t\";\n\x15\x43reateAtespaceRequest\x12\"\n\x08\x61tespace\x18\x01 \x01(\x0b\x32\x10.ateapi.Atespace\"9\n\x12GetAtespaceRequest\x12#\n\x08\x61tespace\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"=\n\x14ListAtespacesRequest\x12\x11\n\tpage_size\x18\x01 \x01(\x05\x12\x12\n\npage_token\x18\x02 \x01(\t\"U\n\x15ListAtespacesResponse\x12#\n\tatespaces\x18\x01 \x03(\x0b\x32\x10.ateapi.Atespace\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"<\n\x15\x44\x65leteAtespaceRequest\x12#\n\x08\x61tespace\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"K\n\x1a\x43reateActorTemplateRequest\x12-\n\x0e\x61\x63tor_template\x18\x01 \x01(\x0b\x32\x15.ateapi.ActorTemplate\"D\n\x17GetActorTemplateRequest\x12)\n\x0e\x61\x63tor_template\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"T\n\x19ListActorTemplatesRequest\x12\x10\n\x08\x61tespace\x18\x01 \x01(\t\x12\x11\n\tpage_size\x18\x02 \x01(\x05\x12\x12\n\npage_token\x18\x03 \x01(\t\"e\n\x1aListActorTemplatesResponse\x12.\n\x0f\x61\x63tor_templates\x18\x01 \x03(\x0b\x32\x15.ateapi.ActorTemplate\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"G\n\x1a\x44\x65leteActorTemplateRequest\x12)\n\x0e\x61\x63tor_template\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"3\n\x0fGetActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"2\n\x12\x43reateActorRequest\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"2\n\x12UpdateActorRequest\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"7\n\x13SuspendActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"4\n\x14SuspendActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"5\n\x11PauseActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"2\n\x12PauseActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"D\n\x12ResumeActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x0c\n\x04\x62oot\x18\x02 \x01(\x08\"D\n\x13ResumeActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\x12\x0f\n\x07resumed\x18\x02 \x01(\x08\"I\n\x12\x44\x65leteActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x11\n\tany_state\x18\x02 \x01(\x08\"?\n\x1bGetActorEgressPolicyRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"o\n\x1e\x43reateActorEgressPolicyRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12+\n\regress_policy\x18\x02 \x01(\x0b\x32\x14.ateapi.EgressPolicy\"o\n\x1eUpdateActorEgressPolicyRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12+\n\regress_policy\x18\x02 \x01(\x0b\x32\x14.ateapi.EgressPolicy\"B\n\x1e\x44\x65leteActorEgressPolicyRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"D\n\x17GetActorSnapshotRequest\x12)\n\x0e\x61\x63tor_snapshot\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"K\n\x1aGetActorSnapshotTagRequest\x12-\n\x12\x61\x63tor_snapshot_tag\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"T\n\x19ListActorSnapshotsRequest\x12\x10\n\x08\x61tespace\x18\x01 \x01(\t\x12\x11\n\tpage_size\x18\x02 \x01(\x05\x12\x12\n\npage_token\x18\x03 \x01(\t\"e\n\x1aListActorSnapshotsResponse\x12.\n\x0f\x61\x63tor_snapshots\x18\x01 \x03(\x0b\x32\x15.ateapi.ActorSnapshot\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"U\n\x1d\x43reateActorSnapshotTagRequest\x12\x34\n\x12\x61\x63tor_snapshot_tag\x18\x01 \x01(\x0b\x32\x18.ateapi.ActorSnapshotTag\"U\n\x1dUpdateActorSnapshotTagRequest\x12\x34\n\x12\x61\x63tor_snapshot_tag\x18\x01 \x01(\x0b\x32\x18.ateapi.ActorSnapshotTag\"N\n\x1d\x44\x65leteActorSnapshotTagRequest\x12-\n\x12\x61\x63tor_snapshot_tag\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"-\n\rDeleteOptions\x12\x0f\n\x07version\x18\x01 \x01(\x03\x12\x0b\n\x03uid\x18\x02 \x01(\t\";\n\x12ListWorkersRequest\x12\x11\n\tpage_size\x18\x01 \x01(\x05\x12\x12\n\npage_token\x18\x02 \x01(\t\"O\n\x13ListWorkersResponse\x12\x1f\n\x07workers\x18\x01 \x03(\x0b\x32\x0e.ateapi.Worker\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"5\n\x10GetWorkerRequest\x12!\n\x06worker\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"5\n\x13\x43reateWorkerRequest\x12\x1e\n\x06worker\x18\x01 \x01(\x0b\x32\x0e.ateapi.Worker\"5\n\x13UpdateWorkerRequest\x12\x1e\n\x06worker\x18\x01 \x01(\x0b\x32\x0e.ateapi.Worker\"`\n\x13\x44\x65leteWorkerRequest\x12!\n\x06worker\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12&\n\x07options\x18\x02 \x01(\x0b\x32\x15.ateapi.DeleteOptions\"7\n\x12\x44rainWorkerRequest\x12!\n\x06worker\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"L\n\x11ListActorsRequest\x12\x10\n\x08\x61tespace\x18\x01 \x01(\t\x12\x11\n\tpage_size\x18\x02 \x01(\x05\x12\x12\n\npage_token\x18\x03 \x01(\t\"L\n\x12ListActorsResponse\x12\x1d\n\x06\x61\x63tors\x18\x01 \x03(\x0b\x32\r.ateapi.Actor\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"\xf0\x02\n\x06Worker\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12\x18\n\x10worker_namespace\x18\x02 \x01(\t\x12\x13\n\x0bworker_pool\x18\x03 \x01(\t\x12\x12\n\nworker_pod\x18\x04 \x01(\t\x12\x16\n\x0eworker_pod_uid\x18\x05 \x01(\t\x12\x11\n\tnode_name\x18\x06 \x01(\t\x12\n\n\x02ip\x18\x07 \x01(\t\x12\x15\n\rsandbox_class\x18\x08 \x01(\t\x12*\n\x06labels\x18\t \x03(\x0b\x32\x1a.ateapi.Worker.LabelsEntry\x12(\n\x08\x63\x61pacity\x18\n \x01(\x0b\x32\x16.ateapi.WorkerCapacity\x12$\n\x06status\x18\x0b \x01(\x0b\x32\x14.ateapi.WorkerStatus\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"_\n\x0cWorkerStatus\x12\"\n\x05state\x18\x01 \x01(\x0e\x32\x13.ateapi.WorkerState\x12+\n\nassignment\x18\x02 \x01(\x0b\x32\x17.ateapi.ActorAssignment\"9\n\x0eWorkerCapacity\x12\x11\n\tcpu_milli\x18\x01 \x01(\x03\x12\x14\n\x0cmemory_bytes\x18\x02 \x01(\x03\"u\n\x0f\x41\x63torAssignment\x12 \n\x05\x61\x63tor\x18\x02 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x11\n\tactor_uid\x18\x03 \x01(\t\x12-\n\x12\x61\x63tor_template_ref\x18\x04 \x01(\x0b\x32\x11.ateapi.ObjectRef\"[\n\x0eMintJWTRequest\x12\x10\n\x08\x61udience\x18\x01 \x03(\t\x12\x10\n\x08\x61tespace\x18\x02 \x01(\t\x12\x12\n\nactor_name\x18\x03 \x01(\t\x12\x11\n\tactor_uid\x18\x04 \x01(\t\"$\n\x0fMintJWTResponse\x12\x11\n\tactor_jwt\x18\x01 \x01(\t\"\xa7\x01\n\x0fMintCertRequest\x12!\n\x06worker\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12#\n\x1b\x63\x65rtificate_signing_request\x18\x02 \x01(\x0c\x12\x1a\n\x12\x65xpected_actor_uid\x18\x03 \x01(\t\x12\x30\n\x07purpose\x18\x04 \x01(\x0e\x32\x1f.ateapi.ActorCertificatePurpose\".\n\x10MintCertResponse\x12\x1a\n\x12\x61\x63tor_certificates\x18\x01 \x03(\x0c*\x80\x01\n\x14SnapshotContentScope\x12&\n\"SNAPSHOT_CONTENT_SCOPE_UNSPECIFIED\x10\x00\x12\x1f\n\x1bSNAPSHOT_CONTENT_SCOPE_FULL\x10\x01\x12\x1f\n\x1bSNAPSHOT_CONTENT_SCOPE_DATA\x10\x02*\x90\x01\n\x15\x41\x63torSnapshotTagScope\x12(\n$ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED\x10\x00\x12%\n!ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE\x10\x01\x12&\n\"ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED\x10\x02*\xf7\x01\n\nActorState\x12\x1b\n\x17\x41\x43TOR_STATE_UNSPECIFIED\x10\x00\x12\x18\n\x14\x41\x43TOR_STATE_RESUMING\x10\x01\x12\x17\n\x13\x41\x43TOR_STATE_RUNNING\x10\x02\x12\x1a\n\x16\x41\x43TOR_STATE_SUSPENDING\x10\x03\x12\x19\n\x15\x41\x43TOR_STATE_SUSPENDED\x10\x04\x12\x17\n\x13\x41\x43TOR_STATE_PAUSING\x10\x05\x12\x16\n\x12\x41\x43TOR_STATE_PAUSED\x10\x06\x12\x17\n\x13\x41\x43TOR_STATE_CRASHED\x10\x07\x12\x18\n\x14\x41\x43TOR_STATE_DELETING\x10\x08*b\n\x0cSandboxClass\x12\x1d\n\x19SANDBOX_CLASS_UNSPECIFIED\x10\x00\x12\x18\n\x14SANDBOX_CLASS_GVISOR\x10\x01\x12\x19\n\x15SANDBOX_CLASS_MICROVM\x10\x02*d\n\x0cResumeSource\x12\x1d\n\x19RESUME_SOURCE_UNSPECIFIED\x10\x00\x12\x1b\n\x17RESUME_SOURCE_COLD_BOOT\x10\x01\x12\x18\n\x14RESUME_SOURCE_GOLDEN\x10\x02*\x9a\x01\n\x12\x41\x63torMetadataField\x12$\n ACTOR_METADATA_FIELD_UNSPECIFIED\x10\x00\x12\x1d\n\x19\x41\x43TOR_METADATA_FIELD_NAME\x10\x01\x12!\n\x1d\x41\x43TOR_METADATA_FIELD_ATESPACE\x10\x02\x12\x1c\n\x18\x41\x43TOR_METADATA_FIELD_UID\x10\x03*_\n\x0bWorkerState\x12\x1c\n\x18WORKER_STATE_UNSPECIFIED\x10\x00\x12\x17\n\x13WORKER_STATE_ACTIVE\x10\x01\x12\x19\n\x15WORKER_STATE_DRAINING\x10\x02*k\n\x17\x41\x63torCertificatePurpose\x12)\n%ACTOR_CERTIFICATE_PURPOSE_UNSPECIFIED\x10\x00\x12%\n!ACTOR_CERTIFICATE_PURPOSE_ATUNNEL\x10\x01\x32\x84\x13\n\x07\x43ontrol\x12\x34\n\x08GetActor\x12\x17.ateapi.GetActorRequest\x1a\r.ateapi.Actor\"\x00\x12:\n\x0b\x43reateActor\x12\x1a.ateapi.CreateActorRequest\x1a\r.ateapi.Actor\"\x00\x12:\n\x0bUpdateActor\x12\x1a.ateapi.UpdateActorRequest\x1a\r.ateapi.Actor\"\x00\x12K\n\x0cSuspendActor\x12\x1b.ateapi.SuspendActorRequest\x1a\x1c.ateapi.SuspendActorResponse\"\x00\x12\x45\n\nPauseActor\x12\x19.ateapi.PauseActorRequest\x1a\x1a.ateapi.PauseActorResponse\"\x00\x12H\n\x0bResumeActor\x12\x1a.ateapi.ResumeActorRequest\x1a\x1b.ateapi.ResumeActorResponse\"\x00\x12:\n\x0b\x44\x65leteActor\x12\x1a.ateapi.DeleteActorRequest\x1a\r.ateapi.Actor\"\x00\x12S\n\x14GetActorEgressPolicy\x12#.ateapi.GetActorEgressPolicyRequest\x1a\x14.ateapi.EgressPolicy\"\x00\x12Y\n\x17\x43reateActorEgressPolicy\x12&.ateapi.CreateActorEgressPolicyRequest\x1a\x14.ateapi.EgressPolicy\"\x00\x12Y\n\x17UpdateActorEgressPolicy\x12&.ateapi.UpdateActorEgressPolicyRequest\x1a\x14.ateapi.EgressPolicy\"\x00\x12Y\n\x17\x44\x65leteActorEgressPolicy\x12&.ateapi.DeleteActorEgressPolicyRequest\x1a\x14.ateapi.EgressPolicy\"\x00\x12L\n\x10GetActorSnapshot\x12\x1f.ateapi.GetActorSnapshotRequest\x1a\x15.ateapi.ActorSnapshot\"\x00\x12U\n\x13GetActorSnapshotTag\x12\".ateapi.GetActorSnapshotTagRequest\x1a\x18.ateapi.ActorSnapshotTag\"\x00\x12]\n\x12ListActorSnapshots\x12!.ateapi.ListActorSnapshotsRequest\x1a\".ateapi.ListActorSnapshotsResponse\"\x00\x12[\n\x16\x43reateActorSnapshotTag\x12%.ateapi.CreateActorSnapshotTagRequest\x1a\x18.ateapi.ActorSnapshotTag\"\x00\x12[\n\x16UpdateActorSnapshotTag\x12%.ateapi.UpdateActorSnapshotTagRequest\x1a\x18.ateapi.ActorSnapshotTag\"\x00\x12[\n\x16\x44\x65leteActorSnapshotTag\x12%.ateapi.DeleteActorSnapshotTagRequest\x1a\x18.ateapi.ActorSnapshotTag\"\x00\x12H\n\x0bListWorkers\x12\x1a.ateapi.ListWorkersRequest\x1a\x1b.ateapi.ListWorkersResponse\"\x00\x12\x37\n\tGetWorker\x12\x18.ateapi.GetWorkerRequest\x1a\x0e.ateapi.Worker\"\x00\x12=\n\x0c\x43reateWorker\x12\x1b.ateapi.CreateWorkerRequest\x1a\x0e.ateapi.Worker\"\x00\x12=\n\x0cUpdateWorker\x12\x1b.ateapi.UpdateWorkerRequest\x1a\x0e.ateapi.Worker\"\x00\x12=\n\x0c\x44\x65leteWorker\x12\x1b.ateapi.DeleteWorkerRequest\x1a\x0e.ateapi.Worker\"\x00\x12;\n\x0b\x44rainWorker\x12\x1a.ateapi.DrainWorkerRequest\x1a\x0e.ateapi.Worker\"\x00\x12\x45\n\nListActors\x12\x19.ateapi.ListActorsRequest\x1a\x1a.ateapi.ListActorsResponse\"\x00\x12\x43\n\x0e\x43reateAtespace\x12\x1d.ateapi.CreateAtespaceRequest\x1a\x10.ateapi.Atespace\"\x00\x12=\n\x0bGetAtespace\x12\x1a.ateapi.GetAtespaceRequest\x1a\x10.ateapi.Atespace\"\x00\x12N\n\rListAtespaces\x12\x1c.ateapi.ListAtespacesRequest\x1a\x1d.ateapi.ListAtespacesResponse\"\x00\x12\x43\n\x0e\x44\x65leteAtespace\x12\x1d.ateapi.DeleteAtespaceRequest\x1a\x10.ateapi.Atespace\"\x00\x12R\n\x13\x43reateActorTemplate\x12\".ateapi.CreateActorTemplateRequest\x1a\x15.ateapi.ActorTemplate\"\x00\x12L\n\x10GetActorTemplate\x12\x1f.ateapi.GetActorTemplateRequest\x1a\x15.ateapi.ActorTemplate\"\x00\x12]\n\x12ListActorTemplates\x12!.ateapi.ListActorTemplatesRequest\x1a\".ateapi.ListActorTemplatesResponse\"\x00\x12R\n\x13\x44\x65leteActorTemplate\x12\".ateapi.DeleteActorTemplateRequest\x1a\x15.ateapi.ActorTemplate\"\x00\x32\x8a\x01\n\rActorIdentity\x12:\n\x07MintJWT\x12\x16.ateapi.MintJWTRequest\x1a\x17.ateapi.MintJWTResponse\x12=\n\x08MintCert\x12\x17.ateapi.MintCertRequest\x1a\x18.ateapi.MintCertResponseB9Z7github.com/agent-substrate/substrate/pkg/proto/ateapipbb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x61teapi.proto\x12\x06\x61teapi\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xbc\x01\n\x11LocalSnapshotInfo\x12\x15\n\rsnapshot_name\x18\x01 \x01(\t\x12%\n\x1dnode_vms_with_local_snapshots\x18\x02 \x03(\t\x12\x33\n\rcontent_scope\x18\x03 \x01(\x0e\x32\x1c.ateapi.SnapshotContentScope\x12\x34\n\x12sandbox_config_ref\x18\x04 \x01(\x0b\x32\x18.ateapi.SandboxConfigRef\"w\n\x08Selector\x12\x37\n\x0cmatch_labels\x18\x01 \x03(\x0b\x32!.ateapi.Selector.MatchLabelsEntry\x1a\x32\n\x10MatchLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xb2\x01\n\x10ResourceMetadata\x12\x10\n\x08\x61tespace\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0b\n\x03uid\x18\x03 \x01(\t\x12\x0f\n\x07version\x18\x04 \x01(\x03\x12/\n\x0b\x63reate_time\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12/\n\x0bupdate_time\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"\xdc\x02\n\x0e\x45xternalVolume\x12\x13\n\x0bvolume_name\x18\x01 \x01(\t\x12\x19\n\x11storage_volume_id\x18\x02 \x01(\t\x12\x13\n\x0bvolume_type\x18\x03 \x01(\t\x12-\n\x06status\x18\x04 \x01(\x0e\x32\x1d.ateapi.ExternalVolume.Status\x12\x41\n\x0evolume_context\x18\x05 \x03(\x0b\x32).ateapi.ExternalVolume.VolumeContextEntry\x1a\x34\n\x12VolumeContextEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"]\n\x06Status\x12\x16\n\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\"\xde\x01\n\x05\x41\x63tor\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12)\n\x0e\x61\x63tor_template\x18\x04 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12)\n\x0fworker_selector\x18\x05 \x01(\x0b\x32\x10.ateapi.Selector\x12.\n\x13source_snapshot_tag\x18\x06 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12#\n\x06status\x18\x07 \x01(\x0b\x32\x13.ateapi.ActorStatus\"]\n\x0c\x45gressPolicy\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12!\n\x05rules\x18\x02 \x03(\x0b\x32\x12.ateapi.EgressRule\"\x82\x01\n\nEgressRule\x12\'\n\thostnames\x18\x01 \x01(\x0b\x32\x14.ateapi.HostnameRule\x12&\n\tip_blocks\x18\x02 \x01(\x0b\x32\x13.ateapi.IPBlockRule\x12#\n\x03\x61ll\x18\x03 \x01(\x0b\x32\x16.google.protobuf.Empty\"L\n\x0cHostnameRule\x12\x10\n\x08patterns\x18\x01 \x03(\t\x12*\n\x07\x65\x66\x66\x65\x63ts\x18\x02 \x01(\x0b\x32\x19.ateapi.EgressRuleEffects\"\x1c\n\x0bIPBlockRule\x12\r\n\x05\x63idrs\x18\x01 \x03(\t\"U\n\x11\x45gressRuleEffects\x12@\n\x15inject_static_headers\x18\x01 \x03(\x0b\x32!.ateapi.CredentialHeaderInjection\"S\n\x19\x43redentialHeaderInjection\x12\x0e\n\x06header\x18\x01 \x01(\t\x12\x0e\n\x06prefix\x18\x02 \x01(\t\x12\x16\n\x0e\x63redential_uri\x18\x03 \x01(\t\"\x8a\x04\n\x0b\x41\x63torStatus\x12!\n\x05state\x18\x01 \x01(\x0e\x32\x12.ateapi.ActorState\x12\x33\n\x11worker_assignment\x18\x02 \x01(\x0b\x32\x18.ateapi.WorkerAssignment\x12!\n\x19in_progress_snapshot_name\x18\x03 \x01(\t\x12*\n\x0flatest_snapshot\x18\x04 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x36\n\x13local_snapshot_info\x18\x05 \x01(\x0b\x32\x19.ateapi.LocalSnapshotInfo\x12\x31\n)in_progress_snapshot_source_actor_version\x18\x06 \x01(\x03\x12-\n\ractor_volumes\x18\x07 \x03(\x0b\x32\x16.ateapi.ExternalVolume\x12\'\n\x1fin_progress_local_snapshot_name\x18\x08 \x01(\t\x12:\n\x0fsource_snapshot\x18\t \x01(\x0b\x32!.ateapi.ActorSourceSnapshotStatus\x12\x31\n\x16\x63urrent_actor_template\x18\n \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\"\n\x1a\x63urrent_actor_template_uid\x18\x0b \x01(\t\"V\n\x19\x41\x63torSourceSnapshotStatus\x12#\n\x08snapshot\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x14\n\x0csnapshot_uid\x18\x02 \x01(\t\"\xa7\x01\n\x10WorkerAssignment\x12!\n\x06worker\x18\x06 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x18\n\x10worker_namespace\x18\x01 \x01(\t\x12\x13\n\x0bworker_pool\x18\x02 \x01(\t\x12\x12\n\nworker_pod\x18\x03 \x01(\t\x12\x16\n\x0eworker_pod_uid\x18\x04 \x01(\t\x12\x15\n\rworker_pod_ip\x18\x05 \x01(\t\"h\n\rActorSnapshot\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12+\n\x06status\x18\x02 \x01(\x0b\x32\x1b.ateapi.ActorSnapshotStatus\"\xbe\x02\n\x13\x41\x63torSnapshotStatus\x12\'\n\x0csource_actor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x18\n\x10source_actor_uid\x18\x02 \x01(\t\x12\x1c\n\x14source_actor_version\x18\x03 \x01(\x03\x12\x1a\n\x12\x61\x63tor_template_uid\x18\x06 \x01(\t\x12\x33\n\rcontent_scope\x18\x07 \x01(\x0e\x32\x1c.ateapi.SnapshotContentScope\x12\x14\n\x0csnapshot_uri\x18\x08 \x01(\t\x12)\n\x0e\x61\x63tor_template\x18\t \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x34\n\x12sandbox_config_ref\x18\n \x01(\x0b\x32\x18.ateapi.SandboxConfigRef\"\x91\x01\n\x10\x41\x63torSnapshotTag\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12#\n\x08snapshot\x18\x02 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12,\n\x05scope\x18\x03 \x01(\x0e\x32\x1d.ateapi.ActorSnapshotTagScope\"6\n\x08\x41tespace\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\"+\n\tObjectRef\x12\x10\n\x08\x61tespace\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\"G\n\x10SandboxConfigRef\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0b\n\x03uid\x18\x02 \x01(\t\x12\x18\n\x10resource_version\x18\x03 \x01(\t\"\xe3\x02\n\rActorTemplate\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12)\n\x0fworker_selector\x18\x02 \x01(\x0b\x32\x10.ateapi.Selector\x12%\n\ncontainers\x18\x03 \x03(\x0b\x32\x11.ateapi.Container\x12\x1f\n\x07volumes\x18\x04 \x03(\x0b\x32\x0e.ateapi.Volume\x12\x31\n\x10snapshots_config\x18\x05 \x01(\x0b\x32\x17.ateapi.SnapshotsConfig\x12-\n\x0esandbox_config\x18\x06 \x01(\x0b\x32\x15.ateapi.SandboxConfig\x12$\n\tresources\x18\x07 \x01(\x0b\x32\x11.ateapi.Resources\x12+\n\x06status\x18\x08 \x01(\x0b\x32\x1b.ateapi.ActorTemplateStatus\"+\n\tResources\x12\x1e\n\x06limits\x18\x01 \x03(\x0b\x32\x0e.ateapi.Limits\"(\n\x06Limits\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x10\n\x08quantity\x18\x02 \x01(\t\"\x96\x01\n\x14GoldenSnapshotStatus\x12*\n\x0fgolden_snapshot\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12;\n\x17take_golden_snapshot_at\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x15\n\rerror_message\x18\x03 \x01(\t\"S\n\x13\x41\x63torTemplateStatus\x12<\n\x16golden_snapshot_status\x18\x01 \x01(\x0b\x32\x1c.ateapi.GoldenSnapshotStatus\"Q\n\rSandboxConfig\x12+\n\rsandbox_class\x18\x01 \x01(\x0e\x32\x14.ateapi.SandboxClass\x12\x13\n\x0b\x63onfig_name\x18\x02 \x01(\t\"\xb7\x01\n\x0fSnapshotsConfig\x12.\n\x08on_pause\x18\x01 \x01(\x0e\x32\x1c.ateapi.SnapshotContentScope\x12/\n\ton_commit\x18\x02 \x01(\x0e\x32\x1c.ateapi.SnapshotContentScope\x12)\n\ton_resume\x18\x03 \x01(\x0b\x32\x16.ateapi.OnResumeConfig\x12\x18\n\x10storage_location\x18\x04 \x01(\t\"9\n\x0eOnResumeConfig\x12\'\n\tfrom_data\x18\x01 \x01(\x0e\x32\x14.ateapi.ResumeSource\"\x92\x02\n\tContainer\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05image\x18\x02 \x01(\t\x12\x0f\n\x07\x63ommand\x18\x03 \x03(\t\x12\x0c\n\x04\x61rgs\x18\x04 \x03(\t\x12\x1b\n\x03\x65nv\x18\x05 \x03(\x0b\x32\x0e.ateapi.EnvVar\x12\'\n\x06readyz\x18\x06 \x01(\x0b\x32\x17.ateapi.ContainerReadyz\x12*\n\rvolume_mounts\x18\x07 \x03(\x0b\x32\x13.ateapi.VolumeMount\x12\x31\n\x10security_context\x18\x08 \x01(\x0b\x32\x17.ateapi.SecurityContext\x12$\n\tresources\x18\t \x01(\x0b\x32\x11.ateapi.Resources\"=\n\x0fSecurityContext\x12*\n\x0c\x63\x61pabilities\x18\x01 \x01(\x0b\x32\x14.ateapi.Capabilities\")\n\x0c\x43\x61pabilities\x12\x0b\n\x03\x61\x64\x64\x18\x01 \x03(\t\x12\x0c\n\x04\x64rop\x18\x02 \x03(\t\"%\n\x06\x45nvVar\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"S\n\x0f\x43ontainerReadyz\x12\'\n\x08http_get\x18\x01 \x01(\x0b\x32\x15.ateapi.HTTPGetAction\x12\x17\n\x0ftimeout_seconds\x18\x02 \x01(\x05\"+\n\rHTTPGetAction\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x0c\n\x04port\x18\x02 \x01(\x05\"\xec\x01\n\x06Volume\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x33\n\x0b\x64urable_dir\x18\x02 \x01(\x0b\x32\x1e.ateapi.DurableDirVolumeSource\x12@\n\x18\x65xternal_volume_template\x18\x03 \x01(\x0b\x32\x1e.ateapi.ExternalVolumeTemplate\x12\x33\n\x0bsystem_info\x18\x05 \x01(\x0b\x32\x1e.ateapi.SystemInfoVolumeSource\x12(\n\x05image\x18\x06 \x01(\x0b\x32\x19.ateapi.ImageVolumeSource\"&\n\x11ImageVolumeSource\x12\x11\n\treference\x18\x01 \x01(\t\"\x18\n\x16\x44urableDirVolumeSource\"F\n\x16\x45xternalVolumeTemplate\x12\x10\n\x08\x63\x61pacity\x18\x01 \x01(\t\x12\x1a\n\x12storage_class_name\x18\x02 \x01(\t\"L\n\x16SystemInfoVolumeSource\x12\x32\n\x0c\x64\x61ta_sources\x18\x01 \x03(\x0b\x32\x1c.ateapi.SystemInfoDataSource\"\x84\x01\n\x14SystemInfoDataSource\x12\x37\n\x0e\x61\x63tor_metadata\x18\x01 \x01(\x0b\x32\x1f.ateapi.ActorMetadataDataSource\x12\x33\n\x0ctrust_bundle\x18\x02 \x01(\x0b\x32\x1d.ateapi.TrustBundleDataSource\"C\n\x17\x41\x63torMetadataDataSource\x12(\n\x05items\x18\x01 \x03(\x0b\x32\x19.ateapi.ActorMetadataItem\"L\n\x11\x41\x63torMetadataItem\x12)\n\x05\x66ield\x18\x01 \x01(\x0e\x32\x1a.ateapi.ActorMetadataField\x12\x0c\n\x04path\x18\x02 \x01(\t\"3\n\x15TrustBundleDataSource\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\t\"/\n\x0bVolumeMount\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\nmount_path\x18\x02 \x01(\t\";\n\x15\x43reateAtespaceRequest\x12\"\n\x08\x61tespace\x18\x01 \x01(\x0b\x32\x10.ateapi.Atespace\"9\n\x12GetAtespaceRequest\x12#\n\x08\x61tespace\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"=\n\x14ListAtespacesRequest\x12\x11\n\tpage_size\x18\x01 \x01(\x05\x12\x12\n\npage_token\x18\x02 \x01(\t\"U\n\x15ListAtespacesResponse\x12#\n\tatespaces\x18\x01 \x03(\x0b\x32\x10.ateapi.Atespace\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"<\n\x15\x44\x65leteAtespaceRequest\x12#\n\x08\x61tespace\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"K\n\x1a\x43reateActorTemplateRequest\x12-\n\x0e\x61\x63tor_template\x18\x01 \x01(\x0b\x32\x15.ateapi.ActorTemplate\"D\n\x17GetActorTemplateRequest\x12)\n\x0e\x61\x63tor_template\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"T\n\x19ListActorTemplatesRequest\x12\x10\n\x08\x61tespace\x18\x01 \x01(\t\x12\x11\n\tpage_size\x18\x02 \x01(\x05\x12\x12\n\npage_token\x18\x03 \x01(\t\"e\n\x1aListActorTemplatesResponse\x12.\n\x0f\x61\x63tor_templates\x18\x01 \x03(\x0b\x32\x15.ateapi.ActorTemplate\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"G\n\x1a\x44\x65leteActorTemplateRequest\x12)\n\x0e\x61\x63tor_template\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"3\n\x0fGetActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"2\n\x12\x43reateActorRequest\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"2\n\x12UpdateActorRequest\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"7\n\x13SuspendActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"4\n\x14SuspendActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"5\n\x11PauseActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"2\n\x12PauseActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"D\n\x12ResumeActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x0c\n\x04\x62oot\x18\x02 \x01(\x08\"D\n\x13ResumeActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\x12\x0f\n\x07resumed\x18\x02 \x01(\x08\"I\n\x12\x44\x65leteActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x11\n\tany_state\x18\x02 \x01(\x08\"?\n\x1bGetActorEgressPolicyRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"o\n\x1e\x43reateActorEgressPolicyRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12+\n\regress_policy\x18\x02 \x01(\x0b\x32\x14.ateapi.EgressPolicy\"o\n\x1eUpdateActorEgressPolicyRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12+\n\regress_policy\x18\x02 \x01(\x0b\x32\x14.ateapi.EgressPolicy\"B\n\x1e\x44\x65leteActorEgressPolicyRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"D\n\x17GetActorSnapshotRequest\x12)\n\x0e\x61\x63tor_snapshot\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"K\n\x1aGetActorSnapshotTagRequest\x12-\n\x12\x61\x63tor_snapshot_tag\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"T\n\x19ListActorSnapshotsRequest\x12\x10\n\x08\x61tespace\x18\x01 \x01(\t\x12\x11\n\tpage_size\x18\x02 \x01(\x05\x12\x12\n\npage_token\x18\x03 \x01(\t\"e\n\x1aListActorSnapshotsResponse\x12.\n\x0f\x61\x63tor_snapshots\x18\x01 \x03(\x0b\x32\x15.ateapi.ActorSnapshot\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"U\n\x1d\x43reateActorSnapshotTagRequest\x12\x34\n\x12\x61\x63tor_snapshot_tag\x18\x01 \x01(\x0b\x32\x18.ateapi.ActorSnapshotTag\"U\n\x1dUpdateActorSnapshotTagRequest\x12\x34\n\x12\x61\x63tor_snapshot_tag\x18\x01 \x01(\x0b\x32\x18.ateapi.ActorSnapshotTag\"N\n\x1d\x44\x65leteActorSnapshotTagRequest\x12-\n\x12\x61\x63tor_snapshot_tag\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"-\n\rDeleteOptions\x12\x0f\n\x07version\x18\x01 \x01(\x03\x12\x0b\n\x03uid\x18\x02 \x01(\t\";\n\x12ListWorkersRequest\x12\x11\n\tpage_size\x18\x01 \x01(\x05\x12\x12\n\npage_token\x18\x02 \x01(\t\"O\n\x13ListWorkersResponse\x12\x1f\n\x07workers\x18\x01 \x03(\x0b\x32\x0e.ateapi.Worker\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"5\n\x10GetWorkerRequest\x12!\n\x06worker\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"5\n\x13\x43reateWorkerRequest\x12\x1e\n\x06worker\x18\x01 \x01(\x0b\x32\x0e.ateapi.Worker\"5\n\x13UpdateWorkerRequest\x12\x1e\n\x06worker\x18\x01 \x01(\x0b\x32\x0e.ateapi.Worker\"`\n\x13\x44\x65leteWorkerRequest\x12!\n\x06worker\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12&\n\x07options\x18\x02 \x01(\x0b\x32\x15.ateapi.DeleteOptions\"7\n\x12\x44rainWorkerRequest\x12!\n\x06worker\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"L\n\x11ListActorsRequest\x12\x10\n\x08\x61tespace\x18\x01 \x01(\t\x12\x11\n\tpage_size\x18\x02 \x01(\x05\x12\x12\n\npage_token\x18\x03 \x01(\t\"L\n\x12ListActorsResponse\x12\x1d\n\x06\x61\x63tors\x18\x01 \x03(\x0b\x32\r.ateapi.Actor\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"\xf0\x02\n\x06Worker\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12\x18\n\x10worker_namespace\x18\x02 \x01(\t\x12\x13\n\x0bworker_pool\x18\x03 \x01(\t\x12\x12\n\nworker_pod\x18\x04 \x01(\t\x12\x16\n\x0eworker_pod_uid\x18\x05 \x01(\t\x12\x11\n\tnode_name\x18\x06 \x01(\t\x12\n\n\x02ip\x18\x07 \x01(\t\x12\x15\n\rsandbox_class\x18\x08 \x01(\t\x12*\n\x06labels\x18\t \x03(\x0b\x32\x1a.ateapi.Worker.LabelsEntry\x12(\n\x08\x63\x61pacity\x18\n \x01(\x0b\x32\x16.ateapi.WorkerCapacity\x12$\n\x06status\x18\x0b \x01(\x0b\x32\x14.ateapi.WorkerStatus\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"_\n\x0cWorkerStatus\x12\"\n\x05state\x18\x01 \x01(\x0e\x32\x13.ateapi.WorkerState\x12+\n\nassignment\x18\x02 \x01(\x0b\x32\x17.ateapi.ActorAssignment\"9\n\x0eWorkerCapacity\x12\x11\n\tcpu_milli\x18\x01 \x01(\x03\x12\x14\n\x0cmemory_bytes\x18\x02 \x01(\x03\"u\n\x0f\x41\x63torAssignment\x12 \n\x05\x61\x63tor\x18\x02 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x11\n\tactor_uid\x18\x03 \x01(\t\x12-\n\x12\x61\x63tor_template_ref\x18\x04 \x01(\x0b\x32\x11.ateapi.ObjectRef\"[\n\x0eMintJWTRequest\x12\x10\n\x08\x61udience\x18\x01 \x03(\t\x12\x10\n\x08\x61tespace\x18\x02 \x01(\t\x12\x12\n\nactor_name\x18\x03 \x01(\t\x12\x11\n\tactor_uid\x18\x04 \x01(\t\"$\n\x0fMintJWTResponse\x12\x11\n\tactor_jwt\x18\x01 \x01(\t\"\xa7\x01\n\x0fMintCertRequest\x12!\n\x06worker\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12#\n\x1b\x63\x65rtificate_signing_request\x18\x02 \x01(\x0c\x12\x1a\n\x12\x65xpected_actor_uid\x18\x03 \x01(\t\x12\x30\n\x07purpose\x18\x04 \x01(\x0e\x32\x1f.ateapi.ActorCertificatePurpose\".\n\x10MintCertResponse\x12\x1a\n\x12\x61\x63tor_certificates\x18\x01 \x03(\x0c*\x80\x01\n\x14SnapshotContentScope\x12&\n\"SNAPSHOT_CONTENT_SCOPE_UNSPECIFIED\x10\x00\x12\x1f\n\x1bSNAPSHOT_CONTENT_SCOPE_FULL\x10\x01\x12\x1f\n\x1bSNAPSHOT_CONTENT_SCOPE_DATA\x10\x02*\x90\x01\n\x15\x41\x63torSnapshotTagScope\x12(\n$ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED\x10\x00\x12%\n!ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE\x10\x01\x12&\n\"ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED\x10\x02*\xf7\x01\n\nActorState\x12\x1b\n\x17\x41\x43TOR_STATE_UNSPECIFIED\x10\x00\x12\x18\n\x14\x41\x43TOR_STATE_RESUMING\x10\x01\x12\x17\n\x13\x41\x43TOR_STATE_RUNNING\x10\x02\x12\x1a\n\x16\x41\x43TOR_STATE_SUSPENDING\x10\x03\x12\x19\n\x15\x41\x43TOR_STATE_SUSPENDED\x10\x04\x12\x17\n\x13\x41\x43TOR_STATE_PAUSING\x10\x05\x12\x16\n\x12\x41\x43TOR_STATE_PAUSED\x10\x06\x12\x17\n\x13\x41\x43TOR_STATE_CRASHED\x10\x07\x12\x18\n\x14\x41\x43TOR_STATE_DELETING\x10\x08*b\n\x0cSandboxClass\x12\x1d\n\x19SANDBOX_CLASS_UNSPECIFIED\x10\x00\x12\x18\n\x14SANDBOX_CLASS_GVISOR\x10\x01\x12\x19\n\x15SANDBOX_CLASS_MICROVM\x10\x02*d\n\x0cResumeSource\x12\x1d\n\x19RESUME_SOURCE_UNSPECIFIED\x10\x00\x12\x1b\n\x17RESUME_SOURCE_COLD_BOOT\x10\x01\x12\x18\n\x14RESUME_SOURCE_GOLDEN\x10\x02*\x9a\x01\n\x12\x41\x63torMetadataField\x12$\n ACTOR_METADATA_FIELD_UNSPECIFIED\x10\x00\x12\x1d\n\x19\x41\x43TOR_METADATA_FIELD_NAME\x10\x01\x12!\n\x1d\x41\x43TOR_METADATA_FIELD_ATESPACE\x10\x02\x12\x1c\n\x18\x41\x43TOR_METADATA_FIELD_UID\x10\x03*_\n\x0bWorkerState\x12\x1c\n\x18WORKER_STATE_UNSPECIFIED\x10\x00\x12\x17\n\x13WORKER_STATE_ACTIVE\x10\x01\x12\x19\n\x15WORKER_STATE_DRAINING\x10\x02*k\n\x17\x41\x63torCertificatePurpose\x12)\n%ACTOR_CERTIFICATE_PURPOSE_UNSPECIFIED\x10\x00\x12%\n!ACTOR_CERTIFICATE_PURPOSE_ATUNNEL\x10\x01\x32\x84\x13\n\x07\x43ontrol\x12\x34\n\x08GetActor\x12\x17.ateapi.GetActorRequest\x1a\r.ateapi.Actor\"\x00\x12:\n\x0b\x43reateActor\x12\x1a.ateapi.CreateActorRequest\x1a\r.ateapi.Actor\"\x00\x12:\n\x0bUpdateActor\x12\x1a.ateapi.UpdateActorRequest\x1a\r.ateapi.Actor\"\x00\x12K\n\x0cSuspendActor\x12\x1b.ateapi.SuspendActorRequest\x1a\x1c.ateapi.SuspendActorResponse\"\x00\x12\x45\n\nPauseActor\x12\x19.ateapi.PauseActorRequest\x1a\x1a.ateapi.PauseActorResponse\"\x00\x12H\n\x0bResumeActor\x12\x1a.ateapi.ResumeActorRequest\x1a\x1b.ateapi.ResumeActorResponse\"\x00\x12:\n\x0b\x44\x65leteActor\x12\x1a.ateapi.DeleteActorRequest\x1a\r.ateapi.Actor\"\x00\x12S\n\x14GetActorEgressPolicy\x12#.ateapi.GetActorEgressPolicyRequest\x1a\x14.ateapi.EgressPolicy\"\x00\x12Y\n\x17\x43reateActorEgressPolicy\x12&.ateapi.CreateActorEgressPolicyRequest\x1a\x14.ateapi.EgressPolicy\"\x00\x12Y\n\x17UpdateActorEgressPolicy\x12&.ateapi.UpdateActorEgressPolicyRequest\x1a\x14.ateapi.EgressPolicy\"\x00\x12Y\n\x17\x44\x65leteActorEgressPolicy\x12&.ateapi.DeleteActorEgressPolicyRequest\x1a\x14.ateapi.EgressPolicy\"\x00\x12L\n\x10GetActorSnapshot\x12\x1f.ateapi.GetActorSnapshotRequest\x1a\x15.ateapi.ActorSnapshot\"\x00\x12U\n\x13GetActorSnapshotTag\x12\".ateapi.GetActorSnapshotTagRequest\x1a\x18.ateapi.ActorSnapshotTag\"\x00\x12]\n\x12ListActorSnapshots\x12!.ateapi.ListActorSnapshotsRequest\x1a\".ateapi.ListActorSnapshotsResponse\"\x00\x12[\n\x16\x43reateActorSnapshotTag\x12%.ateapi.CreateActorSnapshotTagRequest\x1a\x18.ateapi.ActorSnapshotTag\"\x00\x12[\n\x16UpdateActorSnapshotTag\x12%.ateapi.UpdateActorSnapshotTagRequest\x1a\x18.ateapi.ActorSnapshotTag\"\x00\x12[\n\x16\x44\x65leteActorSnapshotTag\x12%.ateapi.DeleteActorSnapshotTagRequest\x1a\x18.ateapi.ActorSnapshotTag\"\x00\x12H\n\x0bListWorkers\x12\x1a.ateapi.ListWorkersRequest\x1a\x1b.ateapi.ListWorkersResponse\"\x00\x12\x37\n\tGetWorker\x12\x18.ateapi.GetWorkerRequest\x1a\x0e.ateapi.Worker\"\x00\x12=\n\x0c\x43reateWorker\x12\x1b.ateapi.CreateWorkerRequest\x1a\x0e.ateapi.Worker\"\x00\x12=\n\x0cUpdateWorker\x12\x1b.ateapi.UpdateWorkerRequest\x1a\x0e.ateapi.Worker\"\x00\x12=\n\x0c\x44\x65leteWorker\x12\x1b.ateapi.DeleteWorkerRequest\x1a\x0e.ateapi.Worker\"\x00\x12;\n\x0b\x44rainWorker\x12\x1a.ateapi.DrainWorkerRequest\x1a\x0e.ateapi.Worker\"\x00\x12\x45\n\nListActors\x12\x19.ateapi.ListActorsRequest\x1a\x1a.ateapi.ListActorsResponse\"\x00\x12\x43\n\x0e\x43reateAtespace\x12\x1d.ateapi.CreateAtespaceRequest\x1a\x10.ateapi.Atespace\"\x00\x12=\n\x0bGetAtespace\x12\x1a.ateapi.GetAtespaceRequest\x1a\x10.ateapi.Atespace\"\x00\x12N\n\rListAtespaces\x12\x1c.ateapi.ListAtespacesRequest\x1a\x1d.ateapi.ListAtespacesResponse\"\x00\x12\x43\n\x0e\x44\x65leteAtespace\x12\x1d.ateapi.DeleteAtespaceRequest\x1a\x10.ateapi.Atespace\"\x00\x12R\n\x13\x43reateActorTemplate\x12\".ateapi.CreateActorTemplateRequest\x1a\x15.ateapi.ActorTemplate\"\x00\x12L\n\x10GetActorTemplate\x12\x1f.ateapi.GetActorTemplateRequest\x1a\x15.ateapi.ActorTemplate\"\x00\x12]\n\x12ListActorTemplates\x12!.ateapi.ListActorTemplatesRequest\x1a\".ateapi.ListActorTemplatesResponse\"\x00\x12R\n\x13\x44\x65leteActorTemplate\x12\".ateapi.DeleteActorTemplateRequest\x1a\x15.ateapi.ActorTemplate\"\x00\x32\x8a\x01\n\rActorIdentity\x12:\n\x07MintJWT\x12\x16.ateapi.MintJWTRequest\x1a\x17.ateapi.MintJWTResponse\x12=\n\x08MintCert\x12\x17.ateapi.MintCertRequest\x1a\x18.ateapi.MintCertResponseB9Z7github.com/agent-substrate/substrate/pkg/proto/ateapipbb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -54,216 +54,218 @@ _globals['_EXTERNALVOLUME_VOLUMECONTEXTENTRY']._serialized_options = b'8\001' _globals['_WORKER_LABELSENTRY']._loaded_options = None _globals['_WORKER_LABELSENTRY']._serialized_options = b'8\001' - _globals['_SNAPSHOTCONTENTSCOPE']._serialized_start=9357 - _globals['_SNAPSHOTCONTENTSCOPE']._serialized_end=9485 - _globals['_ACTORSNAPSHOTTAGSCOPE']._serialized_start=9488 - _globals['_ACTORSNAPSHOTTAGSCOPE']._serialized_end=9632 - _globals['_ACTORSTATE']._serialized_start=9635 - _globals['_ACTORSTATE']._serialized_end=9882 - _globals['_SANDBOXCLASS']._serialized_start=9884 - _globals['_SANDBOXCLASS']._serialized_end=9982 - _globals['_RESUMESOURCE']._serialized_start=9984 - _globals['_RESUMESOURCE']._serialized_end=10084 - _globals['_ACTORMETADATAFIELD']._serialized_start=10087 - _globals['_ACTORMETADATAFIELD']._serialized_end=10241 - _globals['_WORKERSTATE']._serialized_start=10243 - _globals['_WORKERSTATE']._serialized_end=10338 - _globals['_ACTORCERTIFICATEPURPOSE']._serialized_start=10340 - _globals['_ACTORCERTIFICATEPURPOSE']._serialized_end=10447 + _globals['_SNAPSHOTCONTENTSCOPE']._serialized_start=9538 + _globals['_SNAPSHOTCONTENTSCOPE']._serialized_end=9666 + _globals['_ACTORSNAPSHOTTAGSCOPE']._serialized_start=9669 + _globals['_ACTORSNAPSHOTTAGSCOPE']._serialized_end=9813 + _globals['_ACTORSTATE']._serialized_start=9816 + _globals['_ACTORSTATE']._serialized_end=10063 + _globals['_SANDBOXCLASS']._serialized_start=10065 + _globals['_SANDBOXCLASS']._serialized_end=10163 + _globals['_RESUMESOURCE']._serialized_start=10165 + _globals['_RESUMESOURCE']._serialized_end=10265 + _globals['_ACTORMETADATAFIELD']._serialized_start=10268 + _globals['_ACTORMETADATAFIELD']._serialized_end=10422 + _globals['_WORKERSTATE']._serialized_start=10424 + _globals['_WORKERSTATE']._serialized_end=10519 + _globals['_ACTORCERTIFICATEPURPOSE']._serialized_start=10521 + _globals['_ACTORCERTIFICATEPURPOSE']._serialized_end=10628 _globals['_LOCALSNAPSHOTINFO']._serialized_start=87 - _globals['_LOCALSNAPSHOTINFO']._serialized_end=221 - _globals['_SELECTOR']._serialized_start=223 - _globals['_SELECTOR']._serialized_end=342 - _globals['_SELECTOR_MATCHLABELSENTRY']._serialized_start=292 - _globals['_SELECTOR_MATCHLABELSENTRY']._serialized_end=342 - _globals['_RESOURCEMETADATA']._serialized_start=345 - _globals['_RESOURCEMETADATA']._serialized_end=523 - _globals['_EXTERNALVOLUME']._serialized_start=526 - _globals['_EXTERNALVOLUME']._serialized_end=874 - _globals['_EXTERNALVOLUME_VOLUMECONTEXTENTRY']._serialized_start=727 - _globals['_EXTERNALVOLUME_VOLUMECONTEXTENTRY']._serialized_end=779 - _globals['_EXTERNALVOLUME_STATUS']._serialized_start=781 - _globals['_EXTERNALVOLUME_STATUS']._serialized_end=874 - _globals['_ACTOR']._serialized_start=877 - _globals['_ACTOR']._serialized_end=1099 - _globals['_EGRESSPOLICY']._serialized_start=1101 - _globals['_EGRESSPOLICY']._serialized_end=1194 - _globals['_EGRESSRULE']._serialized_start=1197 - _globals['_EGRESSRULE']._serialized_end=1327 - _globals['_HOSTNAMERULE']._serialized_start=1329 - _globals['_HOSTNAMERULE']._serialized_end=1405 - _globals['_IPBLOCKRULE']._serialized_start=1407 - _globals['_IPBLOCKRULE']._serialized_end=1435 - _globals['_EGRESSRULEEFFECTS']._serialized_start=1437 - _globals['_EGRESSRULEEFFECTS']._serialized_end=1522 - _globals['_CREDENTIALHEADERINJECTION']._serialized_start=1524 - _globals['_CREDENTIALHEADERINJECTION']._serialized_end=1607 - _globals['_ACTORSTATUS']._serialized_start=1610 - _globals['_ACTORSTATUS']._serialized_end=2132 - _globals['_ACTORSOURCESNAPSHOTSTATUS']._serialized_start=2134 - _globals['_ACTORSOURCESNAPSHOTSTATUS']._serialized_end=2220 - _globals['_WORKERASSIGNMENT']._serialized_start=2223 - _globals['_WORKERASSIGNMENT']._serialized_end=2390 - _globals['_ACTORSNAPSHOT']._serialized_start=2392 - _globals['_ACTORSNAPSHOT']._serialized_end=2496 - _globals['_ACTORSNAPSHOTSTATUS']._serialized_start=2499 - _globals['_ACTORSNAPSHOTSTATUS']._serialized_end=2763 - _globals['_ACTORSNAPSHOTTAG']._serialized_start=2766 - _globals['_ACTORSNAPSHOTTAG']._serialized_end=2911 - _globals['_ATESPACE']._serialized_start=2913 - _globals['_ATESPACE']._serialized_end=2967 - _globals['_OBJECTREF']._serialized_start=2969 - _globals['_OBJECTREF']._serialized_end=3012 - _globals['_ACTORTEMPLATE']._serialized_start=3015 - _globals['_ACTORTEMPLATE']._serialized_end=3370 - _globals['_RESOURCES']._serialized_start=3372 - _globals['_RESOURCES']._serialized_end=3415 - _globals['_LIMITS']._serialized_start=3417 - _globals['_LIMITS']._serialized_end=3457 - _globals['_GOLDENSNAPSHOTSTATUS']._serialized_start=3460 - _globals['_GOLDENSNAPSHOTSTATUS']._serialized_end=3610 - _globals['_ACTORTEMPLATESTATUS']._serialized_start=3612 - _globals['_ACTORTEMPLATESTATUS']._serialized_end=3695 - _globals['_SANDBOXCONFIG']._serialized_start=3697 - _globals['_SANDBOXCONFIG']._serialized_end=3778 - _globals['_SNAPSHOTSCONFIG']._serialized_start=3781 - _globals['_SNAPSHOTSCONFIG']._serialized_end=3964 - _globals['_ONRESUMECONFIG']._serialized_start=3966 - _globals['_ONRESUMECONFIG']._serialized_end=4023 - _globals['_CONTAINER']._serialized_start=4026 - _globals['_CONTAINER']._serialized_end=4300 - _globals['_SECURITYCONTEXT']._serialized_start=4302 - _globals['_SECURITYCONTEXT']._serialized_end=4363 - _globals['_CAPABILITIES']._serialized_start=4365 - _globals['_CAPABILITIES']._serialized_end=4406 - _globals['_ENVVAR']._serialized_start=4408 - _globals['_ENVVAR']._serialized_end=4445 - _globals['_CONTAINERREADYZ']._serialized_start=4447 - _globals['_CONTAINERREADYZ']._serialized_end=4530 - _globals['_HTTPGETACTION']._serialized_start=4532 - _globals['_HTTPGETACTION']._serialized_end=4575 - _globals['_VOLUME']._serialized_start=4578 - _globals['_VOLUME']._serialized_end=4814 - _globals['_IMAGEVOLUMESOURCE']._serialized_start=4816 - _globals['_IMAGEVOLUMESOURCE']._serialized_end=4854 - _globals['_DURABLEDIRVOLUMESOURCE']._serialized_start=4856 - _globals['_DURABLEDIRVOLUMESOURCE']._serialized_end=4880 - _globals['_EXTERNALVOLUMETEMPLATE']._serialized_start=4882 - _globals['_EXTERNALVOLUMETEMPLATE']._serialized_end=4952 - _globals['_SYSTEMINFOVOLUMESOURCE']._serialized_start=4954 - _globals['_SYSTEMINFOVOLUMESOURCE']._serialized_end=5030 - _globals['_SYSTEMINFODATASOURCE']._serialized_start=5033 - _globals['_SYSTEMINFODATASOURCE']._serialized_end=5165 - _globals['_ACTORMETADATADATASOURCE']._serialized_start=5167 - _globals['_ACTORMETADATADATASOURCE']._serialized_end=5234 - _globals['_ACTORMETADATAITEM']._serialized_start=5236 - _globals['_ACTORMETADATAITEM']._serialized_end=5312 - _globals['_TRUSTBUNDLEDATASOURCE']._serialized_start=5314 - _globals['_TRUSTBUNDLEDATASOURCE']._serialized_end=5365 - _globals['_VOLUMEMOUNT']._serialized_start=5367 - _globals['_VOLUMEMOUNT']._serialized_end=5414 - _globals['_CREATEATESPACEREQUEST']._serialized_start=5416 - _globals['_CREATEATESPACEREQUEST']._serialized_end=5475 - _globals['_GETATESPACEREQUEST']._serialized_start=5477 - _globals['_GETATESPACEREQUEST']._serialized_end=5534 - _globals['_LISTATESPACESREQUEST']._serialized_start=5536 - _globals['_LISTATESPACESREQUEST']._serialized_end=5597 - _globals['_LISTATESPACESRESPONSE']._serialized_start=5599 - _globals['_LISTATESPACESRESPONSE']._serialized_end=5684 - _globals['_DELETEATESPACEREQUEST']._serialized_start=5686 - _globals['_DELETEATESPACEREQUEST']._serialized_end=5746 - _globals['_CREATEACTORTEMPLATEREQUEST']._serialized_start=5748 - _globals['_CREATEACTORTEMPLATEREQUEST']._serialized_end=5823 - _globals['_GETACTORTEMPLATEREQUEST']._serialized_start=5825 - _globals['_GETACTORTEMPLATEREQUEST']._serialized_end=5893 - _globals['_LISTACTORTEMPLATESREQUEST']._serialized_start=5895 - _globals['_LISTACTORTEMPLATESREQUEST']._serialized_end=5979 - _globals['_LISTACTORTEMPLATESRESPONSE']._serialized_start=5981 - _globals['_LISTACTORTEMPLATESRESPONSE']._serialized_end=6082 - _globals['_DELETEACTORTEMPLATEREQUEST']._serialized_start=6084 - _globals['_DELETEACTORTEMPLATEREQUEST']._serialized_end=6155 - _globals['_GETACTORREQUEST']._serialized_start=6157 - _globals['_GETACTORREQUEST']._serialized_end=6208 - _globals['_CREATEACTORREQUEST']._serialized_start=6210 - _globals['_CREATEACTORREQUEST']._serialized_end=6260 - _globals['_UPDATEACTORREQUEST']._serialized_start=6262 - _globals['_UPDATEACTORREQUEST']._serialized_end=6312 - _globals['_SUSPENDACTORREQUEST']._serialized_start=6314 - _globals['_SUSPENDACTORREQUEST']._serialized_end=6369 - _globals['_SUSPENDACTORRESPONSE']._serialized_start=6371 - _globals['_SUSPENDACTORRESPONSE']._serialized_end=6423 - _globals['_PAUSEACTORREQUEST']._serialized_start=6425 - _globals['_PAUSEACTORREQUEST']._serialized_end=6478 - _globals['_PAUSEACTORRESPONSE']._serialized_start=6480 - _globals['_PAUSEACTORRESPONSE']._serialized_end=6530 - _globals['_RESUMEACTORREQUEST']._serialized_start=6532 - _globals['_RESUMEACTORREQUEST']._serialized_end=6600 - _globals['_RESUMEACTORRESPONSE']._serialized_start=6602 - _globals['_RESUMEACTORRESPONSE']._serialized_end=6670 - _globals['_DELETEACTORREQUEST']._serialized_start=6672 - _globals['_DELETEACTORREQUEST']._serialized_end=6745 - _globals['_GETACTOREGRESSPOLICYREQUEST']._serialized_start=6747 - _globals['_GETACTOREGRESSPOLICYREQUEST']._serialized_end=6810 - _globals['_CREATEACTOREGRESSPOLICYREQUEST']._serialized_start=6812 - _globals['_CREATEACTOREGRESSPOLICYREQUEST']._serialized_end=6923 - _globals['_UPDATEACTOREGRESSPOLICYREQUEST']._serialized_start=6925 - _globals['_UPDATEACTOREGRESSPOLICYREQUEST']._serialized_end=7036 - _globals['_DELETEACTOREGRESSPOLICYREQUEST']._serialized_start=7038 - _globals['_DELETEACTOREGRESSPOLICYREQUEST']._serialized_end=7104 - _globals['_GETACTORSNAPSHOTREQUEST']._serialized_start=7106 - _globals['_GETACTORSNAPSHOTREQUEST']._serialized_end=7174 - _globals['_GETACTORSNAPSHOTTAGREQUEST']._serialized_start=7176 - _globals['_GETACTORSNAPSHOTTAGREQUEST']._serialized_end=7251 - _globals['_LISTACTORSNAPSHOTSREQUEST']._serialized_start=7253 - _globals['_LISTACTORSNAPSHOTSREQUEST']._serialized_end=7337 - _globals['_LISTACTORSNAPSHOTSRESPONSE']._serialized_start=7339 - _globals['_LISTACTORSNAPSHOTSRESPONSE']._serialized_end=7440 - _globals['_CREATEACTORSNAPSHOTTAGREQUEST']._serialized_start=7442 - _globals['_CREATEACTORSNAPSHOTTAGREQUEST']._serialized_end=7527 - _globals['_UPDATEACTORSNAPSHOTTAGREQUEST']._serialized_start=7529 - _globals['_UPDATEACTORSNAPSHOTTAGREQUEST']._serialized_end=7614 - _globals['_DELETEACTORSNAPSHOTTAGREQUEST']._serialized_start=7616 - _globals['_DELETEACTORSNAPSHOTTAGREQUEST']._serialized_end=7694 - _globals['_DELETEOPTIONS']._serialized_start=7696 - _globals['_DELETEOPTIONS']._serialized_end=7741 - _globals['_LISTWORKERSREQUEST']._serialized_start=7743 - _globals['_LISTWORKERSREQUEST']._serialized_end=7802 - _globals['_LISTWORKERSRESPONSE']._serialized_start=7804 - _globals['_LISTWORKERSRESPONSE']._serialized_end=7883 - _globals['_GETWORKERREQUEST']._serialized_start=7885 - _globals['_GETWORKERREQUEST']._serialized_end=7938 - _globals['_CREATEWORKERREQUEST']._serialized_start=7940 - _globals['_CREATEWORKERREQUEST']._serialized_end=7993 - _globals['_UPDATEWORKERREQUEST']._serialized_start=7995 - _globals['_UPDATEWORKERREQUEST']._serialized_end=8048 - _globals['_DELETEWORKERREQUEST']._serialized_start=8050 - _globals['_DELETEWORKERREQUEST']._serialized_end=8146 - _globals['_DRAINWORKERREQUEST']._serialized_start=8148 - _globals['_DRAINWORKERREQUEST']._serialized_end=8203 - _globals['_LISTACTORSREQUEST']._serialized_start=8205 - _globals['_LISTACTORSREQUEST']._serialized_end=8281 - _globals['_LISTACTORSRESPONSE']._serialized_start=8283 - _globals['_LISTACTORSRESPONSE']._serialized_end=8359 - _globals['_WORKER']._serialized_start=8362 - _globals['_WORKER']._serialized_end=8730 - _globals['_WORKER_LABELSENTRY']._serialized_start=8685 - _globals['_WORKER_LABELSENTRY']._serialized_end=8730 - _globals['_WORKERSTATUS']._serialized_start=8732 - _globals['_WORKERSTATUS']._serialized_end=8827 - _globals['_WORKERCAPACITY']._serialized_start=8829 - _globals['_WORKERCAPACITY']._serialized_end=8886 - _globals['_ACTORASSIGNMENT']._serialized_start=8888 - _globals['_ACTORASSIGNMENT']._serialized_end=9005 - _globals['_MINTJWTREQUEST']._serialized_start=9007 - _globals['_MINTJWTREQUEST']._serialized_end=9098 - _globals['_MINTJWTRESPONSE']._serialized_start=9100 - _globals['_MINTJWTRESPONSE']._serialized_end=9136 - _globals['_MINTCERTREQUEST']._serialized_start=9139 - _globals['_MINTCERTREQUEST']._serialized_end=9306 - _globals['_MINTCERTRESPONSE']._serialized_start=9308 - _globals['_MINTCERTRESPONSE']._serialized_end=9354 - _globals['_CONTROL']._serialized_start=10450 - _globals['_CONTROL']._serialized_end=12886 - _globals['_ACTORIDENTITY']._serialized_start=12889 - _globals['_ACTORIDENTITY']._serialized_end=13027 + _globals['_LOCALSNAPSHOTINFO']._serialized_end=275 + _globals['_SELECTOR']._serialized_start=277 + _globals['_SELECTOR']._serialized_end=396 + _globals['_SELECTOR_MATCHLABELSENTRY']._serialized_start=346 + _globals['_SELECTOR_MATCHLABELSENTRY']._serialized_end=396 + _globals['_RESOURCEMETADATA']._serialized_start=399 + _globals['_RESOURCEMETADATA']._serialized_end=577 + _globals['_EXTERNALVOLUME']._serialized_start=580 + _globals['_EXTERNALVOLUME']._serialized_end=928 + _globals['_EXTERNALVOLUME_VOLUMECONTEXTENTRY']._serialized_start=781 + _globals['_EXTERNALVOLUME_VOLUMECONTEXTENTRY']._serialized_end=833 + _globals['_EXTERNALVOLUME_STATUS']._serialized_start=835 + _globals['_EXTERNALVOLUME_STATUS']._serialized_end=928 + _globals['_ACTOR']._serialized_start=931 + _globals['_ACTOR']._serialized_end=1153 + _globals['_EGRESSPOLICY']._serialized_start=1155 + _globals['_EGRESSPOLICY']._serialized_end=1248 + _globals['_EGRESSRULE']._serialized_start=1251 + _globals['_EGRESSRULE']._serialized_end=1381 + _globals['_HOSTNAMERULE']._serialized_start=1383 + _globals['_HOSTNAMERULE']._serialized_end=1459 + _globals['_IPBLOCKRULE']._serialized_start=1461 + _globals['_IPBLOCKRULE']._serialized_end=1489 + _globals['_EGRESSRULEEFFECTS']._serialized_start=1491 + _globals['_EGRESSRULEEFFECTS']._serialized_end=1576 + _globals['_CREDENTIALHEADERINJECTION']._serialized_start=1578 + _globals['_CREDENTIALHEADERINJECTION']._serialized_end=1661 + _globals['_ACTORSTATUS']._serialized_start=1664 + _globals['_ACTORSTATUS']._serialized_end=2186 + _globals['_ACTORSOURCESNAPSHOTSTATUS']._serialized_start=2188 + _globals['_ACTORSOURCESNAPSHOTSTATUS']._serialized_end=2274 + _globals['_WORKERASSIGNMENT']._serialized_start=2277 + _globals['_WORKERASSIGNMENT']._serialized_end=2444 + _globals['_ACTORSNAPSHOT']._serialized_start=2446 + _globals['_ACTORSNAPSHOT']._serialized_end=2550 + _globals['_ACTORSNAPSHOTSTATUS']._serialized_start=2553 + _globals['_ACTORSNAPSHOTSTATUS']._serialized_end=2871 + _globals['_ACTORSNAPSHOTTAG']._serialized_start=2874 + _globals['_ACTORSNAPSHOTTAG']._serialized_end=3019 + _globals['_ATESPACE']._serialized_start=3021 + _globals['_ATESPACE']._serialized_end=3075 + _globals['_OBJECTREF']._serialized_start=3077 + _globals['_OBJECTREF']._serialized_end=3120 + _globals['_SANDBOXCONFIGREF']._serialized_start=3122 + _globals['_SANDBOXCONFIGREF']._serialized_end=3193 + _globals['_ACTORTEMPLATE']._serialized_start=3196 + _globals['_ACTORTEMPLATE']._serialized_end=3551 + _globals['_RESOURCES']._serialized_start=3553 + _globals['_RESOURCES']._serialized_end=3596 + _globals['_LIMITS']._serialized_start=3598 + _globals['_LIMITS']._serialized_end=3638 + _globals['_GOLDENSNAPSHOTSTATUS']._serialized_start=3641 + _globals['_GOLDENSNAPSHOTSTATUS']._serialized_end=3791 + _globals['_ACTORTEMPLATESTATUS']._serialized_start=3793 + _globals['_ACTORTEMPLATESTATUS']._serialized_end=3876 + _globals['_SANDBOXCONFIG']._serialized_start=3878 + _globals['_SANDBOXCONFIG']._serialized_end=3959 + _globals['_SNAPSHOTSCONFIG']._serialized_start=3962 + _globals['_SNAPSHOTSCONFIG']._serialized_end=4145 + _globals['_ONRESUMECONFIG']._serialized_start=4147 + _globals['_ONRESUMECONFIG']._serialized_end=4204 + _globals['_CONTAINER']._serialized_start=4207 + _globals['_CONTAINER']._serialized_end=4481 + _globals['_SECURITYCONTEXT']._serialized_start=4483 + _globals['_SECURITYCONTEXT']._serialized_end=4544 + _globals['_CAPABILITIES']._serialized_start=4546 + _globals['_CAPABILITIES']._serialized_end=4587 + _globals['_ENVVAR']._serialized_start=4589 + _globals['_ENVVAR']._serialized_end=4626 + _globals['_CONTAINERREADYZ']._serialized_start=4628 + _globals['_CONTAINERREADYZ']._serialized_end=4711 + _globals['_HTTPGETACTION']._serialized_start=4713 + _globals['_HTTPGETACTION']._serialized_end=4756 + _globals['_VOLUME']._serialized_start=4759 + _globals['_VOLUME']._serialized_end=4995 + _globals['_IMAGEVOLUMESOURCE']._serialized_start=4997 + _globals['_IMAGEVOLUMESOURCE']._serialized_end=5035 + _globals['_DURABLEDIRVOLUMESOURCE']._serialized_start=5037 + _globals['_DURABLEDIRVOLUMESOURCE']._serialized_end=5061 + _globals['_EXTERNALVOLUMETEMPLATE']._serialized_start=5063 + _globals['_EXTERNALVOLUMETEMPLATE']._serialized_end=5133 + _globals['_SYSTEMINFOVOLUMESOURCE']._serialized_start=5135 + _globals['_SYSTEMINFOVOLUMESOURCE']._serialized_end=5211 + _globals['_SYSTEMINFODATASOURCE']._serialized_start=5214 + _globals['_SYSTEMINFODATASOURCE']._serialized_end=5346 + _globals['_ACTORMETADATADATASOURCE']._serialized_start=5348 + _globals['_ACTORMETADATADATASOURCE']._serialized_end=5415 + _globals['_ACTORMETADATAITEM']._serialized_start=5417 + _globals['_ACTORMETADATAITEM']._serialized_end=5493 + _globals['_TRUSTBUNDLEDATASOURCE']._serialized_start=5495 + _globals['_TRUSTBUNDLEDATASOURCE']._serialized_end=5546 + _globals['_VOLUMEMOUNT']._serialized_start=5548 + _globals['_VOLUMEMOUNT']._serialized_end=5595 + _globals['_CREATEATESPACEREQUEST']._serialized_start=5597 + _globals['_CREATEATESPACEREQUEST']._serialized_end=5656 + _globals['_GETATESPACEREQUEST']._serialized_start=5658 + _globals['_GETATESPACEREQUEST']._serialized_end=5715 + _globals['_LISTATESPACESREQUEST']._serialized_start=5717 + _globals['_LISTATESPACESREQUEST']._serialized_end=5778 + _globals['_LISTATESPACESRESPONSE']._serialized_start=5780 + _globals['_LISTATESPACESRESPONSE']._serialized_end=5865 + _globals['_DELETEATESPACEREQUEST']._serialized_start=5867 + _globals['_DELETEATESPACEREQUEST']._serialized_end=5927 + _globals['_CREATEACTORTEMPLATEREQUEST']._serialized_start=5929 + _globals['_CREATEACTORTEMPLATEREQUEST']._serialized_end=6004 + _globals['_GETACTORTEMPLATEREQUEST']._serialized_start=6006 + _globals['_GETACTORTEMPLATEREQUEST']._serialized_end=6074 + _globals['_LISTACTORTEMPLATESREQUEST']._serialized_start=6076 + _globals['_LISTACTORTEMPLATESREQUEST']._serialized_end=6160 + _globals['_LISTACTORTEMPLATESRESPONSE']._serialized_start=6162 + _globals['_LISTACTORTEMPLATESRESPONSE']._serialized_end=6263 + _globals['_DELETEACTORTEMPLATEREQUEST']._serialized_start=6265 + _globals['_DELETEACTORTEMPLATEREQUEST']._serialized_end=6336 + _globals['_GETACTORREQUEST']._serialized_start=6338 + _globals['_GETACTORREQUEST']._serialized_end=6389 + _globals['_CREATEACTORREQUEST']._serialized_start=6391 + _globals['_CREATEACTORREQUEST']._serialized_end=6441 + _globals['_UPDATEACTORREQUEST']._serialized_start=6443 + _globals['_UPDATEACTORREQUEST']._serialized_end=6493 + _globals['_SUSPENDACTORREQUEST']._serialized_start=6495 + _globals['_SUSPENDACTORREQUEST']._serialized_end=6550 + _globals['_SUSPENDACTORRESPONSE']._serialized_start=6552 + _globals['_SUSPENDACTORRESPONSE']._serialized_end=6604 + _globals['_PAUSEACTORREQUEST']._serialized_start=6606 + _globals['_PAUSEACTORREQUEST']._serialized_end=6659 + _globals['_PAUSEACTORRESPONSE']._serialized_start=6661 + _globals['_PAUSEACTORRESPONSE']._serialized_end=6711 + _globals['_RESUMEACTORREQUEST']._serialized_start=6713 + _globals['_RESUMEACTORREQUEST']._serialized_end=6781 + _globals['_RESUMEACTORRESPONSE']._serialized_start=6783 + _globals['_RESUMEACTORRESPONSE']._serialized_end=6851 + _globals['_DELETEACTORREQUEST']._serialized_start=6853 + _globals['_DELETEACTORREQUEST']._serialized_end=6926 + _globals['_GETACTOREGRESSPOLICYREQUEST']._serialized_start=6928 + _globals['_GETACTOREGRESSPOLICYREQUEST']._serialized_end=6991 + _globals['_CREATEACTOREGRESSPOLICYREQUEST']._serialized_start=6993 + _globals['_CREATEACTOREGRESSPOLICYREQUEST']._serialized_end=7104 + _globals['_UPDATEACTOREGRESSPOLICYREQUEST']._serialized_start=7106 + _globals['_UPDATEACTOREGRESSPOLICYREQUEST']._serialized_end=7217 + _globals['_DELETEACTOREGRESSPOLICYREQUEST']._serialized_start=7219 + _globals['_DELETEACTOREGRESSPOLICYREQUEST']._serialized_end=7285 + _globals['_GETACTORSNAPSHOTREQUEST']._serialized_start=7287 + _globals['_GETACTORSNAPSHOTREQUEST']._serialized_end=7355 + _globals['_GETACTORSNAPSHOTTAGREQUEST']._serialized_start=7357 + _globals['_GETACTORSNAPSHOTTAGREQUEST']._serialized_end=7432 + _globals['_LISTACTORSNAPSHOTSREQUEST']._serialized_start=7434 + _globals['_LISTACTORSNAPSHOTSREQUEST']._serialized_end=7518 + _globals['_LISTACTORSNAPSHOTSRESPONSE']._serialized_start=7520 + _globals['_LISTACTORSNAPSHOTSRESPONSE']._serialized_end=7621 + _globals['_CREATEACTORSNAPSHOTTAGREQUEST']._serialized_start=7623 + _globals['_CREATEACTORSNAPSHOTTAGREQUEST']._serialized_end=7708 + _globals['_UPDATEACTORSNAPSHOTTAGREQUEST']._serialized_start=7710 + _globals['_UPDATEACTORSNAPSHOTTAGREQUEST']._serialized_end=7795 + _globals['_DELETEACTORSNAPSHOTTAGREQUEST']._serialized_start=7797 + _globals['_DELETEACTORSNAPSHOTTAGREQUEST']._serialized_end=7875 + _globals['_DELETEOPTIONS']._serialized_start=7877 + _globals['_DELETEOPTIONS']._serialized_end=7922 + _globals['_LISTWORKERSREQUEST']._serialized_start=7924 + _globals['_LISTWORKERSREQUEST']._serialized_end=7983 + _globals['_LISTWORKERSRESPONSE']._serialized_start=7985 + _globals['_LISTWORKERSRESPONSE']._serialized_end=8064 + _globals['_GETWORKERREQUEST']._serialized_start=8066 + _globals['_GETWORKERREQUEST']._serialized_end=8119 + _globals['_CREATEWORKERREQUEST']._serialized_start=8121 + _globals['_CREATEWORKERREQUEST']._serialized_end=8174 + _globals['_UPDATEWORKERREQUEST']._serialized_start=8176 + _globals['_UPDATEWORKERREQUEST']._serialized_end=8229 + _globals['_DELETEWORKERREQUEST']._serialized_start=8231 + _globals['_DELETEWORKERREQUEST']._serialized_end=8327 + _globals['_DRAINWORKERREQUEST']._serialized_start=8329 + _globals['_DRAINWORKERREQUEST']._serialized_end=8384 + _globals['_LISTACTORSREQUEST']._serialized_start=8386 + _globals['_LISTACTORSREQUEST']._serialized_end=8462 + _globals['_LISTACTORSRESPONSE']._serialized_start=8464 + _globals['_LISTACTORSRESPONSE']._serialized_end=8540 + _globals['_WORKER']._serialized_start=8543 + _globals['_WORKER']._serialized_end=8911 + _globals['_WORKER_LABELSENTRY']._serialized_start=8866 + _globals['_WORKER_LABELSENTRY']._serialized_end=8911 + _globals['_WORKERSTATUS']._serialized_start=8913 + _globals['_WORKERSTATUS']._serialized_end=9008 + _globals['_WORKERCAPACITY']._serialized_start=9010 + _globals['_WORKERCAPACITY']._serialized_end=9067 + _globals['_ACTORASSIGNMENT']._serialized_start=9069 + _globals['_ACTORASSIGNMENT']._serialized_end=9186 + _globals['_MINTJWTREQUEST']._serialized_start=9188 + _globals['_MINTJWTREQUEST']._serialized_end=9279 + _globals['_MINTJWTRESPONSE']._serialized_start=9281 + _globals['_MINTJWTRESPONSE']._serialized_end=9317 + _globals['_MINTCERTREQUEST']._serialized_start=9320 + _globals['_MINTCERTREQUEST']._serialized_end=9487 + _globals['_MINTCERTRESPONSE']._serialized_start=9489 + _globals['_MINTCERTRESPONSE']._serialized_end=9535 + _globals['_CONTROL']._serialized_start=10631 + _globals['_CONTROL']._serialized_end=13067 + _globals['_ACTORIDENTITY']._serialized_start=13070 + _globals['_ACTORIDENTITY']._serialized_end=13208 # @@protoc_insertion_point(module_scope) diff --git a/cmd/ateapi/internal/controlapi/sandbox_assets.go b/cmd/ateapi/internal/controlapi/sandbox_assets.go index a564582592..428be59683 100644 --- a/cmd/ateapi/internal/controlapi/sandbox_assets.go +++ b/cmd/ateapi/internal/controlapi/sandbox_assets.go @@ -20,6 +20,10 @@ import ( "github.com/agent-substrate/substrate/internal/proto/ateletpb" atev1alpha1 "github.com/agent-substrate/substrate/pkg/api/v1alpha1" listersv1alpha1 "github.com/agent-substrate/substrate/pkg/client/listers/api/v1alpha1" + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + k8serrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/labels" ) @@ -63,6 +67,47 @@ func resolveSandboxAssets( return sandboxAssetsProto(class, sc), nil } +// resolveSandboxAssetsByRef resolves an actor's recorded SandboxConfig +// reference. The UID must still match: an object re-created under the same +// name is a different config. +func resolveSandboxAssetsByRef( + sandboxConfigLister listersv1alpha1.SandboxConfigLister, + ref *ateapipb.SandboxConfigRef, +) (*ateletpb.SandboxAssets, error) { + sc, err := sandboxConfigLister.Get(ref.GetName()) + if err != nil { + if k8serrors.IsNotFound(err) { + return nil, status.Errorf(codes.FailedPrecondition, "actor's SandboxConfig %s not found", ref.GetName()) + } + return nil, fmt.Errorf("while getting SandboxConfig %q: %w", ref.GetName(), err) + } + if string(sc.UID) != ref.GetUid() { + return nil, status.Errorf(codes.FailedPrecondition, + "actor records SandboxConfig %s with uid %s, but the object now has uid %s", + ref.GetName(), ref.GetUid(), sc.UID) + } + // TODO: we also need to get the correct revision or make sure the revision matches. + class := sc.Spec.SandboxClass + if class == "" { + class = atev1alpha1.SandboxClassGvisor + } + return sandboxAssetsProto(class, sc), nil +} + +// sandboxConfigRefFromAtelet converts the SandboxConfig reference atelet +// reports (from its on-node record) into the control plane's proto. Nil when +// atelet reports none — a record written before the reference existed. +func sandboxConfigRefFromAtelet(ref *ateletpb.SandboxConfigRef) *ateapipb.SandboxConfigRef { + if ref == nil { + return nil + } + return &ateapipb.SandboxConfigRef{ + Name: ref.GetName(), + Uid: ref.GetUid(), + ResourceVersion: ref.GetResourceVersion(), + } +} + // defaultSandboxConfig returns the single SandboxConfig marked Default for the // given class, erroring if there are zero or more than one. func defaultSandboxConfig(lister listersv1alpha1.SandboxConfigLister, class atev1alpha1.SandboxClass) (*atev1alpha1.SandboxConfig, error) { @@ -92,6 +137,11 @@ func sandboxAssetsProto(class atev1alpha1.SandboxClass, sc *atev1alpha1.SandboxC SandboxClass: string(class), PauseImage: sc.Spec.PauseImage, Assets: make(map[string]*ateletpb.ArchAssets, len(sc.Spec.Assets)), + SandboxConfigRef: &ateletpb.SandboxConfigRef{ + Name: sc.Name, + Uid: string(sc.UID), + ResourceVersion: sc.ResourceVersion, + }, } for arch, files := range sc.Spec.Assets { archAssets := &ateletpb.ArchAssets{Files: make(map[string]*ateletpb.AssetFile, len(files))} diff --git a/cmd/ateapi/internal/controlapi/sandbox_assets_test.go b/cmd/ateapi/internal/controlapi/sandbox_assets_test.go index a20bd35a18..5c9593c258 100644 --- a/cmd/ateapi/internal/controlapi/sandbox_assets_test.go +++ b/cmd/ateapi/internal/controlapi/sandbox_assets_test.go @@ -19,6 +19,9 @@ import ( atev1alpha1 "github.com/agent-substrate/substrate/pkg/api/v1alpha1" listersv1alpha1 "github.com/agent-substrate/substrate/pkg/client/listers/api/v1alpha1" + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/tools/cache" ) @@ -101,3 +104,69 @@ func TestResolveSandboxAssetsCarriesPauseImage(t *testing.T) { }) } } + +// TestResolveSandboxAssetsCarriesConfigRef pins that the resolved assets name +// the SandboxConfig object they came from (name + UID + resourceVersion). +func TestResolveSandboxAssetsCarriesConfigRef(t *testing.T) { + config := &atev1alpha1.SandboxConfig{ + ObjectMeta: metav1.ObjectMeta{Name: "gvisor-prod", UID: "sandbox-uid-1", ResourceVersion: "42"}, + Spec: atev1alpha1.SandboxConfigSpec{ + SandboxClass: atev1alpha1.SandboxClassGvisor, + Default: true, + PauseImage: "registry.k8s.io/pause@sha256:abc", + Assets: testAssets(), + }, + } + pool := &atev1alpha1.WorkerPool{ + ObjectMeta: metav1.ObjectMeta{Name: "pool1", Namespace: "worker-ns"}, + } + poolLister, configLister := listersFor(t, []*atev1alpha1.WorkerPool{pool}, []*atev1alpha1.SandboxConfig{config}) + + got, err := resolveSandboxAssets(poolLister, configLister, "worker-ns", "pool1") + if err != nil { + t.Fatalf("resolveSandboxAssets() error: %v", err) + } + ref := got.GetSandboxConfigRef() + if ref.GetName() != "gvisor-prod" || ref.GetUid() != "sandbox-uid-1" || ref.GetResourceVersion() != "42" { + t.Errorf("SandboxConfig ref = %s/%s@%s, want gvisor-prod/sandbox-uid-1@42", ref.GetName(), ref.GetUid(), ref.GetResourceVersion()) + } +} + +// TestResolveSandboxAssetsByRef pins that the named SandboxConfig is used +// only while its UID still matches; a missing or re-created object is a +// FailedPrecondition. +func TestResolveSandboxAssetsByRef(t *testing.T) { + config := &atev1alpha1.SandboxConfig{ + ObjectMeta: metav1.ObjectMeta{Name: "gvisor-prod", UID: "sandbox-uid-1"}, + Spec: atev1alpha1.SandboxConfigSpec{ + SandboxClass: atev1alpha1.SandboxClassGvisor, + PauseImage: "registry.k8s.io/pause@sha256:abc", + Assets: testAssets(), + }, + } + _, configLister := listersFor(t, nil, []*atev1alpha1.SandboxConfig{config}) + + tests := []struct { + name string + ref *ateapipb.SandboxConfigRef + wantCode codes.Code + }{ + {name: "match", ref: &ateapipb.SandboxConfigRef{Name: "gvisor-prod", Uid: "sandbox-uid-1"}, wantCode: codes.OK}, + {name: "object gone", ref: &ateapipb.SandboxConfigRef{Name: "gvisor-gone", Uid: "sandbox-uid-1"}, wantCode: codes.FailedPrecondition}, + {name: "uid mismatch (object recreated under the same name)", ref: &ateapipb.SandboxConfigRef{Name: "gvisor-prod", Uid: "sandbox-uid-0"}, wantCode: codes.FailedPrecondition}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := resolveSandboxAssetsByRef(configLister, tt.ref) + if code := status.Code(err); code != tt.wantCode { + t.Fatalf("status.Code = %v (err %v), want %v", code, err, tt.wantCode) + } + if tt.wantCode != codes.OK { + return + } + if got.GetSandboxConfigRef().GetName() != "gvisor-prod" || got.GetSandboxConfigRef().GetUid() != "sandbox-uid-1" { + t.Errorf("SandboxConfig ref = %s/%s, want gvisor-prod/sandbox-uid-1", got.GetSandboxConfigRef().GetName(), got.GetSandboxConfigRef().GetUid()) + } + }) + } +} diff --git a/cmd/ateapi/internal/controlapi/template_reconciler.go b/cmd/ateapi/internal/controlapi/template_reconciler.go index 1842bbe944..0161c21fc1 100644 --- a/cmd/ateapi/internal/controlapi/template_reconciler.go +++ b/cmd/ateapi/internal/controlapi/template_reconciler.go @@ -206,8 +206,9 @@ func (r *ActorTemplateReconciler) reconcileOne(ctx context.Context, ref resource // The golden snapshot exists already. return 0, nil } - // TODO: Freeze sandbox assets before creating the golden actor. - + // The golden actor boots with the pool's SandboxConfig; the suspend + // below freezes the reference its checkpoint reports into the golden + // ActorSnapshot's status. actor, err := r.ensureActorExists(ctx, tmpl, goldenActorRef) if err != nil { if status.Code(err) == codes.InvalidArgument { diff --git a/cmd/ateapi/internal/controlapi/workflow_pause.go b/cmd/ateapi/internal/controlapi/workflow_pause.go index 07779c25f8..7507471ddd 100644 --- a/cmd/ateapi/internal/controlapi/workflow_pause.go +++ b/cmd/ateapi/internal/controlapi/workflow_pause.go @@ -73,7 +73,8 @@ func (w *ActorWorkflow) PauseActor(ctx context.Context, actorRef resources.Actor return nil, err } actor = marked - if wireSnapshotScope, err = w.ensureAteletPaused(leaseCtx, actorRef, actor, actorTemplate); err != nil { + var sandboxConfigRef *ateapipb.SandboxConfigRef + if wireSnapshotScope, sandboxConfigRef, err = w.ensureAteletPaused(leaseCtx, actorRef, actor, actorTemplate); err != nil { return nil, err } // TODO: There is no difference between suspend and pause for now, but we @@ -86,7 +87,7 @@ func (w *ActorWorkflow) PauseActor(ctx context.Context, actorRef resources.Actor // them here, as crash.go does for the crash counter. finalAttrs = lifecycleOpAttrs(actor, actorTemplate, "", wireSnapshotScope) var finalized *ateapipb.Actor - if finalized, err = w.ensurePausedFinalized(leaseCtx, actorRef, actorTemplate); err != nil { + if finalized, err = w.ensurePausedFinalized(leaseCtx, actorRef, actorTemplate, sandboxConfigRef); err != nil { return nil, err } actor = finalized @@ -147,12 +148,13 @@ func (w *ActorWorkflow) ensureMarkedPausing(ctx context.Context, actorRef resour } // ensureAteletPaused checkpoints the workload locally on the worker node -// under the actor's persisted snapshot name. This is the atelet reentrancy -// seam (#372): the request is keyed by the actor UID, the worker pod UID, and -// the once-minted snapshot name, so a re-entered workflow re-sends the same -// semantic request; once atelet's Checkpoint is idempotent on those keys this -// step becomes fully reentrant with no changes here. -func (w *ActorWorkflow) ensureAteletPaused(ctx context.Context, actorRef resources.ActorRef, actor *ateapipb.Actor, actorTemplate *ateapipb.ActorTemplate) (wireSnapshotScope string, err error) { +// under the actor's persisted snapshot name, returning the SandboxConfig +// reference atelet reports the checkpoint was taken with. This is the atelet +// reentrancy seam (#372): the request is keyed by the actor UID, the worker +// pod UID, and the once-minted snapshot name, so a re-entered workflow +// re-sends the same semantic request; once atelet's Checkpoint is idempotent +// on those keys this step becomes fully reentrant with no changes here. +func (w *ActorWorkflow) ensureAteletPaused(ctx context.Context, actorRef resources.ActorRef, actor *ateapipb.Actor, actorTemplate *ateapipb.ActorTemplate) (wireSnapshotScope string, sandboxConfigRef *ateapipb.SandboxConfigRef, err error) { ctx, done := stepSpan(ctx, "CallAteletPause") defer func() { err = done(err) }() @@ -162,7 +164,7 @@ func (w *ActorWorkflow) ensureAteletPaused(ctx context.Context, actorRef resourc if err := crashActor(ctx, w.store, actorRef, ateattr.OperationPause, ateattr.ReasonCorruptedAssignment); err != nil { slog.ErrorContext(ctx, "Failed to crash actor", slog.String("err", err.Error())) } - return "", status.Errorf(codes.FailedPrecondition, "CallAteletPause prerequisite not met for Actor: %s. No worker assignment", actorRef) + return "", nil, status.Errorf(codes.FailedPrecondition, "CallAteletPause prerequisite not met for Actor: %s. No worker assignment", actorRef) } ateletConn, err := w.dialer.DialForWorker(assignment.GetWorkerNamespace(), assignment.GetWorkerPod()) @@ -172,20 +174,20 @@ func (w *ActorWorkflow) ensureAteletPaused(ctx context.Context, actorRef resourc if err := crashActor(ctx, w.store, actorRef, ateattr.OperationPause, ateattr.ReasonWorkerPodGone); err != nil { slog.ErrorContext(ctx, "Failed to crash actor", slog.String("err", err.Error())) } - return "", fmt.Errorf("actor is CRASHED because its worker pod is gone and no snapshot was written") + return "", nil, fmt.Errorf("actor is CRASHED because its worker pod is gone and no snapshot was written") } - return "", fmt.Errorf("while getting atelet conn for worker pod: %w", err) + return "", nil, fmt.Errorf("while getting atelet conn for worker pod: %w", err) } client := ateletpb.NewAteomHerderClient(ateletConn) workloadSpec, err := workloadSpecFromActorTemplate(actorTemplate, actor) if err != nil { - return "", err + return "", nil, err } - // Checkpoint does not carry the sandbox config: atelet uses the version the - // actor is currently running (recorded on-node at Run/Restore) and pins it - // into the snapshot manifest. + // Checkpoint does not carry the sandbox config: atelet uses the version + // the actor is currently running (recorded on-node at Run/Restore) and + // pins its SandboxConfig reference into the snapshot manifest. req := &ateletpb.CheckpointRequest{ TargetAteomUid: assignment.GetWorkerPodUid(), Atespace: actor.GetMetadata().GetAtespace(), @@ -204,8 +206,8 @@ func (w *ActorWorkflow) ensureAteletPaused(ctx context.Context, actorRef resourc } wireSnapshotScope = ateattr.SnapshotScopeValue(req.Scope) - _, err = client.Checkpoint(ctx, req) - return wireSnapshotScope, maybeCrashActor(ctx, w.store, actorRef, err, "while checkpointing workload", ateattr.OperationPause) + resp, err := client.Checkpoint(ctx, req) + return wireSnapshotScope, sandboxConfigRefFromAtelet(resp.GetSandboxConfigRef()), maybeCrashActor(ctx, w.store, actorRef, err, "while checkpointing workload", ateattr.OperationPause) } // ensurePausedFinalized releases the actor's worker (only when it is still @@ -215,7 +217,9 @@ func (w *ActorWorkflow) ensureAteletPaused(ctx context.Context, actorRef resourc // never be resumed. It re-reads the actor first so an out-of-band transition // (e.g. the syncer crashing the actor after its worker died) is not // overwritten: with no assignment left there is nothing to finalize. -func (w *ActorWorkflow) ensurePausedFinalized(ctx context.Context, actorRef resources.ActorRef, actorTemplate *ateapipb.ActorTemplate) (_ *ateapipb.Actor, err error) { +// sandboxConfigRef is the reference the pause checkpoint reported (nil when +// the checkpoint never completed or atelet's record predates the reference). +func (w *ActorWorkflow) ensurePausedFinalized(ctx context.Context, actorRef resources.ActorRef, actorTemplate *ateapipb.ActorTemplate, sandboxConfigRef *ateapipb.SandboxConfigRef) (_ *ateapipb.Actor, err error) { ctx, done := stepSpan(ctx, "FinalizePaused") defer func() { err = done(err) }() @@ -284,6 +288,10 @@ func (w *ActorWorkflow) ensurePausedFinalized(ctx context.Context, actorRef reso localInfo := &ateapipb.LocalSnapshotInfo{ SnapshotName: toUpdate.GetStatus().GetInProgressLocalSnapshotName(), ContentScope: contentScope, + // The snapshot record carries the SandboxConfig the + // checkpoint reported it was taken with; a later resume + // resolves the restore's assets from it. + SandboxConfigRef: sandboxConfigRef, } if newState != ateapipb.ActorState_ACTOR_STATE_CRASHED { localInfo.NodeVmsWithLocalSnapshots = []string{nodeName} diff --git a/cmd/ateapi/internal/controlapi/workflow_pause_test.go b/cmd/ateapi/internal/controlapi/workflow_pause_test.go index e9b6e0ee33..51a473c968 100644 --- a/cmd/ateapi/internal/controlapi/workflow_pause_test.go +++ b/cmd/ateapi/internal/controlapi/workflow_pause_test.go @@ -59,7 +59,7 @@ func TestEnsurePausedFinalized_WorkerGone(t *testing.T) { // Intentionally NOT creating the worker in store, simulates worker already gone. w := &ActorWorkflow{store: st} - finalized, err := w.ensurePausedFinalized(ctx, actorRef, &ateapipb.ActorTemplate{}) + finalized, err := w.ensurePausedFinalized(ctx, actorRef, &ateapipb.ActorTemplate{}, nil) if err != nil { t.Fatalf("ensurePausedFinalized: %v", err) } @@ -139,7 +139,7 @@ func TestEnsurePausedFinalized_RecordsContentScope(t *testing.T) { tmpl := &ateapipb.ActorTemplate{ SnapshotsConfig: &ateapipb.SnapshotsConfig{OnPause: tc.onPause}, } - got, err := w.ensurePausedFinalized(ctx, actorRef, tmpl) + got, err := w.ensurePausedFinalized(ctx, actorRef, tmpl, &ateapipb.SandboxConfigRef{Name: "gvisor-prod", Uid: "sandbox-uid-1"}) if err != nil { t.Fatalf("ensurePausedFinalized: %v", err) } @@ -150,6 +150,11 @@ func TestEnsurePausedFinalized_RecordsContentScope(t *testing.T) { if scope := got.GetStatus().GetLocalSnapshotInfo().GetContentScope(); scope != tc.want { t.Errorf("LocalSnapshotInfo.ContentScope = %v, want %v", scope, tc.want) } + // The pause snapshot record carries the activation's SandboxConfig + // reference; a later resume resolves the restore's assets from it. + if ref := got.GetStatus().GetLocalSnapshotInfo().GetSandboxConfigRef(); ref.GetName() != "gvisor-prod" || ref.GetUid() != "sandbox-uid-1" { + t.Errorf("LocalSnapshotInfo.SandboxConfigRef = %s/%s, want gvisor-prod/sandbox-uid-1", ref.GetName(), ref.GetUid()) + } }) } } @@ -283,7 +288,7 @@ func TestEnsureAteletPaused_DanglingWorkerDoesNotRecordPhantomSnapshot(t *testin created := storetest.MustCreateActor(t, ctx, persistence, actor) w := &ActorWorkflow{store: persistence, dialer: newDanglingDialer()} - if _, err := w.ensureAteletPaused(ctx, resources.ActorRef{Atespace: "team-a", Name: "actor-1"}, created, &ateapipb.ActorTemplate{}); err == nil { + if _, _, err := w.ensureAteletPaused(ctx, resources.ActorRef{Atespace: "team-a", Name: "actor-1"}, created, &ateapipb.ActorTemplate{}); err == nil { t.Fatal("ensureAteletPaused: want error for dangling worker, got nil") } diff --git a/cmd/ateapi/internal/controlapi/workflow_resume.go b/cmd/ateapi/internal/controlapi/workflow_resume.go index 0e8c62258e..931cb96cd9 100644 --- a/cmd/ateapi/internal/controlapi/workflow_resume.go +++ b/cmd/ateapi/internal/controlapi/workflow_resume.go @@ -52,6 +52,19 @@ type resumeSnapshotSource struct { // TemplateReplaced is true when the snapshot's recorded template UID // differs from the actor's current template. TemplateReplaced bool + + // SandboxConfigRef is the SandboxConfig recorded on the snapshot at + // SnapshotURI; GoldenSandboxConfigRef the one at GoldenSnapshotURI. + // Nil when the snapshot records none or the URI is zero. + SandboxConfigRef *ateapipb.SandboxConfigRef + GoldenSandboxConfigRef *ateapipb.SandboxConfigRef + + // RepointSandboxConfigRef is the SandboxConfig recorded on the + // replacement template's golden snapshot, resolved only when + // TemplateReplaced: the repointed boot uses it so the actor lands on the + // sandbox its new template's golden ran. Nil when the replacement + // template has no golden snapshot or its snapshot records no reference. + RepointSandboxConfigRef *ateapipb.SandboxConfigRef } // restoreTelemetry labels the restore operation for the resume lifecycle @@ -196,6 +209,17 @@ func (w *ActorWorkflow) loadActorForResume(ctx context.Context, actorRef resourc // repointed since the capture. snapshotTemplateUID := snapshot.GetStatus().GetActorTemplateUid() src.TemplateReplaced = snapshotTemplateUID != "" && snapshotTemplateUID != actorTemplate.GetMetadata().GetUid() + src.SandboxConfigRef = snapshot.GetStatus().GetSandboxConfigRef() + if goldenRef := actorTemplate.GetStatus().GetGoldenSnapshotStatus().GetGoldenSnapshot(); src.TemplateReplaced && goldenRef != nil { + goldenSnapshot, err := w.store.GetActorSnapshot(ctx, resources.ActorSnapshotRefFromObjectRef(goldenRef)) + if errors.Is(err, store.ErrNotFound) { + return nil, nil, src, status.Error(codes.DataLoss, "ActorTemplate golden snapshot data is missing") + } + if err != nil { + return nil, nil, src, fmt.Errorf("while getting golden ActorSnapshot: %w", err) + } + src.RepointSandboxConfigRef = goldenSnapshot.GetStatus().GetSandboxConfigRef() + } } else if goldenRef := actorTemplate.GetStatus().GetGoldenSnapshotStatus().GetGoldenSnapshot(); goldenRef != nil && !boot { snapshot, err := w.store.GetActorSnapshot(ctx, resources.ActorSnapshotRefFromObjectRef(goldenRef)) if errors.Is(err, store.ErrNotFound) { @@ -211,6 +235,7 @@ func (w *ActorWorkflow) loadActorForResume(ctx context.Context, actorRef resourc return nil, nil, src, status.Errorf(codes.DataLoss, "golden ActorSnapshot %s: %v", goldenRef.GetName(), err) } src.Scope = snapshot.GetStatus().GetContentScope() + src.SandboxConfigRef = snapshot.GetStatus().GetSandboxConfigRef() } // The template's onResume configuration selects the boot source for the @@ -246,6 +271,7 @@ func (w *ActorWorkflow) loadActorForResume(ctx context.Context, actorRef resourc if src.GoldenSnapshotURI, err = resources.ParseSnapshotURI(goldenSnapshot.GetStatus().GetSnapshotUri()); err != nil { return nil, nil, src, status.Errorf(codes.DataLoss, "golden ActorSnapshot %s: %v", goldenRef.GetName(), err) } + src.GoldenSandboxConfigRef = goldenSnapshot.GetStatus().GetSandboxConfigRef() } } @@ -655,6 +681,9 @@ func (w *ActorWorkflow) ensureVolumesAttached(ctx context.Context, actor *ateapi // the worker pod UID, so a re-entered workflow re-sends the same semantic // request; once atelet's Restore/Run are idempotent on those keys this step // becomes fully reentrant with no changes here. +// +// Every branch resolves and sends sandbox assets; restores resolve them from +// the SandboxConfig reference recorded on the snapshot. func (w *ActorWorkflow) ensureAteletRestored(ctx context.Context, actorRef resources.ActorRef, actor *ateapipb.Actor, actorTemplate *ateapipb.ActorTemplate, src resumeSnapshotSource) (tele restoreTelemetry, err error) { ctx, done := stepSpan(ctx, "CallAteletRestore") defer func() { err = done(err) }() @@ -679,6 +708,14 @@ func (w *ActorWorkflow) ensureAteletRestored(ctx context.Context, actorRef resou return tele, err } + // Snapshot manifests carry only a SandboxConfig reference, so the + // restore's assets ride the request: resolved from the reference recorded + // on the snapshot whose sandbox will run the guest. + sandboxAssets, err := w.resolveSandboxAssetsForResume(actor, src, assignment.GetWorkerNamespace(), assignment.GetWorkerPool()) + if err != nil { + return tele, fmt.Errorf("while resolving sandbox assets: %w", err) + } + if local := actor.GetStatus().GetLocalSnapshotInfo(); local != nil { slog.InfoContext(ctx, "Actor has snapshot; Restoring from snapshot") tele.SnapshotKind = ateattr.SnapshotKindLocal @@ -694,6 +731,7 @@ func (w *ActorWorkflow) ensureAteletRestored(ctx context.Context, actorRef resou EgressGateway: egressGateway, CpuMilli: cpuMilli, MemoryBytes: memBytes, + SandboxAssets: sandboxAssets, } req.Type = ateletpb.CheckpointType_CHECKPOINT_TYPE_LOCAL req.Config = &ateletpb.RestoreRequest_LocalConfig{ @@ -723,6 +761,7 @@ func (w *ActorWorkflow) ensureAteletRestored(ctx context.Context, actorRef resou if actor.GetStatus().GetLatestSnapshot() != nil { tele.SnapshotKind = ateattr.SnapshotKindLatest } + // Same wire-scope derivation as the local branch above. var scope ateletpb.SnapshotScope var goldenSnapshotURI string switch { @@ -755,6 +794,7 @@ func (w *ActorWorkflow) ensureAteletRestored(ctx context.Context, actorRef resou EgressGateway: egressGateway, CpuMilli: cpuMilli, MemoryBytes: memBytes, + SandboxAssets: sandboxAssets, } _, err = client.Restore(ctx, req) return tele, maybeCrashActor(ctx, w.store, actorRef, err, "while restoring durable snapshot", ateattr.OperationResume) @@ -762,14 +802,6 @@ func (w *ActorWorkflow) ensureAteletRestored(ctx context.Context, actorRef resou slog.InfoContext(ctx, "Actor has no snapshot; ActorTemplate has no golden snapshot; Booting from ActorTemplate spec") tele.SnapshotKind = ateattr.SnapshotKindBoot - // Booting from scratch: resolve the sandbox binaries from the pool's - // SandboxConfig and send them so atelet can fetch and record them. - // (Restores above are self-describing via the snapshot manifest.) - sandboxAssets, err := resolveSandboxAssets(w.workerPoolLister, w.sandboxConfigLister, assignment.GetWorkerNamespace(), assignment.GetWorkerPool()) - if err != nil { - return tele, fmt.Errorf("while resolving sandbox assets: %w", err) - } - req := &ateletpb.RunRequest{ TargetAteomUid: assignment.GetWorkerPodUid(), Atespace: actor.GetMetadata().GetAtespace(), @@ -788,6 +820,31 @@ func (w *ActorWorkflow) ensureAteletRestored(ctx context.Context, actorRef resou } } +// resolveSandboxAssetsForResume picks the SandboxConfig for the pending +// boot: the replacement template's golden config when the actor was +// repointed, else the one recorded on the snapshot whose sandbox will run +// the restored guest (the golden's for a DATA_ON_GOLDEN restore, the actor's +// local or durable snapshot's otherwise). Boots from scratch, and snapshots +// recorded before the reference existed, fall back to the assigned pool's +// SandboxConfig. +func (w *ActorWorkflow) resolveSandboxAssetsForResume(actor *ateapipb.Actor, src resumeSnapshotSource, poolNamespace, poolName string) (*ateletpb.SandboxAssets, error) { + var ref *ateapipb.SandboxConfigRef + switch { + case src.TemplateReplaced: + ref = src.RepointSandboxConfigRef + case !src.GoldenSnapshotURI.IsZero(): + ref = src.GoldenSandboxConfigRef + case actor.GetStatus().GetLocalSnapshotInfo() != nil: + ref = actor.GetStatus().GetLocalSnapshotInfo().GetSandboxConfigRef() + default: + ref = src.SandboxConfigRef + } + if ref == nil { + return resolveSandboxAssets(w.workerPoolLister, w.sandboxConfigLister, poolNamespace, poolName) + } + return resolveSandboxAssetsByRef(w.sandboxConfigLister, ref) +} + func (w *ActorWorkflow) egressGateway() *ateletpb.EgressGateway { if w.egressGatewayAddress == "" { return nil diff --git a/cmd/ateapi/internal/controlapi/workflow_resume_test.go b/cmd/ateapi/internal/controlapi/workflow_resume_test.go index bd54e4bd8f..b267391507 100644 --- a/cmd/ateapi/internal/controlapi/workflow_resume_test.go +++ b/cmd/ateapi/internal/controlapi/workflow_resume_test.go @@ -28,10 +28,12 @@ import ( "github.com/agent-substrate/substrate/cmd/ateapi/internal/store/storetest" "github.com/agent-substrate/substrate/cmd/ateapi/internal/workercache" "github.com/agent-substrate/substrate/internal/resources" + atev1alpha1 "github.com/agent-substrate/substrate/pkg/api/v1alpha1" "github.com/agent-substrate/substrate/pkg/proto/ateapipb" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/proto" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) // TestSchedulerRecordable guards the retry-dedup rule: the assignment loop @@ -1233,6 +1235,61 @@ func TestLoadActorForResume_TemplateReplaced(t *testing.T) { } } +// TestLoadActorForResume_RepointResolvesGoldenSandboxConfigRef pins that a +// repointed actor's boot source carries the SandboxConfig recorded on the +// replacement template's golden ActorSnapshot, read from the snapshot itself. +func TestLoadActorForResume_RepointResolvesGoldenSandboxConfigRef(t *testing.T) { + ctx := context.Background() + actorRef := resources.ActorRef{Atespace: "team-a", Name: "id1"} + goldenRef := &ateapipb.SandboxConfigRef{Name: "gvisor-golden", Uid: "sandbox-uid-2"} + + persistence := newTestPersistence(t) + snap := storetest.MustCreateActorSnapshot(t, ctx, persistence, &ateapipb.ActorSnapshot{ + Metadata: &ateapipb.ResourceMetadata{Atespace: actorRef.Atespace, Name: "snap-1"}, + Status: &ateapipb.ActorSnapshotStatus{ + SourceActor: &ateapipb.ObjectRef{Atespace: actorRef.Atespace, Name: actorRef.Name}, + ActorTemplateUid: "replaced-uid", + ContentScope: ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_FULL, + SnapshotUri: "gs://bucket/root/snapshots/" + actorRef.Atespace + "/snap-1", + }, + }) + storetest.MustCreateActorSnapshot(t, ctx, persistence, &ateapipb.ActorSnapshot{ + Metadata: &ateapipb.ResourceMetadata{Atespace: resources.GoldenActorAtespace, Name: "golden-1"}, + Status: &ateapipb.ActorSnapshotStatus{ + ContentScope: ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_FULL, + SnapshotUri: "gs://bucket/golden-root/snapshots/ate-golden/golden-1", + SandboxConfigRef: goldenRef, + }, + }) + seedWorkflowActor(t, ctx, persistence, actorRef, "ns", "tmpl1", ateapipb.ActorState_ACTOR_STATE_SUSPENDED, func(a *ateapipb.Actor) { + a.Status.LatestSnapshot = &ateapipb.ObjectRef{Atespace: actorRef.Atespace, Name: snap.GetMetadata().GetName()} + }) + + storetest.MustCreateAtespace(t, ctx, persistence, "ns") + if _, err := persistence.CreateActorTemplate(ctx, &ateapipb.ActorTemplate{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "ns", Name: "tmpl1"}, + Status: &ateapipb.ActorTemplateStatus{ + GoldenSnapshotStatus: &ateapipb.GoldenSnapshotStatus{ + GoldenSnapshot: &ateapipb.ObjectRef{Atespace: resources.GoldenActorAtespace, Name: "golden-1"}, + }, + }, + }); err != nil { + t.Fatalf("create template: %v", err) + } + + w := &ActorWorkflow{store: persistence} + _, _, src, err := w.loadActorForResume(ctx, actorRef, false) + if err != nil { + t.Fatalf("loadActorForResume: %v", err) + } + if !src.TemplateReplaced { + t.Fatal("src.TemplateReplaced = false, want true") + } + if got := src.RepointSandboxConfigRef; got.GetName() != goldenRef.GetName() || got.GetUid() != goldenRef.GetUid() { + t.Errorf("src.RepointSandboxConfigRef = %s/%s, want %s/%s", got.GetName(), got.GetUid(), goldenRef.GetName(), goldenRef.GetUid()) + } +} + func TestLoadActorForResume_RunningActorShortCircuits(t *testing.T) { ctx := context.Background() persistence := newTestPersistence(t) @@ -1259,3 +1316,162 @@ func TestLoadActorForResume_RunningActorShortCircuits(t *testing.T) { t.Errorf("expected empty snapshot source, got %+v", src) } } + +// TestLoadActorForResume_CarriesSandboxConfigRefs pins that the SandboxConfig +// references recorded on the restored snapshots ride out on the resolved +// boot source. +func TestLoadActorForResume_CarriesSandboxConfigRefs(t *testing.T) { + ctx := context.Background() + actorRef := resources.ActorRef{Atespace: "team-a", Name: "id1"} + ownRef := &ateapipb.SandboxConfigRef{Name: "gvisor-prod", Uid: "sandbox-uid-1"} + goldenRef := &ateapipb.SandboxConfigRef{Name: "gvisor-golden", Uid: "sandbox-uid-2"} + + persistence := newTestPersistence(t) + snap := storetest.MustCreateActorSnapshot(t, ctx, persistence, &ateapipb.ActorSnapshot{ + Metadata: &ateapipb.ResourceMetadata{Atespace: actorRef.Atespace, Name: "snap-1"}, + Status: &ateapipb.ActorSnapshotStatus{ + SourceActor: &ateapipb.ObjectRef{Atespace: actorRef.Atespace, Name: actorRef.Name}, + ContentScope: ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_DATA, + SnapshotUri: "gs://bucket/root/snapshots/" + actorRef.Atespace + "/snap-1", + SandboxConfigRef: ownRef, + }, + }) + storetest.MustCreateActorSnapshot(t, ctx, persistence, &ateapipb.ActorSnapshot{ + Metadata: &ateapipb.ResourceMetadata{Atespace: resources.GoldenActorAtespace, Name: "golden-1"}, + Status: &ateapipb.ActorSnapshotStatus{ + ContentScope: ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_FULL, + SnapshotUri: "gs://bucket/golden-root/snapshots/ate-golden/golden-1", + SandboxConfigRef: goldenRef, + }, + }) + seedWorkflowActor(t, ctx, persistence, actorRef, "ns", "tmpl1", ateapipb.ActorState_ACTOR_STATE_SUSPENDED, func(a *ateapipb.Actor) { + a.Status.LatestSnapshot = &ateapipb.ObjectRef{Atespace: actorRef.Atespace, Name: snap.GetMetadata().GetName()} + }) + + storetest.MustCreateAtespace(t, ctx, persistence, "ns") + if _, err := persistence.CreateActorTemplate(ctx, &ateapipb.ActorTemplate{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "ns", Name: "tmpl1"}, + SnapshotsConfig: &ateapipb.SnapshotsConfig{ + OnResume: &ateapipb.OnResumeConfig{FromData: ateapipb.ResumeSource_RESUME_SOURCE_GOLDEN}, + }, + Status: &ateapipb.ActorTemplateStatus{ + GoldenSnapshotStatus: &ateapipb.GoldenSnapshotStatus{ + GoldenSnapshot: &ateapipb.ObjectRef{Atespace: resources.GoldenActorAtespace, Name: "golden-1"}, + }, + }, + }); err != nil { + t.Fatalf("create template: %v", err) + } + + w := &ActorWorkflow{store: persistence} + _, _, src, err := w.loadActorForResume(ctx, actorRef, false) + if err != nil { + t.Fatalf("loadActorForResume: %v", err) + } + if got := src.SandboxConfigRef; got.GetName() != ownRef.GetName() || got.GetUid() != ownRef.GetUid() { + t.Errorf("src.SandboxConfigRef = %s/%s, want %s/%s", got.GetName(), got.GetUid(), ownRef.GetName(), ownRef.GetUid()) + } + if got := src.GoldenSandboxConfigRef; got.GetName() != goldenRef.GetName() || got.GetUid() != goldenRef.GetUid() { + t.Errorf("src.GoldenSandboxConfigRef = %s/%s, want %s/%s", got.GetName(), got.GetUid(), goldenRef.GetName(), goldenRef.GetUid()) + } +} + +// TestResolveSandboxAssetsForResume pins which SandboxConfig a resume +// boots: the replacement template's golden config when repointed, else the +// one recorded on the snapshot whose sandbox runs the guest, else the +// pool's. +func TestResolveSandboxAssetsForResume(t *testing.T) { + ownConfig := &atev1alpha1.SandboxConfig{ + ObjectMeta: metav1.ObjectMeta{Name: "gvisor-own", UID: "own-uid"}, + Spec: atev1alpha1.SandboxConfigSpec{ + SandboxClass: atev1alpha1.SandboxClassGvisor, + PauseImage: "registry.k8s.io/pause@sha256:own", + Assets: testAssets(), + }, + } + goldenConfig := &atev1alpha1.SandboxConfig{ + ObjectMeta: metav1.ObjectMeta{Name: "gvisor-golden", UID: "golden-uid"}, + Spec: atev1alpha1.SandboxConfigSpec{ + SandboxClass: atev1alpha1.SandboxClassGvisor, + PauseImage: "registry.k8s.io/pause@sha256:golden", + Assets: testAssets(), + }, + } + poolConfig := &atev1alpha1.SandboxConfig{ + ObjectMeta: metav1.ObjectMeta{Name: "gvisor-pool", UID: "pool-uid"}, + Spec: atev1alpha1.SandboxConfigSpec{ + SandboxClass: atev1alpha1.SandboxClassGvisor, + Default: true, + PauseImage: "registry.k8s.io/pause@sha256:pool", + Assets: testAssets(), + }, + } + pool := &atev1alpha1.WorkerPool{ObjectMeta: metav1.ObjectMeta{Name: "pool1", Namespace: "worker-ns"}} + poolLister, configLister := listersFor(t, []*atev1alpha1.WorkerPool{pool}, + []*atev1alpha1.SandboxConfig{ownConfig, goldenConfig, poolConfig}) + w := &ActorWorkflow{workerPoolLister: poolLister, sandboxConfigLister: configLister} + + ownRef := &ateapipb.SandboxConfigRef{Name: "gvisor-own", Uid: "own-uid"} + goldenRef := &ateapipb.SandboxConfigRef{Name: "gvisor-golden", Uid: "golden-uid"} + goldenURI, err := resources.ParseSnapshotURI("gs://bucket/golden-root/snapshots/ate-golden/golden-1") + if err != nil { + t.Fatalf("ParseSnapshotURI: %v", err) + } + + tests := []struct { + name string + actor *ateapipb.Actor + src resumeSnapshotSource + wantName string + }{ + { + name: "repointed actor boots the replacement template's golden config", + actor: &ateapipb.Actor{}, + src: resumeSnapshotSource{TemplateReplaced: true, RepointSandboxConfigRef: goldenRef}, + wantName: "gvisor-golden", + }, + { + name: "repointed actor falls back to the pool when the new golden records none", + actor: &ateapipb.Actor{}, + src: resumeSnapshotSource{TemplateReplaced: true, SandboxConfigRef: ownRef}, + wantName: "gvisor-pool", + }, + { + name: "golden data restore boots the golden snapshot's config", + actor: &ateapipb.Actor{}, + src: resumeSnapshotSource{GoldenSnapshotURI: goldenURI, GoldenSandboxConfigRef: goldenRef, SandboxConfigRef: ownRef}, + wantName: "gvisor-golden", + }, + { + name: "local restore boots the pause snapshot's config", + actor: &ateapipb.Actor{Status: &ateapipb.ActorStatus{ + LocalSnapshotInfo: &ateapipb.LocalSnapshotInfo{SandboxConfigRef: ownRef}, + }}, + src: resumeSnapshotSource{}, + wantName: "gvisor-own", + }, + { + name: "durable restore boots the snapshot's own config", + actor: &ateapipb.Actor{}, + src: resumeSnapshotSource{SandboxConfigRef: ownRef}, + wantName: "gvisor-own", + }, + { + name: "no references fall back to the pool", + actor: &ateapipb.Actor{}, + src: resumeSnapshotSource{}, + wantName: "gvisor-pool", + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got, err := w.resolveSandboxAssetsForResume(tc.actor, tc.src, "worker-ns", "pool1") + if err != nil { + t.Fatalf("resolveSandboxAssetsForResume: %v", err) + } + if got.GetSandboxConfigRef().GetName() != tc.wantName { + t.Errorf("SandboxConfig = %q, want %q", got.GetSandboxConfigRef().GetName(), tc.wantName) + } + }) + } +} diff --git a/cmd/ateapi/internal/controlapi/workflow_suspend.go b/cmd/ateapi/internal/controlapi/workflow_suspend.go index 07f61d77be..91b0e9df92 100644 --- a/cmd/ateapi/internal/controlapi/workflow_suspend.go +++ b/cmd/ateapi/internal/controlapi/workflow_suspend.go @@ -78,10 +78,14 @@ func (w *ActorWorkflow) SuspendActor(ctx context.Context, actorRef resources.Act return nil, err } actor = marked + // sandboxConfigRef stays nil on the paused-origin path: no checkpoint runs + // there, and the finalize below reads the pause snapshot's recorded + // reference instead. + var sandboxConfigRef *ateapipb.SandboxConfigRef if fromPaused { wireSnapshotScope, err = w.ensurePausedSnapshotUploaded(leaseCtx, actorRef, actor, actorTemplate) } else { - wireSnapshotScope, err = w.ensureAteletSuspended(leaseCtx, actorRef, actor, actorTemplate) + wireSnapshotScope, sandboxConfigRef, err = w.ensureAteletSuspended(leaseCtx, actorRef, actor, actorTemplate) } if err != nil { return nil, err @@ -93,7 +97,7 @@ func (w *ActorWorkflow) SuspendActor(ctx context.Context, actorRef resources.Act // them here, as crash.go does for the crash counter. finalAttrs = lifecycleOpAttrs(actor, actorTemplate, "", wireSnapshotScope) var finalized *ateapipb.Actor - if finalized, err = w.ensureSuspendedFinalized(leaseCtx, actorRef, actorTemplate); err != nil { + if finalized, err = w.ensureSuspendedFinalized(leaseCtx, actorRef, actorTemplate, fromPaused, sandboxConfigRef); err != nil { return nil, err } actor = finalized @@ -204,7 +208,7 @@ func isPausedOriginSuspend(actor *ateapipb.Actor) bool { // once-minted snapshot location, so a re-entered workflow re-sends the same // semantic request; once atelet's Checkpoint is idempotent on those keys this // step becomes fully reentrant with no changes here. -func (w *ActorWorkflow) ensureAteletSuspended(ctx context.Context, actorRef resources.ActorRef, actor *ateapipb.Actor, actorTemplate *ateapipb.ActorTemplate) (wireSnapshotScope string, err error) { +func (w *ActorWorkflow) ensureAteletSuspended(ctx context.Context, actorRef resources.ActorRef, actor *ateapipb.Actor, actorTemplate *ateapipb.ActorTemplate) (wireSnapshotScope string, sandboxConfigRef *ateapipb.SandboxConfigRef, err error) { ctx, done := stepSpan(ctx, "CallAteletSuspend") defer func() { err = done(err) }() @@ -214,7 +218,7 @@ func (w *ActorWorkflow) ensureAteletSuspended(ctx context.Context, actorRef reso if err := crashActor(ctx, w.store, actorRef, ateattr.OperationSuspend, ateattr.ReasonCorruptedAssignment); err != nil { slog.ErrorContext(ctx, "Failed to crash actor", slog.String("err", err.Error())) } - return "", fmt.Errorf("actor is CRASHED because it was in SUSPENDING state but has no active worker") + return "", nil, fmt.Errorf("actor is CRASHED because it was in SUSPENDING state but has no active worker") } ateletConn, err := w.dialer.DialForWorker(assignment.GetWorkerNamespace(), assignment.GetWorkerPod()) @@ -224,25 +228,25 @@ func (w *ActorWorkflow) ensureAteletSuspended(ctx context.Context, actorRef reso if err := crashActor(ctx, w.store, actorRef, ateattr.OperationSuspend, ateattr.ReasonWorkerPodGone); err != nil { slog.ErrorContext(ctx, "Failed to crash actor", slog.String("err", err.Error())) } - return "", fmt.Errorf("actor is CRASHED because its worker pod is gone and no snapshot was written") + return "", nil, fmt.Errorf("actor is CRASHED because its worker pod is gone and no snapshot was written") } - return "", fmt.Errorf("while getting atelet conn for worker pod: %w", err) + return "", nil, fmt.Errorf("while getting atelet conn for worker pod: %w", err) } client := ateletpb.NewAteomHerderClient(ateletConn) workloadSpec, err := workloadSpecFromActorTemplate(actorTemplate, actor) if err != nil { - return "", err + return "", nil, err } snapshotURI, err := inProgressSnapshotURI(actorTemplate, actor.GetMetadata().GetAtespace(), actor.GetStatus().GetInProgressSnapshotName()) if err != nil { - return "", err + return "", nil, err } - // Checkpoint does not carry the sandbox config: atelet uses the version the - // actor is currently running (recorded on-node at Run/Restore) and pins it - // into the snapshot manifest. + // Checkpoint does not carry the sandbox config: atelet uses the version + // the actor is currently running (recorded on-node at Run/Restore) and + // pins its SandboxConfig reference into the snapshot manifest. req := &ateletpb.CheckpointRequest{ TargetAteomUid: assignment.GetWorkerPodUid(), Atespace: actor.GetMetadata().GetAtespace(), @@ -261,8 +265,8 @@ func (w *ActorWorkflow) ensureAteletSuspended(ctx context.Context, actorRef reso } wireSnapshotScope = ateattr.SnapshotScopeValue(req.Scope) - _, err = client.Checkpoint(ctx, req) - return wireSnapshotScope, maybeCrashActor(ctx, w.store, actorRef, err, "while checkpointing workload", ateattr.OperationSuspend) + resp, err := client.Checkpoint(ctx, req) + return wireSnapshotScope, sandboxConfigRefFromAtelet(resp.GetSandboxConfigRef()), maybeCrashActor(ctx, w.store, actorRef, err, "while checkpointing workload", ateattr.OperationSuspend) } // ensurePausedSnapshotUploaded suspends a PAUSED actor by telling the atelet @@ -343,7 +347,10 @@ func (w *ActorWorkflow) ensureVolumesDetached(ctx context.Context, actor *ateapi // single update. It re-reads the actor first so an out-of-band transition // (e.g. the syncer crashing the actor after its worker died) is not // overwritten: with no assignment left there is nothing to finalize. -func (w *ActorWorkflow) ensureSuspendedFinalized(ctx context.Context, actorRef resources.ActorRef, actorTemplate *ateapipb.ActorTemplate) (_ *ateapipb.Actor, err error) { +// fromPaused selects the new snapshot's SandboxConfig provenance: the pause +// snapshot's recorded reference when re-uploading its content, the +// checkpoint-reported sandboxConfigRef otherwise. +func (w *ActorWorkflow) ensureSuspendedFinalized(ctx context.Context, actorRef resources.ActorRef, actorTemplate *ateapipb.ActorTemplate, fromPaused bool, sandboxConfigRef *ateapipb.SandboxConfigRef) (_ *ateapipb.Actor, err error) { ctx, done := stepSpan(ctx, "FinalizeSuspended") defer func() { err = done(err) }() @@ -400,6 +407,12 @@ func (w *ActorWorkflow) ensureSuspendedFinalized(ctx context.Context, actorRef r if err != nil { return nil, err } + // A paused-origin suspend re-uploads the pause snapshot's content, so + // its recorded reference is the provenance; no checkpoint ran to + // report one. + if fromPaused { + sandboxConfigRef = latestActor.GetStatus().GetLocalSnapshotInfo().GetSandboxConfigRef() + } snapshot := &ateapipb.ActorSnapshot{ Metadata: &ateapipb.ResourceMetadata{Atespace: actorRef.Atespace, Name: snapshotName}, Status: &ateapipb.ActorSnapshotStatus{ @@ -410,6 +423,7 @@ func (w *ActorWorkflow) ensureSuspendedFinalized(ctx context.Context, actorRef r ActorTemplateUid: actorTemplate.GetMetadata().GetUid(), ContentScope: commitSnapshotScope(actorRef.Atespace, actorTemplate), SnapshotUri: snapshotURI.String(), + SandboxConfigRef: sandboxConfigRef, }, } // ErrAlreadyExists means a previous attempt crashed after creating diff --git a/cmd/ateapi/internal/controlapi/workflow_suspend_test.go b/cmd/ateapi/internal/controlapi/workflow_suspend_test.go index e7dfdf659a..66370a301b 100644 --- a/cmd/ateapi/internal/controlapi/workflow_suspend_test.go +++ b/cmd/ateapi/internal/controlapi/workflow_suspend_test.go @@ -256,7 +256,7 @@ func TestEnsureAteletSuspended_DanglingWorkerDoesNotRecordPhantomSnapshot(t *tes created := storetest.MustCreateActor(t, ctx, persistence, actor) w := &ActorWorkflow{store: persistence, dialer: newDanglingDialer()} - if _, err := w.ensureAteletSuspended(ctx, resources.ActorRef{Atespace: "team-a", Name: "actor-1"}, created, &ateapipb.ActorTemplate{}); err == nil { + if _, _, err := w.ensureAteletSuspended(ctx, resources.ActorRef{Atespace: "team-a", Name: "actor-1"}, created, &ateapipb.ActorTemplate{}); err == nil { t.Fatal("ensureAteletSuspended: want error for dangling worker, got nil") } @@ -308,7 +308,7 @@ func TestEnsureSuspendedFinalized_NoAssignment(t *testing.T) { w := &ActorWorkflow{store: persistence} tmpl := &ateapipb.ActorTemplate{SnapshotsConfig: &ateapipb.SnapshotsConfig{StorageLocation: "gs://snapshots"}} - stored, err := w.ensureSuspendedFinalized(ctx, resources.ActorRef{Atespace: "team-a", Name: "actor-1"}, tmpl) + stored, err := w.ensureSuspendedFinalized(ctx, resources.ActorRef{Atespace: "team-a", Name: "actor-1"}, tmpl, false, nil) if err != nil { t.Fatalf("ensureSuspendedFinalized: %v", err) } @@ -364,7 +364,7 @@ func TestEnsureSuspendedFinalized_StampsSubstrateTemplateRef(t *testing.T) { }) w := &ActorWorkflow{store: persistence} - if _, err := w.ensureSuspendedFinalized(ctx, resources.ActorRef{Atespace: "team-a", Name: "actor-1"}, template); err != nil { + if _, err := w.ensureSuspendedFinalized(ctx, resources.ActorRef{Atespace: "team-a", Name: "actor-1"}, template, false, nil); err != nil { t.Fatalf("ensureSuspendedFinalized: %v", err) } @@ -449,7 +449,7 @@ func TestEnsureSuspendedFinalized_ReleasesOnlyOwnWorker(t *testing.T) { w := &ActorWorkflow{store: persistence} tmpl := &ateapipb.ActorTemplate{SnapshotsConfig: &ateapipb.SnapshotsConfig{StorageLocation: "gs://bucket/root"}} - if _, err := w.ensureSuspendedFinalized(ctx, resources.ActorRef{Atespace: "team-a", Name: "shared"}, tmpl); err != nil { + if _, err := w.ensureSuspendedFinalized(ctx, resources.ActorRef{Atespace: "team-a", Name: "shared"}, tmpl, false, nil); err != nil { t.Fatalf("ensureSuspendedFinalized: %v", err) } @@ -490,7 +490,7 @@ func TestEnsureSuspendedFinalized_SnapshotSourceActorVersion(t *testing.T) { w := &ActorWorkflow{store: persistence} tmpl := &ateapipb.ActorTemplate{SnapshotsConfig: &ateapipb.SnapshotsConfig{StorageLocation: "gs://snapshots"}} - final, err := w.ensureSuspendedFinalized(ctx, resources.ActorRef{Atespace: "team-a", Name: "actor-1"}, tmpl) + final, err := w.ensureSuspendedFinalized(ctx, resources.ActorRef{Atespace: "team-a", Name: "actor-1"}, tmpl, false, &ateapipb.SandboxConfigRef{Name: "gvisor-prod", Uid: "sandbox-uid-1"}) if err != nil { t.Fatalf("ensureSuspendedFinalized: %v", err) } @@ -508,6 +508,11 @@ func TestEnsureSuspendedFinalized_SnapshotSourceActorVersion(t *testing.T) { if got := snap.GetStatus().GetSourceActorVersion(); got != 42 { t.Errorf("SourceActorVersion = %d, want 42", got) } + // The actor's SandboxConfig reference (recorded at resume) rides onto the + // snapshot, where a later restore resolves its assets from it. + if ref := snap.GetStatus().GetSandboxConfigRef(); ref.GetName() != "gvisor-prod" || ref.GetUid() != "sandbox-uid-1" { + t.Errorf("snapshot SandboxConfigRef = %s/%s, want gvisor-prod/sandbox-uid-1", ref.GetName(), ref.GetUid()) + } } // TestCommitSnapshotScope verifies golden actors always commit Full — the @@ -709,3 +714,41 @@ func TestSuspendActor_PausedWithoutLocalSnapshotCrashes(t *testing.T) { t.Errorf("stored state = %v, want %v", got.GetStatus().GetState(), ateapipb.ActorState_ACTOR_STATE_CRASHED) } } + +// TestEnsureSuspendedFinalized_PausedOriginSandboxConfigRef pins that a +// paused-origin suspend carries the pause snapshot's own SandboxConfig +// reference onto the ActorSnapshot, not a checkpoint-reported one (no +// checkpoint runs on that path). +func TestEnsureSuspendedFinalized_PausedOriginSandboxConfigRef(t *testing.T) { + ctx := context.Background() + persistence := newTestPersistence(t) + const snapshotName = "2026-01-01t00-00-00z-abc" + storetest.MustCreateActor(t, ctx, persistence, &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "actor-1"}, + Status: &ateapipb.ActorStatus{ + State: ateapipb.ActorState_ACTOR_STATE_SUSPENDING, + InProgressSnapshotName: snapshotName, + LocalSnapshotInfo: &ateapipb.LocalSnapshotInfo{ + SnapshotName: "pause-snap-1", + SandboxConfigRef: &ateapipb.SandboxConfigRef{Name: "gvisor-at-pause", Uid: "sandbox-uid-pause"}, + }, + }, + }) + + w := &ActorWorkflow{store: persistence} + tmpl := &ateapipb.ActorTemplate{SnapshotsConfig: &ateapipb.SnapshotsConfig{StorageLocation: "gs://snapshots"}} + // A non-nil reference is passed deliberately: the paused-origin path + // must ignore it in favor of the pause snapshot's recorded one. + final, err := w.ensureSuspendedFinalized(ctx, resources.ActorRef{Atespace: "team-a", Name: "actor-1"}, tmpl, true, &ateapipb.SandboxConfigRef{Name: "gvisor-later", Uid: "sandbox-uid-later"}) + if err != nil { + t.Fatalf("ensureSuspendedFinalized: %v", err) + } + + snap, err := persistence.GetActorSnapshot(ctx, resources.ActorSnapshotRef{Atespace: "team-a", Name: final.GetStatus().GetLatestSnapshot().GetName()}) + if err != nil { + t.Fatalf("GetActorSnapshot: %v", err) + } + if ref := snap.GetStatus().GetSandboxConfigRef(); ref.GetName() != "gvisor-at-pause" || ref.GetUid() != "sandbox-uid-pause" { + t.Errorf("snapshot SandboxConfigRef = %s/%s, want the pause snapshot's gvisor-at-pause/sandbox-uid-pause", ref.GetName(), ref.GetUid()) + } +} diff --git a/cmd/ateapi/internal/controlapi/zz_generated.validation.go b/cmd/ateapi/internal/controlapi/zz_generated.validation.go index 4fffe646e4..996093d000 100644 --- a/cmd/ateapi/internal/controlapi/zz_generated.validation.go +++ b/cmd/ateapi/internal/controlapi/zz_generated.validation.go @@ -4380,6 +4380,36 @@ func Validate_LocalSnapshotInfo( errs = append(errs, fn(fldPath.Child("content_scope"), &obj.ContentScope, oldVal, oldObj != nil)...) } + { // field ateapipb.LocalSnapshotInfo.SandboxConfigRef + fn := func( + fldPath *field.Path, + obj, oldObj *ateapipb.SandboxConfigRef, + 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_SandboxConfigRef(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.LocalSnapshotInfo) *ateapipb.SandboxConfigRef { + return oldObj.SandboxConfigRef + }) + errs = append(errs, fn(fldPath.Child("sandbox_config_ref"), obj.SandboxConfigRef, oldVal, oldObj != nil)...) + } + return errs } @@ -5295,6 +5325,108 @@ func Validate_SandboxConfig( return errs } +// Validate_SandboxConfigRef validates an instance of SandboxConfigRef according +// to declarative validation rules in the API schema. +func Validate_SandboxConfigRef( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *ateapipb.SandboxConfigRef) (errs field.ErrorList) { + + { // field ateapipb.SandboxConfigRef.Name + fn := func( + fldPath *field.Path, + obj, oldObj *string, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + if e := validate.LongName(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.SandboxConfigRef) *string { + return &oldObj.Name + }) + errs = append(errs, fn(fldPath.Child("name"), &obj.Name, oldVal, oldObj != nil)...) + } + + { // field ateapipb.SandboxConfigRef.Uid + 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.UUID(ctx, op, fldPath, obj, oldObj); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.SandboxConfigRef) *string { + return &oldObj.Uid + }) + errs = append(errs, fn(fldPath.Child("uid"), &obj.Uid, oldVal, oldObj != nil)...) + } + + { // field ateapipb.SandboxConfigRef.ResourceVersion + 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 + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.SandboxConfigRef) *string { + return &oldObj.ResourceVersion + }) + errs = append(errs, fn(fldPath.Child("resource_version"), &obj.ResourceVersion, oldVal, oldObj != nil)...) + } + + return errs +} + // Validate_SecurityContext validates an instance of SecurityContext according // to declarative validation rules in the API schema. func Validate_SecurityContext( diff --git a/cmd/atelet/lifecycle_test.go b/cmd/atelet/lifecycle_test.go index 6dc93454ca..144d6b4b33 100644 --- a/cmd/atelet/lifecycle_test.go +++ b/cmd/atelet/lifecycle_test.go @@ -15,8 +15,10 @@ package main import ( + "bytes" "context" "crypto/sha256" + "encoding/json" "fmt" "net" "os" @@ -28,6 +30,8 @@ import ( "github.com/agent-substrate/substrate/internal/proto/ateletpb" "github.com/agent-substrate/substrate/internal/proto/ateompb" "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) // useTempNodeDirs roots atelet's on-node state in temp directories so a test @@ -156,6 +160,7 @@ func TestLocalSnapshotGC(t *testing.T) { }, }}, }, + SandboxConfigRef: &ateletpb.SandboxConfigRef{Name: "gvisor-prod", Uid: "sandbox-uid-1", ResourceVersion: "42"}, } spec := &ateletpb.WorkloadSpec{ Containers: []*ateletpb.Container{{Name: "app", Image: image, Command: []string{"/bin/app"}}}, @@ -174,8 +179,18 @@ func TestLocalSnapshotGC(t *testing.T) { t.Fatalf("Run: %v", err) } + // Run records the sandbox assets (with their SandboxConfig reference) + // on-node; Checkpoint and Terminate read them back from there. + rec, err := readSandboxRecord(actorUID) + if err != nil { + t.Fatalf("Run left no readable on-node sandbox record: %v", err) + } + if want := (sandboxConfigRef{Name: "gvisor-prod", UID: "sandbox-uid-1", ResourceVersion: "42"}); rec.SandboxConfigRef != want { + t.Errorf("record SandboxConfig ref = %+v, want %+v", rec.SandboxConfigRef, want) + } + // Pause: a local checkpoint, which leaves the snapshot on this node. - if _, err := s.Checkpoint(ctx, &ateletpb.CheckpointRequest{ + checkpointResp, err := s.Checkpoint(ctx, &ateletpb.CheckpointRequest{ Atespace: atespace, ActorName: actorName, ActorUid: actorUID, @@ -188,15 +203,40 @@ func TestLocalSnapshotGC(t *testing.T) { Config: &ateletpb.CheckpointRequest_LocalConfig{ LocalConfig: &ateletpb.LocalCheckpointConfiguration{SnapshotName: snapshotName}, }, - }); err != nil { + }) + if err != nil { t.Fatalf("Checkpoint: %v", err) } + // The checkpoint reports the on-node record's SandboxConfig reference so + // the control plane can stamp it on the snapshot record it finalizes. + if got := checkpointResp.GetSandboxConfigRef(); got.GetName() != "gvisor-prod" || got.GetUid() != "sandbox-uid-1" || got.GetResourceVersion() != "42" { + t.Errorf("Checkpoint response SandboxConfig ref = %s/%s@%s, want gvisor-prod/sandbox-uid-1@42", got.GetName(), got.GetUid(), got.GetResourceVersion()) + } snapshotFile := filepath.Join(ateompath.LocalSnapshotDir(actorUID, snapshotName), "checkpoint.img") if _, err := os.Stat(snapshotFile); err != nil { t.Fatalf("pause did not write the local snapshot: %v", err) } - // Resume: restores from that local snapshot. + // The pause manifest carries the SandboxConfig reference, not the assets. + manifest, err := os.ReadFile(filepath.Join(ateompath.LocalSnapshotDir(actorUID, snapshotName), sandboxManifestName)) + if err != nil { + t.Fatalf("reading pause manifest: %v", err) + } + for _, key := range []string{`"assets"`, `"pauseImage"`} { + if bytes.Contains(manifest, []byte(key)) { + t.Errorf("pause manifest contains %s: %s", key, manifest) + } + } + man, err := unmarshalSandboxManifest(manifest) + if err != nil { + t.Fatalf("parsing pause manifest: %v", err) + } + if want := (&sandboxConfigRef{Name: "gvisor-prod", UID: "sandbox-uid-1", ResourceVersion: "42"}); man.SandboxConfigRef == nil || *man.SandboxConfigRef != *want { + t.Errorf("pause manifest SandboxConfig ref = %+v, want %+v", man.SandboxConfigRef, want) + } + + // Resume: restores from that local snapshot, with the sandbox assets + // resolved and sent by the control plane. if _, err := s.Restore(ctx, &ateletpb.RestoreRequest{ Atespace: atespace, ActorName: actorName, @@ -210,6 +250,7 @@ func TestLocalSnapshotGC(t *testing.T) { Config: &ateletpb.RestoreRequest_LocalConfig{ LocalConfig: &ateletpb.LocalCheckpointConfiguration{SnapshotName: snapshotName}, }, + SandboxAssets: sandboxAssets, }); err != nil { t.Fatalf("Restore: %v", err) } @@ -236,3 +277,144 @@ func TestLocalSnapshotGC(t *testing.T) { t.Errorf("local checkpoint dir survived terminate (stat err = %v), leaked files: %v", err, leaked) } } + +// TestRestoreSandboxAssetsSource pins that Restore takes its sandbox assets +// only from the request — verified against the manifest's SandboxConfig +// reference — and rejects requests without them. +func TestRestoreSandboxAssetsSource(t *testing.T) { + useTempNodeDirs(t) + ctx := t.Context() + + const ( + atespace = "ate-demo" + actorName = "counter" + actorUID = "actor-uid-1" + ateomUID = "ateom-uid-1" + snapshotName = "pause-snap-1" + ) + + ateom := &fakeAteom{snapshotFiles: map[string]string{"checkpoint.img": "guest-memory"}} + serveFakeAteom(t, ateom) + + host := imageVolumeTestRegistry(t) + image := host + "/actor:v1" + pushTestImage(t, image, singleFileLayer(t, "bin/app", "app")) + + runsc := []byte("runsc binary") + s := &AteomHerder{ + ateomDialer: newAteomDialer(1), + imageCache: newImageVolumeStore(t), + anonGCSClient: fakeObjectStorage{data: runsc}, + } + assetFiles := map[string]*ateletpb.AssetFile{ + runscAssetName: { + Url: "gs://test-bucket/runsc", + Sha256: fmt.Sprintf("%x", sha256.Sum256(runsc)), + }, + } + sandboxAssets := &ateletpb.SandboxAssets{ + SandboxClass: "gvisor", + PauseImage: image, + Assets: map[string]*ateletpb.ArchAssets{runtime.GOARCH: {Files: assetFiles}}, + SandboxConfigRef: &ateletpb.SandboxConfigRef{Name: "gvisor-prod", Uid: "sandbox-uid-1", ResourceVersion: "42"}, + } + spec := &ateletpb.WorkloadSpec{ + Containers: []*ateletpb.Container{{Name: "app", Image: image, Command: []string{"/bin/app"}}}, + } + + // Run + pause to lay a local snapshot (with an asset-less manifest) out + // on the node. + if _, err := s.Run(ctx, &ateletpb.RunRequest{ + Atespace: atespace, ActorName: actorName, ActorUid: actorUID, + ActorTemplateAtespace: "default", ActorTemplateName: "counter", + TargetAteomUid: ateomUID, SandboxAssets: sandboxAssets, Spec: spec, + }); err != nil { + t.Fatalf("Run: %v", err) + } + if _, err := s.Checkpoint(ctx, &ateletpb.CheckpointRequest{ + Atespace: atespace, ActorName: actorName, ActorUid: actorUID, + ActorTemplateAtespace: "default", ActorTemplateName: "counter", + TargetAteomUid: ateomUID, Spec: spec, + Scope: ateletpb.SnapshotScope_SNAPSHOT_SCOPE_FULL, + Type: ateletpb.CheckpointType_CHECKPOINT_TYPE_LOCAL, + Config: &ateletpb.CheckpointRequest_LocalConfig{ + LocalConfig: &ateletpb.LocalCheckpointConfiguration{SnapshotName: snapshotName}, + }, + }); err != nil { + t.Fatalf("Checkpoint: %v", err) + } + + manifestPath := filepath.Join(ateompath.LocalSnapshotDir(actorUID, snapshotName), sandboxManifestName) + strippedManifest, err := os.ReadFile(manifestPath) + if err != nil { + t.Fatalf("reading pause manifest: %v", err) + } + writeManifest := func(t *testing.T, man *snapshotManifest) { + t.Helper() + b, err := json.Marshal(man) + if err != nil { + t.Fatal(err) + } + if err := os.WriteFile(manifestPath, b, 0o600); err != nil { + t.Fatal(err) + } + } + restoreReq := func(sa *ateletpb.SandboxAssets) *ateletpb.RestoreRequest { + return &ateletpb.RestoreRequest{ + Atespace: atespace, ActorName: actorName, ActorUid: actorUID, + ActorTemplateAtespace: "default", ActorTemplateName: "counter", + TargetAteomUid: ateomUID, Spec: spec, + Scope: ateletpb.SnapshotScope_SNAPSHOT_SCOPE_FULL, + Type: ateletpb.CheckpointType_CHECKPOINT_TYPE_LOCAL, + Config: &ateletpb.RestoreRequest_LocalConfig{ + LocalConfig: &ateletpb.LocalCheckpointConfiguration{SnapshotName: snapshotName}, + }, + SandboxAssets: sa, + } + } + + t.Run("request without sandbox_assets is rejected outright", func(t *testing.T) { + _, err := s.Restore(ctx, restoreReq(nil)) + if got := status.Code(err); got != codes.InvalidArgument { + t.Fatalf("status.Code = %v (err %v), want InvalidArgument", got, err) + } + }) + + t.Run("request assets restore the snapshot", func(t *testing.T) { + if _, err := s.Restore(ctx, restoreReq(sandboxAssets)); err != nil { + t.Fatalf("Restore: %v", err) + } + }) + + t.Run("manifest ref mismatch is rejected", func(t *testing.T) { + man, err := unmarshalSandboxManifest(strippedManifest) + if err != nil { + t.Fatal(err) + } + man.SandboxConfigRef.UID = "some-other-uid" + writeManifest(t, man) + _, err = s.Restore(ctx, restoreReq(sandboxAssets)) + if got := status.Code(err); got != codes.FailedPrecondition { + t.Fatalf("status.Code = %v (err %v), want FailedPrecondition", got, err) + } + }) + + t.Run("old-format manifest assets are never read back", func(t *testing.T) { + // An old-format manifest still carries the asset set, but the type no + // longer declares those keys, so an asset-less request must still fail. + legacy := fmt.Sprintf(`{"sandboxClass":"gvisor","pauseImage":%q,"assets":{%q:{"url":"gs://test-bucket/runsc","sha256":"%x"}},"snapshotFiles":["checkpoint.img"],"scope":"full"}`, + image, runscAssetName, sha256.Sum256(runsc)) + if err := os.WriteFile(manifestPath, []byte(legacy), 0o600); err != nil { + t.Fatal(err) + } + _, err := s.Restore(ctx, restoreReq(nil)) + if got := status.Code(err); got != codes.InvalidArgument { + t.Fatalf("status.Code = %v (err %v), want InvalidArgument", got, err) + } + // With request assets the same old-format snapshot restores fine (it + // records no SandboxConfig reference, so there is nothing to match). + if _, err := s.Restore(ctx, restoreReq(sandboxAssets)); err != nil { + t.Fatalf("Restore of old-format snapshot with request assets: %v", err) + } + }) +} diff --git a/cmd/atelet/main.go b/cmd/atelet/main.go index 18d9632883..bd039aa8c8 100644 --- a/cmd/atelet/main.go +++ b/cmd/atelet/main.go @@ -472,8 +472,8 @@ func (s *AteomHerder) Run(ctx context.Context, req *ateletpb.RunRequest) (resp * } // Record the sandbox binaries this actor is running so a later Checkpoint - // (whose request no longer carries the sandbox config) can re-fetch the same - // version and pin it into the snapshot manifest. + // (whose request carries no sandbox config) can re-fetch the same version + // and pin its SandboxConfig reference into the snapshot manifest. if err := writeSandboxRecord(actorUID, sandboxRec); err != nil { return nil, fmt.Errorf("while recording sandbox assets: %w", err) } @@ -580,10 +580,10 @@ func (s *AteomHerder) Checkpoint(ctx context.Context, req *ateletpb.CheckpointRe phase{ateattr.SnapshotPhaseTotal, time.Since(tStart)}) }() - // Checkpoint requests no longer carry the sandbox config; recover the - // version this actor was started with from the on-node record and re-fetch - // it (a cache hit) so ateom can drive runsc, and so we can pin it into the - // snapshot manifest below. + // Checkpoint requests carry no sandbox config; recover the version this + // actor was started with from the on-node record and re-fetch it (a cache + // hit) so ateom can drive runsc. The manifest written below records the + // record's SandboxConfig reference only, never asset content. sandboxRec, err := readSandboxRecord(actorUID) if err != nil { return nil, ateerrors.CrashIfReason(ctx, err, ateerrors.ReasonInvalidSandboxAsset, ateerrors.ReasonTerminalFileSystemError) @@ -633,16 +633,24 @@ func (s *AteomHerder) Checkpoint(ctx context.Context, req *ateletpb.CheckpointRe return nil, fmt.Errorf("while calling ateom.CheckpointWorkload: %w", err) } - sandboxRec.SnapshotFiles = resp.GetSnapshotFiles() - if len(sandboxRec.SnapshotFiles) == 0 && shouldHaveSnapshots(req) { + // The manifest written beside the snapshot: identity, files, scope, and + // the SandboxConfig reference — never asset content. + man := &snapshotManifest{ + SandboxClass: sandboxRec.SandboxClass, + Atespace: req.GetAtespace(), + ActorName: req.GetActorName(), + ActorUID: req.GetActorUid(), + ActorTemplateAtespace: req.GetActorTemplateAtespace(), + ActorTemplateName: req.GetActorTemplateName(), + SnapshotFiles: resp.GetSnapshotFiles(), + Scope: ateattr.SnapshotScopeValue(req.GetScope()), + } + if ref := sandboxRec.SandboxConfigRef; ref.Name != "" || ref.UID != "" { + man.SandboxConfigRef = &ref + } + if len(man.SnapshotFiles) == 0 && shouldHaveSnapshots(req) { return nil, ateerrors.NewGRPCError(ctx, codes.DataLoss, ateerrors.ReasonInvalidCheckpointResult, ateerrors.ActorCrashedMetadata(), errors.New("ateom reported no snapshot files for checkpoint")) } - sandboxRec.Atespace = req.GetAtespace() - sandboxRec.ActorName = req.GetActorName() - sandboxRec.ActorUID = req.GetActorUid() - sandboxRec.ActorTemplateAtespace = req.GetActorTemplateAtespace() - sandboxRec.ActorTemplateName = req.GetActorTemplateName() - sandboxRec.Scope = ateattr.SnapshotScopeValue(req.GetScope()) // No earlier pause snapshot can ever be restored again, so remove them // all: the actor's current state was just captured by CheckpointWorkload, @@ -661,13 +669,13 @@ func (s *AteomHerder) Checkpoint(ctx context.Context, req *ateletpb.CheckpointRe switch req.GetType() { case ateletpb.CheckpointType_CHECKPOINT_TYPE_EXTERNAL: // TODO(#362): Because we do not cache the external snapshot files when upload fails, we have to mark the Actor as CRASHED. - if err := s.uploadExternalCheckpoint(ctx, req, checkpointDir, sandboxRec); err != nil { + if err := s.uploadExternalCheckpoint(ctx, req, checkpointDir, man); err != nil { dPersist = time.Since(tPersist) op.failedPhase = ateattr.SnapshotPhasePersist return nil, ateerrors.NewGRPCError(ctx, codes.DataLoss, ateerrors.ReasonFaileSaveSnapshot, ateerrors.ActorCrashedMetadata(), fmt.Errorf("%w: while uploading external snapshot: %w", ateerrors.ReasonFaileSaveSnapshot, err)) } case ateletpb.CheckpointType_CHECKPOINT_TYPE_LOCAL: - if err := s.moveLocalCheckpoint(ctx, req, checkpointDir, sandboxRec); err != nil { + if err := s.moveLocalCheckpoint(ctx, req, checkpointDir, man); err != nil { dPersist = time.Since(tPersist) op.failedPhase = ateattr.SnapshotPhasePersist return nil, ateerrors.NewGRPCError(ctx, codes.DataLoss, ateerrors.ReasonFaileSaveSnapshot, ateerrors.ActorCrashedMetadata(), fmt.Errorf("%w: while moving to local snapshot: %w", ateerrors.ReasonFaileSaveSnapshot, err)) @@ -686,7 +694,18 @@ func (s *AteomHerder) Checkpoint(ctx context.Context, req *ateletpb.CheckpointRe return nil, fmt.Errorf("while resetting actor dirs: %w", err) } - return &ateletpb.CheckpointResponse{}, nil + // Report the SandboxConfig reference the checkpoint was taken with (the + // on-node record's, as pinned into the manifest) so the control plane can + // copy it onto the snapshot record it finalizes. + checkpointResp := &ateletpb.CheckpointResponse{} + if ref := sandboxRec.SandboxConfigRef; ref.Name != "" || ref.UID != "" { + checkpointResp.SandboxConfigRef = &ateletpb.SandboxConfigRef{ + Name: ref.Name, + Uid: ref.UID, + ResourceVersion: ref.ResourceVersion, + } + } + return checkpointResp, nil } func toAteomSnapshotScope(scope ateletpb.SnapshotScope) ateompb.SnapshotScope { @@ -701,14 +720,14 @@ func toAteomSnapshotScope(scope ateletpb.SnapshotScope) ateompb.SnapshotScope { } } -func (s *AteomHerder) moveLocalCheckpoint(ctx context.Context, req *ateletpb.CheckpointRequest, checkpointDir string, rec *sandboxAssetsRecord) error { +func (s *AteomHerder) moveLocalCheckpoint(ctx context.Context, req *ateletpb.CheckpointRequest, checkpointDir string, man *snapshotManifest) error { localCheckpointPath := ateompath.LocalSnapshotDir(req.GetActorUid(), req.GetLocalConfig().GetSnapshotName()) if err := os.MkdirAll(localCheckpointPath, 0o700); err != nil { return fmt.Errorf("while creating local checkpoint directory: %w", err) } // Move exactly the files ateom reported. - for _, fileName := range rec.SnapshotFiles { + for _, fileName := range man.SnapshotFiles { src := filepath.Join(checkpointDir, fileName) dst := filepath.Join(localCheckpointPath, fileName) recordSnapshotSize(ctx, fileName, src, req.GetActorTemplateAtespace(), req.GetActorTemplateName()) @@ -718,8 +737,8 @@ func (s *AteomHerder) moveLocalCheckpoint(ctx context.Context, req *ateletpb.Che } } - // Write the self-describing snapshot manifest beside the images. - manifest, err := json.Marshal(rec) + // Write the snapshot manifest beside the images. + manifest, err := json.Marshal(man) if err != nil { return fmt.Errorf("while marshaling snapshot manifest: %w", err) } @@ -744,23 +763,23 @@ func shouldHaveSnapshots(req *ateletpb.CheckpointRequest) bool { return false } -func (s *AteomHerder) uploadExternalCheckpoint(ctx context.Context, req *ateletpb.CheckpointRequest, checkpointDir string, rec *sandboxAssetsRecord) error { +func (s *AteomHerder) uploadExternalCheckpoint(ctx context.Context, req *ateletpb.CheckpointRequest, checkpointDir string, man *snapshotManifest) error { uri, err := resources.ParseSnapshotURI(req.GetExternalConfig().GetSnapshotUri()) if err != nil { return err } - return s.uploadSnapshot(ctx, uri, checkpointDir, rec, req.GetActorTemplateAtespace(), req.GetActorTemplateName()) + return s.uploadSnapshot(ctx, uri, checkpointDir, man, req.GetActorTemplateAtespace(), req.GetActorTemplateName()) } -// uploadSnapshot uploads rec's snapshot files from srcDir to uri (each -// zstd-compressed, concurrently), then the marshaled manifest. The manifest -// goes last, never in parallel: its presence is the commit marker — readers -// assume every file it lists is already present. A crash mid-upload thus -// leaves only orphaned files, never a manifest pointing at files that never -// landed; retries overwrite the deterministic object names. -func (s *AteomHerder) uploadSnapshot(ctx context.Context, uri resources.SnapshotURI, srcDir string, rec *sandboxAssetsRecord, templateAtespace, templateName string) error { +// uploadSnapshot uploads the manifest's snapshot files from srcDir to uri +// (each zstd-compressed, concurrently), then the marshaled manifest. The +// manifest goes last, never in parallel: its presence is the commit marker — +// readers assume every file it lists is already present. A crash mid-upload +// thus leaves only orphaned files, never a manifest pointing at files that +// never landed; retries overwrite the deterministic object names. +func (s *AteomHerder) uploadSnapshot(ctx context.Context, uri resources.SnapshotURI, srcDir string, man *snapshotManifest, templateAtespace, templateName string) error { g, gCtx := errgroup.WithContext(ctx) - for _, fileName := range rec.SnapshotFiles { + for _, fileName := range man.SnapshotFiles { local := filepath.Join(srcDir, fileName) recordSnapshotSize(ctx, fileName, local, templateAtespace, templateName) g.Go(func() error { @@ -778,7 +797,7 @@ func (s *AteomHerder) uploadSnapshot(ctx context.Context, uri resources.Snapshot return err } - manifest, err := json.Marshal(rec) + manifest, err := json.Marshal(man) if err != nil { return fmt.Errorf("while marshaling snapshot manifest: %w", err) } @@ -873,7 +892,7 @@ func (s *AteomHerder) uploadLocalCheckpointDir(ctx context.Context, req *ateletp return "", wrapFileSystemErr("while reading local snapshot manifest", err) } - rec, err := unmarshalSandboxRecord(manifest) + rec, err := unmarshalSandboxManifest(manifest) if err != nil { return "", ateerrors.CrashIfReason(ctx, err, ateerrors.ReasonInvalidSandboxAsset) } @@ -899,25 +918,25 @@ func (s *AteomHerder) uploadLocalCheckpointDir(ctx context.Context, req *ateletp return rec.SandboxClass, s.uploadSnapshot(ctx, uri, localDir, rec, req.GetActorTemplateAtespace(), req.GetActorTemplateName()) } -// narrowFullCaptureToData rewrites rec so a FULL capture uploads as a DATA -// snapshot. Each sandbox class owns one branch: micro-VM durable data is a -// self-contained tar that can be carved out of the full file set; gVisor's +// narrowFullCaptureToData rewrites the manifest so a FULL capture uploads as +// a DATA snapshot. Each sandbox class owns one branch: micro-VM durable data +// is a self-contained tar that can be carved out of the full file set; gVisor's // full checkpoint is monolithic until split checkpoints land. -func narrowFullCaptureToData(rec *sandboxAssetsRecord) error { - switch atev1alpha1.SandboxClass(rec.SandboxClass) { +func narrowFullCaptureToData(man *snapshotManifest) error { + switch atev1alpha1.SandboxClass(man.SandboxClass) { case atev1alpha1.SandboxClassMicroVM, atev1alpha1.SandboxClassGvisor: - if !slices.Contains(rec.SnapshotFiles, ateompath.DurableDirTarFile) { + if !slices.Contains(man.SnapshotFiles, ateompath.DurableDirTarFile) { // No durable-dir volumes were attached at pause: this snapshot // holds no data, and never will — not retryable. - return status.Errorf(codes.FailedPrecondition, "full %s capture has no %s; the actor has no durable data to upload as %s", rec.SandboxClass, ateompath.DurableDirTarFile, ateattr.SnapshotScopeData) + return status.Errorf(codes.FailedPrecondition, "full %s capture has no %s; the actor has no durable data to upload as %s", man.SandboxClass, ateompath.DurableDirTarFile, ateattr.SnapshotScopeData) } - rec.SnapshotFiles = []string{ateompath.DurableDirTarFile} - rec.Scope = ateattr.SnapshotScopeData + man.SnapshotFiles = []string{ateompath.DurableDirTarFile} + man.Scope = ateattr.SnapshotScopeData return nil default: // The manifest's class is unvalidated input from disk/object storage. - return status.Errorf(codes.FailedPrecondition, "unknown sandbox class %q in snapshot manifest", rec.SandboxClass) + return status.Errorf(codes.FailedPrecondition, "unknown sandbox class %q in snapshot manifest", man.SandboxClass) } } @@ -986,10 +1005,10 @@ func (s *AteomHerder) Restore(ctx context.Context, req *ateletpb.RestoreRequest) checkpointDir := ateompath.RestoreStateDir(actorUID) - // The snapshot is self-describing: recover the sandbox binaries that created - // it from the manifest stored beside the checkpoint images (the Restore - // request no longer carries the sandbox config). Fetch the (small) manifest - // first — both the checkpoint download and the OCI/asset prep below need it. + // The manifest beside the checkpoint images names the snapshot's files + // and the SandboxConfig it was taken under; the assets come from the + // request. Fetch the (small) manifest first — the checkpoint download + // below needs its file list. tManifest := time.Now() manifestDone := false defer func() { @@ -998,7 +1017,7 @@ func (s *AteomHerder) Restore(ctx context.Context, req *ateletpb.RestoreRequest) op.failedPhase = ateattr.SnapshotPhaseManifestFetch } }() - var sandboxRec *sandboxAssetsRecord + var sandboxMan *snapshotManifest switch req.GetType() { case ateletpb.CheckpointType_CHECKPOINT_TYPE_EXTERNAL: uri, err := resources.ParseSnapshotURI(req.GetExternalConfig().GetSnapshotUri()) @@ -1013,8 +1032,8 @@ func (s *AteomHerder) Restore(ctx context.Context, req *ateletpb.RestoreRequest) if err != nil { return nil, ateerrors.CrashIfReason(ctx, fmt.Errorf("while fetching snapshot manifest: %w", err), ateerrors.ReasonInvalidObjectURL, ateerrors.ReasonFailedGetExternalObject) } - if sandboxRec, err = unmarshalSandboxRecord(manifest); err != nil { - return nil, ateerrors.CrashIfReason(ctx, fmt.Errorf("while unmarshalling sandbox record: %w", err), ateerrors.ReasonInvalidSandboxAsset) + if sandboxMan, err = unmarshalSandboxManifest(manifest); err != nil { + return nil, ateerrors.CrashIfReason(ctx, fmt.Errorf("while unmarshalling snapshot manifest: %w", err), ateerrors.ReasonInvalidSandboxAsset) } case ateletpb.CheckpointType_CHECKPOINT_TYPE_LOCAL: manifest, err := os.ReadFile(filepath.Join(ateompath.LocalSnapshotDir(actorUID, req.GetLocalConfig().GetSnapshotName()), sandboxManifestName)) @@ -1024,8 +1043,8 @@ func (s *AteomHerder) Restore(ctx context.Context, req *ateletpb.RestoreRequest) } return nil, fmt.Errorf("while reading local snapshot manifest: %w", err) } - if sandboxRec, err = unmarshalSandboxRecord(manifest); err != nil { - return nil, ateerrors.CrashIfReason(ctx, fmt.Errorf("while unmarshalling sandbox record: %w", err), ateerrors.ReasonInvalidSandboxAsset) + if sandboxMan, err = unmarshalSandboxManifest(manifest); err != nil { + return nil, ateerrors.CrashIfReason(ctx, fmt.Errorf("while unmarshalling snapshot manifest: %w", err), ateerrors.ReasonInvalidSandboxAsset) } default: return nil, fmt.Errorf("unexpected checkpoint type: %v", req.GetType()) @@ -1034,10 +1053,8 @@ func (s *AteomHerder) Restore(ctx context.Context, req *ateletpb.RestoreRequest) // On a DATA_ON_GOLDEN restore the actor's snapshot holds only durable-dir data; the guest // state (memory + VM state) comes from the template's golden snapshot. Fetch // the golden manifest too: its SnapshotFiles complete the restore set below, - // and its pinned sandbox binaries are the ones that will run the restored - // guest (the golden snapshot's memory image must be resumed by the binaries - // that created it). - var goldenRec *sandboxAssetsRecord + // and its SandboxConfig reference is the one the request's assets must match. + var goldenMan *snapshotManifest if req.GetScope() == ateletpb.SnapshotScope_SNAPSHOT_SCOPE_DATA_ON_GOLDEN { goldenURI, err := resources.ParseSnapshotURI(req.GetGoldenSnapshotUri()) if err != nil { @@ -1051,11 +1068,11 @@ func (s *AteomHerder) Restore(ctx context.Context, req *ateletpb.RestoreRequest) if err != nil { return nil, ateerrors.CrashIfReason(ctx, fmt.Errorf("while fetching golden snapshot manifest: %w", err), ateerrors.ReasonInvalidObjectURL, ateerrors.ReasonFailedGetExternalObject) } - if goldenRec, err = unmarshalSandboxRecord(manifest); err != nil { - return nil, ateerrors.CrashIfReason(ctx, fmt.Errorf("while unmarshalling golden sandbox record: %w", err), ateerrors.ReasonInvalidSandboxAsset) + if goldenMan, err = unmarshalSandboxManifest(manifest); err != nil { + return nil, ateerrors.CrashIfReason(ctx, fmt.Errorf("while unmarshalling golden snapshot manifest: %w", err), ateerrors.ReasonInvalidSandboxAsset) } - if goldenRec.SandboxClass != sandboxRec.SandboxClass { - return nil, status.Errorf(codes.FailedPrecondition, "golden snapshot sandbox class %q does not match actor snapshot sandbox class %q", goldenRec.SandboxClass, sandboxRec.SandboxClass) + if goldenMan.SandboxClass != sandboxMan.SandboxClass { + return nil, status.Errorf(codes.FailedPrecondition, "golden snapshot sandbox class %q does not match actor snapshot sandbox class %q", goldenMan.SandboxClass, sandboxMan.SandboxClass) } } dManifest = time.Since(tManifest) @@ -1063,18 +1080,30 @@ func (s *AteomHerder) Restore(ctx context.Context, req *ateletpb.RestoreRequest) // The manifest is what tells a golden restore from a latest one, so the // metric dimensions only become knowable here. - op.kind = restoreSnapshotKind(req, sandboxRec) - op.sandboxClass = sandboxRec.SandboxClass + op.kind = restoreSnapshotKind(req, sandboxMan) + op.sandboxClass = sandboxMan.SandboxClass - // The record whose pinned sandbox (binaries + pause image) runs the restored - // workload: the golden's for a DATA_ON_GOLDEN restore, the snapshot's own - // otherwise. The golden's set wins because the guest state being resumed is - // the golden snapshot's memory image, and a memory image must be resumed by - // the exact sandbox that produced it; the actor's snapshot contributes only - // durable data (a plain tar), which no sandbox version reads back. - runtimeRec := sandboxRec - if goldenRec != nil { - runtimeRec = goldenRec + // The manifest describing the sandbox that runs the restored guest: the + // golden's for a DATA_ON_GOLDEN restore (its memory image is what + // resumes), the snapshot's own otherwise. + guestMan := sandboxMan + if goldenMan != nil { + guestMan = goldenMan + } + + // The sandbox assets to restore with come only from the request; the + // manifest carries none. + runtimeRec, err := recordFromRequest(req.GetSandboxAssets()) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "invalid sandbox_assets: %v", err) + } + // Defense in depth: the control plane resolved the request's assets from + // the snapshot's recorded reference, so a mismatch here means it resolved + // a different SandboxConfig object. + if manRef := guestMan.SandboxConfigRef; manRef != nil && manRef.UID != "" && manRef.UID != runtimeRec.SandboxConfigRef.UID { + return nil, status.Errorf(codes.FailedPrecondition, + "snapshot manifest records SandboxConfig %s (uid %s) but the request's assets come from %s (uid %s)", + manRef.Name, manRef.UID, runtimeRec.SandboxConfigRef.Name, runtimeRec.SandboxConfigRef.UID) } // Download the memory snapshot and prepare the sandbox assets + OCI bundle @@ -1098,18 +1127,18 @@ func (s *AteomHerder) Restore(ctx context.Context, req *ateletpb.RestoreRequest) switch req.GetType() { case ateletpb.CheckpointType_CHECKPOINT_TYPE_EXTERNAL: if req.GetScope() == ateletpb.SnapshotScope_SNAPSHOT_SCOPE_DATA_ON_GOLDEN { - if goldenRec == nil { + if goldenMan == nil { return fmt.Errorf("no golden snapshot record for a %s restore", req.GetScope()) } - if err := s.downloadCombinedCheckpoint(gctx, req.GetExternalConfig().GetSnapshotUri(), req.GetGoldenSnapshotUri(), checkpointDir, sandboxRec.SnapshotFiles, goldenRec.SnapshotFiles); err != nil { + if err := s.downloadCombinedCheckpoint(gctx, req.GetExternalConfig().GetSnapshotUri(), req.GetGoldenSnapshotUri(), checkpointDir, sandboxMan.SnapshotFiles, goldenMan.SnapshotFiles); err != nil { return ateerrors.CrashIfReason(ctx, err, ateerrors.ReasonFailedGetExternalObject, ateerrors.ReasonInvalidObjectURL, ateerrors.ReasonTerminalFileSystemError) } - } else if err := s.downloadExternalCheckpoint(gctx, req.GetExternalConfig().GetSnapshotUri(), checkpointDir, sandboxRec.SnapshotFiles); err != nil { + } else if err := s.downloadExternalCheckpoint(gctx, req.GetExternalConfig().GetSnapshotUri(), checkpointDir, sandboxMan.SnapshotFiles); err != nil { return ateerrors.CrashIfReason(ctx, err, ateerrors.ReasonFailedGetExternalObject, ateerrors.ReasonInvalidObjectURL, ateerrors.ReasonTerminalFileSystemError) } case ateletpb.CheckpointType_CHECKPOINT_TYPE_LOCAL: combineWithGolden := req.GetScope() == ateletpb.SnapshotScope_SNAPSHOT_SCOPE_DATA_ON_GOLDEN - if combineWithGolden && goldenRec == nil { + if combineWithGolden && goldenMan == nil { return fmt.Errorf("no golden snapshot record for a %s restore", req.GetScope()) } // A local (pause) checkpoint may still combine with the golden @@ -1117,14 +1146,14 @@ func (s *AteomHerder) Restore(ctx context.Context, req *ateletpb.RestoreRequest) // the golden's from object storage, concurrently. gLocal, gLocalCtx := errgroup.WithContext(gctx) gLocal.Go(func() error { - if err := s.copyLocalCheckpoint(gLocalCtx, req.GetLocalConfig().GetSnapshotName(), ateompath.LocalCheckpointsDir(actorUID), checkpointDir, sandboxRec.SnapshotFiles); err != nil { + if err := s.copyLocalCheckpoint(gLocalCtx, req.GetLocalConfig().GetSnapshotName(), ateompath.LocalCheckpointsDir(actorUID), checkpointDir, sandboxMan.SnapshotFiles); err != nil { return ateerrors.CrashIfReason(ctx, err, ateerrors.ReasonTerminalFileSystemError) } return nil }) if combineWithGolden { gLocal.Go(func() error { - if err := s.downloadExternalCheckpoint(gLocalCtx, req.GetGoldenSnapshotUri(), checkpointDir, goldenOnlyFiles(sandboxRec.SnapshotFiles, goldenRec.SnapshotFiles)); err != nil { + if err := s.downloadExternalCheckpoint(gLocalCtx, req.GetGoldenSnapshotUri(), checkpointDir, goldenOnlyFiles(sandboxMan.SnapshotFiles, goldenMan.SnapshotFiles)); err != nil { return ateerrors.CrashIfReason(ctx, err, ateerrors.ReasonFailedGetExternalObject, ateerrors.ReasonInvalidObjectURL, ateerrors.ReasonTerminalFileSystemError) } return nil @@ -1205,11 +1234,9 @@ func (s *AteomHerder) Restore(ctx context.Context, req *ateletpb.RestoreRequest) return nil, fmt.Errorf("while calling ateom.RestoreWorkload: %w", err) } - // Record the (manifest-pinned) sandbox binaries on-node so a subsequent - // Checkpoint of this restored actor can re-pin the same version. For a - // DATA_ON_GOLDEN restore that is the golden's set — those are the binaries - // actually running the guest (Checkpoint overwrites the identity fields - // from its own request). + // Record the sandbox binaries now running the guest on-node so a + // subsequent Checkpoint of this restored actor can re-pin the same + // version and its SandboxConfig reference. if err := writeSandboxRecord(actorUID, runtimeRec); err != nil { // Note: crash the actor right away, if we cannot write the sandbox record now, we will not be able to checkpoint it later. return nil, ateerrors.CrashIfReason(ctx, err, ateerrors.ReasonTerminalFileSystemError) @@ -1229,16 +1256,17 @@ func (s *AteomHerder) Terminate(ctx context.Context, req *ateletpb.TerminateRequ actorRef := resources.ActorRef{Atespace: req.GetAtespace(), Name: req.GetActorName()} actorUID := req.GetActorUid() - var assetPaths map[string]string + // The on-node record names the sandbox assets to tear the actor down + // with (for gVisor, the runsc that kills the sandbox); re-fetching is a + // cache hit. sandboxRec, err := readSandboxRecord(actorUID) if err != nil { return nil, fmt.Errorf("failed to read sandbox record during terminate (actor: %s, actorUID: %s): %w", actorRef, actorUID, err) } - paths, err := s.ensureSandboxAssets(ctx, sandboxRec) + assetPaths, err := s.ensureSandboxAssets(ctx, sandboxRec) if err != nil { return nil, fmt.Errorf("failed to ensure sandbox assets during terminate (actor: %s, actorUID: %s): %w", actorRef, actorUID, err) } - assetPaths = paths client, err := s.dialAteom(ctx, req.GetTargetAteomUid()) if err != nil { @@ -1931,6 +1959,12 @@ func validateRestoreRequest(req *ateletpb.RestoreRequest) error { return err } + // The snapshot manifest carries only a SandboxConfig reference, never + // assets, so the request is the only source of sandbox binaries. + if req.GetSandboxAssets() == nil { + return fmt.Errorf("missing sandbox_assets: the control plane must resolve and send the sandbox binaries") + } + switch req.GetType() { case ateletpb.CheckpointType_CHECKPOINT_TYPE_EXTERNAL: if _, err := resources.ParseSnapshotURI(req.GetExternalConfig().GetSnapshotUri()); err != nil { diff --git a/cmd/atelet/main_test.go b/cmd/atelet/main_test.go index 6a05d88ff8..569183f69a 100644 --- a/cmd/atelet/main_test.go +++ b/cmd/atelet/main_test.go @@ -25,6 +25,7 @@ import ( "net" "os" "path/filepath" + "runtime" "slices" "strconv" "strings" @@ -68,7 +69,7 @@ func TestPortFlagDefault(t *testing.T) { } func TestSnapshotManifestActorMetadata(t *testing.T) { - rec := sandboxAssetsRecord{ + man := snapshotManifest{ Atespace: "team-a", ActorName: "actor-1", ActorUID: "actor-uid", @@ -76,7 +77,7 @@ func TestSnapshotManifestActorMetadata(t *testing.T) { ActorTemplateName: "agent", Scope: ateattr.SnapshotScopeFull, } - got, err := json.Marshal(rec) + got, err := json.Marshal(man) if err != nil { t.Fatal(err) } @@ -89,38 +90,95 @@ func TestSnapshotManifestActorMetadata(t *testing.T) { // TestSnapshotManifestScopeAbsent pins backward compatibility: manifests // written before the scope field existed must still parse, reporting an empty -// scope, and a scope-less record must not serialize a scope key at all. +// scope, and a scope-less manifest must not serialize a scope key at all. func TestSnapshotManifestScopeAbsent(t *testing.T) { legacy := []byte(`{"sandboxClass":"gvisor","pauseImage":"` + testPauseImage + `","snapshotFiles":["checkpoint.img"]}`) - rec, err := unmarshalSandboxRecord(legacy) + man, err := unmarshalSandboxManifest(legacy) if err != nil { - t.Fatalf("unmarshalSandboxRecord(legacy manifest): %v", err) + t.Fatalf("unmarshalSandboxManifest(legacy manifest): %v", err) } - if rec.Scope != "" { - t.Errorf("legacy manifest scope = %q, want empty", rec.Scope) + if man.Scope != "" { + t.Errorf("legacy manifest scope = %q, want empty", man.Scope) } - got, err := json.Marshal(sandboxAssetsRecord{SandboxClass: "gvisor"}) + got, err := json.Marshal(snapshotManifest{SandboxClass: "gvisor"}) if err != nil { t.Fatal(err) } if bytes.Contains(got, []byte(`"scope"`)) { - t.Errorf("scope-less record serialized a scope key: %s", got) + t.Errorf("scope-less manifest serialized a scope key: %s", got) } } -// TestSnapshotManifestRequiresPauseImage pins that a manifest without a pause -// image is rejected outright rather than yielding an empty image that would -// fail later, deep in the image pull. -func TestSnapshotManifestRequiresPauseImage(t *testing.T) { - noPause := []byte(`{"sandboxClass":"gvisor","snapshotFiles":["checkpoint.img"]}`) +// TestSnapshotManifestCarriesNoAssets pins that a marshaled manifest carries +// no asset content, and that an old-format manifest with assets parses with +// those keys ignored. +func TestSnapshotManifestCarriesNoAssets(t *testing.T) { + man := &snapshotManifest{ + SandboxClass: "gvisor", + Atespace: "team-a", + ActorName: "actor-1", + SnapshotFiles: []string{"checkpoint.img"}, + Scope: ateattr.SnapshotScopeFull, + SandboxConfigRef: &sandboxConfigRef{Name: "gvisor-prod", UID: "sandbox-uid-1", ResourceVersion: "42"}, + } + data, err := json.Marshal(man) + if err != nil { + t.Fatal(err) + } + for _, key := range []string{`"assets"`, `"pauseImage"`} { + if bytes.Contains(data, []byte(key)) { + t.Errorf("marshaled manifest contains %s: %s", key, data) + } + } + + legacy := []byte(`{"sandboxClass":"gvisor","pauseImage":"` + testPauseImage + `","assets":{"gvisor":{"url":"gs://b/gvisor.tar.bz2","sha256":"abc"}},"snapshotFiles":["checkpoint.img"],"scope":"full"}`) + parsed, err := unmarshalSandboxManifest(legacy) + if err != nil { + t.Fatalf("unmarshalSandboxManifest(old-format manifest): %v", err) + } + if parsed.SandboxConfigRef != nil { + t.Errorf("old-format manifest yielded a SandboxConfig ref: %+v", parsed.SandboxConfigRef) + } + if parsed.SandboxClass != "gvisor" || parsed.Scope != ateattr.SnapshotScopeFull || !slices.Equal(parsed.SnapshotFiles, []string{"checkpoint.img"}) { + t.Errorf("parsed manifest dropped non-asset fields: %+v", parsed) + } +} + +// TestSandboxRecordRequiresPauseImage pins that an on-node record without a +// pause image is rejected outright rather than yielding an empty image that +// would fail later, deep in the image pull. +func TestSandboxRecordRequiresPauseImage(t *testing.T) { + noPause := []byte(`{"sandboxClass":"gvisor","assets":{"gvisor":{"url":"gs://b/gvisor.tar.bz2","sha256":"abc"}}}`) if _, err := unmarshalSandboxRecord(noPause); err == nil { - t.Fatal("unmarshalSandboxRecord accepted a manifest with no pauseImage") + t.Fatal("unmarshalSandboxRecord accepted a record with no pauseImage") } else if !strings.Contains(err.Error(), "pauseImage") { t.Errorf("error = %v, want it to name pauseImage", err) } } +// TestSandboxAssetsFromRequestSandboxConfigRef pins that the SandboxConfig +// reference rides the request into the projected asset set, where Checkpoint +// picks it up for the snapshot manifest. +func TestSandboxAssetsFromRequestSandboxConfigRef(t *testing.T) { + rec, err := recordFromRequest(&ateletpb.SandboxAssets{ + SandboxClass: "gvisor", + PauseImage: testPauseImage, + Assets: map[string]*ateletpb.ArchAssets{ + runtime.GOARCH: {Files: map[string]*ateletpb.AssetFile{ + gvisorAssetName: {Url: "gs://b/gvisor.tar.bz2", Sha256: "abc"}, + }}, + }, + SandboxConfigRef: &ateletpb.SandboxConfigRef{Name: "gvisor-prod", Uid: "sandbox-uid-1", ResourceVersion: "42"}, + }) + if err != nil { + t.Fatalf("sandboxAssetsFromRequest: %v", err) + } + if want := (sandboxConfigRef{Name: "gvisor-prod", UID: "sandbox-uid-1", ResourceVersion: "42"}); rec.SandboxConfigRef != want { + t.Errorf("record SandboxConfig ref = %+v, want %+v", rec.SandboxConfigRef, want) + } +} + func TestWriteSystemInfoVolume(t *testing.T) { ctx := context.Background() root := filepath.Join(t.TempDir(), "system-info", "vol1") @@ -434,6 +492,15 @@ func validRestoreRequest() *ateletpb.RestoreRequest { }, }, Scope: ateletpb.SnapshotScope_SNAPSHOT_SCOPE_FULL, + SandboxAssets: &ateletpb.SandboxAssets{ + SandboxClass: "gvisor", + PauseImage: testPauseImage, + Assets: map[string]*ateletpb.ArchAssets{ + "amd64": {Files: map[string]*ateletpb.AssetFile{ + gvisorAssetName: {Url: "gs://bucket/gvisor.tar.bz2", Sha256: "abc"}, + }}, + }, + }, } } @@ -571,6 +638,7 @@ func TestValidateRestoreRequest(t *testing.T) { r.Type = ateletpb.CheckpointType_CHECKPOINT_TYPE_LOCAL r.Config = &ateletpb.RestoreRequest_LocalConfig{LocalConfig: &ateletpb.LocalCheckpointConfiguration{SnapshotName: ".."}} }), true}, + {"missing sandbox assets", makeReq(func(r *ateletpb.RestoreRequest) { r.SandboxAssets = nil }), true}, {"unspecified snapshot type", makeReq(func(r *ateletpb.RestoreRequest) { r.Type = ateletpb.CheckpointType_CHECKPOINT_TYPE_UNSPECIFIED }), true}, {"unspecified snapshot scope", makeReq(func(r *ateletpb.RestoreRequest) { r.Scope = ateletpb.SnapshotScope_SNAPSHOT_SCOPE_UNSPECIFIED }), true}, {"invalid snapshot scope", makeReq(func(r *ateletpb.RestoreRequest) { r.Scope = ateletpb.SnapshotScope(23) }), true}, @@ -1599,7 +1667,7 @@ func (r *recordingObjectStorage) keys() []string { // writeLocalSnapshot lays a local pause snapshot out in dir: the given files // plus the marshaled manifest beside them. -func writeLocalSnapshot(t *testing.T, dir string, rec sandboxAssetsRecord, contents map[string]string) { +func writeLocalSnapshot(t *testing.T, dir string, man snapshotManifest, contents map[string]string) { t.Helper() if err := os.MkdirAll(dir, 0o700); err != nil { t.Fatalf("creating snapshot dir: %v", err) @@ -1609,7 +1677,7 @@ func writeLocalSnapshot(t *testing.T, dir string, rec sandboxAssetsRecord, conte t.Fatalf("writing snapshot file %s: %v", name, err) } } - manifest, err := json.Marshal(rec) + manifest, err := json.Marshal(man) if err != nil { t.Fatalf("marshaling manifest: %v", err) } @@ -1637,33 +1705,40 @@ func TestUploadLocalCheckpointDir(t *testing.T) { if err != nil { t.Fatalf("ParseSnapshotURI: %v", err) } - fullRec := func(class string) sandboxAssetsRecord { - return sandboxAssetsRecord{ - SandboxClass: class, - PauseImage: testPauseImage, - SnapshotFiles: []string{"config.json", "memory-ranges", ateompath.DurableDirTarFile}, - Scope: ateattr.SnapshotScopeFull, + fullMan := func(class string) snapshotManifest { + return snapshotManifest{ + SandboxClass: class, + SnapshotFiles: []string{"config.json", "memory-ranges", ateompath.DurableDirTarFile}, + Scope: ateattr.SnapshotScopeFull, + SandboxConfigRef: &sandboxConfigRef{Name: "sandbox-prod", UID: "sandbox-uid-1"}, } } - remoteManifest := func(t *testing.T, store *recordingObjectStorage) sandboxAssetsRecord { + remoteManifest := func(t *testing.T, store *recordingObjectStorage) snapshotManifest { t.Helper() b, ok := store.objects["bucket/root/snapshots/ate-demo/snap-1/manifest.json"] if !ok { t.Fatal("no manifest uploaded") } - rec, err := unmarshalSandboxRecord(b) + // Uploaded manifests carry the SandboxConfig reference, never asset + // content. + for _, key := range []string{`"assets"`, `"pauseImage"`} { + if bytes.Contains(b, []byte(key)) { + t.Errorf("uploaded manifest contains %s: %s", key, b) + } + } + man, err := unmarshalSandboxManifest(b) if err != nil { t.Fatalf("parsing uploaded manifest: %v", err) } - return *rec + return *man } t.Run("matching scope uploads all files", func(t *testing.T) { store := &recordingObjectStorage{} s := &AteomHerder{gcsClient: store} dir := filepath.Join(t.TempDir(), "pause-snap-1") - writeLocalSnapshot(t, dir, fullRec("microvm"), map[string]string{ + writeLocalSnapshot(t, dir, fullMan("microvm"), map[string]string{ "config.json": "cfg", "memory-ranges": "mem", ateompath.DurableDirTarFile: "data", }) @@ -1679,16 +1754,20 @@ func TestUploadLocalCheckpointDir(t *testing.T) { if got := store.keys(); !slices.Equal(got, want) { t.Errorf("uploaded objects = %v, want %v", got, want) } - if rec := remoteManifest(t, store); rec.Scope != ateattr.SnapshotScopeFull { + rec := remoteManifest(t, store) + if rec.Scope != ateattr.SnapshotScopeFull { t.Errorf("uploaded manifest scope = %q, want %q", rec.Scope, ateattr.SnapshotScopeFull) } + if ref := rec.SandboxConfigRef; ref == nil || ref.Name != "sandbox-prod" || ref.UID != "sandbox-uid-1" { + t.Errorf("uploaded manifest SandboxConfig ref = %+v, want sandbox-prod/sandbox-uid-1", ref) + } }) t.Run("microvm full capture uploads durable tar alone as data", func(t *testing.T) { store := &recordingObjectStorage{} s := &AteomHerder{gcsClient: store} dir := filepath.Join(t.TempDir(), "pause-snap-1") - writeLocalSnapshot(t, dir, fullRec("microvm"), map[string]string{ + writeLocalSnapshot(t, dir, fullMan("microvm"), map[string]string{ "config.json": "cfg", "memory-ranges": "mem", ateompath.DurableDirTarFile: "data", }) @@ -1716,9 +1795,8 @@ func TestUploadLocalCheckpointDir(t *testing.T) { t.Run("gvisor full capture without durable tar has no data", func(t *testing.T) { s := &AteomHerder{gcsClient: &recordingObjectStorage{}} dir := filepath.Join(t.TempDir(), "pause-snap-1") - writeLocalSnapshot(t, dir, sandboxAssetsRecord{ + writeLocalSnapshot(t, dir, snapshotManifest{ SandboxClass: "gvisor", - PauseImage: testPauseImage, SnapshotFiles: []string{"checkpoint.img"}, Scope: ateattr.SnapshotScopeFull, }, map[string]string{"checkpoint.img": "img"}) @@ -1734,9 +1812,8 @@ func TestUploadLocalCheckpointDir(t *testing.T) { t.Run("microvm full capture without durable tar has no data", func(t *testing.T) { s := &AteomHerder{gcsClient: &recordingObjectStorage{}} dir := filepath.Join(t.TempDir(), "pause-snap-1") - writeLocalSnapshot(t, dir, sandboxAssetsRecord{ + writeLocalSnapshot(t, dir, snapshotManifest{ SandboxClass: "microvm", - PauseImage: testPauseImage, SnapshotFiles: []string{"config.json", "memory-ranges"}, Scope: ateattr.SnapshotScopeFull, }, map[string]string{"config.json": "cfg", "memory-ranges": "mem"}) @@ -1752,9 +1829,8 @@ func TestUploadLocalCheckpointDir(t *testing.T) { t.Run("unknown sandbox class cannot convert", func(t *testing.T) { s := &AteomHerder{gcsClient: &recordingObjectStorage{}} dir := filepath.Join(t.TempDir(), "pause-snap-1") - writeLocalSnapshot(t, dir, sandboxAssetsRecord{ + writeLocalSnapshot(t, dir, snapshotManifest{ SandboxClass: "mystery", - PauseImage: testPauseImage, SnapshotFiles: []string{ateompath.DurableDirTarFile}, Scope: ateattr.SnapshotScopeFull, }, map[string]string{ateompath.DurableDirTarFile: "data"}) @@ -1770,9 +1846,8 @@ func TestUploadLocalCheckpointDir(t *testing.T) { t.Run("data capture cannot become full", func(t *testing.T) { s := &AteomHerder{gcsClient: &recordingObjectStorage{}} dir := filepath.Join(t.TempDir(), "pause-snap-1") - writeLocalSnapshot(t, dir, sandboxAssetsRecord{ + writeLocalSnapshot(t, dir, snapshotManifest{ SandboxClass: "microvm", - PauseImage: testPauseImage, SnapshotFiles: []string{ateompath.DurableDirTarFile}, Scope: ateattr.SnapshotScopeData, }, map[string]string{ateompath.DurableDirTarFile: "data"}) @@ -1787,9 +1862,8 @@ func TestUploadLocalCheckpointDir(t *testing.T) { store := &recordingObjectStorage{} s := &AteomHerder{gcsClient: store} dir := filepath.Join(t.TempDir(), "pause-snap-1") - writeLocalSnapshot(t, dir, sandboxAssetsRecord{ + writeLocalSnapshot(t, dir, snapshotManifest{ SandboxClass: "microvm", - PauseImage: testPauseImage, SnapshotFiles: []string{ateompath.DurableDirTarFile}, }, map[string]string{ateompath.DurableDirTarFile: "data"}) @@ -1836,7 +1910,7 @@ func TestUploadLocalCheckpointDir(t *testing.T) { t.Run("upload failure is a plain retryable error", func(t *testing.T) { s := &AteomHerder{gcsClient: &recordingObjectStorage{putErr: errors.New("boom")}} dir := filepath.Join(t.TempDir(), "pause-snap-1") - writeLocalSnapshot(t, dir, fullRec("microvm"), map[string]string{ + writeLocalSnapshot(t, dir, fullMan("microvm"), map[string]string{ "config.json": "cfg", "memory-ranges": "mem", ateompath.DurableDirTarFile: "data", }) diff --git a/cmd/atelet/metrics.go b/cmd/atelet/metrics.go index d9433e1390..57fac02b36 100644 --- a/cmd/atelet/metrics.go +++ b/cmd/atelet/metrics.go @@ -183,16 +183,16 @@ func assetsAfterCollateral(prepFailedPhase string, assets time.Duration) time.Du // URI prefix, so they are told apart by the identity the manifest records for // the actor that wrote the snapshot. An empty result means the manifest has not // been read yet, so the kind is not knowable. -func restoreSnapshotKind(req *ateletpb.RestoreRequest, rec *sandboxAssetsRecord) string { +func restoreSnapshotKind(req *ateletpb.RestoreRequest, man *snapshotManifest) string { if req.GetType() == ateletpb.CheckpointType_CHECKPOINT_TYPE_LOCAL { return ateattr.SnapshotKindLocal } - if rec == nil { + if man == nil { return "" } // Manifests written before the identity fields existed carry no atespace and // fall through to latest, which is the common case for them anyway. - if rec.Atespace == resources.GoldenActorAtespace { + if man.Atespace == resources.GoldenActorAtespace { return ateattr.SnapshotKindGolden } return ateattr.SnapshotKindLatest diff --git a/cmd/atelet/metrics_test.go b/cmd/atelet/metrics_test.go index 4c38e16d7f..4cc7f0d0eb 100644 --- a/cmd/atelet/metrics_test.go +++ b/cmd/atelet/metrics_test.go @@ -392,13 +392,13 @@ func TestRestoreSnapshotKind(t *testing.T) { tests := []struct { name string req *ateletpb.RestoreRequest - rec *sandboxAssetsRecord + rec *snapshotManifest want string }{ { name: "local pause snapshot", req: &ateletpb.RestoreRequest{Type: ateletpb.CheckpointType_CHECKPOINT_TYPE_LOCAL}, - rec: &sandboxAssetsRecord{Atespace: "team-a"}, + rec: &snapshotManifest{Atespace: "team-a"}, want: ateattr.SnapshotKindLocal, }, { @@ -410,19 +410,19 @@ func TestRestoreSnapshotKind(t *testing.T) { { name: "external snapshot written by a golden actor", req: &ateletpb.RestoreRequest{Type: ateletpb.CheckpointType_CHECKPOINT_TYPE_EXTERNAL}, - rec: &sandboxAssetsRecord{Atespace: resources.GoldenActorAtespace}, + rec: &snapshotManifest{Atespace: resources.GoldenActorAtespace}, want: ateattr.SnapshotKindGolden, }, { name: "external snapshot written by a tenant actor", req: &ateletpb.RestoreRequest{Type: ateletpb.CheckpointType_CHECKPOINT_TYPE_EXTERNAL}, - rec: &sandboxAssetsRecord{Atespace: "team-a"}, + rec: &snapshotManifest{Atespace: "team-a"}, want: ateattr.SnapshotKindLatest, }, { name: "manifest predating the identity fields", req: &ateletpb.RestoreRequest{Type: ateletpb.CheckpointType_CHECKPOINT_TYPE_EXTERNAL}, - rec: &sandboxAssetsRecord{}, + rec: &snapshotManifest{}, want: ateattr.SnapshotKindLatest, }, { @@ -437,7 +437,7 @@ func TestRestoreSnapshotKind(t *testing.T) { Type: ateletpb.CheckpointType_CHECKPOINT_TYPE_LOCAL, Scope: ateletpb.SnapshotScope_SNAPSHOT_SCOPE_DATA_ON_GOLDEN, }, - rec: &sandboxAssetsRecord{Atespace: "team-a"}, + rec: &snapshotManifest{Atespace: "team-a"}, want: ateattr.SnapshotKindLocal, }, } diff --git a/cmd/atelet/sandbox_assets.go b/cmd/atelet/sandbox_assets.go index 58a81b1de2..e2558463cf 100644 --- a/cmd/atelet/sandbox_assets.go +++ b/cmd/atelet/sandbox_assets.go @@ -25,8 +25,6 @@ import ( "encoding/json" "errors" "fmt" - gzip "github.com/klauspost/compress/gzip" - "github.com/klauspost/compress/zstd" "io" "io/fs" "log/slog" @@ -37,6 +35,9 @@ import ( "syscall" "time" + gzip "github.com/klauspost/compress/gzip" + "github.com/klauspost/compress/zstd" + "github.com/agent-substrate/substrate/cmd/atelet/internal/ategcs" "github.com/agent-substrate/substrate/internal/ateerrors" "github.com/agent-substrate/substrate/internal/ateompath" @@ -44,9 +45,8 @@ import ( "github.com/agent-substrate/substrate/internal/resources" ) -// sandboxManifestName is the object/file name of the per-snapshot manifest that -// records the actor identity, snapshot files, and sandbox binaries. It is written -// next to the checkpoint images so a snapshot is self-describing. +// sandboxManifestName is the object/file name of the per-snapshot manifest +// (see snapshotManifest) written next to the checkpoint images. const sandboxManifestName = "manifest.json" // maxAssetBytes guards disk against an unbounded download URL; a var so tests can lower it. @@ -70,21 +70,40 @@ type assetEntry struct { SHA256 string `json:"sha256"` } -// sandboxAssetsRecord is the sandbox runtime an actor is running, projected onto -// the local node's architecture: the sandbox class and pause image plus the -// asset set keyed by asset name (gVisor uses a single "gvisor" release-tarball -// asset; records written before the tarball release mechanism use a bare -// "runsc" asset). -// It is both the per-actor on-node record (written at Run/Restore, read at -// Checkpoint) and the snapshot manifest (written at Checkpoint, read at -// Restore). +// sandboxAssetsRecord is the sandbox runtime an actor is running, projected +// onto the local node's architecture: the sandbox class and pause image plus +// the asset set keyed by asset name (gVisor uses a single "gvisor" +// release-tarball asset; records written before the tarball release mechanism +// use a bare "runsc" asset). +// It is the per-actor on-node record, written at Run/Restore and read at +// Checkpoint/Terminate. Only its SandboxConfig reference is durable: +// Checkpoint pins that into the snapshot manifest, never the asset content. type sandboxAssetsRecord struct { SandboxClass string `json:"sandboxClass"` Assets map[string]assetEntry `json:"assets"` - // PauseImage is the root sandbox container's image. It is recorded here - // rather than taken from the request at Restore so a snapshot is rebuilt - // with the same sandbox it was captured from. + // PauseImage is the root sandbox container's image. PauseImage string `json:"pauseImage"` + // SandboxConfigRef is the SandboxConfig object the assets were resolved + // from; zero in records written before the reference existed. + SandboxConfigRef sandboxConfigRef `json:"sandboxConfigRef"` +} + +// sandboxConfigRef is the global object reference of a SandboxConfig: name, +// Kubernetes UID (distinguishing an object from a re-creation under the same +// name), and the object's metadata.resourceVersion at asset resolution time. +type sandboxConfigRef struct { + Name string `json:"name"` + UID string `json:"uid"` + ResourceVersion string `json:"resourceVersion,omitempty"` +} + +// snapshotManifest is the manifest.json written beside a snapshot's +// checkpoint files. It carries no sandbox asset content — restores take +// assets from the RestoreRequest — only the SandboxConfig reference the +// control plane verifies before sending them. Old-format manifests carried +// the asset set itself; their extra JSON keys are ignored. +type snapshotManifest struct { + SandboxClass string `json:"sandboxClass"` // Actor identity makes a flat snapshot self-identifying if control-plane // persistence is unavailable. Atespace string `json:"atespace,omitempty"` @@ -94,19 +113,22 @@ type sandboxAssetsRecord struct { ActorTemplateName string `json:"actorTemplateName,omitempty"` // SnapshotFiles are the (relative) names of the files ateom wrote into the // checkpoint directory, as reported by CheckpointWorkloadResponse. Recorded - // in the snapshot manifest so Restore ships/downloads exactly this set - // (gVisor's image files, cloud-hypervisor's snapshot set, ...). Empty in the - // on-node record written at Run/Restore; populated at Checkpoint. + // so Restore ships/downloads exactly this set (gVisor's image files, + // cloud-hypervisor's snapshot set, ...). SnapshotFiles []string `json:"snapshotFiles,omitempty"` // Scope is the snapshot scope the checkpoint captured, as the shared // ateattr label ("full" or "data"), so a snapshot's content is knowable - // from the manifest alone. Empty in the on-node record written at - // Run/Restore and in snapshot manifests written before this field existed. + // from the manifest alone. Empty in manifests written before this field + // existed. Scope string `json:"scope,omitempty"` + // SandboxConfigRef is the SandboxConfig the snapshotted sandbox was + // booted from; the control plane resolves a later restore's assets from + // it. Nil in older manifests. + SandboxConfigRef *sandboxConfigRef `json:"sandboxConfigRef,omitempty"` } -// recordFromRequest projects a request's per-architecture SandboxAssets onto the -// local node's architecture. +// recordFromRequest projects a request's per-architecture SandboxAssets +// onto the local node's architecture. func recordFromRequest(sa *ateletpb.SandboxAssets) (*sandboxAssetsRecord, error) { if sa == nil { return nil, fmt.Errorf("missing sandbox_assets") @@ -123,6 +145,11 @@ func recordFromRequest(sa *ateletpb.SandboxAssets) (*sandboxAssetsRecord, error) SandboxClass: sa.GetSandboxClass(), PauseImage: sa.GetPauseImage(), Assets: make(map[string]assetEntry, len(archAssets.GetFiles())), + SandboxConfigRef: sandboxConfigRef{ + Name: sa.GetSandboxConfigRef().GetName(), + UID: sa.GetSandboxConfigRef().GetUid(), + ResourceVersion: sa.GetSandboxConfigRef().GetResourceVersion(), + }, } for name, f := range archAssets.GetFiles() { rec.Assets[name] = assetEntry{URL: f.GetUrl(), SHA256: f.GetSha256()} @@ -454,8 +481,9 @@ func (s *AteomHerder) openAsset(ctx context.Context, url string) (io.ReadCloser, } // writeSandboxRecord persists the actor's running sandbox assets on-node so a -// later Checkpoint (whose request no longer carries the sandbox config) can -// re-fetch the same binaries and pin them into the snapshot manifest. +// later Checkpoint/Terminate (whose requests carry no sandbox config) can +// re-fetch the same binaries, and Checkpoint can pin their SandboxConfig +// reference into the snapshot manifest. func writeSandboxRecord(actorUID string, rec *sandboxAssetsRecord) error { data, err := json.Marshal(rec) if err != nil { @@ -485,17 +513,27 @@ func readSandboxRecord(actorUID string) (*sandboxAssetsRecord, error) { func unmarshalSandboxRecord(data []byte) (*sandboxAssetsRecord, error) { rec := &sandboxAssetsRecord{} if err := json.Unmarshal(data, rec); err != nil { - return nil, fmt.Errorf("%w: while parsing sandbox record/manifest: %w", ateerrors.ReasonInvalidSandboxAsset, err) + return nil, fmt.Errorf("%w: while parsing sandbox record: %w", ateerrors.ReasonInvalidSandboxAsset, err) } // Fail loudly rather than let an empty image reach the image pull: a record // without one predates the pause image moving into the sandbox config, and - // its snapshot cannot be rebuilt with a known-matching sandbox. + // its sandbox cannot be rebuilt with a known-matching image. if rec.PauseImage == "" { - return nil, fmt.Errorf("%w: sandbox record/manifest has no pauseImage", ateerrors.ReasonInvalidSandboxAsset) + return nil, fmt.Errorf("%w: sandbox record has no pauseImage", ateerrors.ReasonInvalidSandboxAsset) } return rec, nil } +// unmarshalSandboxManifest parses a snapshot manifest; old-format asset keys +// are ignored. +func unmarshalSandboxManifest(data []byte) (*snapshotManifest, error) { + man := &snapshotManifest{} + if err := json.Unmarshal(data, man); err != nil { + return nil, fmt.Errorf("%w: while parsing snapshot manifest: %w", ateerrors.ReasonInvalidSandboxAsset, err) + } + return man, nil +} + func wrapFileSystemErr(msg string, err error) error { if isTerminalFileSystemErr(err) { return fmt.Errorf("%w: %s: %w", ateerrors.ReasonTerminalFileSystemError, msg, err) diff --git a/internal/e2e/suites/demo/updatesandboxconfig_test.go b/internal/e2e/suites/demo/updatesandboxconfig_test.go new file mode 100644 index 0000000000..d4359a252a --- /dev/null +++ b/internal/e2e/suites/demo/updatesandboxconfig_test.go @@ -0,0 +1,277 @@ +// 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 demo + +import ( + "context" + "testing" + "time" + + "github.com/agent-substrate/substrate/internal/e2e" + "github.com/agent-substrate/substrate/internal/resources" + "github.com/agent-substrate/substrate/pkg/api/v1alpha1" + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// TestUpdateTemplateSandboxConfig covers the SandboxConfig side of repointing +// a suspended actor at a different ActorTemplate: the actor first runs under +// template A (whose pool resolves the fixture's SandboxConfig), suspends — +// recording that config on its durable snapshot — and is then repointed at +// template B, whose pool names a freshly created SandboxConfig (a copy of the +// fixture's under a new name, so a new UID). The resume after the repoint +// must boot with the config recorded on template B's golden snapshot, not the +// one on the actor's own snapshot — observable in the snapshot the next +// suspend produces, which records the config the checkpoint reported. +func TestUpdateTemplateSandboxConfig(t *testing.T) { + nsObj := e2e.CreateNamespace(t) + ctx := context.Background() + clients := e2e.GetClients() + + env, err := e2e.CheckEnv("BUCKET_NAME") + if err != nil { + t.Fatalf("CheckEnv failed: %v", err) + } + + // Create a new SandboxConfig: a spec-identical copy of the one the + // fixture pool resolves to, under a fresh name. Same binaries, so the + // sandbox boots the same either way; only the reference identity + // (name/UID) differs, which is exactly what the test asserts on. + // + baseCfg := fixturePoolSandboxConfig(ctx, t, clients) + newCfg := &v1alpha1.SandboxConfig{ + ObjectMeta: metav1.ObjectMeta{Name: "update-sbcfg-" + nsObj.Name}, + Spec: *baseCfg.Spec.DeepCopy(), + } + // Never the class default: only pool B's explicit reference may pick it. + newCfg.Spec.Default = false + newCfg, err = clients.SubstrateK8s.ApiV1alpha1().SandboxConfigs().Create(ctx, newCfg, metav1.CreateOptions{}) + if err != nil { + t.Fatalf("failed to create SandboxConfig copy: %v", err) + } + t.Cleanup(func() { + cleanupCtx, cancel := context.WithTimeout(context.Background(), time.Minute) + defer cancel() + if err := clients.SubstrateK8s.ApiV1alpha1().SandboxConfigs().Delete(cleanupCtx, newCfg.Name, metav1.DeleteOptions{}); err != nil { + t.Logf("failed to delete SandboxConfig %q: %v", newCfg.Name, err) + } + }) + + // + // Template A rides the fixture's SandboxConfig; template B's pool names + // the new one. The pools get disjoint labels so each template's golden + // snapshot builds on its own pool — B's golden must record the new + // config, and a golden actor landing on pool A would record the old one. + // + nameA, nameB := "sbcfg-a-"+nsObj.Name, "sbcfg-b-"+nsObj.Name + snapshotsConfig := func(name string) *ateapipb.SnapshotsConfig { + return &ateapipb.SnapshotsConfig{ + StorageLocation: "gs://" + env["BUCKET_NAME"] + "/ate-demo-" + name, + OnPause: ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_DATA, + OnCommit: ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_DATA, + } + } + e2e.CreateSubstrateCounterTemplate(ctx, t, clients, nsObj.Name, e2e.SubstrateTemplateOptions{ + Atespace: demoAtespace, + Name: nameA, + PoolName: "sbcfg-a", + PoolReplicas: 2, + Labels: map[string]string{"demo": nsObj.Name + "-a"}, + SnapshotsConfig: snapshotsConfig(nameA), + }) + createdB := e2e.CreateSubstrateCounterTemplate(ctx, t, clients, nsObj.Name, e2e.SubstrateTemplateOptions{ + Atespace: demoAtespace, + Name: nameB, + PoolName: "sbcfg-b", + PoolReplicas: 2, + Labels: map[string]string{"demo": nsObj.Name + "-b"}, + SnapshotsConfig: snapshotsConfig(nameB), + PoolSandboxConfigName: newCfg.Name, + Modify: func(tmpl *ateapipb.ActorTemplate) { + tmpl.SandboxConfig.ConfigName = newCfg.Name + }, + }) + + // Template B's golden snapshot must have recorded the new config: the + // repointed resume below resolves its sandbox from this reference. + refB := &ateapipb.ObjectRef{Atespace: demoAtespace, Name: nameB} + tmplB, err := clients.SubstrateAPI.GetActorTemplate(ctx, &ateapipb.GetActorTemplateRequest{ActorTemplate: refB}) + if err != nil { + t.Fatalf("failed to get ActorTemplate %q: %v", nameB, err) + } + goldenB, err := clients.SubstrateAPI.GetActorSnapshot(ctx, &ateapipb.GetActorSnapshotRequest{ + ActorSnapshot: tmplB.GetStatus().GetGoldenSnapshotStatus().GetGoldenSnapshot(), + }) + if err != nil { + t.Fatalf("failed to get template B's golden snapshot: %v", err) + } + if got := goldenB.GetStatus().GetSandboxConfigRef(); got.GetUid() != string(newCfg.UID) { + t.Fatalf("template B's golden snapshot records SandboxConfig %q (uid %q), want the new config %q (uid %q)", + got.GetName(), got.GetUid(), newCfg.Name, string(newCfg.UID)) + } + + // + // Create an Actor from template A and run it once. + // + actorID := "update-sbcfg-" + nsObj.Name + actorRef := &ateapipb.ObjectRef{Atespace: demoAtespace, Name: actorID} + t.Logf("Creating Actor %q from substrate template %q...", actorID, nameA) + if _, err := clients.SubstrateAPI.CreateActor(ctx, &ateapipb.CreateActorRequest{Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: demoAtespace, Name: actorID}, + ActorTemplate: &ateapipb.ObjectRef{Atespace: demoAtespace, Name: nameA}, + }}); err != nil { + t.Fatalf("failed to create Actor: %v", err) + } + defer func() { + clients.SubstrateAPI.DeleteActor(ctx, &ateapipb.DeleteActorRequest{Actor: actorRef}) + }() + + t.Logf("Resuming Actor %q under template A...", actorID) + if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapipb.ResumeActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("failed to resume Actor: %v", err) + } + // The first resume also absorbs the freshly created pool's worker + // startup, so it gets a longer budget than the steady-state waits. + waitForActorStateWithTimeout(ctx, t, clients, actorID, ateapipb.ActorState_ACTOR_STATE_RUNNING, 120*time.Second) + + resp, err := callActor(t, resources.ActorRef{Atespace: demoAtespace, Name: actorID}) + if err != nil { + t.Fatalf("failed to call actor under template A: %v", err) + } + validateCounterResponse(t, resp, "under template A", 1, 1) + + // + // Suspend: the durable snapshot must record the config the sprint booted + // with — the old one. This is the reference a plain (non-repointed) + // resume would boot from. + // + t.Logf("Suspending Actor %q...", actorID) + if _, err := clients.SubstrateAPI.SuspendActor(ctx, &ateapipb.SuspendActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("failed to suspend Actor: %v", err) + } + waitForActorState(ctx, t, clients, actorID, ateapipb.ActorState_ACTOR_STATE_SUSPENDED) + + suspended, err := clients.SubstrateAPI.GetActor(ctx, &ateapipb.GetActorRequest{Actor: actorRef}) + if err != nil { + t.Fatalf("failed to get suspended Actor: %v", err) + } + snapshotA, err := clients.SubstrateAPI.GetActorSnapshot(ctx, &ateapipb.GetActorSnapshotRequest{ + ActorSnapshot: suspended.GetStatus().GetLatestSnapshot(), + }) + if err != nil { + t.Fatalf("failed to get the suspended Actor's snapshot: %v", err) + } + oldRef := snapshotA.GetStatus().GetSandboxConfigRef() + if oldRef.GetUid() == "" { + t.Fatal("suspended Actor's snapshot records no sandbox_config_ref") + } + if oldRef.GetUid() == string(newCfg.UID) { + t.Fatalf("Actor booted under template A already ran the new SandboxConfig %q; the test cannot distinguish old from new", newCfg.Name) + } + + // + // Repoint at template B and resume: the boot must resolve the new + // SandboxConfig from B's golden snapshot, not the old one recorded on + // the actor's own snapshot. + // + t.Logf("Repointing Actor %q at template %q...", actorID, nameB) + if _, err := clients.SubstrateAPI.UpdateActor(ctx, &ateapipb.UpdateActorRequest{Actor: &ateapipb.Actor{ + Metadata: suspended.GetMetadata(), + ActorTemplate: refB, + }}); err != nil { + t.Fatalf("failed to update Actor's template: %v", err) + } + + t.Logf("Resuming Actor %q under template B...", actorID) + if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapipb.ResumeActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("failed to resume Actor after template update: %v", err) + } + waitForActorState(ctx, t, clients, actorID, ateapipb.ActorState_ACTOR_STATE_RUNNING) + + repointed, err := clients.SubstrateAPI.GetActor(ctx, &ateapipb.GetActorRequest{Actor: actorRef}) + if err != nil { + t.Fatalf("failed to get repointed Actor: %v", err) + } + if got, want := repointed.GetStatus().GetCurrentActorTemplateUid(), createdB.GetMetadata().GetUid(); got != want { + t.Errorf("repointed Actor current_actor_template_uid = %q, want template B's %q", got, want) + } + + // The repoint forces a data-only restore: the guest cold-boots from B + // (memory counter resets) while the durable dir carries over (file + // counter continues). + resp, err = callActor(t, resources.ActorRef{Atespace: demoAtespace, Name: actorID}) + if err != nil { + t.Fatalf("failed to call actor after template update: %v", err) + } + validateCounterResponse(t, resp, "after template update", 1, 2) + + // A second suspend closes the loop: the snapshot chain now carries the + // new config, so later resumes keep booting with it. + t.Logf("Suspending Actor %q again...", actorID) + if _, err := clients.SubstrateAPI.SuspendActor(ctx, &ateapipb.SuspendActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("failed to suspend Actor again: %v", err) + } + waitForActorState(ctx, t, clients, actorID, ateapipb.ActorState_ACTOR_STATE_SUSPENDED) + + suspended, err = clients.SubstrateAPI.GetActor(ctx, &ateapipb.GetActorRequest{Actor: actorRef}) + if err != nil { + t.Fatalf("failed to get re-suspended Actor: %v", err) + } + snapshotB, err := clients.SubstrateAPI.GetActorSnapshot(ctx, &ateapipb.GetActorSnapshotRequest{ + ActorSnapshot: suspended.GetStatus().GetLatestSnapshot(), + }) + if err != nil { + t.Fatalf("failed to get the re-suspended Actor's snapshot: %v", err) + } + if got := snapshotB.GetStatus().GetSandboxConfigRef(); got.GetUid() != string(newCfg.UID) { + t.Errorf("re-suspended Actor's snapshot records SandboxConfig %q (uid %q), want the new config %q (uid %q)", + got.GetName(), got.GetUid(), newCfg.Name, string(newCfg.UID)) + } +} + +// fixturePoolSandboxConfig resolves the SandboxConfig the counter fixture's +// WorkerPool boots with, mirroring the control plane's resolution: the pool's +// explicit SandboxConfigName when set, else the cluster-wide default for the +// pool's SandboxClass. +func fixturePoolSandboxConfig(ctx context.Context, t *testing.T, clients *e2e.Clients) *v1alpha1.SandboxConfig { + t.Helper() + fixture := e2e.SubstrateCounterFixture() + wp, err := clients.SubstrateK8s.ApiV1alpha1().WorkerPools(fixture.PoolNamespace).Get(ctx, fixture.PoolName, metav1.GetOptions{}) + if err != nil { + t.Fatalf("failed to get WorkerPool %s/%s (deploy with: %s): %v", fixture.PoolNamespace, fixture.PoolName, fixture.DeployWith, err) + } + if name := wp.Spec.SandboxConfigName; name != "" { + sc, err := clients.SubstrateK8s.ApiV1alpha1().SandboxConfigs().Get(ctx, name, metav1.GetOptions{}) + if err != nil { + t.Fatalf("failed to get SandboxConfig %q named by WorkerPool %s/%s: %v", name, fixture.PoolNamespace, fixture.PoolName, err) + } + return sc + } + class := wp.Spec.SandboxClass + if class == "" { + class = v1alpha1.SandboxClassGvisor + } + list, err := clients.SubstrateK8s.ApiV1alpha1().SandboxConfigs().List(ctx, metav1.ListOptions{}) + if err != nil { + t.Fatalf("failed to list SandboxConfigs: %v", err) + } + for i := range list.Items { + if sc := &list.Items[i]; sc.Spec.SandboxClass == class && sc.Spec.Default { + return sc + } + } + t.Fatalf("no default SandboxConfig for class %q", class) + return nil +} diff --git a/internal/e2e/template.go b/internal/e2e/template.go index c914a94b59..861cf3c681 100644 --- a/internal/e2e/template.go +++ b/internal/e2e/template.go @@ -42,6 +42,10 @@ type SubstrateTemplateOptions struct { // k8s namespace. PoolName string PoolReplicas int32 + // PoolSandboxConfigName, when set, replaces the source pool's + // SandboxConfigName on the new WorkerPool, pointing its workers (and the + // golden snapshot built on them) at a different SandboxConfig. + PoolSandboxConfigName string // Labels tie the template's workerSelector to the pool, keeping this // pool's workers invisible to other namespaces' actors. Labels map[string]string @@ -91,6 +95,9 @@ func CreateSubstrateTemplateFrom(ctx context.Context, t *testing.T, clients *Cli SandboxConfigName: existingWp.Spec.SandboxConfigName, }, } + if opts.PoolSandboxConfigName != "" { + wp.Spec.SandboxConfigName = opts.PoolSandboxConfigName + } if _, err := clients.SubstrateK8s.ApiV1alpha1().WorkerPools(namespace).Create(ctx, wp, metav1.CreateOptions{}); err != nil { t.Fatalf("failed to create WorkerPool: %v", err) } diff --git a/internal/proto/ateletpb/atelet.pb.go b/internal/proto/ateletpb/atelet.pb.go index a060b537cd..b4308f1153 100644 --- a/internal/proto/ateletpb/atelet.pb.go +++ b/internal/proto/ateletpb/atelet.pb.go @@ -443,8 +443,9 @@ type RunRequest struct { ActorTemplateName string `protobuf:"bytes,6,opt,name=actor_template_name,json=actorTemplateName,proto3" json:"actor_template_name,omitempty"` Spec *WorkloadSpec `protobuf:"bytes,7,opt,name=spec,proto3" json:"spec,omitempty"` // The sandbox binaries to use for booting this actor from scratch. atelet - // fetches the relevant assets and records them with the actor's on-node state - // so a later Checkpoint can pin the same version into the snapshot manifest. + // fetches the relevant assets and records them (with their SandboxConfig + // reference) in the actor's on-node state so a later Checkpoint can pin the + // reference into the snapshot manifest. SandboxAssets *SandboxAssets `protobuf:"bytes,8,opt,name=sandbox_assets,json=sandboxAssets,proto3" json:"sandbox_assets,omitempty"` // When absent, actor traffic uses direct egress instead of atunnel. EgressGateway *EgressGateway `protobuf:"bytes,9,opt,name=egress_gateway,json=egressGateway,proto3,oneof" json:"egress_gateway,omitempty"` @@ -713,6 +714,72 @@ func (x *ArchAssets) GetFiles() map[string]*AssetFile { return nil } +// SandboxConfigRef references a cluster-scoped SandboxConfig Kubernetes +// object by name, UID, and resource version. The UID distinguishes an object +// from a later re-creation under the same name; the resource version pins the +// exact object version. +type SandboxConfigRef struct { + state protoimpl.MessageState `protogen:"open.v1"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Uid string `protobuf:"bytes,2,opt,name=uid,proto3" json:"uid,omitempty"` + // resource_version is the object's metadata.resourceVersion at the time + // the control plane resolved the request from it. + ResourceVersion string `protobuf:"bytes,3,opt,name=resource_version,json=resourceVersion,proto3" json:"resource_version,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxConfigRef) Reset() { + *x = SandboxConfigRef{} + mi := &file_atelet_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxConfigRef) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxConfigRef) ProtoMessage() {} + +func (x *SandboxConfigRef) ProtoReflect() protoreflect.Message { + mi := &file_atelet_proto_msgTypes[8] + 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 SandboxConfigRef.ProtoReflect.Descriptor instead. +func (*SandboxConfigRef) Descriptor() ([]byte, []int) { + return file_atelet_proto_rawDescGZIP(), []int{8} +} + +func (x *SandboxConfigRef) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *SandboxConfigRef) GetUid() string { + if x != nil { + return x.Uid + } + return "" +} + +func (x *SandboxConfigRef) GetResourceVersion() string { + if x != nil { + return x.ResourceVersion + } + return "" +} + // SandboxAssets is the generic, backend-agnostic description of the sandbox // an actor runs in: a sandbox class, the pause image holding its namespaces, // and binaries keyed first by architecture (GOARCH) and then by asset name. @@ -723,17 +790,20 @@ type SandboxAssets struct { SandboxClass string `protobuf:"bytes,1,opt,name=sandbox_class,json=sandboxClass,proto3" json:"sandbox_class,omitempty"` // e.g. "gvisor" Assets map[string]*ArchAssets `protobuf:"bytes,2,rep,name=assets,proto3" json:"assets,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` // arch -> {name -> file} // pause_image is the image for the sandbox's root container. Like the - // binaries above it is sandbox configuration, not workload configuration, - // and atelet pins it into the snapshot manifest so a restore rebuilds the - // sandbox from the same image. - PauseImage string `protobuf:"bytes,3,opt,name=pause_image,json=pauseImage,proto3" json:"pause_image,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // binaries above it is sandbox configuration, not workload configuration. + PauseImage string `protobuf:"bytes,3,opt,name=pause_image,json=pauseImage,proto3" json:"pause_image,omitempty"` + // Reference to the SandboxConfig object these assets were resolved from. + // atelet keeps it in the actor's on-node record and pins it into the + // snapshot manifest; the control plane stores it on the ActorSnapshot and + // resolves a later restore's assets from it. + SandboxConfigRef *SandboxConfigRef `protobuf:"bytes,4,opt,name=sandbox_config_ref,json=sandboxConfigRef,proto3" json:"sandbox_config_ref,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *SandboxAssets) Reset() { *x = SandboxAssets{} - mi := &file_atelet_proto_msgTypes[8] + mi := &file_atelet_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -745,7 +815,7 @@ func (x *SandboxAssets) String() string { func (*SandboxAssets) ProtoMessage() {} func (x *SandboxAssets) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[8] + mi := &file_atelet_proto_msgTypes[9] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -758,7 +828,7 @@ func (x *SandboxAssets) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxAssets.ProtoReflect.Descriptor instead. func (*SandboxAssets) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{8} + return file_atelet_proto_rawDescGZIP(), []int{9} } func (x *SandboxAssets) GetSandboxClass() string { @@ -782,6 +852,13 @@ func (x *SandboxAssets) GetPauseImage() string { return "" } +func (x *SandboxAssets) GetSandboxConfigRef() *SandboxConfigRef { + if x != nil { + return x.SandboxConfigRef + } + return nil +} + // WorkloadSpec parallels Pod, but with far fewer configurable fields. type WorkloadSpec struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -793,7 +870,7 @@ type WorkloadSpec struct { func (x *WorkloadSpec) Reset() { *x = WorkloadSpec{} - mi := &file_atelet_proto_msgTypes[9] + mi := &file_atelet_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -805,7 +882,7 @@ func (x *WorkloadSpec) String() string { func (*WorkloadSpec) ProtoMessage() {} func (x *WorkloadSpec) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[9] + mi := &file_atelet_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -818,7 +895,7 @@ func (x *WorkloadSpec) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkloadSpec.ProtoReflect.Descriptor instead. func (*WorkloadSpec) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{9} + return file_atelet_proto_rawDescGZIP(), []int{10} } func (x *WorkloadSpec) GetContainers() []*Container { @@ -843,7 +920,7 @@ type DurableDirVolume struct { func (x *DurableDirVolume) Reset() { *x = DurableDirVolume{} - mi := &file_atelet_proto_msgTypes[10] + mi := &file_atelet_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -855,7 +932,7 @@ func (x *DurableDirVolume) String() string { func (*DurableDirVolume) ProtoMessage() {} func (x *DurableDirVolume) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[10] + mi := &file_atelet_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -868,7 +945,7 @@ func (x *DurableDirVolume) ProtoReflect() protoreflect.Message { // Deprecated: Use DurableDirVolume.ProtoReflect.Descriptor instead. func (*DurableDirVolume) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{10} + return file_atelet_proto_rawDescGZIP(), []int{11} } type ExternalVolumeSource struct { @@ -882,7 +959,7 @@ type ExternalVolumeSource struct { func (x *ExternalVolumeSource) Reset() { *x = ExternalVolumeSource{} - mi := &file_atelet_proto_msgTypes[11] + mi := &file_atelet_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -894,7 +971,7 @@ func (x *ExternalVolumeSource) String() string { func (*ExternalVolumeSource) ProtoMessage() {} func (x *ExternalVolumeSource) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[11] + mi := &file_atelet_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -907,7 +984,7 @@ func (x *ExternalVolumeSource) ProtoReflect() protoreflect.Message { // Deprecated: Use ExternalVolumeSource.ProtoReflect.Descriptor instead. func (*ExternalVolumeSource) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{11} + return file_atelet_proto_rawDescGZIP(), []int{12} } func (x *ExternalVolumeSource) GetStorageVolumeId() string { @@ -940,7 +1017,7 @@ type ImageVolumeSource struct { func (x *ImageVolumeSource) Reset() { *x = ImageVolumeSource{} - mi := &file_atelet_proto_msgTypes[12] + mi := &file_atelet_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -952,7 +1029,7 @@ func (x *ImageVolumeSource) String() string { func (*ImageVolumeSource) ProtoMessage() {} func (x *ImageVolumeSource) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[12] + mi := &file_atelet_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -965,7 +1042,7 @@ func (x *ImageVolumeSource) ProtoReflect() protoreflect.Message { // Deprecated: Use ImageVolumeSource.ProtoReflect.Descriptor instead. func (*ImageVolumeSource) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{12} + return file_atelet_proto_rawDescGZIP(), []int{13} } func (x *ImageVolumeSource) GetReference() string { @@ -987,7 +1064,7 @@ type ActorMetadataItem struct { func (x *ActorMetadataItem) Reset() { *x = ActorMetadataItem{} - mi := &file_atelet_proto_msgTypes[13] + mi := &file_atelet_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -999,7 +1076,7 @@ func (x *ActorMetadataItem) String() string { func (*ActorMetadataItem) ProtoMessage() {} func (x *ActorMetadataItem) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[13] + mi := &file_atelet_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1012,7 +1089,7 @@ func (x *ActorMetadataItem) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorMetadataItem.ProtoReflect.Descriptor instead. func (*ActorMetadataItem) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{13} + return file_atelet_proto_rawDescGZIP(), []int{14} } func (x *ActorMetadataItem) GetField() ActorMetadataField { @@ -1040,7 +1117,7 @@ type ActorMetadataDataSource struct { func (x *ActorMetadataDataSource) Reset() { *x = ActorMetadataDataSource{} - mi := &file_atelet_proto_msgTypes[14] + mi := &file_atelet_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1052,7 +1129,7 @@ func (x *ActorMetadataDataSource) String() string { func (*ActorMetadataDataSource) ProtoMessage() {} func (x *ActorMetadataDataSource) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[14] + mi := &file_atelet_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1065,7 +1142,7 @@ func (x *ActorMetadataDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorMetadataDataSource.ProtoReflect.Descriptor instead. func (*ActorMetadataDataSource) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{14} + return file_atelet_proto_rawDescGZIP(), []int{15} } func (x *ActorMetadataDataSource) GetItems() []*ActorMetadataItem { @@ -1091,7 +1168,7 @@ type TrustBundleDataSource struct { func (x *TrustBundleDataSource) Reset() { *x = TrustBundleDataSource{} - mi := &file_atelet_proto_msgTypes[15] + mi := &file_atelet_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1103,7 +1180,7 @@ func (x *TrustBundleDataSource) String() string { func (*TrustBundleDataSource) ProtoMessage() {} func (x *TrustBundleDataSource) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[15] + mi := &file_atelet_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1116,7 +1193,7 @@ func (x *TrustBundleDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use TrustBundleDataSource.ProtoReflect.Descriptor instead. func (*TrustBundleDataSource) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{15} + return file_atelet_proto_rawDescGZIP(), []int{16} } func (x *TrustBundleDataSource) GetPath() string { @@ -1146,7 +1223,7 @@ type SystemInfoDataSource struct { func (x *SystemInfoDataSource) Reset() { *x = SystemInfoDataSource{} - mi := &file_atelet_proto_msgTypes[16] + mi := &file_atelet_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1158,7 +1235,7 @@ func (x *SystemInfoDataSource) String() string { func (*SystemInfoDataSource) ProtoMessage() {} func (x *SystemInfoDataSource) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[16] + mi := &file_atelet_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1171,7 +1248,7 @@ func (x *SystemInfoDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemInfoDataSource.ProtoReflect.Descriptor instead. func (*SystemInfoDataSource) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{16} + return file_atelet_proto_rawDescGZIP(), []int{17} } func (x *SystemInfoDataSource) GetDataSource() isSystemInfoDataSource_DataSource { @@ -1227,7 +1304,7 @@ type SystemInfoVolume struct { func (x *SystemInfoVolume) Reset() { *x = SystemInfoVolume{} - mi := &file_atelet_proto_msgTypes[17] + mi := &file_atelet_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1239,7 +1316,7 @@ func (x *SystemInfoVolume) String() string { func (*SystemInfoVolume) ProtoMessage() {} func (x *SystemInfoVolume) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[17] + mi := &file_atelet_proto_msgTypes[18] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1252,7 +1329,7 @@ func (x *SystemInfoVolume) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemInfoVolume.ProtoReflect.Descriptor instead. func (*SystemInfoVolume) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{17} + return file_atelet_proto_rawDescGZIP(), []int{18} } func (x *SystemInfoVolume) GetDataSources() []*SystemInfoDataSource { @@ -1278,7 +1355,7 @@ type Volume struct { func (x *Volume) Reset() { *x = Volume{} - mi := &file_atelet_proto_msgTypes[18] + mi := &file_atelet_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1290,7 +1367,7 @@ func (x *Volume) String() string { func (*Volume) ProtoMessage() {} func (x *Volume) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[18] + mi := &file_atelet_proto_msgTypes[19] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1303,7 +1380,7 @@ func (x *Volume) ProtoReflect() protoreflect.Message { // Deprecated: Use Volume.ProtoReflect.Descriptor instead. func (*Volume) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{18} + return file_atelet_proto_rawDescGZIP(), []int{19} } func (x *Volume) GetName() string { @@ -1394,7 +1471,7 @@ type VolumeMount struct { func (x *VolumeMount) Reset() { *x = VolumeMount{} - mi := &file_atelet_proto_msgTypes[19] + mi := &file_atelet_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1406,7 +1483,7 @@ func (x *VolumeMount) String() string { func (*VolumeMount) ProtoMessage() {} func (x *VolumeMount) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[19] + mi := &file_atelet_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1419,7 +1496,7 @@ func (x *VolumeMount) ProtoReflect() protoreflect.Message { // Deprecated: Use VolumeMount.ProtoReflect.Descriptor instead. func (*VolumeMount) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{19} + return file_atelet_proto_rawDescGZIP(), []int{20} } func (x *VolumeMount) GetName() string { @@ -1455,7 +1532,7 @@ type Container struct { func (x *Container) Reset() { *x = Container{} - mi := &file_atelet_proto_msgTypes[20] + mi := &file_atelet_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1467,7 +1544,7 @@ func (x *Container) String() string { func (*Container) ProtoMessage() {} func (x *Container) ProtoReflect() protoreflect.Message { - mi := &file_atelet_proto_msgTypes[20] + mi := &file_atelet_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1480,7 +1557,7 @@ func (x *Container) ProtoReflect() protoreflect.Message { // Deprecated: Use Container.ProtoReflect.Descriptor instead. func (*Container) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{20} + return file_atelet_proto_rawDescGZIP(), []int{21} } func (x *Container) GetName() string { @@ -1556,7 +1633,7 @@ type SecurityContext struct { func (x *SecurityContext) Reset() { *x = SecurityContext{} - mi := &file_atelet_proto_msgTypes[21] + mi := &file_atelet_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1568,7 +1645,7 @@ func (x *SecurityContext) String() string { func (*SecurityContext) ProtoMessage() {} func (x *SecurityContext) 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 { @@ -1581,7 +1658,7 @@ func (x *SecurityContext) ProtoReflect() protoreflect.Message { // Deprecated: Use SecurityContext.ProtoReflect.Descriptor instead. func (*SecurityContext) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{21} + return file_atelet_proto_rawDescGZIP(), []int{22} } func (x *SecurityContext) GetCapabilities() *Capabilities { @@ -1603,7 +1680,7 @@ type Capabilities struct { func (x *Capabilities) Reset() { *x = Capabilities{} - mi := &file_atelet_proto_msgTypes[22] + mi := &file_atelet_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1615,7 +1692,7 @@ func (x *Capabilities) String() string { func (*Capabilities) ProtoMessage() {} func (x *Capabilities) 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 { @@ -1628,7 +1705,7 @@ func (x *Capabilities) ProtoReflect() protoreflect.Message { // Deprecated: Use Capabilities.ProtoReflect.Descriptor instead. func (*Capabilities) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{22} + return file_atelet_proto_rawDescGZIP(), []int{23} } func (x *Capabilities) GetAdd() []string { @@ -1659,7 +1736,7 @@ type ResourceLimits struct { func (x *ResourceLimits) Reset() { *x = ResourceLimits{} - mi := &file_atelet_proto_msgTypes[23] + mi := &file_atelet_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1671,7 +1748,7 @@ func (x *ResourceLimits) String() string { func (*ResourceLimits) ProtoMessage() {} func (x *ResourceLimits) 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 { @@ -1684,7 +1761,7 @@ func (x *ResourceLimits) ProtoReflect() protoreflect.Message { // Deprecated: Use ResourceLimits.ProtoReflect.Descriptor instead. func (*ResourceLimits) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{23} + return file_atelet_proto_rawDescGZIP(), []int{24} } func (x *ResourceLimits) GetMemoryBytes() int64 { @@ -1711,7 +1788,7 @@ type EnvEntry struct { func (x *EnvEntry) Reset() { *x = EnvEntry{} - mi := &file_atelet_proto_msgTypes[24] + mi := &file_atelet_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1723,7 +1800,7 @@ func (x *EnvEntry) String() string { func (*EnvEntry) ProtoMessage() {} func (x *EnvEntry) 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 { @@ -1736,7 +1813,7 @@ func (x *EnvEntry) ProtoReflect() protoreflect.Message { // Deprecated: Use EnvEntry.ProtoReflect.Descriptor instead. func (*EnvEntry) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{24} + return file_atelet_proto_rawDescGZIP(), []int{25} } func (x *EnvEntry) GetName() string { @@ -1767,7 +1844,7 @@ type Readyz struct { func (x *Readyz) Reset() { *x = Readyz{} - mi := &file_atelet_proto_msgTypes[25] + mi := &file_atelet_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1779,7 +1856,7 @@ func (x *Readyz) String() string { func (*Readyz) ProtoMessage() {} func (x *Readyz) 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 { @@ -1792,7 +1869,7 @@ func (x *Readyz) ProtoReflect() protoreflect.Message { // Deprecated: Use Readyz.ProtoReflect.Descriptor instead. func (*Readyz) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{25} + return file_atelet_proto_rawDescGZIP(), []int{26} } func (x *Readyz) GetHttpGet() *HTTPGetAction { @@ -1822,7 +1899,7 @@ type HTTPGetAction struct { func (x *HTTPGetAction) Reset() { *x = HTTPGetAction{} - mi := &file_atelet_proto_msgTypes[26] + mi := &file_atelet_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1834,7 +1911,7 @@ func (x *HTTPGetAction) String() string { func (*HTTPGetAction) ProtoMessage() {} func (x *HTTPGetAction) 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 { @@ -1847,7 +1924,7 @@ func (x *HTTPGetAction) ProtoReflect() protoreflect.Message { // Deprecated: Use HTTPGetAction.ProtoReflect.Descriptor instead. func (*HTTPGetAction) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{26} + return file_atelet_proto_rawDescGZIP(), []int{27} } func (x *HTTPGetAction) GetPath() string { @@ -1872,7 +1949,7 @@ type RunResponse struct { func (x *RunResponse) Reset() { *x = RunResponse{} - mi := &file_atelet_proto_msgTypes[27] + mi := &file_atelet_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1884,7 +1961,7 @@ func (x *RunResponse) String() string { func (*RunResponse) ProtoMessage() {} func (x *RunResponse) 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 { @@ -1897,7 +1974,7 @@ func (x *RunResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RunResponse.ProtoReflect.Descriptor instead. func (*RunResponse) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{27} + return file_atelet_proto_rawDescGZIP(), []int{28} } type LocalCheckpointConfiguration struct { @@ -1913,7 +1990,7 @@ type LocalCheckpointConfiguration struct { func (x *LocalCheckpointConfiguration) Reset() { *x = LocalCheckpointConfiguration{} - mi := &file_atelet_proto_msgTypes[28] + mi := &file_atelet_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1925,7 +2002,7 @@ func (x *LocalCheckpointConfiguration) String() string { func (*LocalCheckpointConfiguration) ProtoMessage() {} func (x *LocalCheckpointConfiguration) 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 { @@ -1938,7 +2015,7 @@ func (x *LocalCheckpointConfiguration) ProtoReflect() protoreflect.Message { // Deprecated: Use LocalCheckpointConfiguration.ProtoReflect.Descriptor instead. func (*LocalCheckpointConfiguration) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{28} + return file_atelet_proto_rawDescGZIP(), []int{29} } func (x *LocalCheckpointConfiguration) GetSnapshotName() string { @@ -1959,7 +2036,7 @@ type ExternalCheckpointConfiguration struct { func (x *ExternalCheckpointConfiguration) Reset() { *x = ExternalCheckpointConfiguration{} - mi := &file_atelet_proto_msgTypes[29] + mi := &file_atelet_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1971,7 +2048,7 @@ func (x *ExternalCheckpointConfiguration) String() string { func (*ExternalCheckpointConfiguration) ProtoMessage() {} func (x *ExternalCheckpointConfiguration) 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 { @@ -1984,7 +2061,7 @@ func (x *ExternalCheckpointConfiguration) ProtoReflect() protoreflect.Message { // Deprecated: Use ExternalCheckpointConfiguration.ProtoReflect.Descriptor instead. func (*ExternalCheckpointConfiguration) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{29} + return file_atelet_proto_rawDescGZIP(), []int{30} } func (x *ExternalCheckpointConfiguration) GetSnapshotUri() string { @@ -2002,9 +2079,10 @@ type CheckpointRequest struct { ActorUid string `protobuf:"bytes,4,opt,name=actor_uid,json=actorUid,proto3" json:"actor_uid,omitempty"` ActorTemplateAtespace string `protobuf:"bytes,5,opt,name=actor_template_atespace,json=actorTemplateAtespace,proto3" json:"actor_template_atespace,omitempty"` ActorTemplateName string `protobuf:"bytes,6,opt,name=actor_template_name,json=actorTemplateName,proto3" json:"actor_template_name,omitempty"` - // Sandbox binary config is not sent on checkpoint: atelet uses the version the - // actor is currently running (recorded with the actor's on-node state at - // Run/Restore) and records it into the snapshot manifest. + // Sandbox binary config is not sent on checkpoint: atelet uses the version + // the actor is currently running (recorded with the actor's on-node state + // at Run/Restore) and records its SandboxConfig reference into the snapshot + // manifest. Spec *WorkloadSpec `protobuf:"bytes,7,opt,name=spec,proto3" json:"spec,omitempty"` Type CheckpointType `protobuf:"varint,8,opt,name=type,proto3,enum=atelet.CheckpointType" json:"type,omitempty"` // The checkpoint configuration, depending on the type. @@ -2022,7 +2100,7 @@ type CheckpointRequest struct { func (x *CheckpointRequest) Reset() { *x = CheckpointRequest{} - mi := &file_atelet_proto_msgTypes[30] + mi := &file_atelet_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2034,7 +2112,7 @@ func (x *CheckpointRequest) String() string { func (*CheckpointRequest) ProtoMessage() {} func (x *CheckpointRequest) 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 { @@ -2047,7 +2125,7 @@ func (x *CheckpointRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckpointRequest.ProtoReflect.Descriptor instead. func (*CheckpointRequest) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{30} + return file_atelet_proto_rawDescGZIP(), []int{31} } func (x *CheckpointRequest) GetTargetAteomUid() string { @@ -2155,14 +2233,20 @@ func (*CheckpointRequest_LocalConfig) isCheckpointRequest_Config() {} func (*CheckpointRequest_ExternalConfig) isCheckpointRequest_Config() {} type CheckpointResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + // The SandboxConfig reference from the actor's on-node record — the + // sandbox the checkpoint was actually taken with, as pinned into the + // snapshot manifest. The control plane copies it onto the ActorSnapshot / + // LocalSnapshotInfo record it finalizes for this checkpoint. Unset when + // the record predates the reference. + SandboxConfigRef *SandboxConfigRef `protobuf:"bytes,1,opt,name=sandbox_config_ref,json=sandboxConfigRef,proto3" json:"sandbox_config_ref,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *CheckpointResponse) Reset() { *x = CheckpointResponse{} - mi := &file_atelet_proto_msgTypes[31] + mi := &file_atelet_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2174,7 +2258,7 @@ func (x *CheckpointResponse) String() string { func (*CheckpointResponse) ProtoMessage() {} func (x *CheckpointResponse) 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 { @@ -2187,7 +2271,14 @@ func (x *CheckpointResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckpointResponse.ProtoReflect.Descriptor instead. func (*CheckpointResponse) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{31} + return file_atelet_proto_rawDescGZIP(), []int{32} +} + +func (x *CheckpointResponse) GetSandboxConfigRef() *SandboxConfigRef { + if x != nil { + return x.SandboxConfigRef + } + return nil } type UploadPausedCheckpointRequest struct { @@ -2215,7 +2306,7 @@ type UploadPausedCheckpointRequest struct { func (x *UploadPausedCheckpointRequest) Reset() { *x = UploadPausedCheckpointRequest{} - mi := &file_atelet_proto_msgTypes[32] + mi := &file_atelet_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2227,7 +2318,7 @@ func (x *UploadPausedCheckpointRequest) String() string { func (*UploadPausedCheckpointRequest) ProtoMessage() {} func (x *UploadPausedCheckpointRequest) 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 { @@ -2240,7 +2331,7 @@ func (x *UploadPausedCheckpointRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UploadPausedCheckpointRequest.ProtoReflect.Descriptor instead. func (*UploadPausedCheckpointRequest) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{32} + return file_atelet_proto_rawDescGZIP(), []int{33} } func (x *UploadPausedCheckpointRequest) GetAtespace() string { @@ -2307,7 +2398,7 @@ type UploadPausedCheckpointResponse struct { func (x *UploadPausedCheckpointResponse) Reset() { *x = UploadPausedCheckpointResponse{} - mi := &file_atelet_proto_msgTypes[33] + mi := &file_atelet_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2319,7 +2410,7 @@ func (x *UploadPausedCheckpointResponse) String() string { func (*UploadPausedCheckpointResponse) ProtoMessage() {} func (x *UploadPausedCheckpointResponse) 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 { @@ -2332,7 +2423,7 @@ func (x *UploadPausedCheckpointResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UploadPausedCheckpointResponse.ProtoReflect.Descriptor instead. func (*UploadPausedCheckpointResponse) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{33} + return file_atelet_proto_rawDescGZIP(), []int{34} } type RestoreRequest struct { @@ -2343,11 +2434,8 @@ type RestoreRequest struct { ActorUid string `protobuf:"bytes,4,opt,name=actor_uid,json=actorUid,proto3" json:"actor_uid,omitempty"` ActorTemplateAtespace string `protobuf:"bytes,5,opt,name=actor_template_atespace,json=actorTemplateAtespace,proto3" json:"actor_template_atespace,omitempty"` ActorTemplateName string `protobuf:"bytes,6,opt,name=actor_template_name,json=actorTemplateName,proto3" json:"actor_template_name,omitempty"` - // Sandbox binary config is not sent on restore: the snapshot is - // self-describing. atelet reads the snapshot manifest to recover the pinned - // sandbox version that created it. - Spec *WorkloadSpec `protobuf:"bytes,7,opt,name=spec,proto3" json:"spec,omitempty"` - Type CheckpointType `protobuf:"varint,8,opt,name=type,proto3,enum=atelet.CheckpointType" json:"type,omitempty"` + Spec *WorkloadSpec `protobuf:"bytes,7,opt,name=spec,proto3" json:"spec,omitempty"` + Type CheckpointType `protobuf:"varint,8,opt,name=type,proto3,enum=atelet.CheckpointType" json:"type,omitempty"` // The checkpoint configuration, depending on the type. // // Types that are valid to be assigned to Config: @@ -2370,15 +2458,19 @@ type RestoreRequest struct { // gVisor and micro-VM DATA-scope restores the sandbox is (re)sized to these; // for a FULL micro-VM restore the size baked into the snapshot wins. Zero // means "unset": keep the runtime default. - CpuMilli int64 `protobuf:"varint,14,opt,name=cpu_milli,json=cpuMilli,proto3" json:"cpu_milli,omitempty"` // CPU limit in millicores (1000 = one core). - MemoryBytes int64 `protobuf:"varint,15,opt,name=memory_bytes,json=memoryBytes,proto3" json:"memory_bytes,omitempty"` // Memory limit in bytes. + CpuMilli int64 `protobuf:"varint,14,opt,name=cpu_milli,json=cpuMilli,proto3" json:"cpu_milli,omitempty"` // CPU limit in millicores (1000 = one core). + MemoryBytes int64 `protobuf:"varint,15,opt,name=memory_bytes,json=memoryBytes,proto3" json:"memory_bytes,omitempty"` // Memory limit in bytes. + // The sandbox binaries to restore this actor with. Required: the snapshot + // manifest carries only a SandboxConfig reference, never asset content, + // so this is the only source of binaries for a restore. + SandboxAssets *SandboxAssets `protobuf:"bytes,16,opt,name=sandbox_assets,json=sandboxAssets,proto3" json:"sandbox_assets,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *RestoreRequest) Reset() { *x = RestoreRequest{} - mi := &file_atelet_proto_msgTypes[34] + mi := &file_atelet_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2390,7 +2482,7 @@ func (x *RestoreRequest) String() string { func (*RestoreRequest) ProtoMessage() {} func (x *RestoreRequest) 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 { @@ -2403,7 +2495,7 @@ func (x *RestoreRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RestoreRequest.ProtoReflect.Descriptor instead. func (*RestoreRequest) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{34} + return file_atelet_proto_rawDescGZIP(), []int{35} } func (x *RestoreRequest) GetTargetAteomUid() string { @@ -2522,6 +2614,13 @@ func (x *RestoreRequest) GetMemoryBytes() int64 { return 0 } +func (x *RestoreRequest) GetSandboxAssets() *SandboxAssets { + if x != nil { + return x.SandboxAssets + } + return nil +} + type isRestoreRequest_Config interface { isRestoreRequest_Config() } @@ -2546,7 +2645,7 @@ type RestoreResponse struct { func (x *RestoreResponse) Reset() { *x = RestoreResponse{} - mi := &file_atelet_proto_msgTypes[35] + mi := &file_atelet_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2558,7 +2657,7 @@ func (x *RestoreResponse) String() string { func (*RestoreResponse) ProtoMessage() {} func (x *RestoreResponse) 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 { @@ -2571,7 +2670,7 @@ func (x *RestoreResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use RestoreResponse.ProtoReflect.Descriptor instead. func (*RestoreResponse) Descriptor() ([]byte, []int) { - return file_atelet_proto_rawDescGZIP(), []int{35} + return file_atelet_proto_rawDescGZIP(), []int{36} } var File_atelet_proto protoreflect.FileDescriptor @@ -2621,12 +2720,17 @@ const file_atelet_proto_rawDesc = "" + "\n" + "FilesEntry\x12\x10\n" + "\x03key\x18\x01 \x01(\tR\x03key\x12'\n" + - "\x05value\x18\x02 \x01(\v2\x11.atelet.AssetFileR\x05value:\x028\x01\"\xdf\x01\n" + + "\x05value\x18\x02 \x01(\v2\x11.atelet.AssetFileR\x05value:\x028\x01\"c\n" + + "\x10SandboxConfigRef\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x10\n" + + "\x03uid\x18\x02 \x01(\tR\x03uid\x12)\n" + + "\x10resource_version\x18\x03 \x01(\tR\x0fresourceVersion\"\xa7\x02\n" + "\rSandboxAssets\x12#\n" + "\rsandbox_class\x18\x01 \x01(\tR\fsandboxClass\x129\n" + "\x06assets\x18\x02 \x03(\v2!.atelet.SandboxAssets.AssetsEntryR\x06assets\x12\x1f\n" + "\vpause_image\x18\x03 \x01(\tR\n" + - "pauseImage\x1aM\n" + + "pauseImage\x12F\n" + + "\x12sandbox_config_ref\x18\x04 \x01(\v2\x18.atelet.SandboxConfigRefR\x10sandboxConfigRef\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\"~\n" + @@ -2720,8 +2824,9 @@ const file_atelet_proto_rawDesc = "" + "\x0fexternal_config\x18\n" + " \x01(\v2'.atelet.ExternalCheckpointConfigurationH\x00R\x0eexternalConfig\x12+\n" + "\x05scope\x18\v \x01(\x0e2\x15.atelet.SnapshotScopeR\x05scopeB\b\n" + - "\x06config\"\x14\n" + - "\x12CheckpointResponse\"\x85\x03\n" + + "\x06config\"\\\n" + + "\x12CheckpointResponse\x12F\n" + + "\x12sandbox_config_ref\x18\x01 \x01(\v2\x18.atelet.SandboxConfigRefR\x10sandboxConfigRef\"\x85\x03\n" + "\x1dUploadPausedCheckpointRequest\x12\x1a\n" + "\batespace\x18\x01 \x01(\tR\batespace\x12\x1d\n" + "\n" + @@ -2732,7 +2837,7 @@ const file_atelet_proto_rawDesc = "" + "\x13local_snapshot_name\x18\x06 \x01(\tR\x11localSnapshotName\x128\n" + "\x18destination_snapshot_uri\x18\a \x01(\tR\x16destinationSnapshotUri\x12:\n" + "\rdesired_scope\x18\b \x01(\x0e2\x15.atelet.SnapshotScopeR\fdesiredScope\" \n" + - "\x1eUploadPausedCheckpointResponse\"\xec\x05\n" + + "\x1eUploadPausedCheckpointResponse\"\xaa\x06\n" + "\x0eRestoreRequest\x12(\n" + "\x10target_ateom_uid\x18\x01 \x01(\tR\x0etargetAteomUid\x12\x1a\n" + "\batespace\x18\x02 \x01(\tR\batespace\x12\x1d\n" + @@ -2750,7 +2855,8 @@ const file_atelet_proto_rawDesc = "" + "\x13golden_snapshot_uri\x18\f \x01(\tR\x11goldenSnapshotUri\x12A\n" + "\x0eegress_gateway\x18\r \x01(\v2\x15.atelet.EgressGatewayH\x01R\regressGateway\x88\x01\x01\x12\x1b\n" + "\tcpu_milli\x18\x0e \x01(\x03R\bcpuMilli\x12!\n" + - "\fmemory_bytes\x18\x0f \x01(\x03R\vmemoryBytesB\b\n" + + "\fmemory_bytes\x18\x0f \x01(\x03R\vmemoryBytes\x12<\n" + + "\x0esandbox_assets\x18\x10 \x01(\v2\x15.atelet.SandboxAssetsR\rsandboxAssetsB\b\n" + "\x06configB\x11\n" + "\x0f_egress_gateway\"\x11\n" + "\x0fRestoreResponse*\x9a\x01\n" + @@ -2791,7 +2897,7 @@ func file_atelet_proto_rawDescGZIP() []byte { } var file_atelet_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_atelet_proto_msgTypes = make([]protoimpl.MessageInfo, 39) +var file_atelet_proto_msgTypes = make([]protoimpl.MessageInfo, 40) var file_atelet_proto_goTypes = []any{ (ActorMetadataField)(0), // 0: atelet.ActorMetadataField (CheckpointType)(0), // 1: atelet.CheckpointType @@ -2804,95 +2910,99 @@ var file_atelet_proto_goTypes = []any{ (*EgressGateway)(nil), // 8: atelet.EgressGateway (*AssetFile)(nil), // 9: atelet.AssetFile (*ArchAssets)(nil), // 10: atelet.ArchAssets - (*SandboxAssets)(nil), // 11: atelet.SandboxAssets - (*WorkloadSpec)(nil), // 12: atelet.WorkloadSpec - (*DurableDirVolume)(nil), // 13: atelet.DurableDirVolume - (*ExternalVolumeSource)(nil), // 14: atelet.ExternalVolumeSource - (*ImageVolumeSource)(nil), // 15: atelet.ImageVolumeSource - (*ActorMetadataItem)(nil), // 16: atelet.ActorMetadataItem - (*ActorMetadataDataSource)(nil), // 17: atelet.ActorMetadataDataSource - (*TrustBundleDataSource)(nil), // 18: atelet.TrustBundleDataSource - (*SystemInfoDataSource)(nil), // 19: atelet.SystemInfoDataSource - (*SystemInfoVolume)(nil), // 20: atelet.SystemInfoVolume - (*Volume)(nil), // 21: atelet.Volume - (*VolumeMount)(nil), // 22: atelet.VolumeMount - (*Container)(nil), // 23: atelet.Container - (*SecurityContext)(nil), // 24: atelet.SecurityContext - (*Capabilities)(nil), // 25: atelet.Capabilities - (*ResourceLimits)(nil), // 26: atelet.ResourceLimits - (*EnvEntry)(nil), // 27: atelet.EnvEntry - (*Readyz)(nil), // 28: atelet.Readyz - (*HTTPGetAction)(nil), // 29: atelet.HTTPGetAction - (*RunResponse)(nil), // 30: atelet.RunResponse - (*LocalCheckpointConfiguration)(nil), // 31: atelet.LocalCheckpointConfiguration - (*ExternalCheckpointConfiguration)(nil), // 32: atelet.ExternalCheckpointConfiguration - (*CheckpointRequest)(nil), // 33: atelet.CheckpointRequest - (*CheckpointResponse)(nil), // 34: atelet.CheckpointResponse - (*UploadPausedCheckpointRequest)(nil), // 35: atelet.UploadPausedCheckpointRequest - (*UploadPausedCheckpointResponse)(nil), // 36: atelet.UploadPausedCheckpointResponse - (*RestoreRequest)(nil), // 37: atelet.RestoreRequest - (*RestoreResponse)(nil), // 38: atelet.RestoreResponse - nil, // 39: atelet.ArchAssets.FilesEntry - nil, // 40: atelet.SandboxAssets.AssetsEntry - nil, // 41: atelet.ExternalVolumeSource.VolumeContextEntry + (*SandboxConfigRef)(nil), // 11: atelet.SandboxConfigRef + (*SandboxAssets)(nil), // 12: atelet.SandboxAssets + (*WorkloadSpec)(nil), // 13: atelet.WorkloadSpec + (*DurableDirVolume)(nil), // 14: atelet.DurableDirVolume + (*ExternalVolumeSource)(nil), // 15: atelet.ExternalVolumeSource + (*ImageVolumeSource)(nil), // 16: atelet.ImageVolumeSource + (*ActorMetadataItem)(nil), // 17: atelet.ActorMetadataItem + (*ActorMetadataDataSource)(nil), // 18: atelet.ActorMetadataDataSource + (*TrustBundleDataSource)(nil), // 19: atelet.TrustBundleDataSource + (*SystemInfoDataSource)(nil), // 20: atelet.SystemInfoDataSource + (*SystemInfoVolume)(nil), // 21: atelet.SystemInfoVolume + (*Volume)(nil), // 22: atelet.Volume + (*VolumeMount)(nil), // 23: atelet.VolumeMount + (*Container)(nil), // 24: atelet.Container + (*SecurityContext)(nil), // 25: atelet.SecurityContext + (*Capabilities)(nil), // 26: atelet.Capabilities + (*ResourceLimits)(nil), // 27: atelet.ResourceLimits + (*EnvEntry)(nil), // 28: atelet.EnvEntry + (*Readyz)(nil), // 29: atelet.Readyz + (*HTTPGetAction)(nil), // 30: atelet.HTTPGetAction + (*RunResponse)(nil), // 31: atelet.RunResponse + (*LocalCheckpointConfiguration)(nil), // 32: atelet.LocalCheckpointConfiguration + (*ExternalCheckpointConfiguration)(nil), // 33: atelet.ExternalCheckpointConfiguration + (*CheckpointRequest)(nil), // 34: atelet.CheckpointRequest + (*CheckpointResponse)(nil), // 35: atelet.CheckpointResponse + (*UploadPausedCheckpointRequest)(nil), // 36: atelet.UploadPausedCheckpointRequest + (*UploadPausedCheckpointResponse)(nil), // 37: atelet.UploadPausedCheckpointResponse + (*RestoreRequest)(nil), // 38: atelet.RestoreRequest + (*RestoreResponse)(nil), // 39: atelet.RestoreResponse + nil, // 40: atelet.ArchAssets.FilesEntry + nil, // 41: atelet.SandboxAssets.AssetsEntry + nil, // 42: atelet.ExternalVolumeSource.VolumeContextEntry } var file_atelet_proto_depIdxs = []int32{ - 12, // 0: atelet.TerminateRequest.spec:type_name -> atelet.WorkloadSpec - 12, // 1: atelet.RunRequest.spec:type_name -> atelet.WorkloadSpec - 11, // 2: atelet.RunRequest.sandbox_assets:type_name -> atelet.SandboxAssets + 13, // 0: atelet.TerminateRequest.spec:type_name -> atelet.WorkloadSpec + 13, // 1: atelet.RunRequest.spec:type_name -> atelet.WorkloadSpec + 12, // 2: atelet.RunRequest.sandbox_assets:type_name -> atelet.SandboxAssets 8, // 3: atelet.RunRequest.egress_gateway:type_name -> atelet.EgressGateway - 39, // 4: atelet.ArchAssets.files:type_name -> atelet.ArchAssets.FilesEntry - 40, // 5: atelet.SandboxAssets.assets:type_name -> atelet.SandboxAssets.AssetsEntry - 23, // 6: atelet.WorkloadSpec.containers:type_name -> atelet.Container - 21, // 7: atelet.WorkloadSpec.volumes:type_name -> atelet.Volume - 41, // 8: atelet.ExternalVolumeSource.volume_context:type_name -> atelet.ExternalVolumeSource.VolumeContextEntry - 0, // 9: atelet.ActorMetadataItem.field:type_name -> atelet.ActorMetadataField - 16, // 10: atelet.ActorMetadataDataSource.items:type_name -> atelet.ActorMetadataItem - 17, // 11: atelet.SystemInfoDataSource.actor_metadata:type_name -> atelet.ActorMetadataDataSource - 18, // 12: atelet.SystemInfoDataSource.trust_bundle:type_name -> atelet.TrustBundleDataSource - 19, // 13: atelet.SystemInfoVolume.data_sources:type_name -> atelet.SystemInfoDataSource - 13, // 14: atelet.Volume.durable_dir:type_name -> atelet.DurableDirVolume - 14, // 15: atelet.Volume.external:type_name -> atelet.ExternalVolumeSource - 20, // 16: atelet.Volume.system_info:type_name -> atelet.SystemInfoVolume - 15, // 17: atelet.Volume.image:type_name -> atelet.ImageVolumeSource - 27, // 18: atelet.Container.env:type_name -> atelet.EnvEntry - 28, // 19: atelet.Container.readyz:type_name -> atelet.Readyz - 22, // 20: atelet.Container.volume_mounts:type_name -> atelet.VolumeMount - 24, // 21: atelet.Container.security_context:type_name -> atelet.SecurityContext - 26, // 22: atelet.Container.resources:type_name -> atelet.ResourceLimits - 25, // 23: atelet.SecurityContext.capabilities:type_name -> atelet.Capabilities - 29, // 24: atelet.Readyz.http_get:type_name -> atelet.HTTPGetAction - 12, // 25: atelet.CheckpointRequest.spec:type_name -> atelet.WorkloadSpec - 1, // 26: atelet.CheckpointRequest.type:type_name -> atelet.CheckpointType - 31, // 27: atelet.CheckpointRequest.local_config:type_name -> atelet.LocalCheckpointConfiguration - 32, // 28: atelet.CheckpointRequest.external_config:type_name -> atelet.ExternalCheckpointConfiguration - 2, // 29: atelet.CheckpointRequest.scope:type_name -> atelet.SnapshotScope - 2, // 30: atelet.UploadPausedCheckpointRequest.desired_scope:type_name -> atelet.SnapshotScope - 12, // 31: atelet.RestoreRequest.spec:type_name -> atelet.WorkloadSpec - 1, // 32: atelet.RestoreRequest.type:type_name -> atelet.CheckpointType - 31, // 33: atelet.RestoreRequest.local_config:type_name -> atelet.LocalCheckpointConfiguration - 32, // 34: atelet.RestoreRequest.external_config:type_name -> atelet.ExternalCheckpointConfiguration - 2, // 35: atelet.RestoreRequest.scope:type_name -> atelet.SnapshotScope - 8, // 36: atelet.RestoreRequest.egress_gateway:type_name -> atelet.EgressGateway - 9, // 37: atelet.ArchAssets.FilesEntry.value:type_name -> atelet.AssetFile - 10, // 38: atelet.SandboxAssets.AssetsEntry.value:type_name -> atelet.ArchAssets - 3, // 39: atelet.CredentialBroker.MintActorCertificate:input_type -> atelet.MintActorCertificateRequest - 7, // 40: atelet.AteomHerder.Run:input_type -> atelet.RunRequest - 33, // 41: atelet.AteomHerder.Checkpoint:input_type -> atelet.CheckpointRequest - 37, // 42: atelet.AteomHerder.Restore:input_type -> atelet.RestoreRequest - 35, // 43: atelet.AteomHerder.UploadPausedCheckpoint:input_type -> atelet.UploadPausedCheckpointRequest - 5, // 44: atelet.AteomHerder.Terminate:input_type -> atelet.TerminateRequest - 4, // 45: atelet.CredentialBroker.MintActorCertificate:output_type -> atelet.MintActorCertificateResponse - 30, // 46: atelet.AteomHerder.Run:output_type -> atelet.RunResponse - 34, // 47: atelet.AteomHerder.Checkpoint:output_type -> atelet.CheckpointResponse - 38, // 48: atelet.AteomHerder.Restore:output_type -> atelet.RestoreResponse - 36, // 49: atelet.AteomHerder.UploadPausedCheckpoint:output_type -> atelet.UploadPausedCheckpointResponse - 6, // 50: atelet.AteomHerder.Terminate:output_type -> atelet.TerminateResponse - 45, // [45:51] is the sub-list for method output_type - 39, // [39:45] is the sub-list for method input_type - 39, // [39:39] is the sub-list for extension type_name - 39, // [39:39] is the sub-list for extension extendee - 0, // [0:39] is the sub-list for field type_name + 40, // 4: atelet.ArchAssets.files:type_name -> atelet.ArchAssets.FilesEntry + 41, // 5: atelet.SandboxAssets.assets:type_name -> atelet.SandboxAssets.AssetsEntry + 11, // 6: atelet.SandboxAssets.sandbox_config_ref:type_name -> atelet.SandboxConfigRef + 24, // 7: atelet.WorkloadSpec.containers:type_name -> atelet.Container + 22, // 8: atelet.WorkloadSpec.volumes:type_name -> atelet.Volume + 42, // 9: atelet.ExternalVolumeSource.volume_context:type_name -> atelet.ExternalVolumeSource.VolumeContextEntry + 0, // 10: atelet.ActorMetadataItem.field:type_name -> atelet.ActorMetadataField + 17, // 11: atelet.ActorMetadataDataSource.items:type_name -> atelet.ActorMetadataItem + 18, // 12: atelet.SystemInfoDataSource.actor_metadata:type_name -> atelet.ActorMetadataDataSource + 19, // 13: atelet.SystemInfoDataSource.trust_bundle:type_name -> atelet.TrustBundleDataSource + 20, // 14: atelet.SystemInfoVolume.data_sources:type_name -> atelet.SystemInfoDataSource + 14, // 15: atelet.Volume.durable_dir:type_name -> atelet.DurableDirVolume + 15, // 16: atelet.Volume.external:type_name -> atelet.ExternalVolumeSource + 21, // 17: atelet.Volume.system_info:type_name -> atelet.SystemInfoVolume + 16, // 18: atelet.Volume.image:type_name -> atelet.ImageVolumeSource + 28, // 19: atelet.Container.env:type_name -> atelet.EnvEntry + 29, // 20: atelet.Container.readyz:type_name -> atelet.Readyz + 23, // 21: atelet.Container.volume_mounts:type_name -> atelet.VolumeMount + 25, // 22: atelet.Container.security_context:type_name -> atelet.SecurityContext + 27, // 23: atelet.Container.resources:type_name -> atelet.ResourceLimits + 26, // 24: atelet.SecurityContext.capabilities:type_name -> atelet.Capabilities + 30, // 25: atelet.Readyz.http_get:type_name -> atelet.HTTPGetAction + 13, // 26: atelet.CheckpointRequest.spec:type_name -> atelet.WorkloadSpec + 1, // 27: atelet.CheckpointRequest.type:type_name -> atelet.CheckpointType + 32, // 28: atelet.CheckpointRequest.local_config:type_name -> atelet.LocalCheckpointConfiguration + 33, // 29: atelet.CheckpointRequest.external_config:type_name -> atelet.ExternalCheckpointConfiguration + 2, // 30: atelet.CheckpointRequest.scope:type_name -> atelet.SnapshotScope + 11, // 31: atelet.CheckpointResponse.sandbox_config_ref:type_name -> atelet.SandboxConfigRef + 2, // 32: atelet.UploadPausedCheckpointRequest.desired_scope:type_name -> atelet.SnapshotScope + 13, // 33: atelet.RestoreRequest.spec:type_name -> atelet.WorkloadSpec + 1, // 34: atelet.RestoreRequest.type:type_name -> atelet.CheckpointType + 32, // 35: atelet.RestoreRequest.local_config:type_name -> atelet.LocalCheckpointConfiguration + 33, // 36: atelet.RestoreRequest.external_config:type_name -> atelet.ExternalCheckpointConfiguration + 2, // 37: atelet.RestoreRequest.scope:type_name -> atelet.SnapshotScope + 8, // 38: atelet.RestoreRequest.egress_gateway:type_name -> atelet.EgressGateway + 12, // 39: atelet.RestoreRequest.sandbox_assets:type_name -> atelet.SandboxAssets + 9, // 40: atelet.ArchAssets.FilesEntry.value:type_name -> atelet.AssetFile + 10, // 41: atelet.SandboxAssets.AssetsEntry.value:type_name -> atelet.ArchAssets + 3, // 42: atelet.CredentialBroker.MintActorCertificate:input_type -> atelet.MintActorCertificateRequest + 7, // 43: atelet.AteomHerder.Run:input_type -> atelet.RunRequest + 34, // 44: atelet.AteomHerder.Checkpoint:input_type -> atelet.CheckpointRequest + 38, // 45: atelet.AteomHerder.Restore:input_type -> atelet.RestoreRequest + 36, // 46: atelet.AteomHerder.UploadPausedCheckpoint:input_type -> atelet.UploadPausedCheckpointRequest + 5, // 47: atelet.AteomHerder.Terminate:input_type -> atelet.TerminateRequest + 4, // 48: atelet.CredentialBroker.MintActorCertificate:output_type -> atelet.MintActorCertificateResponse + 31, // 49: atelet.AteomHerder.Run:output_type -> atelet.RunResponse + 35, // 50: atelet.AteomHerder.Checkpoint:output_type -> atelet.CheckpointResponse + 39, // 51: atelet.AteomHerder.Restore:output_type -> atelet.RestoreResponse + 37, // 52: atelet.AteomHerder.UploadPausedCheckpoint:output_type -> atelet.UploadPausedCheckpointResponse + 6, // 53: atelet.AteomHerder.Terminate:output_type -> atelet.TerminateResponse + 48, // [48:54] is the sub-list for method output_type + 42, // [42:48] is the sub-list for method input_type + 42, // [42:42] is the sub-list for extension type_name + 42, // [42:42] is the sub-list for extension extendee + 0, // [0:42] is the sub-list for field type_name } func init() { file_atelet_proto_init() } @@ -2901,21 +3011,21 @@ func file_atelet_proto_init() { return } file_atelet_proto_msgTypes[4].OneofWrappers = []any{} - file_atelet_proto_msgTypes[16].OneofWrappers = []any{ + file_atelet_proto_msgTypes[17].OneofWrappers = []any{ (*SystemInfoDataSource_ActorMetadata)(nil), (*SystemInfoDataSource_TrustBundle)(nil), } - file_atelet_proto_msgTypes[18].OneofWrappers = []any{ + file_atelet_proto_msgTypes[19].OneofWrappers = []any{ (*Volume_DurableDir)(nil), (*Volume_External)(nil), (*Volume_SystemInfo)(nil), (*Volume_Image)(nil), } - file_atelet_proto_msgTypes[30].OneofWrappers = []any{ + file_atelet_proto_msgTypes[31].OneofWrappers = []any{ (*CheckpointRequest_LocalConfig)(nil), (*CheckpointRequest_ExternalConfig)(nil), } - file_atelet_proto_msgTypes[34].OneofWrappers = []any{ + file_atelet_proto_msgTypes[35].OneofWrappers = []any{ (*RestoreRequest_LocalConfig)(nil), (*RestoreRequest_ExternalConfig)(nil), } @@ -2925,7 +3035,7 @@ func file_atelet_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_atelet_proto_rawDesc), len(file_atelet_proto_rawDesc)), NumEnums: 3, - NumMessages: 39, + NumMessages: 40, NumExtensions: 0, NumServices: 2, }, diff --git a/internal/proto/ateletpb/atelet.proto b/internal/proto/ateletpb/atelet.proto index aa3fbbcf2a..4eaa8a3cdc 100644 --- a/internal/proto/ateletpb/atelet.proto +++ b/internal/proto/ateletpb/atelet.proto @@ -91,8 +91,9 @@ message RunRequest { WorkloadSpec spec = 7; // The sandbox binaries to use for booting this actor from scratch. atelet - // fetches the relevant assets and records them with the actor's on-node state - // so a later Checkpoint can pin the same version into the snapshot manifest. + // fetches the relevant assets and records them (with their SandboxConfig + // reference) in the actor's on-node state so a later Checkpoint can pin the + // reference into the snapshot manifest. SandboxAssets sandbox_assets = 8; // When absent, actor traffic uses direct egress instead of atunnel. @@ -127,6 +128,18 @@ message ArchAssets { map files = 1; // asset name -> file } +// SandboxConfigRef references a cluster-scoped SandboxConfig Kubernetes +// object by name, UID, and resource version. The UID distinguishes an object +// from a later re-creation under the same name; the resource version pins the +// exact object version. +message SandboxConfigRef { + string name = 1; + string uid = 2; + // resource_version is the object's metadata.resourceVersion at the time + // the control plane resolved the request from it. + string resource_version = 3; +} + // SandboxAssets is the generic, backend-agnostic description of the sandbox // an actor runs in: a sandbox class, the pause image holding its namespaces, // and binaries keyed first by architecture (GOARCH) and then by asset name. @@ -137,10 +150,14 @@ message SandboxAssets { map assets = 2; // arch -> {name -> file} // pause_image is the image for the sandbox's root container. Like the - // binaries above it is sandbox configuration, not workload configuration, - // and atelet pins it into the snapshot manifest so a restore rebuilds the - // sandbox from the same image. + // binaries above it is sandbox configuration, not workload configuration. string pause_image = 3; + + // Reference to the SandboxConfig object these assets were resolved from. + // atelet keeps it in the actor's on-node record and pins it into the + // snapshot manifest; the control plane stores it on the ActorSnapshot and + // resolves a later restore's assets from it. + SandboxConfigRef sandbox_config_ref = 4; } // WorkloadSpec parallels Pod, but with far fewer configurable fields. @@ -340,9 +357,10 @@ message CheckpointRequest { string actor_template_atespace = 5; string actor_template_name = 6; - // Sandbox binary config is not sent on checkpoint: atelet uses the version the - // actor is currently running (recorded with the actor's on-node state at - // Run/Restore) and records it into the snapshot manifest. + // Sandbox binary config is not sent on checkpoint: atelet uses the version + // the actor is currently running (recorded with the actor's on-node state + // at Run/Restore) and records its SandboxConfig reference into the snapshot + // manifest. WorkloadSpec spec = 7; CheckpointType type = 8; @@ -358,6 +376,12 @@ message CheckpointRequest { } message CheckpointResponse { + // The SandboxConfig reference from the actor's on-node record — the + // sandbox the checkpoint was actually taken with, as pinned into the + // snapshot manifest. The control plane copies it onto the ActorSnapshot / + // LocalSnapshotInfo record it finalizes for this checkpoint. Unset when + // the record predates the reference. + SandboxConfigRef sandbox_config_ref = 1; } message UploadPausedCheckpointRequest { @@ -397,9 +421,6 @@ message RestoreRequest { string actor_template_atespace = 5; string actor_template_name = 6; - // Sandbox binary config is not sent on restore: the snapshot is - // self-describing. atelet reads the snapshot manifest to recover the pinned - // sandbox version that created it. WorkloadSpec spec = 7; CheckpointType type = 8; @@ -430,6 +451,11 @@ message RestoreRequest { // means "unset": keep the runtime default. int64 cpu_milli = 14; // CPU limit in millicores (1000 = one core). int64 memory_bytes = 15; // Memory limit in bytes. + + // The sandbox binaries to restore this actor with. Required: the snapshot + // manifest carries only a SandboxConfig reference, never asset content, + // so this is the only source of binaries for a restore. + SandboxAssets sandbox_assets = 16; } message RestoreResponse { diff --git a/pkg/proto/ateapipb/ateapi.pb.go b/pkg/proto/ateapipb/ateapi.pb.go index ea5121e4c9..62b32a38fb 100644 --- a/pkg/proto/ateapipb/ateapi.pb.go +++ b/pkg/proto/ateapipb/ateapi.pb.go @@ -545,9 +545,13 @@ type LocalSnapshotInfo struct { // +k8s:optional // +k8s:minimum=1 // +k8s:maximum=2 # keep this in sync with the SnapshotContentScope enum - ContentScope SnapshotContentScope `protobuf:"varint,3,opt,name=content_scope,json=contentScope,proto3,enum=ateapi.SnapshotContentScope" json:"content_scope,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + ContentScope SnapshotContentScope `protobuf:"varint,3,opt,name=content_scope,json=contentScope,proto3,enum=ateapi.SnapshotContentScope" json:"content_scope,omitempty"` + // The SandboxConfig the paused activation was booted with. + // + // +k8s:optional + SandboxConfigRef *SandboxConfigRef `protobuf:"bytes,4,opt,name=sandbox_config_ref,json=sandboxConfigRef,proto3" json:"sandbox_config_ref,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *LocalSnapshotInfo) Reset() { @@ -601,6 +605,13 @@ func (x *LocalSnapshotInfo) GetContentScope() SnapshotContentScope { return SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_UNSPECIFIED } +func (x *LocalSnapshotInfo) GetSandboxConfigRef() *SandboxConfigRef { + if x != nil { + return x.SandboxConfigRef + } + return nil +} + // Selector matches worker pools by label. // Only equality-based matching is supported. type Selector struct { @@ -1847,8 +1858,13 @@ type ActorSnapshotStatus struct { // Immutable reference to the actor_template where the snapshot was created from. // +k8s:opaqueType ActorTemplate *ObjectRef `protobuf:"bytes,9,opt,name=actor_template,json=actorTemplate,proto3" json:"actor_template,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + // The SandboxConfig the snapshotted sandbox was booted from. A restore + // resolves it to send the sandbox assets to atelet. Unset on older + // snapshots. + // +k8s:optional + SandboxConfigRef *SandboxConfigRef `protobuf:"bytes,10,opt,name=sandbox_config_ref,json=sandboxConfigRef,proto3" json:"sandbox_config_ref,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ActorSnapshotStatus) Reset() { @@ -1930,6 +1946,13 @@ func (x *ActorSnapshotStatus) GetActorTemplate() *ObjectRef { return nil } +func (x *ActorSnapshotStatus) GetSandboxConfigRef() *SandboxConfigRef { + if x != nil { + return x.SandboxConfigRef + } + return nil +} + // ActorSnapshotTag is an immutable, Atespace-owned alias and retention pin. // Its owning Atespace cannot be deleted until the tag is removed. type ActorSnapshotTag struct { @@ -2110,6 +2133,82 @@ func (x *ObjectRef) GetName() string { return "" } +// SandboxConfigRef references a cluster-scoped SandboxConfig Kubernetes +// object by name, UID, and resource version. The UID distinguishes an object +// from a later re-creation under the same name; the resource version pins the +// exact object version. +type SandboxConfigRef struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The name of the referenced Kubernetes object. Required. + // + // +k8s:required + // +k8s:format=k8s-long-name + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + // The Kubernetes UID of the referenced object. Required. + // + // +k8s:required + // +k8s:format=k8s-uuid + Uid string `protobuf:"bytes,2,opt,name=uid,proto3" json:"uid,omitempty"` + // resource_version is the object's metadata.resourceVersion at the time + // the control plane resolved the request from it. + // + // +k8s:required + ResourceVersion string `protobuf:"bytes,3,opt,name=resource_version,json=resourceVersion,proto3" json:"resource_version,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SandboxConfigRef) Reset() { + *x = SandboxConfigRef{} + mi := &file_ateapi_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SandboxConfigRef) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SandboxConfigRef) ProtoMessage() {} + +func (x *SandboxConfigRef) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[19] + 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 SandboxConfigRef.ProtoReflect.Descriptor instead. +func (*SandboxConfigRef) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{19} +} + +func (x *SandboxConfigRef) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *SandboxConfigRef) GetUid() string { + if x != nil { + return x.Uid + } + return "" +} + +func (x *SandboxConfigRef) GetResourceVersion() string { + if x != nil { + return x.ResourceVersion + } + return "" +} + type ActorTemplate struct { state protoimpl.MessageState `protogen:"open.v1"` // Common resource metadata: atespace, name, uid, version, timestamps. @@ -2151,7 +2250,7 @@ type ActorTemplate struct { func (x *ActorTemplate) Reset() { *x = ActorTemplate{} - mi := &file_ateapi_proto_msgTypes[19] + mi := &file_ateapi_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2163,7 +2262,7 @@ func (x *ActorTemplate) String() string { func (*ActorTemplate) ProtoMessage() {} func (x *ActorTemplate) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[19] + mi := &file_ateapi_proto_msgTypes[20] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2176,7 +2275,7 @@ func (x *ActorTemplate) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorTemplate.ProtoReflect.Descriptor instead. func (*ActorTemplate) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{19} + return file_ateapi_proto_rawDescGZIP(), []int{20} } func (x *ActorTemplate) GetMetadata() *ResourceMetadata { @@ -2253,7 +2352,7 @@ type Resources struct { func (x *Resources) Reset() { *x = Resources{} - mi := &file_ateapi_proto_msgTypes[20] + mi := &file_ateapi_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2265,7 +2364,7 @@ func (x *Resources) String() string { func (*Resources) ProtoMessage() {} func (x *Resources) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[20] + mi := &file_ateapi_proto_msgTypes[21] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2278,7 +2377,7 @@ func (x *Resources) ProtoReflect() protoreflect.Message { // Deprecated: Use Resources.ProtoReflect.Descriptor instead. func (*Resources) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{20} + return file_ateapi_proto_rawDescGZIP(), []int{21} } func (x *Resources) GetLimits() []*Limits { @@ -2305,7 +2404,7 @@ type Limits struct { func (x *Limits) Reset() { *x = Limits{} - mi := &file_ateapi_proto_msgTypes[21] + mi := &file_ateapi_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2317,7 +2416,7 @@ func (x *Limits) String() string { func (*Limits) ProtoMessage() {} func (x *Limits) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[21] + mi := &file_ateapi_proto_msgTypes[22] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2330,7 +2429,7 @@ func (x *Limits) ProtoReflect() protoreflect.Message { // Deprecated: Use Limits.ProtoReflect.Descriptor instead. func (*Limits) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{21} + return file_ateapi_proto_rawDescGZIP(), []int{22} } func (x *Limits) GetName() string { @@ -2364,7 +2463,7 @@ type GoldenSnapshotStatus struct { func (x *GoldenSnapshotStatus) Reset() { *x = GoldenSnapshotStatus{} - mi := &file_ateapi_proto_msgTypes[22] + mi := &file_ateapi_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2376,7 +2475,7 @@ func (x *GoldenSnapshotStatus) String() string { func (*GoldenSnapshotStatus) ProtoMessage() {} func (x *GoldenSnapshotStatus) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[22] + mi := &file_ateapi_proto_msgTypes[23] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2389,7 +2488,7 @@ func (x *GoldenSnapshotStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use GoldenSnapshotStatus.ProtoReflect.Descriptor instead. func (*GoldenSnapshotStatus) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{22} + return file_ateapi_proto_rawDescGZIP(), []int{23} } func (x *GoldenSnapshotStatus) GetGoldenSnapshot() *ObjectRef { @@ -2422,7 +2521,7 @@ type ActorTemplateStatus struct { func (x *ActorTemplateStatus) Reset() { *x = ActorTemplateStatus{} - mi := &file_ateapi_proto_msgTypes[23] + mi := &file_ateapi_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2434,7 +2533,7 @@ func (x *ActorTemplateStatus) String() string { func (*ActorTemplateStatus) ProtoMessage() {} func (x *ActorTemplateStatus) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[23] + mi := &file_ateapi_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2447,7 +2546,7 @@ func (x *ActorTemplateStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorTemplateStatus.ProtoReflect.Descriptor instead. func (*ActorTemplateStatus) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{23} + return file_ateapi_proto_rawDescGZIP(), []int{24} } func (x *ActorTemplateStatus) GetGoldenSnapshotStatus() *GoldenSnapshotStatus { @@ -2478,7 +2577,7 @@ type SandboxConfig struct { func (x *SandboxConfig) Reset() { *x = SandboxConfig{} - mi := &file_ateapi_proto_msgTypes[24] + mi := &file_ateapi_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2490,7 +2589,7 @@ func (x *SandboxConfig) String() string { func (*SandboxConfig) ProtoMessage() {} func (x *SandboxConfig) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[24] + mi := &file_ateapi_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2503,7 +2602,7 @@ func (x *SandboxConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use SandboxConfig.ProtoReflect.Descriptor instead. func (*SandboxConfig) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{24} + return file_ateapi_proto_rawDescGZIP(), []int{25} } func (x *SandboxConfig) GetSandboxClass() SandboxClass { @@ -2554,7 +2653,7 @@ type SnapshotsConfig struct { func (x *SnapshotsConfig) Reset() { *x = SnapshotsConfig{} - mi := &file_ateapi_proto_msgTypes[25] + mi := &file_ateapi_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2566,7 +2665,7 @@ func (x *SnapshotsConfig) String() string { func (*SnapshotsConfig) ProtoMessage() {} func (x *SnapshotsConfig) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[25] + mi := &file_ateapi_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2579,7 +2678,7 @@ func (x *SnapshotsConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use SnapshotsConfig.ProtoReflect.Descriptor instead. func (*SnapshotsConfig) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{25} + return file_ateapi_proto_rawDescGZIP(), []int{26} } func (x *SnapshotsConfig) GetOnPause() SnapshotContentScope { @@ -2629,7 +2728,7 @@ type OnResumeConfig struct { func (x *OnResumeConfig) Reset() { *x = OnResumeConfig{} - mi := &file_ateapi_proto_msgTypes[26] + mi := &file_ateapi_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2641,7 +2740,7 @@ func (x *OnResumeConfig) String() string { func (*OnResumeConfig) ProtoMessage() {} func (x *OnResumeConfig) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[26] + mi := &file_ateapi_proto_msgTypes[27] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2654,7 +2753,7 @@ func (x *OnResumeConfig) ProtoReflect() protoreflect.Message { // Deprecated: Use OnResumeConfig.ProtoReflect.Descriptor instead. func (*OnResumeConfig) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{26} + return file_ateapi_proto_rawDescGZIP(), []int{27} } func (x *OnResumeConfig) GetFromData() ResumeSource { @@ -2729,7 +2828,7 @@ type Container struct { func (x *Container) Reset() { *x = Container{} - mi := &file_ateapi_proto_msgTypes[27] + mi := &file_ateapi_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2741,7 +2840,7 @@ func (x *Container) String() string { func (*Container) ProtoMessage() {} func (x *Container) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[27] + mi := &file_ateapi_proto_msgTypes[28] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2754,7 +2853,7 @@ func (x *Container) ProtoReflect() protoreflect.Message { // Deprecated: Use Container.ProtoReflect.Descriptor instead. func (*Container) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{27} + return file_ateapi_proto_rawDescGZIP(), []int{28} } func (x *Container) GetName() string { @@ -2834,7 +2933,7 @@ type SecurityContext struct { func (x *SecurityContext) Reset() { *x = SecurityContext{} - mi := &file_ateapi_proto_msgTypes[28] + mi := &file_ateapi_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2846,7 +2945,7 @@ func (x *SecurityContext) String() string { func (*SecurityContext) ProtoMessage() {} func (x *SecurityContext) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[28] + mi := &file_ateapi_proto_msgTypes[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2859,7 +2958,7 @@ func (x *SecurityContext) ProtoReflect() protoreflect.Message { // Deprecated: Use SecurityContext.ProtoReflect.Descriptor instead. func (*SecurityContext) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{28} + return file_ateapi_proto_rawDescGZIP(), []int{29} } func (x *SecurityContext) GetCapabilities() *Capabilities { @@ -2897,7 +2996,7 @@ type Capabilities struct { func (x *Capabilities) Reset() { *x = Capabilities{} - mi := &file_ateapi_proto_msgTypes[29] + mi := &file_ateapi_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2909,7 +3008,7 @@ func (x *Capabilities) String() string { func (*Capabilities) ProtoMessage() {} func (x *Capabilities) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[29] + mi := &file_ateapi_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2922,7 +3021,7 @@ func (x *Capabilities) ProtoReflect() protoreflect.Message { // Deprecated: Use Capabilities.ProtoReflect.Descriptor instead. func (*Capabilities) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{29} + return file_ateapi_proto_rawDescGZIP(), []int{30} } func (x *Capabilities) GetAdd() []string { @@ -2960,7 +3059,7 @@ type EnvVar struct { func (x *EnvVar) Reset() { *x = EnvVar{} - mi := &file_ateapi_proto_msgTypes[30] + mi := &file_ateapi_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2972,7 +3071,7 @@ func (x *EnvVar) String() string { func (*EnvVar) ProtoMessage() {} func (x *EnvVar) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[30] + mi := &file_ateapi_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2985,7 +3084,7 @@ func (x *EnvVar) ProtoReflect() protoreflect.Message { // Deprecated: Use EnvVar.ProtoReflect.Descriptor instead. func (*EnvVar) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{30} + return file_ateapi_proto_rawDescGZIP(), []int{31} } func (x *EnvVar) GetName() string { @@ -3022,7 +3121,7 @@ type ContainerReadyz struct { func (x *ContainerReadyz) Reset() { *x = ContainerReadyz{} - mi := &file_ateapi_proto_msgTypes[31] + mi := &file_ateapi_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3034,7 +3133,7 @@ func (x *ContainerReadyz) String() string { func (*ContainerReadyz) ProtoMessage() {} func (x *ContainerReadyz) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[31] + mi := &file_ateapi_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3047,7 +3146,7 @@ func (x *ContainerReadyz) ProtoReflect() protoreflect.Message { // Deprecated: Use ContainerReadyz.ProtoReflect.Descriptor instead. func (*ContainerReadyz) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{31} + return file_ateapi_proto_rawDescGZIP(), []int{32} } func (x *ContainerReadyz) GetHttpGet() *HTTPGetAction { @@ -3084,7 +3183,7 @@ type HTTPGetAction struct { func (x *HTTPGetAction) Reset() { *x = HTTPGetAction{} - mi := &file_ateapi_proto_msgTypes[32] + mi := &file_ateapi_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3096,7 +3195,7 @@ func (x *HTTPGetAction) String() string { func (*HTTPGetAction) ProtoMessage() {} func (x *HTTPGetAction) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[32] + mi := &file_ateapi_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3109,7 +3208,7 @@ func (x *HTTPGetAction) ProtoReflect() protoreflect.Message { // Deprecated: Use HTTPGetAction.ProtoReflect.Descriptor instead. func (*HTTPGetAction) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{32} + return file_ateapi_proto_rawDescGZIP(), []int{33} } func (x *HTTPGetAction) GetPath() string { @@ -3156,7 +3255,7 @@ type Volume struct { func (x *Volume) Reset() { *x = Volume{} - mi := &file_ateapi_proto_msgTypes[33] + mi := &file_ateapi_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3168,7 +3267,7 @@ func (x *Volume) String() string { func (*Volume) ProtoMessage() {} func (x *Volume) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[33] + mi := &file_ateapi_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3181,7 +3280,7 @@ func (x *Volume) ProtoReflect() protoreflect.Message { // Deprecated: Use Volume.ProtoReflect.Descriptor instead. func (*Volume) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{33} + return file_ateapi_proto_rawDescGZIP(), []int{34} } func (x *Volume) GetName() string { @@ -3236,7 +3335,7 @@ type ImageVolumeSource struct { func (x *ImageVolumeSource) Reset() { *x = ImageVolumeSource{} - mi := &file_ateapi_proto_msgTypes[34] + mi := &file_ateapi_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3248,7 +3347,7 @@ func (x *ImageVolumeSource) String() string { func (*ImageVolumeSource) ProtoMessage() {} func (x *ImageVolumeSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[34] + mi := &file_ateapi_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3261,7 +3360,7 @@ func (x *ImageVolumeSource) ProtoReflect() protoreflect.Message { // Deprecated: Use ImageVolumeSource.ProtoReflect.Descriptor instead. func (*ImageVolumeSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{34} + return file_ateapi_proto_rawDescGZIP(), []int{35} } func (x *ImageVolumeSource) GetReference() string { @@ -3281,7 +3380,7 @@ type DurableDirVolumeSource struct { func (x *DurableDirVolumeSource) Reset() { *x = DurableDirVolumeSource{} - mi := &file_ateapi_proto_msgTypes[35] + mi := &file_ateapi_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3293,7 +3392,7 @@ func (x *DurableDirVolumeSource) String() string { func (*DurableDirVolumeSource) ProtoMessage() {} func (x *DurableDirVolumeSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[35] + mi := &file_ateapi_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3306,7 +3405,7 @@ func (x *DurableDirVolumeSource) ProtoReflect() protoreflect.Message { // Deprecated: Use DurableDirVolumeSource.ProtoReflect.Descriptor instead. func (*DurableDirVolumeSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{35} + return file_ateapi_proto_rawDescGZIP(), []int{36} } // ExternalVolumeTemplate provisions an external volume per actor; the volume @@ -3331,7 +3430,7 @@ type ExternalVolumeTemplate struct { func (x *ExternalVolumeTemplate) Reset() { *x = ExternalVolumeTemplate{} - mi := &file_ateapi_proto_msgTypes[36] + mi := &file_ateapi_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3343,7 +3442,7 @@ func (x *ExternalVolumeTemplate) String() string { func (*ExternalVolumeTemplate) ProtoMessage() {} func (x *ExternalVolumeTemplate) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[36] + mi := &file_ateapi_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3356,7 +3455,7 @@ func (x *ExternalVolumeTemplate) ProtoReflect() protoreflect.Message { // Deprecated: Use ExternalVolumeTemplate.ProtoReflect.Descriptor instead. func (*ExternalVolumeTemplate) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{36} + return file_ateapi_proto_rawDescGZIP(), []int{37} } func (x *ExternalVolumeTemplate) GetCapacity() string { @@ -3392,7 +3491,7 @@ type SystemInfoVolumeSource struct { func (x *SystemInfoVolumeSource) Reset() { *x = SystemInfoVolumeSource{} - mi := &file_ateapi_proto_msgTypes[37] + mi := &file_ateapi_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3404,7 +3503,7 @@ func (x *SystemInfoVolumeSource) String() string { func (*SystemInfoVolumeSource) ProtoMessage() {} func (x *SystemInfoVolumeSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[37] + mi := &file_ateapi_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3417,7 +3516,7 @@ func (x *SystemInfoVolumeSource) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemInfoVolumeSource.ProtoReflect.Descriptor instead. func (*SystemInfoVolumeSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{37} + return file_ateapi_proto_rawDescGZIP(), []int{38} } func (x *SystemInfoVolumeSource) GetDataSources() []*SystemInfoDataSource { @@ -3443,7 +3542,7 @@ type SystemInfoDataSource struct { func (x *SystemInfoDataSource) Reset() { *x = SystemInfoDataSource{} - mi := &file_ateapi_proto_msgTypes[38] + mi := &file_ateapi_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3455,7 +3554,7 @@ func (x *SystemInfoDataSource) String() string { func (*SystemInfoDataSource) ProtoMessage() {} func (x *SystemInfoDataSource) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[38] + mi := &file_ateapi_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -3468,7 +3567,7 @@ func (x *SystemInfoDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemInfoDataSource.ProtoReflect.Descriptor instead. func (*SystemInfoDataSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{38} + return file_ateapi_proto_rawDescGZIP(), []int{39} } func (x *SystemInfoDataSource) GetActorMetadata() *ActorMetadataDataSource { @@ -3505,7 +3604,7 @@ type ActorMetadataDataSource struct { func (x *ActorMetadataDataSource) Reset() { *x = ActorMetadataDataSource{} - mi := &file_ateapi_proto_msgTypes[39] + mi := &file_ateapi_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3517,7 +3616,7 @@ func (x *ActorMetadataDataSource) String() string { func (*ActorMetadataDataSource) ProtoMessage() {} func (x *ActorMetadataDataSource) 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 { @@ -3530,7 +3629,7 @@ func (x *ActorMetadataDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorMetadataDataSource.ProtoReflect.Descriptor instead. func (*ActorMetadataDataSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{39} + return file_ateapi_proto_rawDescGZIP(), []int{40} } func (x *ActorMetadataDataSource) GetItems() []*ActorMetadataItem { @@ -3556,7 +3655,7 @@ type ActorMetadataItem struct { func (x *ActorMetadataItem) Reset() { *x = ActorMetadataItem{} - mi := &file_ateapi_proto_msgTypes[40] + mi := &file_ateapi_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3568,7 +3667,7 @@ func (x *ActorMetadataItem) String() string { func (*ActorMetadataItem) ProtoMessage() {} func (x *ActorMetadataItem) 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 { @@ -3581,7 +3680,7 @@ func (x *ActorMetadataItem) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorMetadataItem.ProtoReflect.Descriptor instead. func (*ActorMetadataItem) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{40} + return file_ateapi_proto_rawDescGZIP(), []int{41} } func (x *ActorMetadataItem) GetField() ActorMetadataField { @@ -3616,7 +3715,7 @@ type TrustBundleDataSource struct { func (x *TrustBundleDataSource) Reset() { *x = TrustBundleDataSource{} - mi := &file_ateapi_proto_msgTypes[41] + mi := &file_ateapi_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3628,7 +3727,7 @@ func (x *TrustBundleDataSource) String() string { func (*TrustBundleDataSource) ProtoMessage() {} func (x *TrustBundleDataSource) 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 { @@ -3641,7 +3740,7 @@ func (x *TrustBundleDataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use TrustBundleDataSource.ProtoReflect.Descriptor instead. func (*TrustBundleDataSource) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{41} + return file_ateapi_proto_rawDescGZIP(), []int{42} } func (x *TrustBundleDataSource) GetName() string { @@ -3680,7 +3779,7 @@ type VolumeMount struct { func (x *VolumeMount) Reset() { *x = VolumeMount{} - mi := &file_ateapi_proto_msgTypes[42] + mi := &file_ateapi_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3692,7 +3791,7 @@ func (x *VolumeMount) String() string { func (*VolumeMount) ProtoMessage() {} func (x *VolumeMount) 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 { @@ -3705,7 +3804,7 @@ func (x *VolumeMount) ProtoReflect() protoreflect.Message { // Deprecated: Use VolumeMount.ProtoReflect.Descriptor instead. func (*VolumeMount) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{42} + return file_ateapi_proto_rawDescGZIP(), []int{43} } func (x *VolumeMount) GetName() string { @@ -3734,7 +3833,7 @@ type CreateAtespaceRequest struct { func (x *CreateAtespaceRequest) Reset() { *x = CreateAtespaceRequest{} - mi := &file_ateapi_proto_msgTypes[43] + mi := &file_ateapi_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3746,7 +3845,7 @@ func (x *CreateAtespaceRequest) String() string { func (*CreateAtespaceRequest) ProtoMessage() {} func (x *CreateAtespaceRequest) 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 { @@ -3759,7 +3858,7 @@ func (x *CreateAtespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateAtespaceRequest.ProtoReflect.Descriptor instead. func (*CreateAtespaceRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{43} + return file_ateapi_proto_rawDescGZIP(), []int{44} } func (x *CreateAtespaceRequest) GetAtespace() *Atespace { @@ -3780,7 +3879,7 @@ type GetAtespaceRequest struct { func (x *GetAtespaceRequest) Reset() { *x = GetAtespaceRequest{} - mi := &file_ateapi_proto_msgTypes[44] + mi := &file_ateapi_proto_msgTypes[45] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3792,7 +3891,7 @@ func (x *GetAtespaceRequest) String() string { func (*GetAtespaceRequest) ProtoMessage() {} func (x *GetAtespaceRequest) 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 { @@ -3805,7 +3904,7 @@ func (x *GetAtespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAtespaceRequest.ProtoReflect.Descriptor instead. func (*GetAtespaceRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{44} + return file_ateapi_proto_rawDescGZIP(), []int{45} } func (x *GetAtespaceRequest) GetAtespace() *ObjectRef { @@ -3836,7 +3935,7 @@ type ListAtespacesRequest struct { func (x *ListAtespacesRequest) Reset() { *x = ListAtespacesRequest{} - mi := &file_ateapi_proto_msgTypes[45] + mi := &file_ateapi_proto_msgTypes[46] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3848,7 +3947,7 @@ func (x *ListAtespacesRequest) String() string { func (*ListAtespacesRequest) ProtoMessage() {} func (x *ListAtespacesRequest) 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 { @@ -3861,7 +3960,7 @@ func (x *ListAtespacesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAtespacesRequest.ProtoReflect.Descriptor instead. func (*ListAtespacesRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{45} + return file_ateapi_proto_rawDescGZIP(), []int{46} } func (x *ListAtespacesRequest) GetPageSize() int32 { @@ -3890,7 +3989,7 @@ type ListAtespacesResponse struct { func (x *ListAtespacesResponse) Reset() { *x = ListAtespacesResponse{} - mi := &file_ateapi_proto_msgTypes[46] + mi := &file_ateapi_proto_msgTypes[47] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3902,7 +4001,7 @@ func (x *ListAtespacesResponse) String() string { func (*ListAtespacesResponse) ProtoMessage() {} func (x *ListAtespacesResponse) 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 { @@ -3915,7 +4014,7 @@ func (x *ListAtespacesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAtespacesResponse.ProtoReflect.Descriptor instead. func (*ListAtespacesResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{46} + return file_ateapi_proto_rawDescGZIP(), []int{47} } func (x *ListAtespacesResponse) GetAtespaces() []*Atespace { @@ -3943,7 +4042,7 @@ type DeleteAtespaceRequest struct { func (x *DeleteAtespaceRequest) Reset() { *x = DeleteAtespaceRequest{} - mi := &file_ateapi_proto_msgTypes[47] + mi := &file_ateapi_proto_msgTypes[48] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -3955,7 +4054,7 @@ func (x *DeleteAtespaceRequest) String() string { func (*DeleteAtespaceRequest) ProtoMessage() {} func (x *DeleteAtespaceRequest) 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 { @@ -3968,7 +4067,7 @@ func (x *DeleteAtespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteAtespaceRequest.ProtoReflect.Descriptor instead. func (*DeleteAtespaceRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{47} + return file_ateapi_proto_rawDescGZIP(), []int{48} } func (x *DeleteAtespaceRequest) GetAtespace() *ObjectRef { @@ -3991,7 +4090,7 @@ type CreateActorTemplateRequest struct { func (x *CreateActorTemplateRequest) Reset() { *x = CreateActorTemplateRequest{} - mi := &file_ateapi_proto_msgTypes[48] + mi := &file_ateapi_proto_msgTypes[49] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4003,7 +4102,7 @@ func (x *CreateActorTemplateRequest) String() string { func (*CreateActorTemplateRequest) ProtoMessage() {} func (x *CreateActorTemplateRequest) 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 { @@ -4016,7 +4115,7 @@ func (x *CreateActorTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateActorTemplateRequest.ProtoReflect.Descriptor instead. func (*CreateActorTemplateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{48} + return file_ateapi_proto_rawDescGZIP(), []int{49} } func (x *CreateActorTemplateRequest) GetActorTemplate() *ActorTemplate { @@ -4037,7 +4136,7 @@ type GetActorTemplateRequest struct { func (x *GetActorTemplateRequest) Reset() { *x = GetActorTemplateRequest{} - mi := &file_ateapi_proto_msgTypes[49] + mi := &file_ateapi_proto_msgTypes[50] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4049,7 +4148,7 @@ func (x *GetActorTemplateRequest) String() string { func (*GetActorTemplateRequest) ProtoMessage() {} func (x *GetActorTemplateRequest) 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 { @@ -4062,7 +4161,7 @@ func (x *GetActorTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorTemplateRequest.ProtoReflect.Descriptor instead. func (*GetActorTemplateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{49} + return file_ateapi_proto_rawDescGZIP(), []int{50} } func (x *GetActorTemplateRequest) GetActorTemplate() *ObjectRef { @@ -4099,7 +4198,7 @@ type ListActorTemplatesRequest struct { func (x *ListActorTemplatesRequest) Reset() { *x = ListActorTemplatesRequest{} - mi := &file_ateapi_proto_msgTypes[50] + mi := &file_ateapi_proto_msgTypes[51] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4111,7 +4210,7 @@ func (x *ListActorTemplatesRequest) String() string { func (*ListActorTemplatesRequest) ProtoMessage() {} func (x *ListActorTemplatesRequest) 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 { @@ -4124,7 +4223,7 @@ func (x *ListActorTemplatesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorTemplatesRequest.ProtoReflect.Descriptor instead. func (*ListActorTemplatesRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{50} + return file_ateapi_proto_rawDescGZIP(), []int{51} } func (x *ListActorTemplatesRequest) GetAtespace() string { @@ -4161,7 +4260,7 @@ type ListActorTemplatesResponse struct { func (x *ListActorTemplatesResponse) Reset() { *x = ListActorTemplatesResponse{} - mi := &file_ateapi_proto_msgTypes[51] + mi := &file_ateapi_proto_msgTypes[52] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4173,7 +4272,7 @@ func (x *ListActorTemplatesResponse) String() string { func (*ListActorTemplatesResponse) ProtoMessage() {} func (x *ListActorTemplatesResponse) 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 { @@ -4186,7 +4285,7 @@ func (x *ListActorTemplatesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorTemplatesResponse.ProtoReflect.Descriptor instead. func (*ListActorTemplatesResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{51} + return file_ateapi_proto_rawDescGZIP(), []int{52} } func (x *ListActorTemplatesResponse) GetActorTemplates() []*ActorTemplate { @@ -4214,7 +4313,7 @@ type DeleteActorTemplateRequest struct { func (x *DeleteActorTemplateRequest) Reset() { *x = DeleteActorTemplateRequest{} - mi := &file_ateapi_proto_msgTypes[52] + mi := &file_ateapi_proto_msgTypes[53] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4226,7 +4325,7 @@ func (x *DeleteActorTemplateRequest) String() string { func (*DeleteActorTemplateRequest) ProtoMessage() {} func (x *DeleteActorTemplateRequest) 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 { @@ -4239,7 +4338,7 @@ func (x *DeleteActorTemplateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteActorTemplateRequest.ProtoReflect.Descriptor instead. func (*DeleteActorTemplateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{52} + return file_ateapi_proto_rawDescGZIP(), []int{53} } func (x *DeleteActorTemplateRequest) GetActorTemplate() *ObjectRef { @@ -4260,7 +4359,7 @@ type GetActorRequest struct { func (x *GetActorRequest) Reset() { *x = GetActorRequest{} - mi := &file_ateapi_proto_msgTypes[53] + mi := &file_ateapi_proto_msgTypes[54] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4272,7 +4371,7 @@ func (x *GetActorRequest) String() string { func (*GetActorRequest) ProtoMessage() {} func (x *GetActorRequest) 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 { @@ -4285,7 +4384,7 @@ func (x *GetActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorRequest.ProtoReflect.Descriptor instead. func (*GetActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{53} + return file_ateapi_proto_rawDescGZIP(), []int{54} } func (x *GetActorRequest) GetActor() *ObjectRef { @@ -4308,7 +4407,7 @@ type CreateActorRequest struct { func (x *CreateActorRequest) Reset() { *x = CreateActorRequest{} - mi := &file_ateapi_proto_msgTypes[54] + mi := &file_ateapi_proto_msgTypes[55] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4320,7 +4419,7 @@ func (x *CreateActorRequest) String() string { func (*CreateActorRequest) ProtoMessage() {} func (x *CreateActorRequest) 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 { @@ -4333,7 +4432,7 @@ func (x *CreateActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateActorRequest.ProtoReflect.Descriptor instead. func (*CreateActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{54} + return file_ateapi_proto_rawDescGZIP(), []int{55} } func (x *CreateActorRequest) GetActor() *Actor { @@ -4364,7 +4463,7 @@ type UpdateActorRequest struct { func (x *UpdateActorRequest) Reset() { *x = UpdateActorRequest{} - mi := &file_ateapi_proto_msgTypes[55] + mi := &file_ateapi_proto_msgTypes[56] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4376,7 +4475,7 @@ func (x *UpdateActorRequest) String() string { func (*UpdateActorRequest) ProtoMessage() {} func (x *UpdateActorRequest) 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 { @@ -4389,7 +4488,7 @@ func (x *UpdateActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateActorRequest.ProtoReflect.Descriptor instead. func (*UpdateActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{55} + return file_ateapi_proto_rawDescGZIP(), []int{56} } func (x *UpdateActorRequest) GetActor() *Actor { @@ -4410,7 +4509,7 @@ type SuspendActorRequest struct { func (x *SuspendActorRequest) Reset() { *x = SuspendActorRequest{} - mi := &file_ateapi_proto_msgTypes[56] + mi := &file_ateapi_proto_msgTypes[57] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4422,7 +4521,7 @@ func (x *SuspendActorRequest) String() string { func (*SuspendActorRequest) ProtoMessage() {} func (x *SuspendActorRequest) 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 { @@ -4435,7 +4534,7 @@ func (x *SuspendActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SuspendActorRequest.ProtoReflect.Descriptor instead. func (*SuspendActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{56} + return file_ateapi_proto_rawDescGZIP(), []int{57} } func (x *SuspendActorRequest) GetActor() *ObjectRef { @@ -4454,7 +4553,7 @@ type SuspendActorResponse struct { func (x *SuspendActorResponse) Reset() { *x = SuspendActorResponse{} - mi := &file_ateapi_proto_msgTypes[57] + mi := &file_ateapi_proto_msgTypes[58] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4466,7 +4565,7 @@ func (x *SuspendActorResponse) String() string { func (*SuspendActorResponse) ProtoMessage() {} func (x *SuspendActorResponse) 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 { @@ -4479,7 +4578,7 @@ func (x *SuspendActorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SuspendActorResponse.ProtoReflect.Descriptor instead. func (*SuspendActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{57} + return file_ateapi_proto_rawDescGZIP(), []int{58} } func (x *SuspendActorResponse) GetActor() *Actor { @@ -4500,7 +4599,7 @@ type PauseActorRequest struct { func (x *PauseActorRequest) Reset() { *x = PauseActorRequest{} - mi := &file_ateapi_proto_msgTypes[58] + mi := &file_ateapi_proto_msgTypes[59] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4512,7 +4611,7 @@ func (x *PauseActorRequest) String() string { func (*PauseActorRequest) ProtoMessage() {} func (x *PauseActorRequest) 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 { @@ -4525,7 +4624,7 @@ func (x *PauseActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use PauseActorRequest.ProtoReflect.Descriptor instead. func (*PauseActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{58} + return file_ateapi_proto_rawDescGZIP(), []int{59} } func (x *PauseActorRequest) GetActor() *ObjectRef { @@ -4544,7 +4643,7 @@ type PauseActorResponse struct { func (x *PauseActorResponse) Reset() { *x = PauseActorResponse{} - mi := &file_ateapi_proto_msgTypes[59] + mi := &file_ateapi_proto_msgTypes[60] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4556,7 +4655,7 @@ func (x *PauseActorResponse) String() string { func (*PauseActorResponse) ProtoMessage() {} func (x *PauseActorResponse) 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 { @@ -4569,7 +4668,7 @@ func (x *PauseActorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use PauseActorResponse.ProtoReflect.Descriptor instead. func (*PauseActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{59} + return file_ateapi_proto_rawDescGZIP(), []int{60} } func (x *PauseActorResponse) GetActor() *Actor { @@ -4594,7 +4693,7 @@ type ResumeActorRequest struct { func (x *ResumeActorRequest) Reset() { *x = ResumeActorRequest{} - mi := &file_ateapi_proto_msgTypes[60] + mi := &file_ateapi_proto_msgTypes[61] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4606,7 +4705,7 @@ func (x *ResumeActorRequest) String() string { func (*ResumeActorRequest) ProtoMessage() {} func (x *ResumeActorRequest) 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 { @@ -4619,7 +4718,7 @@ func (x *ResumeActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ResumeActorRequest.ProtoReflect.Descriptor instead. func (*ResumeActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{60} + return file_ateapi_proto_rawDescGZIP(), []int{61} } func (x *ResumeActorRequest) GetActor() *ObjectRef { @@ -4648,7 +4747,7 @@ type ResumeActorResponse struct { func (x *ResumeActorResponse) Reset() { *x = ResumeActorResponse{} - mi := &file_ateapi_proto_msgTypes[61] + mi := &file_ateapi_proto_msgTypes[62] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4660,7 +4759,7 @@ func (x *ResumeActorResponse) String() string { func (*ResumeActorResponse) ProtoMessage() {} func (x *ResumeActorResponse) 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 { @@ -4673,7 +4772,7 @@ func (x *ResumeActorResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ResumeActorResponse.ProtoReflect.Descriptor instead. func (*ResumeActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{61} + return file_ateapi_proto_rawDescGZIP(), []int{62} } func (x *ResumeActorResponse) GetActor() *Actor { @@ -4705,7 +4804,7 @@ type DeleteActorRequest struct { func (x *DeleteActorRequest) Reset() { *x = DeleteActorRequest{} - mi := &file_ateapi_proto_msgTypes[62] + mi := &file_ateapi_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4717,7 +4816,7 @@ func (x *DeleteActorRequest) String() string { func (*DeleteActorRequest) ProtoMessage() {} func (x *DeleteActorRequest) 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 { @@ -4730,7 +4829,7 @@ func (x *DeleteActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteActorRequest.ProtoReflect.Descriptor instead. func (*DeleteActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{62} + return file_ateapi_proto_rawDescGZIP(), []int{63} } func (x *DeleteActorRequest) GetActor() *ObjectRef { @@ -4761,7 +4860,7 @@ type GetActorEgressPolicyRequest struct { func (x *GetActorEgressPolicyRequest) Reset() { *x = GetActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[63] + mi := &file_ateapi_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4773,7 +4872,7 @@ func (x *GetActorEgressPolicyRequest) String() string { func (*GetActorEgressPolicyRequest) ProtoMessage() {} func (x *GetActorEgressPolicyRequest) 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 { @@ -4786,7 +4885,7 @@ func (x *GetActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*GetActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{63} + return file_ateapi_proto_rawDescGZIP(), []int{64} } func (x *GetActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -4817,7 +4916,7 @@ type CreateActorEgressPolicyRequest struct { func (x *CreateActorEgressPolicyRequest) Reset() { *x = CreateActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[64] + mi := &file_ateapi_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4829,7 +4928,7 @@ func (x *CreateActorEgressPolicyRequest) String() string { func (*CreateActorEgressPolicyRequest) ProtoMessage() {} func (x *CreateActorEgressPolicyRequest) 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 { @@ -4842,7 +4941,7 @@ func (x *CreateActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*CreateActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{64} + return file_ateapi_proto_rawDescGZIP(), []int{65} } func (x *CreateActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -4880,7 +4979,7 @@ type UpdateActorEgressPolicyRequest struct { func (x *UpdateActorEgressPolicyRequest) Reset() { *x = UpdateActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[65] + mi := &file_ateapi_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4892,7 +4991,7 @@ func (x *UpdateActorEgressPolicyRequest) String() string { func (*UpdateActorEgressPolicyRequest) ProtoMessage() {} func (x *UpdateActorEgressPolicyRequest) 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 { @@ -4905,7 +5004,7 @@ func (x *UpdateActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*UpdateActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{65} + return file_ateapi_proto_rawDescGZIP(), []int{66} } func (x *UpdateActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -4936,7 +5035,7 @@ type DeleteActorEgressPolicyRequest struct { func (x *DeleteActorEgressPolicyRequest) Reset() { *x = DeleteActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[66] + mi := &file_ateapi_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4948,7 +5047,7 @@ func (x *DeleteActorEgressPolicyRequest) String() string { func (*DeleteActorEgressPolicyRequest) ProtoMessage() {} func (x *DeleteActorEgressPolicyRequest) 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 { @@ -4961,7 +5060,7 @@ func (x *DeleteActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*DeleteActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{66} + return file_ateapi_proto_rawDescGZIP(), []int{67} } func (x *DeleteActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -4981,7 +5080,7 @@ type GetActorSnapshotRequest struct { func (x *GetActorSnapshotRequest) Reset() { *x = GetActorSnapshotRequest{} - mi := &file_ateapi_proto_msgTypes[67] + mi := &file_ateapi_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4993,7 +5092,7 @@ func (x *GetActorSnapshotRequest) String() string { func (*GetActorSnapshotRequest) ProtoMessage() {} func (x *GetActorSnapshotRequest) 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 { @@ -5006,7 +5105,7 @@ func (x *GetActorSnapshotRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorSnapshotRequest.ProtoReflect.Descriptor instead. func (*GetActorSnapshotRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{67} + return file_ateapi_proto_rawDescGZIP(), []int{68} } func (x *GetActorSnapshotRequest) GetActorSnapshot() *ObjectRef { @@ -5026,7 +5125,7 @@ type GetActorSnapshotTagRequest struct { func (x *GetActorSnapshotTagRequest) Reset() { *x = GetActorSnapshotTagRequest{} - mi := &file_ateapi_proto_msgTypes[68] + mi := &file_ateapi_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5038,7 +5137,7 @@ func (x *GetActorSnapshotTagRequest) String() string { func (*GetActorSnapshotTagRequest) ProtoMessage() {} func (x *GetActorSnapshotTagRequest) 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 { @@ -5051,7 +5150,7 @@ func (x *GetActorSnapshotTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorSnapshotTagRequest.ProtoReflect.Descriptor instead. func (*GetActorSnapshotTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{68} + return file_ateapi_proto_rawDescGZIP(), []int{69} } func (x *GetActorSnapshotTagRequest) GetActorSnapshotTag() *ObjectRef { @@ -5072,7 +5171,7 @@ type ListActorSnapshotsRequest struct { func (x *ListActorSnapshotsRequest) Reset() { *x = ListActorSnapshotsRequest{} - mi := &file_ateapi_proto_msgTypes[69] + mi := &file_ateapi_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5084,7 +5183,7 @@ func (x *ListActorSnapshotsRequest) String() string { func (*ListActorSnapshotsRequest) ProtoMessage() {} func (x *ListActorSnapshotsRequest) 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 { @@ -5097,7 +5196,7 @@ func (x *ListActorSnapshotsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorSnapshotsRequest.ProtoReflect.Descriptor instead. func (*ListActorSnapshotsRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{69} + return file_ateapi_proto_rawDescGZIP(), []int{70} } func (x *ListActorSnapshotsRequest) GetAtespace() string { @@ -5131,7 +5230,7 @@ type ListActorSnapshotsResponse struct { func (x *ListActorSnapshotsResponse) Reset() { *x = ListActorSnapshotsResponse{} - mi := &file_ateapi_proto_msgTypes[70] + mi := &file_ateapi_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5143,7 +5242,7 @@ func (x *ListActorSnapshotsResponse) String() string { func (*ListActorSnapshotsResponse) ProtoMessage() {} func (x *ListActorSnapshotsResponse) 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 { @@ -5156,7 +5255,7 @@ func (x *ListActorSnapshotsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorSnapshotsResponse.ProtoReflect.Descriptor instead. func (*ListActorSnapshotsResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{70} + return file_ateapi_proto_rawDescGZIP(), []int{71} } func (x *ListActorSnapshotsResponse) GetActorSnapshots() []*ActorSnapshot { @@ -5183,7 +5282,7 @@ type CreateActorSnapshotTagRequest struct { func (x *CreateActorSnapshotTagRequest) Reset() { *x = CreateActorSnapshotTagRequest{} - mi := &file_ateapi_proto_msgTypes[71] + mi := &file_ateapi_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5195,7 +5294,7 @@ func (x *CreateActorSnapshotTagRequest) String() string { func (*CreateActorSnapshotTagRequest) ProtoMessage() {} func (x *CreateActorSnapshotTagRequest) 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 { @@ -5208,7 +5307,7 @@ func (x *CreateActorSnapshotTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateActorSnapshotTagRequest.ProtoReflect.Descriptor instead. func (*CreateActorSnapshotTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{71} + return file_ateapi_proto_rawDescGZIP(), []int{72} } func (x *CreateActorSnapshotTagRequest) GetActorSnapshotTag() *ActorSnapshotTag { @@ -5234,7 +5333,7 @@ type UpdateActorSnapshotTagRequest struct { func (x *UpdateActorSnapshotTagRequest) Reset() { *x = UpdateActorSnapshotTagRequest{} - mi := &file_ateapi_proto_msgTypes[72] + mi := &file_ateapi_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5246,7 +5345,7 @@ func (x *UpdateActorSnapshotTagRequest) String() string { func (*UpdateActorSnapshotTagRequest) ProtoMessage() {} func (x *UpdateActorSnapshotTagRequest) 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 { @@ -5259,7 +5358,7 @@ func (x *UpdateActorSnapshotTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateActorSnapshotTagRequest.ProtoReflect.Descriptor instead. func (*UpdateActorSnapshotTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{72} + return file_ateapi_proto_rawDescGZIP(), []int{73} } func (x *UpdateActorSnapshotTagRequest) GetActorSnapshotTag() *ActorSnapshotTag { @@ -5279,7 +5378,7 @@ type DeleteActorSnapshotTagRequest struct { func (x *DeleteActorSnapshotTagRequest) Reset() { *x = DeleteActorSnapshotTagRequest{} - mi := &file_ateapi_proto_msgTypes[73] + mi := &file_ateapi_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5291,7 +5390,7 @@ func (x *DeleteActorSnapshotTagRequest) String() string { func (*DeleteActorSnapshotTagRequest) ProtoMessage() {} func (x *DeleteActorSnapshotTagRequest) 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 { @@ -5304,7 +5403,7 @@ func (x *DeleteActorSnapshotTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteActorSnapshotTagRequest.ProtoReflect.Descriptor instead. func (*DeleteActorSnapshotTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{73} + return file_ateapi_proto_rawDescGZIP(), []int{74} } func (x *DeleteActorSnapshotTagRequest) GetActorSnapshotTag() *ObjectRef { @@ -5340,7 +5439,7 @@ type DeleteOptions struct { func (x *DeleteOptions) Reset() { *x = DeleteOptions{} - mi := &file_ateapi_proto_msgTypes[74] + mi := &file_ateapi_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5352,7 +5451,7 @@ func (x *DeleteOptions) String() string { func (*DeleteOptions) ProtoMessage() {} func (x *DeleteOptions) 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 { @@ -5365,7 +5464,7 @@ func (x *DeleteOptions) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteOptions.ProtoReflect.Descriptor instead. func (*DeleteOptions) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{74} + return file_ateapi_proto_rawDescGZIP(), []int{75} } func (x *DeleteOptions) GetVersion() int64 { @@ -5403,7 +5502,7 @@ type ListWorkersRequest struct { func (x *ListWorkersRequest) Reset() { *x = ListWorkersRequest{} - mi := &file_ateapi_proto_msgTypes[75] + mi := &file_ateapi_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5415,7 +5514,7 @@ func (x *ListWorkersRequest) String() string { func (*ListWorkersRequest) ProtoMessage() {} func (x *ListWorkersRequest) 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 { @@ -5428,7 +5527,7 @@ func (x *ListWorkersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkersRequest.ProtoReflect.Descriptor instead. func (*ListWorkersRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{75} + return file_ateapi_proto_rawDescGZIP(), []int{76} } func (x *ListWorkersRequest) GetPageSize() int32 { @@ -5457,7 +5556,7 @@ type ListWorkersResponse struct { func (x *ListWorkersResponse) Reset() { *x = ListWorkersResponse{} - mi := &file_ateapi_proto_msgTypes[76] + mi := &file_ateapi_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5469,7 +5568,7 @@ func (x *ListWorkersResponse) String() string { func (*ListWorkersResponse) ProtoMessage() {} func (x *ListWorkersResponse) 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 { @@ -5482,7 +5581,7 @@ func (x *ListWorkersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkersResponse.ProtoReflect.Descriptor instead. func (*ListWorkersResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{76} + return file_ateapi_proto_rawDescGZIP(), []int{77} } func (x *ListWorkersResponse) GetWorkers() []*Worker { @@ -5512,7 +5611,7 @@ type GetWorkerRequest struct { func (x *GetWorkerRequest) Reset() { *x = GetWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[77] + mi := &file_ateapi_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5524,7 +5623,7 @@ func (x *GetWorkerRequest) String() string { func (*GetWorkerRequest) ProtoMessage() {} func (x *GetWorkerRequest) 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 { @@ -5537,7 +5636,7 @@ func (x *GetWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkerRequest.ProtoReflect.Descriptor instead. func (*GetWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{77} + return file_ateapi_proto_rawDescGZIP(), []int{78} } func (x *GetWorkerRequest) GetWorker() *ObjectRef { @@ -5559,7 +5658,7 @@ type CreateWorkerRequest struct { func (x *CreateWorkerRequest) Reset() { *x = CreateWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[78] + mi := &file_ateapi_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5571,7 +5670,7 @@ func (x *CreateWorkerRequest) String() string { func (*CreateWorkerRequest) ProtoMessage() {} func (x *CreateWorkerRequest) 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 { @@ -5584,7 +5683,7 @@ func (x *CreateWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkerRequest.ProtoReflect.Descriptor instead. func (*CreateWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{78} + return file_ateapi_proto_rawDescGZIP(), []int{79} } func (x *CreateWorkerRequest) GetWorker() *Worker { @@ -5619,7 +5718,7 @@ type UpdateWorkerRequest struct { func (x *UpdateWorkerRequest) Reset() { *x = UpdateWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[79] + mi := &file_ateapi_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5631,7 +5730,7 @@ func (x *UpdateWorkerRequest) String() string { func (*UpdateWorkerRequest) ProtoMessage() {} func (x *UpdateWorkerRequest) 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 { @@ -5644,7 +5743,7 @@ func (x *UpdateWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateWorkerRequest.ProtoReflect.Descriptor instead. func (*UpdateWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{79} + return file_ateapi_proto_rawDescGZIP(), []int{80} } func (x *UpdateWorkerRequest) GetWorker() *Worker { @@ -5671,7 +5770,7 @@ type DeleteWorkerRequest struct { func (x *DeleteWorkerRequest) Reset() { *x = DeleteWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[80] + mi := &file_ateapi_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5683,7 +5782,7 @@ func (x *DeleteWorkerRequest) String() string { func (*DeleteWorkerRequest) ProtoMessage() {} func (x *DeleteWorkerRequest) 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 { @@ -5696,7 +5795,7 @@ func (x *DeleteWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkerRequest.ProtoReflect.Descriptor instead. func (*DeleteWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{80} + return file_ateapi_proto_rawDescGZIP(), []int{81} } func (x *DeleteWorkerRequest) GetWorker() *ObjectRef { @@ -5726,7 +5825,7 @@ type DrainWorkerRequest struct { func (x *DrainWorkerRequest) Reset() { *x = DrainWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[81] + mi := &file_ateapi_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5738,7 +5837,7 @@ func (x *DrainWorkerRequest) String() string { func (*DrainWorkerRequest) ProtoMessage() {} func (x *DrainWorkerRequest) 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 { @@ -5751,7 +5850,7 @@ func (x *DrainWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DrainWorkerRequest.ProtoReflect.Descriptor instead. func (*DrainWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{81} + return file_ateapi_proto_rawDescGZIP(), []int{82} } func (x *DrainWorkerRequest) GetWorker() *ObjectRef { @@ -5789,7 +5888,7 @@ type ListActorsRequest struct { func (x *ListActorsRequest) Reset() { *x = ListActorsRequest{} - mi := &file_ateapi_proto_msgTypes[82] + mi := &file_ateapi_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5801,7 +5900,7 @@ func (x *ListActorsRequest) String() string { func (*ListActorsRequest) ProtoMessage() {} func (x *ListActorsRequest) 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 { @@ -5814,7 +5913,7 @@ func (x *ListActorsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorsRequest.ProtoReflect.Descriptor instead. func (*ListActorsRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{82} + return file_ateapi_proto_rawDescGZIP(), []int{83} } func (x *ListActorsRequest) GetAtespace() string { @@ -5850,7 +5949,7 @@ type ListActorsResponse struct { func (x *ListActorsResponse) Reset() { *x = ListActorsResponse{} - mi := &file_ateapi_proto_msgTypes[83] + mi := &file_ateapi_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5862,7 +5961,7 @@ func (x *ListActorsResponse) String() string { func (*ListActorsResponse) ProtoMessage() {} func (x *ListActorsResponse) 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 { @@ -5875,7 +5974,7 @@ func (x *ListActorsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorsResponse.ProtoReflect.Descriptor instead. func (*ListActorsResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{83} + return file_ateapi_proto_rawDescGZIP(), []int{84} } func (x *ListActorsResponse) GetActors() []*Actor { @@ -5972,7 +6071,7 @@ type Worker struct { func (x *Worker) Reset() { *x = Worker{} - mi := &file_ateapi_proto_msgTypes[84] + mi := &file_ateapi_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5984,7 +6083,7 @@ func (x *Worker) String() string { func (*Worker) ProtoMessage() {} func (x *Worker) 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 { @@ -5997,7 +6096,7 @@ func (x *Worker) ProtoReflect() protoreflect.Message { // Deprecated: Use Worker.ProtoReflect.Descriptor instead. func (*Worker) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{84} + return file_ateapi_proto_rawDescGZIP(), []int{85} } func (x *Worker) GetMetadata() *ResourceMetadata { @@ -6093,7 +6192,7 @@ type WorkerStatus struct { func (x *WorkerStatus) Reset() { *x = WorkerStatus{} - mi := &file_ateapi_proto_msgTypes[85] + mi := &file_ateapi_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6105,7 +6204,7 @@ func (x *WorkerStatus) String() string { func (*WorkerStatus) ProtoMessage() {} func (x *WorkerStatus) 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 { @@ -6118,7 +6217,7 @@ func (x *WorkerStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkerStatus.ProtoReflect.Descriptor instead. func (*WorkerStatus) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{85} + return file_ateapi_proto_rawDescGZIP(), []int{86} } func (x *WorkerStatus) GetState() WorkerState { @@ -6159,7 +6258,7 @@ type WorkerCapacity struct { func (x *WorkerCapacity) Reset() { *x = WorkerCapacity{} - mi := &file_ateapi_proto_msgTypes[86] + mi := &file_ateapi_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6171,7 +6270,7 @@ func (x *WorkerCapacity) String() string { func (*WorkerCapacity) ProtoMessage() {} func (x *WorkerCapacity) 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 { @@ -6184,7 +6283,7 @@ func (x *WorkerCapacity) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkerCapacity.ProtoReflect.Descriptor instead. func (*WorkerCapacity) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{86} + return file_ateapi_proto_rawDescGZIP(), []int{87} } func (x *WorkerCapacity) GetCpuMilli() int64 { @@ -6223,7 +6322,7 @@ type ActorAssignment struct { func (x *ActorAssignment) Reset() { *x = ActorAssignment{} - mi := &file_ateapi_proto_msgTypes[87] + mi := &file_ateapi_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6235,7 +6334,7 @@ func (x *ActorAssignment) String() string { func (*ActorAssignment) ProtoMessage() {} func (x *ActorAssignment) 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 { @@ -6248,7 +6347,7 @@ func (x *ActorAssignment) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorAssignment.ProtoReflect.Descriptor instead. func (*ActorAssignment) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{87} + return file_ateapi_proto_rawDescGZIP(), []int{88} } func (x *ActorAssignment) GetActor() *ObjectRef { @@ -6297,7 +6396,7 @@ type MintJWTRequest struct { func (x *MintJWTRequest) Reset() { *x = MintJWTRequest{} - mi := &file_ateapi_proto_msgTypes[88] + mi := &file_ateapi_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6309,7 +6408,7 @@ func (x *MintJWTRequest) String() string { func (*MintJWTRequest) ProtoMessage() {} func (x *MintJWTRequest) 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 { @@ -6322,7 +6421,7 @@ func (x *MintJWTRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintJWTRequest.ProtoReflect.Descriptor instead. func (*MintJWTRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{88} + return file_ateapi_proto_rawDescGZIP(), []int{89} } func (x *MintJWTRequest) GetAudience() []string { @@ -6381,7 +6480,7 @@ type MintJWTResponse struct { func (x *MintJWTResponse) Reset() { *x = MintJWTResponse{} - mi := &file_ateapi_proto_msgTypes[89] + mi := &file_ateapi_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6393,7 +6492,7 @@ func (x *MintJWTResponse) String() string { func (*MintJWTResponse) ProtoMessage() {} func (x *MintJWTResponse) 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 { @@ -6406,7 +6505,7 @@ func (x *MintJWTResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MintJWTResponse.ProtoReflect.Descriptor instead. func (*MintJWTResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{89} + return file_ateapi_proto_rawDescGZIP(), []int{90} } func (x *MintJWTResponse) GetActorJwt() string { @@ -6453,7 +6552,7 @@ type MintCertRequest struct { func (x *MintCertRequest) Reset() { *x = MintCertRequest{} - mi := &file_ateapi_proto_msgTypes[90] + mi := &file_ateapi_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6465,7 +6564,7 @@ func (x *MintCertRequest) String() string { func (*MintCertRequest) ProtoMessage() {} func (x *MintCertRequest) 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 { @@ -6478,7 +6577,7 @@ func (x *MintCertRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintCertRequest.ProtoReflect.Descriptor instead. func (*MintCertRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{90} + return file_ateapi_proto_rawDescGZIP(), []int{91} } func (x *MintCertRequest) GetWorker() *ObjectRef { @@ -6521,7 +6620,7 @@ type MintCertResponse struct { func (x *MintCertResponse) Reset() { *x = MintCertResponse{} - mi := &file_ateapi_proto_msgTypes[91] + mi := &file_ateapi_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6533,7 +6632,7 @@ func (x *MintCertResponse) String() string { func (*MintCertResponse) ProtoMessage() {} func (x *MintCertResponse) 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 { @@ -6546,7 +6645,7 @@ func (x *MintCertResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MintCertResponse.ProtoReflect.Descriptor instead. func (*MintCertResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{91} + return file_ateapi_proto_rawDescGZIP(), []int{92} } func (x *MintCertResponse) GetActorCertificates() [][]byte { @@ -6560,11 +6659,12 @@ var File_ateapi_proto protoreflect.FileDescriptor const file_ateapi_proto_rawDesc = "" + "\n" + - "\fateapi.proto\x12\x06ateapi\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\xbd\x01\n" + + "\fateapi.proto\x12\x06ateapi\x1a\x1bgoogle/protobuf/empty.proto\x1a\x1fgoogle/protobuf/timestamp.proto\"\x85\x02\n" + "\x11LocalSnapshotInfo\x12#\n" + "\rsnapshot_name\x18\x01 \x01(\tR\fsnapshotName\x12@\n" + "\x1dnode_vms_with_local_snapshots\x18\x02 \x03(\tR\x19nodeVmsWithLocalSnapshots\x12A\n" + - "\rcontent_scope\x18\x03 \x01(\x0e2\x1c.ateapi.SnapshotContentScopeR\fcontentScope\"\x90\x01\n" + + "\rcontent_scope\x18\x03 \x01(\x0e2\x1c.ateapi.SnapshotContentScopeR\fcontentScope\x12F\n" + + "\x12sandbox_config_ref\x18\x04 \x01(\v2\x18.ateapi.SandboxConfigRefR\x10sandboxConfigRef\"\x90\x01\n" + "\bSelector\x12D\n" + "\fmatch_labels\x18\x01 \x03(\v2!.ateapi.Selector.MatchLabelsEntryR\vmatchLabels\x1a>\n" + "\x10MatchLabelsEntry\x12\x10\n" + @@ -6647,7 +6747,7 @@ const file_ateapi_proto_rawDesc = "" + "\rworker_pod_ip\x18\x05 \x01(\tR\vworkerPodIp\"z\n" + "\rActorSnapshot\x124\n" + "\bmetadata\x18\x01 \x01(\v2\x18.ateapi.ResourceMetadataR\bmetadata\x123\n" + - "\x06status\x18\x02 \x01(\v2\x1b.ateapi.ActorSnapshotStatusR\x06status\"\xf5\x02\n" + + "\x06status\x18\x02 \x01(\v2\x1b.ateapi.ActorSnapshotStatusR\x06status\"\xbd\x03\n" + "\x13ActorSnapshotStatus\x124\n" + "\fsource_actor\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\vsourceActor\x12(\n" + "\x10source_actor_uid\x18\x02 \x01(\tR\x0esourceActorUid\x120\n" + @@ -6655,7 +6755,9 @@ const file_ateapi_proto_rawDesc = "" + "\x12actor_template_uid\x18\x06 \x01(\tR\x10actorTemplateUid\x12A\n" + "\rcontent_scope\x18\a \x01(\x0e2\x1c.ateapi.SnapshotContentScopeR\fcontentScope\x12!\n" + "\fsnapshot_uri\x18\b \x01(\tR\vsnapshotUri\x128\n" + - "\x0eactor_template\x18\t \x01(\v2\x11.ateapi.ObjectRefR\ractorTemplate\"\xac\x01\n" + + "\x0eactor_template\x18\t \x01(\v2\x11.ateapi.ObjectRefR\ractorTemplate\x12F\n" + + "\x12sandbox_config_ref\x18\n" + + " \x01(\v2\x18.ateapi.SandboxConfigRefR\x10sandboxConfigRef\"\xac\x01\n" + "\x10ActorSnapshotTag\x124\n" + "\bmetadata\x18\x01 \x01(\v2\x18.ateapi.ResourceMetadataR\bmetadata\x12-\n" + "\bsnapshot\x18\x02 \x01(\v2\x11.ateapi.ObjectRefR\bsnapshot\x123\n" + @@ -6664,7 +6766,11 @@ const file_ateapi_proto_rawDesc = "" + "\bmetadata\x18\x01 \x01(\v2\x18.ateapi.ResourceMetadataR\bmetadata\";\n" + "\tObjectRef\x12\x1a\n" + "\batespace\x18\x01 \x01(\tR\batespace\x12\x12\n" + - "\x04name\x18\x02 \x01(\tR\x04name\"\xc5\x03\n" + + "\x04name\x18\x02 \x01(\tR\x04name\"c\n" + + "\x10SandboxConfigRef\x12\x12\n" + + "\x04name\x18\x01 \x01(\tR\x04name\x12\x10\n" + + "\x03uid\x18\x02 \x01(\tR\x03uid\x12)\n" + + "\x10resource_version\x18\x03 \x01(\tR\x0fresourceVersion\"\xc5\x03\n" + "\rActorTemplate\x124\n" + "\bmetadata\x18\x01 \x01(\v2\x18.ateapi.ResourceMetadataR\bmetadata\x129\n" + "\x0fworker_selector\x18\x02 \x01(\v2\x10.ateapi.SelectorR\x0eworkerSelector\x121\n" + @@ -6996,7 +7102,7 @@ func file_ateapi_proto_rawDescGZIP() []byte { } var file_ateapi_proto_enumTypes = make([]protoimpl.EnumInfo, 9) -var file_ateapi_proto_msgTypes = make([]protoimpl.MessageInfo, 95) +var file_ateapi_proto_msgTypes = make([]protoimpl.MessageInfo, 96) var file_ateapi_proto_goTypes = []any{ (SnapshotContentScope)(0), // 0: ateapi.SnapshotContentScope (ActorSnapshotTagScope)(0), // 1: ateapi.ActorSnapshotTagScope @@ -7026,276 +7132,279 @@ var file_ateapi_proto_goTypes = []any{ (*ActorSnapshotTag)(nil), // 25: ateapi.ActorSnapshotTag (*Atespace)(nil), // 26: ateapi.Atespace (*ObjectRef)(nil), // 27: ateapi.ObjectRef - (*ActorTemplate)(nil), // 28: ateapi.ActorTemplate - (*Resources)(nil), // 29: ateapi.Resources - (*Limits)(nil), // 30: ateapi.Limits - (*GoldenSnapshotStatus)(nil), // 31: ateapi.GoldenSnapshotStatus - (*ActorTemplateStatus)(nil), // 32: ateapi.ActorTemplateStatus - (*SandboxConfig)(nil), // 33: ateapi.SandboxConfig - (*SnapshotsConfig)(nil), // 34: ateapi.SnapshotsConfig - (*OnResumeConfig)(nil), // 35: ateapi.OnResumeConfig - (*Container)(nil), // 36: ateapi.Container - (*SecurityContext)(nil), // 37: ateapi.SecurityContext - (*Capabilities)(nil), // 38: ateapi.Capabilities - (*EnvVar)(nil), // 39: ateapi.EnvVar - (*ContainerReadyz)(nil), // 40: ateapi.ContainerReadyz - (*HTTPGetAction)(nil), // 41: ateapi.HTTPGetAction - (*Volume)(nil), // 42: ateapi.Volume - (*ImageVolumeSource)(nil), // 43: ateapi.ImageVolumeSource - (*DurableDirVolumeSource)(nil), // 44: ateapi.DurableDirVolumeSource - (*ExternalVolumeTemplate)(nil), // 45: ateapi.ExternalVolumeTemplate - (*SystemInfoVolumeSource)(nil), // 46: ateapi.SystemInfoVolumeSource - (*SystemInfoDataSource)(nil), // 47: ateapi.SystemInfoDataSource - (*ActorMetadataDataSource)(nil), // 48: ateapi.ActorMetadataDataSource - (*ActorMetadataItem)(nil), // 49: ateapi.ActorMetadataItem - (*TrustBundleDataSource)(nil), // 50: ateapi.TrustBundleDataSource - (*VolumeMount)(nil), // 51: ateapi.VolumeMount - (*CreateAtespaceRequest)(nil), // 52: ateapi.CreateAtespaceRequest - (*GetAtespaceRequest)(nil), // 53: ateapi.GetAtespaceRequest - (*ListAtespacesRequest)(nil), // 54: ateapi.ListAtespacesRequest - (*ListAtespacesResponse)(nil), // 55: ateapi.ListAtespacesResponse - (*DeleteAtespaceRequest)(nil), // 56: ateapi.DeleteAtespaceRequest - (*CreateActorTemplateRequest)(nil), // 57: ateapi.CreateActorTemplateRequest - (*GetActorTemplateRequest)(nil), // 58: ateapi.GetActorTemplateRequest - (*ListActorTemplatesRequest)(nil), // 59: ateapi.ListActorTemplatesRequest - (*ListActorTemplatesResponse)(nil), // 60: ateapi.ListActorTemplatesResponse - (*DeleteActorTemplateRequest)(nil), // 61: ateapi.DeleteActorTemplateRequest - (*GetActorRequest)(nil), // 62: ateapi.GetActorRequest - (*CreateActorRequest)(nil), // 63: ateapi.CreateActorRequest - (*UpdateActorRequest)(nil), // 64: ateapi.UpdateActorRequest - (*SuspendActorRequest)(nil), // 65: ateapi.SuspendActorRequest - (*SuspendActorResponse)(nil), // 66: ateapi.SuspendActorResponse - (*PauseActorRequest)(nil), // 67: ateapi.PauseActorRequest - (*PauseActorResponse)(nil), // 68: ateapi.PauseActorResponse - (*ResumeActorRequest)(nil), // 69: ateapi.ResumeActorRequest - (*ResumeActorResponse)(nil), // 70: ateapi.ResumeActorResponse - (*DeleteActorRequest)(nil), // 71: ateapi.DeleteActorRequest - (*GetActorEgressPolicyRequest)(nil), // 72: ateapi.GetActorEgressPolicyRequest - (*CreateActorEgressPolicyRequest)(nil), // 73: ateapi.CreateActorEgressPolicyRequest - (*UpdateActorEgressPolicyRequest)(nil), // 74: ateapi.UpdateActorEgressPolicyRequest - (*DeleteActorEgressPolicyRequest)(nil), // 75: ateapi.DeleteActorEgressPolicyRequest - (*GetActorSnapshotRequest)(nil), // 76: ateapi.GetActorSnapshotRequest - (*GetActorSnapshotTagRequest)(nil), // 77: ateapi.GetActorSnapshotTagRequest - (*ListActorSnapshotsRequest)(nil), // 78: ateapi.ListActorSnapshotsRequest - (*ListActorSnapshotsResponse)(nil), // 79: ateapi.ListActorSnapshotsResponse - (*CreateActorSnapshotTagRequest)(nil), // 80: ateapi.CreateActorSnapshotTagRequest - (*UpdateActorSnapshotTagRequest)(nil), // 81: ateapi.UpdateActorSnapshotTagRequest - (*DeleteActorSnapshotTagRequest)(nil), // 82: ateapi.DeleteActorSnapshotTagRequest - (*DeleteOptions)(nil), // 83: ateapi.DeleteOptions - (*ListWorkersRequest)(nil), // 84: ateapi.ListWorkersRequest - (*ListWorkersResponse)(nil), // 85: ateapi.ListWorkersResponse - (*GetWorkerRequest)(nil), // 86: ateapi.GetWorkerRequest - (*CreateWorkerRequest)(nil), // 87: ateapi.CreateWorkerRequest - (*UpdateWorkerRequest)(nil), // 88: ateapi.UpdateWorkerRequest - (*DeleteWorkerRequest)(nil), // 89: ateapi.DeleteWorkerRequest - (*DrainWorkerRequest)(nil), // 90: ateapi.DrainWorkerRequest - (*ListActorsRequest)(nil), // 91: ateapi.ListActorsRequest - (*ListActorsResponse)(nil), // 92: ateapi.ListActorsResponse - (*Worker)(nil), // 93: ateapi.Worker - (*WorkerStatus)(nil), // 94: ateapi.WorkerStatus - (*WorkerCapacity)(nil), // 95: ateapi.WorkerCapacity - (*ActorAssignment)(nil), // 96: ateapi.ActorAssignment - (*MintJWTRequest)(nil), // 97: ateapi.MintJWTRequest - (*MintJWTResponse)(nil), // 98: ateapi.MintJWTResponse - (*MintCertRequest)(nil), // 99: ateapi.MintCertRequest - (*MintCertResponse)(nil), // 100: ateapi.MintCertResponse - nil, // 101: ateapi.Selector.MatchLabelsEntry - nil, // 102: ateapi.ExternalVolume.VolumeContextEntry - nil, // 103: ateapi.Worker.LabelsEntry - (*timestamppb.Timestamp)(nil), // 104: google.protobuf.Timestamp - (*emptypb.Empty)(nil), // 105: google.protobuf.Empty + (*SandboxConfigRef)(nil), // 28: ateapi.SandboxConfigRef + (*ActorTemplate)(nil), // 29: ateapi.ActorTemplate + (*Resources)(nil), // 30: ateapi.Resources + (*Limits)(nil), // 31: ateapi.Limits + (*GoldenSnapshotStatus)(nil), // 32: ateapi.GoldenSnapshotStatus + (*ActorTemplateStatus)(nil), // 33: ateapi.ActorTemplateStatus + (*SandboxConfig)(nil), // 34: ateapi.SandboxConfig + (*SnapshotsConfig)(nil), // 35: ateapi.SnapshotsConfig + (*OnResumeConfig)(nil), // 36: ateapi.OnResumeConfig + (*Container)(nil), // 37: ateapi.Container + (*SecurityContext)(nil), // 38: ateapi.SecurityContext + (*Capabilities)(nil), // 39: ateapi.Capabilities + (*EnvVar)(nil), // 40: ateapi.EnvVar + (*ContainerReadyz)(nil), // 41: ateapi.ContainerReadyz + (*HTTPGetAction)(nil), // 42: ateapi.HTTPGetAction + (*Volume)(nil), // 43: ateapi.Volume + (*ImageVolumeSource)(nil), // 44: ateapi.ImageVolumeSource + (*DurableDirVolumeSource)(nil), // 45: ateapi.DurableDirVolumeSource + (*ExternalVolumeTemplate)(nil), // 46: ateapi.ExternalVolumeTemplate + (*SystemInfoVolumeSource)(nil), // 47: ateapi.SystemInfoVolumeSource + (*SystemInfoDataSource)(nil), // 48: ateapi.SystemInfoDataSource + (*ActorMetadataDataSource)(nil), // 49: ateapi.ActorMetadataDataSource + (*ActorMetadataItem)(nil), // 50: ateapi.ActorMetadataItem + (*TrustBundleDataSource)(nil), // 51: ateapi.TrustBundleDataSource + (*VolumeMount)(nil), // 52: ateapi.VolumeMount + (*CreateAtespaceRequest)(nil), // 53: ateapi.CreateAtespaceRequest + (*GetAtespaceRequest)(nil), // 54: ateapi.GetAtespaceRequest + (*ListAtespacesRequest)(nil), // 55: ateapi.ListAtespacesRequest + (*ListAtespacesResponse)(nil), // 56: ateapi.ListAtespacesResponse + (*DeleteAtespaceRequest)(nil), // 57: ateapi.DeleteAtespaceRequest + (*CreateActorTemplateRequest)(nil), // 58: ateapi.CreateActorTemplateRequest + (*GetActorTemplateRequest)(nil), // 59: ateapi.GetActorTemplateRequest + (*ListActorTemplatesRequest)(nil), // 60: ateapi.ListActorTemplatesRequest + (*ListActorTemplatesResponse)(nil), // 61: ateapi.ListActorTemplatesResponse + (*DeleteActorTemplateRequest)(nil), // 62: ateapi.DeleteActorTemplateRequest + (*GetActorRequest)(nil), // 63: ateapi.GetActorRequest + (*CreateActorRequest)(nil), // 64: ateapi.CreateActorRequest + (*UpdateActorRequest)(nil), // 65: ateapi.UpdateActorRequest + (*SuspendActorRequest)(nil), // 66: ateapi.SuspendActorRequest + (*SuspendActorResponse)(nil), // 67: ateapi.SuspendActorResponse + (*PauseActorRequest)(nil), // 68: ateapi.PauseActorRequest + (*PauseActorResponse)(nil), // 69: ateapi.PauseActorResponse + (*ResumeActorRequest)(nil), // 70: ateapi.ResumeActorRequest + (*ResumeActorResponse)(nil), // 71: ateapi.ResumeActorResponse + (*DeleteActorRequest)(nil), // 72: ateapi.DeleteActorRequest + (*GetActorEgressPolicyRequest)(nil), // 73: ateapi.GetActorEgressPolicyRequest + (*CreateActorEgressPolicyRequest)(nil), // 74: ateapi.CreateActorEgressPolicyRequest + (*UpdateActorEgressPolicyRequest)(nil), // 75: ateapi.UpdateActorEgressPolicyRequest + (*DeleteActorEgressPolicyRequest)(nil), // 76: ateapi.DeleteActorEgressPolicyRequest + (*GetActorSnapshotRequest)(nil), // 77: ateapi.GetActorSnapshotRequest + (*GetActorSnapshotTagRequest)(nil), // 78: ateapi.GetActorSnapshotTagRequest + (*ListActorSnapshotsRequest)(nil), // 79: ateapi.ListActorSnapshotsRequest + (*ListActorSnapshotsResponse)(nil), // 80: ateapi.ListActorSnapshotsResponse + (*CreateActorSnapshotTagRequest)(nil), // 81: ateapi.CreateActorSnapshotTagRequest + (*UpdateActorSnapshotTagRequest)(nil), // 82: ateapi.UpdateActorSnapshotTagRequest + (*DeleteActorSnapshotTagRequest)(nil), // 83: ateapi.DeleteActorSnapshotTagRequest + (*DeleteOptions)(nil), // 84: ateapi.DeleteOptions + (*ListWorkersRequest)(nil), // 85: ateapi.ListWorkersRequest + (*ListWorkersResponse)(nil), // 86: ateapi.ListWorkersResponse + (*GetWorkerRequest)(nil), // 87: ateapi.GetWorkerRequest + (*CreateWorkerRequest)(nil), // 88: ateapi.CreateWorkerRequest + (*UpdateWorkerRequest)(nil), // 89: ateapi.UpdateWorkerRequest + (*DeleteWorkerRequest)(nil), // 90: ateapi.DeleteWorkerRequest + (*DrainWorkerRequest)(nil), // 91: ateapi.DrainWorkerRequest + (*ListActorsRequest)(nil), // 92: ateapi.ListActorsRequest + (*ListActorsResponse)(nil), // 93: ateapi.ListActorsResponse + (*Worker)(nil), // 94: ateapi.Worker + (*WorkerStatus)(nil), // 95: ateapi.WorkerStatus + (*WorkerCapacity)(nil), // 96: ateapi.WorkerCapacity + (*ActorAssignment)(nil), // 97: ateapi.ActorAssignment + (*MintJWTRequest)(nil), // 98: ateapi.MintJWTRequest + (*MintJWTResponse)(nil), // 99: ateapi.MintJWTResponse + (*MintCertRequest)(nil), // 100: ateapi.MintCertRequest + (*MintCertResponse)(nil), // 101: ateapi.MintCertResponse + nil, // 102: ateapi.Selector.MatchLabelsEntry + nil, // 103: ateapi.ExternalVolume.VolumeContextEntry + nil, // 104: ateapi.Worker.LabelsEntry + (*timestamppb.Timestamp)(nil), // 105: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 106: google.protobuf.Empty } var file_ateapi_proto_depIdxs = []int32{ 0, // 0: ateapi.LocalSnapshotInfo.content_scope:type_name -> ateapi.SnapshotContentScope - 101, // 1: ateapi.Selector.match_labels:type_name -> ateapi.Selector.MatchLabelsEntry - 104, // 2: ateapi.ResourceMetadata.create_time:type_name -> google.protobuf.Timestamp - 104, // 3: ateapi.ResourceMetadata.update_time:type_name -> google.protobuf.Timestamp - 8, // 4: ateapi.ExternalVolume.status:type_name -> ateapi.ExternalVolume.Status - 102, // 5: ateapi.ExternalVolume.volume_context:type_name -> ateapi.ExternalVolume.VolumeContextEntry - 11, // 6: ateapi.Actor.metadata:type_name -> ateapi.ResourceMetadata - 27, // 7: ateapi.Actor.actor_template:type_name -> ateapi.ObjectRef - 10, // 8: ateapi.Actor.worker_selector:type_name -> ateapi.Selector - 27, // 9: ateapi.Actor.source_snapshot_tag:type_name -> ateapi.ObjectRef - 20, // 10: ateapi.Actor.status:type_name -> ateapi.ActorStatus - 11, // 11: ateapi.EgressPolicy.metadata:type_name -> ateapi.ResourceMetadata - 15, // 12: ateapi.EgressPolicy.rules:type_name -> ateapi.EgressRule - 16, // 13: ateapi.EgressRule.hostnames:type_name -> ateapi.HostnameRule - 17, // 14: ateapi.EgressRule.ip_blocks:type_name -> ateapi.IPBlockRule - 105, // 15: ateapi.EgressRule.all:type_name -> google.protobuf.Empty - 18, // 16: ateapi.HostnameRule.effects:type_name -> ateapi.EgressRuleEffects - 19, // 17: ateapi.EgressRuleEffects.inject_static_headers:type_name -> ateapi.CredentialHeaderInjection - 2, // 18: ateapi.ActorStatus.state:type_name -> ateapi.ActorState - 22, // 19: ateapi.ActorStatus.worker_assignment:type_name -> ateapi.WorkerAssignment - 27, // 20: ateapi.ActorStatus.latest_snapshot:type_name -> ateapi.ObjectRef - 9, // 21: ateapi.ActorStatus.local_snapshot_info:type_name -> ateapi.LocalSnapshotInfo - 12, // 22: ateapi.ActorStatus.actor_volumes:type_name -> ateapi.ExternalVolume - 21, // 23: ateapi.ActorStatus.source_snapshot:type_name -> ateapi.ActorSourceSnapshotStatus - 27, // 24: ateapi.ActorStatus.current_actor_template:type_name -> ateapi.ObjectRef - 27, // 25: ateapi.ActorSourceSnapshotStatus.snapshot:type_name -> ateapi.ObjectRef - 27, // 26: ateapi.WorkerAssignment.worker:type_name -> ateapi.ObjectRef - 11, // 27: ateapi.ActorSnapshot.metadata:type_name -> ateapi.ResourceMetadata - 24, // 28: ateapi.ActorSnapshot.status:type_name -> ateapi.ActorSnapshotStatus - 27, // 29: ateapi.ActorSnapshotStatus.source_actor:type_name -> ateapi.ObjectRef - 0, // 30: ateapi.ActorSnapshotStatus.content_scope:type_name -> ateapi.SnapshotContentScope - 27, // 31: ateapi.ActorSnapshotStatus.actor_template:type_name -> ateapi.ObjectRef - 11, // 32: ateapi.ActorSnapshotTag.metadata:type_name -> ateapi.ResourceMetadata - 27, // 33: ateapi.ActorSnapshotTag.snapshot:type_name -> ateapi.ObjectRef - 1, // 34: ateapi.ActorSnapshotTag.scope:type_name -> ateapi.ActorSnapshotTagScope - 11, // 35: ateapi.Atespace.metadata:type_name -> ateapi.ResourceMetadata - 11, // 36: ateapi.ActorTemplate.metadata:type_name -> ateapi.ResourceMetadata - 10, // 37: ateapi.ActorTemplate.worker_selector:type_name -> ateapi.Selector - 36, // 38: ateapi.ActorTemplate.containers:type_name -> ateapi.Container - 42, // 39: ateapi.ActorTemplate.volumes:type_name -> ateapi.Volume - 34, // 40: ateapi.ActorTemplate.snapshots_config:type_name -> ateapi.SnapshotsConfig - 33, // 41: ateapi.ActorTemplate.sandbox_config:type_name -> ateapi.SandboxConfig - 29, // 42: ateapi.ActorTemplate.resources:type_name -> ateapi.Resources - 32, // 43: ateapi.ActorTemplate.status:type_name -> ateapi.ActorTemplateStatus - 30, // 44: ateapi.Resources.limits:type_name -> ateapi.Limits - 27, // 45: ateapi.GoldenSnapshotStatus.golden_snapshot:type_name -> ateapi.ObjectRef - 104, // 46: ateapi.GoldenSnapshotStatus.take_golden_snapshot_at:type_name -> google.protobuf.Timestamp - 31, // 47: ateapi.ActorTemplateStatus.golden_snapshot_status:type_name -> ateapi.GoldenSnapshotStatus - 3, // 48: ateapi.SandboxConfig.sandbox_class:type_name -> ateapi.SandboxClass - 0, // 49: ateapi.SnapshotsConfig.on_pause:type_name -> ateapi.SnapshotContentScope - 0, // 50: ateapi.SnapshotsConfig.on_commit:type_name -> ateapi.SnapshotContentScope - 35, // 51: ateapi.SnapshotsConfig.on_resume:type_name -> ateapi.OnResumeConfig - 4, // 52: ateapi.OnResumeConfig.from_data:type_name -> ateapi.ResumeSource - 39, // 53: ateapi.Container.env:type_name -> ateapi.EnvVar - 40, // 54: ateapi.Container.readyz:type_name -> ateapi.ContainerReadyz - 51, // 55: ateapi.Container.volume_mounts:type_name -> ateapi.VolumeMount - 37, // 56: ateapi.Container.security_context:type_name -> ateapi.SecurityContext - 29, // 57: ateapi.Container.resources:type_name -> ateapi.Resources - 38, // 58: ateapi.SecurityContext.capabilities:type_name -> ateapi.Capabilities - 41, // 59: ateapi.ContainerReadyz.http_get:type_name -> ateapi.HTTPGetAction - 44, // 60: ateapi.Volume.durable_dir:type_name -> ateapi.DurableDirVolumeSource - 45, // 61: ateapi.Volume.external_volume_template:type_name -> ateapi.ExternalVolumeTemplate - 46, // 62: ateapi.Volume.system_info:type_name -> ateapi.SystemInfoVolumeSource - 43, // 63: ateapi.Volume.image:type_name -> ateapi.ImageVolumeSource - 47, // 64: ateapi.SystemInfoVolumeSource.data_sources:type_name -> ateapi.SystemInfoDataSource - 48, // 65: ateapi.SystemInfoDataSource.actor_metadata:type_name -> ateapi.ActorMetadataDataSource - 50, // 66: ateapi.SystemInfoDataSource.trust_bundle:type_name -> ateapi.TrustBundleDataSource - 49, // 67: ateapi.ActorMetadataDataSource.items:type_name -> ateapi.ActorMetadataItem - 5, // 68: ateapi.ActorMetadataItem.field:type_name -> ateapi.ActorMetadataField - 26, // 69: ateapi.CreateAtespaceRequest.atespace:type_name -> ateapi.Atespace - 27, // 70: ateapi.GetAtespaceRequest.atespace:type_name -> ateapi.ObjectRef - 26, // 71: ateapi.ListAtespacesResponse.atespaces:type_name -> ateapi.Atespace - 27, // 72: ateapi.DeleteAtespaceRequest.atespace:type_name -> ateapi.ObjectRef - 28, // 73: ateapi.CreateActorTemplateRequest.actor_template:type_name -> ateapi.ActorTemplate - 27, // 74: ateapi.GetActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef - 28, // 75: ateapi.ListActorTemplatesResponse.actor_templates:type_name -> ateapi.ActorTemplate - 27, // 76: ateapi.DeleteActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef - 27, // 77: ateapi.GetActorRequest.actor:type_name -> ateapi.ObjectRef - 13, // 78: ateapi.CreateActorRequest.actor:type_name -> ateapi.Actor - 13, // 79: ateapi.UpdateActorRequest.actor:type_name -> ateapi.Actor - 27, // 80: ateapi.SuspendActorRequest.actor:type_name -> ateapi.ObjectRef - 13, // 81: ateapi.SuspendActorResponse.actor:type_name -> ateapi.Actor - 27, // 82: ateapi.PauseActorRequest.actor:type_name -> ateapi.ObjectRef - 13, // 83: ateapi.PauseActorResponse.actor:type_name -> ateapi.Actor - 27, // 84: ateapi.ResumeActorRequest.actor:type_name -> ateapi.ObjectRef - 13, // 85: ateapi.ResumeActorResponse.actor:type_name -> ateapi.Actor - 27, // 86: ateapi.DeleteActorRequest.actor:type_name -> ateapi.ObjectRef - 27, // 87: ateapi.GetActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 27, // 88: ateapi.CreateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 14, // 89: ateapi.CreateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy - 27, // 90: ateapi.UpdateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 14, // 91: ateapi.UpdateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy - 27, // 92: ateapi.DeleteActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 27, // 93: ateapi.GetActorSnapshotRequest.actor_snapshot:type_name -> ateapi.ObjectRef - 27, // 94: ateapi.GetActorSnapshotTagRequest.actor_snapshot_tag:type_name -> ateapi.ObjectRef - 23, // 95: ateapi.ListActorSnapshotsResponse.actor_snapshots:type_name -> ateapi.ActorSnapshot - 25, // 96: ateapi.CreateActorSnapshotTagRequest.actor_snapshot_tag:type_name -> ateapi.ActorSnapshotTag - 25, // 97: ateapi.UpdateActorSnapshotTagRequest.actor_snapshot_tag:type_name -> ateapi.ActorSnapshotTag - 27, // 98: ateapi.DeleteActorSnapshotTagRequest.actor_snapshot_tag:type_name -> ateapi.ObjectRef - 93, // 99: ateapi.ListWorkersResponse.workers:type_name -> ateapi.Worker - 27, // 100: ateapi.GetWorkerRequest.worker:type_name -> ateapi.ObjectRef - 93, // 101: ateapi.CreateWorkerRequest.worker:type_name -> ateapi.Worker - 93, // 102: ateapi.UpdateWorkerRequest.worker:type_name -> ateapi.Worker - 27, // 103: ateapi.DeleteWorkerRequest.worker:type_name -> ateapi.ObjectRef - 83, // 104: ateapi.DeleteWorkerRequest.options:type_name -> ateapi.DeleteOptions - 27, // 105: ateapi.DrainWorkerRequest.worker:type_name -> ateapi.ObjectRef - 13, // 106: ateapi.ListActorsResponse.actors:type_name -> ateapi.Actor - 11, // 107: ateapi.Worker.metadata:type_name -> ateapi.ResourceMetadata - 103, // 108: ateapi.Worker.labels:type_name -> ateapi.Worker.LabelsEntry - 95, // 109: ateapi.Worker.capacity:type_name -> ateapi.WorkerCapacity - 94, // 110: ateapi.Worker.status:type_name -> ateapi.WorkerStatus - 6, // 111: ateapi.WorkerStatus.state:type_name -> ateapi.WorkerState - 96, // 112: ateapi.WorkerStatus.assignment:type_name -> ateapi.ActorAssignment - 27, // 113: ateapi.ActorAssignment.actor:type_name -> ateapi.ObjectRef - 27, // 114: ateapi.ActorAssignment.actor_template_ref:type_name -> ateapi.ObjectRef - 27, // 115: ateapi.MintCertRequest.worker:type_name -> ateapi.ObjectRef - 7, // 116: ateapi.MintCertRequest.purpose:type_name -> ateapi.ActorCertificatePurpose - 62, // 117: ateapi.Control.GetActor:input_type -> ateapi.GetActorRequest - 63, // 118: ateapi.Control.CreateActor:input_type -> ateapi.CreateActorRequest - 64, // 119: ateapi.Control.UpdateActor:input_type -> ateapi.UpdateActorRequest - 65, // 120: ateapi.Control.SuspendActor:input_type -> ateapi.SuspendActorRequest - 67, // 121: ateapi.Control.PauseActor:input_type -> ateapi.PauseActorRequest - 69, // 122: ateapi.Control.ResumeActor:input_type -> ateapi.ResumeActorRequest - 71, // 123: ateapi.Control.DeleteActor:input_type -> ateapi.DeleteActorRequest - 72, // 124: ateapi.Control.GetActorEgressPolicy:input_type -> ateapi.GetActorEgressPolicyRequest - 73, // 125: ateapi.Control.CreateActorEgressPolicy:input_type -> ateapi.CreateActorEgressPolicyRequest - 74, // 126: ateapi.Control.UpdateActorEgressPolicy:input_type -> ateapi.UpdateActorEgressPolicyRequest - 75, // 127: ateapi.Control.DeleteActorEgressPolicy:input_type -> ateapi.DeleteActorEgressPolicyRequest - 76, // 128: ateapi.Control.GetActorSnapshot:input_type -> ateapi.GetActorSnapshotRequest - 77, // 129: ateapi.Control.GetActorSnapshotTag:input_type -> ateapi.GetActorSnapshotTagRequest - 78, // 130: ateapi.Control.ListActorSnapshots:input_type -> ateapi.ListActorSnapshotsRequest - 80, // 131: ateapi.Control.CreateActorSnapshotTag:input_type -> ateapi.CreateActorSnapshotTagRequest - 81, // 132: ateapi.Control.UpdateActorSnapshotTag:input_type -> ateapi.UpdateActorSnapshotTagRequest - 82, // 133: ateapi.Control.DeleteActorSnapshotTag:input_type -> ateapi.DeleteActorSnapshotTagRequest - 84, // 134: ateapi.Control.ListWorkers:input_type -> ateapi.ListWorkersRequest - 86, // 135: ateapi.Control.GetWorker:input_type -> ateapi.GetWorkerRequest - 87, // 136: ateapi.Control.CreateWorker:input_type -> ateapi.CreateWorkerRequest - 88, // 137: ateapi.Control.UpdateWorker:input_type -> ateapi.UpdateWorkerRequest - 89, // 138: ateapi.Control.DeleteWorker:input_type -> ateapi.DeleteWorkerRequest - 90, // 139: ateapi.Control.DrainWorker:input_type -> ateapi.DrainWorkerRequest - 91, // 140: ateapi.Control.ListActors:input_type -> ateapi.ListActorsRequest - 52, // 141: ateapi.Control.CreateAtespace:input_type -> ateapi.CreateAtespaceRequest - 53, // 142: ateapi.Control.GetAtespace:input_type -> ateapi.GetAtespaceRequest - 54, // 143: ateapi.Control.ListAtespaces:input_type -> ateapi.ListAtespacesRequest - 56, // 144: ateapi.Control.DeleteAtespace:input_type -> ateapi.DeleteAtespaceRequest - 57, // 145: ateapi.Control.CreateActorTemplate:input_type -> ateapi.CreateActorTemplateRequest - 58, // 146: ateapi.Control.GetActorTemplate:input_type -> ateapi.GetActorTemplateRequest - 59, // 147: ateapi.Control.ListActorTemplates:input_type -> ateapi.ListActorTemplatesRequest - 61, // 148: ateapi.Control.DeleteActorTemplate:input_type -> ateapi.DeleteActorTemplateRequest - 97, // 149: ateapi.ActorIdentity.MintJWT:input_type -> ateapi.MintJWTRequest - 99, // 150: ateapi.ActorIdentity.MintCert:input_type -> ateapi.MintCertRequest - 13, // 151: ateapi.Control.GetActor:output_type -> ateapi.Actor - 13, // 152: ateapi.Control.CreateActor:output_type -> ateapi.Actor - 13, // 153: ateapi.Control.UpdateActor:output_type -> ateapi.Actor - 66, // 154: ateapi.Control.SuspendActor:output_type -> ateapi.SuspendActorResponse - 68, // 155: ateapi.Control.PauseActor:output_type -> ateapi.PauseActorResponse - 70, // 156: ateapi.Control.ResumeActor:output_type -> ateapi.ResumeActorResponse - 13, // 157: ateapi.Control.DeleteActor:output_type -> ateapi.Actor - 14, // 158: ateapi.Control.GetActorEgressPolicy:output_type -> ateapi.EgressPolicy - 14, // 159: ateapi.Control.CreateActorEgressPolicy:output_type -> ateapi.EgressPolicy - 14, // 160: ateapi.Control.UpdateActorEgressPolicy:output_type -> ateapi.EgressPolicy - 14, // 161: ateapi.Control.DeleteActorEgressPolicy:output_type -> ateapi.EgressPolicy - 23, // 162: ateapi.Control.GetActorSnapshot:output_type -> ateapi.ActorSnapshot - 25, // 163: ateapi.Control.GetActorSnapshotTag:output_type -> ateapi.ActorSnapshotTag - 79, // 164: ateapi.Control.ListActorSnapshots:output_type -> ateapi.ListActorSnapshotsResponse - 25, // 165: ateapi.Control.CreateActorSnapshotTag:output_type -> ateapi.ActorSnapshotTag - 25, // 166: ateapi.Control.UpdateActorSnapshotTag:output_type -> ateapi.ActorSnapshotTag - 25, // 167: ateapi.Control.DeleteActorSnapshotTag:output_type -> ateapi.ActorSnapshotTag - 85, // 168: ateapi.Control.ListWorkers:output_type -> ateapi.ListWorkersResponse - 93, // 169: ateapi.Control.GetWorker:output_type -> ateapi.Worker - 93, // 170: ateapi.Control.CreateWorker:output_type -> ateapi.Worker - 93, // 171: ateapi.Control.UpdateWorker:output_type -> ateapi.Worker - 93, // 172: ateapi.Control.DeleteWorker:output_type -> ateapi.Worker - 93, // 173: ateapi.Control.DrainWorker:output_type -> ateapi.Worker - 92, // 174: ateapi.Control.ListActors:output_type -> ateapi.ListActorsResponse - 26, // 175: ateapi.Control.CreateAtespace:output_type -> ateapi.Atespace - 26, // 176: ateapi.Control.GetAtespace:output_type -> ateapi.Atespace - 55, // 177: ateapi.Control.ListAtespaces:output_type -> ateapi.ListAtespacesResponse - 26, // 178: ateapi.Control.DeleteAtespace:output_type -> ateapi.Atespace - 28, // 179: ateapi.Control.CreateActorTemplate:output_type -> ateapi.ActorTemplate - 28, // 180: ateapi.Control.GetActorTemplate:output_type -> ateapi.ActorTemplate - 60, // 181: ateapi.Control.ListActorTemplates:output_type -> ateapi.ListActorTemplatesResponse - 28, // 182: ateapi.Control.DeleteActorTemplate:output_type -> ateapi.ActorTemplate - 98, // 183: ateapi.ActorIdentity.MintJWT:output_type -> ateapi.MintJWTResponse - 100, // 184: ateapi.ActorIdentity.MintCert:output_type -> ateapi.MintCertResponse - 151, // [151:185] is the sub-list for method output_type - 117, // [117:151] is the sub-list for method input_type - 117, // [117:117] is the sub-list for extension type_name - 117, // [117:117] is the sub-list for extension extendee - 0, // [0:117] is the sub-list for field type_name + 28, // 1: ateapi.LocalSnapshotInfo.sandbox_config_ref:type_name -> ateapi.SandboxConfigRef + 102, // 2: ateapi.Selector.match_labels:type_name -> ateapi.Selector.MatchLabelsEntry + 105, // 3: ateapi.ResourceMetadata.create_time:type_name -> google.protobuf.Timestamp + 105, // 4: ateapi.ResourceMetadata.update_time:type_name -> google.protobuf.Timestamp + 8, // 5: ateapi.ExternalVolume.status:type_name -> ateapi.ExternalVolume.Status + 103, // 6: ateapi.ExternalVolume.volume_context:type_name -> ateapi.ExternalVolume.VolumeContextEntry + 11, // 7: ateapi.Actor.metadata:type_name -> ateapi.ResourceMetadata + 27, // 8: ateapi.Actor.actor_template:type_name -> ateapi.ObjectRef + 10, // 9: ateapi.Actor.worker_selector:type_name -> ateapi.Selector + 27, // 10: ateapi.Actor.source_snapshot_tag:type_name -> ateapi.ObjectRef + 20, // 11: ateapi.Actor.status:type_name -> ateapi.ActorStatus + 11, // 12: ateapi.EgressPolicy.metadata:type_name -> ateapi.ResourceMetadata + 15, // 13: ateapi.EgressPolicy.rules:type_name -> ateapi.EgressRule + 16, // 14: ateapi.EgressRule.hostnames:type_name -> ateapi.HostnameRule + 17, // 15: ateapi.EgressRule.ip_blocks:type_name -> ateapi.IPBlockRule + 106, // 16: ateapi.EgressRule.all:type_name -> google.protobuf.Empty + 18, // 17: ateapi.HostnameRule.effects:type_name -> ateapi.EgressRuleEffects + 19, // 18: ateapi.EgressRuleEffects.inject_static_headers:type_name -> ateapi.CredentialHeaderInjection + 2, // 19: ateapi.ActorStatus.state:type_name -> ateapi.ActorState + 22, // 20: ateapi.ActorStatus.worker_assignment:type_name -> ateapi.WorkerAssignment + 27, // 21: ateapi.ActorStatus.latest_snapshot:type_name -> ateapi.ObjectRef + 9, // 22: ateapi.ActorStatus.local_snapshot_info:type_name -> ateapi.LocalSnapshotInfo + 12, // 23: ateapi.ActorStatus.actor_volumes:type_name -> ateapi.ExternalVolume + 21, // 24: ateapi.ActorStatus.source_snapshot:type_name -> ateapi.ActorSourceSnapshotStatus + 27, // 25: ateapi.ActorStatus.current_actor_template:type_name -> ateapi.ObjectRef + 27, // 26: ateapi.ActorSourceSnapshotStatus.snapshot:type_name -> ateapi.ObjectRef + 27, // 27: ateapi.WorkerAssignment.worker:type_name -> ateapi.ObjectRef + 11, // 28: ateapi.ActorSnapshot.metadata:type_name -> ateapi.ResourceMetadata + 24, // 29: ateapi.ActorSnapshot.status:type_name -> ateapi.ActorSnapshotStatus + 27, // 30: ateapi.ActorSnapshotStatus.source_actor:type_name -> ateapi.ObjectRef + 0, // 31: ateapi.ActorSnapshotStatus.content_scope:type_name -> ateapi.SnapshotContentScope + 27, // 32: ateapi.ActorSnapshotStatus.actor_template:type_name -> ateapi.ObjectRef + 28, // 33: ateapi.ActorSnapshotStatus.sandbox_config_ref:type_name -> ateapi.SandboxConfigRef + 11, // 34: ateapi.ActorSnapshotTag.metadata:type_name -> ateapi.ResourceMetadata + 27, // 35: ateapi.ActorSnapshotTag.snapshot:type_name -> ateapi.ObjectRef + 1, // 36: ateapi.ActorSnapshotTag.scope:type_name -> ateapi.ActorSnapshotTagScope + 11, // 37: ateapi.Atespace.metadata:type_name -> ateapi.ResourceMetadata + 11, // 38: ateapi.ActorTemplate.metadata:type_name -> ateapi.ResourceMetadata + 10, // 39: ateapi.ActorTemplate.worker_selector:type_name -> ateapi.Selector + 37, // 40: ateapi.ActorTemplate.containers:type_name -> ateapi.Container + 43, // 41: ateapi.ActorTemplate.volumes:type_name -> ateapi.Volume + 35, // 42: ateapi.ActorTemplate.snapshots_config:type_name -> ateapi.SnapshotsConfig + 34, // 43: ateapi.ActorTemplate.sandbox_config:type_name -> ateapi.SandboxConfig + 30, // 44: ateapi.ActorTemplate.resources:type_name -> ateapi.Resources + 33, // 45: ateapi.ActorTemplate.status:type_name -> ateapi.ActorTemplateStatus + 31, // 46: ateapi.Resources.limits:type_name -> ateapi.Limits + 27, // 47: ateapi.GoldenSnapshotStatus.golden_snapshot:type_name -> ateapi.ObjectRef + 105, // 48: ateapi.GoldenSnapshotStatus.take_golden_snapshot_at:type_name -> google.protobuf.Timestamp + 32, // 49: ateapi.ActorTemplateStatus.golden_snapshot_status:type_name -> ateapi.GoldenSnapshotStatus + 3, // 50: ateapi.SandboxConfig.sandbox_class:type_name -> ateapi.SandboxClass + 0, // 51: ateapi.SnapshotsConfig.on_pause:type_name -> ateapi.SnapshotContentScope + 0, // 52: ateapi.SnapshotsConfig.on_commit:type_name -> ateapi.SnapshotContentScope + 36, // 53: ateapi.SnapshotsConfig.on_resume:type_name -> ateapi.OnResumeConfig + 4, // 54: ateapi.OnResumeConfig.from_data:type_name -> ateapi.ResumeSource + 40, // 55: ateapi.Container.env:type_name -> ateapi.EnvVar + 41, // 56: ateapi.Container.readyz:type_name -> ateapi.ContainerReadyz + 52, // 57: ateapi.Container.volume_mounts:type_name -> ateapi.VolumeMount + 38, // 58: ateapi.Container.security_context:type_name -> ateapi.SecurityContext + 30, // 59: ateapi.Container.resources:type_name -> ateapi.Resources + 39, // 60: ateapi.SecurityContext.capabilities:type_name -> ateapi.Capabilities + 42, // 61: ateapi.ContainerReadyz.http_get:type_name -> ateapi.HTTPGetAction + 45, // 62: ateapi.Volume.durable_dir:type_name -> ateapi.DurableDirVolumeSource + 46, // 63: ateapi.Volume.external_volume_template:type_name -> ateapi.ExternalVolumeTemplate + 47, // 64: ateapi.Volume.system_info:type_name -> ateapi.SystemInfoVolumeSource + 44, // 65: ateapi.Volume.image:type_name -> ateapi.ImageVolumeSource + 48, // 66: ateapi.SystemInfoVolumeSource.data_sources:type_name -> ateapi.SystemInfoDataSource + 49, // 67: ateapi.SystemInfoDataSource.actor_metadata:type_name -> ateapi.ActorMetadataDataSource + 51, // 68: ateapi.SystemInfoDataSource.trust_bundle:type_name -> ateapi.TrustBundleDataSource + 50, // 69: ateapi.ActorMetadataDataSource.items:type_name -> ateapi.ActorMetadataItem + 5, // 70: ateapi.ActorMetadataItem.field:type_name -> ateapi.ActorMetadataField + 26, // 71: ateapi.CreateAtespaceRequest.atespace:type_name -> ateapi.Atespace + 27, // 72: ateapi.GetAtespaceRequest.atespace:type_name -> ateapi.ObjectRef + 26, // 73: ateapi.ListAtespacesResponse.atespaces:type_name -> ateapi.Atespace + 27, // 74: ateapi.DeleteAtespaceRequest.atespace:type_name -> ateapi.ObjectRef + 29, // 75: ateapi.CreateActorTemplateRequest.actor_template:type_name -> ateapi.ActorTemplate + 27, // 76: ateapi.GetActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef + 29, // 77: ateapi.ListActorTemplatesResponse.actor_templates:type_name -> ateapi.ActorTemplate + 27, // 78: ateapi.DeleteActorTemplateRequest.actor_template:type_name -> ateapi.ObjectRef + 27, // 79: ateapi.GetActorRequest.actor:type_name -> ateapi.ObjectRef + 13, // 80: ateapi.CreateActorRequest.actor:type_name -> ateapi.Actor + 13, // 81: ateapi.UpdateActorRequest.actor:type_name -> ateapi.Actor + 27, // 82: ateapi.SuspendActorRequest.actor:type_name -> ateapi.ObjectRef + 13, // 83: ateapi.SuspendActorResponse.actor:type_name -> ateapi.Actor + 27, // 84: ateapi.PauseActorRequest.actor:type_name -> ateapi.ObjectRef + 13, // 85: ateapi.PauseActorResponse.actor:type_name -> ateapi.Actor + 27, // 86: ateapi.ResumeActorRequest.actor:type_name -> ateapi.ObjectRef + 13, // 87: ateapi.ResumeActorResponse.actor:type_name -> ateapi.Actor + 27, // 88: ateapi.DeleteActorRequest.actor:type_name -> ateapi.ObjectRef + 27, // 89: ateapi.GetActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 27, // 90: ateapi.CreateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 14, // 91: ateapi.CreateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy + 27, // 92: ateapi.UpdateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 14, // 93: ateapi.UpdateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy + 27, // 94: ateapi.DeleteActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 27, // 95: ateapi.GetActorSnapshotRequest.actor_snapshot:type_name -> ateapi.ObjectRef + 27, // 96: ateapi.GetActorSnapshotTagRequest.actor_snapshot_tag:type_name -> ateapi.ObjectRef + 23, // 97: ateapi.ListActorSnapshotsResponse.actor_snapshots:type_name -> ateapi.ActorSnapshot + 25, // 98: ateapi.CreateActorSnapshotTagRequest.actor_snapshot_tag:type_name -> ateapi.ActorSnapshotTag + 25, // 99: ateapi.UpdateActorSnapshotTagRequest.actor_snapshot_tag:type_name -> ateapi.ActorSnapshotTag + 27, // 100: ateapi.DeleteActorSnapshotTagRequest.actor_snapshot_tag:type_name -> ateapi.ObjectRef + 94, // 101: ateapi.ListWorkersResponse.workers:type_name -> ateapi.Worker + 27, // 102: ateapi.GetWorkerRequest.worker:type_name -> ateapi.ObjectRef + 94, // 103: ateapi.CreateWorkerRequest.worker:type_name -> ateapi.Worker + 94, // 104: ateapi.UpdateWorkerRequest.worker:type_name -> ateapi.Worker + 27, // 105: ateapi.DeleteWorkerRequest.worker:type_name -> ateapi.ObjectRef + 84, // 106: ateapi.DeleteWorkerRequest.options:type_name -> ateapi.DeleteOptions + 27, // 107: ateapi.DrainWorkerRequest.worker:type_name -> ateapi.ObjectRef + 13, // 108: ateapi.ListActorsResponse.actors:type_name -> ateapi.Actor + 11, // 109: ateapi.Worker.metadata:type_name -> ateapi.ResourceMetadata + 104, // 110: ateapi.Worker.labels:type_name -> ateapi.Worker.LabelsEntry + 96, // 111: ateapi.Worker.capacity:type_name -> ateapi.WorkerCapacity + 95, // 112: ateapi.Worker.status:type_name -> ateapi.WorkerStatus + 6, // 113: ateapi.WorkerStatus.state:type_name -> ateapi.WorkerState + 97, // 114: ateapi.WorkerStatus.assignment:type_name -> ateapi.ActorAssignment + 27, // 115: ateapi.ActorAssignment.actor:type_name -> ateapi.ObjectRef + 27, // 116: ateapi.ActorAssignment.actor_template_ref:type_name -> ateapi.ObjectRef + 27, // 117: ateapi.MintCertRequest.worker:type_name -> ateapi.ObjectRef + 7, // 118: ateapi.MintCertRequest.purpose:type_name -> ateapi.ActorCertificatePurpose + 63, // 119: ateapi.Control.GetActor:input_type -> ateapi.GetActorRequest + 64, // 120: ateapi.Control.CreateActor:input_type -> ateapi.CreateActorRequest + 65, // 121: ateapi.Control.UpdateActor:input_type -> ateapi.UpdateActorRequest + 66, // 122: ateapi.Control.SuspendActor:input_type -> ateapi.SuspendActorRequest + 68, // 123: ateapi.Control.PauseActor:input_type -> ateapi.PauseActorRequest + 70, // 124: ateapi.Control.ResumeActor:input_type -> ateapi.ResumeActorRequest + 72, // 125: ateapi.Control.DeleteActor:input_type -> ateapi.DeleteActorRequest + 73, // 126: ateapi.Control.GetActorEgressPolicy:input_type -> ateapi.GetActorEgressPolicyRequest + 74, // 127: ateapi.Control.CreateActorEgressPolicy:input_type -> ateapi.CreateActorEgressPolicyRequest + 75, // 128: ateapi.Control.UpdateActorEgressPolicy:input_type -> ateapi.UpdateActorEgressPolicyRequest + 76, // 129: ateapi.Control.DeleteActorEgressPolicy:input_type -> ateapi.DeleteActorEgressPolicyRequest + 77, // 130: ateapi.Control.GetActorSnapshot:input_type -> ateapi.GetActorSnapshotRequest + 78, // 131: ateapi.Control.GetActorSnapshotTag:input_type -> ateapi.GetActorSnapshotTagRequest + 79, // 132: ateapi.Control.ListActorSnapshots:input_type -> ateapi.ListActorSnapshotsRequest + 81, // 133: ateapi.Control.CreateActorSnapshotTag:input_type -> ateapi.CreateActorSnapshotTagRequest + 82, // 134: ateapi.Control.UpdateActorSnapshotTag:input_type -> ateapi.UpdateActorSnapshotTagRequest + 83, // 135: ateapi.Control.DeleteActorSnapshotTag:input_type -> ateapi.DeleteActorSnapshotTagRequest + 85, // 136: ateapi.Control.ListWorkers:input_type -> ateapi.ListWorkersRequest + 87, // 137: ateapi.Control.GetWorker:input_type -> ateapi.GetWorkerRequest + 88, // 138: ateapi.Control.CreateWorker:input_type -> ateapi.CreateWorkerRequest + 89, // 139: ateapi.Control.UpdateWorker:input_type -> ateapi.UpdateWorkerRequest + 90, // 140: ateapi.Control.DeleteWorker:input_type -> ateapi.DeleteWorkerRequest + 91, // 141: ateapi.Control.DrainWorker:input_type -> ateapi.DrainWorkerRequest + 92, // 142: ateapi.Control.ListActors:input_type -> ateapi.ListActorsRequest + 53, // 143: ateapi.Control.CreateAtespace:input_type -> ateapi.CreateAtespaceRequest + 54, // 144: ateapi.Control.GetAtespace:input_type -> ateapi.GetAtespaceRequest + 55, // 145: ateapi.Control.ListAtespaces:input_type -> ateapi.ListAtespacesRequest + 57, // 146: ateapi.Control.DeleteAtespace:input_type -> ateapi.DeleteAtespaceRequest + 58, // 147: ateapi.Control.CreateActorTemplate:input_type -> ateapi.CreateActorTemplateRequest + 59, // 148: ateapi.Control.GetActorTemplate:input_type -> ateapi.GetActorTemplateRequest + 60, // 149: ateapi.Control.ListActorTemplates:input_type -> ateapi.ListActorTemplatesRequest + 62, // 150: ateapi.Control.DeleteActorTemplate:input_type -> ateapi.DeleteActorTemplateRequest + 98, // 151: ateapi.ActorIdentity.MintJWT:input_type -> ateapi.MintJWTRequest + 100, // 152: ateapi.ActorIdentity.MintCert:input_type -> ateapi.MintCertRequest + 13, // 153: ateapi.Control.GetActor:output_type -> ateapi.Actor + 13, // 154: ateapi.Control.CreateActor:output_type -> ateapi.Actor + 13, // 155: ateapi.Control.UpdateActor:output_type -> ateapi.Actor + 67, // 156: ateapi.Control.SuspendActor:output_type -> ateapi.SuspendActorResponse + 69, // 157: ateapi.Control.PauseActor:output_type -> ateapi.PauseActorResponse + 71, // 158: ateapi.Control.ResumeActor:output_type -> ateapi.ResumeActorResponse + 13, // 159: ateapi.Control.DeleteActor:output_type -> ateapi.Actor + 14, // 160: ateapi.Control.GetActorEgressPolicy:output_type -> ateapi.EgressPolicy + 14, // 161: ateapi.Control.CreateActorEgressPolicy:output_type -> ateapi.EgressPolicy + 14, // 162: ateapi.Control.UpdateActorEgressPolicy:output_type -> ateapi.EgressPolicy + 14, // 163: ateapi.Control.DeleteActorEgressPolicy:output_type -> ateapi.EgressPolicy + 23, // 164: ateapi.Control.GetActorSnapshot:output_type -> ateapi.ActorSnapshot + 25, // 165: ateapi.Control.GetActorSnapshotTag:output_type -> ateapi.ActorSnapshotTag + 80, // 166: ateapi.Control.ListActorSnapshots:output_type -> ateapi.ListActorSnapshotsResponse + 25, // 167: ateapi.Control.CreateActorSnapshotTag:output_type -> ateapi.ActorSnapshotTag + 25, // 168: ateapi.Control.UpdateActorSnapshotTag:output_type -> ateapi.ActorSnapshotTag + 25, // 169: ateapi.Control.DeleteActorSnapshotTag:output_type -> ateapi.ActorSnapshotTag + 86, // 170: ateapi.Control.ListWorkers:output_type -> ateapi.ListWorkersResponse + 94, // 171: ateapi.Control.GetWorker:output_type -> ateapi.Worker + 94, // 172: ateapi.Control.CreateWorker:output_type -> ateapi.Worker + 94, // 173: ateapi.Control.UpdateWorker:output_type -> ateapi.Worker + 94, // 174: ateapi.Control.DeleteWorker:output_type -> ateapi.Worker + 94, // 175: ateapi.Control.DrainWorker:output_type -> ateapi.Worker + 93, // 176: ateapi.Control.ListActors:output_type -> ateapi.ListActorsResponse + 26, // 177: ateapi.Control.CreateAtespace:output_type -> ateapi.Atespace + 26, // 178: ateapi.Control.GetAtespace:output_type -> ateapi.Atespace + 56, // 179: ateapi.Control.ListAtespaces:output_type -> ateapi.ListAtespacesResponse + 26, // 180: ateapi.Control.DeleteAtespace:output_type -> ateapi.Atespace + 29, // 181: ateapi.Control.CreateActorTemplate:output_type -> ateapi.ActorTemplate + 29, // 182: ateapi.Control.GetActorTemplate:output_type -> ateapi.ActorTemplate + 61, // 183: ateapi.Control.ListActorTemplates:output_type -> ateapi.ListActorTemplatesResponse + 29, // 184: ateapi.Control.DeleteActorTemplate:output_type -> ateapi.ActorTemplate + 99, // 185: ateapi.ActorIdentity.MintJWT:output_type -> ateapi.MintJWTResponse + 101, // 186: ateapi.ActorIdentity.MintCert:output_type -> ateapi.MintCertResponse + 153, // [153:187] is the sub-list for method output_type + 119, // [119:153] is the sub-list for method input_type + 119, // [119:119] is the sub-list for extension type_name + 119, // [119:119] is the sub-list for extension extendee + 0, // [0:119] is the sub-list for field type_name } func init() { file_ateapi_proto_init() } @@ -7309,7 +7418,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: 9, - NumMessages: 95, + NumMessages: 96, NumExtensions: 0, NumServices: 2, }, diff --git a/pkg/proto/ateapipb/ateapi.proto b/pkg/proto/ateapipb/ateapi.proto index ed94c0aac1..5783ef95af 100644 --- a/pkg/proto/ateapipb/ateapi.proto +++ b/pkg/proto/ateapipb/ateapi.proto @@ -152,6 +152,11 @@ message LocalSnapshotInfo { // +k8s:minimum=1 // +k8s:maximum=2 # keep this in sync with the SnapshotContentScope enum SnapshotContentScope content_scope = 3; + + // The SandboxConfig the paused activation was booted with. + // + // +k8s:optional + SandboxConfigRef sandbox_config_ref = 4; } enum SnapshotContentScope { @@ -667,6 +672,12 @@ message ActorSnapshotStatus { // Immutable reference to the actor_template where the snapshot was created from. // +k8s:opaqueType ObjectRef actor_template = 9; + + // The SandboxConfig the snapshotted sandbox was booted from. A restore + // resolves it to send the sandbox assets to atelet. Unset on older + // snapshots. + // +k8s:optional + SandboxConfigRef sandbox_config_ref = 10; } // ActorSnapshotTag is an immutable, Atespace-owned alias and retention pin. @@ -709,6 +720,30 @@ message ObjectRef { string name = 2; } +// SandboxConfigRef references a cluster-scoped SandboxConfig Kubernetes +// object by name, UID, and resource version. The UID distinguishes an object +// from a later re-creation under the same name; the resource version pins the +// exact object version. +message SandboxConfigRef { + // The name of the referenced Kubernetes object. Required. + // + // +k8s:required + // +k8s:format=k8s-long-name + string name = 1; + + // The Kubernetes UID of the referenced object. Required. + // + // +k8s:required + // +k8s:format=k8s-uuid + string uid = 2; + + // resource_version is the object's metadata.resourceVersion at the time + // the control plane resolved the request from it. + // + // +k8s:required + string resource_version = 3; +} + // SandboxClass selects the sandbox runtime family. Snapshots are not portable // across classes. enum SandboxClass { From d411e2f3881092ee7622342432cff1dcf4570b67 Mon Sep 17 00:00:00 2001 From: zoezhao Date: Wed, 2 Sep 2026 17:30:33 -0700 Subject: [PATCH 2/3] atelet: exempt DATA restores from the manifest SandboxConfig cross-check A DATA restore cold-boots the guest from the template spec; no manifest's memory image resumes. After an actor is repointed at a template with a different SandboxConfig, the control plane rightly resolves the request's assets from the replacement template's golden snapshot, so they no longer match the reference recorded on the actor's own snapshot manifest and the defense-in-depth check rejected the resume with FailedPrecondition. Only enforce the cross-check when the guest actually resumes from a manifest's state (FULL and DATA_ON_GOLDEN restores). --- cmd/atelet/lifecycle_test.go | 12 ++++++++++++ cmd/atelet/main.go | 15 ++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/cmd/atelet/lifecycle_test.go b/cmd/atelet/lifecycle_test.go index 144d6b4b33..83f121e5cc 100644 --- a/cmd/atelet/lifecycle_test.go +++ b/cmd/atelet/lifecycle_test.go @@ -399,6 +399,18 @@ func TestRestoreSandboxAssetsSource(t *testing.T) { } }) + t.Run("manifest ref mismatch is allowed for a DATA restore", func(t *testing.T) { + // A DATA restore cold-boots the guest from the spec, so the request's + // assets may legitimately come from a different SandboxConfig than the + // snapshot's (a repointed actor). The mismatched manifest written by + // the previous subtest is still in place. + req := restoreReq(sandboxAssets) + req.Scope = ateletpb.SnapshotScope_SNAPSHOT_SCOPE_DATA + if _, err := s.Restore(ctx, req); err != nil { + t.Fatalf("Restore: %v", err) + } + }) + t.Run("old-format manifest assets are never read back", func(t *testing.T) { // An old-format manifest still carries the asset set, but the type no // longer declares those keys, so an asset-less request must still fail. diff --git a/cmd/atelet/main.go b/cmd/atelet/main.go index bd039aa8c8..b9e42c7ffc 100644 --- a/cmd/atelet/main.go +++ b/cmd/atelet/main.go @@ -1099,11 +1099,16 @@ func (s *AteomHerder) Restore(ctx context.Context, req *ateletpb.RestoreRequest) } // Defense in depth: the control plane resolved the request's assets from // the snapshot's recorded reference, so a mismatch here means it resolved - // a different SandboxConfig object. - if manRef := guestMan.SandboxConfigRef; manRef != nil && manRef.UID != "" && manRef.UID != runtimeRec.SandboxConfigRef.UID { - return nil, status.Errorf(codes.FailedPrecondition, - "snapshot manifest records SandboxConfig %s (uid %s) but the request's assets come from %s (uid %s)", - manRef.Name, manRef.UID, runtimeRec.SandboxConfigRef.Name, runtimeRec.SandboxConfigRef.UID) + // a different SandboxConfig object. A DATA restore is exempt: the guest + // cold-boots from the spec rather than resuming any manifest's memory + // image (e.g. after a repoint at a template with a different config), so + // the snapshot's recorded config does not constrain the request. + if req.GetScope() != ateletpb.SnapshotScope_SNAPSHOT_SCOPE_DATA { + if manRef := guestMan.SandboxConfigRef; manRef != nil && manRef.UID != "" && manRef.UID != runtimeRec.SandboxConfigRef.UID { + return nil, status.Errorf(codes.FailedPrecondition, + "snapshot manifest records SandboxConfig %s (uid %s) but the request's assets come from %s (uid %s)", + manRef.Name, manRef.UID, runtimeRec.SandboxConfigRef.Name, runtimeRec.SandboxConfigRef.UID) + } } // Download the memory snapshot and prepare the sandbox assets + OCI bundle From ccb3ba6088d7edbea103f5b618881e9a5e7476c7 Mon Sep 17 00:00:00 2001 From: zoezhao Date: Wed, 2 Sep 2026 17:43:19 -0700 Subject: [PATCH 3/3] Pin restores to the recorded SandboxConfig revision The SandboxConfig reference stamped on snapshot records and manifests carried a resourceVersion that nothing consumed: an in-place update to a SandboxConfig (same UID, new revision) would silently resolve different binaries under a previously captured snapshot. Every resume path now holds the recorded reference to the exact object revision. resolveSandboxAssetsByRef fails with FailedPrecondition when the object's resourceVersion no longer matches the recorded one, just as it already did for a UID mismatch; atelet's non-DATA manifest cross-check likewise rejects a resourceVersion mismatch between the guest manifest's reference and the request's assets. A snapshot or golden recorded under a superseded revision fails resume loudly instead of booting binaries it was not captured with. resourceVersion is the only usable version signal: SandboxConfig has no status subresource, so metadata.generation never increments. --- .../internal/controlapi/sandbox_assets.go | 13 +++- .../controlapi/sandbox_assets_test.go | 15 ++-- .../internal/controlapi/workflow_resume.go | 46 +++++++----- .../controlapi/workflow_resume_test.go | 73 +++++++++++++++++++ cmd/atelet/lifecycle_test.go | 16 ++++ cmd/atelet/main.go | 18 ++++- 6 files changed, 148 insertions(+), 33 deletions(-) diff --git a/cmd/ateapi/internal/controlapi/sandbox_assets.go b/cmd/ateapi/internal/controlapi/sandbox_assets.go index 428be59683..ca4c47bf00 100644 --- a/cmd/ateapi/internal/controlapi/sandbox_assets.go +++ b/cmd/ateapi/internal/controlapi/sandbox_assets.go @@ -68,8 +68,11 @@ func resolveSandboxAssets( } // resolveSandboxAssetsByRef resolves an actor's recorded SandboxConfig -// reference. The UID must still match: an object re-created under the same -// name is a different config. +// reference. The object must still be exactly the recorded revision: a UID +// mismatch means it was re-created under the same name, a resourceVersion +// mismatch that it was updated in place — either way the binaries the +// snapshot recorded are gone, and it must not silently resolve different +// ones. func resolveSandboxAssetsByRef( sandboxConfigLister listersv1alpha1.SandboxConfigLister, ref *ateapipb.SandboxConfigRef, @@ -86,7 +89,11 @@ func resolveSandboxAssetsByRef( "actor records SandboxConfig %s with uid %s, but the object now has uid %s", ref.GetName(), ref.GetUid(), sc.UID) } - // TODO: we also need to get the correct revision or make sure the revision matches. + if sc.ResourceVersion != ref.GetResourceVersion() { + return nil, status.Errorf(codes.FailedPrecondition, + "actor records SandboxConfig %s at resourceVersion %s, but the object is now at %s", + ref.GetName(), ref.GetResourceVersion(), sc.ResourceVersion) + } class := sc.Spec.SandboxClass if class == "" { class = atev1alpha1.SandboxClassGvisor diff --git a/cmd/ateapi/internal/controlapi/sandbox_assets_test.go b/cmd/ateapi/internal/controlapi/sandbox_assets_test.go index 5c9593c258..d00f823145 100644 --- a/cmd/ateapi/internal/controlapi/sandbox_assets_test.go +++ b/cmd/ateapi/internal/controlapi/sandbox_assets_test.go @@ -133,11 +133,12 @@ func TestResolveSandboxAssetsCarriesConfigRef(t *testing.T) { } // TestResolveSandboxAssetsByRef pins that the named SandboxConfig is used -// only while its UID still matches; a missing or re-created object is a -// FailedPrecondition. +// only while it is exactly the recorded object revision; a missing, +// re-created, or in-place-updated object is a FailedPrecondition rather +// than silently resolving different binaries. func TestResolveSandboxAssetsByRef(t *testing.T) { config := &atev1alpha1.SandboxConfig{ - ObjectMeta: metav1.ObjectMeta{Name: "gvisor-prod", UID: "sandbox-uid-1"}, + ObjectMeta: metav1.ObjectMeta{Name: "gvisor-prod", UID: "sandbox-uid-1", ResourceVersion: "42"}, Spec: atev1alpha1.SandboxConfigSpec{ SandboxClass: atev1alpha1.SandboxClassGvisor, PauseImage: "registry.k8s.io/pause@sha256:abc", @@ -151,9 +152,11 @@ func TestResolveSandboxAssetsByRef(t *testing.T) { ref *ateapipb.SandboxConfigRef wantCode codes.Code }{ - {name: "match", ref: &ateapipb.SandboxConfigRef{Name: "gvisor-prod", Uid: "sandbox-uid-1"}, wantCode: codes.OK}, - {name: "object gone", ref: &ateapipb.SandboxConfigRef{Name: "gvisor-gone", Uid: "sandbox-uid-1"}, wantCode: codes.FailedPrecondition}, - {name: "uid mismatch (object recreated under the same name)", ref: &ateapipb.SandboxConfigRef{Name: "gvisor-prod", Uid: "sandbox-uid-0"}, wantCode: codes.FailedPrecondition}, + {name: "match", ref: &ateapipb.SandboxConfigRef{Name: "gvisor-prod", Uid: "sandbox-uid-1", ResourceVersion: "42"}, wantCode: codes.OK}, + {name: "object gone", ref: &ateapipb.SandboxConfigRef{Name: "gvisor-gone", Uid: "sandbox-uid-1", ResourceVersion: "42"}, wantCode: codes.FailedPrecondition}, + {name: "uid mismatch (object recreated under the same name)", ref: &ateapipb.SandboxConfigRef{Name: "gvisor-prod", Uid: "sandbox-uid-0", ResourceVersion: "42"}, wantCode: codes.FailedPrecondition}, + {name: "revision mismatch (object updated in place)", ref: &ateapipb.SandboxConfigRef{Name: "gvisor-prod", Uid: "sandbox-uid-1", ResourceVersion: "41"}, wantCode: codes.FailedPrecondition}, + {name: "ref recorded without a revision", ref: &ateapipb.SandboxConfigRef{Name: "gvisor-prod", Uid: "sandbox-uid-1"}, wantCode: codes.FailedPrecondition}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/cmd/ateapi/internal/controlapi/workflow_resume.go b/cmd/ateapi/internal/controlapi/workflow_resume.go index 931cb96cd9..1d78c63123 100644 --- a/cmd/ateapi/internal/controlapi/workflow_resume.go +++ b/cmd/ateapi/internal/controlapi/workflow_resume.go @@ -737,17 +737,9 @@ func (w *ActorWorkflow) ensureAteletRestored(ctx context.Context, actorRef resou req.Config = &ateletpb.RestoreRequest_LocalConfig{ LocalConfig: &ateletpb.LocalCheckpointConfiguration{SnapshotName: local.GetSnapshotName()}, } - // The wire scope describes the restore OPERATION: DATA_ON_GOLDEN when - // loadActorForResume resolved a golden URI per the template's onResume - // configuration, else what the pause captured. - switch { - case src.TemplateReplaced: - req.Scope = ateletpb.SnapshotScope_SNAPSHOT_SCOPE_DATA - case !src.GoldenSnapshotURI.IsZero(): - req.Scope = ateletpb.SnapshotScope_SNAPSHOT_SCOPE_DATA_ON_GOLDEN + req.Scope = resumeWireScope(actor, actorTemplate, src) + if req.Scope == ateletpb.SnapshotScope_SNAPSHOT_SCOPE_DATA_ON_GOLDEN { req.GoldenSnapshotUri = src.GoldenSnapshotURI.String() - default: - req.Scope = actorSnapshotContentScopeToAtelet(actorTemplate.GetSnapshotsConfig().GetOnPause()) } tele.WireSnapshotScope = ateattr.SnapshotScopeValue(req.Scope) @@ -761,17 +753,10 @@ func (w *ActorWorkflow) ensureAteletRestored(ctx context.Context, actorRef resou if actor.GetStatus().GetLatestSnapshot() != nil { tele.SnapshotKind = ateattr.SnapshotKindLatest } - // Same wire-scope derivation as the local branch above. - var scope ateletpb.SnapshotScope + scope := resumeWireScope(actor, actorTemplate, src) var goldenSnapshotURI string - switch { - case src.TemplateReplaced: - scope = ateletpb.SnapshotScope_SNAPSHOT_SCOPE_DATA - case !src.GoldenSnapshotURI.IsZero(): - scope = ateletpb.SnapshotScope_SNAPSHOT_SCOPE_DATA_ON_GOLDEN + if scope == ateletpb.SnapshotScope_SNAPSHOT_SCOPE_DATA_ON_GOLDEN { goldenSnapshotURI = src.GoldenSnapshotURI.String() - default: - scope = actorSnapshotContentScopeToAtelet(src.Scope) } tele.WireSnapshotScope = ateattr.SnapshotScopeValue(scope) req := &ateletpb.RestoreRequest{ @@ -826,7 +811,9 @@ func (w *ActorWorkflow) ensureAteletRestored(ctx context.Context, actorRef resou // the restored guest (the golden's for a DATA_ON_GOLDEN restore, the actor's // local or durable snapshot's otherwise). Boots from scratch, and snapshots // recorded before the reference existed, fall back to the assigned pool's -// SandboxConfig. +// SandboxConfig. The recorded config is pinned to its exact revision — the +// resolve fails rather than silently serving binaries the snapshot did not +// record. func (w *ActorWorkflow) resolveSandboxAssetsForResume(actor *ateapipb.Actor, src resumeSnapshotSource, poolNamespace, poolName string) (*ateletpb.SandboxAssets, error) { var ref *ateapipb.SandboxConfigRef switch { @@ -845,6 +832,25 @@ func (w *ActorWorkflow) resolveSandboxAssetsForResume(actor *ateapipb.Actor, src return resolveSandboxAssetsByRef(w.sandboxConfigLister, ref) } +// resumeWireScope derives the wire scope of the pending restore — the +// restore OPERATION, not the stored snapshot's scope: DATA when the actor +// was repointed (the guest cold-boots from the spec), DATA_ON_GOLDEN when +// loadActorForResume resolved a golden URI per the template's onResume +// configuration, else the scope the snapshot holds (what the pause captures +// for a local snapshot, the stored scope for a durable one). +func resumeWireScope(actor *ateapipb.Actor, actorTemplate *ateapipb.ActorTemplate, src resumeSnapshotSource) ateletpb.SnapshotScope { + switch { + case src.TemplateReplaced: + return ateletpb.SnapshotScope_SNAPSHOT_SCOPE_DATA + case !src.GoldenSnapshotURI.IsZero(): + return ateletpb.SnapshotScope_SNAPSHOT_SCOPE_DATA_ON_GOLDEN + case actor.GetStatus().GetLocalSnapshotInfo() != nil: + return actorSnapshotContentScopeToAtelet(actorTemplate.GetSnapshotsConfig().GetOnPause()) + default: + return actorSnapshotContentScopeToAtelet(src.Scope) + } +} + func (w *ActorWorkflow) egressGateway() *ateletpb.EgressGateway { if w.egressGatewayAddress == "" { return nil diff --git a/cmd/ateapi/internal/controlapi/workflow_resume_test.go b/cmd/ateapi/internal/controlapi/workflow_resume_test.go index b267391507..edaeec9142 100644 --- a/cmd/ateapi/internal/controlapi/workflow_resume_test.go +++ b/cmd/ateapi/internal/controlapi/workflow_resume_test.go @@ -1475,3 +1475,76 @@ func TestResolveSandboxAssetsForResume(t *testing.T) { }) } } + +// TestResolveSandboxAssetsForResumeExactRevision pins that every resume path +// holds the recorded SandboxConfig to its exact resourceVersion: a stale +// recorded revision is a FailedPrecondition instead of silently resolving +// binaries the snapshot did not record. +func TestResolveSandboxAssetsForResumeExactRevision(t *testing.T) { + config := &atev1alpha1.SandboxConfig{ + ObjectMeta: metav1.ObjectMeta{Name: "gvisor-prod", UID: "prod-uid", ResourceVersion: "43"}, + Spec: atev1alpha1.SandboxConfigSpec{ + SandboxClass: atev1alpha1.SandboxClassGvisor, + PauseImage: "registry.k8s.io/pause@sha256:prod", + Assets: testAssets(), + }, + } + pool := &atev1alpha1.WorkerPool{ObjectMeta: metav1.ObjectMeta{Name: "pool1", Namespace: "worker-ns"}} + poolLister, configLister := listersFor(t, []*atev1alpha1.WorkerPool{pool}, []*atev1alpha1.SandboxConfig{config}) + w := &ActorWorkflow{workerPoolLister: poolLister, sandboxConfigLister: configLister} + + // The object was updated in place since the snapshot recorded it. + staleRef := &ateapipb.SandboxConfigRef{Name: "gvisor-prod", Uid: "prod-uid", ResourceVersion: "42"} + currentRef := &ateapipb.SandboxConfigRef{Name: "gvisor-prod", Uid: "prod-uid", ResourceVersion: "43"} + goldenURI, err := resources.ParseSnapshotURI("gs://bucket/golden-root/snapshots/ate-golden/golden-1") + if err != nil { + t.Fatalf("ParseSnapshotURI: %v", err) + } + + tests := []struct { + name string + actor *ateapipb.Actor + src resumeSnapshotSource + wantCode codes.Code + }{ + { + name: "repointed actor pins the new golden's revision", + actor: &ateapipb.Actor{}, + src: resumeSnapshotSource{TemplateReplaced: true, RepointSandboxConfigRef: staleRef}, + wantCode: codes.FailedPrecondition, + }, + { + name: "golden data restore pins the golden's revision", + actor: &ateapipb.Actor{}, + src: resumeSnapshotSource{GoldenSnapshotURI: goldenURI, GoldenSandboxConfigRef: staleRef}, + wantCode: codes.FailedPrecondition, + }, + { + name: "local restore pins the pause snapshot's revision", + actor: &ateapipb.Actor{Status: &ateapipb.ActorStatus{ + LocalSnapshotInfo: &ateapipb.LocalSnapshotInfo{SandboxConfigRef: staleRef}, + }}, + wantCode: codes.FailedPrecondition, + }, + { + name: "durable restore pins the snapshot's revision", + actor: &ateapipb.Actor{}, + src: resumeSnapshotSource{SandboxConfigRef: staleRef}, + wantCode: codes.FailedPrecondition, + }, + { + name: "the recorded revision passes", + actor: &ateapipb.Actor{}, + src: resumeSnapshotSource{SandboxConfigRef: currentRef}, + wantCode: codes.OK, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + _, err := w.resolveSandboxAssetsForResume(tc.actor, tc.src, "worker-ns", "pool1") + if code := status.Code(err); code != tc.wantCode { + t.Fatalf("status.Code = %v (err %v), want %v", code, err, tc.wantCode) + } + }) + } +} diff --git a/cmd/atelet/lifecycle_test.go b/cmd/atelet/lifecycle_test.go index 83f121e5cc..1026a66fc0 100644 --- a/cmd/atelet/lifecycle_test.go +++ b/cmd/atelet/lifecycle_test.go @@ -386,6 +386,22 @@ func TestRestoreSandboxAssetsSource(t *testing.T) { } }) + t.Run("manifest revision mismatch is rejected", func(t *testing.T) { + // Same SandboxConfig object, updated in place since the checkpoint: + // the request's assets no longer describe the binaries the memory + // image was captured under. + man, err := unmarshalSandboxManifest(strippedManifest) + if err != nil { + t.Fatal(err) + } + man.SandboxConfigRef.ResourceVersion = "41" + writeManifest(t, man) + _, err = s.Restore(ctx, restoreReq(sandboxAssets)) + if got := status.Code(err); got != codes.FailedPrecondition { + t.Fatalf("status.Code = %v (err %v), want FailedPrecondition", got, err) + } + }) + t.Run("manifest ref mismatch is rejected", func(t *testing.T) { man, err := unmarshalSandboxManifest(strippedManifest) if err != nil { diff --git a/cmd/atelet/main.go b/cmd/atelet/main.go index b9e42c7ffc..1a266ca1f6 100644 --- a/cmd/atelet/main.go +++ b/cmd/atelet/main.go @@ -1104,10 +1104,20 @@ func (s *AteomHerder) Restore(ctx context.Context, req *ateletpb.RestoreRequest) // image (e.g. after a repoint at a template with a different config), so // the snapshot's recorded config does not constrain the request. if req.GetScope() != ateletpb.SnapshotScope_SNAPSHOT_SCOPE_DATA { - if manRef := guestMan.SandboxConfigRef; manRef != nil && manRef.UID != "" && manRef.UID != runtimeRec.SandboxConfigRef.UID { - return nil, status.Errorf(codes.FailedPrecondition, - "snapshot manifest records SandboxConfig %s (uid %s) but the request's assets come from %s (uid %s)", - manRef.Name, manRef.UID, runtimeRec.SandboxConfigRef.Name, runtimeRec.SandboxConfigRef.UID) + if manRef := guestMan.SandboxConfigRef; manRef != nil && manRef.UID != "" { + reqRef := runtimeRec.SandboxConfigRef + if manRef.UID != reqRef.UID { + return nil, status.Errorf(codes.FailedPrecondition, + "snapshot manifest records SandboxConfig %s (uid %s) but the request's assets come from %s (uid %s)", + manRef.Name, manRef.UID, reqRef.Name, reqRef.UID) + } + // Same object, different revision: an in-place update swapped the + // binaries under the memory image. + if manRef.ResourceVersion != reqRef.ResourceVersion { + return nil, status.Errorf(codes.FailedPrecondition, + "snapshot manifest records SandboxConfig %s at resourceVersion %s but the request's assets come from resourceVersion %s", + manRef.Name, manRef.ResourceVersion, reqRef.ResourceVersion) + } } }