From 1145d99bffab7c5884aba710aa5b15ae46f66e1e Mon Sep 17 00:00:00 2001 From: shrutiyam-glitch Date: Tue, 15 Sep 2026 17:10:36 -0700 Subject: [PATCH 01/14] Add RevertActor RPC --- benchmarking/locust/common/ateapi_pb2.py | 190 ++--- benchmarking/locust/common/ateapi_pb2_grpc.py | 45 ++ cmd/ateapi/internal/controlapi/actor_test.go | 2 +- .../controlapi/zz_generated.validation.go | 57 +- internal/ateattr/ateattr.go | 3 + internal/ateattr/ateattr_test.go | 2 + pkg/proto/ateapipb/ateapi.pb.go | 657 ++++++++++-------- pkg/proto/ateapipb/ateapi.proto | 17 +- pkg/proto/ateapipb/ateapi_grpc.pb.go | 42 ++ 9 files changed, 643 insertions(+), 372 deletions(-) diff --git a/benchmarking/locust/common/ateapi_pb2.py b/benchmarking/locust/common/ateapi_pb2.py index e0a6d66d74..aad58e7b42 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\"]\n\x10\x45xternalSnapshot\x12\x14\n\x0csnapshot_uri\x18\x01 \x01(\t\x12\x33\n\rcontent_scope\x18\x02 \x01(\x0e\x32\x1c.ateapi.SnapshotContentScope\"\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\"\xd5\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\nsource_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\"{\n\nEgressRule\x12\'\n\thostnames\x18\x01 \x01(\x0b\x32\x14.ateapi.HostnameRule\x12\x1f\n\x05\x63idrs\x18\x02 \x01(\x0b\x32\x10.ateapi.CIDRRule\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\"\x19\n\x08\x43IDRRule\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\"\xf1\x02\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\x33\n\x11\x65xternal_snapshot\x18\x04 \x01(\x0b\x32\x18.ateapi.ExternalSnapshot\x12\x36\n\x13local_snapshot_info\x18\x05 \x01(\x0b\x32\x19.ateapi.LocalSnapshotInfo\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\x1a\x63urrent_actor_template_uid\x18\x0b \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\"\x87\x01\n\tTagStatus\x12*\n\x08snapshot\x18\x01 \x01(\x0b\x32\x18.ateapi.ExternalSnapshot\x12\x1a\n\x12\x61\x63tor_template_uid\x18\x02 \x01(\t\x12\x18\n\x10storage_location\x18\x03 \x01(\t\x12\x18\n\x10source_actor_uid\x18\x04 \x01(\t\"\x9e\x01\n\x03Tag\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12!\n\x06status\x18\x02 \x01(\x0b\x32\x11.ateapi.TagStatus\x12\x1f\n\x05scope\x18\x03 \x01(\x0e\x32\x10.ateapi.TagScope\x12\'\n\x0csource_actor\x18\x04 \x01(\x0b\x32\x11.ateapi.ObjectRef\"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\"\x9d\x01\n\x14GoldenSnapshotStatus\x12\x31\n\x0fgolden_snapshot\x18\x01 \x01(\x0b\x32\x18.ateapi.ExternalSnapshot\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\"6\n\x12ResumeActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"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\"/\n\rGetTagRequest\x12\x1e\n\x03tag\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"\\\n\x13MintActorJWTRequest\x12 \n\x05\x61\x63tor\x18\x05 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x11\n\tactor_uid\x18\x07 \x01(\t\x12\x10\n\x08\x61udience\x18\x01 \x03(\t\")\n\x14MintActorJWTResponse\x12\x11\n\tactor_jwt\x18\x01 \x01(\t\"\xa9\x01\n\x1bMintActorCertificateRequest\x12 \n\x05\x61\x63tor\x18\x06 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x11\n\tactor_uid\x18\x07 \x01(\t\x12#\n\x1b\x63\x65rtificate_signing_request\x18\x02 \x01(\x0c\x12\x30\n\x07purpose\x18\x04 \x01(\x0e\x32\x1f.ateapi.ActorCertificatePurpose\":\n\x1cMintActorCertificateResponse\x12\x1a\n\x12\x61\x63tor_certificates\x18\x01 \x03(\x0c\"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\"J\n\x0fListTagsRequest\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\"F\n\x10ListTagsResponse\x12\x19\n\x04tags\x18\x01 \x03(\x0b\x32\x0b.ateapi.Tag\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\",\n\x10\x43reateTagRequest\x12\x18\n\x03tag\x18\x01 \x01(\x0b\x32\x0b.ateapi.Tag\",\n\x10UpdateTagRequest\x12\x18\n\x03tag\x18\x01 \x01(\x0b\x32\x0b.ateapi.Tag\"2\n\x10\x44\x65leteTagRequest\x12\x1e\n\x03tag\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\"m\n!ListWorkerActorAssignmentsRequest\x12!\n\x06worker\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x11\n\tpage_size\x18\x02 \x01(\x05\x12\x12\n\npage_token\x18\x03 \x01(\t\"q\n\"ListWorkerActorAssignmentsResponse\x12\x32\n\x11\x61\x63tor_assignments\x18\x01 \x03(\x0b\x32\x17.ateapi.ActorAssignment\x12\x17\n\x0fnext_page_token\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\"\xc6\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\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\"\x89\x01\n\x0cWorkerStatus\x12\"\n\x05state\x18\x01 \x01(\x0e\x32\x13.ateapi.WorkerState\x12)\n\x08\x63\x61pacity\x18\x02 \x01(\x0b\x32\x17.ateapi.WorkerResources\x12*\n\tallocated\x18\x03 \x01(\x0b\x32\x17.ateapi.WorkerResources\"G\n\x0fWorkerResources\x12$\n\tresources\x18\x01 \x01(\x0b\x32\x11.ateapi.Resources\x12\x0e\n\x06\x61\x63tors\x18\x02 \x01(\x05\"\xc7\x01\n\x0f\x41\x63torAssignment\x12*\n\x08metadata\x18\x06 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\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\x12$\n\tresources\x18\x05 \x01(\x0b\x32\x11.ateapi.Resources\"h\n\x18SetWorkerCapacityRequest\x12!\n\x06worker\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12)\n\x08\x63\x61pacity\x18\x02 \x01(\x0b\x32\x17.ateapi.WorkerResources\";\n\x19SetWorkerCapacityResponse\x12\x1e\n\x06worker\x18\x01 \x01(\x0b\x32\x0e.ateapi.Worker*\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*V\n\x08TagScope\x12\x19\n\x15TAG_SCOPE_UNSPECIFIED\x10\x00\x12\x16\n\x12TAG_SCOPE_ATESPACE\x10\x01\x12\x17\n\x13TAG_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*k\n\x17\x41\x63torCertificatePurpose\x12)\n%ACTOR_CERTIFICATE_PURPOSE_UNSPECIFIED\x10\x00\x12%\n!ACTOR_CERTIFICATE_PURPOSE_ATUNNEL\x10\x01*_\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\x32\xa5\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\x12K\n\x0cMintActorJWT\x12\x1b.ateapi.MintActorJWTRequest\x1a\x1c.ateapi.MintActorJWTResponse\"\x00\x12\x63\n\x14MintActorCertificate\x12#.ateapi.MintActorCertificateRequest\x1a$.ateapi.MintActorCertificateResponse\"\x00\x12\x34\n\tCreateTag\x12\x18.ateapi.CreateTagRequest\x1a\x0b.ateapi.Tag\"\x00\x12.\n\x06GetTag\x12\x15.ateapi.GetTagRequest\x1a\x0b.ateapi.Tag\"\x00\x12?\n\x08ListTags\x12\x17.ateapi.ListTagsRequest\x1a\x18.ateapi.ListTagsResponse\"\x00\x12\x34\n\tUpdateTag\x12\x18.ateapi.UpdateTagRequest\x1a\x0b.ateapi.Tag\"\x00\x12\x34\n\tDeleteTag\x12\x18.ateapi.DeleteTagRequest\x1a\x0b.ateapi.Tag\"\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\x12u\n\x1aListWorkerActorAssignments\x12).ateapi.ListWorkerActorAssignmentsRequest\x1a*.ateapi.ListWorkerActorAssignmentsResponse\"\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\x32i\n\rWorkerService\x12X\n\x11SetWorkerCapacity\x12 .ateapi.SetWorkerCapacityRequest\x1a!.ateapi.SetWorkerCapacityResponseB9Z7github.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\"]\n\x10\x45xternalSnapshot\x12\x14\n\x0csnapshot_uri\x18\x01 \x01(\t\x12\x33\n\rcontent_scope\x18\x02 \x01(\x0e\x32\x1c.ateapi.SnapshotContentScope\"\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\"\xd5\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\nsource_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\"{\n\nEgressRule\x12\'\n\thostnames\x18\x01 \x01(\x0b\x32\x14.ateapi.HostnameRule\x12\x1f\n\x05\x63idrs\x18\x02 \x01(\x0b\x32\x10.ateapi.CIDRRule\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\"\x19\n\x08\x43IDRRule\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\"\xf1\x02\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\x33\n\x11\x65xternal_snapshot\x18\x04 \x01(\x0b\x32\x18.ateapi.ExternalSnapshot\x12\x36\n\x13local_snapshot_info\x18\x05 \x01(\x0b\x32\x19.ateapi.LocalSnapshotInfo\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\x1a\x63urrent_actor_template_uid\x18\x0b \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\"\x87\x01\n\tTagStatus\x12*\n\x08snapshot\x18\x01 \x01(\x0b\x32\x18.ateapi.ExternalSnapshot\x12\x1a\n\x12\x61\x63tor_template_uid\x18\x02 \x01(\t\x12\x18\n\x10storage_location\x18\x03 \x01(\t\x12\x18\n\x10source_actor_uid\x18\x04 \x01(\t\"\x9e\x01\n\x03Tag\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12!\n\x06status\x18\x02 \x01(\x0b\x32\x11.ateapi.TagStatus\x12\x1f\n\x05scope\x18\x03 \x01(\x0e\x32\x10.ateapi.TagScope\x12\'\n\x0csource_actor\x18\x04 \x01(\x0b\x32\x11.ateapi.ObjectRef\"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\"\x9d\x01\n\x14GoldenSnapshotStatus\x12\x31\n\x0fgolden_snapshot\x18\x01 \x01(\x0b\x32\x18.ateapi.ExternalSnapshot\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\"6\n\x12ResumeActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"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\"6\n\x12RevertActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"3\n\x13RevertActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"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\"/\n\rGetTagRequest\x12\x1e\n\x03tag\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"\\\n\x13MintActorJWTRequest\x12 \n\x05\x61\x63tor\x18\x05 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x11\n\tactor_uid\x18\x07 \x01(\t\x12\x10\n\x08\x61udience\x18\x01 \x03(\t\")\n\x14MintActorJWTResponse\x12\x11\n\tactor_jwt\x18\x01 \x01(\t\"\xa9\x01\n\x1bMintActorCertificateRequest\x12 \n\x05\x61\x63tor\x18\x06 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x11\n\tactor_uid\x18\x07 \x01(\t\x12#\n\x1b\x63\x65rtificate_signing_request\x18\x02 \x01(\x0c\x12\x30\n\x07purpose\x18\x04 \x01(\x0e\x32\x1f.ateapi.ActorCertificatePurpose\":\n\x1cMintActorCertificateResponse\x12\x1a\n\x12\x61\x63tor_certificates\x18\x01 \x03(\x0c\"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\"J\n\x0fListTagsRequest\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\"F\n\x10ListTagsResponse\x12\x19\n\x04tags\x18\x01 \x03(\x0b\x32\x0b.ateapi.Tag\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\",\n\x10\x43reateTagRequest\x12\x18\n\x03tag\x18\x01 \x01(\x0b\x32\x0b.ateapi.Tag\",\n\x10UpdateTagRequest\x12\x18\n\x03tag\x18\x01 \x01(\x0b\x32\x0b.ateapi.Tag\"2\n\x10\x44\x65leteTagRequest\x12\x1e\n\x03tag\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\"m\n!ListWorkerActorAssignmentsRequest\x12!\n\x06worker\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x11\n\tpage_size\x18\x02 \x01(\x05\x12\x12\n\npage_token\x18\x03 \x01(\t\"q\n\"ListWorkerActorAssignmentsResponse\x12\x32\n\x11\x61\x63tor_assignments\x18\x01 \x03(\x0b\x32\x17.ateapi.ActorAssignment\x12\x17\n\x0fnext_page_token\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\"\xc6\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\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\"\x89\x01\n\x0cWorkerStatus\x12\"\n\x05state\x18\x01 \x01(\x0e\x32\x13.ateapi.WorkerState\x12)\n\x08\x63\x61pacity\x18\x02 \x01(\x0b\x32\x17.ateapi.WorkerResources\x12*\n\tallocated\x18\x03 \x01(\x0b\x32\x17.ateapi.WorkerResources\"G\n\x0fWorkerResources\x12$\n\tresources\x18\x01 \x01(\x0b\x32\x11.ateapi.Resources\x12\x0e\n\x06\x61\x63tors\x18\x02 \x01(\x05\"\xc7\x01\n\x0f\x41\x63torAssignment\x12*\n\x08metadata\x18\x06 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\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\x12$\n\tresources\x18\x05 \x01(\x0b\x32\x11.ateapi.Resources\"h\n\x18SetWorkerCapacityRequest\x12!\n\x06worker\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12)\n\x08\x63\x61pacity\x18\x02 \x01(\x0b\x32\x17.ateapi.WorkerResources\";\n\x19SetWorkerCapacityResponse\x12\x1e\n\x06worker\x18\x01 \x01(\x0b\x32\x0e.ateapi.Worker*\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*V\n\x08TagScope\x12\x19\n\x15TAG_SCOPE_UNSPECIFIED\x10\x00\x12\x16\n\x12TAG_SCOPE_ATESPACE\x10\x01\x12\x17\n\x13TAG_SCOPE_PUBLISHED\x10\x02*\x92\x02\n\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\x12\x19\n\x15\x41\x43TOR_STATE_REVERTING\x10\t*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*k\n\x17\x41\x63torCertificatePurpose\x12)\n%ACTOR_CERTIFICATE_PURPOSE_UNSPECIFIED\x10\x00\x12%\n!ACTOR_CERTIFICATE_PURPOSE_ATUNNEL\x10\x01*_\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\x32\xef\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\x12H\n\x0bRevertActor\x12\x1a.ateapi.RevertActorRequest\x1a\x1b.ateapi.RevertActorResponse\"\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\x12K\n\x0cMintActorJWT\x12\x1b.ateapi.MintActorJWTRequest\x1a\x1c.ateapi.MintActorJWTResponse\"\x00\x12\x63\n\x14MintActorCertificate\x12#.ateapi.MintActorCertificateRequest\x1a$.ateapi.MintActorCertificateResponse\"\x00\x12\x34\n\tCreateTag\x12\x18.ateapi.CreateTagRequest\x1a\x0b.ateapi.Tag\"\x00\x12.\n\x06GetTag\x12\x15.ateapi.GetTagRequest\x1a\x0b.ateapi.Tag\"\x00\x12?\n\x08ListTags\x12\x17.ateapi.ListTagsRequest\x1a\x18.ateapi.ListTagsResponse\"\x00\x12\x34\n\tUpdateTag\x12\x18.ateapi.UpdateTagRequest\x1a\x0b.ateapi.Tag\"\x00\x12\x34\n\tDeleteTag\x12\x18.ateapi.DeleteTagRequest\x1a\x0b.ateapi.Tag\"\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\x12u\n\x1aListWorkerActorAssignments\x12).ateapi.ListWorkerActorAssignmentsRequest\x1a*.ateapi.ListWorkerActorAssignmentsResponse\"\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\x32i\n\rWorkerService\x12X\n\x11SetWorkerCapacity\x12 .ateapi.SetWorkerCapacityRequest\x1a!.ateapi.SetWorkerCapacityResponseB9Z7github.com/agent-substrate/substrate/pkg/proto/ateapipbb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -54,22 +54,22 @@ _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=9371 - _globals['_SNAPSHOTCONTENTSCOPE']._serialized_end=9499 - _globals['_TAGSCOPE']._serialized_start=9501 - _globals['_TAGSCOPE']._serialized_end=9587 - _globals['_ACTORSTATE']._serialized_start=9590 - _globals['_ACTORSTATE']._serialized_end=9837 - _globals['_SANDBOXCLASS']._serialized_start=9839 - _globals['_SANDBOXCLASS']._serialized_end=9937 - _globals['_RESUMESOURCE']._serialized_start=9939 - _globals['_RESUMESOURCE']._serialized_end=10039 - _globals['_ACTORMETADATAFIELD']._serialized_start=10042 - _globals['_ACTORMETADATAFIELD']._serialized_end=10196 - _globals['_ACTORCERTIFICATEPURPOSE']._serialized_start=10198 - _globals['_ACTORCERTIFICATEPURPOSE']._serialized_end=10305 - _globals['_WORKERSTATE']._serialized_start=10307 - _globals['_WORKERSTATE']._serialized_end=10402 + _globals['_SNAPSHOTCONTENTSCOPE']._serialized_start=9480 + _globals['_SNAPSHOTCONTENTSCOPE']._serialized_end=9608 + _globals['_TAGSCOPE']._serialized_start=9610 + _globals['_TAGSCOPE']._serialized_end=9696 + _globals['_ACTORSTATE']._serialized_start=9699 + _globals['_ACTORSTATE']._serialized_end=9973 + _globals['_SANDBOXCLASS']._serialized_start=9975 + _globals['_SANDBOXCLASS']._serialized_end=10073 + _globals['_RESUMESOURCE']._serialized_start=10075 + _globals['_RESUMESOURCE']._serialized_end=10175 + _globals['_ACTORMETADATAFIELD']._serialized_start=10178 + _globals['_ACTORMETADATAFIELD']._serialized_end=10332 + _globals['_ACTORCERTIFICATEPURPOSE']._serialized_start=10334 + _globals['_ACTORCERTIFICATEPURPOSE']._serialized_end=10441 + _globals['_WORKERSTATE']._serialized_start=10443 + _globals['_WORKERSTATE']._serialized_end=10538 _globals['_EXTERNALSNAPSHOT']._serialized_start=86 _globals['_EXTERNALSNAPSHOT']._serialized_end=179 _globals['_LOCALSNAPSHOTINFO']._serialized_start=182 @@ -198,80 +198,84 @@ _globals['_RESUMEACTORREQUEST']._serialized_end=6205 _globals['_RESUMEACTORRESPONSE']._serialized_start=6207 _globals['_RESUMEACTORRESPONSE']._serialized_end=6275 - _globals['_DELETEACTORREQUEST']._serialized_start=6277 - _globals['_DELETEACTORREQUEST']._serialized_end=6350 - _globals['_GETACTOREGRESSPOLICYREQUEST']._serialized_start=6352 - _globals['_GETACTOREGRESSPOLICYREQUEST']._serialized_end=6415 - _globals['_CREATEACTOREGRESSPOLICYREQUEST']._serialized_start=6417 - _globals['_CREATEACTOREGRESSPOLICYREQUEST']._serialized_end=6528 - _globals['_UPDATEACTOREGRESSPOLICYREQUEST']._serialized_start=6530 - _globals['_UPDATEACTOREGRESSPOLICYREQUEST']._serialized_end=6641 - _globals['_DELETEACTOREGRESSPOLICYREQUEST']._serialized_start=6643 - _globals['_DELETEACTOREGRESSPOLICYREQUEST']._serialized_end=6709 - _globals['_GETTAGREQUEST']._serialized_start=6711 - _globals['_GETTAGREQUEST']._serialized_end=6758 - _globals['_MINTACTORJWTREQUEST']._serialized_start=6760 - _globals['_MINTACTORJWTREQUEST']._serialized_end=6852 - _globals['_MINTACTORJWTRESPONSE']._serialized_start=6854 - _globals['_MINTACTORJWTRESPONSE']._serialized_end=6895 - _globals['_MINTACTORCERTIFICATEREQUEST']._serialized_start=6898 - _globals['_MINTACTORCERTIFICATEREQUEST']._serialized_end=7067 - _globals['_MINTACTORCERTIFICATERESPONSE']._serialized_start=7069 - _globals['_MINTACTORCERTIFICATERESPONSE']._serialized_end=7127 - _globals['_GETACTORSNAPSHOTREQUEST']._serialized_start=7129 - _globals['_GETACTORSNAPSHOTREQUEST']._serialized_end=7197 - _globals['_GETACTORSNAPSHOTTAGREQUEST']._serialized_start=7199 - _globals['_GETACTORSNAPSHOTTAGREQUEST']._serialized_end=7274 - _globals['_LISTTAGSREQUEST']._serialized_start=7276 - _globals['_LISTTAGSREQUEST']._serialized_end=7350 - _globals['_LISTTAGSRESPONSE']._serialized_start=7352 - _globals['_LISTTAGSRESPONSE']._serialized_end=7422 - _globals['_CREATETAGREQUEST']._serialized_start=7424 - _globals['_CREATETAGREQUEST']._serialized_end=7468 - _globals['_UPDATETAGREQUEST']._serialized_start=7470 - _globals['_UPDATETAGREQUEST']._serialized_end=7514 - _globals['_DELETETAGREQUEST']._serialized_start=7516 - _globals['_DELETETAGREQUEST']._serialized_end=7566 - _globals['_DELETEOPTIONS']._serialized_start=7568 - _globals['_DELETEOPTIONS']._serialized_end=7613 - _globals['_LISTWORKERACTORASSIGNMENTSREQUEST']._serialized_start=7615 - _globals['_LISTWORKERACTORASSIGNMENTSREQUEST']._serialized_end=7724 - _globals['_LISTWORKERACTORASSIGNMENTSRESPONSE']._serialized_start=7726 - _globals['_LISTWORKERACTORASSIGNMENTSRESPONSE']._serialized_end=7839 - _globals['_LISTWORKERSREQUEST']._serialized_start=7841 - _globals['_LISTWORKERSREQUEST']._serialized_end=7900 - _globals['_LISTWORKERSRESPONSE']._serialized_start=7902 - _globals['_LISTWORKERSRESPONSE']._serialized_end=7981 - _globals['_GETWORKERREQUEST']._serialized_start=7983 - _globals['_GETWORKERREQUEST']._serialized_end=8036 - _globals['_CREATEWORKERREQUEST']._serialized_start=8038 - _globals['_CREATEWORKERREQUEST']._serialized_end=8091 - _globals['_UPDATEWORKERREQUEST']._serialized_start=8093 - _globals['_UPDATEWORKERREQUEST']._serialized_end=8146 - _globals['_DELETEWORKERREQUEST']._serialized_start=8148 - _globals['_DELETEWORKERREQUEST']._serialized_end=8244 - _globals['_DRAINWORKERREQUEST']._serialized_start=8246 - _globals['_DRAINWORKERREQUEST']._serialized_end=8301 - _globals['_LISTACTORSREQUEST']._serialized_start=8303 - _globals['_LISTACTORSREQUEST']._serialized_end=8379 - _globals['_LISTACTORSRESPONSE']._serialized_start=8381 - _globals['_LISTACTORSRESPONSE']._serialized_end=8457 - _globals['_WORKER']._serialized_start=8460 - _globals['_WORKER']._serialized_end=8786 - _globals['_WORKER_LABELSENTRY']._serialized_start=8741 - _globals['_WORKER_LABELSENTRY']._serialized_end=8786 - _globals['_WORKERSTATUS']._serialized_start=8789 - _globals['_WORKERSTATUS']._serialized_end=8926 - _globals['_WORKERRESOURCES']._serialized_start=8928 - _globals['_WORKERRESOURCES']._serialized_end=8999 - _globals['_ACTORASSIGNMENT']._serialized_start=9002 - _globals['_ACTORASSIGNMENT']._serialized_end=9201 - _globals['_SETWORKERCAPACITYREQUEST']._serialized_start=9203 - _globals['_SETWORKERCAPACITYREQUEST']._serialized_end=9307 - _globals['_SETWORKERCAPACITYRESPONSE']._serialized_start=9309 - _globals['_SETWORKERCAPACITYRESPONSE']._serialized_end=9368 - _globals['_CONTROL']._serialized_start=10405 - _globals['_CONTROL']._serialized_end=12874 - _globals['_WORKERSERVICE']._serialized_start=12876 - _globals['_WORKERSERVICE']._serialized_end=12981 + _globals['_REVERTACTORREQUEST']._serialized_start=6277 + _globals['_REVERTACTORREQUEST']._serialized_end=6331 + _globals['_REVERTACTORRESPONSE']._serialized_start=6333 + _globals['_REVERTACTORRESPONSE']._serialized_end=6384 + _globals['_DELETEACTORREQUEST']._serialized_start=6386 + _globals['_DELETEACTORREQUEST']._serialized_end=6459 + _globals['_GETACTOREGRESSPOLICYREQUEST']._serialized_start=6461 + _globals['_GETACTOREGRESSPOLICYREQUEST']._serialized_end=6524 + _globals['_CREATEACTOREGRESSPOLICYREQUEST']._serialized_start=6526 + _globals['_CREATEACTOREGRESSPOLICYREQUEST']._serialized_end=6637 + _globals['_UPDATEACTOREGRESSPOLICYREQUEST']._serialized_start=6639 + _globals['_UPDATEACTOREGRESSPOLICYREQUEST']._serialized_end=6750 + _globals['_DELETEACTOREGRESSPOLICYREQUEST']._serialized_start=6752 + _globals['_DELETEACTOREGRESSPOLICYREQUEST']._serialized_end=6818 + _globals['_GETTAGREQUEST']._serialized_start=6820 + _globals['_GETTAGREQUEST']._serialized_end=6867 + _globals['_MINTACTORJWTREQUEST']._serialized_start=6869 + _globals['_MINTACTORJWTREQUEST']._serialized_end=6961 + _globals['_MINTACTORJWTRESPONSE']._serialized_start=6963 + _globals['_MINTACTORJWTRESPONSE']._serialized_end=7004 + _globals['_MINTACTORCERTIFICATEREQUEST']._serialized_start=7007 + _globals['_MINTACTORCERTIFICATEREQUEST']._serialized_end=7176 + _globals['_MINTACTORCERTIFICATERESPONSE']._serialized_start=7178 + _globals['_MINTACTORCERTIFICATERESPONSE']._serialized_end=7236 + _globals['_GETACTORSNAPSHOTREQUEST']._serialized_start=7238 + _globals['_GETACTORSNAPSHOTREQUEST']._serialized_end=7306 + _globals['_GETACTORSNAPSHOTTAGREQUEST']._serialized_start=7308 + _globals['_GETACTORSNAPSHOTTAGREQUEST']._serialized_end=7383 + _globals['_LISTTAGSREQUEST']._serialized_start=7385 + _globals['_LISTTAGSREQUEST']._serialized_end=7459 + _globals['_LISTTAGSRESPONSE']._serialized_start=7461 + _globals['_LISTTAGSRESPONSE']._serialized_end=7531 + _globals['_CREATETAGREQUEST']._serialized_start=7533 + _globals['_CREATETAGREQUEST']._serialized_end=7577 + _globals['_UPDATETAGREQUEST']._serialized_start=7579 + _globals['_UPDATETAGREQUEST']._serialized_end=7623 + _globals['_DELETETAGREQUEST']._serialized_start=7625 + _globals['_DELETETAGREQUEST']._serialized_end=7675 + _globals['_DELETEOPTIONS']._serialized_start=7677 + _globals['_DELETEOPTIONS']._serialized_end=7722 + _globals['_LISTWORKERACTORASSIGNMENTSREQUEST']._serialized_start=7724 + _globals['_LISTWORKERACTORASSIGNMENTSREQUEST']._serialized_end=7833 + _globals['_LISTWORKERACTORASSIGNMENTSRESPONSE']._serialized_start=7835 + _globals['_LISTWORKERACTORASSIGNMENTSRESPONSE']._serialized_end=7948 + _globals['_LISTWORKERSREQUEST']._serialized_start=7950 + _globals['_LISTWORKERSREQUEST']._serialized_end=8009 + _globals['_LISTWORKERSRESPONSE']._serialized_start=8011 + _globals['_LISTWORKERSRESPONSE']._serialized_end=8090 + _globals['_GETWORKERREQUEST']._serialized_start=8092 + _globals['_GETWORKERREQUEST']._serialized_end=8145 + _globals['_CREATEWORKERREQUEST']._serialized_start=8147 + _globals['_CREATEWORKERREQUEST']._serialized_end=8200 + _globals['_UPDATEWORKERREQUEST']._serialized_start=8202 + _globals['_UPDATEWORKERREQUEST']._serialized_end=8255 + _globals['_DELETEWORKERREQUEST']._serialized_start=8257 + _globals['_DELETEWORKERREQUEST']._serialized_end=8353 + _globals['_DRAINWORKERREQUEST']._serialized_start=8355 + _globals['_DRAINWORKERREQUEST']._serialized_end=8410 + _globals['_LISTACTORSREQUEST']._serialized_start=8412 + _globals['_LISTACTORSREQUEST']._serialized_end=8488 + _globals['_LISTACTORSRESPONSE']._serialized_start=8490 + _globals['_LISTACTORSRESPONSE']._serialized_end=8566 + _globals['_WORKER']._serialized_start=8569 + _globals['_WORKER']._serialized_end=8895 + _globals['_WORKER_LABELSENTRY']._serialized_start=8850 + _globals['_WORKER_LABELSENTRY']._serialized_end=8895 + _globals['_WORKERSTATUS']._serialized_start=8898 + _globals['_WORKERSTATUS']._serialized_end=9035 + _globals['_WORKERRESOURCES']._serialized_start=9037 + _globals['_WORKERRESOURCES']._serialized_end=9108 + _globals['_ACTORASSIGNMENT']._serialized_start=9111 + _globals['_ACTORASSIGNMENT']._serialized_end=9310 + _globals['_SETWORKERCAPACITYREQUEST']._serialized_start=9312 + _globals['_SETWORKERCAPACITYREQUEST']._serialized_end=9416 + _globals['_SETWORKERCAPACITYRESPONSE']._serialized_start=9418 + _globals['_SETWORKERCAPACITYRESPONSE']._serialized_end=9477 + _globals['_CONTROL']._serialized_start=10541 + _globals['_CONTROL']._serialized_end=13084 + _globals['_WORKERSERVICE']._serialized_start=13086 + _globals['_WORKERSERVICE']._serialized_end=13191 # @@protoc_insertion_point(module_scope) diff --git a/benchmarking/locust/common/ateapi_pb2_grpc.py b/benchmarking/locust/common/ateapi_pb2_grpc.py index 63d5cbb699..f1036aed1d 100644 --- a/benchmarking/locust/common/ateapi_pb2_grpc.py +++ b/benchmarking/locust/common/ateapi_pb2_grpc.py @@ -79,6 +79,11 @@ def __init__(self, channel): request_serializer=ateapi__pb2.ResumeActorRequest.SerializeToString, response_deserializer=ateapi__pb2.ResumeActorResponse.FromString, _registered_method=True) + self.RevertActor = channel.unary_unary( + '/ateapi.Control/RevertActor', + request_serializer=ateapi__pb2.RevertActorRequest.SerializeToString, + response_deserializer=ateapi__pb2.RevertActorResponse.FromString, + _registered_method=True) self.DeleteActor = channel.unary_unary( '/ateapi.Control/DeleteActor', request_serializer=ateapi__pb2.DeleteActorRequest.SerializeToString, @@ -269,6 +274,14 @@ def ResumeActor(self, request, context): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def RevertActor(self, request, context): + """Revert an actor to SUSPENDED state. + Only crashed, running or paused actors can be reverted. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def DeleteActor(self, request, context): """Delete an actor. Only suspended actors can be deleted. """ @@ -512,6 +525,11 @@ def add_ControlServicer_to_server(servicer, server): request_deserializer=ateapi__pb2.ResumeActorRequest.FromString, response_serializer=ateapi__pb2.ResumeActorResponse.SerializeToString, ), + 'RevertActor': grpc.unary_unary_rpc_method_handler( + servicer.RevertActor, + request_deserializer=ateapi__pb2.RevertActorRequest.FromString, + response_serializer=ateapi__pb2.RevertActorResponse.SerializeToString, + ), 'DeleteActor': grpc.unary_unary_rpc_method_handler( servicer.DeleteActor, request_deserializer=ateapi__pb2.DeleteActorRequest.FromString, @@ -826,6 +844,33 @@ def ResumeActor(request, metadata, _registered_method=True) + @staticmethod + def RevertActor(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/ateapi.Control/RevertActor', + ateapi__pb2.RevertActorRequest.SerializeToString, + ateapi__pb2.RevertActorResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + @staticmethod def DeleteActor(request, target, diff --git a/cmd/ateapi/internal/controlapi/actor_test.go b/cmd/ateapi/internal/controlapi/actor_test.go index de6a77705f..eaaea64a43 100644 --- a/cmd/ateapi/internal/controlapi/actor_test.go +++ b/cmd/ateapi/internal/controlapi/actor_test.go @@ -324,7 +324,7 @@ func TestValidateActorUpdate(t *testing.T) { }, { "just out of bounds actor.status.state", validInput(), - validOutput(withStatus(func(s *ateapipb.ActorStatus) { s.State = 9 })), + validOutput(withStatus(func(s *ateapipb.ActorStatus) { s.State = 10 })), field.ErrorList{field.Invalid(field.NewPath("status", "state"), nil, "").WithOrigin("maximum")}, }, { "invalid actor.status.state", diff --git a/cmd/ateapi/internal/controlapi/zz_generated.validation.go b/cmd/ateapi/internal/controlapi/zz_generated.validation.go index 5e55c7239f..80703987f8 100644 --- a/cmd/ateapi/internal/controlapi/zz_generated.validation.go +++ b/cmd/ateapi/internal/controlapi/zz_generated.validation.go @@ -413,7 +413,7 @@ func Validate_ActorStatus( if earlyReturn { return // do not proceed } - if e := validate.Maximum(ctx, op, fldPath, obj, oldObj, 8); len(e) != 0 { + if e := validate.Maximum(ctx, op, fldPath, obj, oldObj, 9); len(e) != 0 { errs = append(errs, e...) } if e := validate.Minimum(ctx, op, fldPath, obj, oldObj, 1); len(e) != 0 { @@ -5367,6 +5367,61 @@ func Validate_ResumeActorRequest( return errs } +// Validate_RevertActorRequest validates an instance of RevertActorRequest according +// to declarative validation rules in the API schema. +func Validate_RevertActorRequest( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *ateapipb.RevertActorRequest) (errs field.ErrorList) { + + { // field ateapipb.RevertActorRequest.Actor + fn := func( + fldPath *field.Path, + obj, oldObj *ateapipb.ObjectRef, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if ateDeepEqual(obj, oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.RequiredPointer(ctx, op, fldPath, obj, oldObj).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + func() { // cohort = "atespace" + earlyReturn := false + if e := validate.Subfield(ctx, op, fldPath, obj, oldObj, "atespace", + func(o *ateapipb.ObjectRef) *string { return &o.Atespace }, validate.DirectEqual, validate.RequiredValue).MarkShortCircuit(); len(e) != 0 { + errs = append(errs, e...) + earlyReturn = true + } + if e := validate.Subfield(ctx, op, fldPath, obj, oldObj, "atespace", + func(o *ateapipb.ObjectRef) *string { return &o.Atespace }, validate.DirectEqual, validate.OptionalValue).MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + }() + // call the type's validation function + errs = append(errs, Validate_ObjectRef(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *ateapipb.RevertActorRequest) *ateapipb.ObjectRef { + return oldObj.Actor + }) + errs = append(errs, fn(fldPath.Child("actor"), obj.Actor, oldVal, oldObj != nil)...) + } + + return errs +} + // Validate_SandboxConfig validates an instance of SandboxConfig according // to declarative validation rules in the API schema. func Validate_SandboxConfig( diff --git a/internal/ateattr/ateattr.go b/internal/ateattr/ateattr.go index e533ddb39c..82651f8af0 100644 --- a/internal/ateattr/ateattr.go +++ b/internal/ateattr/ateattr.go @@ -94,6 +94,7 @@ const ( ActorStatePaused = "paused" ActorStateCrashed = "crashed" ActorStateDeleting = "deleting" + ActorStateReverting = "reverting" ActorStateDeleted = "deleted" ActorStateUnknown = "unknown" ) @@ -118,6 +119,8 @@ func ActorStateValue(state ateapipb.ActorState) string { return ActorStateCrashed case ateapipb.ActorState_ACTOR_STATE_DELETING: return ActorStateDeleting + case ateapipb.ActorState_ACTOR_STATE_REVERTING: + return ActorStateReverting default: return ActorStateUnknown } diff --git a/internal/ateattr/ateattr_test.go b/internal/ateattr/ateattr_test.go index e6257e61c5..274b4436fe 100644 --- a/internal/ateattr/ateattr_test.go +++ b/internal/ateattr/ateattr_test.go @@ -647,6 +647,7 @@ func TestActorStateValue(t *testing.T) { {name: "paused", state: ateapipb.ActorState_ACTOR_STATE_PAUSED, want: ActorStatePaused}, {name: "crashed", state: ateapipb.ActorState_ACTOR_STATE_CRASHED, want: ActorStateCrashed}, {name: "deleting", state: ateapipb.ActorState_ACTOR_STATE_DELETING, want: ActorStateDeleting}, + {name: "reverting", state: ateapipb.ActorState_ACTOR_STATE_REVERTING, want: ActorStateReverting}, {name: "unspecified", state: ateapipb.ActorState_ACTOR_STATE_UNSPECIFIED, want: ActorStateUnknown}, {name: "value outside the enum", state: ateapipb.ActorState(9999), want: ActorStateUnknown}, } @@ -680,6 +681,7 @@ func TestActorStateValuesMirrorActorState(t *testing.T) { ActorStatePaused: true, ActorStateCrashed: true, ActorStateDeleting: true, + ActorStateReverting: true, ActorStateDeleted: true, ActorStateUnknown: true, } diff --git a/pkg/proto/ateapipb/ateapi.pb.go b/pkg/proto/ateapipb/ateapi.pb.go index 3f012d15e4..7edb9c1e58 100644 --- a/pkg/proto/ateapipb/ateapi.pb.go +++ b/pkg/proto/ateapipb/ateapi.pb.go @@ -153,7 +153,8 @@ const ( ActorState_ACTOR_STATE_PAUSING ActorState = 5 ActorState_ACTOR_STATE_PAUSED ActorState = 6 ActorState_ACTOR_STATE_CRASHED ActorState = 7 - ActorState_ACTOR_STATE_DELETING ActorState = 8 // Keep this in sync with ActorStatus.state's maximum. + ActorState_ACTOR_STATE_DELETING ActorState = 8 + ActorState_ACTOR_STATE_REVERTING ActorState = 9 // Keep this in sync with ActorStatus.state's maximum. ) // Enum value maps for ActorState. @@ -168,6 +169,7 @@ var ( 6: "ACTOR_STATE_PAUSED", 7: "ACTOR_STATE_CRASHED", 8: "ACTOR_STATE_DELETING", + 9: "ACTOR_STATE_REVERTING", } ActorState_value = map[string]int32{ "ACTOR_STATE_UNSPECIFIED": 0, @@ -179,6 +181,7 @@ var ( "ACTOR_STATE_PAUSED": 6, "ACTOR_STATE_CRASHED": 7, "ACTOR_STATE_DELETING": 8, + "ACTOR_STATE_REVERTING": 9, } ) @@ -1482,7 +1485,7 @@ type ActorStatus struct { // // +k8s:required // +k8s:minimum=1 - // +k8s:maximum=8 # keep this in sync with the ActorState enum + // +k8s:maximum=9 # keep this in sync with the ActorState enum State ActorState `protobuf:"varint,1,opt,name=state,proto3,enum=ateapi.ActorState" json:"state,omitempty"` // worker_assignment points at the worker currently hosting this Actor. // Unset whenever the Actor has no worker (SUSPENDED, PAUSED, CRASHED). @@ -4625,6 +4628,96 @@ func (x *ResumeActorResponse) GetResumed() bool { return false } +type RevertActorRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + // +k8s:required + // +k8s:subfield(atespace)=+k8s:required + Actor *ObjectRef `protobuf:"bytes,1,opt,name=actor,proto3" json:"actor,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RevertActorRequest) Reset() { + *x = RevertActorRequest{} + mi := &file_ateapi_proto_msgTypes[61] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RevertActorRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RevertActorRequest) ProtoMessage() {} + +func (x *RevertActorRequest) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[61] + 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 RevertActorRequest.ProtoReflect.Descriptor instead. +func (*RevertActorRequest) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{61} +} + +func (x *RevertActorRequest) GetActor() *ObjectRef { + if x != nil { + return x.Actor + } + return nil +} + +type RevertActorResponse struct { + state protoimpl.MessageState `protogen:"open.v1"` + Actor *Actor `protobuf:"bytes,1,opt,name=actor,proto3" json:"actor,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *RevertActorResponse) Reset() { + *x = RevertActorResponse{} + mi := &file_ateapi_proto_msgTypes[62] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *RevertActorResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RevertActorResponse) ProtoMessage() {} + +func (x *RevertActorResponse) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[62] + 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 RevertActorResponse.ProtoReflect.Descriptor instead. +func (*RevertActorResponse) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{62} +} + +func (x *RevertActorResponse) GetActor() *Actor { + if x != nil { + return x.Actor + } + return nil +} + type DeleteActorRequest struct { state protoimpl.MessageState `protogen:"open.v1"` // +k8s:required @@ -4640,7 +4733,7 @@ type DeleteActorRequest struct { func (x *DeleteActorRequest) Reset() { *x = DeleteActorRequest{} - mi := &file_ateapi_proto_msgTypes[61] + mi := &file_ateapi_proto_msgTypes[63] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4652,7 +4745,7 @@ func (x *DeleteActorRequest) String() string { func (*DeleteActorRequest) ProtoMessage() {} func (x *DeleteActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[61] + mi := &file_ateapi_proto_msgTypes[63] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4665,7 +4758,7 @@ func (x *DeleteActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteActorRequest.ProtoReflect.Descriptor instead. func (*DeleteActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{61} + return file_ateapi_proto_rawDescGZIP(), []int{63} } func (x *DeleteActorRequest) GetActor() *ObjectRef { @@ -4696,7 +4789,7 @@ type GetActorEgressPolicyRequest struct { func (x *GetActorEgressPolicyRequest) Reset() { *x = GetActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[62] + mi := &file_ateapi_proto_msgTypes[64] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4708,7 +4801,7 @@ func (x *GetActorEgressPolicyRequest) String() string { func (*GetActorEgressPolicyRequest) ProtoMessage() {} func (x *GetActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[62] + mi := &file_ateapi_proto_msgTypes[64] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4721,7 +4814,7 @@ func (x *GetActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*GetActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{62} + return file_ateapi_proto_rawDescGZIP(), []int{64} } func (x *GetActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -4752,7 +4845,7 @@ type CreateActorEgressPolicyRequest struct { func (x *CreateActorEgressPolicyRequest) Reset() { *x = CreateActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[63] + mi := &file_ateapi_proto_msgTypes[65] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4764,7 +4857,7 @@ func (x *CreateActorEgressPolicyRequest) String() string { func (*CreateActorEgressPolicyRequest) ProtoMessage() {} func (x *CreateActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[63] + mi := &file_ateapi_proto_msgTypes[65] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4777,7 +4870,7 @@ func (x *CreateActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*CreateActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{63} + return file_ateapi_proto_rawDescGZIP(), []int{65} } func (x *CreateActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -4815,7 +4908,7 @@ type UpdateActorEgressPolicyRequest struct { func (x *UpdateActorEgressPolicyRequest) Reset() { *x = UpdateActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[64] + mi := &file_ateapi_proto_msgTypes[66] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4827,7 +4920,7 @@ func (x *UpdateActorEgressPolicyRequest) String() string { func (*UpdateActorEgressPolicyRequest) ProtoMessage() {} func (x *UpdateActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[64] + mi := &file_ateapi_proto_msgTypes[66] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4840,7 +4933,7 @@ func (x *UpdateActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*UpdateActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{64} + return file_ateapi_proto_rawDescGZIP(), []int{66} } func (x *UpdateActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -4871,7 +4964,7 @@ type DeleteActorEgressPolicyRequest struct { func (x *DeleteActorEgressPolicyRequest) Reset() { *x = DeleteActorEgressPolicyRequest{} - mi := &file_ateapi_proto_msgTypes[65] + mi := &file_ateapi_proto_msgTypes[67] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4883,7 +4976,7 @@ func (x *DeleteActorEgressPolicyRequest) String() string { func (*DeleteActorEgressPolicyRequest) ProtoMessage() {} func (x *DeleteActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[65] + mi := &file_ateapi_proto_msgTypes[67] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4896,7 +4989,7 @@ func (x *DeleteActorEgressPolicyRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteActorEgressPolicyRequest.ProtoReflect.Descriptor instead. func (*DeleteActorEgressPolicyRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{65} + return file_ateapi_proto_rawDescGZIP(), []int{67} } func (x *DeleteActorEgressPolicyRequest) GetActor() *ObjectRef { @@ -4917,7 +5010,7 @@ type GetTagRequest struct { func (x *GetTagRequest) Reset() { *x = GetTagRequest{} - mi := &file_ateapi_proto_msgTypes[66] + mi := &file_ateapi_proto_msgTypes[68] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4929,7 +5022,7 @@ func (x *GetTagRequest) String() string { func (*GetTagRequest) ProtoMessage() {} func (x *GetTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[66] + mi := &file_ateapi_proto_msgTypes[68] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -4942,7 +5035,7 @@ func (x *GetTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetTagRequest.ProtoReflect.Descriptor instead. func (*GetTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{66} + return file_ateapi_proto_rawDescGZIP(), []int{68} } func (x *GetTagRequest) GetTag() *ObjectRef { @@ -4981,7 +5074,7 @@ type MintActorJWTRequest struct { func (x *MintActorJWTRequest) Reset() { *x = MintActorJWTRequest{} - mi := &file_ateapi_proto_msgTypes[67] + mi := &file_ateapi_proto_msgTypes[69] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -4993,7 +5086,7 @@ func (x *MintActorJWTRequest) String() string { func (*MintActorJWTRequest) ProtoMessage() {} func (x *MintActorJWTRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[67] + mi := &file_ateapi_proto_msgTypes[69] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5006,7 +5099,7 @@ func (x *MintActorJWTRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorJWTRequest.ProtoReflect.Descriptor instead. func (*MintActorJWTRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{67} + return file_ateapi_proto_rawDescGZIP(), []int{69} } func (x *MintActorJWTRequest) GetActor() *ObjectRef { @@ -5061,7 +5154,7 @@ type MintActorJWTResponse struct { func (x *MintActorJWTResponse) Reset() { *x = MintActorJWTResponse{} - mi := &file_ateapi_proto_msgTypes[68] + mi := &file_ateapi_proto_msgTypes[70] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5073,7 +5166,7 @@ func (x *MintActorJWTResponse) String() string { func (*MintActorJWTResponse) ProtoMessage() {} func (x *MintActorJWTResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[68] + mi := &file_ateapi_proto_msgTypes[70] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5086,7 +5179,7 @@ func (x *MintActorJWTResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorJWTResponse.ProtoReflect.Descriptor instead. func (*MintActorJWTResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{68} + return file_ateapi_proto_rawDescGZIP(), []int{70} } func (x *MintActorJWTResponse) GetActorJwt() string { @@ -5131,7 +5224,7 @@ type MintActorCertificateRequest struct { func (x *MintActorCertificateRequest) Reset() { *x = MintActorCertificateRequest{} - mi := &file_ateapi_proto_msgTypes[69] + mi := &file_ateapi_proto_msgTypes[71] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5143,7 +5236,7 @@ func (x *MintActorCertificateRequest) String() string { func (*MintActorCertificateRequest) ProtoMessage() {} func (x *MintActorCertificateRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[69] + mi := &file_ateapi_proto_msgTypes[71] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5156,7 +5249,7 @@ func (x *MintActorCertificateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorCertificateRequest.ProtoReflect.Descriptor instead. func (*MintActorCertificateRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{69} + return file_ateapi_proto_rawDescGZIP(), []int{71} } func (x *MintActorCertificateRequest) GetActor() *ObjectRef { @@ -5200,7 +5293,7 @@ type MintActorCertificateResponse struct { func (x *MintActorCertificateResponse) Reset() { *x = MintActorCertificateResponse{} - mi := &file_ateapi_proto_msgTypes[70] + mi := &file_ateapi_proto_msgTypes[72] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5212,7 +5305,7 @@ func (x *MintActorCertificateResponse) String() string { func (*MintActorCertificateResponse) ProtoMessage() {} func (x *MintActorCertificateResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[70] + mi := &file_ateapi_proto_msgTypes[72] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5225,7 +5318,7 @@ func (x *MintActorCertificateResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MintActorCertificateResponse.ProtoReflect.Descriptor instead. func (*MintActorCertificateResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{70} + return file_ateapi_proto_rawDescGZIP(), []int{72} } func (x *MintActorCertificateResponse) GetActorCertificates() [][]byte { @@ -5245,7 +5338,7 @@ type GetActorSnapshotRequest struct { func (x *GetActorSnapshotRequest) Reset() { *x = GetActorSnapshotRequest{} - mi := &file_ateapi_proto_msgTypes[71] + mi := &file_ateapi_proto_msgTypes[73] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5257,7 +5350,7 @@ func (x *GetActorSnapshotRequest) String() string { func (*GetActorSnapshotRequest) ProtoMessage() {} func (x *GetActorSnapshotRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[71] + mi := &file_ateapi_proto_msgTypes[73] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5270,7 +5363,7 @@ func (x *GetActorSnapshotRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorSnapshotRequest.ProtoReflect.Descriptor instead. func (*GetActorSnapshotRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{71} + return file_ateapi_proto_rawDescGZIP(), []int{73} } func (x *GetActorSnapshotRequest) GetActorSnapshot() *ObjectRef { @@ -5290,7 +5383,7 @@ type GetActorSnapshotTagRequest struct { func (x *GetActorSnapshotTagRequest) Reset() { *x = GetActorSnapshotTagRequest{} - mi := &file_ateapi_proto_msgTypes[72] + mi := &file_ateapi_proto_msgTypes[74] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5302,7 +5395,7 @@ func (x *GetActorSnapshotTagRequest) String() string { func (*GetActorSnapshotTagRequest) ProtoMessage() {} func (x *GetActorSnapshotTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[72] + mi := &file_ateapi_proto_msgTypes[74] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5315,7 +5408,7 @@ func (x *GetActorSnapshotTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorSnapshotTagRequest.ProtoReflect.Descriptor instead. func (*GetActorSnapshotTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{72} + return file_ateapi_proto_rawDescGZIP(), []int{74} } func (x *GetActorSnapshotTagRequest) GetActorSnapshotTag() *ObjectRef { @@ -5351,7 +5444,7 @@ type ListTagsRequest struct { func (x *ListTagsRequest) Reset() { *x = ListTagsRequest{} - mi := &file_ateapi_proto_msgTypes[73] + mi := &file_ateapi_proto_msgTypes[75] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5363,7 +5456,7 @@ func (x *ListTagsRequest) String() string { func (*ListTagsRequest) ProtoMessage() {} func (x *ListTagsRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[73] + mi := &file_ateapi_proto_msgTypes[75] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5376,7 +5469,7 @@ func (x *ListTagsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListTagsRequest.ProtoReflect.Descriptor instead. func (*ListTagsRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{73} + return file_ateapi_proto_rawDescGZIP(), []int{75} } func (x *ListTagsRequest) GetAtespace() string { @@ -5410,7 +5503,7 @@ type ListTagsResponse struct { func (x *ListTagsResponse) Reset() { *x = ListTagsResponse{} - mi := &file_ateapi_proto_msgTypes[74] + mi := &file_ateapi_proto_msgTypes[76] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5422,7 +5515,7 @@ func (x *ListTagsResponse) String() string { func (*ListTagsResponse) ProtoMessage() {} func (x *ListTagsResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[74] + mi := &file_ateapi_proto_msgTypes[76] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5435,7 +5528,7 @@ func (x *ListTagsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListTagsResponse.ProtoReflect.Descriptor instead. func (*ListTagsResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{74} + return file_ateapi_proto_rawDescGZIP(), []int{76} } func (x *ListTagsResponse) GetTags() []*Tag { @@ -5480,7 +5573,7 @@ type CreateTagRequest struct { func (x *CreateTagRequest) Reset() { *x = CreateTagRequest{} - mi := &file_ateapi_proto_msgTypes[75] + mi := &file_ateapi_proto_msgTypes[77] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5492,7 +5585,7 @@ func (x *CreateTagRequest) String() string { func (*CreateTagRequest) ProtoMessage() {} func (x *CreateTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[75] + mi := &file_ateapi_proto_msgTypes[77] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5505,7 +5598,7 @@ func (x *CreateTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateTagRequest.ProtoReflect.Descriptor instead. func (*CreateTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{75} + return file_ateapi_proto_rawDescGZIP(), []int{77} } func (x *CreateTagRequest) GetTag() *Tag { @@ -5535,7 +5628,7 @@ type UpdateTagRequest struct { func (x *UpdateTagRequest) Reset() { *x = UpdateTagRequest{} - mi := &file_ateapi_proto_msgTypes[76] + mi := &file_ateapi_proto_msgTypes[78] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5547,7 +5640,7 @@ func (x *UpdateTagRequest) String() string { func (*UpdateTagRequest) ProtoMessage() {} func (x *UpdateTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[76] + mi := &file_ateapi_proto_msgTypes[78] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5560,7 +5653,7 @@ func (x *UpdateTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateTagRequest.ProtoReflect.Descriptor instead. func (*UpdateTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{76} + return file_ateapi_proto_rawDescGZIP(), []int{78} } func (x *UpdateTagRequest) GetTag() *Tag { @@ -5581,7 +5674,7 @@ type DeleteTagRequest struct { func (x *DeleteTagRequest) Reset() { *x = DeleteTagRequest{} - mi := &file_ateapi_proto_msgTypes[77] + mi := &file_ateapi_proto_msgTypes[79] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5593,7 +5686,7 @@ func (x *DeleteTagRequest) String() string { func (*DeleteTagRequest) ProtoMessage() {} func (x *DeleteTagRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[77] + mi := &file_ateapi_proto_msgTypes[79] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5606,7 +5699,7 @@ func (x *DeleteTagRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteTagRequest.ProtoReflect.Descriptor instead. func (*DeleteTagRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{77} + return file_ateapi_proto_rawDescGZIP(), []int{79} } func (x *DeleteTagRequest) GetTag() *ObjectRef { @@ -5642,7 +5735,7 @@ type DeleteOptions struct { func (x *DeleteOptions) Reset() { *x = DeleteOptions{} - mi := &file_ateapi_proto_msgTypes[78] + mi := &file_ateapi_proto_msgTypes[80] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5654,7 +5747,7 @@ func (x *DeleteOptions) String() string { func (*DeleteOptions) ProtoMessage() {} func (x *DeleteOptions) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[78] + mi := &file_ateapi_proto_msgTypes[80] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5667,7 +5760,7 @@ func (x *DeleteOptions) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteOptions.ProtoReflect.Descriptor instead. func (*DeleteOptions) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{78} + return file_ateapi_proto_rawDescGZIP(), []int{80} } func (x *DeleteOptions) GetVersion() int64 { @@ -5711,7 +5804,7 @@ type ListWorkerActorAssignmentsRequest struct { func (x *ListWorkerActorAssignmentsRequest) Reset() { *x = ListWorkerActorAssignmentsRequest{} - mi := &file_ateapi_proto_msgTypes[79] + mi := &file_ateapi_proto_msgTypes[81] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5723,7 +5816,7 @@ func (x *ListWorkerActorAssignmentsRequest) String() string { func (*ListWorkerActorAssignmentsRequest) ProtoMessage() {} func (x *ListWorkerActorAssignmentsRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[79] + mi := &file_ateapi_proto_msgTypes[81] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5736,7 +5829,7 @@ func (x *ListWorkerActorAssignmentsRequest) ProtoReflect() protoreflect.Message // Deprecated: Use ListWorkerActorAssignmentsRequest.ProtoReflect.Descriptor instead. func (*ListWorkerActorAssignmentsRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{79} + return file_ateapi_proto_rawDescGZIP(), []int{81} } func (x *ListWorkerActorAssignmentsRequest) GetWorker() *ObjectRef { @@ -5773,7 +5866,7 @@ type ListWorkerActorAssignmentsResponse struct { func (x *ListWorkerActorAssignmentsResponse) Reset() { *x = ListWorkerActorAssignmentsResponse{} - mi := &file_ateapi_proto_msgTypes[80] + mi := &file_ateapi_proto_msgTypes[82] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5785,7 +5878,7 @@ func (x *ListWorkerActorAssignmentsResponse) String() string { func (*ListWorkerActorAssignmentsResponse) ProtoMessage() {} func (x *ListWorkerActorAssignmentsResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[80] + mi := &file_ateapi_proto_msgTypes[82] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5798,7 +5891,7 @@ func (x *ListWorkerActorAssignmentsResponse) ProtoReflect() protoreflect.Message // Deprecated: Use ListWorkerActorAssignmentsResponse.ProtoReflect.Descriptor instead. func (*ListWorkerActorAssignmentsResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{80} + return file_ateapi_proto_rawDescGZIP(), []int{82} } func (x *ListWorkerActorAssignmentsResponse) GetActorAssignments() []*ActorAssignment { @@ -5836,7 +5929,7 @@ type ListWorkersRequest struct { func (x *ListWorkersRequest) Reset() { *x = ListWorkersRequest{} - mi := &file_ateapi_proto_msgTypes[81] + mi := &file_ateapi_proto_msgTypes[83] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5848,7 +5941,7 @@ func (x *ListWorkersRequest) String() string { func (*ListWorkersRequest) ProtoMessage() {} func (x *ListWorkersRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[81] + mi := &file_ateapi_proto_msgTypes[83] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5861,7 +5954,7 @@ func (x *ListWorkersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkersRequest.ProtoReflect.Descriptor instead. func (*ListWorkersRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{81} + return file_ateapi_proto_rawDescGZIP(), []int{83} } func (x *ListWorkersRequest) GetPageSize() int32 { @@ -5890,7 +5983,7 @@ type ListWorkersResponse struct { func (x *ListWorkersResponse) Reset() { *x = ListWorkersResponse{} - mi := &file_ateapi_proto_msgTypes[82] + mi := &file_ateapi_proto_msgTypes[84] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5902,7 +5995,7 @@ func (x *ListWorkersResponse) String() string { func (*ListWorkersResponse) ProtoMessage() {} func (x *ListWorkersResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[82] + mi := &file_ateapi_proto_msgTypes[84] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5915,7 +6008,7 @@ func (x *ListWorkersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkersResponse.ProtoReflect.Descriptor instead. func (*ListWorkersResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{82} + return file_ateapi_proto_rawDescGZIP(), []int{84} } func (x *ListWorkersResponse) GetWorkers() []*Worker { @@ -5945,7 +6038,7 @@ type GetWorkerRequest struct { func (x *GetWorkerRequest) Reset() { *x = GetWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[83] + mi := &file_ateapi_proto_msgTypes[85] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -5957,7 +6050,7 @@ func (x *GetWorkerRequest) String() string { func (*GetWorkerRequest) ProtoMessage() {} func (x *GetWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[83] + mi := &file_ateapi_proto_msgTypes[85] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -5970,7 +6063,7 @@ func (x *GetWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetWorkerRequest.ProtoReflect.Descriptor instead. func (*GetWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{83} + return file_ateapi_proto_rawDescGZIP(), []int{85} } func (x *GetWorkerRequest) GetWorker() *ObjectRef { @@ -5992,7 +6085,7 @@ type CreateWorkerRequest struct { func (x *CreateWorkerRequest) Reset() { *x = CreateWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[84] + mi := &file_ateapi_proto_msgTypes[86] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6004,7 +6097,7 @@ func (x *CreateWorkerRequest) String() string { func (*CreateWorkerRequest) ProtoMessage() {} func (x *CreateWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[84] + mi := &file_ateapi_proto_msgTypes[86] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6017,7 +6110,7 @@ func (x *CreateWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateWorkerRequest.ProtoReflect.Descriptor instead. func (*CreateWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{84} + return file_ateapi_proto_rawDescGZIP(), []int{86} } func (x *CreateWorkerRequest) GetWorker() *Worker { @@ -6052,7 +6145,7 @@ type UpdateWorkerRequest struct { func (x *UpdateWorkerRequest) Reset() { *x = UpdateWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[85] + mi := &file_ateapi_proto_msgTypes[87] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6064,7 +6157,7 @@ func (x *UpdateWorkerRequest) String() string { func (*UpdateWorkerRequest) ProtoMessage() {} func (x *UpdateWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[85] + mi := &file_ateapi_proto_msgTypes[87] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6077,7 +6170,7 @@ func (x *UpdateWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateWorkerRequest.ProtoReflect.Descriptor instead. func (*UpdateWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{85} + return file_ateapi_proto_rawDescGZIP(), []int{87} } func (x *UpdateWorkerRequest) GetWorker() *Worker { @@ -6104,7 +6197,7 @@ type DeleteWorkerRequest struct { func (x *DeleteWorkerRequest) Reset() { *x = DeleteWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[86] + mi := &file_ateapi_proto_msgTypes[88] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6116,7 +6209,7 @@ func (x *DeleteWorkerRequest) String() string { func (*DeleteWorkerRequest) ProtoMessage() {} func (x *DeleteWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[86] + mi := &file_ateapi_proto_msgTypes[88] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6129,7 +6222,7 @@ func (x *DeleteWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteWorkerRequest.ProtoReflect.Descriptor instead. func (*DeleteWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{86} + return file_ateapi_proto_rawDescGZIP(), []int{88} } func (x *DeleteWorkerRequest) GetWorker() *ObjectRef { @@ -6159,7 +6252,7 @@ type DrainWorkerRequest struct { func (x *DrainWorkerRequest) Reset() { *x = DrainWorkerRequest{} - mi := &file_ateapi_proto_msgTypes[87] + mi := &file_ateapi_proto_msgTypes[89] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6171,7 +6264,7 @@ func (x *DrainWorkerRequest) String() string { func (*DrainWorkerRequest) ProtoMessage() {} func (x *DrainWorkerRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[87] + mi := &file_ateapi_proto_msgTypes[89] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6184,7 +6277,7 @@ func (x *DrainWorkerRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DrainWorkerRequest.ProtoReflect.Descriptor instead. func (*DrainWorkerRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{87} + return file_ateapi_proto_rawDescGZIP(), []int{89} } func (x *DrainWorkerRequest) GetWorker() *ObjectRef { @@ -6222,7 +6315,7 @@ type ListActorsRequest struct { func (x *ListActorsRequest) Reset() { *x = ListActorsRequest{} - mi := &file_ateapi_proto_msgTypes[88] + mi := &file_ateapi_proto_msgTypes[90] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6234,7 +6327,7 @@ func (x *ListActorsRequest) String() string { func (*ListActorsRequest) ProtoMessage() {} func (x *ListActorsRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[88] + mi := &file_ateapi_proto_msgTypes[90] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6247,7 +6340,7 @@ func (x *ListActorsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorsRequest.ProtoReflect.Descriptor instead. func (*ListActorsRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{88} + return file_ateapi_proto_rawDescGZIP(), []int{90} } func (x *ListActorsRequest) GetAtespace() string { @@ -6283,7 +6376,7 @@ type ListActorsResponse struct { func (x *ListActorsResponse) Reset() { *x = ListActorsResponse{} - mi := &file_ateapi_proto_msgTypes[89] + mi := &file_ateapi_proto_msgTypes[91] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6295,7 +6388,7 @@ func (x *ListActorsResponse) String() string { func (*ListActorsResponse) ProtoMessage() {} func (x *ListActorsResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[89] + mi := &file_ateapi_proto_msgTypes[91] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6308,7 +6401,7 @@ func (x *ListActorsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorsResponse.ProtoReflect.Descriptor instead. func (*ListActorsResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{89} + return file_ateapi_proto_rawDescGZIP(), []int{91} } func (x *ListActorsResponse) GetActors() []*Actor { @@ -6398,7 +6491,7 @@ type Worker struct { func (x *Worker) Reset() { *x = Worker{} - mi := &file_ateapi_proto_msgTypes[90] + mi := &file_ateapi_proto_msgTypes[92] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6410,7 +6503,7 @@ func (x *Worker) String() string { func (*Worker) ProtoMessage() {} func (x *Worker) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[90] + mi := &file_ateapi_proto_msgTypes[92] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6423,7 +6516,7 @@ func (x *Worker) ProtoReflect() protoreflect.Message { // Deprecated: Use Worker.ProtoReflect.Descriptor instead. func (*Worker) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{90} + return file_ateapi_proto_rawDescGZIP(), []int{92} } func (x *Worker) GetMetadata() *ResourceMetadata { @@ -6525,7 +6618,7 @@ type WorkerStatus struct { func (x *WorkerStatus) Reset() { *x = WorkerStatus{} - mi := &file_ateapi_proto_msgTypes[91] + mi := &file_ateapi_proto_msgTypes[93] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6537,7 +6630,7 @@ func (x *WorkerStatus) String() string { func (*WorkerStatus) ProtoMessage() {} func (x *WorkerStatus) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[91] + mi := &file_ateapi_proto_msgTypes[93] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6550,7 +6643,7 @@ func (x *WorkerStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkerStatus.ProtoReflect.Descriptor instead. func (*WorkerStatus) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{91} + return file_ateapi_proto_rawDescGZIP(), []int{93} } func (x *WorkerStatus) GetState() WorkerState { @@ -6596,7 +6689,7 @@ type WorkerResources struct { func (x *WorkerResources) Reset() { *x = WorkerResources{} - mi := &file_ateapi_proto_msgTypes[92] + mi := &file_ateapi_proto_msgTypes[94] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6608,7 +6701,7 @@ func (x *WorkerResources) String() string { func (*WorkerResources) ProtoMessage() {} func (x *WorkerResources) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[92] + mi := &file_ateapi_proto_msgTypes[94] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6621,7 +6714,7 @@ func (x *WorkerResources) ProtoReflect() protoreflect.Message { // Deprecated: Use WorkerResources.ProtoReflect.Descriptor instead. func (*WorkerResources) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{92} + return file_ateapi_proto_rawDescGZIP(), []int{94} } func (x *WorkerResources) GetResources() *Resources { @@ -6675,7 +6768,7 @@ type ActorAssignment struct { func (x *ActorAssignment) Reset() { *x = ActorAssignment{} - mi := &file_ateapi_proto_msgTypes[93] + mi := &file_ateapi_proto_msgTypes[95] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6687,7 +6780,7 @@ func (x *ActorAssignment) String() string { func (*ActorAssignment) ProtoMessage() {} func (x *ActorAssignment) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[93] + mi := &file_ateapi_proto_msgTypes[95] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6700,7 +6793,7 @@ func (x *ActorAssignment) ProtoReflect() protoreflect.Message { // Deprecated: Use ActorAssignment.ProtoReflect.Descriptor instead. func (*ActorAssignment) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{93} + return file_ateapi_proto_rawDescGZIP(), []int{95} } func (x *ActorAssignment) GetMetadata() *ResourceMetadata { @@ -6758,7 +6851,7 @@ type SetWorkerCapacityRequest struct { func (x *SetWorkerCapacityRequest) Reset() { *x = SetWorkerCapacityRequest{} - mi := &file_ateapi_proto_msgTypes[94] + mi := &file_ateapi_proto_msgTypes[96] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6770,7 +6863,7 @@ func (x *SetWorkerCapacityRequest) String() string { func (*SetWorkerCapacityRequest) ProtoMessage() {} func (x *SetWorkerCapacityRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[94] + mi := &file_ateapi_proto_msgTypes[96] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6783,7 +6876,7 @@ func (x *SetWorkerCapacityRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SetWorkerCapacityRequest.ProtoReflect.Descriptor instead. func (*SetWorkerCapacityRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{94} + return file_ateapi_proto_rawDescGZIP(), []int{96} } func (x *SetWorkerCapacityRequest) GetWorker() *ObjectRef { @@ -6810,7 +6903,7 @@ type SetWorkerCapacityResponse struct { func (x *SetWorkerCapacityResponse) Reset() { *x = SetWorkerCapacityResponse{} - mi := &file_ateapi_proto_msgTypes[95] + mi := &file_ateapi_proto_msgTypes[97] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -6822,7 +6915,7 @@ func (x *SetWorkerCapacityResponse) String() string { func (*SetWorkerCapacityResponse) ProtoMessage() {} func (x *SetWorkerCapacityResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[95] + mi := &file_ateapi_proto_msgTypes[97] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -6835,7 +6928,7 @@ func (x *SetWorkerCapacityResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use SetWorkerCapacityResponse.ProtoReflect.Descriptor instead. func (*SetWorkerCapacityResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{95} + return file_ateapi_proto_rawDescGZIP(), []int{97} } func (x *SetWorkerCapacityResponse) GetWorker() *Worker { @@ -7079,7 +7172,11 @@ const file_ateapi_proto_rawDesc = "" + "\x05actor\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\x05actor\"T\n" + "\x13ResumeActorResponse\x12#\n" + "\x05actor\x18\x01 \x01(\v2\r.ateapi.ActorR\x05actor\x12\x18\n" + - "\aresumed\x18\x02 \x01(\bR\aresumed\"Z\n" + + "\aresumed\x18\x02 \x01(\bR\aresumed\"=\n" + + "\x12RevertActorRequest\x12'\n" + + "\x05actor\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\x05actor\":\n" + + "\x13RevertActorResponse\x12#\n" + + "\x05actor\x18\x01 \x01(\v2\r.ateapi.ActorR\x05actor\"Z\n" + "\x12DeleteActorRequest\x12'\n" + "\x05actor\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\x05actor\x12\x1b\n" + "\tany_state\x18\x02 \x01(\bR\banyState\"F\n" + @@ -7204,7 +7301,7 @@ const file_ateapi_proto_rawDesc = "" + "\bTagScope\x12\x19\n" + "\x15TAG_SCOPE_UNSPECIFIED\x10\x00\x12\x16\n" + "\x12TAG_SCOPE_ATESPACE\x10\x01\x12\x17\n" + - "\x13TAG_SCOPE_PUBLISHED\x10\x02*\xf7\x01\n" + + "\x13TAG_SCOPE_PUBLISHED\x10\x02*\x92\x02\n" + "\n" + "ActorState\x12\x1b\n" + "\x17ACTOR_STATE_UNSPECIFIED\x10\x00\x12\x18\n" + @@ -7215,7 +7312,8 @@ const file_ateapi_proto_rawDesc = "" + "\x13ACTOR_STATE_PAUSING\x10\x05\x12\x16\n" + "\x12ACTOR_STATE_PAUSED\x10\x06\x12\x17\n" + "\x13ACTOR_STATE_CRASHED\x10\a\x12\x18\n" + - "\x14ACTOR_STATE_DELETING\x10\b*b\n" + + "\x14ACTOR_STATE_DELETING\x10\b\x12\x19\n" + + "\x15ACTOR_STATE_REVERTING\x10\t*b\n" + "\fSandboxClass\x12\x1d\n" + "\x19SANDBOX_CLASS_UNSPECIFIED\x10\x00\x12\x18\n" + "\x14SANDBOX_CLASS_GVISOR\x10\x01\x12\x19\n" + @@ -7235,7 +7333,7 @@ const file_ateapi_proto_rawDesc = "" + "\vWorkerState\x12\x1c\n" + "\x18WORKER_STATE_UNSPECIFIED\x10\x00\x12\x17\n" + "\x13WORKER_STATE_ACTIVE\x10\x01\x12\x19\n" + - "\x15WORKER_STATE_DRAINING\x10\x022\xa5\x13\n" + + "\x15WORKER_STATE_DRAINING\x10\x022\xef\x13\n" + "\aControl\x124\n" + "\bGetActor\x12\x17.ateapi.GetActorRequest\x1a\r.ateapi.Actor\"\x00\x12:\n" + "\vCreateActor\x12\x1a.ateapi.CreateActorRequest\x1a\r.ateapi.Actor\"\x00\x12:\n" + @@ -7243,7 +7341,8 @@ const file_ateapi_proto_rawDesc = "" + "\fSuspendActor\x12\x1b.ateapi.SuspendActorRequest\x1a\x1c.ateapi.SuspendActorResponse\"\x00\x12E\n" + "\n" + "PauseActor\x12\x19.ateapi.PauseActorRequest\x1a\x1a.ateapi.PauseActorResponse\"\x00\x12H\n" + - "\vResumeActor\x12\x1a.ateapi.ResumeActorRequest\x1a\x1b.ateapi.ResumeActorResponse\"\x00\x12:\n" + + "\vResumeActor\x12\x1a.ateapi.ResumeActorRequest\x1a\x1b.ateapi.ResumeActorResponse\"\x00\x12H\n" + + "\vRevertActor\x12\x1a.ateapi.RevertActorRequest\x1a\x1b.ateapi.RevertActorResponse\"\x00\x12:\n" + "\vDeleteActor\x12\x1a.ateapi.DeleteActorRequest\x1a\r.ateapi.Actor\"\x00\x12S\n" + "\x14GetActorEgressPolicy\x12#.ateapi.GetActorEgressPolicyRequest\x1a\x14.ateapi.EgressPolicy\"\x00\x12Y\n" + "\x17CreateActorEgressPolicy\x12&.ateapi.CreateActorEgressPolicyRequest\x1a\x14.ateapi.EgressPolicy\"\x00\x12Y\n" + @@ -7289,7 +7388,7 @@ func file_ateapi_proto_rawDescGZIP() []byte { } var file_ateapi_proto_enumTypes = make([]protoimpl.EnumInfo, 9) -var file_ateapi_proto_msgTypes = make([]protoimpl.MessageInfo, 99) +var file_ateapi_proto_msgTypes = make([]protoimpl.MessageInfo, 101) var file_ateapi_proto_goTypes = []any{ (SnapshotContentScope)(0), // 0: ateapi.SnapshotContentScope (TagScope)(0), // 1: ateapi.TagScope @@ -7361,55 +7460,57 @@ var file_ateapi_proto_goTypes = []any{ (*PauseActorResponse)(nil), // 67: ateapi.PauseActorResponse (*ResumeActorRequest)(nil), // 68: ateapi.ResumeActorRequest (*ResumeActorResponse)(nil), // 69: ateapi.ResumeActorResponse - (*DeleteActorRequest)(nil), // 70: ateapi.DeleteActorRequest - (*GetActorEgressPolicyRequest)(nil), // 71: ateapi.GetActorEgressPolicyRequest - (*CreateActorEgressPolicyRequest)(nil), // 72: ateapi.CreateActorEgressPolicyRequest - (*UpdateActorEgressPolicyRequest)(nil), // 73: ateapi.UpdateActorEgressPolicyRequest - (*DeleteActorEgressPolicyRequest)(nil), // 74: ateapi.DeleteActorEgressPolicyRequest - (*GetTagRequest)(nil), // 75: ateapi.GetTagRequest - (*MintActorJWTRequest)(nil), // 76: ateapi.MintActorJWTRequest - (*MintActorJWTResponse)(nil), // 77: ateapi.MintActorJWTResponse - (*MintActorCertificateRequest)(nil), // 78: ateapi.MintActorCertificateRequest - (*MintActorCertificateResponse)(nil), // 79: ateapi.MintActorCertificateResponse - (*GetActorSnapshotRequest)(nil), // 80: ateapi.GetActorSnapshotRequest - (*GetActorSnapshotTagRequest)(nil), // 81: ateapi.GetActorSnapshotTagRequest - (*ListTagsRequest)(nil), // 82: ateapi.ListTagsRequest - (*ListTagsResponse)(nil), // 83: ateapi.ListTagsResponse - (*CreateTagRequest)(nil), // 84: ateapi.CreateTagRequest - (*UpdateTagRequest)(nil), // 85: ateapi.UpdateTagRequest - (*DeleteTagRequest)(nil), // 86: ateapi.DeleteTagRequest - (*DeleteOptions)(nil), // 87: ateapi.DeleteOptions - (*ListWorkerActorAssignmentsRequest)(nil), // 88: ateapi.ListWorkerActorAssignmentsRequest - (*ListWorkerActorAssignmentsResponse)(nil), // 89: ateapi.ListWorkerActorAssignmentsResponse - (*ListWorkersRequest)(nil), // 90: ateapi.ListWorkersRequest - (*ListWorkersResponse)(nil), // 91: ateapi.ListWorkersResponse - (*GetWorkerRequest)(nil), // 92: ateapi.GetWorkerRequest - (*CreateWorkerRequest)(nil), // 93: ateapi.CreateWorkerRequest - (*UpdateWorkerRequest)(nil), // 94: ateapi.UpdateWorkerRequest - (*DeleteWorkerRequest)(nil), // 95: ateapi.DeleteWorkerRequest - (*DrainWorkerRequest)(nil), // 96: ateapi.DrainWorkerRequest - (*ListActorsRequest)(nil), // 97: ateapi.ListActorsRequest - (*ListActorsResponse)(nil), // 98: ateapi.ListActorsResponse - (*Worker)(nil), // 99: ateapi.Worker - (*WorkerStatus)(nil), // 100: ateapi.WorkerStatus - (*WorkerResources)(nil), // 101: ateapi.WorkerResources - (*ActorAssignment)(nil), // 102: ateapi.ActorAssignment - (*SetWorkerCapacityRequest)(nil), // 103: ateapi.SetWorkerCapacityRequest - (*SetWorkerCapacityResponse)(nil), // 104: ateapi.SetWorkerCapacityResponse - nil, // 105: ateapi.Selector.MatchLabelsEntry - nil, // 106: ateapi.ExternalVolume.VolumeContextEntry - nil, // 107: ateapi.Worker.LabelsEntry - (*timestamppb.Timestamp)(nil), // 108: google.protobuf.Timestamp - (*emptypb.Empty)(nil), // 109: google.protobuf.Empty + (*RevertActorRequest)(nil), // 70: ateapi.RevertActorRequest + (*RevertActorResponse)(nil), // 71: ateapi.RevertActorResponse + (*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 + (*GetTagRequest)(nil), // 77: ateapi.GetTagRequest + (*MintActorJWTRequest)(nil), // 78: ateapi.MintActorJWTRequest + (*MintActorJWTResponse)(nil), // 79: ateapi.MintActorJWTResponse + (*MintActorCertificateRequest)(nil), // 80: ateapi.MintActorCertificateRequest + (*MintActorCertificateResponse)(nil), // 81: ateapi.MintActorCertificateResponse + (*GetActorSnapshotRequest)(nil), // 82: ateapi.GetActorSnapshotRequest + (*GetActorSnapshotTagRequest)(nil), // 83: ateapi.GetActorSnapshotTagRequest + (*ListTagsRequest)(nil), // 84: ateapi.ListTagsRequest + (*ListTagsResponse)(nil), // 85: ateapi.ListTagsResponse + (*CreateTagRequest)(nil), // 86: ateapi.CreateTagRequest + (*UpdateTagRequest)(nil), // 87: ateapi.UpdateTagRequest + (*DeleteTagRequest)(nil), // 88: ateapi.DeleteTagRequest + (*DeleteOptions)(nil), // 89: ateapi.DeleteOptions + (*ListWorkerActorAssignmentsRequest)(nil), // 90: ateapi.ListWorkerActorAssignmentsRequest + (*ListWorkerActorAssignmentsResponse)(nil), // 91: ateapi.ListWorkerActorAssignmentsResponse + (*ListWorkersRequest)(nil), // 92: ateapi.ListWorkersRequest + (*ListWorkersResponse)(nil), // 93: ateapi.ListWorkersResponse + (*GetWorkerRequest)(nil), // 94: ateapi.GetWorkerRequest + (*CreateWorkerRequest)(nil), // 95: ateapi.CreateWorkerRequest + (*UpdateWorkerRequest)(nil), // 96: ateapi.UpdateWorkerRequest + (*DeleteWorkerRequest)(nil), // 97: ateapi.DeleteWorkerRequest + (*DrainWorkerRequest)(nil), // 98: ateapi.DrainWorkerRequest + (*ListActorsRequest)(nil), // 99: ateapi.ListActorsRequest + (*ListActorsResponse)(nil), // 100: ateapi.ListActorsResponse + (*Worker)(nil), // 101: ateapi.Worker + (*WorkerStatus)(nil), // 102: ateapi.WorkerStatus + (*WorkerResources)(nil), // 103: ateapi.WorkerResources + (*ActorAssignment)(nil), // 104: ateapi.ActorAssignment + (*SetWorkerCapacityRequest)(nil), // 105: ateapi.SetWorkerCapacityRequest + (*SetWorkerCapacityResponse)(nil), // 106: ateapi.SetWorkerCapacityResponse + nil, // 107: ateapi.Selector.MatchLabelsEntry + nil, // 108: ateapi.ExternalVolume.VolumeContextEntry + nil, // 109: ateapi.Worker.LabelsEntry + (*timestamppb.Timestamp)(nil), // 110: google.protobuf.Timestamp + (*emptypb.Empty)(nil), // 111: google.protobuf.Empty } var file_ateapi_proto_depIdxs = []int32{ 0, // 0: ateapi.ExternalSnapshot.content_scope:type_name -> ateapi.SnapshotContentScope 0, // 1: ateapi.LocalSnapshotInfo.content_scope:type_name -> ateapi.SnapshotContentScope - 105, // 2: ateapi.Selector.match_labels:type_name -> ateapi.Selector.MatchLabelsEntry - 108, // 3: ateapi.ResourceMetadata.create_time:type_name -> google.protobuf.Timestamp - 108, // 4: ateapi.ResourceMetadata.update_time:type_name -> google.protobuf.Timestamp + 107, // 2: ateapi.Selector.match_labels:type_name -> ateapi.Selector.MatchLabelsEntry + 110, // 3: ateapi.ResourceMetadata.create_time:type_name -> google.protobuf.Timestamp + 110, // 4: ateapi.ResourceMetadata.update_time:type_name -> google.protobuf.Timestamp 8, // 5: ateapi.ExternalVolume.status:type_name -> ateapi.ExternalVolume.Status - 106, // 6: ateapi.ExternalVolume.volume_context:type_name -> ateapi.ExternalVolume.VolumeContextEntry + 108, // 6: ateapi.ExternalVolume.volume_context:type_name -> ateapi.ExternalVolume.VolumeContextEntry 12, // 7: ateapi.Actor.metadata:type_name -> ateapi.ResourceMetadata 26, // 8: ateapi.Actor.actor_template:type_name -> ateapi.ObjectRef 11, // 9: ateapi.Actor.worker_selector:type_name -> ateapi.Selector @@ -7419,7 +7520,7 @@ var file_ateapi_proto_depIdxs = []int32{ 16, // 13: ateapi.EgressPolicy.rules:type_name -> ateapi.EgressRule 17, // 14: ateapi.EgressRule.hostnames:type_name -> ateapi.HostnameRule 18, // 15: ateapi.EgressRule.cidrs:type_name -> ateapi.CIDRRule - 109, // 16: ateapi.EgressRule.all:type_name -> google.protobuf.Empty + 111, // 16: ateapi.EgressRule.all:type_name -> google.protobuf.Empty 19, // 17: ateapi.HostnameRule.effects:type_name -> ateapi.EgressRuleEffects 20, // 18: ateapi.EgressRuleEffects.inject_static_headers:type_name -> ateapi.CredentialHeaderInjection 2, // 19: ateapi.ActorStatus.state:type_name -> ateapi.ActorState @@ -7444,7 +7545,7 @@ var file_ateapi_proto_depIdxs = []int32{ 31, // 38: ateapi.ActorTemplate.status:type_name -> ateapi.ActorTemplateStatus 29, // 39: ateapi.Resources.limits:type_name -> ateapi.Limits 9, // 40: ateapi.GoldenSnapshotStatus.golden_snapshot:type_name -> ateapi.ExternalSnapshot - 108, // 41: ateapi.GoldenSnapshotStatus.take_golden_snapshot_at:type_name -> google.protobuf.Timestamp + 110, // 41: ateapi.GoldenSnapshotStatus.take_golden_snapshot_at:type_name -> google.protobuf.Timestamp 30, // 42: ateapi.ActorTemplateStatus.golden_snapshot_status:type_name -> ateapi.GoldenSnapshotStatus 3, // 43: ateapi.SandboxConfig.sandbox_class:type_name -> ateapi.SandboxClass 0, // 44: ateapi.SnapshotsConfig.on_pause:type_name -> ateapi.SnapshotContentScope @@ -7484,122 +7585,126 @@ var file_ateapi_proto_depIdxs = []int32{ 14, // 78: ateapi.PauseActorResponse.actor:type_name -> ateapi.Actor 26, // 79: ateapi.ResumeActorRequest.actor:type_name -> ateapi.ObjectRef 14, // 80: ateapi.ResumeActorResponse.actor:type_name -> ateapi.Actor - 26, // 81: ateapi.DeleteActorRequest.actor:type_name -> ateapi.ObjectRef - 26, // 82: ateapi.GetActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 26, // 83: ateapi.CreateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 15, // 84: ateapi.CreateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy - 26, // 85: ateapi.UpdateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 15, // 86: ateapi.UpdateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy - 26, // 87: ateapi.DeleteActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef - 26, // 88: ateapi.GetTagRequest.tag:type_name -> ateapi.ObjectRef - 26, // 89: ateapi.MintActorJWTRequest.actor:type_name -> ateapi.ObjectRef - 26, // 90: ateapi.MintActorCertificateRequest.actor:type_name -> ateapi.ObjectRef - 6, // 91: ateapi.MintActorCertificateRequest.purpose:type_name -> ateapi.ActorCertificatePurpose - 26, // 92: ateapi.GetActorSnapshotRequest.actor_snapshot:type_name -> ateapi.ObjectRef - 26, // 93: ateapi.GetActorSnapshotTagRequest.actor_snapshot_tag:type_name -> ateapi.ObjectRef - 24, // 94: ateapi.ListTagsResponse.tags:type_name -> ateapi.Tag - 24, // 95: ateapi.CreateTagRequest.tag:type_name -> ateapi.Tag - 24, // 96: ateapi.UpdateTagRequest.tag:type_name -> ateapi.Tag - 26, // 97: ateapi.DeleteTagRequest.tag:type_name -> ateapi.ObjectRef - 26, // 98: ateapi.ListWorkerActorAssignmentsRequest.worker:type_name -> ateapi.ObjectRef - 102, // 99: ateapi.ListWorkerActorAssignmentsResponse.actor_assignments:type_name -> ateapi.ActorAssignment - 99, // 100: ateapi.ListWorkersResponse.workers:type_name -> ateapi.Worker - 26, // 101: ateapi.GetWorkerRequest.worker:type_name -> ateapi.ObjectRef - 99, // 102: ateapi.CreateWorkerRequest.worker:type_name -> ateapi.Worker - 99, // 103: ateapi.UpdateWorkerRequest.worker:type_name -> ateapi.Worker - 26, // 104: ateapi.DeleteWorkerRequest.worker:type_name -> ateapi.ObjectRef - 87, // 105: ateapi.DeleteWorkerRequest.options:type_name -> ateapi.DeleteOptions - 26, // 106: ateapi.DrainWorkerRequest.worker:type_name -> ateapi.ObjectRef - 14, // 107: ateapi.ListActorsResponse.actors:type_name -> ateapi.Actor - 12, // 108: ateapi.Worker.metadata:type_name -> ateapi.ResourceMetadata - 107, // 109: ateapi.Worker.labels:type_name -> ateapi.Worker.LabelsEntry - 100, // 110: ateapi.Worker.status:type_name -> ateapi.WorkerStatus - 7, // 111: ateapi.WorkerStatus.state:type_name -> ateapi.WorkerState - 101, // 112: ateapi.WorkerStatus.capacity:type_name -> ateapi.WorkerResources - 101, // 113: ateapi.WorkerStatus.allocated:type_name -> ateapi.WorkerResources - 28, // 114: ateapi.WorkerResources.resources:type_name -> ateapi.Resources - 12, // 115: ateapi.ActorAssignment.metadata:type_name -> ateapi.ResourceMetadata - 26, // 116: ateapi.ActorAssignment.actor:type_name -> ateapi.ObjectRef - 26, // 117: ateapi.ActorAssignment.actor_template_ref:type_name -> ateapi.ObjectRef - 28, // 118: ateapi.ActorAssignment.resources:type_name -> ateapi.Resources - 26, // 119: ateapi.SetWorkerCapacityRequest.worker:type_name -> ateapi.ObjectRef - 101, // 120: ateapi.SetWorkerCapacityRequest.capacity:type_name -> ateapi.WorkerResources - 99, // 121: ateapi.SetWorkerCapacityResponse.worker:type_name -> ateapi.Worker - 61, // 122: ateapi.Control.GetActor:input_type -> ateapi.GetActorRequest - 62, // 123: ateapi.Control.CreateActor:input_type -> ateapi.CreateActorRequest - 63, // 124: ateapi.Control.UpdateActor:input_type -> ateapi.UpdateActorRequest - 64, // 125: ateapi.Control.SuspendActor:input_type -> ateapi.SuspendActorRequest - 66, // 126: ateapi.Control.PauseActor:input_type -> ateapi.PauseActorRequest - 68, // 127: ateapi.Control.ResumeActor:input_type -> ateapi.ResumeActorRequest - 70, // 128: ateapi.Control.DeleteActor:input_type -> ateapi.DeleteActorRequest - 71, // 129: ateapi.Control.GetActorEgressPolicy:input_type -> ateapi.GetActorEgressPolicyRequest - 72, // 130: ateapi.Control.CreateActorEgressPolicy:input_type -> ateapi.CreateActorEgressPolicyRequest - 73, // 131: ateapi.Control.UpdateActorEgressPolicy:input_type -> ateapi.UpdateActorEgressPolicyRequest - 74, // 132: ateapi.Control.DeleteActorEgressPolicy:input_type -> ateapi.DeleteActorEgressPolicyRequest - 76, // 133: ateapi.Control.MintActorJWT:input_type -> ateapi.MintActorJWTRequest - 78, // 134: ateapi.Control.MintActorCertificate:input_type -> ateapi.MintActorCertificateRequest - 84, // 135: ateapi.Control.CreateTag:input_type -> ateapi.CreateTagRequest - 75, // 136: ateapi.Control.GetTag:input_type -> ateapi.GetTagRequest - 82, // 137: ateapi.Control.ListTags:input_type -> ateapi.ListTagsRequest - 85, // 138: ateapi.Control.UpdateTag:input_type -> ateapi.UpdateTagRequest - 86, // 139: ateapi.Control.DeleteTag:input_type -> ateapi.DeleteTagRequest - 90, // 140: ateapi.Control.ListWorkers:input_type -> ateapi.ListWorkersRequest - 92, // 141: ateapi.Control.GetWorker:input_type -> ateapi.GetWorkerRequest - 93, // 142: ateapi.Control.CreateWorker:input_type -> ateapi.CreateWorkerRequest - 94, // 143: ateapi.Control.UpdateWorker:input_type -> ateapi.UpdateWorkerRequest - 95, // 144: ateapi.Control.DeleteWorker:input_type -> ateapi.DeleteWorkerRequest - 96, // 145: ateapi.Control.DrainWorker:input_type -> ateapi.DrainWorkerRequest - 88, // 146: ateapi.Control.ListWorkerActorAssignments:input_type -> ateapi.ListWorkerActorAssignmentsRequest - 97, // 147: ateapi.Control.ListActors:input_type -> ateapi.ListActorsRequest - 51, // 148: ateapi.Control.CreateAtespace:input_type -> ateapi.CreateAtespaceRequest - 52, // 149: ateapi.Control.GetAtespace:input_type -> ateapi.GetAtespaceRequest - 53, // 150: ateapi.Control.ListAtespaces:input_type -> ateapi.ListAtespacesRequest - 55, // 151: ateapi.Control.DeleteAtespace:input_type -> ateapi.DeleteAtespaceRequest - 56, // 152: ateapi.Control.CreateActorTemplate:input_type -> ateapi.CreateActorTemplateRequest - 57, // 153: ateapi.Control.GetActorTemplate:input_type -> ateapi.GetActorTemplateRequest - 58, // 154: ateapi.Control.ListActorTemplates:input_type -> ateapi.ListActorTemplatesRequest - 60, // 155: ateapi.Control.DeleteActorTemplate:input_type -> ateapi.DeleteActorTemplateRequest - 103, // 156: ateapi.WorkerService.SetWorkerCapacity:input_type -> ateapi.SetWorkerCapacityRequest - 14, // 157: ateapi.Control.GetActor:output_type -> ateapi.Actor - 14, // 158: ateapi.Control.CreateActor:output_type -> ateapi.Actor - 14, // 159: ateapi.Control.UpdateActor:output_type -> ateapi.Actor - 65, // 160: ateapi.Control.SuspendActor:output_type -> ateapi.SuspendActorResponse - 67, // 161: ateapi.Control.PauseActor:output_type -> ateapi.PauseActorResponse - 69, // 162: ateapi.Control.ResumeActor:output_type -> ateapi.ResumeActorResponse - 14, // 163: ateapi.Control.DeleteActor:output_type -> ateapi.Actor - 15, // 164: ateapi.Control.GetActorEgressPolicy:output_type -> ateapi.EgressPolicy - 15, // 165: ateapi.Control.CreateActorEgressPolicy:output_type -> ateapi.EgressPolicy - 15, // 166: ateapi.Control.UpdateActorEgressPolicy:output_type -> ateapi.EgressPolicy - 15, // 167: ateapi.Control.DeleteActorEgressPolicy:output_type -> ateapi.EgressPolicy - 77, // 168: ateapi.Control.MintActorJWT:output_type -> ateapi.MintActorJWTResponse - 79, // 169: ateapi.Control.MintActorCertificate:output_type -> ateapi.MintActorCertificateResponse - 24, // 170: ateapi.Control.CreateTag:output_type -> ateapi.Tag - 24, // 171: ateapi.Control.GetTag:output_type -> ateapi.Tag - 83, // 172: ateapi.Control.ListTags:output_type -> ateapi.ListTagsResponse - 24, // 173: ateapi.Control.UpdateTag:output_type -> ateapi.Tag - 24, // 174: ateapi.Control.DeleteTag:output_type -> ateapi.Tag - 91, // 175: ateapi.Control.ListWorkers:output_type -> ateapi.ListWorkersResponse - 99, // 176: ateapi.Control.GetWorker:output_type -> ateapi.Worker - 99, // 177: ateapi.Control.CreateWorker:output_type -> ateapi.Worker - 99, // 178: ateapi.Control.UpdateWorker:output_type -> ateapi.Worker - 99, // 179: ateapi.Control.DeleteWorker:output_type -> ateapi.Worker - 99, // 180: ateapi.Control.DrainWorker:output_type -> ateapi.Worker - 89, // 181: ateapi.Control.ListWorkerActorAssignments:output_type -> ateapi.ListWorkerActorAssignmentsResponse - 98, // 182: ateapi.Control.ListActors:output_type -> ateapi.ListActorsResponse - 25, // 183: ateapi.Control.CreateAtespace:output_type -> ateapi.Atespace - 25, // 184: ateapi.Control.GetAtespace:output_type -> ateapi.Atespace - 54, // 185: ateapi.Control.ListAtespaces:output_type -> ateapi.ListAtespacesResponse - 25, // 186: ateapi.Control.DeleteAtespace:output_type -> ateapi.Atespace - 27, // 187: ateapi.Control.CreateActorTemplate:output_type -> ateapi.ActorTemplate - 27, // 188: ateapi.Control.GetActorTemplate:output_type -> ateapi.ActorTemplate - 59, // 189: ateapi.Control.ListActorTemplates:output_type -> ateapi.ListActorTemplatesResponse - 27, // 190: ateapi.Control.DeleteActorTemplate:output_type -> ateapi.ActorTemplate - 104, // 191: ateapi.WorkerService.SetWorkerCapacity:output_type -> ateapi.SetWorkerCapacityResponse - 157, // [157:192] is the sub-list for method output_type - 122, // [122:157] is the sub-list for method input_type - 122, // [122:122] is the sub-list for extension type_name - 122, // [122:122] is the sub-list for extension extendee - 0, // [0:122] is the sub-list for field type_name + 26, // 81: ateapi.RevertActorRequest.actor:type_name -> ateapi.ObjectRef + 14, // 82: ateapi.RevertActorResponse.actor:type_name -> ateapi.Actor + 26, // 83: ateapi.DeleteActorRequest.actor:type_name -> ateapi.ObjectRef + 26, // 84: ateapi.GetActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 26, // 85: ateapi.CreateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 15, // 86: ateapi.CreateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy + 26, // 87: ateapi.UpdateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 15, // 88: ateapi.UpdateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy + 26, // 89: ateapi.DeleteActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef + 26, // 90: ateapi.GetTagRequest.tag:type_name -> ateapi.ObjectRef + 26, // 91: ateapi.MintActorJWTRequest.actor:type_name -> ateapi.ObjectRef + 26, // 92: ateapi.MintActorCertificateRequest.actor:type_name -> ateapi.ObjectRef + 6, // 93: ateapi.MintActorCertificateRequest.purpose:type_name -> ateapi.ActorCertificatePurpose + 26, // 94: ateapi.GetActorSnapshotRequest.actor_snapshot:type_name -> ateapi.ObjectRef + 26, // 95: ateapi.GetActorSnapshotTagRequest.actor_snapshot_tag:type_name -> ateapi.ObjectRef + 24, // 96: ateapi.ListTagsResponse.tags:type_name -> ateapi.Tag + 24, // 97: ateapi.CreateTagRequest.tag:type_name -> ateapi.Tag + 24, // 98: ateapi.UpdateTagRequest.tag:type_name -> ateapi.Tag + 26, // 99: ateapi.DeleteTagRequest.tag:type_name -> ateapi.ObjectRef + 26, // 100: ateapi.ListWorkerActorAssignmentsRequest.worker:type_name -> ateapi.ObjectRef + 104, // 101: ateapi.ListWorkerActorAssignmentsResponse.actor_assignments:type_name -> ateapi.ActorAssignment + 101, // 102: ateapi.ListWorkersResponse.workers:type_name -> ateapi.Worker + 26, // 103: ateapi.GetWorkerRequest.worker:type_name -> ateapi.ObjectRef + 101, // 104: ateapi.CreateWorkerRequest.worker:type_name -> ateapi.Worker + 101, // 105: ateapi.UpdateWorkerRequest.worker:type_name -> ateapi.Worker + 26, // 106: ateapi.DeleteWorkerRequest.worker:type_name -> ateapi.ObjectRef + 89, // 107: ateapi.DeleteWorkerRequest.options:type_name -> ateapi.DeleteOptions + 26, // 108: ateapi.DrainWorkerRequest.worker:type_name -> ateapi.ObjectRef + 14, // 109: ateapi.ListActorsResponse.actors:type_name -> ateapi.Actor + 12, // 110: ateapi.Worker.metadata:type_name -> ateapi.ResourceMetadata + 109, // 111: ateapi.Worker.labels:type_name -> ateapi.Worker.LabelsEntry + 102, // 112: ateapi.Worker.status:type_name -> ateapi.WorkerStatus + 7, // 113: ateapi.WorkerStatus.state:type_name -> ateapi.WorkerState + 103, // 114: ateapi.WorkerStatus.capacity:type_name -> ateapi.WorkerResources + 103, // 115: ateapi.WorkerStatus.allocated:type_name -> ateapi.WorkerResources + 28, // 116: ateapi.WorkerResources.resources:type_name -> ateapi.Resources + 12, // 117: ateapi.ActorAssignment.metadata:type_name -> ateapi.ResourceMetadata + 26, // 118: ateapi.ActorAssignment.actor:type_name -> ateapi.ObjectRef + 26, // 119: ateapi.ActorAssignment.actor_template_ref:type_name -> ateapi.ObjectRef + 28, // 120: ateapi.ActorAssignment.resources:type_name -> ateapi.Resources + 26, // 121: ateapi.SetWorkerCapacityRequest.worker:type_name -> ateapi.ObjectRef + 103, // 122: ateapi.SetWorkerCapacityRequest.capacity:type_name -> ateapi.WorkerResources + 101, // 123: ateapi.SetWorkerCapacityResponse.worker:type_name -> ateapi.Worker + 61, // 124: ateapi.Control.GetActor:input_type -> ateapi.GetActorRequest + 62, // 125: ateapi.Control.CreateActor:input_type -> ateapi.CreateActorRequest + 63, // 126: ateapi.Control.UpdateActor:input_type -> ateapi.UpdateActorRequest + 64, // 127: ateapi.Control.SuspendActor:input_type -> ateapi.SuspendActorRequest + 66, // 128: ateapi.Control.PauseActor:input_type -> ateapi.PauseActorRequest + 68, // 129: ateapi.Control.ResumeActor:input_type -> ateapi.ResumeActorRequest + 70, // 130: ateapi.Control.RevertActor:input_type -> ateapi.RevertActorRequest + 72, // 131: ateapi.Control.DeleteActor:input_type -> ateapi.DeleteActorRequest + 73, // 132: ateapi.Control.GetActorEgressPolicy:input_type -> ateapi.GetActorEgressPolicyRequest + 74, // 133: ateapi.Control.CreateActorEgressPolicy:input_type -> ateapi.CreateActorEgressPolicyRequest + 75, // 134: ateapi.Control.UpdateActorEgressPolicy:input_type -> ateapi.UpdateActorEgressPolicyRequest + 76, // 135: ateapi.Control.DeleteActorEgressPolicy:input_type -> ateapi.DeleteActorEgressPolicyRequest + 78, // 136: ateapi.Control.MintActorJWT:input_type -> ateapi.MintActorJWTRequest + 80, // 137: ateapi.Control.MintActorCertificate:input_type -> ateapi.MintActorCertificateRequest + 86, // 138: ateapi.Control.CreateTag:input_type -> ateapi.CreateTagRequest + 77, // 139: ateapi.Control.GetTag:input_type -> ateapi.GetTagRequest + 84, // 140: ateapi.Control.ListTags:input_type -> ateapi.ListTagsRequest + 87, // 141: ateapi.Control.UpdateTag:input_type -> ateapi.UpdateTagRequest + 88, // 142: ateapi.Control.DeleteTag:input_type -> ateapi.DeleteTagRequest + 92, // 143: ateapi.Control.ListWorkers:input_type -> ateapi.ListWorkersRequest + 94, // 144: ateapi.Control.GetWorker:input_type -> ateapi.GetWorkerRequest + 95, // 145: ateapi.Control.CreateWorker:input_type -> ateapi.CreateWorkerRequest + 96, // 146: ateapi.Control.UpdateWorker:input_type -> ateapi.UpdateWorkerRequest + 97, // 147: ateapi.Control.DeleteWorker:input_type -> ateapi.DeleteWorkerRequest + 98, // 148: ateapi.Control.DrainWorker:input_type -> ateapi.DrainWorkerRequest + 90, // 149: ateapi.Control.ListWorkerActorAssignments:input_type -> ateapi.ListWorkerActorAssignmentsRequest + 99, // 150: ateapi.Control.ListActors:input_type -> ateapi.ListActorsRequest + 51, // 151: ateapi.Control.CreateAtespace:input_type -> ateapi.CreateAtespaceRequest + 52, // 152: ateapi.Control.GetAtespace:input_type -> ateapi.GetAtespaceRequest + 53, // 153: ateapi.Control.ListAtespaces:input_type -> ateapi.ListAtespacesRequest + 55, // 154: ateapi.Control.DeleteAtespace:input_type -> ateapi.DeleteAtespaceRequest + 56, // 155: ateapi.Control.CreateActorTemplate:input_type -> ateapi.CreateActorTemplateRequest + 57, // 156: ateapi.Control.GetActorTemplate:input_type -> ateapi.GetActorTemplateRequest + 58, // 157: ateapi.Control.ListActorTemplates:input_type -> ateapi.ListActorTemplatesRequest + 60, // 158: ateapi.Control.DeleteActorTemplate:input_type -> ateapi.DeleteActorTemplateRequest + 105, // 159: ateapi.WorkerService.SetWorkerCapacity:input_type -> ateapi.SetWorkerCapacityRequest + 14, // 160: ateapi.Control.GetActor:output_type -> ateapi.Actor + 14, // 161: ateapi.Control.CreateActor:output_type -> ateapi.Actor + 14, // 162: ateapi.Control.UpdateActor:output_type -> ateapi.Actor + 65, // 163: ateapi.Control.SuspendActor:output_type -> ateapi.SuspendActorResponse + 67, // 164: ateapi.Control.PauseActor:output_type -> ateapi.PauseActorResponse + 69, // 165: ateapi.Control.ResumeActor:output_type -> ateapi.ResumeActorResponse + 71, // 166: ateapi.Control.RevertActor:output_type -> ateapi.RevertActorResponse + 14, // 167: ateapi.Control.DeleteActor:output_type -> ateapi.Actor + 15, // 168: ateapi.Control.GetActorEgressPolicy:output_type -> ateapi.EgressPolicy + 15, // 169: ateapi.Control.CreateActorEgressPolicy:output_type -> ateapi.EgressPolicy + 15, // 170: ateapi.Control.UpdateActorEgressPolicy:output_type -> ateapi.EgressPolicy + 15, // 171: ateapi.Control.DeleteActorEgressPolicy:output_type -> ateapi.EgressPolicy + 79, // 172: ateapi.Control.MintActorJWT:output_type -> ateapi.MintActorJWTResponse + 81, // 173: ateapi.Control.MintActorCertificate:output_type -> ateapi.MintActorCertificateResponse + 24, // 174: ateapi.Control.CreateTag:output_type -> ateapi.Tag + 24, // 175: ateapi.Control.GetTag:output_type -> ateapi.Tag + 85, // 176: ateapi.Control.ListTags:output_type -> ateapi.ListTagsResponse + 24, // 177: ateapi.Control.UpdateTag:output_type -> ateapi.Tag + 24, // 178: ateapi.Control.DeleteTag:output_type -> ateapi.Tag + 93, // 179: ateapi.Control.ListWorkers:output_type -> ateapi.ListWorkersResponse + 101, // 180: ateapi.Control.GetWorker:output_type -> ateapi.Worker + 101, // 181: ateapi.Control.CreateWorker:output_type -> ateapi.Worker + 101, // 182: ateapi.Control.UpdateWorker:output_type -> ateapi.Worker + 101, // 183: ateapi.Control.DeleteWorker:output_type -> ateapi.Worker + 101, // 184: ateapi.Control.DrainWorker:output_type -> ateapi.Worker + 91, // 185: ateapi.Control.ListWorkerActorAssignments:output_type -> ateapi.ListWorkerActorAssignmentsResponse + 100, // 186: ateapi.Control.ListActors:output_type -> ateapi.ListActorsResponse + 25, // 187: ateapi.Control.CreateAtespace:output_type -> ateapi.Atespace + 25, // 188: ateapi.Control.GetAtespace:output_type -> ateapi.Atespace + 54, // 189: ateapi.Control.ListAtespaces:output_type -> ateapi.ListAtespacesResponse + 25, // 190: ateapi.Control.DeleteAtespace:output_type -> ateapi.Atespace + 27, // 191: ateapi.Control.CreateActorTemplate:output_type -> ateapi.ActorTemplate + 27, // 192: ateapi.Control.GetActorTemplate:output_type -> ateapi.ActorTemplate + 59, // 193: ateapi.Control.ListActorTemplates:output_type -> ateapi.ListActorTemplatesResponse + 27, // 194: ateapi.Control.DeleteActorTemplate:output_type -> ateapi.ActorTemplate + 106, // 195: ateapi.WorkerService.SetWorkerCapacity:output_type -> ateapi.SetWorkerCapacityResponse + 160, // [160:196] is the sub-list for method output_type + 124, // [124:160] is the sub-list for method input_type + 124, // [124:124] is the sub-list for extension type_name + 124, // [124:124] is the sub-list for extension extendee + 0, // [0:124] is the sub-list for field type_name } func init() { file_ateapi_proto_init() } @@ -7613,7 +7718,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: 99, + NumMessages: 101, NumExtensions: 0, NumServices: 2, }, diff --git a/pkg/proto/ateapipb/ateapi.proto b/pkg/proto/ateapipb/ateapi.proto index 081d383b7f..df45965809 100644 --- a/pkg/proto/ateapipb/ateapi.proto +++ b/pkg/proto/ateapipb/ateapi.proto @@ -43,6 +43,10 @@ service Control { // Resume an actor from its latest snapshot. rpc ResumeActor(ResumeActorRequest) returns (ResumeActorResponse) {} + // Revert an actor to SUSPENDED state. + // Only crashed, running or paused actors can be reverted. + rpc RevertActor(RevertActorRequest) returns (RevertActorResponse) {} + // Delete an actor. Only suspended actors can be deleted. rpc DeleteActor(DeleteActorRequest) returns (Actor) {} @@ -523,6 +527,7 @@ enum ActorState { ACTOR_STATE_PAUSED = 6; ACTOR_STATE_CRASHED = 7; ACTOR_STATE_DELETING = 8; + ACTOR_STATE_REVERTING = 9; // Keep this in sync with ActorStatus.state's maximum. } @@ -531,7 +536,7 @@ message ActorStatus { // // +k8s:required // +k8s:minimum=1 - // +k8s:maximum=8 # keep this in sync with the ActorState enum + // +k8s:maximum=9 # keep this in sync with the ActorState enum ActorState state = 1; // worker_assignment points at the worker currently hosting this Actor. @@ -1392,6 +1397,16 @@ message ResumeActorResponse { bool resumed = 2; } +message RevertActorRequest { + // +k8s:required + // +k8s:subfield(atespace)=+k8s:required + ObjectRef actor = 1; +} + +message RevertActorResponse { + Actor actor = 1; +} + message DeleteActorRequest { // +k8s:required // +k8s:subfield(atespace)=+k8s:required diff --git a/pkg/proto/ateapipb/ateapi_grpc.pb.go b/pkg/proto/ateapipb/ateapi_grpc.pb.go index 69a154a2c1..8734540bd7 100644 --- a/pkg/proto/ateapipb/ateapi_grpc.pb.go +++ b/pkg/proto/ateapipb/ateapi_grpc.pb.go @@ -39,6 +39,7 @@ const ( Control_SuspendActor_FullMethodName = "/ateapi.Control/SuspendActor" Control_PauseActor_FullMethodName = "/ateapi.Control/PauseActor" Control_ResumeActor_FullMethodName = "/ateapi.Control/ResumeActor" + Control_RevertActor_FullMethodName = "/ateapi.Control/RevertActor" Control_DeleteActor_FullMethodName = "/ateapi.Control/DeleteActor" Control_GetActorEgressPolicy_FullMethodName = "/ateapi.Control/GetActorEgressPolicy" Control_CreateActorEgressPolicy_FullMethodName = "/ateapi.Control/CreateActorEgressPolicy" @@ -89,6 +90,9 @@ type ControlClient interface { PauseActor(ctx context.Context, in *PauseActorRequest, opts ...grpc.CallOption) (*PauseActorResponse, error) // Resume an actor from its latest snapshot. ResumeActor(ctx context.Context, in *ResumeActorRequest, opts ...grpc.CallOption) (*ResumeActorResponse, error) + // Revert an actor to SUSPENDED state. + // Only crashed, running or paused actors can be reverted. + RevertActor(ctx context.Context, in *RevertActorRequest, opts ...grpc.CallOption) (*RevertActorResponse, error) // Delete an actor. Only suspended actors can be deleted. DeleteActor(ctx context.Context, in *DeleteActorRequest, opts ...grpc.CallOption) (*Actor, error) // Get the egress policy resource nested under an Actor. @@ -229,6 +233,16 @@ func (c *controlClient) ResumeActor(ctx context.Context, in *ResumeActorRequest, return out, nil } +func (c *controlClient) RevertActor(ctx context.Context, in *RevertActorRequest, opts ...grpc.CallOption) (*RevertActorResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(RevertActorResponse) + err := c.cc.Invoke(ctx, Control_RevertActor_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *controlClient) DeleteActor(ctx context.Context, in *DeleteActorRequest, opts ...grpc.CallOption) (*Actor, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(Actor) @@ -529,6 +543,9 @@ type ControlServer interface { PauseActor(context.Context, *PauseActorRequest) (*PauseActorResponse, error) // Resume an actor from its latest snapshot. ResumeActor(context.Context, *ResumeActorRequest) (*ResumeActorResponse, error) + // Revert an actor to SUSPENDED state. + // Only crashed, running or paused actors can be reverted. + RevertActor(context.Context, *RevertActorRequest) (*RevertActorResponse, error) // Delete an actor. Only suspended actors can be deleted. DeleteActor(context.Context, *DeleteActorRequest) (*Actor, error) // Get the egress policy resource nested under an Actor. @@ -627,6 +644,9 @@ func (UnimplementedControlServer) PauseActor(context.Context, *PauseActorRequest func (UnimplementedControlServer) ResumeActor(context.Context, *ResumeActorRequest) (*ResumeActorResponse, error) { return nil, status.Error(codes.Unimplemented, "method ResumeActor not implemented") } +func (UnimplementedControlServer) RevertActor(context.Context, *RevertActorRequest) (*RevertActorResponse, error) { + return nil, status.Error(codes.Unimplemented, "method RevertActor not implemented") +} func (UnimplementedControlServer) DeleteActor(context.Context, *DeleteActorRequest) (*Actor, error) { return nil, status.Error(codes.Unimplemented, "method DeleteActor not implemented") } @@ -840,6 +860,24 @@ func _Control_ResumeActor_Handler(srv interface{}, ctx context.Context, dec func return interceptor(ctx, in, info, handler) } +func _Control_RevertActor_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RevertActorRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ControlServer).RevertActor(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Control_RevertActor_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ControlServer).RevertActor(ctx, req.(*RevertActorRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Control_DeleteActor_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(DeleteActorRequest) if err := dec(in); err != nil { @@ -1375,6 +1413,10 @@ var Control_ServiceDesc = grpc.ServiceDesc{ MethodName: "ResumeActor", Handler: _Control_ResumeActor_Handler, }, + { + MethodName: "RevertActor", + Handler: _Control_RevertActor_Handler, + }, { MethodName: "DeleteActor", Handler: _Control_DeleteActor_Handler, From dcb1faef6f2105541637456b30981f951c388969 Mon Sep 17 00:00:00 2001 From: shrutiyam-glitch Date: Wed, 16 Sep 2026 07:54:14 -0700 Subject: [PATCH 02/14] Add the revertActtor workflow and the observability metrics --- .../internal/controlapi/workflow_revert.go | 255 +++++++++++++ .../controlapi/workflow_revert_test.go | 346 ++++++++++++++++++ docs/metrics/registry/metrics.yaml | 4 + docs/observability.md | 2 +- internal/ateattr/ateattr.go | 2 + 5 files changed, 608 insertions(+), 1 deletion(-) create mode 100644 cmd/ateapi/internal/controlapi/workflow_revert.go create mode 100644 cmd/ateapi/internal/controlapi/workflow_revert_test.go diff --git a/cmd/ateapi/internal/controlapi/workflow_revert.go b/cmd/ateapi/internal/controlapi/workflow_revert.go new file mode 100644 index 0000000000..25a9c846eb --- /dev/null +++ b/cmd/ateapi/internal/controlapi/workflow_revert.go @@ -0,0 +1,255 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package controlapi + +import ( + "context" + "errors" + "fmt" + "log/slog" + "slices" + "time" + + "github.com/agent-substrate/substrate/cmd/ateapi/internal/store" + "github.com/agent-substrate/substrate/internal/ateattr" + "github.com/agent-substrate/substrate/internal/objectstore" + "github.com/agent-substrate/substrate/internal/resources" + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" + "go.opentelemetry.io/otel/attribute" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// revertableStates are the states a revert is accepted from. +var revertableStates = []ateapipb.ActorState{ + ateapipb.ActorState_ACTOR_STATE_RUNNING, + ateapipb.ActorState_ACTOR_STATE_PAUSED, + ateapipb.ActorState_ACTOR_STATE_CRASHED, +} + +// RevertActor executes the workflow to discard an actor's current execution and +// return it to SUSPENDED, leaving its external snapshot untouched for a later +// resume to restore from. It is the recovery verb: it accepts a CRASHED actor, +// and needs no live worker to succeed. +// +// Idempotent: each step keys on a persisted field rather than on the state the +// actor was reverted from, so a re-entered workflow fast-forwards to wherever +// the previous attempt stopped. +func (w *ActorWorkflow) RevertActor(ctx context.Context, actorRef resources.ActorRef) (_ *ateapipb.Actor, err error) { + start := time.Now() + var actor *ateapipb.Actor + var actorTemplate *ateapipb.ActorTemplate + // Set just before finalize; nil until then, so earlier exits label + // themselves from the record they hold. + var finalAttrs []attribute.KeyValue + + defer func() { + attrs := finalAttrs + if attrs == nil { + attrs = lifecycleOpAttrs(actor, actorTemplate, "", "") + } + w.instruments.recordLifecycleOp(ctx, ateattr.OperationRevert, start, err, attrs...) + }() + + leaseCtx, lease, err := w.acquireActorLease(ctx, actorRef) + if err != nil { + return nil, err + } + defer lease.Close() + + actor, actorTemplate, err = w.loadActorForRevert(leaseCtx, actorRef) + if err != nil { + return nil, err + } + + var marked *ateapipb.Actor + if marked, err = w.ensureMarkedReverting(leaseCtx, actorRef, actor); err != nil { + return nil, err + } + actor = marked + + if err = w.ensureWorkerDiscarded(leaseCtx, actorRef, actor, actorTemplate); err != nil { + return nil, err + } + + if err = w.ensureInProgressSnapshotCollected(leaseCtx, actor, actorTemplate); err != nil { + return nil, err + } + + // TODO: Check if local checkpoints need to be pruned #641 + // w.ensureLocalCheckpointsPruned(leaseCtx, actor) + + // FinalizeReverted clears the WorkerAssignment the labels read, so snapshot + // them here, as suspend and crash.go do. + finalAttrs = lifecycleOpAttrs(actor, actorTemplate, "", "") + var finalized *ateapipb.Actor + if finalized, err = w.ensureRevertedFinalized(leaseCtx, actorRef); err != nil { + return nil, err + } + return finalized, nil +} + +// loadActorForRevert fetches the current actor record and its template. +func (w *ActorWorkflow) loadActorForRevert(ctx context.Context, actorRef resources.ActorRef) (_ *ateapipb.Actor, _ *ateapipb.ActorTemplate, err error) { + ctx, done := stepSpan(ctx, "LoadActorForRevert") + defer func() { err = done(err) }() + + actor, err := w.store.GetActor(ctx, actorRef) + if err != nil { + if errors.Is(err, store.ErrNotFound) { + return nil, nil, status.Errorf(codes.NotFound, "Actor %s not found", actorRef) + } + return nil, nil, fmt.Errorf("while fetching actor: %w", err) + } + + actorTemplate, err := resolveActorTemplate(ctx, w.store, actor) + if errors.Is(err, errActorTemplateNotFound) { + slog.WarnContext(ctx, "Reverting an actor whose template no longer resolves", + slog.Any("actor", actorRef), + slog.String("templateAtespace", actor.GetActorTemplate().GetAtespace()), + slog.String("templateName", actor.GetActorTemplate().GetName())) + return actor, nil, nil + } + if err != nil { + return nil, nil, err + } + return actor, actorTemplate, nil +} + +// ensureMarkedReverting transitions the actor to REVERTING and persists the +// change. Skips when a previous attempt already marked it, which is what makes +// the rest of the workflow re-enterable. +func (w *ActorWorkflow) ensureMarkedReverting(ctx context.Context, actorRef resources.ActorRef, actor *ateapipb.Actor) (_ *ateapipb.Actor, err error) { + ctx, done := stepSpan(ctx, "MarkReverting") + defer func() { err = done(err) }() + + st := actor.GetStatus().GetState() + if st == ateapipb.ActorState_ACTOR_STATE_REVERTING { + markSkipped(ctx, "actor already REVERTING") + return actor, nil + } + if !slices.Contains(revertableStates, st) { + return nil, status.Errorf(codes.FailedPrecondition, "Actor %s is not in a revertable state (got: %v, want one of %v)", actorRef, st, revertableStates) + } + + storedActor, err := w.store.UpdateActor(ctx, actorRef, store.PreconditionFrom(actor), func(toUpdate *ateapipb.Actor) error { + toUpdate.Status.State = ateapipb.ActorState_ACTOR_STATE_REVERTING + return nil + }) + if err != nil { + if errors.Is(err, store.ErrVersionConflict) { + return nil, status.Error(codes.Aborted, "concurrent update conflict, please retry") + } + return nil, fmt.Errorf("while setting actor state to REVERTING: %w", err) + } + logActorStateChanged(ctx, storedActor, ateattr.OperationRevert) + return storedActor, nil +} + +// ensureWorkerDiscarded tears down whatever the actor is running on and frees +// the worker it booked — including one the actor does not name. +// +// The assignment-backed path mirrors delete's ordering: terminate, detach, and +// only then release, so a worker is never handed back while a sandbox or a +// mount may still be live on it. The assignment itself is left on the record +// for FinalizeReverted to clear, so an interrupted release is rediscoverable. +// +// The sweep afterwards runs on every origin, not just when the record names no +// worker. An assignment commits before the actor is updated to point at it, so +// a crash in between leaves a row nothing references — and a CRASHED actor is +// the likeliest holder of one. Absence is the ordinary case, not an error. +func (w *ActorWorkflow) ensureWorkerDiscarded(ctx context.Context, actorRef resources.ActorRef, actor *ateapipb.Actor, actorTemplate *ateapipb.ActorTemplate) (err error) { + ctx, done := stepSpan(ctx, "DiscardWorker") + defer func() { err = done(err) }() + + if actor.GetStatus().GetWorkerAssignment() != nil { + if terr := w.ensureAteletTerminated(ctx, actorRef, actor, actorTemplate); terr != nil { + // A terminate that comes back with a crash directive lands the + // actor in CRASHED, which the user can revert again — that retry + // needs no live worker. + return maybeCrashActor(ctx, w.store, actorRef, terr, "while terminating the actor's workload", ateattr.OperationRevert) + } + if err := w.ensureVolumesDetached(ctx, actor, actorTemplate, "DetachVolumesForRevert", ateattr.OperationRevert); err != nil { + return err + } + if _, _, err := releaseWorker(ctx, w.store, actor); err != nil { + return fmt.Errorf("while releasing worker: %w", err) + } + } + + return w.releaseAssignmentWithoutBacklink(ctx, actor) +} + +// ensureInProgressSnapshotCollected deletes the objects a suspend was partway +// through writing when the actor was reverted. +func (w *ActorWorkflow) ensureInProgressSnapshotCollected(ctx context.Context, actor *ateapipb.Actor, actorTemplate *ateapipb.ActorTemplate) (err error) { + ctx, done := stepSpan(ctx, "CollectInProgressSnapshot") + defer func() { err = done(err) }() + + name := actor.GetStatus().GetInProgressSnapshotName() + switch { + case w.objectStore == nil: + markSkipped(ctx, "no object store configured") + return nil + case name == "": + markSkipped(ctx, "no in-progress snapshot recorded") + return nil + case actorTemplate == nil: + // The template's storage location is the only place the prefix can be + // derived from. Refusing here would leave the actor REVERTING forever + // TODO: prevent this from leaking objects in the external storage. + slog.WarnContext(ctx, "Leaking an in-progress external snapshot, the actor's template no longer resolves", + slog.String("actor", actor.GetMetadata().GetName()), + slog.String("in_progress_snapshot_name", name)) + return nil + } + + uri, err := inProgressSnapshotURI(actorTemplate, actor, name) + if err != nil { + return err + } + return objectstore.DeletePrefix(ctx, w.objectStore, uri.Prefix()) +} + +// ensureRevertedFinalized commits SUSPENDED and drops every pointer to the +// execution that was discarded, in a single update. +// It re-reads the actor first so an out-of-band transition is not overwritten, +// and so the version precondition guards what was actually observed. +func (w *ActorWorkflow) ensureRevertedFinalized(ctx context.Context, actorRef resources.ActorRef) (_ *ateapipb.Actor, err error) { + ctx, done := stepSpan(ctx, "FinalizeReverted") + defer func() { err = done(err) }() + + latestActor, err := w.store.GetActor(ctx, actorRef) + if err != nil { + return nil, err + } + + storedActor, err := w.store.UpdateActor(ctx, actorRef, store.PreconditionFrom(latestActor), func(toUpdate *ateapipb.Actor) error { + toUpdate.Status.State = ateapipb.ActorState_ACTOR_STATE_SUSPENDED + toUpdate.Status.WorkerAssignment = nil + toUpdate.Status.InProgressSnapshotName = "" + toUpdate.Status.InProgressLocalSnapshotName = "" + toUpdate.Status.LocalSnapshotInfo = nil + return nil + }) + if err != nil { + if errors.Is(err, store.ErrVersionConflict) { + return nil, status.Error(codes.Aborted, "concurrent update conflict, please retry") + } + return nil, err + } + logActorStateChanged(ctx, storedActor, ateattr.OperationRevert) + return storedActor, nil +} diff --git a/cmd/ateapi/internal/controlapi/workflow_revert_test.go b/cmd/ateapi/internal/controlapi/workflow_revert_test.go new file mode 100644 index 0000000000..d425eb0be7 --- /dev/null +++ b/cmd/ateapi/internal/controlapi/workflow_revert_test.go @@ -0,0 +1,346 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package controlapi + +import ( + "context" + "testing" + + "github.com/agent-substrate/substrate/cmd/ateapi/internal/store/storetest" + "github.com/agent-substrate/substrate/internal/resources" + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// TestEnsureMarkedReverting_StateMatrix pins which states a revert is accepted +// from. It runs over every enum value, so a state added to the proto without a +// decision here fails rather than silently landing in the reject branch. +// +// SUSPENDED is the load-bearing rejection: it is revert's own destination, and +// also what a suspend that won the race leaves behind, so accepting it would +// report success for the opposite of what was asked. +func TestEnsureMarkedReverting_StateMatrix(t *testing.T) { + allowed := map[ateapipb.ActorState]bool{ + ateapipb.ActorState_ACTOR_STATE_RUNNING: true, + ateapipb.ActorState_ACTOR_STATE_PAUSED: true, + ateapipb.ActorState_ACTOR_STATE_CRASHED: true, + // Re-entry: a previous attempt already marked it, so the step skips + // rather than re-committing. + ateapipb.ActorState_ACTOR_STATE_REVERTING: true, + } + + for _, seedState := range allActorStates { + ctx := context.Background() + st, cleanup := storetest.SetupTestStore(t) + w := newTestActorWorkflow(t, st, "ns", "tmpl1") + + actorRef := resources.ActorRef{Atespace: "team-a", Name: "id1"} + seedWorkflowActor(t, ctx, st, actorRef, "ns", "tmpl1", seedState) + actor, err := st.GetActor(ctx, actorRef) + if err != nil { + t.Fatalf("state %v: get seeded actor: %v", seedState, err) + } + + updated, err := w.ensureMarkedReverting(ctx, actorRef, actor) + assertPrerequisiteResult(t, seedState, err, allowed[seedState]) + if err == nil { + if got := updated.GetStatus().GetState(); got != ateapipb.ActorState_ACTOR_STATE_REVERTING { + t.Errorf("state %v: ensureMarkedReverting returned actor in %v, want REVERTING", seedState, got) + } + } + cleanup() + } +} + +// TestRevertActor_ReturnsActorToItsSnapshot covers the whole workflow from each +// accepted origin: the actor lands SUSPENDED holding the same external snapshot +// it started with, and every pointer to the discarded execution is gone. +// +// None of these actors has a worker assignment, so the terminate path is not +// exercised here; it needs the atelet rig, and the unit workflow is built with +// a nil dialer on purpose so an unexpected dial fails loudly. +func TestRevertActor_ReturnsActorToItsSnapshot(t *testing.T) { + for _, seedState := range []ateapipb.ActorState{ + ateapipb.ActorState_ACTOR_STATE_RUNNING, + ateapipb.ActorState_ACTOR_STATE_PAUSED, + ateapipb.ActorState_ACTOR_STATE_CRASHED, + // A revert that died partway is retried, not rejected. + ateapipb.ActorState_ACTOR_STATE_REVERTING, + } { + t.Run(seedState.String(), func(t *testing.T) { + ctx := context.Background() + st, cleanup := storetest.SetupTestStore(t) + defer cleanup() + w := newTestActorWorkflow(t, st, "ns", "tmpl1") + + actorRef := resources.ActorRef{Atespace: "team-a", Name: "id1"} + seedWorkflowActor(t, ctx, st, actorRef, "ns", "tmpl1", seedState) + actor, err := st.GetActor(ctx, actorRef) + if err != nil { + t.Fatalf("get seeded actor: %v", err) + } + + // The snapshot revert must preserve, plus the node-local state a + // pause left behind, which it must not. Revert drops the pointer; + // pruning the bytes it names is still a TODO (#641). + const keptURI = "gs://snapshots/team-a/actors/keep/snapshot" + mustUpdateActorStatus(t, ctx, st, actor, func(s *ateapipb.ActorStatus) { + s.ExternalSnapshot = &ateapipb.ExternalSnapshot{SnapshotUri: keptURI} + s.LocalSnapshotInfo = &ateapipb.LocalSnapshotInfo{SnapshotName: "local-1"} + s.InProgressLocalSnapshotName = "local-in-progress" + }) + + reverted, err := w.RevertActor(ctx, actorRef) + if err != nil { + t.Fatalf("RevertActor: %v", err) + } + + gotStatus := reverted.GetStatus() + if got := gotStatus.GetState(); got != ateapipb.ActorState_ACTOR_STATE_SUSPENDED { + t.Errorf("state = %v, want SUSPENDED", got) + } + if got := gotStatus.GetExternalSnapshot().GetSnapshotUri(); got != keptURI { + t.Errorf("external snapshot = %q, want it untouched at %q", got, keptURI) + } + // Resume prefers a local snapshot over the external one, so a + // surviving LocalSnapshotInfo would restore the execution this + // revert just discarded. + if got := gotStatus.GetLocalSnapshotInfo(); got != nil { + t.Errorf("local snapshot info = %v, want nil", got) + } + if got := gotStatus.GetInProgressSnapshotName(); got != "" { + t.Errorf("in-progress snapshot name = %q, want empty", got) + } + if got := gotStatus.GetInProgressLocalSnapshotName(); got != "" { + t.Errorf("in-progress local snapshot name = %q, want empty", got) + } + if got := gotStatus.GetWorkerAssignment(); got != nil { + t.Errorf("worker assignment = %v, want nil", got) + } + }) + } +} + +// TestRevertActor_RejectsSuspended covers both ways an actor can already be +// SUSPENDED when a revert arrives: it never ran, or a previous revert already +// finished. Both are FailedPrecondition — revert is not a no-op success on its +// own destination, for the same reason a second DeleteActor is NotFound. +func TestRevertActor_RejectsSuspended(t *testing.T) { + t.Run("actor was already suspended", func(t *testing.T) { + ctx := context.Background() + st, cleanup := storetest.SetupTestStore(t) + defer cleanup() + w := newTestActorWorkflow(t, st, "ns", "tmpl1") + + actorRef := resources.ActorRef{Atespace: "team-a", Name: "id1"} + seedWorkflowActor(t, ctx, st, actorRef, "ns", "tmpl1", ateapipb.ActorState_ACTOR_STATE_SUSPENDED) + + if _, err := w.RevertActor(ctx, actorRef); status.Code(err) != codes.FailedPrecondition { + t.Fatalf("RevertActor = %v, want FailedPrecondition", err) + } + }) + + t.Run("second revert of an already-reverted actor", func(t *testing.T) { + ctx := context.Background() + st, cleanup := storetest.SetupTestStore(t) + defer cleanup() + w := newTestActorWorkflow(t, st, "ns", "tmpl1") + + actorRef := resources.ActorRef{Atespace: "team-a", Name: "id1"} + seedWorkflowActor(t, ctx, st, actorRef, "ns", "tmpl1", ateapipb.ActorState_ACTOR_STATE_CRASHED) + + if _, err := w.RevertActor(ctx, actorRef); err != nil { + t.Fatalf("first RevertActor: %v", err) + } + if _, err := w.RevertActor(ctx, actorRef); status.Code(err) != codes.FailedPrecondition { + t.Fatalf("second RevertActor = %v, want FailedPrecondition", err) + } + }) +} + +// TestRevertActor_MissingTemplate covers the wreck revert most needs to +// recover: an actor whose template was deleted. Suspend refuses this actor +// outright, so revert must not, or the only way out would be deletion. +func TestRevertActor_MissingTemplate(t *testing.T) { + ctx := context.Background() + st, cleanup := storetest.SetupTestStore(t) + defer cleanup() + w := newTestActorWorkflow(t, st, "ns", "tmpl1") + + actorRef := resources.ActorRef{Atespace: "team-a", Name: "id1"} + seedWorkflowActor(t, ctx, st, actorRef, "ns", "missing-tmpl", ateapipb.ActorState_ACTOR_STATE_CRASHED) + + reverted, err := w.RevertActor(ctx, actorRef) + if err != nil { + t.Fatalf("RevertActor: %v", err) + } + if got := reverted.GetStatus().GetState(); got != ateapipb.ActorState_ACTOR_STATE_SUSPENDED { + t.Errorf("state = %v, want SUSPENDED", got) + } +} + +// TestRevertActor_NoSnapshotToRevertTo covers "revert to birth": an actor that +// crashed before it ever suspended holds no external snapshot, so there is +// nothing to return it to. That is accepted, not an error — the actor resumes +// from its template as a fresh one. +func TestRevertActor_NoSnapshotToRevertTo(t *testing.T) { + ctx := context.Background() + st, cleanup := storetest.SetupTestStore(t) + defer cleanup() + w := newTestActorWorkflow(t, st, "ns", "tmpl1") + + actorRef := resources.ActorRef{Atespace: "team-a", Name: "id1"} + seedWorkflowActor(t, ctx, st, actorRef, "ns", "tmpl1", ateapipb.ActorState_ACTOR_STATE_CRASHED) + + reverted, err := w.RevertActor(ctx, actorRef) + if err != nil { + t.Fatalf("RevertActor: %v", err) + } + if got := reverted.GetStatus().GetState(); got != ateapipb.ActorState_ACTOR_STATE_SUSPENDED { + t.Errorf("state = %v, want SUSPENDED", got) + } + if got := reverted.GetStatus().GetExternalSnapshot().GetSnapshotUri(); got != "" { + t.Errorf("external snapshot = %q, want none", got) + } +} + +// TestEnsureInProgressSnapshotCollected covers what a revert deletes from +// object storage and, more importantly, what it must not. Delete drops the +// actor's whole prefix; revert cannot, because the snapshot it is returning the +// actor to lives under that same prefix. +func TestEnsureInProgressSnapshotCollected(t *testing.T) { + const inFlightSnapshotName = "2026-01-01t00-00-00z-abandoned" + + tests := []struct { + name string + // tagOwnedSnapshot makes the actor's external snapshot a tag's rather + // than one it took itself, as an actor created from a tag starts out. + tagOwnedSnapshot bool + // inFlight names a snapshot the interrupted suspend was writing. + inFlight string + // missingTemplate drops the template, leaving no way to derive the + // prefix: the objects leak rather than wedging the actor. + missingTemplate bool + wantInFlightCollected bool + }{ + { + name: "collects the snapshot an interrupted suspend was writing", + inFlight: inFlightSnapshotName, + wantInFlightCollected: true, + }, + { + name: "leaves the actor's own external snapshot in place", + inFlight: "", + }, + { + name: "leaves a snapshot borrowed from a tag in place", + tagOwnedSnapshot: true, + inFlight: inFlightSnapshotName, + wantInFlightCollected: true, + }, + { + name: "leaks rather than wedges when the template is gone", + inFlight: inFlightSnapshotName, + missingTemplate: true, + wantInFlightCollected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + persistence := newTestPersistence(t) + template := seedSubstrateTemplate(t, ctx, persistence, "sub-tmpl") + w, objects := newFinalizeWorkflow(persistence) + + actor := storetest.MustCreateActor(t, ctx, persistence, &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "actor-1"}, + ActorTemplate: &ateapipb.ObjectRef{Atespace: "team-a", Name: "sub-tmpl"}, + Status: &ateapipb.ActorStatus{State: ateapipb.ActorState_ACTOR_STATE_REVERTING}, + }) + + // The actor's prefix is keyed on the UID the store just assigned, + // so its snapshots can only be placed now. + current := mustActorSnapshotURI(t, template, actor, "current") + if tt.tagOwnedSnapshot { + current = mustTagSnapshotURI(t, template, "team-a", "v1-snapshot") + } + objects.PutSnapshot(t, current, "manifest.json") + inFlight := mustActorSnapshotURI(t, template, actor, inFlightSnapshotName) + if tt.inFlight != "" { + objects.PutSnapshot(t, inFlight, "manifest.json") + } + actor = mustUpdateActorStatus(t, ctx, persistence, actor, func(s *ateapipb.ActorStatus) { + s.ExternalSnapshot = &ateapipb.ExternalSnapshot{SnapshotUri: current.String()} + s.InProgressSnapshotName = tt.inFlight + }) + + passedTemplate := template + if tt.missingTemplate { + passedTemplate = nil + } + if err := w.ensureInProgressSnapshotCollected(ctx, actor, passedTemplate); err != nil { + t.Fatalf("ensureInProgressSnapshotCollected: %v", err) + } + + // The whole point: whatever else happens, the snapshot the actor + // is being returned to survives. + if len(objects.Snapshot(t, current)) == 0 { + t.Errorf("external snapshot %v was collected, but revert must preserve it", current) + } + if tt.inFlight != "" { + collected := len(objects.Snapshot(t, inFlight)) == 0 + if collected != tt.wantInFlightCollected { + t.Errorf("in-flight snapshot collected = %v, want %v", collected, tt.wantInFlightCollected) + } + } + }) + } +} + +// TestEnsureRevertedFinalized_NoObjectStore covers a workflow built without an +// object store: the collect step skips instead of failing, so the revert still +// finalizes. +func TestEnsureRevertedFinalized_NoObjectStore(t *testing.T) { + ctx := context.Background() + persistence := newTestPersistence(t) + w := &ActorWorkflow{store: persistence} + + actor := storetest.MustCreateActor(t, ctx, persistence, &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "actor-1"}, + ActorTemplate: &ateapipb.ObjectRef{Atespace: "team-a", Name: "sub-tmpl"}, + Status: &ateapipb.ActorStatus{ + State: ateapipb.ActorState_ACTOR_STATE_REVERTING, + InProgressSnapshotName: "abandoned", + }, + }) + + if err := w.ensureInProgressSnapshotCollected(ctx, actor, nil); err != nil { + t.Fatalf("ensureInProgressSnapshotCollected: %v", err) + } + + actorRef := resources.ActorRefFromActor(actor) + finalized, err := w.ensureRevertedFinalized(ctx, actorRef) + if err != nil { + t.Fatalf("ensureRevertedFinalized: %v", err) + } + if got := finalized.GetStatus().GetState(); got != ateapipb.ActorState_ACTOR_STATE_SUSPENDED { + t.Errorf("state = %v, want SUSPENDED", got) + } + if got := finalized.GetStatus().GetInProgressSnapshotName(); got != "" { + t.Errorf("in-progress snapshot name = %q, want empty", got) + } +} diff --git a/docs/metrics/registry/metrics.yaml b/docs/metrics/registry/metrics.yaml index 45c6317310..c1877d462b 100644 --- a/docs/metrics/registry/metrics.yaml +++ b/docs/metrics/registry/metrics.yaml @@ -60,6 +60,10 @@ groups: stability: development value: delete brief: ateapi removed the actor record. + - id: revert + stability: development + value: revert + brief: ateapi discarded the actor's execution and returned it to its existing snapshot. - id: unknown stability: development value: unknown diff --git a/docs/observability.md b/docs/observability.md index b7fe136f7a..184a874fd2 100644 --- a/docs/observability.md +++ b/docs/observability.md @@ -234,7 +234,7 @@ Agent Substrate emits foundational OpenTelemetry system and server metrics to mo | `ate.workerpool.ready_workers` | atecontroller | up/down counter | number of worker pods currently ready for a WorkerPool, from `status.readyReplicas` (labels `ate.workerpool.namespace`, `ate.workerpool.name`) | | `ate.workerpool.workers` | ateapi | up/down counter | live worker count per pool, split by state (`idle`/`assigned`) and sandbox class to provide fleet capacity and saturation at a glance | -| `ate.actor.lifecycle.operation.duration` | ateapi | histogram | how long each actor operation (create/resume/suspend/pause/delete) takes and whether it failed (`error.type` present = failure, absent = success); labeled by operation, template, pool (`ate.workerpool.namespace` + `ate.workerpool.name`), sandbox class, and snapshot kind and scope on resume; already-running resume no-ops are not recorded so the histogram tracks actual activations, not router traffic | +| `ate.actor.lifecycle.operation.duration` | ateapi | histogram | how long each actor operation (create/resume/suspend/pause/delete/revert) takes and whether it failed (`error.type` present = failure, absent = success); labeled by operation, template, pool (`ate.workerpool.namespace` + `ate.workerpool.name`), sandbox class, and snapshot kind and scope on resume; already-running resume no-ops are not recorded so the histogram tracks actual activations, not router traffic | | `ate.scheduler.assignment.duration` | ateapi | histogram | time it takes for an actor to be assigned to a worker, per attempt (version-conflict retries record only the final attempt), with the outcome (`assigned` / `no_free_worker` / `error`), the assigned pool (`ate.workerpool.namespace` + `ate.workerpool.name`) and sandbox class to catch scheduling latency and capacity starvation problems | | `ate.actor.restore.duration` | atelet | histogram | how long each phase of a restore takes on the worker node, which is where cold-start latency actually goes once ateapi hands off (labels `ate.snapshot.phase`, `ate.snapshot.kind`, `ate.snapshot.scope`, `ate.template.atespace`, `ate.template.name`, `ate.sandbox.class`, plus `ate.failure.reason` and `ate.failure.domain` on failure) | | `ate.actor.checkpoint.duration` | atelet | histogram | the same phase breakdown for writing a snapshot, so a slow suspend can be attributed to ateom or to the upload (same labels as the restore histogram) | diff --git a/internal/ateattr/ateattr.go b/internal/ateattr/ateattr.go index 82651f8af0..2e7a591268 100644 --- a/internal/ateattr/ateattr.go +++ b/internal/ateattr/ateattr.go @@ -279,6 +279,7 @@ const ( OperationSuspend = "suspend" OperationPause = "pause" OperationDelete = "delete" + OperationRevert = "revert" OperationUnknown = "unknown" ) @@ -289,6 +290,7 @@ var AllOperations = []string{ OperationSuspend, OperationPause, OperationDelete, + OperationRevert, } // NormalizeOperationName ensures op is one of the bounded lifecycle operations. From 2fc53ae8a2b45408b27f8c664e6b5ff9f924b0ac Mon Sep 17 00:00:00 2001 From: shrutiyam-glitch Date: Wed, 16 Sep 2026 08:47:57 -0700 Subject: [PATCH 03/14] Add can_revert to the authorization model RevertActor is a new actor lifecycle RPC, so the model needs a permission for it. Give it the same shape as can_suspend: the editor tier of the parent atespace, plus a direct grant so a machine identity can revert the actor it drives without holding an atespace role. Revert is the recovery counterpart of suspend and discards execution the same way, so anyone trusted to suspend an actor is trusted to revert it. Viewers and cluster viewers are asserted false, matching the other data plane verbs. Nothing in Go reads these relations yet. This is the model and its test suite only, as with can_suspend and can_resume. --- internal/authz/model.fga | 1 + internal/authz/model_test.fga.yaml | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/internal/authz/model.fga b/internal/authz/model.fga index bfe7facee8..fa441f3cbe 100644 --- a/internal/authz/model.fga +++ b/internal/authz/model.fga @@ -92,3 +92,4 @@ type actor # Lifecycle Operations define can_suspend: [user] or editor from parent_atespace + define can_revert: [user] or editor from parent_atespace diff --git a/internal/authz/model_test.fga.yaml b/internal/authz/model_test.fga.yaml index 9835c6290e..e5baf22910 100644 --- a/internal/authz/model_test.fga.yaml +++ b/internal/authz/model_test.fga.yaml @@ -66,6 +66,9 @@ tuples: - user: user:sa-runner-1 relation: can_suspend object: actor:runner-1 + - user: user:sa-runner-1 + relation: can_revert + object: actor:runner-1 tests: - name: 1. Cluster Superadmin & Viewer Propagation @@ -206,6 +209,7 @@ tests: can_delete: true can_resume: true can_suspend: true + can_revert: true - user: user:bob # Editor object: actor:runner-1 assertions: @@ -214,6 +218,7 @@ tests: can_delete: true can_resume: true can_suspend: true + can_revert: true - user: user:dave # Viewer object: actor:runner-1 assertions: @@ -222,6 +227,7 @@ tests: can_delete: false can_resume: false can_suspend: false + can_revert: false - user: user:frank # Cluster Viewer object: actor:runner-1 assertions: @@ -230,14 +236,16 @@ tests: can_delete: false can_resume: false can_suspend: false + can_revert: false - user: user:sa-router # Ingress router proxy object: actor:runner-1 assertions: can_resume: true - - user: user:sa-runner-1 # Workload identity can suspend + - user: user:sa-runner-1 # Workload identity can suspend and revert object: actor:runner-1 assertions: can_suspend: true + can_revert: true - name: 5. Node Restriction (can_mint_ateom_actor_credential) check: From f04fab471cf39f78e7c5f4675039420218dff9d5 Mon Sep 17 00:00:00 2001 From: shrutiyam-glitch Date: Wed, 16 Sep 2026 09:22:05 -0700 Subject: [PATCH 04/14] Serve RevertActor and add the CLI verb The workflow existed but nothing reached it: Control.RevertActor was still the generated stub answering Unimplemented. Wire the service method to the workflow and add "ate revert actor", so the feature is usable end to end. The fake atelet gained a Terminate implementation. It had none, because no functional test had ever reached that call: delete is the only other caller and every delete test runs against an actor with no worker assignment, which skips the step. Revert from RUNNING is the first path that gets there, and without the method the embedded UnimplementedAteomHerderServer answers Unimplemented, which revert treats as a real failure. --- cmd/ateapi/internal/controlapi/actor.go | 27 +++++ .../controlapi/functionaltest/actor_test.go | 109 ++++++++++++++++++ .../controlapi/functionaltest/main_test.go | 20 ++++ cmd/kubectl-ate/internal/cmd/revert.go | 28 +++++ cmd/kubectl-ate/internal/cmd/revert_actor.go | 61 ++++++++++ 5 files changed, 245 insertions(+) create mode 100644 cmd/kubectl-ate/internal/cmd/revert.go create mode 100644 cmd/kubectl-ate/internal/cmd/revert_actor.go diff --git a/cmd/ateapi/internal/controlapi/actor.go b/cmd/ateapi/internal/controlapi/actor.go index 57917151ca..141a267c14 100644 --- a/cmd/ateapi/internal/controlapi/actor.go +++ b/cmd/ateapi/internal/controlapi/actor.go @@ -525,6 +525,33 @@ func validateSuspendActorRequest(ctx context.Context, req *ateapipb.SuspendActor return Validate_SuspendActorRequest(ctx, op, nil, req, nil) } +func (s *RPCService) RevertActor(ctx context.Context, req *ateapipb.RevertActorRequest) (*ateapipb.RevertActorResponse, error) { + if errs := validateRevertActorRequest(ctx, req); len(errs) > 0 { + return nil, toGRPCStatusError(errs) + } + actorRef := resources.ActorRefFromObjectRef(req.GetActor()) + setSpanActorRefAttributes(ctx, actorRef) + + actor, err := s.actorWorkflow.RevertActor(ctx, actorRef) + if err != nil { + if errors.Is(err, store.ErrVersionConflict) { + return nil, status.Error(codes.Aborted, "concurrent update conflict, please retry") + } + if errors.Is(err, store.ErrNotFound) { + return nil, status.Errorf(codes.NotFound, "Actor %s not found", actorRef) + } + return nil, err + } + setSpanActorAttributes(ctx, actor) + return &ateapipb.RevertActorResponse{Actor: actor}, nil +} + +func validateRevertActorRequest(ctx context.Context, req *ateapipb.RevertActorRequest) field.ErrorList { + // Call the generated validation. + op := operation.Operation{Type: operation.Create} + return Validate_RevertActorRequest(ctx, op, nil, req, nil) +} + func validateActorUpdate(ctx context.Context, fldPath *field.Path, newVal, oldVal *ateapipb.Actor, requireStatus bool) field.ErrorList { // Call the generated validation. op := operation.Operation{Type: operation.Update} diff --git a/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go b/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go index fdb9ee2a00..0dd6ca54d0 100644 --- a/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go +++ b/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go @@ -3502,3 +3502,112 @@ func TestMintActorJWT_Success(t *testing.T) { t.Fatalf("Error while calling MintActorJWT: %v", err) } } + +// TestRevertActor returns a running actor to the snapshot its last suspend +// wrote, without taking a new one. +func TestRevertActor(t *testing.T) { + ns := namespaceForTest("ns-revert") + tc := setupTest(t, ns) + defer tc.cleanup() + + createTemplate(t, tc, ns) + workerName := createWorkerPod(t, tc, ns, "worker-1", "node1", "pool1") + + ctx := context.Background() + const name = "id1" + actorRef := &ateapipb.ObjectRef{Atespace: testAtespace, Name: name} + + if _, err := tc.client.CreateActor(ctx, &ateapipb.CreateActorRequest{Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: name}, + ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"}, + }}); err != nil { + t.Fatalf("CreateActor failed: %v", err) + } + + // Run and suspend once, so the revert has a snapshot to return the actor to. + if _, err := tc.client.ResumeActor(ctx, &ateapipb.ResumeActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("ResumeActor failed: %v", err) + } + suspended, err := tc.client.SuspendActor(ctx, &ateapipb.SuspendActorRequest{Actor: actorRef}) + if err != nil { + t.Fatalf("SuspendActor failed: %v", err) + } + waitForWorkerAvailable(t, tc, workerName) + snapshotURI := suspended.GetActor().GetStatus().GetExternalSnapshot().GetSnapshotUri() + if snapshotURI == "" { + t.Fatalf("SuspendActor wrote no external snapshot: %v", suspended) + } + + // Run it again, then throw that second execution away. + if _, err := tc.client.ResumeActor(ctx, &ateapipb.ResumeActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("second ResumeActor failed: %v", err) + } + tc.fakeAtelet.Lock.Lock() + tc.fakeAtelet.CheckpointCalled = false + tc.fakeAtelet.Lock.Unlock() + + reverted, err := tc.client.RevertActor(ctx, &ateapipb.RevertActorRequest{Actor: actorRef}) + if err != nil { + t.Fatalf("RevertActor failed: %v", err) + } + waitForWorkerAvailable(t, tc, workerName) + + got := reverted.GetActor().GetStatus() + if got.GetState() != ateapipb.ActorState_ACTOR_STATE_SUSPENDED { + t.Errorf("state = %v, want SUSPENDED", got.GetState()) + } + if uri := got.GetExternalSnapshot().GetSnapshotUri(); uri != snapshotURI { + t.Errorf("external snapshot = %q, want it untouched at %q", uri, snapshotURI) + } + assertSnapshotPresent(t, tc, snapshotURI) + if got.GetWorkerAssignment() != nil { + t.Errorf("worker assignment = %v, want nil", got.GetWorkerAssignment()) + } + if !tc.fakeAtelet.TerminateCalled { + t.Errorf("expected atelet Terminate to be called, the workload was still running") + } + // The difference from suspend: the execution is discarded, not captured. + if tc.fakeAtelet.CheckpointCalled { + t.Errorf("RevertActor checkpointed the workload, want the execution discarded") + } +} + +// TestRevertActor_RejectsSuspended pins the rejection a lost race produces: a +// suspend that won left the actor SUSPENDED, and reporting success there would +// claim the opposite of what the revert asked for. +func TestRevertActor_RejectsSuspended(t *testing.T) { + ns := namespaceForTest("ns-revert-suspended") + tc := setupTest(t, ns) + defer tc.cleanup() + + createTemplate(t, tc, ns) + + ctx := context.Background() + const name = "id1" + actorRef := &ateapipb.ObjectRef{Atespace: testAtespace, Name: name} + + if _, err := tc.client.CreateActor(ctx, &ateapipb.CreateActorRequest{Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: name}, + ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"}, + }}); err != nil { + t.Fatalf("CreateActor failed: %v", err) + } + + _, err := tc.client.RevertActor(ctx, &ateapipb.RevertActorRequest{Actor: actorRef}) + if status.Code(err) != codes.FailedPrecondition { + t.Fatalf("RevertActor = %v, want FailedPrecondition", err) + } +} + +func TestRevertActor_NotFound(t *testing.T) { + ns := namespaceForTest("ns-revert-missing") + tc := setupTest(t, ns) + defer tc.cleanup() + + _, err := tc.client.RevertActor(context.Background(), &ateapipb.RevertActorRequest{ + Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "nope"}, + }) + if status.Code(err) != codes.NotFound { + t.Fatalf("RevertActor = %v, want NotFound", err) + } +} diff --git a/cmd/ateapi/internal/controlapi/functionaltest/main_test.go b/cmd/ateapi/internal/controlapi/functionaltest/main_test.go index 6b74af0f3b..39273cbf40 100644 --- a/cmd/ateapi/internal/controlapi/functionaltest/main_test.go +++ b/cmd/ateapi/internal/controlapi/functionaltest/main_test.go @@ -127,6 +127,10 @@ type FakeAteletServer struct { UploadRequest *ateletpb.UploadPausedCheckpointRequest FailUpload error + TerminateCalled bool + TerminateRequest *ateletpb.TerminateRequest + FailTerminate error + // objectStore, when set, receives the objects a checkpoint or an upload // writes, so the control plane's copy and release steps have real external // snapshots to act on. setupTest points it at the test's own store. @@ -174,6 +178,10 @@ func (f *FakeAteletServer) Reset() { f.UploadRequest = nil f.FailUpload = nil + f.TerminateCalled = false + f.TerminateRequest = nil + f.FailTerminate = nil + f.objectStore = nil } @@ -233,6 +241,18 @@ func (f *FakeAteletServer) Restore(ctx context.Context, req *ateletpb.RestoreReq return &ateletpb.RestoreResponse{}, nil } +func (f *FakeAteletServer) Terminate(ctx context.Context, req *ateletpb.TerminateRequest) (*ateletpb.TerminateResponse, error) { + f.Lock.Lock() + defer f.Lock.Unlock() + + f.TerminateCalled = true + f.TerminateRequest = proto.Clone(req).(*ateletpb.TerminateRequest) + if f.FailTerminate != nil { + return nil, f.FailTerminate + } + return &ateletpb.TerminateResponse{}, nil +} + func (f *FakeAteletServer) lastRestoreRequest() *ateletpb.RestoreRequest { f.Lock.Lock() defer f.Lock.Unlock() diff --git a/cmd/kubectl-ate/internal/cmd/revert.go b/cmd/kubectl-ate/internal/cmd/revert.go new file mode 100644 index 0000000000..f27df15fbe --- /dev/null +++ b/cmd/kubectl-ate/internal/cmd/revert.go @@ -0,0 +1,28 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "github.com/spf13/cobra" +) + +var revertCmd = &cobra.Command{ + Use: "revert", + Short: "Revert a resource", +} + +func init() { + rootCmd.AddCommand(revertCmd) +} diff --git a/cmd/kubectl-ate/internal/cmd/revert_actor.go b/cmd/kubectl-ate/internal/cmd/revert_actor.go new file mode 100644 index 0000000000..79c7df933b --- /dev/null +++ b/cmd/kubectl-ate/internal/cmd/revert_actor.go @@ -0,0 +1,61 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package cmd + +import ( + "fmt" + + "github.com/agent-substrate/substrate/cmd/kubectl-ate/internal/printer" + "github.com/agent-substrate/substrate/internal/ateclient" + "github.com/agent-substrate/substrate/internal/resources" + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" + "github.com/spf13/cobra" +) + +var revertAtespaceFlag string + +var revertActorCmd = &cobra.Command{ + Use: "actor ", + Short: "Revert an actor to its latest snapshot", + Long: `Revert an actor to SUSPENDED, discarding its current execution. + +The actor's external snapshot is left untouched, so a later resume restores +from it. Only crashed, running, or paused actors can be reverted.`, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + ctx := cmd.Context() + apiClient, err := ateclient.NewClient(ctx, kubeconfig, k8sContext, endpoint, tokenFile, traceEnabled) + if err != nil { + return fmt.Errorf("failed to connect to ate-api-server: %w", err) + } + defer apiClient.Close() + + actorRef := resources.ActorRef{Atespace: revertAtespaceFlag, Name: args[0]} + resp, err := apiClient.RevertActor(ctx, &ateapipb.RevertActorRequest{ + Actor: actorRef.ToObjectRef(), + }) + if err != nil { + return fmt.Errorf("failed to revert actor: %w", err) + } + + return printer.PrintActorTo(cmd.OutOrStdout(), resp.GetActor(), outputFmt) + }, +} + +func init() { + revertActorCmd.Flags().StringVarP(&revertAtespaceFlag, "atespace", "a", "", "Atespace the actor lives in") + _ = revertActorCmd.MarkFlagRequired("atespace") + revertCmd.AddCommand(revertActorCmd) +} From 8022db319fabb8c02459f3f4b0bfeb916c63a654 Mon Sep 17 00:00:00 2001 From: shrutiyam-glitch Date: Wed, 16 Sep 2026 12:09:07 -0700 Subject: [PATCH 05/14] Add a manual verify script for RevertActor RevertActor's unit and functional tests run against a fake atelet, so nothing exercises the verb against a real control plane. This script reverts from CRASHED, RUNNING and PAUSED, and checks that a SUSPENDED actor is rejected. The crash is produced by deleting the worker pod the actor runs on, which is the case that leaves revert with no worker to terminate through. It needs a live cluster and an existing template, so it is not wired into make verify. --- hack/verify-revert-actor.sh | 292 ++++++++++++++++++++++++++++++++++++ 1 file changed, 292 insertions(+) create mode 100755 hack/verify-revert-actor.sh diff --git a/hack/verify-revert-actor.sh b/hack/verify-revert-actor.sh new file mode 100755 index 0000000000..3c0a39e161 --- /dev/null +++ b/hack/verify-revert-actor.sh @@ -0,0 +1,292 @@ +#!/usr/bin/env bash + +# 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. +# +# Exercises RevertActor against a live cluster. Not part of `make verify`: it +# needs a running control plane, a worker pool with spare capacity, and an +# ActorTemplate whose actors can be resumed and suspended. +# +# The interesting case is revert from CRASHED. A real crash is produced by +# deleting the worker pod the actor is running on: the control plane notices +# the pod is gone, marks the actor CRASHED, and clears its worker assignment. +# That leaves an actor with no worker to talk to, which is exactly the wreck +# revert exists to clean up. +# +# hack/verify-revert-actor.sh --atespace my-space --template my-template +# +# Everything the script creates is torn down on exit unless --keep is passed. + +set -o errexit +set -o nounset +set -o pipefail + +ATE="${ATE:-bin/kubectl-ate}" +ATESPACE="" +TEMPLATE="" +ACTOR="revert-check-$$" +ENDPOINT="${ATE_ENDPOINT:-}" +KEEP="false" +# Deleting a pod, noticing it is gone, and rescheduling all take real time on a +# real cluster; a laptop-speed timeout only produces confusing failures. +TIMEOUT_SECONDS="${ATE_VERIFY_TIMEOUT:-180}" + +usage() { + cat <<'EOF' +Usage: hack/verify-revert-actor.sh --atespace --template [options] + +Required: + --atespace Atespace to create the test actor in. + --template ActorTemplate to derive it from. Must already exist, and + its actors must be resumable on an available worker. + +Options: + --actor Name for the test actor. Default: revert-check-. + --endpoint gRPC target, e.g. localhost:8080. Without this the CLI + port-forwards on every call, which makes the run slow. + --keep Leave the actor behind for inspection. + --timeout Per-wait timeout. Default: 180. + +Environment: + ATE Path to the kubectl-ate binary. Default: bin/kubectl-ate. + ATE_ENDPOINT Same as --endpoint. + ATE_VERIFY_TIMEOUT Same as --timeout. +EOF +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --atespace) ATESPACE="$2"; shift 2 ;; + --template) TEMPLATE="$2"; shift 2 ;; + --actor) ACTOR="$2"; shift 2 ;; + --endpoint) ENDPOINT="$2"; shift 2 ;; + --timeout) TIMEOUT_SECONDS="$2"; shift 2 ;; + --keep) KEEP="true"; shift ;; + -h|--help) usage; exit 0 ;; + *) echo "unknown argument: $1" >&2; usage; exit 2 ;; + esac +done + +if [[ -z "${ATESPACE}" || -z "${TEMPLATE}" ]]; then + echo "--atespace and --template are required" >&2 + usage + exit 2 +fi + +FAILURES=0 + +step() { printf '\n\033[1m==> %s\033[0m\n' "$*"; } +info() { printf ' %s\n' "$*"; } +pass() { printf ' \033[32mPASS\033[0m %s\n' "$*"; } +fail() { printf ' \033[31mFAIL\033[0m %s\n' "$*"; FAILURES=$((FAILURES + 1)); } +die() { printf '\n\033[31m%s\033[0m\n' "$*" >&2; exit 1; } + +ate() { + if [[ -n "${ENDPOINT}" ]]; then + "${ATE}" "$@" --endpoint "${ENDPOINT}" + else + "${ATE}" "$@" + fi +} + +actor_json() { + ate get actor "${ACTOR}" -a "${ATESPACE}" -o json +} + +# actor_field prints one jq path from the actor, empty when protojson omitted +# it. A failed read is also reported as empty: these are called from polling +# loops, where a single blip should cost a retry rather than the whole run. +actor_field() { + local raw + raw="$(actor_json 2>/dev/null)" || return 0 + jq -r "$1 // \"\"" <<<"${raw}" +} + +actor_state() { + actor_field '.status.state' +} + +expect_state() { + local want="$1" context="$2" got + got="$(actor_state)" + if [[ "${got}" == "${want}" ]]; then + pass "${context}: state is ${want}" + else + fail "${context}: state is ${got}, want ${want}" + fi +} + +wait_for_state() { + local want="$1" deadline=$((SECONDS + TIMEOUT_SECONDS)) got + while (( SECONDS < deadline )); do + got="$(actor_state)" + if [[ "${got}" == "${want}" ]]; then + return 0 + fi + sleep 2 + done + fail "timed out after ${TIMEOUT_SECONDS}s waiting for ${want}, last state ${got:-unknown}" + return 1 +} + +cleanup() { + local code=$? + if [[ "${KEEP}" == "true" ]]; then + printf '\n--keep set; leaving actor %s/%s in place\n' "${ATESPACE}" "${ACTOR}" + else + step "Cleanup" + # --any-state: a failed run can leave the actor anywhere, including REVERTING. + if ate delete actor "${ACTOR}" -a "${ATESPACE}" --any-state >/dev/null 2>&1; then + info "deleted actor ${ACTOR}" + else + info "no actor to delete (or delete failed; check manually)" + fi + fi + exit "${code}" +} +trap cleanup EXIT + +# --- Preflight ------------------------------------------------------------- + +step "Preflight" +command -v jq >/dev/null || die "jq is required" +command -v kubectl >/dev/null || die "kubectl is required" +[[ -x "${ATE}" ]] || die "${ATE} not found or not executable; run 'make build-atectl' or set ATE" +ate get atespaces >/dev/null || die "cannot reach the control plane" +info "atespace=${ATESPACE} template=${TEMPLATE} actor=${ACTOR}" +[[ -n "${ENDPOINT}" ]] || info "no --endpoint: each CLI call will port-forward, expect a slow run" + +# --- Establish a snapshot for revert to return to -------------------------- + +step "Create and run the actor" +ate create actor "${ACTOR}" -a "${ATESPACE}" --template "${TEMPLATE}" >/dev/null +ate resume actor "${ACTOR}" -a "${ATESPACE}" >/dev/null +wait_for_state "ACTOR_STATE_RUNNING" || die "actor never reached RUNNING" +pass "actor is RUNNING" + +step "Suspend once, so there is an external snapshot to revert to" +ate suspend actor "${ACTOR}" -a "${ATESPACE}" >/dev/null +expect_state "ACTOR_STATE_SUSPENDED" "after suspend" +SNAPSHOT_URI="$(actor_field '.status.externalSnapshot.snapshotUri')" +[[ -n "${SNAPSHOT_URI}" ]] || die "suspend wrote no external snapshot; cannot verify revert" +info "snapshot: ${SNAPSHOT_URI}" + +# --- Scenario 1: revert from CRASHED --------------------------------------- + +step "Scenario 1: revert from CRASHED" +ate resume actor "${ACTOR}" -a "${ATESPACE}" >/dev/null +wait_for_state "ACTOR_STATE_RUNNING" || die "actor never got back to RUNNING" + +WORKER_POD="$(actor_field '.status.workerAssignment.workerPod')" +WORKER_NS="$(actor_field '.status.workerAssignment.workerNamespace')" +[[ -n "${WORKER_POD}" && -n "${WORKER_NS}" ]] || die "running actor has no worker pod recorded" +info "running on ${WORKER_NS}/${WORKER_POD}" + +info "deleting the worker pod to crash the actor" +kubectl delete pod "${WORKER_POD}" -n "${WORKER_NS}" --wait=false >/dev/null +wait_for_state "ACTOR_STATE_CRASHED" || die "actor never reached CRASHED after its pod was deleted" +pass "actor is CRASHED" + +# The crash clears the assignment, so revert has no worker to terminate +# through. This is the path that needs no live worker to succeed. +if [[ -n "$(actor_field '.status.workerAssignment.workerPod')" ]]; then + info "note: the crashed actor still records a worker assignment" +fi + +ate revert actor "${ACTOR}" -a "${ATESPACE}" >/dev/null || fail "RevertActor from CRASHED returned an error" +expect_state "ACTOR_STATE_SUSPENDED" "after revert from CRASHED" + +GOT_URI="$(actor_field '.status.externalSnapshot.snapshotUri')" +if [[ "${GOT_URI}" == "${SNAPSHOT_URI}" ]]; then + pass "external snapshot untouched" +else + fail "external snapshot is ${GOT_URI:-}, want it untouched at ${SNAPSHOT_URI}" +fi + +if [[ -z "$(actor_field '.status.workerAssignment.workerPod')" ]]; then + pass "worker assignment cleared" +else + fail "worker assignment survived the revert" +fi + +if [[ -z "$(actor_field '.status.localSnapshotInfo.snapshotName')" ]]; then + pass "local snapshot pointer cleared" +else + fail "local snapshot pointer survived the revert; the next resume would restore the discarded execution" +fi + +step "The reverted actor is usable: resume it" +ate resume actor "${ACTOR}" -a "${ATESPACE}" >/dev/null || fail "resume after revert returned an error" +wait_for_state "ACTOR_STATE_RUNNING" || fail "actor did not come back up after revert" +pass "actor resumed from its preserved snapshot" + +# --- Scenario 2: revert from RUNNING --------------------------------------- + +step "Scenario 2: revert from RUNNING" +ate revert actor "${ACTOR}" -a "${ATESPACE}" >/dev/null || fail "RevertActor from RUNNING returned an error" +expect_state "ACTOR_STATE_SUSPENDED" "after revert from RUNNING" +GOT_URI="$(actor_field '.status.externalSnapshot.snapshotUri')" +if [[ "${GOT_URI}" == "${SNAPSHOT_URI}" ]]; then + pass "external snapshot still the original one, no new snapshot taken" +else + fail "external snapshot is ${GOT_URI:-}, want the original ${SNAPSHOT_URI}" +fi + +# --- Scenario 3: revert from PAUSED ---------------------------------------- + +step "Scenario 3: revert from PAUSED" +ate resume actor "${ACTOR}" -a "${ATESPACE}" >/dev/null +wait_for_state "ACTOR_STATE_RUNNING" || die "actor never reached RUNNING" +if ate pause actor "${ACTOR}" -a "${ATESPACE}" >/dev/null 2>&1; then + wait_for_state "ACTOR_STATE_PAUSED" || die "actor never reached PAUSED" + PAUSE_NODE="$(actor_field '.status.localSnapshotInfo.nodeVmsWithLocalSnapshots[0]')" + info "paused with a node-local snapshot on ${PAUSE_NODE:-}" + + ate revert actor "${ACTOR}" -a "${ATESPACE}" >/dev/null || fail "RevertActor from PAUSED returned an error" + expect_state "ACTOR_STATE_SUSPENDED" "after revert from PAUSED" + if [[ -z "$(actor_field '.status.localSnapshotInfo.snapshotName')" ]]; then + pass "pause snapshot pointer discarded" + else + fail "pause snapshot pointer survived; resume would restore the discarded execution" + fi + if [[ -n "${PAUSE_NODE}" ]]; then + info "NOTE: the checkpoint bytes on ${PAUSE_NODE} are not pruned yet (see the" + info " commented-out ensureLocalCheckpointsPruned call in workflow_revert.go)." + info " Check with: kubectl debug node/${PAUSE_NODE} -- ls /host/var/lib/ateom-gvisor/actors" + fi +else + info "pause is unavailable for this template; skipping" +fi + +# --- Scenario 4: SUSPENDED is rejected ------------------------------------- + +step "Scenario 4: reverting a SUSPENDED actor is rejected" +expect_state "ACTOR_STATE_SUSPENDED" "before the rejection check" +if REJECT_OUT="$(ate revert actor "${ACTOR}" -a "${ATESPACE}" 2>&1)"; then + fail "RevertActor succeeded on a SUSPENDED actor, want FailedPrecondition" +elif grep -qi 'FailedPrecondition' <<<"${REJECT_OUT}"; then + pass "rejected with FailedPrecondition" +else + fail "rejected, but not with FailedPrecondition: ${REJECT_OUT}" +fi + +# --- Result ---------------------------------------------------------------- + +step "Result" +if (( FAILURES == 0 )); then + printf ' \033[32mall checks passed\033[0m\n' +else + printf ' \033[31m%d check(s) failed\033[0m\n' "${FAILURES}" + exit 1 +fi From 7200dde8228b5e94889cda65f5ba41a6f4a46641 Mon Sep 17 00:00:00 2001 From: shrutiyam-glitch Date: Wed, 16 Sep 2026 12:09:25 -0700 Subject: [PATCH 06/14] Fix test --- cmd/ateapi/internal/controlapi/workflow_delete_test.go | 1 + pkg/proto/ateapipb/ateapi.pb.go | 9 +++++++-- pkg/proto/ateapipb/ateapi.proto | 5 +++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/cmd/ateapi/internal/controlapi/workflow_delete_test.go b/cmd/ateapi/internal/controlapi/workflow_delete_test.go index c54c4c1098..d873fb9f25 100644 --- a/cmd/ateapi/internal/controlapi/workflow_delete_test.go +++ b/cmd/ateapi/internal/controlapi/workflow_delete_test.go @@ -169,6 +169,7 @@ func TestEnsureMarkedDeleting_StateMatrix(t *testing.T) { ateapipb.ActorState_ACTOR_STATE_PAUSED: true, ateapipb.ActorState_ACTOR_STATE_SUSPENDED: true, ateapipb.ActorState_ACTOR_STATE_CRASHED: true, + ateapipb.ActorState_ACTOR_STATE_REVERTING: true, ateapipb.ActorState_ACTOR_STATE_DELETING: true, // skipped }, }, diff --git a/pkg/proto/ateapipb/ateapi.pb.go b/pkg/proto/ateapipb/ateapi.pb.go index fdd966e63d..1a0ad64393 100644 --- a/pkg/proto/ateapipb/ateapi.pb.go +++ b/pkg/proto/ateapipb/ateapi.pb.go @@ -4627,8 +4627,10 @@ func (x *ResumeActorResponse) GetResumed() bool { return false } +// RevertActorRequest identifies the Actor to revert. type RevertActorRequest struct { state protoimpl.MessageState `protogen:"open.v1"` + // actor to revert. // +k8s:required // +k8s:subfield(atespace)=+k8s:required Actor *ObjectRef `protobuf:"bytes,1,opt,name=actor,proto3" json:"actor,omitempty"` @@ -4673,9 +4675,12 @@ func (x *RevertActorRequest) GetActor() *ObjectRef { return nil } +// RevertActorResponse holds the reverted Actor. type RevertActorResponse struct { - state protoimpl.MessageState `protogen:"open.v1"` - Actor *Actor `protobuf:"bytes,1,opt,name=actor,proto3" json:"actor,omitempty"` + state protoimpl.MessageState `protogen:"open.v1"` + // actor as it stands after the revert, SUSPENDED and still holding the + // external snapshot it was reverted to. + Actor *Actor `protobuf:"bytes,1,opt,name=actor,proto3" json:"actor,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } diff --git a/pkg/proto/ateapipb/ateapi.proto b/pkg/proto/ateapipb/ateapi.proto index ae1351e95b..d17665bb64 100644 --- a/pkg/proto/ateapipb/ateapi.proto +++ b/pkg/proto/ateapipb/ateapi.proto @@ -1396,13 +1396,18 @@ message ResumeActorResponse { bool resumed = 2; } +// RevertActorRequest identifies the Actor to revert. message RevertActorRequest { + // actor to revert. // +k8s:required // +k8s:subfield(atespace)=+k8s:required ObjectRef actor = 1; } +// RevertActorResponse holds the reverted Actor. message RevertActorResponse { + // actor as it stands after the revert, SUSPENDED and still holding the + // external snapshot it was reverted to. Actor actor = 1; } From c23daeacf4e884557c0b9b2842adfede4867fe16 Mon Sep 17 00:00:00 2001 From: shrutiyam-glitch Date: Wed, 16 Sep 2026 14:31:57 -0700 Subject: [PATCH 07/14] Add e2e test --- internal/e2e/suites/demo/demo_test.go | 228 ++++++++++++++++++++++++++ 1 file changed, 228 insertions(+) diff --git a/internal/e2e/suites/demo/demo_test.go b/internal/e2e/suites/demo/demo_test.go index 392128152f..603583278a 100644 --- a/internal/e2e/suites/demo/demo_test.go +++ b/internal/e2e/suites/demo/demo_test.go @@ -75,6 +75,10 @@ func TestActorLifecycle(t *testing.T) { name: "DeletePausedActorAnyState", f: deletePausedActorAnyState, }, + { + name: "RevertResumeActor", + f: revertActor, + }, } for _, tc := range tests { @@ -917,6 +921,129 @@ func suspendActor(ctx context.Context, t *testing.T, clients *e2e.Clients, nsObj return nil } +func revertActor(ctx context.Context, t *testing.T, clients *e2e.Clients, nsObj *e2e.Namespace, at *ateapipb.ActorTemplate) error { + actorName := "revert-actor-" + nsObj.Name + actorRef := &ateapipb.ObjectRef{Atespace: demoAtespace, Name: actorName} + t.Cleanup(func() { + cleanupCtx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + defer cancel() + _, _ = clients.SubstrateAPI.DeleteActor(cleanupCtx, &ateapipb.DeleteActorRequest{Actor: actorRef, AnyState: true}) + }) + + if _, err := clients.SubstrateAPI.CreateActor(ctx, &ateapipb.CreateActorRequest{Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: demoAtespace, Name: actorName}, + ActorTemplate: e2e.TemplateRef(at), + }}); err != nil { + t.Fatalf("failed to create Actor: %v", err) + } + waitForActorState(ctx, t, clients, actorName, ateapipb.ActorState_ACTOR_STATE_SUSPENDED) + + if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapipb.ResumeActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("failed to resume Actor: %v", err) + } + waitForActorState(ctx, t, clients, actorName, ateapipb.ActorState_ACTOR_STATE_RUNNING) + + resp, err := callActor(t, resources.ActorRef{Atespace: demoAtespace, Name: actorName}) + if err != nil { + t.Fatalf("failed to call actor: %v", err) + } + validateCounterResponse(t, resp, "before snapshot", 1, 1) + + suspended, err := clients.SubstrateAPI.SuspendActor(ctx, &ateapipb.SuspendActorRequest{Actor: actorRef}) + if err != nil { + t.Fatalf("failed to suspend Actor: %v", err) + } + snapshotURI := suspended.GetActor().GetStatus().GetExternalSnapshot().GetSnapshotUri() + if snapshotURI == "" { + t.Fatal("suspend wrote no external snapshot") + } + + // Mutate guest state after the snapshot, then revert from RUNNING: the + // increment to 2 must be discarded and the snapshot left untouched. + if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapipb.ResumeActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("failed to resume Actor after suspend: %v", err) + } + waitForActorState(ctx, t, clients, actorName, ateapipb.ActorState_ACTOR_STATE_RUNNING) + + resp, err = callActor(t, resources.ActorRef{Atespace: demoAtespace, Name: actorName}) + if err != nil { + t.Fatalf("failed to call actor before revert: %v", err) + } + validateCounterResponse(t, resp, "before revert from RUNNING", 2, 2) + + reverted, err := clients.SubstrateAPI.RevertActor(ctx, &ateapipb.RevertActorRequest{Actor: actorRef}) + if err != nil { + t.Fatalf("RevertActor from RUNNING: %v", err) + } + if got := reverted.GetActor().GetStatus().GetState(); got != ateapipb.ActorState_ACTOR_STATE_SUSPENDED { + t.Fatalf("state after revert = %v, want SUSPENDED", got) + } + if got := reverted.GetActor().GetStatus().GetExternalSnapshot().GetSnapshotUri(); got != snapshotURI { + t.Fatalf("snapshot URI after revert = %q, want %q", got, snapshotURI) + } + if reverted.GetActor().GetStatus().GetWorkerAssignment() != nil { + t.Fatal("worker assignment survived revert") + } + + // Resuming proves the guest restored from the count=1 snapshot rather than + // continuing from count=2: this call increments from 1 to 2, not from 2 to 3. + if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapipb.ResumeActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("failed to resume Actor after revert: %v", err) + } + waitForActorState(ctx, t, clients, actorName, ateapipb.ActorState_ACTOR_STATE_RUNNING) + + resp, err = callActor(t, resources.ActorRef{Atespace: demoAtespace, Name: actorName}) + if err != nil { + t.Fatalf("failed to call actor after revert: %v", err) + } + validateCounterResponse(t, resp, "after revert from RUNNING", 2, 2) + + // Revert from PAUSED. Resume prefers a local snapshot over the external + // one, so clearing LocalSnapshotInfo is what prevents this pause's count=2 + // checkpoint from restoring on the next resume. + if _, err := clients.SubstrateAPI.PauseActor(ctx, &ateapipb.PauseActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("failed to pause Actor: %v", err) + } + waitForActorState(ctx, t, clients, actorName, ateapipb.ActorState_ACTOR_STATE_PAUSED) + + reverted, err = clients.SubstrateAPI.RevertActor(ctx, &ateapipb.RevertActorRequest{Actor: actorRef}) + if err != nil { + t.Fatalf("RevertActor from PAUSED: %v", err) + } + if got := reverted.GetActor().GetStatus().GetState(); got != ateapipb.ActorState_ACTOR_STATE_SUSPENDED { + t.Fatalf("state after revert from PAUSED = %v, want SUSPENDED", got) + } + if reverted.GetActor().GetStatus().GetLocalSnapshotInfo() != nil { + t.Fatal("local snapshot pointer survived revert from PAUSED") + } + if got := reverted.GetActor().GetStatus().GetExternalSnapshot().GetSnapshotUri(); got != snapshotURI { + t.Fatalf("snapshot URI after revert from PAUSED = %q, want %q", got, snapshotURI) + } + + // SUSPENDED is rejected with FailedPrecondition rather than no-oping. + if _, err := clients.SubstrateAPI.RevertActor(ctx, &ateapipb.RevertActorRequest{Actor: actorRef}); status.Code(err) != codes.FailedPrecondition { + t.Fatalf("RevertActor from SUSPENDED: got %v, want FailedPrecondition", err) + } + + // Final resume: if the pause checkpoint had been restored, the counter + // would advance from 2 to 3. Expecting 2 proves the external snapshot won. + if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapipb.ResumeActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("failed to resume Actor after PAUSED revert: %v", err) + } + waitForActorState(ctx, t, clients, actorName, ateapipb.ActorState_ACTOR_STATE_RUNNING) + + resp, err = callActor(t, resources.ActorRef{Atespace: demoAtespace, Name: actorName}) + if err != nil { + t.Fatalf("failed to call actor after PAUSED revert: %v", err) + } + validateCounterResponse(t, resp, "after revert from PAUSED", 2, 2) + + if _, err := clients.SubstrateAPI.DeleteActor(ctx, &ateapipb.DeleteActorRequest{Actor: actorRef, AnyState: true}); err != nil { + t.Fatalf("failed to delete Actor: %v", err) + } + return nil +} + func deleteActorAnyState(ctx context.Context, t *testing.T, clients *e2e.Clients, nsObj *e2e.Namespace, at *ateapipb.ActorTemplate) error { actorName := "anystate-delete-actor-" + nsObj.Name @@ -1416,3 +1543,104 @@ func TestWorkerPodDeletion(t *testing.T) { t.Errorf("worker for pod %s/%s was not cleaned up within 30s. Current workers: %v", podNamespace, podName, lastWorkers) } + +func TestRevertCrashedActor(t *testing.T) { + nsObj := e2e.CreateNamespace(t) + ctx := context.Background() + clients := e2e.GetClients() + + at, err := createActorTemplate(ctx, t, clients, nsObj, ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_FULL, ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_FULL, ateapipb.ResumeSource_RESUME_SOURCE_COLD_BOOT) + if err != nil { + t.Fatalf("failed to initialize ActorTemplate: %v", err) + } + + actorName := "revert-crash-actor-" + nsObj.Name + actorRef := &ateapipb.ObjectRef{Atespace: demoAtespace, Name: actorName} + t.Cleanup(func() { + cleanupCtx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + defer cancel() + _, _ = clients.SubstrateAPI.DeleteActor(cleanupCtx, &ateapipb.DeleteActorRequest{Actor: actorRef, AnyState: true}) + }) + + if _, err := clients.SubstrateAPI.CreateActor(ctx, &ateapipb.CreateActorRequest{Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: demoAtespace, Name: actorName}, + ActorTemplate: e2e.TemplateRef(at), + }}); err != nil { + t.Fatalf("failed to create Actor: %v", err) + } + waitForActorState(ctx, t, clients, actorName, ateapipb.ActorState_ACTOR_STATE_SUSPENDED) + + if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapipb.ResumeActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("failed to resume Actor: %v", err) + } + waitForActorState(ctx, t, clients, actorName, ateapipb.ActorState_ACTOR_STATE_RUNNING) + + resp, err := callActor(t, resources.ActorRef{Atespace: demoAtespace, Name: actorName}) + if err != nil { + t.Fatalf("failed to call actor: %v", err) + } + validateCounterResponse(t, resp, "before snapshot", 1, 1) + + suspended, err := clients.SubstrateAPI.SuspendActor(ctx, &ateapipb.SuspendActorRequest{Actor: actorRef}) + if err != nil { + t.Fatalf("failed to suspend Actor: %v", err) + } + snapshotURI := suspended.GetActor().GetStatus().GetExternalSnapshot().GetSnapshotUri() + if snapshotURI == "" { + t.Fatal("suspend wrote no external snapshot") + } + + if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapipb.ResumeActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("failed to resume Actor after suspend: %v", err) + } + waitForActorState(ctx, t, clients, actorName, ateapipb.ActorState_ACTOR_STATE_RUNNING) + + resp, err = callActor(t, resources.ActorRef{Atespace: demoAtespace, Name: actorName}) + if err != nil { + t.Fatalf("failed to call actor before crash: %v", err) + } + validateCounterResponse(t, resp, "before crash", 2, 2) + + actor, err := clients.SubstrateAPI.GetActor(ctx, &ateapipb.GetActorRequest{Actor: actorRef}) + if err != nil { + t.Fatalf("failed to get Actor: %v", err) + } + podName := actor.GetStatus().GetWorkerAssignment().GetWorkerPod() + podNamespace := actor.GetStatus().GetWorkerAssignment().GetWorkerNamespace() + if podName == "" || podNamespace == "" { + t.Fatalf("running actor has no pod recorded: %v", actor.GetStatus().GetWorkerAssignment()) + } + + // Deleting the pod is how a real crash happens: releaseBoundActor marks the + // actor CRASHED and clears its assignment, leaving revert with no worker to + // terminate through. + if err := clients.K8s.CoreV1().Pods(podNamespace).Delete(ctx, podName, metav1.DeleteOptions{}); err != nil { + t.Fatalf("failed to delete worker pod %s/%s: %v", podNamespace, podName, err) + } + waitForActorState(ctx, t, clients, actorName, ateapipb.ActorState_ACTOR_STATE_CRASHED) + + reverted, err := clients.SubstrateAPI.RevertActor(ctx, &ateapipb.RevertActorRequest{Actor: actorRef}) + if err != nil { + t.Fatalf("RevertActor from CRASHED: %v", err) + } + if got := reverted.GetActor().GetStatus().GetState(); got != ateapipb.ActorState_ACTOR_STATE_SUSPENDED { + t.Fatalf("state after revert = %v, want SUSPENDED", got) + } + if got := reverted.GetActor().GetStatus().GetExternalSnapshot().GetSnapshotUri(); got != snapshotURI { + t.Fatalf("snapshot URI after revert = %q, want %q", got, snapshotURI) + } + if reverted.GetActor().GetStatus().GetWorkerAssignment() != nil { + t.Fatal("worker assignment survived revert") + } + + if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapipb.ResumeActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("failed to resume crashed-and-reverted Actor: %v", err) + } + waitForActorState(ctx, t, clients, actorName, ateapipb.ActorState_ACTOR_STATE_RUNNING) + + resp, err = callActor(t, resources.ActorRef{Atespace: demoAtespace, Name: actorName}) + if err != nil { + t.Fatalf("failed to call actor after recovery: %v", err) + } + validateCounterResponse(t, resp, "after recovery from CRASHED", 2, 2) +} From a66fe23d9145109345420e407e40dd447697cf5a Mon Sep 17 00:00:00 2001 From: shrutiyam-glitch Date: Wed, 16 Sep 2026 16:07:34 -0700 Subject: [PATCH 08/14] Add RevertActor functional tests for PAUSED and CRASHED actors Add TestRevertActor_FromPaused and TestRevertActor_FromCrashed to verify RevertActor recovers paused and crashed actors to SUSPENDED at their last external snapshot and allows subsequent resumes --- .../controlapi/functionaltest/actor_test.go | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) diff --git a/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go b/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go index dbf0f4d9ec..3f97ae1292 100644 --- a/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go +++ b/cmd/ateapi/internal/controlapi/functionaltest/actor_test.go @@ -3586,6 +3586,165 @@ func TestRevertActor(t *testing.T) { } } +// TestRevertActor_FromPaused reverts a paused actor back to its external +// snapshot, discarding the local pause snapshot info on the actor record. +func TestRevertActor_FromPaused(t *testing.T) { + ns := namespaceForTest("ns-revert-paused") + tc := setupTest(t, ns) + defer tc.cleanup() + + createTemplate(t, tc, ns) + workerName := createWorkerPod(t, tc, ns, "worker-1", "node1", "pool1") + + ctx := context.Background() + const name = "id1" + actorRef := &ateapipb.ObjectRef{Atespace: testAtespace, Name: name} + + if _, err := tc.client.CreateActor(ctx, &ateapipb.CreateActorRequest{Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: name}, + ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"}, + }}); err != nil { + t.Fatalf("CreateActor failed: %v", err) + } + + if _, err := tc.client.ResumeActor(ctx, &ateapipb.ResumeActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("ResumeActor failed: %v", err) + } + suspended, err := tc.client.SuspendActor(ctx, &ateapipb.SuspendActorRequest{Actor: actorRef}) + if err != nil { + t.Fatalf("SuspendActor failed: %v", err) + } + waitForWorkerAvailable(t, tc, workerName) + snapshotURI := suspended.GetActor().GetStatus().GetExternalSnapshot().GetSnapshotUri() + if snapshotURI == "" { + t.Fatalf("SuspendActor wrote no external snapshot: %v", suspended) + } + + if _, err := tc.client.ResumeActor(ctx, &ateapipb.ResumeActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("second ResumeActor failed: %v", err) + } + if _, err := tc.client.PauseActor(ctx, &ateapipb.PauseActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("PauseActor failed: %v", err) + } + waitForWorkerAvailable(t, tc, workerName) + tc.fakeAtelet.Lock.Lock() + tc.fakeAtelet.TerminateCalled = false + tc.fakeAtelet.CheckpointCalled = false + tc.fakeAtelet.Lock.Unlock() + + reverted, err := tc.client.RevertActor(ctx, &ateapipb.RevertActorRequest{Actor: actorRef}) + if err != nil { + t.Fatalf("RevertActor failed: %v", err) + } + + got := reverted.GetActor().GetStatus() + if got.GetState() != ateapipb.ActorState_ACTOR_STATE_SUSPENDED { + t.Errorf("state = %v, want SUSPENDED", got.GetState()) + } + if uri := got.GetExternalSnapshot().GetSnapshotUri(); uri != snapshotURI { + t.Errorf("external snapshot = %q, want it untouched at %q", uri, snapshotURI) + } + assertSnapshotPresent(t, tc, snapshotURI) + if got.GetLocalSnapshotInfo() != nil { + t.Errorf("local snapshot info = %v, want nil", got.GetLocalSnapshotInfo()) + } + if got.GetWorkerAssignment() != nil { + t.Errorf("worker assignment = %v, want nil", got.GetWorkerAssignment()) + } + if tc.fakeAtelet.TerminateCalled { + t.Errorf("unexpected Terminate call for paused actor") + } + if tc.fakeAtelet.CheckpointCalled { + t.Errorf("RevertActor checkpointed the workload, want the execution discarded") + } +} + +// TestRevertActor_FromCrashed recovers a crashed actor back to SUSPENDED at its +// last external snapshot so it can be resumed again. +func TestRevertActor_FromCrashed(t *testing.T) { + ns := namespaceForTest("ns-revert-crashed") + tc := setupTest(t, ns) + defer tc.cleanup() + + createTemplate(t, tc, ns) + workerName := createWorkerPod(t, tc, ns, "worker-1", "node1", "pool1") + + ctx := context.Background() + const name = "id1" + actorRef := &ateapipb.ObjectRef{Atespace: testAtespace, Name: name} + + if _, err := tc.client.CreateActor(ctx, &ateapipb.CreateActorRequest{Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: name}, + ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"}, + }}); err != nil { + t.Fatalf("CreateActor failed: %v", err) + } + + if _, err := tc.client.ResumeActor(ctx, &ateapipb.ResumeActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("ResumeActor failed: %v", err) + } + suspended, err := tc.client.SuspendActor(ctx, &ateapipb.SuspendActorRequest{Actor: actorRef}) + if err != nil { + t.Fatalf("SuspendActor failed: %v", err) + } + waitForWorkerAvailable(t, tc, workerName) + snapshotURI := suspended.GetActor().GetStatus().GetExternalSnapshot().GetSnapshotUri() + if snapshotURI == "" { + t.Fatalf("SuspendActor wrote no external snapshot: %v", suspended) + } + + // Resume onto worker-1, then delete the worker pod so the actor crashes. + if _, err := tc.client.ResumeActor(ctx, &ateapipb.ResumeActorRequest{Actor: actorRef}); err != nil { + t.Fatalf("second ResumeActor failed: %v", err) + } + deleteWorkerPod(t, tc, ns, "worker-1") + + crashed, err := tc.client.GetActor(ctx, &ateapipb.GetActorRequest{Actor: actorRef}) + if err != nil { + t.Fatalf("GetActor failed: %v", err) + } + if crashed.GetStatus().GetState() != ateapipb.ActorState_ACTOR_STATE_CRASHED { + t.Fatalf("state = %v, want CRASHED", crashed.GetStatus().GetState()) + } + tc.fakeAtelet.Lock.Lock() + tc.fakeAtelet.TerminateCalled = false + tc.fakeAtelet.CheckpointCalled = false + tc.fakeAtelet.Lock.Unlock() + + reverted, err := tc.client.RevertActor(ctx, &ateapipb.RevertActorRequest{Actor: actorRef}) + if err != nil { + t.Fatalf("RevertActor from CRASHED failed: %v", err) + } + + got := reverted.GetActor().GetStatus() + if got.GetState() != ateapipb.ActorState_ACTOR_STATE_SUSPENDED { + t.Errorf("state = %v, want SUSPENDED", got.GetState()) + } + if uri := got.GetExternalSnapshot().GetSnapshotUri(); uri != snapshotURI { + t.Errorf("external snapshot = %q, want it untouched at %q", uri, snapshotURI) + } + assertSnapshotPresent(t, tc, snapshotURI) + if got.GetWorkerAssignment() != nil { + t.Errorf("worker assignment = %v, want nil", got.GetWorkerAssignment()) + } + if tc.fakeAtelet.TerminateCalled { + t.Errorf("unexpected Terminate call for crashed actor with no worker") + } + if tc.fakeAtelet.CheckpointCalled { + t.Errorf("RevertActor checkpointed the workload, want the execution discarded") + } + + // Verify the recovered actor can be resumed onto a new worker. + createWorkerPod(t, tc, ns, "worker-2", "node1", "pool1") + resumed, err := tc.client.ResumeActor(ctx, &ateapipb.ResumeActorRequest{Actor: actorRef}) + if err != nil { + t.Fatalf("ResumeActor after revert from CRASHED failed: %v", err) + } + if resumed.GetActor().GetStatus().GetState() != ateapipb.ActorState_ACTOR_STATE_RUNNING { + t.Errorf("resumed state = %v, want RUNNING", resumed.GetActor().GetStatus().GetState()) + } +} + // TestRevertActor_RejectsSuspended pins the rejection a lost race produces: a // suspend that won left the actor SUSPENDED, and reporting success there would // claim the opposite of what the revert asked for. From e0571bd30e24642e17a85b198f53af4d6e0835d4 Mon Sep 17 00:00:00 2001 From: shrutiyam-glitch Date: Wed, 16 Sep 2026 17:01:58 -0700 Subject: [PATCH 09/14] Rename ensureInProgressSnapshotCollected to ensureInProgressSnapshotDiscarded Align function, trace span, and test names with revert semantics of discarding rather than collecting in-progress snapshots, and clarify local checkpoint pruning behavior during revert. --- .../internal/controlapi/workflow_revert.go | 8 +++--- .../controlapi/workflow_revert_test.go | 28 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/cmd/ateapi/internal/controlapi/workflow_revert.go b/cmd/ateapi/internal/controlapi/workflow_revert.go index 25a9c846eb..af467eb7db 100644 --- a/cmd/ateapi/internal/controlapi/workflow_revert.go +++ b/cmd/ateapi/internal/controlapi/workflow_revert.go @@ -84,7 +84,7 @@ func (w *ActorWorkflow) RevertActor(ctx context.Context, actorRef resources.Acto return nil, err } - if err = w.ensureInProgressSnapshotCollected(leaseCtx, actor, actorTemplate); err != nil { + if err = w.ensureInProgressSnapshotDiscarded(leaseCtx, actor, actorTemplate); err != nil { return nil, err } @@ -192,10 +192,10 @@ func (w *ActorWorkflow) ensureWorkerDiscarded(ctx context.Context, actorRef reso return w.releaseAssignmentWithoutBacklink(ctx, actor) } -// ensureInProgressSnapshotCollected deletes the objects a suspend was partway +// ensureInProgressSnapshotDiscarded deletes the objects a suspend was partway // through writing when the actor was reverted. -func (w *ActorWorkflow) ensureInProgressSnapshotCollected(ctx context.Context, actor *ateapipb.Actor, actorTemplate *ateapipb.ActorTemplate) (err error) { - ctx, done := stepSpan(ctx, "CollectInProgressSnapshot") +func (w *ActorWorkflow) ensureInProgressSnapshotDiscarded(ctx context.Context, actor *ateapipb.Actor, actorTemplate *ateapipb.ActorTemplate) (err error) { + ctx, done := stepSpan(ctx, "DiscardInProgressSnapshot") defer func() { err = done(err) }() name := actor.GetStatus().GetInProgressSnapshotName() diff --git a/cmd/ateapi/internal/controlapi/workflow_revert_test.go b/cmd/ateapi/internal/controlapi/workflow_revert_test.go index d425eb0be7..9440bcb640 100644 --- a/cmd/ateapi/internal/controlapi/workflow_revert_test.go +++ b/cmd/ateapi/internal/controlapi/workflow_revert_test.go @@ -217,11 +217,11 @@ func TestRevertActor_NoSnapshotToRevertTo(t *testing.T) { } } -// TestEnsureInProgressSnapshotCollected covers what a revert deletes from +// TestEnsureInProgressSnapshotDiscarded covers what a revert deletes from // object storage and, more importantly, what it must not. Delete drops the // actor's whole prefix; revert cannot, because the snapshot it is returning the // actor to lives under that same prefix. -func TestEnsureInProgressSnapshotCollected(t *testing.T) { +func TestEnsureInProgressSnapshotDiscarded(t *testing.T) { const inFlightSnapshotName = "2026-01-01t00-00-00z-abandoned" tests := []struct { @@ -234,12 +234,12 @@ func TestEnsureInProgressSnapshotCollected(t *testing.T) { // missingTemplate drops the template, leaving no way to derive the // prefix: the objects leak rather than wedging the actor. missingTemplate bool - wantInFlightCollected bool + wantInFlightDiscarded bool }{ { - name: "collects the snapshot an interrupted suspend was writing", + name: "discards the snapshot an interrupted suspend was writing", inFlight: inFlightSnapshotName, - wantInFlightCollected: true, + wantInFlightDiscarded: true, }, { name: "leaves the actor's own external snapshot in place", @@ -249,13 +249,13 @@ func TestEnsureInProgressSnapshotCollected(t *testing.T) { name: "leaves a snapshot borrowed from a tag in place", tagOwnedSnapshot: true, inFlight: inFlightSnapshotName, - wantInFlightCollected: true, + wantInFlightDiscarded: true, }, { name: "leaks rather than wedges when the template is gone", inFlight: inFlightSnapshotName, missingTemplate: true, - wantInFlightCollected: false, + wantInFlightDiscarded: false, }, } @@ -292,8 +292,8 @@ func TestEnsureInProgressSnapshotCollected(t *testing.T) { if tt.missingTemplate { passedTemplate = nil } - if err := w.ensureInProgressSnapshotCollected(ctx, actor, passedTemplate); err != nil { - t.Fatalf("ensureInProgressSnapshotCollected: %v", err) + if err := w.ensureInProgressSnapshotDiscarded(ctx, actor, passedTemplate); err != nil { + t.Fatalf("ensureInProgressSnapshotDiscarded: %v", err) } // The whole point: whatever else happens, the snapshot the actor @@ -302,9 +302,9 @@ func TestEnsureInProgressSnapshotCollected(t *testing.T) { t.Errorf("external snapshot %v was collected, but revert must preserve it", current) } if tt.inFlight != "" { - collected := len(objects.Snapshot(t, inFlight)) == 0 - if collected != tt.wantInFlightCollected { - t.Errorf("in-flight snapshot collected = %v, want %v", collected, tt.wantInFlightCollected) + discarded := len(objects.Snapshot(t, inFlight)) == 0 + if discarded != tt.wantInFlightDiscarded { + t.Errorf("in-flight snapshot discarded = %v, want %v", discarded, tt.wantInFlightDiscarded) } } }) @@ -328,8 +328,8 @@ func TestEnsureRevertedFinalized_NoObjectStore(t *testing.T) { }, }) - if err := w.ensureInProgressSnapshotCollected(ctx, actor, nil); err != nil { - t.Fatalf("ensureInProgressSnapshotCollected: %v", err) + if err := w.ensureInProgressSnapshotDiscarded(ctx, actor, nil); err != nil { + t.Fatalf("ensureInProgressSnapshotDiscarded: %v", err) } actorRef := resources.ActorRefFromActor(actor) From 1ab72ff87d648d4d0d26094706406b7f5a5fc603 Mon Sep 17 00:00:00 2001 From: shrutiyam-glitch Date: Wed, 16 Sep 2026 17:34:03 -0700 Subject: [PATCH 10/14] Discard the in-progress snapshot by its recorded URI The in-progress snapshot is now recorded as a full URI rather than a name derived from the actor's template, so revert reads the URI directly and no longer needs the template to find the objects. Check that the URI is owned by the actor before deleting its prefix. Derivation used to make that structural; a stored URI can name anything, and this step deletes what it is pointed at. --- .../internal/controlapi/workflow_revert.go | 31 +++++------ .../controlapi/workflow_revert_test.go | 52 ++++++++++++------- 2 files changed, 48 insertions(+), 35 deletions(-) diff --git a/cmd/ateapi/internal/controlapi/workflow_revert.go b/cmd/ateapi/internal/controlapi/workflow_revert.go index af467eb7db..fb7c857820 100644 --- a/cmd/ateapi/internal/controlapi/workflow_revert.go +++ b/cmd/ateapi/internal/controlapi/workflow_revert.go @@ -84,7 +84,7 @@ func (w *ActorWorkflow) RevertActor(ctx context.Context, actorRef resources.Acto return nil, err } - if err = w.ensureInProgressSnapshotDiscarded(leaseCtx, actor, actorTemplate); err != nil { + if err = w.ensureInProgressSnapshotDiscarded(leaseCtx, actor); err != nil { return nil, err } @@ -194,32 +194,33 @@ func (w *ActorWorkflow) ensureWorkerDiscarded(ctx context.Context, actorRef reso // ensureInProgressSnapshotDiscarded deletes the objects a suspend was partway // through writing when the actor was reverted. -func (w *ActorWorkflow) ensureInProgressSnapshotDiscarded(ctx context.Context, actor *ateapipb.Actor, actorTemplate *ateapipb.ActorTemplate) (err error) { +func (w *ActorWorkflow) ensureInProgressSnapshotDiscarded(ctx context.Context, actor *ateapipb.Actor) (err error) { ctx, done := stepSpan(ctx, "DiscardInProgressSnapshot") defer func() { err = done(err) }() - name := actor.GetStatus().GetInProgressSnapshotName() + inProgress := actor.GetStatus().GetInProgressSnapshotUri() switch { case w.objectStore == nil: markSkipped(ctx, "no object store configured") return nil - case name == "": + case inProgress == "": markSkipped(ctx, "no in-progress snapshot recorded") return nil - case actorTemplate == nil: - // The template's storage location is the only place the prefix can be - // derived from. Refusing here would leave the actor REVERTING forever - // TODO: prevent this from leaking objects in the external storage. - slog.WarnContext(ctx, "Leaking an in-progress external snapshot, the actor's template no longer resolves", - slog.String("actor", actor.GetMetadata().GetName()), - slog.String("in_progress_snapshot_name", name)) - return nil } - uri, err := inProgressSnapshotURI(actorTemplate, actor, name) + uri, err := resources.ParseSnapshotURI(inProgress) if err != nil { - return err + return fmt.Errorf("while parsing the in-progress snapshot %q: %w", inProgress, err) + } + // A suspend records the in-progress URI under the actor's own prefix + // before atelet writes the first object, so a URI owned by anything else + // is a corrupted record: deleting it would collect another actor's data. + owner := actorSnapshotOwner(actor) + if !uri.OwnedBy(owner) { + return fmt.Errorf("the in-progress snapshot %q is not owned by actor %s", inProgress, owner) } + // Only the abandoned snapshot goes, not the actor's whole prefix: the + // external snapshot the revert returns the actor to lives under it too. return objectstore.DeletePrefix(ctx, w.objectStore, uri.Prefix()) } @@ -239,7 +240,7 @@ func (w *ActorWorkflow) ensureRevertedFinalized(ctx context.Context, actorRef re storedActor, err := w.store.UpdateActor(ctx, actorRef, store.PreconditionFrom(latestActor), func(toUpdate *ateapipb.Actor) error { toUpdate.Status.State = ateapipb.ActorState_ACTOR_STATE_SUSPENDED toUpdate.Status.WorkerAssignment = nil - toUpdate.Status.InProgressSnapshotName = "" + toUpdate.Status.InProgressSnapshotUri = "" toUpdate.Status.InProgressLocalSnapshotName = "" toUpdate.Status.LocalSnapshotInfo = nil return nil diff --git a/cmd/ateapi/internal/controlapi/workflow_revert_test.go b/cmd/ateapi/internal/controlapi/workflow_revert_test.go index 9440bcb640..4bb9eee9b4 100644 --- a/cmd/ateapi/internal/controlapi/workflow_revert_test.go +++ b/cmd/ateapi/internal/controlapi/workflow_revert_test.go @@ -121,8 +121,8 @@ func TestRevertActor_ReturnsActorToItsSnapshot(t *testing.T) { if got := gotStatus.GetLocalSnapshotInfo(); got != nil { t.Errorf("local snapshot info = %v, want nil", got) } - if got := gotStatus.GetInProgressSnapshotName(); got != "" { - t.Errorf("in-progress snapshot name = %q, want empty", got) + if got := gotStatus.GetInProgressSnapshotUri(); got != "" { + t.Errorf("in-progress snapshot uri = %q, want empty", got) } if got := gotStatus.GetInProgressLocalSnapshotName(); got != "" { t.Errorf("in-progress local snapshot name = %q, want empty", got) @@ -231,10 +231,11 @@ func TestEnsureInProgressSnapshotDiscarded(t *testing.T) { tagOwnedSnapshot bool // inFlight names a snapshot the interrupted suspend was writing. inFlight string - // missingTemplate drops the template, leaving no way to derive the - // prefix: the objects leak rather than wedging the actor. - missingTemplate bool + // foreignInFlight records the in-progress snapshot under another + // owner's prefix, which no suspend can produce. + foreignInFlight bool wantInFlightDiscarded bool + wantErr bool }{ { name: "discards the snapshot an interrupted suspend was writing", @@ -252,10 +253,10 @@ func TestEnsureInProgressSnapshotDiscarded(t *testing.T) { wantInFlightDiscarded: true, }, { - name: "leaks rather than wedges when the template is gone", - inFlight: inFlightSnapshotName, - missingTemplate: true, - wantInFlightDiscarded: false, + name: "refuses an in-progress snapshot the actor does not own", + inFlight: inFlightSnapshotName, + foreignInFlight: true, + wantErr: true, }, } @@ -280,19 +281,30 @@ func TestEnsureInProgressSnapshotDiscarded(t *testing.T) { } objects.PutSnapshot(t, current, "manifest.json") inFlight := mustActorSnapshotURI(t, template, actor, inFlightSnapshotName) + if tt.foreignInFlight { + inFlight = mustTagSnapshotURI(t, template, "team-a", "someone-elses-snapshot") + } if tt.inFlight != "" { objects.PutSnapshot(t, inFlight, "manifest.json") } actor = mustUpdateActorStatus(t, ctx, persistence, actor, func(s *ateapipb.ActorStatus) { s.ExternalSnapshot = &ateapipb.ExternalSnapshot{SnapshotUri: current.String()} - s.InProgressSnapshotName = tt.inFlight + if tt.inFlight != "" { + s.InProgressSnapshotUri = inFlight.String() + } }) - passedTemplate := template - if tt.missingTemplate { - passedTemplate = nil + err := w.ensureInProgressSnapshotDiscarded(ctx, actor) + if tt.wantErr { + if err == nil { + t.Fatal("ensureInProgressSnapshotDiscarded = nil, want an error for a snapshot the actor does not own") + } + if len(objects.Snapshot(t, inFlight)) == 0 { + t.Errorf("snapshot %v was discarded, but it belongs to another owner", inFlight) + } + return } - if err := w.ensureInProgressSnapshotDiscarded(ctx, actor, passedTemplate); err != nil { + if err != nil { t.Fatalf("ensureInProgressSnapshotDiscarded: %v", err) } @@ -312,7 +324,7 @@ func TestEnsureInProgressSnapshotDiscarded(t *testing.T) { } // TestEnsureRevertedFinalized_NoObjectStore covers a workflow built without an -// object store: the collect step skips instead of failing, so the revert still +// object store: the discard step skips instead of failing, so the revert still // finalizes. func TestEnsureRevertedFinalized_NoObjectStore(t *testing.T) { ctx := context.Background() @@ -323,12 +335,12 @@ func TestEnsureRevertedFinalized_NoObjectStore(t *testing.T) { Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "actor-1"}, ActorTemplate: &ateapipb.ObjectRef{Atespace: "team-a", Name: "sub-tmpl"}, Status: &ateapipb.ActorStatus{ - State: ateapipb.ActorState_ACTOR_STATE_REVERTING, - InProgressSnapshotName: "abandoned", + State: ateapipb.ActorState_ACTOR_STATE_REVERTING, + InProgressSnapshotUri: someActorSnapshotURI(t, testStorageLocation, "team-a", "abandoned"), }, }) - if err := w.ensureInProgressSnapshotDiscarded(ctx, actor, nil); err != nil { + if err := w.ensureInProgressSnapshotDiscarded(ctx, actor); err != nil { t.Fatalf("ensureInProgressSnapshotDiscarded: %v", err) } @@ -340,7 +352,7 @@ func TestEnsureRevertedFinalized_NoObjectStore(t *testing.T) { if got := finalized.GetStatus().GetState(); got != ateapipb.ActorState_ACTOR_STATE_SUSPENDED { t.Errorf("state = %v, want SUSPENDED", got) } - if got := finalized.GetStatus().GetInProgressSnapshotName(); got != "" { - t.Errorf("in-progress snapshot name = %q, want empty", got) + if got := finalized.GetStatus().GetInProgressSnapshotUri(); got != "" { + t.Errorf("in-progress snapshot uri = %q, want empty", got) } } From 71fb584f743ada5dd43ea20e8a2070cc31cd6eaa Mon Sep 17 00:00:00 2001 From: shrutiyam-glitch Date: Thu, 17 Sep 2026 00:15:35 -0700 Subject: [PATCH 11/14] Handle REVERTING in two ActorState switches Adding RevertActor left both unupdated. releaseBoundActor labelled the crash metric with the unknown operation, hiding that a revert was in flight when the worker pod went away. The golden snapshot reconciler fell through to the default branch and requeued forever instead of failing the template. Nothing in the golden flow reverts its actor, so that state means someone else interfered. --- cmd/ateapi/internal/controlapi/template_reconciler.go | 4 ++-- cmd/ateapi/internal/controlapi/workflow_worker_delete.go | 2 ++ cmd/ateapi/internal/controlapi/workflow_worker_delete_test.go | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cmd/ateapi/internal/controlapi/template_reconciler.go b/cmd/ateapi/internal/controlapi/template_reconciler.go index 9d4e7c1728..5d8bd2bf5e 100644 --- a/cmd/ateapi/internal/controlapi/template_reconciler.go +++ b/cmd/ateapi/internal/controlapi/template_reconciler.go @@ -295,8 +295,8 @@ func (r *ActorTemplateReconciler) reconcileOne(ctx context.Context, ref resource }); err != nil { return 0, err } - case ateapipb.ActorState_ACTOR_STATE_DELETING, ateapipb.ActorState_ACTOR_STATE_PAUSED, ateapipb.ActorState_ACTOR_STATE_PAUSING: - // Nothing in the golden flow deletes or pauses the actor before + case ateapipb.ActorState_ACTOR_STATE_DELETING, ateapipb.ActorState_ACTOR_STATE_PAUSED, ateapipb.ActorState_ACTOR_STATE_PAUSING, ateapipb.ActorState_ACTOR_STATE_REVERTING: + // Nothing in the golden flow deletes, pauses, or reverts the actor before // the snapshot is taken; someone else interfered. return 0, r.fail(ctx, tmpl, reasonUnexpectedState, fmt.Sprintf("golden actor in unexpected state %v", state)) diff --git a/cmd/ateapi/internal/controlapi/workflow_worker_delete.go b/cmd/ateapi/internal/controlapi/workflow_worker_delete.go index 677d85cfbc..656bff449d 100644 --- a/cmd/ateapi/internal/controlapi/workflow_worker_delete.go +++ b/cmd/ateapi/internal/controlapi/workflow_worker_delete.go @@ -200,6 +200,8 @@ func (w *WorkerWorkflow) releaseBoundActor(ctx context.Context, worker *ateapipb opName = ateattr.OperationSuspend case ateapipb.ActorState_ACTOR_STATE_PAUSING: opName = ateattr.OperationPause + case ateapipb.ActorState_ACTOR_STATE_REVERTING: + opName = ateattr.OperationRevert } wasAlreadyCrashed := actor.GetStatus().GetState() == ateapipb.ActorState_ACTOR_STATE_CRASHED diff --git a/cmd/ateapi/internal/controlapi/workflow_worker_delete_test.go b/cmd/ateapi/internal/controlapi/workflow_worker_delete_test.go index 1cfecf6ae0..54ec481853 100644 --- a/cmd/ateapi/internal/controlapi/workflow_worker_delete_test.go +++ b/cmd/ateapi/internal/controlapi/workflow_worker_delete_test.go @@ -161,6 +161,7 @@ func TestDeleteWorkerWorkflow_ReleasedActorStateTransitions(t *testing.T) { {name: "resuming becomes crashed", start: ateapipb.ActorState_ACTOR_STATE_RESUMING, wantState: ateapipb.ActorState_ACTOR_STATE_CRASHED, wantOp: ateattr.OperationResume, wantMetric: true}, {name: "suspending becomes crashed", start: ateapipb.ActorState_ACTOR_STATE_SUSPENDING, wantState: ateapipb.ActorState_ACTOR_STATE_CRASHED, wantOp: ateattr.OperationSuspend, wantMetric: true}, {name: "pausing becomes crashed", start: ateapipb.ActorState_ACTOR_STATE_PAUSING, wantState: ateapipb.ActorState_ACTOR_STATE_CRASHED, wantOp: ateattr.OperationPause, wantMetric: true}, + {name: "reverting becomes crashed", start: ateapipb.ActorState_ACTOR_STATE_REVERTING, wantState: ateapipb.ActorState_ACTOR_STATE_CRASHED, wantOp: ateattr.OperationRevert, wantMetric: true}, {name: "suspended stays suspended", start: ateapipb.ActorState_ACTOR_STATE_SUSPENDED, wantState: ateapipb.ActorState_ACTOR_STATE_SUSPENDED, wantMetric: false}, {name: "crashed is not counted twice", start: ateapipb.ActorState_ACTOR_STATE_CRASHED, wantState: ateapipb.ActorState_ACTOR_STATE_CRASHED, wantMetric: false}, } From 02c938e41fbdb9e8c84d9af863580bd3276638a6 Mon Sep 17 00:00:00 2001 From: shrutiyam-glitch Date: Thu, 17 Sep 2026 14:13:49 -0700 Subject: [PATCH 12/14] remove test script --- hack/verify-revert-actor.sh | 292 ------------------------------------ 1 file changed, 292 deletions(-) delete mode 100755 hack/verify-revert-actor.sh diff --git a/hack/verify-revert-actor.sh b/hack/verify-revert-actor.sh deleted file mode 100755 index 3c0a39e161..0000000000 --- a/hack/verify-revert-actor.sh +++ /dev/null @@ -1,292 +0,0 @@ -#!/usr/bin/env bash - -# 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. -# -# Exercises RevertActor against a live cluster. Not part of `make verify`: it -# needs a running control plane, a worker pool with spare capacity, and an -# ActorTemplate whose actors can be resumed and suspended. -# -# The interesting case is revert from CRASHED. A real crash is produced by -# deleting the worker pod the actor is running on: the control plane notices -# the pod is gone, marks the actor CRASHED, and clears its worker assignment. -# That leaves an actor with no worker to talk to, which is exactly the wreck -# revert exists to clean up. -# -# hack/verify-revert-actor.sh --atespace my-space --template my-template -# -# Everything the script creates is torn down on exit unless --keep is passed. - -set -o errexit -set -o nounset -set -o pipefail - -ATE="${ATE:-bin/kubectl-ate}" -ATESPACE="" -TEMPLATE="" -ACTOR="revert-check-$$" -ENDPOINT="${ATE_ENDPOINT:-}" -KEEP="false" -# Deleting a pod, noticing it is gone, and rescheduling all take real time on a -# real cluster; a laptop-speed timeout only produces confusing failures. -TIMEOUT_SECONDS="${ATE_VERIFY_TIMEOUT:-180}" - -usage() { - cat <<'EOF' -Usage: hack/verify-revert-actor.sh --atespace --template [options] - -Required: - --atespace Atespace to create the test actor in. - --template ActorTemplate to derive it from. Must already exist, and - its actors must be resumable on an available worker. - -Options: - --actor Name for the test actor. Default: revert-check-. - --endpoint gRPC target, e.g. localhost:8080. Without this the CLI - port-forwards on every call, which makes the run slow. - --keep Leave the actor behind for inspection. - --timeout Per-wait timeout. Default: 180. - -Environment: - ATE Path to the kubectl-ate binary. Default: bin/kubectl-ate. - ATE_ENDPOINT Same as --endpoint. - ATE_VERIFY_TIMEOUT Same as --timeout. -EOF -} - -while [[ $# -gt 0 ]]; do - case "$1" in - --atespace) ATESPACE="$2"; shift 2 ;; - --template) TEMPLATE="$2"; shift 2 ;; - --actor) ACTOR="$2"; shift 2 ;; - --endpoint) ENDPOINT="$2"; shift 2 ;; - --timeout) TIMEOUT_SECONDS="$2"; shift 2 ;; - --keep) KEEP="true"; shift ;; - -h|--help) usage; exit 0 ;; - *) echo "unknown argument: $1" >&2; usage; exit 2 ;; - esac -done - -if [[ -z "${ATESPACE}" || -z "${TEMPLATE}" ]]; then - echo "--atespace and --template are required" >&2 - usage - exit 2 -fi - -FAILURES=0 - -step() { printf '\n\033[1m==> %s\033[0m\n' "$*"; } -info() { printf ' %s\n' "$*"; } -pass() { printf ' \033[32mPASS\033[0m %s\n' "$*"; } -fail() { printf ' \033[31mFAIL\033[0m %s\n' "$*"; FAILURES=$((FAILURES + 1)); } -die() { printf '\n\033[31m%s\033[0m\n' "$*" >&2; exit 1; } - -ate() { - if [[ -n "${ENDPOINT}" ]]; then - "${ATE}" "$@" --endpoint "${ENDPOINT}" - else - "${ATE}" "$@" - fi -} - -actor_json() { - ate get actor "${ACTOR}" -a "${ATESPACE}" -o json -} - -# actor_field prints one jq path from the actor, empty when protojson omitted -# it. A failed read is also reported as empty: these are called from polling -# loops, where a single blip should cost a retry rather than the whole run. -actor_field() { - local raw - raw="$(actor_json 2>/dev/null)" || return 0 - jq -r "$1 // \"\"" <<<"${raw}" -} - -actor_state() { - actor_field '.status.state' -} - -expect_state() { - local want="$1" context="$2" got - got="$(actor_state)" - if [[ "${got}" == "${want}" ]]; then - pass "${context}: state is ${want}" - else - fail "${context}: state is ${got}, want ${want}" - fi -} - -wait_for_state() { - local want="$1" deadline=$((SECONDS + TIMEOUT_SECONDS)) got - while (( SECONDS < deadline )); do - got="$(actor_state)" - if [[ "${got}" == "${want}" ]]; then - return 0 - fi - sleep 2 - done - fail "timed out after ${TIMEOUT_SECONDS}s waiting for ${want}, last state ${got:-unknown}" - return 1 -} - -cleanup() { - local code=$? - if [[ "${KEEP}" == "true" ]]; then - printf '\n--keep set; leaving actor %s/%s in place\n' "${ATESPACE}" "${ACTOR}" - else - step "Cleanup" - # --any-state: a failed run can leave the actor anywhere, including REVERTING. - if ate delete actor "${ACTOR}" -a "${ATESPACE}" --any-state >/dev/null 2>&1; then - info "deleted actor ${ACTOR}" - else - info "no actor to delete (or delete failed; check manually)" - fi - fi - exit "${code}" -} -trap cleanup EXIT - -# --- Preflight ------------------------------------------------------------- - -step "Preflight" -command -v jq >/dev/null || die "jq is required" -command -v kubectl >/dev/null || die "kubectl is required" -[[ -x "${ATE}" ]] || die "${ATE} not found or not executable; run 'make build-atectl' or set ATE" -ate get atespaces >/dev/null || die "cannot reach the control plane" -info "atespace=${ATESPACE} template=${TEMPLATE} actor=${ACTOR}" -[[ -n "${ENDPOINT}" ]] || info "no --endpoint: each CLI call will port-forward, expect a slow run" - -# --- Establish a snapshot for revert to return to -------------------------- - -step "Create and run the actor" -ate create actor "${ACTOR}" -a "${ATESPACE}" --template "${TEMPLATE}" >/dev/null -ate resume actor "${ACTOR}" -a "${ATESPACE}" >/dev/null -wait_for_state "ACTOR_STATE_RUNNING" || die "actor never reached RUNNING" -pass "actor is RUNNING" - -step "Suspend once, so there is an external snapshot to revert to" -ate suspend actor "${ACTOR}" -a "${ATESPACE}" >/dev/null -expect_state "ACTOR_STATE_SUSPENDED" "after suspend" -SNAPSHOT_URI="$(actor_field '.status.externalSnapshot.snapshotUri')" -[[ -n "${SNAPSHOT_URI}" ]] || die "suspend wrote no external snapshot; cannot verify revert" -info "snapshot: ${SNAPSHOT_URI}" - -# --- Scenario 1: revert from CRASHED --------------------------------------- - -step "Scenario 1: revert from CRASHED" -ate resume actor "${ACTOR}" -a "${ATESPACE}" >/dev/null -wait_for_state "ACTOR_STATE_RUNNING" || die "actor never got back to RUNNING" - -WORKER_POD="$(actor_field '.status.workerAssignment.workerPod')" -WORKER_NS="$(actor_field '.status.workerAssignment.workerNamespace')" -[[ -n "${WORKER_POD}" && -n "${WORKER_NS}" ]] || die "running actor has no worker pod recorded" -info "running on ${WORKER_NS}/${WORKER_POD}" - -info "deleting the worker pod to crash the actor" -kubectl delete pod "${WORKER_POD}" -n "${WORKER_NS}" --wait=false >/dev/null -wait_for_state "ACTOR_STATE_CRASHED" || die "actor never reached CRASHED after its pod was deleted" -pass "actor is CRASHED" - -# The crash clears the assignment, so revert has no worker to terminate -# through. This is the path that needs no live worker to succeed. -if [[ -n "$(actor_field '.status.workerAssignment.workerPod')" ]]; then - info "note: the crashed actor still records a worker assignment" -fi - -ate revert actor "${ACTOR}" -a "${ATESPACE}" >/dev/null || fail "RevertActor from CRASHED returned an error" -expect_state "ACTOR_STATE_SUSPENDED" "after revert from CRASHED" - -GOT_URI="$(actor_field '.status.externalSnapshot.snapshotUri')" -if [[ "${GOT_URI}" == "${SNAPSHOT_URI}" ]]; then - pass "external snapshot untouched" -else - fail "external snapshot is ${GOT_URI:-}, want it untouched at ${SNAPSHOT_URI}" -fi - -if [[ -z "$(actor_field '.status.workerAssignment.workerPod')" ]]; then - pass "worker assignment cleared" -else - fail "worker assignment survived the revert" -fi - -if [[ -z "$(actor_field '.status.localSnapshotInfo.snapshotName')" ]]; then - pass "local snapshot pointer cleared" -else - fail "local snapshot pointer survived the revert; the next resume would restore the discarded execution" -fi - -step "The reverted actor is usable: resume it" -ate resume actor "${ACTOR}" -a "${ATESPACE}" >/dev/null || fail "resume after revert returned an error" -wait_for_state "ACTOR_STATE_RUNNING" || fail "actor did not come back up after revert" -pass "actor resumed from its preserved snapshot" - -# --- Scenario 2: revert from RUNNING --------------------------------------- - -step "Scenario 2: revert from RUNNING" -ate revert actor "${ACTOR}" -a "${ATESPACE}" >/dev/null || fail "RevertActor from RUNNING returned an error" -expect_state "ACTOR_STATE_SUSPENDED" "after revert from RUNNING" -GOT_URI="$(actor_field '.status.externalSnapshot.snapshotUri')" -if [[ "${GOT_URI}" == "${SNAPSHOT_URI}" ]]; then - pass "external snapshot still the original one, no new snapshot taken" -else - fail "external snapshot is ${GOT_URI:-}, want the original ${SNAPSHOT_URI}" -fi - -# --- Scenario 3: revert from PAUSED ---------------------------------------- - -step "Scenario 3: revert from PAUSED" -ate resume actor "${ACTOR}" -a "${ATESPACE}" >/dev/null -wait_for_state "ACTOR_STATE_RUNNING" || die "actor never reached RUNNING" -if ate pause actor "${ACTOR}" -a "${ATESPACE}" >/dev/null 2>&1; then - wait_for_state "ACTOR_STATE_PAUSED" || die "actor never reached PAUSED" - PAUSE_NODE="$(actor_field '.status.localSnapshotInfo.nodeVmsWithLocalSnapshots[0]')" - info "paused with a node-local snapshot on ${PAUSE_NODE:-}" - - ate revert actor "${ACTOR}" -a "${ATESPACE}" >/dev/null || fail "RevertActor from PAUSED returned an error" - expect_state "ACTOR_STATE_SUSPENDED" "after revert from PAUSED" - if [[ -z "$(actor_field '.status.localSnapshotInfo.snapshotName')" ]]; then - pass "pause snapshot pointer discarded" - else - fail "pause snapshot pointer survived; resume would restore the discarded execution" - fi - if [[ -n "${PAUSE_NODE}" ]]; then - info "NOTE: the checkpoint bytes on ${PAUSE_NODE} are not pruned yet (see the" - info " commented-out ensureLocalCheckpointsPruned call in workflow_revert.go)." - info " Check with: kubectl debug node/${PAUSE_NODE} -- ls /host/var/lib/ateom-gvisor/actors" - fi -else - info "pause is unavailable for this template; skipping" -fi - -# --- Scenario 4: SUSPENDED is rejected ------------------------------------- - -step "Scenario 4: reverting a SUSPENDED actor is rejected" -expect_state "ACTOR_STATE_SUSPENDED" "before the rejection check" -if REJECT_OUT="$(ate revert actor "${ACTOR}" -a "${ATESPACE}" 2>&1)"; then - fail "RevertActor succeeded on a SUSPENDED actor, want FailedPrecondition" -elif grep -qi 'FailedPrecondition' <<<"${REJECT_OUT}"; then - pass "rejected with FailedPrecondition" -else - fail "rejected, but not with FailedPrecondition: ${REJECT_OUT}" -fi - -# --- Result ---------------------------------------------------------------- - -step "Result" -if (( FAILURES == 0 )); then - printf ' \033[32mall checks passed\033[0m\n' -else - printf ' \033[31m%d check(s) failed\033[0m\n' "${FAILURES}" - exit 1 -fi From eaf34c58f732ab183fe9ce26aa54680f6f522098 Mon Sep 17 00:00:00 2001 From: shrutiyam-glitch Date: Fri, 18 Sep 2026 09:47:33 -0700 Subject: [PATCH 13/14] check workerHostsActor before discarding worker in RevertActor --- .../internal/controlapi/workflow_revert.go | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/cmd/ateapi/internal/controlapi/workflow_revert.go b/cmd/ateapi/internal/controlapi/workflow_revert.go index fb7c857820..5bc7990f71 100644 --- a/cmd/ateapi/internal/controlapi/workflow_revert.go +++ b/cmd/ateapi/internal/controlapi/workflow_revert.go @@ -174,18 +174,24 @@ func (w *ActorWorkflow) ensureWorkerDiscarded(ctx context.Context, actorRef reso ctx, done := stepSpan(ctx, "DiscardWorker") defer func() { err = done(err) }() - if actor.GetStatus().GetWorkerAssignment() != nil { - if terr := w.ensureAteletTerminated(ctx, actorRef, actor, actorTemplate); terr != nil { - // A terminate that comes back with a crash directive lands the - // actor in CRASHED, which the user can revert again — that retry - // needs no live worker. - return maybeCrashActor(ctx, w.store, actorRef, terr, "while terminating the actor's workload", ateattr.OperationRevert) - } - if err := w.ensureVolumesDetached(ctx, actor, actorTemplate, "DetachVolumesForRevert", ateattr.OperationRevert); err != nil { + if assignment := actor.GetStatus().GetWorkerAssignment(); assignment != nil { + hosted, err := workerHostsActor(ctx, w.store, assignment.GetWorker().GetName(), actor.GetMetadata().GetUid()) + if err != nil { return err } - if _, _, err := releaseWorker(ctx, w.store, actor); err != nil { - return fmt.Errorf("while releasing worker: %w", err) + if hosted { + if terr := w.ensureAteletTerminated(ctx, actorRef, actor, actorTemplate); terr != nil { + // A terminate that comes back with a crash directive lands the + // actor in CRASHED, which the user can revert again — that retry + // needs no live worker. + return maybeCrashActor(ctx, w.store, actorRef, terr, "while terminating the actor's workload", ateattr.OperationRevert) + } + if err := w.ensureVolumesDetached(ctx, actor, actorTemplate, "DetachVolumesForRevert", ateattr.OperationRevert); err != nil { + return err + } + if _, _, err := releaseWorker(ctx, w.store, actor); err != nil { + return fmt.Errorf("while releasing worker: %w", err) + } } } @@ -214,7 +220,7 @@ func (w *ActorWorkflow) ensureInProgressSnapshotDiscarded(ctx context.Context, a } // A suspend records the in-progress URI under the actor's own prefix // before atelet writes the first object, so a URI owned by anything else - // is a corrupted record: deleting it would collect another actor's data. + // is a corrupted record. owner := actorSnapshotOwner(actor) if !uri.OwnedBy(owner) { return fmt.Errorf("the in-progress snapshot %q is not owned by actor %s", inProgress, owner) From 30870b7d352d50625b9d88d22989b3175cbeb9ac Mon Sep 17 00:00:00 2001 From: shrutiyam-glitch Date: Fri, 18 Sep 2026 10:15:03 -0700 Subject: [PATCH 14/14] verify actor is REVERTING before finalizing revert --- cmd/ateapi/internal/controlapi/workflow_revert.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/ateapi/internal/controlapi/workflow_revert.go b/cmd/ateapi/internal/controlapi/workflow_revert.go index 5bc7990f71..efae353798 100644 --- a/cmd/ateapi/internal/controlapi/workflow_revert.go +++ b/cmd/ateapi/internal/controlapi/workflow_revert.go @@ -242,6 +242,9 @@ func (w *ActorWorkflow) ensureRevertedFinalized(ctx context.Context, actorRef re if err != nil { return nil, err } + if got := latestActor.GetStatus().GetState(); got != ateapipb.ActorState_ACTOR_STATE_REVERTING { + return nil, status.Errorf(codes.FailedPrecondition, "FinalizeReverted prerequisite not met for Actor: %s (got: %v, want %s)", actorRef, got, ateapipb.ActorState_ACTOR_STATE_REVERTING) + } storedActor, err := w.store.UpdateActor(ctx, actorRef, store.PreconditionFrom(latestActor), func(toUpdate *ateapipb.Actor) error { toUpdate.Status.State = ateapipb.ActorState_ACTOR_STATE_SUSPENDED