From 88cb2fa4e3e3f8cc72e8ba34bf0c191985f5b2ef Mon Sep 17 00:00:00 2001 From: Eitan Yarmush Date: Thu, 30 Jul 2026 16:29:24 +0000 Subject: [PATCH 1/2] ateapi: store self-describing snapshots under stable paths --- .../internal/controlapi/functional_test.go | 2 +- .../internal/controlapi/workflow_suspend.go | 2 +- .../controlapi/workflow_suspend_test.go | 32 +++++++++++++++++++ cmd/atelet/main.go | 11 ++++--- cmd/atelet/main_test.go | 20 ++++++++++++ cmd/atelet/sandbox_assets.go | 12 +++++-- 6 files changed, 70 insertions(+), 9 deletions(-) diff --git a/cmd/ateapi/internal/controlapi/functional_test.go b/cmd/ateapi/internal/controlapi/functional_test.go index 4b914d4fd..3b3e0abfe 100644 --- a/cmd/ateapi/internal/controlapi/functional_test.go +++ b/cmd/ateapi/internal/controlapi/functional_test.go @@ -1553,7 +1553,7 @@ func TestSuspendActor(t *testing.T) { LatestSnapshotInfo: &ateapipb.SnapshotInfo{ Data: &ateapipb.SnapshotInfo_External{ External: &ateapipb.ExternalSnapshotInfo{ - SnapshotUriPrefix: fmt.Sprintf("gs://fake-fake-fake/%s/", name), + SnapshotUriPrefix: "gs://fake-fake-fake/snapshots/", }, }, }, diff --git a/cmd/ateapi/internal/controlapi/workflow_suspend.go b/cmd/ateapi/internal/controlapi/workflow_suspend.go index e01f5480f..a282d670b 100644 --- a/cmd/ateapi/internal/controlapi/workflow_suspend.go +++ b/cmd/ateapi/internal/controlapi/workflow_suspend.go @@ -94,7 +94,7 @@ func (s *MarkSuspendingStep) CheckPrerequisite(ctx context.Context, input *Suspe func (s *MarkSuspendingStep) Execute(ctx context.Context, input *SuspendInput, state *SuspendState) error { state.Actor.Status = ateapipb.Actor_STATUS_SUSPENDING snapshotID := time.Now().Format(time.RFC3339) + "-" + rand.Text() - state.Actor.InProgressSnapshot = strings.TrimSuffix(state.ActorTemplate.Spec.SnapshotsConfig.Location, "/") + "/" + input.ActorRef.Name + "/" + snapshotID + state.Actor.InProgressSnapshot = strings.TrimSuffix(state.ActorTemplate.Spec.SnapshotsConfig.Location, "/") + "/snapshots/" + snapshotID updatedActor, err := s.store.UpdateActor(ctx, state.Actor, state.Actor.GetMetadata().GetVersion()) if err != nil { return err diff --git a/cmd/ateapi/internal/controlapi/workflow_suspend_test.go b/cmd/ateapi/internal/controlapi/workflow_suspend_test.go index 91e02419c..e1d19b123 100644 --- a/cmd/ateapi/internal/controlapi/workflow_suspend_test.go +++ b/cmd/ateapi/internal/controlapi/workflow_suspend_test.go @@ -16,12 +16,14 @@ package controlapi import ( "context" + "strings" "testing" "github.com/agent-substrate/substrate/cmd/ateapi/internal/store" "github.com/agent-substrate/substrate/cmd/ateapi/internal/store/ateredis" "github.com/agent-substrate/substrate/cmd/ateapi/internal/store/storetest" "github.com/agent-substrate/substrate/internal/resources" + atev1alpha1 "github.com/agent-substrate/substrate/pkg/api/v1alpha1" "github.com/agent-substrate/substrate/pkg/proto/ateapipb" "github.com/alicebob/miniredis/v2" "github.com/redis/go-redis/v9" @@ -30,6 +32,36 @@ import ( "k8s.io/client-go/tools/cache" ) +func TestMarkSuspendingStep_SnapshotLocation(t *testing.T) { + ctx := context.Background() + persistence := newTestPersistence(t) + actor, err := persistence.CreateActor(ctx, &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "actor-1"}, + Status: ateapipb.Actor_STATUS_RUNNING, + }) + if err != nil { + t.Fatalf("CreateActor: %v", err) + } + state := &SuspendState{ + Actor: actor, + ActorTemplate: &atev1alpha1.ActorTemplate{Spec: atev1alpha1.ActorTemplateSpec{ + SnapshotsConfig: atev1alpha1.SnapshotsConfig{Location: "gs://bucket/root/"}, + }}, + } + if err := (&MarkSuspendingStep{store: persistence}).Execute(ctx, &SuspendInput{ActorRef: resources.ActorRef{Atespace: "team-a", Name: "actor-1"}}, state); err != nil { + t.Fatalf("Execute: %v", err) + } + + const prefix = "gs://bucket/root/snapshots/" + snapshotID, ok := strings.CutPrefix(state.Actor.GetInProgressSnapshot(), prefix) + if !ok { + t.Fatalf("snapshot location = %q, want prefix %q", state.Actor.GetInProgressSnapshot(), prefix) + } + if snapshotID == "" { + t.Fatal("snapshot ID is empty") + } +} + // TestSuspendActorWorkflow_RejectedAndIdempotentPaths covers the two // short-circuit paths of the suspend workflow: rejection by // MarkSuspendingStep's CheckPrerequisite and the IsComplete idempotent diff --git a/cmd/atelet/main.go b/cmd/atelet/main.go index 28a5a6aca..476548fa2 100644 --- a/cmd/atelet/main.go +++ b/cmd/atelet/main.go @@ -389,6 +389,11 @@ func (s *AteomHerder) Checkpoint(ctx context.Context, req *ateletpb.CheckpointRe if len(sandboxRec.SnapshotFiles) == 0 { return nil, ateerrors.NewGRPCError(ctx, codes.DataLoss, ateerrors.ReasonInvalidCheckpointResult, ateerrors.ActorCrashedMetadata(), errors.New("ateom reported no snapshot files for checkpoint")) } + sandboxRec.Atespace = req.GetAtespace() + sandboxRec.ActorName = req.GetActorName() + sandboxRec.ActorUID = req.GetActorUid() + sandboxRec.ActorTemplateNamespace = req.GetActorTemplateNamespace() + sandboxRec.ActorTemplateName = req.GetActorTemplateName() switch req.GetType() { case ateletpb.CheckpointType_CHECKPOINT_TYPE_EXTERNAL: @@ -442,8 +447,7 @@ func (s *AteomHerder) moveLocalCheckpoint(ctx context.Context, req *ateletpb.Che } } - // Pin the sandbox binaries + snapshot file list into a manifest beside the - // images so a later Restore is self-describing. + // Write the self-describing snapshot manifest beside the images. manifest, err := json.Marshal(rec) if err != nil { return fmt.Errorf("while marshaling snapshot manifest: %w", err) @@ -475,8 +479,7 @@ func (s *AteomHerder) uploadExternalCheckpoint(ctx context.Context, req *ateletp return err } - // Pin the sandbox binaries + snapshot file list into a manifest beside the - // images, written last, so a Restore on any node is self-describing. + // Write the self-describing snapshot manifest last. manifest, err := json.Marshal(rec) if err != nil { return fmt.Errorf("while marshaling snapshot manifest: %w", err) diff --git a/cmd/atelet/main_test.go b/cmd/atelet/main_test.go index ad0785f7b..57574548c 100644 --- a/cmd/atelet/main_test.go +++ b/cmd/atelet/main_test.go @@ -18,6 +18,7 @@ import ( "bytes" "context" "crypto/sha256" + "encoding/json" "errors" "fmt" "io" @@ -37,6 +38,25 @@ import ( "google.golang.org/protobuf/testing/protocmp" ) +func TestSnapshotManifestActorMetadata(t *testing.T) { + rec := sandboxAssetsRecord{ + Atespace: "team-a", + ActorName: "actor-1", + ActorUID: "actor-uid", + ActorTemplateNamespace: "templates", + ActorTemplateName: "agent", + } + got, err := json.Marshal(rec) + if err != nil { + t.Fatal(err) + } + for _, want := range []string{`"atespace":"team-a"`, `"actorName":"actor-1"`, `"actorUid":"actor-uid"`, `"actorTemplateNamespace":"templates"`, `"actorTemplateName":"agent"`} { + if !bytes.Contains(got, []byte(want)) { + t.Errorf("manifest %s missing %s", got, want) + } + } +} + func TestWriteFileAtomic(t *testing.T) { dir := t.TempDir() target := filepath.Join(dir, "actor-id") diff --git a/cmd/atelet/sandbox_assets.go b/cmd/atelet/sandbox_assets.go index 0154837cb..71a98e93a 100644 --- a/cmd/atelet/sandbox_assets.go +++ b/cmd/atelet/sandbox_assets.go @@ -36,9 +36,8 @@ import ( ) // sandboxManifestName is the object/file name of the per-snapshot manifest that -// records which sandbox binaries created a snapshot. It is written next to the -// checkpoint images (in the external object store, or the local checkpoint dir) -// so a Restore — possibly on another node — is self-describing. +// records the actor identity, snapshot files, and sandbox binaries. It is written +// next to the checkpoint images so a snapshot is self-describing. const sandboxManifestName = "manifest.json" // maxAssetBytes guards disk against an unbounded download URL; a var so tests can lower it. @@ -59,6 +58,13 @@ type assetEntry struct { type sandboxAssetsRecord struct { SandboxClass string `json:"sandboxClass"` Assets map[string]assetEntry `json:"assets"` + // Actor identity makes a flat snapshot self-identifying if control-plane + // persistence is unavailable. + Atespace string `json:"atespace,omitempty"` + ActorName string `json:"actorName,omitempty"` + ActorUID string `json:"actorUid,omitempty"` + ActorTemplateNamespace string `json:"actorTemplateNamespace,omitempty"` + ActorTemplateName string `json:"actorTemplateName,omitempty"` // SnapshotFiles are the (relative) names of the files ateom wrote into the // checkpoint directory, as reported by CheckpointWorkloadResponse. Recorded // in the snapshot manifest so Restore ships/downloads exactly this set From a8926855f00f3128cab5e14a603e6d9915e7af08 Mon Sep 17 00:00:00 2001 From: Eitan Yarmush Date: Mon, 27 Jul 2026 13:47:09 +0000 Subject: [PATCH 2/2] ateapi: add ActorSnapshot lifecycle APIs --- benchmarking/locust/common/ateapi_pb2.py | 212 ++- benchmarking/locust/common/ateapi_pb2_grpc.py | 226 ++- .../internal/controlapi/actor_snapshot.go | 245 +++ cmd/ateapi/internal/controlapi/converter.go | 15 + cmd/ateapi/internal/controlapi/crash.go | 2 +- .../internal/controlapi/create_actor.go | 43 + .../internal/controlapi/create_actor_test.go | 104 + .../internal/controlapi/delete_atespace.go | 10 +- .../internal/controlapi/functional_test.go | 163 +- .../internal/controlapi/suspend_actor.go | 2 - cmd/ateapi/internal/controlapi/syncer_test.go | 12 +- .../internal/controlapi/workflow_pause.go | 4 +- .../controlapi/workflow_pause_test.go | 22 +- .../internal/controlapi/workflow_resume.go | 68 +- .../internal/controlapi/workflow_suspend.go | 30 +- .../controlapi/workflow_suspend_test.go | 27 +- .../internal/store/ateredis/ateredis.go | 220 ++- .../internal/store/ateredis/ateredis_test.go | 117 +- cmd/ateapi/internal/store/store.go | 21 + .../controllers/actortemplate_controller.go | 7 +- docs/architecture.md | 10 +- pkg/proto/ateapipb/ateapi.pb.go | 1695 +++++++++++------ pkg/proto/ateapipb/ateapi.proto | 122 +- pkg/proto/ateapipb/ateapi_grpc.pb.go | 234 ++- 24 files changed, 2830 insertions(+), 781 deletions(-) create mode 100644 cmd/ateapi/internal/controlapi/actor_snapshot.go diff --git a/benchmarking/locust/common/ateapi_pb2.py b/benchmarking/locust/common/ateapi_pb2.py index bfa6d5e49..d339d0136 100644 --- a/benchmarking/locust/common/ateapi_pb2.py +++ b/benchmarking/locust/common/ateapi_pb2.py @@ -16,7 +16,7 @@ # Generated by the protocol buffer compiler. DO NOT EDIT! # NO CHECKED-IN PROTOBUF GENCODE # source: ateapi.proto -# Protobuf Python Version: 6.33.5 +# Protobuf Python Version: 7.35.0 """Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor from google.protobuf import descriptor_pool as _descriptor_pool @@ -25,9 +25,9 @@ from google.protobuf.internal import builder as _builder _runtime_version.ValidateProtobufRuntimeVersion( _runtime_version.Domain.PUBLIC, - 6, - 33, - 5, + 7, + 35, + 0, '', 'ateapi.proto' ) @@ -39,7 +39,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\x1fgoogle/protobuf/timestamp.proto\"3\n\x14\x45xternalSnapshotInfo\x12\x1b\n\x13snapshot_uri_prefix\x18\x01 \x01(\t\"S\n\x11LocalSnapshotInfo\x12\x17\n\x0fsnapshot_prefix\x18\x01 \x01(\t\x12%\n\x1dnode_vms_with_local_snapshots\x18\x02 \x03(\t\"\x80\x01\n\x0cSnapshotInfo\x12\x30\n\x08\x65xternal\x18\x02 \x01(\x0b\x32\x1c.ateapi.ExternalSnapshotInfoH\x00\x12*\n\x05local\x18\x03 \x01(\x0b\x32\x19.ateapi.LocalSnapshotInfoH\x00\x42\x06\n\x04\x64\x61taJ\x04\x08\x01\x10\x02R\x04type\"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\"\xbf\x01\n\x0e\x45xternalVolume\x12\x17\n\x0f\x61\x63tor_volume_id\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\"5\n\x06Status\x12\x10\n\x0cPROVISIONING\x10\x00\x12\x0b\n\x07\x43REATED\x10\x01\x12\x0c\n\x08\x44\x45LETING\x10\x02\"\xf4\x04\n\x05\x41\x63tor\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12 \n\x18\x61\x63tor_template_namespace\x18\x02 \x01(\t\x12\x1b\n\x13\x61\x63tor_template_name\x18\x03 \x01(\t\x12$\n\x06status\x18\x04 \x01(\x0e\x32\x14.ateapi.Actor.Status\x12\x1b\n\x13\x61teom_pod_namespace\x18\x05 \x01(\t\x12\x16\n\x0e\x61teom_pod_name\x18\x06 \x01(\t\x12\x14\n\x0c\x61teom_pod_ip\x18\x07 \x01(\t\x12\x1c\n\x14in_progress_snapshot\x18\x08 \x01(\t\x12\x15\n\rateom_pod_uid\x18\t \x01(\t\x12\x32\n\x14latest_snapshot_info\x18\n \x01(\x0b\x32\x14.ateapi.SnapshotInfo\x12)\n\x0fworker_selector\x18\x0b \x01(\x0b\x32\x10.ateapi.Selector\x12\x18\n\x10worker_pool_name\x18\x0c \x01(\t\x12-\n\ractor_volumes\x18\x10 \x03(\x0b\x32\x16.ateapi.ExternalVolume\"\xb1\x01\n\x06Status\x12\x16\n\x12STATUS_UNSPECIFIED\x10\x00\x12\x13\n\x0fSTATUS_RESUMING\x10\x01\x12\x12\n\x0eSTATUS_RUNNING\x10\x02\x12\x15\n\x11STATUS_SUSPENDING\x10\x03\x12\x14\n\x10STATUS_SUSPENDED\x10\x04\x12\x12\n\x0eSTATUS_PAUSING\x10\x05\x12\x11\n\rSTATUS_PAUSED\x10\x06\x12\x12\n\x0eSTATUS_CRASHED\x10\x07\"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\";\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\"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\"a\n\x12UpdateActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12)\n\x0fworker_selector\x18\x02 \x01(\x0b\x32\x10.ateapi.Selector\"3\n\x13UpdateActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"7\n\x13SuspendActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"4\n\x14SuspendActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"5\n\x11PauseActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"2\n\x12PauseActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"D\n\x12ResumeActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x0c\n\x04\x62oot\x18\x02 \x01(\x08\"3\n\x13ResumeActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"6\n\x12\x44\x65leteActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\";\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\"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\"\x98\x03\n\x06Worker\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&\n\nassignment\x18\x04 \x01(\x0b\x32\x12.ateapi.Assignment\x12\n\n\x02ip\x18\x05 \x01(\t\x12\x0f\n\x07version\x18\x06 \x01(\x03\x12\x16\n\x0eworker_pod_uid\x18\x07 \x01(\t\x12\x11\n\tnode_name\x18\x08 \x01(\t\x12\x15\n\rsandbox_class\x18\t \x01(\t\x12*\n\x06labels\x18\n \x03(\x0b\x32\x1a.ateapi.Worker.LabelsEntry\x12#\n\x05state\x18\x0b \x01(\x0e\x32\x14.ateapi.Worker.State\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"D\n\x05State\x12\x15\n\x11STATE_UNSPECIFIED\x10\x00\x12\x10\n\x0cSTATE_ACTIVE\x10\x01\x12\x12\n\x0eSTATE_DRAINING\x10\x02\"g\n\nAssignment\x12\x37\n\x0e\x61\x63tor_template\x18\x01 \x01(\x0b\x32\x1f.ateapi.KubeNamespacedObjectRef\x12 \n\x05\x61\x63tor\x18\x02 \x01(\x0b\x32\x11.ateapi.ObjectRef\":\n\x17KubeNamespacedObjectRef\x12\x11\n\tnamespace\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\"\x13\n\x11\x44\x65\x62ugClearRequest\"\x14\n\x12\x44\x65\x62ugClearResponse\"U\n\x0eMintJWTRequest\x12\x10\n\x08\x61udience\x18\x01 \x03(\t\x12\x0e\n\x06\x61pp_id\x18\x02 \x01(\t\x12\x0f\n\x07user_id\x18\x03 \x01(\t\x12\x10\n\x08\x61\x63tor_id\x18\x04 \x01(\t\"$\n\x0fMintJWTResponse\x12\x11\n\tactor_jwt\x18\x01 \x01(\t\"i\n\x0fMintCertRequest\x12\x0e\n\x06\x61pp_id\x18\x01 \x01(\t\x12\x0f\n\x07user_id\x18\x02 \x01(\t\x12\x10\n\x08\x61\x63tor_id\x18\x03 \x01(\t\x12#\n\x1b\x63\x65rtificate_signing_request\x18\x04 \x01(\x0c\".\n\x10MintCertResponse\x12\x1a\n\x12\x61\x63tor_certificates\x18\x01 \x03(\x0c\x32\x89\x07\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\x12H\n\x0bUpdateActor\x12\x1a.ateapi.UpdateActorRequest\x1a\x1b.ateapi.UpdateActorResponse\"\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\x12H\n\x0bListWorkers\x12\x1a.ateapi.ListWorkersRequest\x1a\x1b.ateapi.ListWorkersResponse\"\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\x32N\n\x05\x44\x65\x62ug\x12\x45\n\nDebugClear\x12\x19.ateapi.DebugClearRequest\x1a\x1a.ateapi.DebugClearResponse\"\x00\x32\x8a\x01\n\rActorIdentity\x12:\n\x07MintJWT\x12\x16.ateapi.MintJWTRequest\x1a\x17.ateapi.MintJWTResponse\x12=\n\x08MintCert\x12\x17.ateapi.MintCertRequest\x1a\x18.ateapi.MintCertResponseB9Z7github.com/agent-substrate/substrate/pkg/proto/ateapipbb\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0c\x61teapi.proto\x12\x06\x61teapi\x1a\x1fgoogle/protobuf/timestamp.proto\"S\n\x11LocalSnapshotInfo\x12\x17\n\x0fsnapshot_prefix\x18\x01 \x01(\t\x12%\n\x1dnode_vms_with_local_snapshots\x18\x02 \x03(\t\"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\"\xbf\x01\n\x0e\x45xternalVolume\x12\x17\n\x0f\x61\x63tor_volume_id\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\"5\n\x06Status\x12\x10\n\x0cPROVISIONING\x10\x00\x12\x0b\n\x07\x43REATED\x10\x01\x12\x0c\n\x08\x44\x45LETING\x10\x02\"\xf3\x05\n\x05\x41\x63tor\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12 \n\x18\x61\x63tor_template_namespace\x18\x02 \x01(\t\x12\x1b\n\x13\x61\x63tor_template_name\x18\x03 \x01(\t\x12$\n\x06status\x18\x04 \x01(\x0e\x32\x14.ateapi.Actor.Status\x12\x1b\n\x13\x61teom_pod_namespace\x18\x05 \x01(\t\x12\x16\n\x0e\x61teom_pod_name\x18\x06 \x01(\t\x12\x14\n\x0c\x61teom_pod_ip\x18\x07 \x01(\t\x12\x1c\n\x14in_progress_snapshot\x18\x08 \x01(\t\x12\x15\n\rateom_pod_uid\x18\t \x01(\t\x12)\n\x0fworker_selector\x18\x0b \x01(\x0b\x32\x10.ateapi.Selector\x12\x18\n\x10worker_pool_name\x18\x0c \x01(\t\x12*\n\x0flatest_snapshot\x18\r \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x36\n\x13local_snapshot_info\x18\x0e \x01(\x0b\x32\x19.ateapi.LocalSnapshotInfo\x12\x31\n)in_progress_snapshot_source_actor_version\x18\x0f \x01(\x03\x12-\n\ractor_volumes\x18\x10 \x03(\x0b\x32\x16.ateapi.ExternalVolume\"\xb1\x01\n\x06Status\x12\x16\n\x12STATUS_UNSPECIFIED\x10\x00\x12\x13\n\x0fSTATUS_RESUMING\x10\x01\x12\x12\n\x0eSTATUS_RUNNING\x10\x02\x12\x15\n\x11STATUS_SUSPENDING\x10\x03\x12\x14\n\x10STATUS_SUSPENDED\x10\x04\x12\x12\n\x0eSTATUS_PAUSING\x10\x05\x12\x11\n\rSTATUS_PAUSED\x10\x06\x12\x12\n\x0eSTATUS_CRASHED\x10\x07J\x04\x08\n\x10\x0bR\x14latest_snapshot_info\"\xac\x02\n\rActorSnapshot\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12\'\n\x0csource_actor\x18\x02 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x18\n\x10source_actor_uid\x18\x03 \x01(\t\x12\x1c\n\x14source_actor_version\x18\x04 \x01(\x03\x12 \n\x18\x61\x63tor_template_namespace\x18\x05 \x01(\t\x12\x1b\n\x13\x61\x63tor_template_name\x18\x06 \x01(\t\x12\x1a\n\x12\x61\x63tor_template_uid\x18\x07 \x01(\t\x12\x33\n\rcontent_scope\x18\x08 \x01(\x0e\x32\x1c.ateapi.SnapshotContentScope\"\x91\x01\n\x10\x41\x63torSnapshotTag\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\x12#\n\x08snapshot\x18\x02 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12,\n\x05scope\x18\x03 \x01(\x0e\x32\x1d.ateapi.ActorSnapshotTagScope\"6\n\x08\x41tespace\x12*\n\x08metadata\x18\x01 \x01(\x0b\x32\x18.ateapi.ResourceMetadata\"+\n\tObjectRef\x12\x10\n\x08\x61tespace\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\"h\n\x10\x41\x63torSnapshotRef\x12%\n\x08snapshot\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRefH\x00\x12 \n\x03tag\x18\x02 \x01(\x0b\x32\x11.ateapi.ObjectRefH\x00\x42\x0b\n\treference\";\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\"3\n\x0fGetActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"e\n\x12\x43reateActorRequest\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\x12\x31\n\x0fsource_snapshot\x18\x02 \x01(\x0b\x32\x18.ateapi.ActorSnapshotRef\"a\n\x12UpdateActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12)\n\x0fworker_selector\x18\x02 \x01(\x0b\x32\x10.ateapi.Selector\"3\n\x13UpdateActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"7\n\x13SuspendActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"4\n\x14SuspendActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"5\n\x11PauseActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"2\n\x12PauseActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"D\n\x12ResumeActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12\x0c\n\x04\x62oot\x18\x02 \x01(\x08\"3\n\x13ResumeActorResponse\x12\x1c\n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\r.ateapi.Actor\"6\n\x12\x44\x65leteActorRequest\x12 \n\x05\x61\x63tor\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\"E\n\x17GetActorSnapshotRequest\x12*\n\x08snapshot\x18\x01 \x01(\x0b\x32\x18.ateapi.ActorSnapshotRef\"T\n\x19ListActorSnapshotsRequest\x12\x10\n\x08\x61tespace\x18\x01 \x01(\t\x12\x11\n\tpage_size\x18\x02 \x01(\x05\x12\x12\n\npage_token\x18\x03 \x01(\t\"_\n\x1aListActorSnapshotsResponse\x12(\n\tsnapshots\x18\x01 \x03(\x0b\x32\x15.ateapi.ActorSnapshot\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t\"l\n\x17TagActorSnapshotRequest\x12*\n\x08snapshot\x18\x01 \x01(\x0b\x32\x18.ateapi.ActorSnapshotRef\x12%\n\x03tag\x18\x02 \x01(\x0b\x32\x18.ateapi.ActorSnapshotTag\"m\n\x1dUpdateActorSnapshotTagRequest\x12\x1e\n\x03tag\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\x12,\n\x05scope\x18\x02 \x01(\x0e\x32\x1d.ateapi.ActorSnapshotTagScope\"?\n\x1d\x44\x65leteActorSnapshotTagRequest\x12\x1e\n\x03tag\x18\x01 \x01(\x0b\x32\x11.ateapi.ObjectRef\";\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\"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\"\x98\x03\n\x06Worker\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&\n\nassignment\x18\x04 \x01(\x0b\x32\x12.ateapi.Assignment\x12\n\n\x02ip\x18\x05 \x01(\t\x12\x0f\n\x07version\x18\x06 \x01(\x03\x12\x16\n\x0eworker_pod_uid\x18\x07 \x01(\t\x12\x11\n\tnode_name\x18\x08 \x01(\t\x12\x15\n\rsandbox_class\x18\t \x01(\t\x12*\n\x06labels\x18\n \x03(\x0b\x32\x1a.ateapi.Worker.LabelsEntry\x12#\n\x05state\x18\x0b \x01(\x0e\x32\x14.ateapi.Worker.State\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"D\n\x05State\x12\x15\n\x11STATE_UNSPECIFIED\x10\x00\x12\x10\n\x0cSTATE_ACTIVE\x10\x01\x12\x12\n\x0eSTATE_DRAINING\x10\x02\"g\n\nAssignment\x12\x37\n\x0e\x61\x63tor_template\x18\x01 \x01(\x0b\x32\x1f.ateapi.KubeNamespacedObjectRef\x12 \n\x05\x61\x63tor\x18\x02 \x01(\x0b\x32\x11.ateapi.ObjectRef\":\n\x17KubeNamespacedObjectRef\x12\x11\n\tnamespace\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\"\x13\n\x11\x44\x65\x62ugClearRequest\"\x14\n\x12\x44\x65\x62ugClearResponse\"U\n\x0eMintJWTRequest\x12\x10\n\x08\x61udience\x18\x01 \x03(\t\x12\x0e\n\x06\x61pp_id\x18\x02 \x01(\t\x12\x0f\n\x07user_id\x18\x03 \x01(\t\x12\x10\n\x08\x61\x63tor_id\x18\x04 \x01(\t\"$\n\x0fMintJWTResponse\x12\x11\n\tactor_jwt\x18\x01 \x01(\t\"i\n\x0fMintCertRequest\x12\x0e\n\x06\x61pp_id\x18\x01 \x01(\t\x12\x0f\n\x07user_id\x18\x02 \x01(\t\x12\x10\n\x08\x61\x63tor_id\x18\x03 \x01(\t\x12#\n\x1b\x63\x65rtificate_signing_request\x18\x04 \x01(\x0c\".\n\x10MintCertResponse\x12\x1a\n\x12\x61\x63tor_certificates\x18\x01 \x03(\x0c*\x80\x01\n\x14SnapshotContentScope\x12&\n\"SNAPSHOT_CONTENT_SCOPE_UNSPECIFIED\x10\x00\x12\x1f\n\x1bSNAPSHOT_CONTENT_SCOPE_FULL\x10\x01\x12\x1f\n\x1bSNAPSHOT_CONTENT_SCOPE_DATA\x10\x02*f\n\x15\x41\x63torSnapshotTagScope\x12%\n!ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE\x10\x00\x12&\n\"ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED\x10\x01\x32\xc1\n\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\x12H\n\x0bUpdateActor\x12\x1a.ateapi.UpdateActorRequest\x1a\x1b.ateapi.UpdateActorResponse\"\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\x12L\n\x10GetActorSnapshot\x12\x1f.ateapi.GetActorSnapshotRequest\x1a\x15.ateapi.ActorSnapshot\"\x00\x12]\n\x12ListActorSnapshots\x12!.ateapi.ListActorSnapshotsRequest\x1a\".ateapi.ListActorSnapshotsResponse\"\x00\x12O\n\x10TagActorSnapshot\x12\x1f.ateapi.TagActorSnapshotRequest\x1a\x18.ateapi.ActorSnapshotTag\"\x00\x12[\n\x16UpdateActorSnapshotTag\x12%.ateapi.UpdateActorSnapshotTagRequest\x1a\x18.ateapi.ActorSnapshotTag\"\x00\x12[\n\x16\x44\x65leteActorSnapshotTag\x12%.ateapi.DeleteActorSnapshotTagRequest\x1a\x18.ateapi.ActorSnapshotTag\"\x00\x12H\n\x0bListWorkers\x12\x1a.ateapi.ListWorkersRequest\x1a\x1b.ateapi.ListWorkersResponse\"\x00\x12\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\x32N\n\x05\x44\x65\x62ug\x12\x45\n\nDebugClear\x12\x19.ateapi.DebugClearRequest\x1a\x1a.ateapi.DebugClearResponse\"\x00\x32\x8a\x01\n\rActorIdentity\x12:\n\x07MintJWT\x12\x16.ateapi.MintJWTRequest\x1a\x17.ateapi.MintJWTResponse\x12=\n\x08MintCert\x12\x17.ateapi.MintCertRequest\x1a\x18.ateapi.MintCertResponseB9Z7github.com/agent-substrate/substrate/pkg/proto/ateapipbb\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) @@ -51,96 +51,114 @@ _globals['_SELECTOR_MATCHLABELSENTRY']._serialized_options = b'8\001' _globals['_WORKER_LABELSENTRY']._loaded_options = None _globals['_WORKER_LABELSENTRY']._serialized_options = b'8\001' - _globals['_EXTERNALSNAPSHOTINFO']._serialized_start=57 - _globals['_EXTERNALSNAPSHOTINFO']._serialized_end=108 - _globals['_LOCALSNAPSHOTINFO']._serialized_start=110 - _globals['_LOCALSNAPSHOTINFO']._serialized_end=193 - _globals['_SNAPSHOTINFO']._serialized_start=196 - _globals['_SNAPSHOTINFO']._serialized_end=324 - _globals['_SELECTOR']._serialized_start=326 - _globals['_SELECTOR']._serialized_end=445 - _globals['_SELECTOR_MATCHLABELSENTRY']._serialized_start=395 - _globals['_SELECTOR_MATCHLABELSENTRY']._serialized_end=445 - _globals['_RESOURCEMETADATA']._serialized_start=448 - _globals['_RESOURCEMETADATA']._serialized_end=626 - _globals['_EXTERNALVOLUME']._serialized_start=629 - _globals['_EXTERNALVOLUME']._serialized_end=820 - _globals['_EXTERNALVOLUME_STATUS']._serialized_start=767 - _globals['_EXTERNALVOLUME_STATUS']._serialized_end=820 - _globals['_ACTOR']._serialized_start=823 - _globals['_ACTOR']._serialized_end=1451 - _globals['_ACTOR_STATUS']._serialized_start=1274 - _globals['_ACTOR_STATUS']._serialized_end=1451 - _globals['_ATESPACE']._serialized_start=1453 - _globals['_ATESPACE']._serialized_end=1507 - _globals['_OBJECTREF']._serialized_start=1509 - _globals['_OBJECTREF']._serialized_end=1552 - _globals['_CREATEATESPACEREQUEST']._serialized_start=1554 - _globals['_CREATEATESPACEREQUEST']._serialized_end=1613 - _globals['_GETATESPACEREQUEST']._serialized_start=1615 - _globals['_GETATESPACEREQUEST']._serialized_end=1672 - _globals['_LISTATESPACESREQUEST']._serialized_start=1674 - _globals['_LISTATESPACESREQUEST']._serialized_end=1735 - _globals['_LISTATESPACESRESPONSE']._serialized_start=1737 - _globals['_LISTATESPACESRESPONSE']._serialized_end=1822 - _globals['_DELETEATESPACEREQUEST']._serialized_start=1824 - _globals['_DELETEATESPACEREQUEST']._serialized_end=1884 - _globals['_GETACTORREQUEST']._serialized_start=1886 - _globals['_GETACTORREQUEST']._serialized_end=1937 - _globals['_CREATEACTORREQUEST']._serialized_start=1939 - _globals['_CREATEACTORREQUEST']._serialized_end=1989 - _globals['_UPDATEACTORREQUEST']._serialized_start=1991 - _globals['_UPDATEACTORREQUEST']._serialized_end=2088 - _globals['_UPDATEACTORRESPONSE']._serialized_start=2090 - _globals['_UPDATEACTORRESPONSE']._serialized_end=2141 - _globals['_SUSPENDACTORREQUEST']._serialized_start=2143 - _globals['_SUSPENDACTORREQUEST']._serialized_end=2198 - _globals['_SUSPENDACTORRESPONSE']._serialized_start=2200 - _globals['_SUSPENDACTORRESPONSE']._serialized_end=2252 - _globals['_PAUSEACTORREQUEST']._serialized_start=2254 - _globals['_PAUSEACTORREQUEST']._serialized_end=2307 - _globals['_PAUSEACTORRESPONSE']._serialized_start=2309 - _globals['_PAUSEACTORRESPONSE']._serialized_end=2359 - _globals['_RESUMEACTORREQUEST']._serialized_start=2361 - _globals['_RESUMEACTORREQUEST']._serialized_end=2429 - _globals['_RESUMEACTORRESPONSE']._serialized_start=2431 - _globals['_RESUMEACTORRESPONSE']._serialized_end=2482 - _globals['_DELETEACTORREQUEST']._serialized_start=2484 - _globals['_DELETEACTORREQUEST']._serialized_end=2538 - _globals['_LISTWORKERSREQUEST']._serialized_start=2540 - _globals['_LISTWORKERSREQUEST']._serialized_end=2599 - _globals['_LISTWORKERSRESPONSE']._serialized_start=2601 - _globals['_LISTWORKERSRESPONSE']._serialized_end=2680 - _globals['_LISTACTORSREQUEST']._serialized_start=2682 - _globals['_LISTACTORSREQUEST']._serialized_end=2758 - _globals['_LISTACTORSRESPONSE']._serialized_start=2760 - _globals['_LISTACTORSRESPONSE']._serialized_end=2836 - _globals['_WORKER']._serialized_start=2839 - _globals['_WORKER']._serialized_end=3247 - _globals['_WORKER_LABELSENTRY']._serialized_start=3132 - _globals['_WORKER_LABELSENTRY']._serialized_end=3177 - _globals['_WORKER_STATE']._serialized_start=3179 - _globals['_WORKER_STATE']._serialized_end=3247 - _globals['_ASSIGNMENT']._serialized_start=3249 - _globals['_ASSIGNMENT']._serialized_end=3352 - _globals['_KUBENAMESPACEDOBJECTREF']._serialized_start=3354 - _globals['_KUBENAMESPACEDOBJECTREF']._serialized_end=3412 - _globals['_DEBUGCLEARREQUEST']._serialized_start=3414 - _globals['_DEBUGCLEARREQUEST']._serialized_end=3433 - _globals['_DEBUGCLEARRESPONSE']._serialized_start=3435 - _globals['_DEBUGCLEARRESPONSE']._serialized_end=3455 - _globals['_MINTJWTREQUEST']._serialized_start=3457 - _globals['_MINTJWTREQUEST']._serialized_end=3542 - _globals['_MINTJWTRESPONSE']._serialized_start=3544 - _globals['_MINTJWTRESPONSE']._serialized_end=3580 - _globals['_MINTCERTREQUEST']._serialized_start=3582 - _globals['_MINTCERTREQUEST']._serialized_end=3687 - _globals['_MINTCERTRESPONSE']._serialized_start=3689 - _globals['_MINTCERTRESPONSE']._serialized_end=3735 - _globals['_CONTROL']._serialized_start=3738 - _globals['_CONTROL']._serialized_end=4643 - _globals['_DEBUG']._serialized_start=4645 - _globals['_DEBUG']._serialized_end=4723 - _globals['_ACTORIDENTITY']._serialized_start=4726 - _globals['_ACTORIDENTITY']._serialized_end=4864 + _globals['_SNAPSHOTCONTENTSCOPE']._serialized_start=4829 + _globals['_SNAPSHOTCONTENTSCOPE']._serialized_end=4957 + _globals['_ACTORSNAPSHOTTAGSCOPE']._serialized_start=4959 + _globals['_ACTORSNAPSHOTTAGSCOPE']._serialized_end=5061 + _globals['_LOCALSNAPSHOTINFO']._serialized_start=57 + _globals['_LOCALSNAPSHOTINFO']._serialized_end=140 + _globals['_SELECTOR']._serialized_start=142 + _globals['_SELECTOR']._serialized_end=261 + _globals['_SELECTOR_MATCHLABELSENTRY']._serialized_start=211 + _globals['_SELECTOR_MATCHLABELSENTRY']._serialized_end=261 + _globals['_RESOURCEMETADATA']._serialized_start=264 + _globals['_RESOURCEMETADATA']._serialized_end=442 + _globals['_EXTERNALVOLUME']._serialized_start=445 + _globals['_EXTERNALVOLUME']._serialized_end=636 + _globals['_EXTERNALVOLUME_STATUS']._serialized_start=583 + _globals['_EXTERNALVOLUME_STATUS']._serialized_end=636 + _globals['_ACTOR']._serialized_start=639 + _globals['_ACTOR']._serialized_end=1394 + _globals['_ACTOR_STATUS']._serialized_start=1189 + _globals['_ACTOR_STATUS']._serialized_end=1366 + _globals['_ACTORSNAPSHOT']._serialized_start=1397 + _globals['_ACTORSNAPSHOT']._serialized_end=1697 + _globals['_ACTORSNAPSHOTTAG']._serialized_start=1700 + _globals['_ACTORSNAPSHOTTAG']._serialized_end=1845 + _globals['_ATESPACE']._serialized_start=1847 + _globals['_ATESPACE']._serialized_end=1901 + _globals['_OBJECTREF']._serialized_start=1903 + _globals['_OBJECTREF']._serialized_end=1946 + _globals['_ACTORSNAPSHOTREF']._serialized_start=1948 + _globals['_ACTORSNAPSHOTREF']._serialized_end=2052 + _globals['_CREATEATESPACEREQUEST']._serialized_start=2054 + _globals['_CREATEATESPACEREQUEST']._serialized_end=2113 + _globals['_GETATESPACEREQUEST']._serialized_start=2115 + _globals['_GETATESPACEREQUEST']._serialized_end=2172 + _globals['_LISTATESPACESREQUEST']._serialized_start=2174 + _globals['_LISTATESPACESREQUEST']._serialized_end=2235 + _globals['_LISTATESPACESRESPONSE']._serialized_start=2237 + _globals['_LISTATESPACESRESPONSE']._serialized_end=2322 + _globals['_DELETEATESPACEREQUEST']._serialized_start=2324 + _globals['_DELETEATESPACEREQUEST']._serialized_end=2384 + _globals['_GETACTORREQUEST']._serialized_start=2386 + _globals['_GETACTORREQUEST']._serialized_end=2437 + _globals['_CREATEACTORREQUEST']._serialized_start=2439 + _globals['_CREATEACTORREQUEST']._serialized_end=2540 + _globals['_UPDATEACTORREQUEST']._serialized_start=2542 + _globals['_UPDATEACTORREQUEST']._serialized_end=2639 + _globals['_UPDATEACTORRESPONSE']._serialized_start=2641 + _globals['_UPDATEACTORRESPONSE']._serialized_end=2692 + _globals['_SUSPENDACTORREQUEST']._serialized_start=2694 + _globals['_SUSPENDACTORREQUEST']._serialized_end=2749 + _globals['_SUSPENDACTORRESPONSE']._serialized_start=2751 + _globals['_SUSPENDACTORRESPONSE']._serialized_end=2803 + _globals['_PAUSEACTORREQUEST']._serialized_start=2805 + _globals['_PAUSEACTORREQUEST']._serialized_end=2858 + _globals['_PAUSEACTORRESPONSE']._serialized_start=2860 + _globals['_PAUSEACTORRESPONSE']._serialized_end=2910 + _globals['_RESUMEACTORREQUEST']._serialized_start=2912 + _globals['_RESUMEACTORREQUEST']._serialized_end=2980 + _globals['_RESUMEACTORRESPONSE']._serialized_start=2982 + _globals['_RESUMEACTORRESPONSE']._serialized_end=3033 + _globals['_DELETEACTORREQUEST']._serialized_start=3035 + _globals['_DELETEACTORREQUEST']._serialized_end=3089 + _globals['_GETACTORSNAPSHOTREQUEST']._serialized_start=3091 + _globals['_GETACTORSNAPSHOTREQUEST']._serialized_end=3160 + _globals['_LISTACTORSNAPSHOTSREQUEST']._serialized_start=3162 + _globals['_LISTACTORSNAPSHOTSREQUEST']._serialized_end=3246 + _globals['_LISTACTORSNAPSHOTSRESPONSE']._serialized_start=3248 + _globals['_LISTACTORSNAPSHOTSRESPONSE']._serialized_end=3343 + _globals['_TAGACTORSNAPSHOTREQUEST']._serialized_start=3345 + _globals['_TAGACTORSNAPSHOTREQUEST']._serialized_end=3453 + _globals['_UPDATEACTORSNAPSHOTTAGREQUEST']._serialized_start=3455 + _globals['_UPDATEACTORSNAPSHOTTAGREQUEST']._serialized_end=3564 + _globals['_DELETEACTORSNAPSHOTTAGREQUEST']._serialized_start=3566 + _globals['_DELETEACTORSNAPSHOTTAGREQUEST']._serialized_end=3629 + _globals['_LISTWORKERSREQUEST']._serialized_start=3631 + _globals['_LISTWORKERSREQUEST']._serialized_end=3690 + _globals['_LISTWORKERSRESPONSE']._serialized_start=3692 + _globals['_LISTWORKERSRESPONSE']._serialized_end=3771 + _globals['_LISTACTORSREQUEST']._serialized_start=3773 + _globals['_LISTACTORSREQUEST']._serialized_end=3849 + _globals['_LISTACTORSRESPONSE']._serialized_start=3851 + _globals['_LISTACTORSRESPONSE']._serialized_end=3927 + _globals['_WORKER']._serialized_start=3930 + _globals['_WORKER']._serialized_end=4338 + _globals['_WORKER_LABELSENTRY']._serialized_start=4223 + _globals['_WORKER_LABELSENTRY']._serialized_end=4268 + _globals['_WORKER_STATE']._serialized_start=4270 + _globals['_WORKER_STATE']._serialized_end=4338 + _globals['_ASSIGNMENT']._serialized_start=4340 + _globals['_ASSIGNMENT']._serialized_end=4443 + _globals['_KUBENAMESPACEDOBJECTREF']._serialized_start=4445 + _globals['_KUBENAMESPACEDOBJECTREF']._serialized_end=4503 + _globals['_DEBUGCLEARREQUEST']._serialized_start=4505 + _globals['_DEBUGCLEARREQUEST']._serialized_end=4524 + _globals['_DEBUGCLEARRESPONSE']._serialized_start=4526 + _globals['_DEBUGCLEARRESPONSE']._serialized_end=4546 + _globals['_MINTJWTREQUEST']._serialized_start=4548 + _globals['_MINTJWTREQUEST']._serialized_end=4633 + _globals['_MINTJWTRESPONSE']._serialized_start=4635 + _globals['_MINTJWTRESPONSE']._serialized_end=4671 + _globals['_MINTCERTREQUEST']._serialized_start=4673 + _globals['_MINTCERTREQUEST']._serialized_end=4778 + _globals['_MINTCERTRESPONSE']._serialized_start=4780 + _globals['_MINTCERTRESPONSE']._serialized_end=4826 + _globals['_CONTROL']._serialized_start=5064 + _globals['_CONTROL']._serialized_end=6409 + _globals['_DEBUG']._serialized_start=6411 + _globals['_DEBUG']._serialized_end=6489 + _globals['_ACTORIDENTITY']._serialized_start=6492 + _globals['_ACTORIDENTITY']._serialized_end=6630 # @@protoc_insertion_point(module_scope) diff --git a/benchmarking/locust/common/ateapi_pb2_grpc.py b/benchmarking/locust/common/ateapi_pb2_grpc.py index 8ded3fa82..abba923b7 100644 --- a/benchmarking/locust/common/ateapi_pb2_grpc.py +++ b/benchmarking/locust/common/ateapi_pb2_grpc.py @@ -19,7 +19,7 @@ from . import ateapi_pb2 as ateapi__pb2 -GRPC_GENERATED_VERSION = '1.81.1' +GRPC_GENERATED_VERSION = '1.82.1' GRPC_VERSION = grpc.__version__ _version_not_supported = False @@ -84,6 +84,31 @@ def __init__(self, channel): request_serializer=ateapi__pb2.DeleteActorRequest.SerializeToString, response_deserializer=ateapi__pb2.Actor.FromString, _registered_method=True) + self.GetActorSnapshot = channel.unary_unary( + '/ateapi.Control/GetActorSnapshot', + request_serializer=ateapi__pb2.GetActorSnapshotRequest.SerializeToString, + response_deserializer=ateapi__pb2.ActorSnapshot.FromString, + _registered_method=True) + self.ListActorSnapshots = channel.unary_unary( + '/ateapi.Control/ListActorSnapshots', + request_serializer=ateapi__pb2.ListActorSnapshotsRequest.SerializeToString, + response_deserializer=ateapi__pb2.ListActorSnapshotsResponse.FromString, + _registered_method=True) + self.TagActorSnapshot = channel.unary_unary( + '/ateapi.Control/TagActorSnapshot', + request_serializer=ateapi__pb2.TagActorSnapshotRequest.SerializeToString, + response_deserializer=ateapi__pb2.ActorSnapshotTag.FromString, + _registered_method=True) + self.UpdateActorSnapshotTag = channel.unary_unary( + '/ateapi.Control/UpdateActorSnapshotTag', + request_serializer=ateapi__pb2.UpdateActorSnapshotTagRequest.SerializeToString, + response_deserializer=ateapi__pb2.ActorSnapshotTag.FromString, + _registered_method=True) + self.DeleteActorSnapshotTag = channel.unary_unary( + '/ateapi.Control/DeleteActorSnapshotTag', + request_serializer=ateapi__pb2.DeleteActorSnapshotTagRequest.SerializeToString, + response_deserializer=ateapi__pb2.ActorSnapshotTag.FromString, + _registered_method=True) self.ListWorkers = channel.unary_unary( '/ateapi.Control/ListWorkers', request_serializer=ateapi__pb2.ListWorkersRequest.SerializeToString, @@ -169,6 +194,42 @@ def DeleteActor(self, request, context): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def GetActorSnapshot(self, request, context): + """Get an ActorSnapshot. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def ListActorSnapshots(self, request, context): + """List ActorSnapshots. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def TagActorSnapshot(self, request, context): + """Add an Atespace-owned, stable name for an ActorSnapshot. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def UpdateActorSnapshotTag(self, request, context): + """Publish or unpublish an ActorSnapshot tag without changing its address. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def DeleteActorSnapshotTag(self, request, context): + """Delete an ActorSnapshot tag. The snapshot becomes garbage-collectable when + its final tag is deleted. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def ListWorkers(self, request, context): """List Workers. """ @@ -205,7 +266,8 @@ def ListAtespaces(self, request, context): raise NotImplementedError('Method not implemented!') def DeleteAtespace(self, request, context): - """Delete an empty Atespace. Rejects (FailedPrecondition) if any actors remain. + """Delete an empty Atespace. Rejects (FailedPrecondition) if any Actors or + ActorSnapshotTags remain. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -249,6 +311,31 @@ def add_ControlServicer_to_server(servicer, server): request_deserializer=ateapi__pb2.DeleteActorRequest.FromString, response_serializer=ateapi__pb2.Actor.SerializeToString, ), + 'GetActorSnapshot': grpc.unary_unary_rpc_method_handler( + servicer.GetActorSnapshot, + request_deserializer=ateapi__pb2.GetActorSnapshotRequest.FromString, + response_serializer=ateapi__pb2.ActorSnapshot.SerializeToString, + ), + 'ListActorSnapshots': grpc.unary_unary_rpc_method_handler( + servicer.ListActorSnapshots, + request_deserializer=ateapi__pb2.ListActorSnapshotsRequest.FromString, + response_serializer=ateapi__pb2.ListActorSnapshotsResponse.SerializeToString, + ), + 'TagActorSnapshot': grpc.unary_unary_rpc_method_handler( + servicer.TagActorSnapshot, + request_deserializer=ateapi__pb2.TagActorSnapshotRequest.FromString, + response_serializer=ateapi__pb2.ActorSnapshotTag.SerializeToString, + ), + 'UpdateActorSnapshotTag': grpc.unary_unary_rpc_method_handler( + servicer.UpdateActorSnapshotTag, + request_deserializer=ateapi__pb2.UpdateActorSnapshotTagRequest.FromString, + response_serializer=ateapi__pb2.ActorSnapshotTag.SerializeToString, + ), + 'DeleteActorSnapshotTag': grpc.unary_unary_rpc_method_handler( + servicer.DeleteActorSnapshotTag, + request_deserializer=ateapi__pb2.DeleteActorSnapshotTagRequest.FromString, + response_serializer=ateapi__pb2.ActorSnapshotTag.SerializeToString, + ), 'ListWorkers': grpc.unary_unary_rpc_method_handler( servicer.ListWorkers, request_deserializer=ateapi__pb2.ListWorkersRequest.FromString, @@ -480,6 +567,141 @@ def DeleteActor(request, metadata, _registered_method=True) + @staticmethod + def GetActorSnapshot(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/GetActorSnapshot', + ateapi__pb2.GetActorSnapshotRequest.SerializeToString, + ateapi__pb2.ActorSnapshot.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def ListActorSnapshots(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/ListActorSnapshots', + ateapi__pb2.ListActorSnapshotsRequest.SerializeToString, + ateapi__pb2.ListActorSnapshotsResponse.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def TagActorSnapshot(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/TagActorSnapshot', + ateapi__pb2.TagActorSnapshotRequest.SerializeToString, + ateapi__pb2.ActorSnapshotTag.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def UpdateActorSnapshotTag(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/UpdateActorSnapshotTag', + ateapi__pb2.UpdateActorSnapshotTagRequest.SerializeToString, + ateapi__pb2.ActorSnapshotTag.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + + @staticmethod + def DeleteActorSnapshotTag(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/DeleteActorSnapshotTag', + ateapi__pb2.DeleteActorSnapshotTagRequest.SerializeToString, + ateapi__pb2.ActorSnapshotTag.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + @staticmethod def ListWorkers(request, target, diff --git a/cmd/ateapi/internal/controlapi/actor_snapshot.go b/cmd/ateapi/internal/controlapi/actor_snapshot.go new file mode 100644 index 000000000..e0d74fc81 --- /dev/null +++ b/cmd/ateapi/internal/controlapi/actor_snapshot.go @@ -0,0 +1,245 @@ +// Copyright 2026 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package controlapi + +import ( + "context" + "errors" + "fmt" + + "github.com/agent-substrate/substrate/cmd/ateapi/internal/store" + "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" + "k8s.io/apimachinery/pkg/util/validation/field" +) + +func (s *Service) GetActorSnapshot(ctx context.Context, req *ateapipb.GetActorSnapshotRequest) (*ateapipb.ActorSnapshot, error) { + if err := validateActorSnapshotRef(req.GetSnapshot(), "snapshot"); err != nil { + return nil, err + } + snapshot, _, _, _, err := s.getActorSnapshot(ctx, req.GetSnapshot()) + if errors.Is(err, store.ErrNotFound) { + return nil, status.Error(codes.NotFound, "ActorSnapshot not found") + } + if err != nil { + return nil, fmt.Errorf("while getting actor snapshot: %w", err) + } + return snapshot, nil +} + +func (s *Service) ListActorSnapshots(ctx context.Context, req *ateapipb.ListActorSnapshotsRequest) (*ateapipb.ListActorSnapshotsResponse, error) { + var fldPath *field.Path + var errs field.ErrorList + if req.GetAtespace() != "" { + errs = append(errs, resources.ValidateResourceName(req.GetAtespace(), fldPath.Child("atespace"))...) + } + if req.GetPageSize() < 0 { + errs = append(errs, field.Invalid(fldPath.Child("page_size"), req.GetPageSize(), "must be greater than or equal to 0")) + } + if len(errs) > 0 { + return nil, status.Error(codes.InvalidArgument, errs.ToAggregate().Error()) + } + snapshots, nextToken, err := s.persistence.ListActorSnapshots(ctx, req.GetAtespace(), effectivePageSize(req.GetPageSize()), req.GetPageToken()) + if err != nil { + return nil, fmt.Errorf("while listing actor snapshots: %w", err) + } + return &ateapipb.ListActorSnapshotsResponse{Snapshots: snapshots, NextPageToken: nextToken}, nil +} + +func (s *Service) TagActorSnapshot(ctx context.Context, req *ateapipb.TagActorSnapshotRequest) (*ateapipb.ActorSnapshotTag, error) { + if err := validateActorSnapshotRef(req.GetSnapshot(), "snapshot"); err != nil { + return nil, err + } + if err := validateActorSnapshotTag(req.GetTag(), "tag"); err != nil { + return nil, err + } + lock, _, ref, _, err := s.lockActorSnapshot(ctx, req.GetSnapshot()) + if err != nil { + return nil, err + } + defer lock.Close() + if req.GetTag().GetMetadata().GetAtespace() != ref.GetAtespace() { + return nil, status.Error(codes.FailedPrecondition, "ActorSnapshot tags must belong to the snapshot's Atespace") + } + atespaceLock, err := s.persistence.AcquireLock(lock.Context(), "lock:atespace:"+req.GetTag().GetMetadata().GetAtespace()) + if errors.Is(err, store.ErrLockConflict) { + return nil, status.Error(codes.Aborted, "another operation is using this Atespace") + } + if err != nil { + return nil, fmt.Errorf("while locking tag Atespace: %w", err) + } + defer atespaceLock.Close() + exists, err := s.persistence.AtespaceExists(atespaceLock.Context(), req.GetTag().GetMetadata().GetAtespace()) + if err != nil { + return nil, fmt.Errorf("while checking tag Atespace: %w", err) + } + if !exists { + return nil, status.Errorf(codes.FailedPrecondition, "Atespace %s not found", req.GetTag().GetMetadata().GetAtespace()) + } + tag, err := s.persistence.TagActorSnapshot(atespaceLock.Context(), ref.GetAtespace(), ref.GetName(), req.GetTag()) + if errors.Is(err, store.ErrAlreadyExists) { + return nil, status.Errorf(codes.AlreadyExists, "ActorSnapshot tag %s/%s already exists", req.GetTag().GetMetadata().GetAtespace(), req.GetTag().GetMetadata().GetName()) + } + if err != nil { + return nil, fmt.Errorf("while tagging actor snapshot: %w", err) + } + return tag, nil +} + +func (s *Service) UpdateActorSnapshotTag(ctx context.Context, req *ateapipb.UpdateActorSnapshotTagRequest) (*ateapipb.ActorSnapshotTag, error) { + if errs := resources.ValidateObjectRef(req.GetTag(), field.NewPath("tag")); len(errs) > 0 { + return nil, status.Error(codes.InvalidArgument, errs.ToAggregate().Error()) + } + if err := validateActorSnapshotTagScope(req.GetScope()); err != nil { + return nil, err + } + ref := &ateapipb.ActorSnapshotRef{Reference: &ateapipb.ActorSnapshotRef_Tag{Tag: req.GetTag()}} + lock, _, _, _, err := s.lockActorSnapshot(ctx, ref) + if err != nil { + return nil, err + } + defer lock.Close() + atespaceLock, err := s.persistence.AcquireLock(lock.Context(), "lock:atespace:"+req.GetTag().GetAtespace()) + if errors.Is(err, store.ErrLockConflict) { + return nil, status.Error(codes.Aborted, "another operation is using this Atespace") + } + if err != nil { + return nil, fmt.Errorf("while locking tag Atespace: %w", err) + } + defer atespaceLock.Close() + tag, err := s.persistence.UpdateActorSnapshotTag(atespaceLock.Context(), req.GetTag().GetAtespace(), req.GetTag().GetName(), req.GetScope()) + if errors.Is(err, store.ErrNotFound) { + return nil, status.Errorf(codes.NotFound, "ActorSnapshot tag %s/%s not found", req.GetTag().GetAtespace(), req.GetTag().GetName()) + } + if err != nil { + return nil, fmt.Errorf("while updating actor snapshot tag: %w", err) + } + return tag, nil +} + +func (s *Service) DeleteActorSnapshotTag(ctx context.Context, req *ateapipb.DeleteActorSnapshotTagRequest) (*ateapipb.ActorSnapshotTag, error) { + if errs := resources.ValidateObjectRef(req.GetTag(), field.NewPath("tag")); len(errs) > 0 { + return nil, status.Error(codes.InvalidArgument, errs.ToAggregate().Error()) + } + ref := &ateapipb.ActorSnapshotRef{Reference: &ateapipb.ActorSnapshotRef_Tag{Tag: req.GetTag()}} + lock, _, _, _, err := s.lockActorSnapshot(ctx, ref) + if err != nil { + return nil, err + } + defer lock.Close() + tag, err := s.persistence.DeleteActorSnapshotTag(lock.Context(), req.GetTag().GetAtespace(), req.GetTag().GetName()) + if errors.Is(err, store.ErrNotFound) { + return nil, status.Errorf(codes.NotFound, "ActorSnapshot tag %s/%s not found", req.GetTag().GetAtespace(), req.GetTag().GetName()) + } + if err != nil { + return nil, fmt.Errorf("while deleting actor snapshot tag: %w", err) + } + return tag, nil +} + +func (s *Service) getActorSnapshot(ctx context.Context, ref *ateapipb.ActorSnapshotRef) (*ateapipb.ActorSnapshot, string, *ateapipb.ObjectRef, *ateapipb.ActorSnapshotTag, error) { + var snapshot *ateapipb.ActorSnapshot + var tag *ateapipb.ActorSnapshotTag + var location string + var err error + switch ref.GetReference().(type) { + case *ateapipb.ActorSnapshotRef_Snapshot: + canonical := ref.GetSnapshot() + snapshot, location, err = s.persistence.GetActorSnapshot(ctx, canonical.GetAtespace(), canonical.GetName()) + case *ateapipb.ActorSnapshotRef_Tag: + snapshot, location, tag, err = s.persistence.GetActorSnapshotByTag(ctx, ref.GetTag().GetAtespace(), ref.GetTag().GetName()) + default: + return nil, "", nil, nil, store.ErrNotFound + } + if err != nil { + return nil, "", nil, nil, err + } + canonical := &ateapipb.ObjectRef{Atespace: snapshot.GetMetadata().GetAtespace(), Name: snapshot.GetMetadata().GetName()} + return snapshot, location, canonical, tag, nil +} + +func (s *Service) lockActorSnapshot(ctx context.Context, ref *ateapipb.ActorSnapshotRef) (*store.Lock, *ateapipb.ActorSnapshot, *ateapipb.ObjectRef, *ateapipb.ActorSnapshotTag, error) { + _, _, canonical, _, err := s.getActorSnapshot(ctx, ref) + if errors.Is(err, store.ErrNotFound) { + return nil, nil, nil, nil, status.Error(codes.NotFound, "ActorSnapshot not found") + } + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("while getting actor snapshot: %w", err) + } + lock, err := s.persistence.AcquireLock(ctx, "lock:actor-snapshot:"+canonical.GetAtespace()+":"+canonical.GetName()) + if errors.Is(err, store.ErrLockConflict) { + return nil, nil, nil, nil, status.Error(codes.Aborted, "another operation is using this ActorSnapshot") + } + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("while locking actor snapshot: %w", err) + } + snapshot, _, lockedCanonical, tag, err := s.getActorSnapshot(lock.Context(), ref) + if err != nil || canonical.GetAtespace() != lockedCanonical.GetAtespace() || canonical.GetName() != lockedCanonical.GetName() { + lock.Close() + if errors.Is(err, store.ErrNotFound) { + return nil, nil, nil, nil, status.Error(codes.NotFound, "ActorSnapshot not found") + } + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("while getting actor snapshot: %w", err) + } + return nil, nil, nil, nil, status.Error(codes.Aborted, "ActorSnapshot reference changed, please retry") + } + return lock, snapshot, lockedCanonical, tag, nil +} + +func validateActorSnapshotRef(ref *ateapipb.ActorSnapshotRef, name string) error { + var fldPath *field.Path + p := fldPath.Child(name) + if ref == nil { + return status.Error(codes.InvalidArgument, field.ErrorList{field.Required(p, "")}.ToAggregate().Error()) + } + switch ref.GetReference().(type) { + case *ateapipb.ActorSnapshotRef_Snapshot: + if errs := resources.ValidateObjectRef(ref.GetSnapshot(), p.Child("snapshot")); len(errs) > 0 { + return status.Error(codes.InvalidArgument, errs.ToAggregate().Error()) + } + case *ateapipb.ActorSnapshotRef_Tag: + if errs := resources.ValidateObjectRef(ref.GetTag(), p.Child("tag")); len(errs) > 0 { + return status.Error(codes.InvalidArgument, errs.ToAggregate().Error()) + } + default: + return status.Error(codes.InvalidArgument, field.ErrorList{field.Required(p, "")}.ToAggregate().Error()) + } + return nil +} + +func validateActorSnapshotTag(tag *ateapipb.ActorSnapshotTag, name string) error { + var fldPath *field.Path + p := fldPath.Child(name) + if tag == nil { + return status.Error(codes.InvalidArgument, field.ErrorList{field.Required(p, "")}.ToAggregate().Error()) + } + if errs := resources.ValidateObjectRef(&ateapipb.ObjectRef{Atespace: tag.GetMetadata().GetAtespace(), Name: tag.GetMetadata().GetName()}, p.Child("metadata")); len(errs) > 0 { + return status.Error(codes.InvalidArgument, errs.ToAggregate().Error()) + } + return validateActorSnapshotTagScope(tag.GetScope()) +} + +func validateActorSnapshotTagScope(scope ateapipb.ActorSnapshotTagScope) error { + switch scope { + case ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE, + ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED: + return nil + default: + return status.Error(codes.InvalidArgument, "invalid ActorSnapshot tag scope") + } +} diff --git a/cmd/ateapi/internal/controlapi/converter.go b/cmd/ateapi/internal/controlapi/converter.go index b851aa42e..ddc6eec68 100644 --- a/cmd/ateapi/internal/controlapi/converter.go +++ b/cmd/ateapi/internal/controlapi/converter.go @@ -19,6 +19,7 @@ import ( "github.com/agent-substrate/substrate/internal/proto/ateletpb" atev1alpha1 "github.com/agent-substrate/substrate/pkg/api/v1alpha1" + "github.com/agent-substrate/substrate/pkg/proto/ateapipb" ) // convert atev1alpha1.SnapshotScope to ateletpb.SnapshotScope @@ -33,3 +34,17 @@ func toAteletSnapshotScope(in atev1alpha1.SnapshotScope) ateletpb.SnapshotScope return ateletpb.SnapshotScope_SNAPSHOT_SCOPE_FULL } } + +func toActorSnapshotContentScope(in atev1alpha1.SnapshotScope) ateapipb.SnapshotContentScope { + if in == atev1alpha1.SnapshotScopeData { + return ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_DATA + } + return ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_FULL +} + +func actorSnapshotContentScopeToAtelet(in ateapipb.SnapshotContentScope) ateletpb.SnapshotScope { + if in == ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_DATA { + return ateletpb.SnapshotScope_SNAPSHOT_SCOPE_DATA + } + return ateletpb.SnapshotScope_SNAPSHOT_SCOPE_FULL +} diff --git a/cmd/ateapi/internal/controlapi/crash.go b/cmd/ateapi/internal/controlapi/crash.go index 3b464edba..1c371eb69 100644 --- a/cmd/ateapi/internal/controlapi/crash.go +++ b/cmd/ateapi/internal/controlapi/crash.go @@ -62,7 +62,7 @@ func crashActor(ctx context.Context, st store.Interface, actorRef resources.Acto actor.Status = ateapipb.Actor_STATUS_CRASHED // InProgressSnapshot is kept for debugging; failed workflow - // steps must never promote it to LatestSnapshotInfo. + // steps must never promote it to an ActorSnapshot. actor.AteomPodNamespace = "" actor.AteomPodName = "" actor.AteomPodIp = "" diff --git a/cmd/ateapi/internal/controlapi/create_actor.go b/cmd/ateapi/internal/controlapi/create_actor.go index f19ee0d1b..6a2d479a3 100644 --- a/cmd/ateapi/internal/controlapi/create_actor.go +++ b/cmd/ateapi/internal/controlapi/create_actor.go @@ -34,6 +34,31 @@ func (s *Service) CreateActor(ctx context.Context, req *ateapipb.CreateActorRequ return nil, toGRPCStatusError(errs) } in := req.GetActor() + var sourceSnapshot *ateapipb.ActorSnapshot + var sourceSnapshotRef *ateapipb.ObjectRef + if ref := req.GetSourceSnapshot(); ref != nil { + if _, ok := ref.GetReference().(*ateapipb.ActorSnapshotRef_Tag); !ok { + return nil, status.Error(codes.FailedPrecondition, "source ActorSnapshot must be referenced by tag") + } + lock, snapshot, canonical, tag, err := s.lockActorSnapshot(ctx, ref) + if err != nil { + return nil, err + } + defer lock.Close() + ctx = lock.Context() + sourceSnapshot = snapshot + sourceSnapshotRef = canonical + target := in.GetMetadata() + switch tag.GetScope() { + case ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE: + if tag.GetMetadata().GetAtespace() != target.GetAtespace() { + return nil, status.Error(codes.FailedPrecondition, "ActorSnapshot tag is not published outside its Atespace") + } + case ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED: + default: + return nil, status.Error(codes.FailedPrecondition, "source ActorSnapshot tag has an invalid scope") + } + } templateNamespace := in.GetActorTemplateNamespace() templateName := in.GetActorTemplateName() @@ -46,6 +71,18 @@ func (s *Service) CreateActor(ctx context.Context, req *ateapipb.CreateActorRequ } return nil, fmt.Errorf("while getting ActorTemplate: %w", err) } + // TODO: Permit compatible DATA snapshots when runtimes can extract portable data. + if sourceSnapshot != nil && sourceSnapshot.GetActorTemplateUid() != string(template.GetUID()) { + return nil, status.Error(codes.FailedPrecondition, "ActorSnapshot requires the source ActorTemplate") + } + if sourceSnapshot != nil { + for _, volume := range template.Spec.Volumes { + if volume.ExternalVolumeTemplate != nil { + // TODO: Permit cloning after CSI volume snapshots are supported. + return nil, status.Error(codes.FailedPrecondition, "ActorSnapshot cloning does not support external volumes") + } + } + } atespace := in.GetMetadata().GetAtespace() name := in.GetMetadata().GetName() @@ -79,6 +116,7 @@ func (s *Service) CreateActor(ctx context.Context, req *ateapipb.CreateActorRequ ActorTemplateName: templateName, WorkerSelector: in.GetWorkerSelector(), ActorVolumes: volumes, + LatestSnapshot: sourceSnapshotRef, } stored, err := s.persistence.CreateActor(ctx, actor) if err != nil { @@ -135,6 +173,11 @@ func validateCreateActorRequest(req *ateapipb.CreateActorRequest) field.ErrorLis if val := actor.GetWorkerSelector(); val != nil { errs = append(errs, validateSelector(val, actorPath.Child("worker_selector"))...) } + if val := req.GetSourceSnapshot(); val != nil { + if err := validateActorSnapshotRef(val, "source_snapshot"); err != nil { + errs = append(errs, field.Invalid(fldPath.Child("source_snapshot"), val, err.Error())) + } + } return errs } diff --git a/cmd/ateapi/internal/controlapi/create_actor_test.go b/cmd/ateapi/internal/controlapi/create_actor_test.go index bab43e91c..8bb3f9e0d 100644 --- a/cmd/ateapi/internal/controlapi/create_actor_test.go +++ b/cmd/ateapi/internal/controlapi/create_actor_test.go @@ -17,12 +17,19 @@ package controlapi import ( "context" "testing" + "time" "go.opentelemetry.io/otel/attribute" "github.com/agent-substrate/substrate/internal/ateattr" + atev1alpha1 "github.com/agent-substrate/substrate/pkg/api/v1alpha1" "github.com/agent-substrate/substrate/pkg/proto/ateapipb" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apimachinery/pkg/util/wait" ) // CreateActor is the only lifecycle op with the full identity (incl. version) @@ -157,3 +164,100 @@ func TestValidateCreateActorRequest(t *testing.T) { }) } } + +func TestCreateActor_RejectsDifferentTemplateForDataSnapshot(t *testing.T) { + ns := namespaceForTest("ns-data-snapshot-template") + tc := setupTest(t, ns) + defer tc.cleanup() + createTemplate(t, tc, ns) + createTemplateWithSelector(t, tc, ns, "tmpl2", nil) + + tmpl, err := tc.actorTemplateLister.ActorTemplates(ns).Get("tmpl1") + if err != nil { + t.Fatalf("Get source ActorTemplate: %v", err) + } + snapshot, err := tc.persistence.CreateActorSnapshot(context.Background(), &ateapipb.ActorSnapshot{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "data-snapshot"}, + SourceActor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "source"}, + ActorTemplateUid: string(tmpl.GetUID()), + ContentScope: ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_DATA, + }, "gs://snapshots/data") + if err != nil { + t.Fatalf("CreateActorSnapshot: %v", err) + } + if _, err := tc.persistence.TagActorSnapshot(context.Background(), testAtespace, snapshot.GetMetadata().GetName(), &ateapipb.ActorSnapshotTag{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "data-snapshot"}, + Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE, + }); err != nil { + t.Fatalf("TagActorSnapshot: %v", err) + } + + _, err = tc.service.CreateActor(context.Background(), &ateapipb.CreateActorRequest{ + Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "clone"}, + ActorTemplateNamespace: ns, + ActorTemplateName: "tmpl2", + }, + SourceSnapshot: &ateapipb.ActorSnapshotRef{Reference: &ateapipb.ActorSnapshotRef_Tag{Tag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "data-snapshot"}}}, + }) + if status.Code(err) != codes.FailedPrecondition { + t.Fatalf("CreateActor status = %v, want FailedPrecondition", status.Code(err)) + } +} + +func TestCreateActor_RejectsSnapshotWithExternalVolumes(t *testing.T) { + ns := namespaceForTest("ns-snapshot-external-volume") + tc := setupTest(t, ns) + defer tc.cleanup() + template, err := tc.substrateClient.ApiV1alpha1().ActorTemplates(ns).Create(context.Background(), &atev1alpha1.ActorTemplate{ + ObjectMeta: metav1.ObjectMeta{Name: "tmpl1", Namespace: ns}, + Spec: atev1alpha1.ActorTemplateSpec{ + PauseImage: "pause@sha256:abc", + SnapshotsConfig: atev1alpha1.SnapshotsConfig{Location: "gs://snapshots"}, + Containers: []atev1alpha1.Container{{ + Name: "main", Image: "main@sha256:abc", VolumeMounts: []atev1alpha1.VolumeMount{{Name: "data", MountPath: "/data"}}, + }}, + Volumes: []atev1alpha1.Volume{{ + Name: "data", + VolumeSource: atev1alpha1.VolumeSource{ExternalVolumeTemplate: &atev1alpha1.ExternalVolumeTemplate{ + Capacity: resource.MustParse("1Gi"), StorageClassName: "standard", + }}, + }}, + }, + }, metav1.CreateOptions{}) + if err != nil { + t.Fatalf("Create ActorTemplate: %v", err) + } + if err := wait.PollUntilContextTimeout(context.Background(), 100*time.Millisecond, 5*time.Second, true, func(ctx context.Context) (bool, error) { + got, err := tc.actorTemplateLister.ActorTemplates(ns).Get("tmpl1") + return err == nil && len(got.Spec.Volumes) == 1, nil + }); err != nil { + t.Fatalf("wait for ActorTemplate update: %v", err) + } + snapshot, err := tc.persistence.CreateActorSnapshot(context.Background(), &ateapipb.ActorSnapshot{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "external-volume-snapshot"}, + ActorTemplateUid: string(template.GetUID()), + }, "gs://snapshots/external-volume") + if err != nil { + t.Fatalf("CreateActorSnapshot: %v", err) + } + tagRef := &ateapipb.ObjectRef{Atespace: testAtespace, Name: "external-volume-snapshot"} + if _, err := tc.persistence.TagActorSnapshot(context.Background(), testAtespace, snapshot.GetMetadata().GetName(), &ateapipb.ActorSnapshotTag{ + Metadata: &ateapipb.ResourceMetadata{Atespace: tagRef.GetAtespace(), Name: tagRef.GetName()}, + Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE, + }); err != nil { + t.Fatalf("TagActorSnapshot: %v", err) + } + + _, err = tc.service.CreateActor(context.Background(), &ateapipb.CreateActorRequest{ + Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "clone"}, + ActorTemplateNamespace: ns, + ActorTemplateName: "tmpl1", + }, + SourceSnapshot: &ateapipb.ActorSnapshotRef{Reference: &ateapipb.ActorSnapshotRef_Tag{Tag: tagRef}}, + }) + if status.Code(err) != codes.FailedPrecondition { + t.Fatalf("CreateActor status = %v, want FailedPrecondition", status.Code(err)) + } +} diff --git a/cmd/ateapi/internal/controlapi/delete_atespace.go b/cmd/ateapi/internal/controlapi/delete_atespace.go index 9c66b8414..a13c12a4c 100644 --- a/cmd/ateapi/internal/controlapi/delete_atespace.go +++ b/cmd/ateapi/internal/controlapi/delete_atespace.go @@ -33,7 +33,15 @@ func (s *Service) DeleteAtespace(ctx context.Context, req *ateapipb.DeleteAtespa } name := req.GetAtespace().GetName() - deleted, err := s.persistence.DeleteAtespace(ctx, name) + lock, err := s.persistence.AcquireLock(ctx, "lock:atespace:"+name) + if errors.Is(err, store.ErrLockConflict) { + return nil, status.Error(codes.Aborted, "another operation is using this Atespace") + } + if err != nil { + return nil, fmt.Errorf("while locking Atespace: %w", err) + } + defer lock.Close() + deleted, err := s.persistence.DeleteAtespace(lock.Context(), name) if err != nil { if errors.Is(err, store.ErrNotFound) { return nil, status.Errorf(codes.NotFound, "Atespace %s not found", name) diff --git a/cmd/ateapi/internal/controlapi/functional_test.go b/cmd/ateapi/internal/controlapi/functional_test.go index 3b3e0abfe..84df0aefb 100644 --- a/cmd/ateapi/internal/controlapi/functional_test.go +++ b/cmd/ateapi/internal/controlapi/functional_test.go @@ -462,8 +462,18 @@ func createTemplateWithContainers(t *testing.T, tc *testContext, ns string, cont t.Fatalf("failed to create actor template: %v", err) } + const goldenSnapshot = "golden" + if _, err := tc.persistence.CreateActorSnapshot(context.Background(), &ateapipb.ActorSnapshot{ + Metadata: &ateapipb.ResourceMetadata{Atespace: resources.GoldenActorAtespace, Name: goldenSnapshot}, + ActorTemplateNamespace: ns, + ActorTemplateName: createdTemplate.GetName(), + ActorTemplateUid: string(createdTemplate.GetUID()), + ContentScope: ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_FULL, + }, "gs://my-bucket/my-folder"); err != nil { + t.Fatalf("failed to create golden ActorSnapshot: %v", err) + } createdTemplate.Status = atev1alpha1.ActorTemplateStatus{ - GoldenSnapshot: "gs://my-bucket/my-folder", + GoldenSnapshot: goldenSnapshot, } _, err = tc.substrateClient.ApiV1alpha1().ActorTemplates(ns).UpdateStatus(context.Background(), createdTemplate, metav1.UpdateOptions{}) @@ -1520,7 +1530,7 @@ func TestSuspendActor(t *testing.T) { } // Resume first to make it running - _, err = tc.client.ResumeActor(context.Background(), &ateapipb.ResumeActorRequest{ + running, err := tc.client.ResumeActor(context.Background(), &ateapipb.ResumeActorRequest{ Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: name}, }) if err != nil { @@ -1528,7 +1538,7 @@ func TestSuspendActor(t *testing.T) { } // Suspend - _, err = tc.client.SuspendActor(context.Background(), &ateapipb.SuspendActorRequest{ + suspended, err := tc.client.SuspendActor(context.Background(), &ateapipb.SuspendActorRequest{ Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: name}, }) if err != nil { @@ -1538,6 +1548,116 @@ func TestSuspendActor(t *testing.T) { if !tc.fakeAtelet.CheckpointCalled { t.Errorf("expected atelet Checkpoint to be called") } + ref := suspended.GetActor().GetLatestSnapshot() + if ref.GetName() == "" { + t.Fatalf("SuspendActor returned no ActorSnapshot reference: %v", suspended) + } + snapshotRef := &ateapipb.ActorSnapshotRef{Reference: &ateapipb.ActorSnapshotRef_Snapshot{Snapshot: ref}} + snapshot, err := tc.client.GetActorSnapshot(context.Background(), &ateapipb.GetActorSnapshotRequest{Snapshot: snapshotRef}) + if err != nil { + t.Fatalf("GetActorSnapshot failed: %v", err) + } + if got := snapshot.GetSourceActorVersion(); got != running.GetActor().GetMetadata().GetVersion() { + t.Errorf("snapshot source version = %d, want %d", got, running.GetActor().GetMetadata().GetVersion()) + } + listed, err := tc.client.ListActorSnapshots(context.Background(), &ateapipb.ListActorSnapshotsRequest{Atespace: testAtespace, PageSize: 1}) + if err != nil || len(listed.GetSnapshots()) != 1 { + t.Fatalf("ListActorSnapshots = (%v, %v), want one", listed, err) + } + if _, err := tc.client.CreateActor(context.Background(), &ateapipb.CreateActorRequest{ + Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "untagged-clone"}, + ActorTemplateNamespace: ns, + ActorTemplateName: "tmpl1", + }, + SourceSnapshot: snapshotRef, + }); status.Code(err) != codes.FailedPrecondition { + t.Fatalf("untagged CreateActor status = %v, want FailedPrecondition", status.Code(err)) + } + tagRef := &ateapipb.ObjectRef{Atespace: testAtespace, Name: "before-upgrade"} + tagged, err := tc.client.TagActorSnapshot(context.Background(), &ateapipb.TagActorSnapshotRequest{ + Snapshot: snapshotRef, + Tag: &ateapipb.ActorSnapshotTag{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "before-upgrade"}, + Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE, + }, + }) + if err != nil || !proto.Equal(tagged.GetSnapshot(), ref) { + t.Fatalf("TagActorSnapshot = (%v, %v), want tag for snapshot", tagged, err) + } + if _, err := tc.client.TagActorSnapshot(context.Background(), &ateapipb.TagActorSnapshotRequest{ + Snapshot: snapshotRef, + Tag: &ateapipb.ActorSnapshotTag{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "other", Name: "cross-atespace"}, + Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE, + }, + }); status.Code(err) != codes.FailedPrecondition { + t.Fatalf("cross-atespace TagActorSnapshot status = %v, want FailedPrecondition", status.Code(err)) + } + snapshotTagRef := &ateapipb.ActorSnapshotRef{Reference: &ateapipb.ActorSnapshotRef_Tag{Tag: tagRef}} + if _, err := tc.client.CreateActor(context.Background(), &ateapipb.CreateActorRequest{ + Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "other", Name: "cross-atespace"}, + ActorTemplateNamespace: ns, + ActorTemplateName: "tmpl1", + }, + SourceSnapshot: snapshotTagRef, + }); status.Code(err) != codes.FailedPrecondition { + t.Fatalf("cross-atespace CreateActor status = %v, want FailedPrecondition", status.Code(err)) + } + updated, err := tc.client.UpdateActorSnapshotTag(context.Background(), &ateapipb.UpdateActorSnapshotTagRequest{ + Tag: tagRef, + Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED, + }) + if err != nil || updated.GetScope() != ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED { + t.Fatalf("UpdateActorSnapshotTag = (%v, %v), want published", updated, err) + } + if got, err := tc.client.GetActorSnapshot(context.Background(), &ateapipb.GetActorSnapshotRequest{Snapshot: snapshotTagRef}); err != nil || got.GetMetadata().GetUid() != snapshot.GetMetadata().GetUid() { + t.Fatalf("tag after publication = (%v, %v), want same address and snapshot", got, err) + } + createAtespace(t, tc, "other") + if _, err := tc.client.CreateActor(context.Background(), &ateapipb.CreateActorRequest{ + Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "other", Name: "cross-atespace"}, + ActorTemplateNamespace: ns, + ActorTemplateName: "tmpl1", + }, + SourceSnapshot: snapshotTagRef, + }); err != nil { + t.Fatalf("CreateActor from published tag failed: %v", err) + } + + clone, err := tc.client.CreateActor(context.Background(), &ateapipb.CreateActorRequest{ + Actor: &ateapipb.Actor{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "clone"}, + ActorTemplateNamespace: ns, + ActorTemplateName: "tmpl1", + }, + SourceSnapshot: snapshotTagRef, + }) + if err != nil { + t.Fatalf("CreateActor from snapshot failed: %v", err) + } + if !proto.Equal(clone.GetLatestSnapshot(), ref) { + t.Fatalf("clone latest snapshot = %v, want %v", clone.GetLatestSnapshot(), ref) + } + if _, err := tc.client.ResumeActor(context.Background(), &ateapipb.ResumeActorRequest{Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "clone"}}); err != nil { + t.Fatalf("ResumeActor clone failed: %v", err) + } + if !tc.fakeAtelet.RestoreCalled { + t.Error("resuming clone did not restore its source ActorSnapshot") + } + cloneSuspended, err := tc.client.SuspendActor(context.Background(), &ateapipb.SuspendActorRequest{Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "clone"}}) + if err != nil { + t.Fatalf("SuspendActor clone failed: %v", err) + } + if cloneSuspended.GetActor().GetLatestSnapshot().GetName() == ref.GetName() { + t.Fatal("clone suspension reused its source snapshot") + } + listed, err = tc.client.ListActorSnapshots(context.Background(), &ateapipb.ListActorSnapshotsRequest{Atespace: testAtespace}) + if err != nil || len(listed.GetSnapshots()) != 2 { + t.Fatalf("ListActorSnapshots after clone suspension = (%v, %v), want two", listed, err) + } getResp, err := tc.client.GetActor(context.Background(), &ateapipb.GetActorRequest{ Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: name}, @@ -1550,13 +1670,6 @@ func TestSuspendActor(t *testing.T) { ActorTemplateNamespace: ns, ActorTemplateName: "tmpl1", Status: ateapipb.Actor_STATUS_SUSPENDED, - LatestSnapshotInfo: &ateapipb.SnapshotInfo{ - Data: &ateapipb.SnapshotInfo_External{ - External: &ateapipb.ExternalSnapshotInfo{ - SnapshotUriPrefix: "gs://fake-fake-fake/snapshots/", - }, - }, - }, } if diff := cmp.Diff(want, getResp, @@ -1564,13 +1677,25 @@ func TestSuspendActor(t *testing.T) { ignoreUID, ignoreVersion, ignoreTimestamps, - protocmp.IgnoreFields(&ateapipb.Actor{}, "ateom_pod_uid"), - protocmp.FilterField(&ateapipb.ExternalSnapshotInfo{}, "snapshot_uri_prefix", cmp.Comparer(func(x, y string) bool { - return strings.HasPrefix(y, x) - })), + protocmp.IgnoreFields(&ateapipb.Actor{}, "ateom_pod_uid", "latest_snapshot"), ); diff != "" { t.Errorf("GetActor response mismatch (-want +got):\n%s", diff) } + if _, err := tc.client.DeleteActor(context.Background(), &ateapipb.DeleteActorRequest{Actor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: name}}); err != nil { + t.Fatalf("DeleteActor source failed: %v", err) + } + if _, err := tc.client.GetActorSnapshot(context.Background(), &ateapipb.GetActorSnapshotRequest{Snapshot: snapshotTagRef}); err != nil { + t.Fatalf("source snapshot disappeared with source Actor: %v", err) + } + if deleted, err := tc.client.DeleteActorSnapshotTag(context.Background(), &ateapipb.DeleteActorSnapshotTagRequest{Tag: tagRef}); err != nil || deleted.GetMetadata().GetName() != tagRef.GetName() { + t.Fatalf("DeleteActorSnapshotTag = (%v, %v)", deleted, err) + } + if _, err := tc.client.GetActorSnapshot(context.Background(), &ateapipb.GetActorSnapshotRequest{Snapshot: snapshotTagRef}); status.Code(err) != codes.NotFound { + t.Fatalf("deleted tag status = %v, want NotFound", status.Code(err)) + } + if _, err := tc.client.GetActorSnapshot(context.Background(), &ateapipb.GetActorSnapshotRequest{Snapshot: snapshotRef}); err != nil { + t.Fatalf("snapshot metadata disappeared after tag deletion: %v", err) + } } // TestPauseActor tests the full workflow of pausing a running actor. @@ -1633,13 +1758,9 @@ func TestPauseActor(t *testing.T) { ActorTemplateNamespace: ns, ActorTemplateName: "tmpl1", Status: ateapipb.Actor_STATUS_PAUSED, - LatestSnapshotInfo: &ateapipb.SnapshotInfo{ - Data: &ateapipb.SnapshotInfo_Local{ - Local: &ateapipb.LocalSnapshotInfo{ - SnapshotPrefix: name, - NodeVmsWithLocalSnapshots: []string{"node1"}, - }, - }, + LocalSnapshotInfo: &ateapipb.LocalSnapshotInfo{ + SnapshotPrefix: name, + NodeVmsWithLocalSnapshots: []string{"node1"}, }, } diff --git a/cmd/ateapi/internal/controlapi/suspend_actor.go b/cmd/ateapi/internal/controlapi/suspend_actor.go index 7c5bc2b2c..2890e1e26 100644 --- a/cmd/ateapi/internal/controlapi/suspend_actor.go +++ b/cmd/ateapi/internal/controlapi/suspend_actor.go @@ -43,7 +43,6 @@ func (s *Service) SuspendActor(ctx context.Context, req *ateapipb.SuspendActorRe } return nil, err } - setSpanActorAttributes(ctx, actor) return &ateapipb.SuspendActorResponse{Actor: actor}, nil } @@ -57,6 +56,5 @@ func validateSuspendActorRequest(req *ateapipb.SuspendActorRequest) field.ErrorL } else { errs = append(errs, resources.ValidateObjectRef(val, fldPath)...) } - return errs } diff --git a/cmd/ateapi/internal/controlapi/syncer_test.go b/cmd/ateapi/internal/controlapi/syncer_test.go index fa3da123c..8acfaa421 100644 --- a/cmd/ateapi/internal/controlapi/syncer_test.go +++ b/cmd/ateapi/internal/controlapi/syncer_test.go @@ -248,13 +248,7 @@ func TestSyncer_DeleteBoundWorker_ClearsActor(t *testing.T) { Status: ateapipb.Actor_STATUS_RUNNING, AteomPodNamespace: ns, AteomPodName: pod, AteomPodIp: ip, InProgressSnapshot: "gs://snapshots/partial", - LatestSnapshotInfo: &ateapipb.SnapshotInfo{ - Data: &ateapipb.SnapshotInfo_External{ - External: &ateapipb.ExternalSnapshotInfo{ - SnapshotUriPrefix: "gs://snapshots/last", - }, - }, - }, + LatestSnapshot: &ateapipb.ObjectRef{Atespace: "team-orphan", Name: "last"}, }); err != nil { t.Fatalf("create actor: %v", err) } @@ -292,8 +286,8 @@ func TestSyncer_DeleteBoundWorker_ClearsActor(t *testing.T) { if got.AteomPodName != "" || got.AteomPodNamespace != "" || got.AteomPodIp != "" || got.InProgressSnapshot != "" { t.Errorf("bind fields not cleared: %+v", got) } - if got.GetLatestSnapshotInfo().GetExternal().SnapshotUriPrefix == "" { - t.Errorf("External SnapshotUriPrefix must be preserved") + if got.GetLatestSnapshot().GetName() == "" { + t.Errorf("LatestSnapshot must be preserved") } } diff --git a/cmd/ateapi/internal/controlapi/workflow_pause.go b/cmd/ateapi/internal/controlapi/workflow_pause.go index 35e571e45..c162117f5 100644 --- a/cmd/ateapi/internal/controlapi/workflow_pause.go +++ b/cmd/ateapi/internal/controlapi/workflow_pause.go @@ -272,9 +272,7 @@ func (s *FinalizePausedStep) Execute(ctx context.Context, input *PauseInput, sta if latestActor.Status != ateapipb.Actor_STATUS_CRASHED { localInfo.NodeVmsWithLocalSnapshots = []string{nodeName} } - latestActor.LatestSnapshotInfo = &ateapipb.SnapshotInfo{ - Data: &ateapipb.SnapshotInfo_Local{Local: localInfo}, - } + latestActor.LocalSnapshotInfo = localInfo latestActor.InProgressSnapshot = "" } latestActor.AteomPodNamespace = "" diff --git a/cmd/ateapi/internal/controlapi/workflow_pause_test.go b/cmd/ateapi/internal/controlapi/workflow_pause_test.go index a1128038b..637adb5e7 100644 --- a/cmd/ateapi/internal/controlapi/workflow_pause_test.go +++ b/cmd/ateapi/internal/controlapi/workflow_pause_test.go @@ -71,7 +71,7 @@ func TestFinalizePausedStep_WorkerGone(t *testing.T) { if got.GetStatus() != ateapipb.Actor_STATUS_CRASHED { t.Errorf("status = %v, want CRASHED (node name unknown, cannot resume safely)", got.GetStatus()) } - for _, n := range got.GetLatestSnapshotInfo().GetLocal().GetNodeVmsWithLocalSnapshots() { + for _, n := range got.GetLocalSnapshotInfo().GetNodeVmsWithLocalSnapshots() { if n == "" { t.Errorf("BUG: empty string in NodeVmsWithLocalSnapshots, the scheduler's node restriction would never match a real worker") } @@ -211,15 +211,11 @@ func TestPauseSteps_CheckPrerequisite(t *testing.T) { func TestCallAteletPauseStep_DanglingWorkerDoesNotRecordPhantomSnapshot(t *testing.T) { tests := []struct { name string - prevSnapshot *ateapipb.SnapshotInfo + prevSnapshot *ateapipb.ObjectRef }{ { - name: "keeps previous snapshot", - prevSnapshot: &ateapipb.SnapshotInfo{ - Data: &ateapipb.SnapshotInfo_External{ - External: &ateapipb.ExternalSnapshotInfo{SnapshotUriPrefix: "gs://snapshots/actor-1/prev"}, - }, - }, + name: "keeps previous snapshot", + prevSnapshot: &ateapipb.ObjectRef{Atespace: "team-a", Name: "prev"}, }, { name: "stays nil without previous snapshot", @@ -239,7 +235,7 @@ func TestCallAteletPauseStep_DanglingWorkerDoesNotRecordPhantomSnapshot(t *testi AteomPodName: "pod-gone", WorkerPoolName: "pool", InProgressSnapshot: "actor-1-never-written", - LatestSnapshotInfo: tt.prevSnapshot, + LatestSnapshot: tt.prevSnapshot, } created, err := persistence.CreateActor(ctx, actor) if err != nil { @@ -263,11 +259,11 @@ func TestCallAteletPauseStep_DanglingWorkerDoesNotRecordPhantomSnapshot(t *testi t.Errorf("InProgressSnapshot = %q, want preserved for debugging", got) } if tt.prevSnapshot == nil { - if stored.GetLatestSnapshotInfo() != nil { - t.Errorf("LatestSnapshotInfo = %v, want nil", stored.GetLatestSnapshotInfo()) + if stored.GetLatestSnapshot() != nil { + t.Errorf("LatestSnapshot = %v, want nil", stored.GetLatestSnapshot()) } - } else if got, want := stored.GetLatestSnapshotInfo().GetExternal().GetSnapshotUriPrefix(), tt.prevSnapshot.GetExternal().GetSnapshotUriPrefix(); got != want { - t.Errorf("LatestSnapshotInfo uri = %q, want %q", got, want) + } else if got, want := stored.GetLatestSnapshot().GetName(), tt.prevSnapshot.GetName(); got != want { + t.Errorf("LatestSnapshot name = %q, want %q", got, want) } }) } diff --git a/cmd/ateapi/internal/controlapi/workflow_resume.go b/cmd/ateapi/internal/controlapi/workflow_resume.go index ebb955a37..25a4ea1f4 100644 --- a/cmd/ateapi/internal/controlapi/workflow_resume.go +++ b/cmd/ateapi/internal/controlapi/workflow_resume.go @@ -46,9 +46,11 @@ type ResumeInput struct { // ResumeState holds the mutable state loaded and modified during execution. type ResumeState struct { - Actor *ateapipb.Actor - Worker *ateapipb.Worker - ActorTemplate *atev1alpha1.ActorTemplate + Actor *ateapipb.Actor + Worker *ateapipb.Worker + ActorTemplate *atev1alpha1.ActorTemplate + SnapshotLocation string + SnapshotScope ateapipb.SnapshotContentScope } type LoadActorForResumeStep struct { @@ -79,6 +81,27 @@ func (s *LoadActorForResumeStep) Execute(ctx context.Context, input *ResumeInput return fmt.Errorf("while getting ActorTemplate: %w", err) } state.ActorTemplate = actorTemplate + if ref := actor.GetLatestSnapshot(); ref != nil { + snapshot, location, err := s.store.GetActorSnapshot(ctx, ref.GetAtespace(), ref.GetName()) + if errors.Is(err, store.ErrNotFound) { + return status.Error(codes.DataLoss, "ActorSnapshot data is missing") + } + if err != nil { + return fmt.Errorf("while getting ActorSnapshot: %w", err) + } + state.SnapshotLocation = location + state.SnapshotScope = snapshot.GetContentScope() + } else if actorTemplate.Status.GoldenSnapshot != "" && !input.Boot { + snapshot, location, err := s.store.GetActorSnapshot(ctx, resources.GoldenActorAtespace, actorTemplate.Status.GoldenSnapshot) + if errors.Is(err, store.ErrNotFound) { + return status.Error(codes.DataLoss, "ActorTemplate golden snapshot data is missing") + } + if err != nil { + return fmt.Errorf("while getting golden ActorSnapshot: %w", err) + } + state.SnapshotLocation = location + state.SnapshotScope = snapshot.GetContentScope() + } // If the Actor is in Resuming state, it means a previous attempt crashed after AssignWorkerStep. // We don't need to repeat the AssignWorkerStep, load the Worker now. @@ -255,7 +278,7 @@ func schedulingConstraints(actor *ateapipb.Actor, tmpl *atev1alpha1.ActorTemplat c := scheduling.Constraints{ SandboxClass: string(tmpl.Spec.SandboxClass), ActorSelector: labels.SelectorFromSet(labels.Set(actor.GetWorkerSelector().GetMatchLabels())), - RequiredNodes: actor.GetLatestSnapshotInfo().GetLocal().GetNodeVmsWithLocalSnapshots(), + RequiredNodes: actor.GetLocalSnapshotInfo().GetNodeVmsWithLocalSnapshots(), } if tmpl.Spec.WorkerSelector != nil { sel, err := metav1.LabelSelectorAsSelector(tmpl.Spec.WorkerSelector) @@ -385,7 +408,7 @@ func (s *CallAteletRestoreStep) Execute(ctx context.Context, input *ResumeInput, return err } - if data := state.Actor.GetLatestSnapshotInfo().GetData(); data != nil { + if local := state.Actor.GetLocalSnapshotInfo(); local != nil { slog.InfoContext(ctx, "Actor has snapshot; Restoring from snapshot") req := &ateletpb.RestoreRequest{ @@ -397,33 +420,16 @@ func (s *CallAteletRestoreStep) Execute(ctx context.Context, input *ResumeInput, Spec: workloadSpec, ActorUid: state.Actor.GetMetadata().Uid, } - switch d := data.(type) { - case *ateapipb.SnapshotInfo_Local: - req.Type = ateletpb.CheckpointType_CHECKPOINT_TYPE_LOCAL - req.Config = &ateletpb.RestoreRequest_LocalConfig{ - LocalConfig: &ateletpb.LocalCheckpointConfiguration{ - SnapshotPrefix: d.Local.GetSnapshotPrefix(), - }, - } - req.Scope = toAteletSnapshotScope(state.ActorTemplate.Spec.SnapshotsConfig.OnPause) - case *ateapipb.SnapshotInfo_External: - req.Type = ateletpb.CheckpointType_CHECKPOINT_TYPE_EXTERNAL - req.Config = &ateletpb.RestoreRequest_ExternalConfig{ - ExternalConfig: &ateletpb.ExternalCheckpointConfiguration{ - SnapshotUriPrefix: d.External.GetSnapshotUriPrefix(), - }, - } - req.Scope = toAteletSnapshotScope(state.ActorTemplate.Spec.SnapshotsConfig.OnCommit) - default: - return fmt.Errorf("unsupported snapshot type: %T", data) + req.Type = ateletpb.CheckpointType_CHECKPOINT_TYPE_LOCAL + req.Config = &ateletpb.RestoreRequest_LocalConfig{ + LocalConfig: &ateletpb.LocalCheckpointConfiguration{SnapshotPrefix: local.GetSnapshotPrefix()}, } + req.Scope = toAteletSnapshotScope(state.ActorTemplate.Spec.SnapshotsConfig.OnPause) _, err = client.Restore(ctx, req) return maybeCrashActor(ctx, s.store, input.ActorRef, err, "while restoring workload") - } else if state.ActorTemplate.Status.GoldenSnapshot != "" && !input.Boot { - slog.InfoContext(ctx, "Actor has no snapshot; ActorTemplate has golden snapshot; Restoring from golden snapshot") - - snapshot := state.ActorTemplate.Status.GoldenSnapshot + } else if state.SnapshotLocation != "" { + slog.InfoContext(ctx, "Actor has durable snapshot; Restoring from snapshot") req := &ateletpb.RestoreRequest{ TargetAteomUid: state.Actor.GetAteomPodUid(), @@ -435,14 +441,14 @@ func (s *CallAteletRestoreStep) Execute(ctx context.Context, input *ResumeInput, Type: ateletpb.CheckpointType_CHECKPOINT_TYPE_EXTERNAL, Config: &ateletpb.RestoreRequest_ExternalConfig{ ExternalConfig: &ateletpb.ExternalCheckpointConfiguration{ - SnapshotUriPrefix: snapshot, + SnapshotUriPrefix: state.SnapshotLocation, }, }, - Scope: toAteletSnapshotScope(state.ActorTemplate.Spec.SnapshotsConfig.OnCommit), + Scope: actorSnapshotContentScopeToAtelet(state.SnapshotScope), ActorUid: state.Actor.GetMetadata().Uid, } _, err = client.Restore(ctx, req) - return maybeCrashActor(ctx, s.store, input.ActorRef, err, "while creating workload from golden snapshot") + return maybeCrashActor(ctx, s.store, input.ActorRef, err, "while restoring durable snapshot") } else { slog.InfoContext(ctx, "Actor has no snapshot; ActorTemplate has no golden snapshot; Booting from ActorTemplate spec") diff --git a/cmd/ateapi/internal/controlapi/workflow_suspend.go b/cmd/ateapi/internal/controlapi/workflow_suspend.go index a282d670b..28b9bf49b 100644 --- a/cmd/ateapi/internal/controlapi/workflow_suspend.go +++ b/cmd/ateapi/internal/controlapi/workflow_suspend.go @@ -43,6 +43,7 @@ type SuspendInput struct { type SuspendState struct { Actor *ateapipb.Actor ActorTemplate *atev1alpha1.ActorTemplate + SourceVersion int64 } type LoadActorForSuspendStep struct { @@ -64,6 +65,10 @@ func (s *LoadActorForSuspendStep) Execute(ctx context.Context, input *SuspendInp return err } state.Actor = actor + state.SourceVersion = actor.GetMetadata().GetVersion() + if actor.GetStatus() == ateapipb.Actor_STATUS_SUSPENDING { + state.SourceVersion = actor.GetInProgressSnapshotSourceActorVersion() + } actorTemplate, err := s.actorTemplateLister.ActorTemplates(actor.GetActorTemplateNamespace()).Get(actor.GetActorTemplateName()) if err != nil { @@ -93,6 +98,7 @@ func (s *MarkSuspendingStep) CheckPrerequisite(ctx context.Context, input *Suspe } func (s *MarkSuspendingStep) Execute(ctx context.Context, input *SuspendInput, state *SuspendState) error { state.Actor.Status = ateapipb.Actor_STATUS_SUSPENDING + state.Actor.InProgressSnapshotSourceActorVersion = state.SourceVersion snapshotID := time.Now().Format(time.RFC3339) + "-" + rand.Text() state.Actor.InProgressSnapshot = strings.TrimSuffix(state.ActorTemplate.Spec.SnapshotsConfig.Location, "/") + "/snapshots/" + snapshotID updatedActor, err := s.store.UpdateActor(ctx, state.Actor, state.Actor.GetMetadata().GetVersion()) @@ -246,19 +252,31 @@ func (s *FinalizeSuspendedStep) Execute(ctx context.Context, input *SuspendInput } latestActor.Status = ateapipb.Actor_STATUS_SUSPENDED if latestActor.InProgressSnapshot != "" { - latestActor.LatestSnapshotInfo = &ateapipb.SnapshotInfo{ - Data: &ateapipb.SnapshotInfo_External{ - External: &ateapipb.ExternalSnapshotInfo{ - SnapshotUriPrefix: latestActor.InProgressSnapshot, - }, - }, + location := latestActor.InProgressSnapshot + prefix := strings.TrimSuffix(state.ActorTemplate.Spec.SnapshotsConfig.Location, "/") + "/snapshots/" + snapshotID := strings.ToLower(strings.NewReplacer(":", "-", "+", "-").Replace(strings.TrimPrefix(location, prefix))) + snapshot := &ateapipb.ActorSnapshot{ + Metadata: &ateapipb.ResourceMetadata{Atespace: input.ActorRef.Atespace, Name: snapshotID}, + SourceActor: input.ActorRef.ToObjectRef(), + SourceActorUid: latestActor.GetMetadata().GetUid(), + SourceActorVersion: state.SourceVersion, + ActorTemplateNamespace: latestActor.GetActorTemplateNamespace(), + ActorTemplateName: latestActor.GetActorTemplateName(), + ActorTemplateUid: string(state.ActorTemplate.GetUID()), + ContentScope: toActorSnapshotContentScope(state.ActorTemplate.Spec.SnapshotsConfig.OnCommit), + } + if _, err := s.store.CreateActorSnapshot(ctx, snapshot, location); err != nil && !errors.Is(err, store.ErrAlreadyExists) { + return err } + latestActor.LatestSnapshot = &ateapipb.ObjectRef{Atespace: input.ActorRef.Atespace, Name: snapshotID} latestActor.InProgressSnapshot = "" + latestActor.InProgressSnapshotSourceActorVersion = 0 } latestActor.AteomPodNamespace = "" latestActor.AteomPodName = "" latestActor.AteomPodIp = "" latestActor.WorkerPoolName = "" + latestActor.LocalSnapshotInfo = nil updatedActor, err := s.store.UpdateActor(ctx, latestActor, latestActor.GetMetadata().GetVersion()) if err != nil { return err diff --git a/cmd/ateapi/internal/controlapi/workflow_suspend_test.go b/cmd/ateapi/internal/controlapi/workflow_suspend_test.go index e1d19b123..ba418a418 100644 --- a/cmd/ateapi/internal/controlapi/workflow_suspend_test.go +++ b/cmd/ateapi/internal/controlapi/workflow_suspend_test.go @@ -87,7 +87,7 @@ func TestSuspendActorWorkflow_RejectedAndIdempotentPaths(t *testing.T) { { // Suspending a SUSPENDED actor succeeds idempotently via // IsComplete fast-forward without calling atelet. - name: "already suspended succeeds", + name: "newly created suspended succeeds", seedStatus: ateapipb.Actor_STATUS_SUSPENDED, wantStatus: ateapipb.Actor_STATUS_SUSPENDED, }, @@ -234,15 +234,11 @@ func newDanglingDialer() *AteletDialer { func TestCallAteletSuspendStep_DanglingWorkerDoesNotRecordPhantomSnapshot(t *testing.T) { tests := []struct { name string - prevSnapshot *ateapipb.SnapshotInfo + prevSnapshot *ateapipb.ObjectRef }{ { - name: "keeps previous snapshot", - prevSnapshot: &ateapipb.SnapshotInfo{ - Data: &ateapipb.SnapshotInfo_External{ - External: &ateapipb.ExternalSnapshotInfo{SnapshotUriPrefix: "gs://snapshots/actor-1/prev"}, - }, - }, + name: "keeps previous snapshot", + prevSnapshot: &ateapipb.ObjectRef{Atespace: "team-a", Name: "prev"}, }, { name: "stays nil without previous snapshot", @@ -262,7 +258,7 @@ func TestCallAteletSuspendStep_DanglingWorkerDoesNotRecordPhantomSnapshot(t *tes AteomPodName: "pod-gone", WorkerPoolName: "pool", InProgressSnapshot: "gs://snapshots/actor-1/never-written", - LatestSnapshotInfo: tt.prevSnapshot, + LatestSnapshot: tt.prevSnapshot, } created, err := persistence.CreateActor(ctx, actor) if err != nil { @@ -286,11 +282,11 @@ func TestCallAteletSuspendStep_DanglingWorkerDoesNotRecordPhantomSnapshot(t *tes t.Errorf("InProgressSnapshot = %q, want preserved for debugging", got) } if tt.prevSnapshot == nil { - if stored.GetLatestSnapshotInfo() != nil { - t.Errorf("LatestSnapshotInfo = %v, want nil", stored.GetLatestSnapshotInfo()) + if stored.GetLatestSnapshot() != nil { + t.Errorf("LatestSnapshot = %v, want nil", stored.GetLatestSnapshot()) } - } else if got, want := stored.GetLatestSnapshotInfo().GetExternal().GetSnapshotUriPrefix(), tt.prevSnapshot.GetExternal().GetSnapshotUriPrefix(); got != want { - t.Errorf("LatestSnapshotInfo uri = %q, want %q", got, want) + } else if got, want := stored.GetLatestSnapshot().GetName(), tt.prevSnapshot.GetName(); got != want { + t.Errorf("LatestSnapshot name = %q, want %q", got, want) } }) } @@ -337,7 +333,7 @@ func TestFinalizeSuspendedStep_ReleasesOnlyOwnWorker(t *testing.T) { AteomPodNamespace: "worker-ns", AteomPodName: "pod-1", WorkerPoolName: "pool", - InProgressSnapshot: "gs://snapshots/shared/1", + InProgressSnapshot: "snapshot-1", } if _, err := persistence.CreateActor(ctx, actor); err != nil { t.Fatalf("CreateActor: %v", err) @@ -345,7 +341,8 @@ func TestFinalizeSuspendedStep_ReleasesOnlyOwnWorker(t *testing.T) { step := &FinalizeSuspendedStep{store: persistence} input := &SuspendInput{ActorRef: resources.ActorRef{Atespace: "team-a", Name: "shared"}} - if err := step.Execute(ctx, input, &SuspendState{}); err != nil { + state := &SuspendState{ActorTemplate: &atev1alpha1.ActorTemplate{Spec: atev1alpha1.ActorTemplateSpec{SnapshotsConfig: atev1alpha1.SnapshotsConfig{Location: "gs://snapshots"}}}} + if err := step.Execute(ctx, input, state); err != nil { t.Fatalf("Execute: %v", err) } diff --git a/cmd/ateapi/internal/store/ateredis/ateredis.go b/cmd/ateapi/internal/store/ateredis/ateredis.go index e5ada1ff8..3ceaa578c 100644 --- a/cmd/ateapi/internal/store/ateredis/ateredis.go +++ b/cmd/ateapi/internal/store/ateredis/ateredis.go @@ -107,6 +107,50 @@ func actorScanPattern(atespace string) string { return "actor:" + atespace + ":*" } +func actorSnapshotDBKey(atespace, name string) string { + return "actor-snapshot:" + atespace + ":" + name +} + +func actorSnapshotScanPattern(atespace string) string { + if atespace == "" { + return "actor-snapshot:*" + } + return "actor-snapshot:" + atespace + ":*" +} + +func actorSnapshotTagDBKey(atespace, name string) string { + return "actor-snapshot-tag:" + atespace + ":" + name +} + +func actorSnapshotTagScanPattern(atespace string) string { + return "actor-snapshot-tag:" + atespace + ":*" +} + +type dbActorSnapshot struct { + Snapshot json.RawMessage `json:"snapshot"` + Location string `json:"location"` +} + +func marshalActorSnapshot(snapshot *ateapipb.ActorSnapshot, location string) ([]byte, error) { + b, err := protojson.Marshal(snapshot) + if err != nil { + return nil, err + } + return json.Marshal(dbActorSnapshot{Snapshot: b, Location: location}) +} + +func unmarshalActorSnapshot(b []byte) (*ateapipb.ActorSnapshot, string, error) { + var record dbActorSnapshot + if err := json.Unmarshal(b, &record); err != nil { + return nil, "", err + } + snapshot := &ateapipb.ActorSnapshot{} + if err := protojson.Unmarshal(record.Snapshot, snapshot); err != nil { + return nil, "", err + } + return snapshot, record.Location, nil +} + func atespaceDBKey(name string) string { return "atespace:" + name } @@ -178,8 +222,8 @@ func (s *Persistence) ListAtespaces(ctx context.Context, pageSize int32, pageTok } // DeleteAtespace deletes an empty atespace. Returns store.ErrNotFound if the -// atespace does not exist, or store.ErrFailedPrecondition if any actor still -// lives in it. +// atespace does not exist, or store.ErrFailedPrecondition if any Actor or +// ActorSnapshotTag still lives in it. func (s *Persistence) DeleteAtespace(ctx context.Context, name string) (*ateapipb.Atespace, error) { dbKey := atespaceDBKey(name) @@ -206,13 +250,41 @@ func (s *Persistence) DeleteAtespace(ctx context.Context, name string) (*ateapip if len(actors) > 0 { return nil, store.ErrFailedPrecondition } - + hasTags, err := s.hasMatching(ctx, actorSnapshotTagScanPattern(name)) + if err != nil { + return nil, fmt.Errorf("while checking ActorSnapshot tags: %w", err) + } + if hasTags { + return nil, store.ErrFailedPrecondition + } if err := s.rdb.Del(ctx, dbKey).Err(); err != nil { return nil, fmt.Errorf("while deleting atespace key %q: %w", dbKey, err) } return deleted, nil } +func (s *Persistence) hasMatching(ctx context.Context, pattern string) (bool, error) { + masters, err := s.getSortedMasters(ctx) + if err != nil { + return false, err + } + for _, master := range masters { + for cursor := uint64(0); ; { + keys, next, err := master.Scan(ctx, cursor, pattern, 1).Result() + if err != nil { + return false, err + } + if len(keys) > 0 { + return true, nil + } + if cursor = next; cursor == 0 { + break + } + } + } + return false, nil +} + func workerDBKey(namespace, poolName, podName string) string { return "worker:" + namespace + ":" + poolName + ":" + podName } @@ -363,6 +435,148 @@ func (s *Persistence) CreateActor(ctx context.Context, actor *ateapipb.Actor) (* return dbActor, nil } +func (s *Persistence) CreateActorSnapshot(ctx context.Context, snapshot *ateapipb.ActorSnapshot, location string) (*ateapipb.ActorSnapshot, error) { + dbKey := actorSnapshotDBKey(snapshot.GetMetadata().GetAtespace(), snapshot.GetMetadata().GetName()) + dbSnapshot := proto.Clone(snapshot).(*ateapipb.ActorSnapshot) + dbSnapshot.Metadata = newCreateMetadata(snapshot.GetMetadata().GetAtespace(), snapshot.GetMetadata().GetName()) + b, err := marshalActorSnapshot(dbSnapshot, location) + if err != nil { + return nil, fmt.Errorf("while marshaling actor snapshot: %w", err) + } + ok, err := s.rdb.SetNX(ctx, dbKey, b, 0).Result() + if err != nil { + return nil, fmt.Errorf("while creating actor snapshot: %w", err) + } + if !ok { + return nil, store.ErrAlreadyExists + } + return dbSnapshot, nil +} + +func (s *Persistence) GetActorSnapshot(ctx context.Context, atespace, name string) (*ateapipb.ActorSnapshot, string, error) { + dbKey := actorSnapshotDBKey(atespace, name) + b, err := s.rdb.Get(ctx, dbKey).Bytes() + if err != nil { + if errors.Is(err, redis.Nil) { + return nil, "", store.ErrNotFound + } + return nil, "", fmt.Errorf("while getting actor snapshot key %q: %w", dbKey, err) + } + snapshot, location, err := unmarshalActorSnapshot(b) + if err != nil { + return nil, "", fmt.Errorf("while unmarshaling actor snapshot: %w", err) + } + return snapshot, location, nil +} + +func (s *Persistence) GetActorSnapshotByTag(ctx context.Context, atespace, name string) (*ateapipb.ActorSnapshot, string, *ateapipb.ActorSnapshotTag, error) { + b, err := s.rdb.Get(ctx, actorSnapshotTagDBKey(atespace, name)).Bytes() + if err != nil { + if errors.Is(err, redis.Nil) { + return nil, "", nil, store.ErrNotFound + } + return nil, "", nil, fmt.Errorf("while resolving actor snapshot tag %s/%s: %w", atespace, name, err) + } + tag := &ateapipb.ActorSnapshotTag{} + if err := protojson.Unmarshal(b, tag); err != nil { + return nil, "", nil, fmt.Errorf("while unmarshaling actor snapshot tag %s/%s: %w", atespace, name, err) + } + snapshot, location, err := s.GetActorSnapshot(ctx, tag.GetSnapshot().GetAtespace(), tag.GetSnapshot().GetName()) + return snapshot, location, tag, err +} + +func (s *Persistence) ListActorSnapshots(ctx context.Context, atespace string, pageSize int32, pageTokenStr string) ([]*ateapipb.ActorSnapshot, string, error) { + var result []*ateapipb.ActorSnapshot + nextToken, err := s.listPage(ctx, actorSnapshotScanPattern(atespace), pageSize, pageTokenStr, func(ctx context.Context, master *redis.Client, keys []string) (int, error) { + values, err := master.MGet(ctx, keys...).Result() + if err != nil { + return 0, err + } + for _, value := range values { + if value == nil { + continue + } + snapshot, _, err := unmarshalActorSnapshot([]byte(value.(string))) + if err != nil { + return 0, err + } + result = append(result, snapshot) + } + return len(values), nil + }) + if err != nil { + return nil, "", err + } + return result, nextToken, nil +} + +func (s *Persistence) TagActorSnapshot(ctx context.Context, atespace, name string, tag *ateapipb.ActorSnapshotTag) (*ateapipb.ActorSnapshotTag, error) { + if _, _, err := s.GetActorSnapshot(ctx, atespace, name); err != nil { + return nil, err + } + dbTag := proto.Clone(tag).(*ateapipb.ActorSnapshotTag) + dbTag.Metadata = newCreateMetadata(tag.GetMetadata().GetAtespace(), tag.GetMetadata().GetName()) + dbTag.Snapshot = &ateapipb.ObjectRef{Atespace: atespace, Name: name} + b, err := protojson.Marshal(dbTag) + if err != nil { + return nil, fmt.Errorf("while marshaling actor snapshot tag: %w", err) + } + tagKey := actorSnapshotTagDBKey(dbTag.GetMetadata().GetAtespace(), dbTag.GetMetadata().GetName()) + created, err := s.rdb.SetNX(ctx, tagKey, b, 0).Result() + if err != nil { + return nil, fmt.Errorf("while creating actor snapshot tag: %w", err) + } + if !created { + existing, err := s.rdb.Get(ctx, tagKey).Bytes() + if err != nil { + return nil, fmt.Errorf("while getting actor snapshot tag: %w", err) + } + existingTag := &ateapipb.ActorSnapshotTag{} + if err := protojson.Unmarshal(existing, existingTag); err != nil { + return nil, fmt.Errorf("while unmarshaling actor snapshot tag: %w", err) + } + if existingTag.GetSnapshot().GetAtespace() != atespace || existingTag.GetSnapshot().GetName() != name || existingTag.GetScope() != tag.GetScope() { + return nil, store.ErrAlreadyExists + } + return existingTag, nil + } + return dbTag, nil +} + +func (s *Persistence) UpdateActorSnapshotTag(ctx context.Context, atespace, name string, scope ateapipb.ActorSnapshotTagScope) (*ateapipb.ActorSnapshotTag, error) { + _, _, tag, err := s.GetActorSnapshotByTag(ctx, atespace, name) + if err != nil { + return nil, err + } + if tag.GetScope() == scope { + return tag, nil + } + tag.Scope = scope + tag.Metadata = newUpdateMetadata(tag.GetMetadata()) + b, err := protojson.Marshal(tag) + if err != nil { + return nil, fmt.Errorf("while marshaling actor snapshot tag: %w", err) + } + if err := s.rdb.Set(ctx, actorSnapshotTagDBKey(atespace, name), b, 0).Err(); err != nil { + return nil, fmt.Errorf("while updating actor snapshot tag: %w", err) + } + return tag, nil +} + +func (s *Persistence) DeleteActorSnapshotTag(ctx context.Context, atespace, name string) (*ateapipb.ActorSnapshotTag, error) { + _, _, tag, err := s.GetActorSnapshotByTag(ctx, atespace, name) + if err != nil { + return nil, err + } + tagKey := actorSnapshotTagDBKey(atespace, name) + if n, err := s.rdb.Del(ctx, tagKey).Result(); err != nil { + return nil, fmt.Errorf("while deleting actor snapshot tag: %w", err) + } else if n == 0 { + return nil, store.ErrNotFound + } + return tag, nil +} + func (s *Persistence) CreateWorker(ctx context.Context, worker *ateapipb.Worker) error { dbKey := workerDBKey(worker.GetWorkerNamespace(), worker.GetWorkerPool(), worker.GetWorkerPod()) diff --git a/cmd/ateapi/internal/store/ateredis/ateredis_test.go b/cmd/ateapi/internal/store/ateredis/ateredis_test.go index 87959a153..e881758f8 100644 --- a/cmd/ateapi/internal/store/ateredis/ateredis_test.go +++ b/cmd/ateapi/internal/store/ateredis/ateredis_test.go @@ -519,26 +519,14 @@ func TestListActors(t *testing.T) { ActorTemplateNamespace: "ns1", ActorTemplateName: "tmpl1", Status: ateapipb.Actor_STATUS_SUSPENDED, - LatestSnapshotInfo: &ateapipb.SnapshotInfo{ - Data: &ateapipb.SnapshotInfo_External{ - External: &ateapipb.ExternalSnapshotInfo{ - SnapshotUriPrefix: "gs://b1/f1", - }, - }, - }, + LatestSnapshot: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "snapshot-1"}, } actor2 := &ateapipb.Actor{ Metadata: &ateapipb.ResourceMetadata{Name: "id2", Atespace: testAtespace}, ActorTemplateNamespace: "ns1", ActorTemplateName: "tmpl1", Status: ateapipb.Actor_STATUS_SUSPENDED, - LatestSnapshotInfo: &ateapipb.SnapshotInfo{ - Data: &ateapipb.SnapshotInfo_External{ - External: &ateapipb.ExternalSnapshotInfo{ - SnapshotUriPrefix: "gs://b1/f2", - }, - }, - }, + LatestSnapshot: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "snapshot-2"}, } if _, err := s.CreateActor(ctx, actor1); err != nil { @@ -572,6 +560,79 @@ func TestListActors(t *testing.T) { } } +func TestActorSnapshotLifecycle(t *testing.T) { + _, s, ctx := setupTest(t) + snapshot := &ateapipb.ActorSnapshot{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "snapshot-1"}, + SourceActor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "actor-1"}, + SourceActorUid: "actor-uid", + SourceActorVersion: 7, + ContentScope: ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_FULL, + } + created, err := s.CreateActorSnapshot(ctx, snapshot, "gs://private/snapshot-1") + if err != nil { + t.Fatalf("CreateActorSnapshot: %v", err) + } + got, location, err := s.GetActorSnapshot(ctx, testAtespace, "snapshot-1") + if err != nil { + t.Fatalf("GetActorSnapshot: %v", err) + } + if !proto.Equal(created, got) || location != "gs://private/snapshot-1" { + t.Fatalf("GetActorSnapshot = (%v, %q), want (%v, private location)", got, location, created) + } + tag := &ateapipb.ActorSnapshotTag{ + Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "before-upgrade"}, + Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE, + } + tagged, err := s.TagActorSnapshot(ctx, testAtespace, "snapshot-1", tag) + if err != nil || tagged.GetSnapshot().GetName() != "snapshot-1" { + t.Fatalf("TagActorSnapshot = (%v, %v), want stable tag", tagged, err) + } + byTag, _, resolvedTag, err := s.GetActorSnapshotByTag(ctx, testAtespace, "before-upgrade") + if err != nil || !proto.Equal(created, byTag) || !proto.Equal(tagged, resolvedTag) { + t.Fatalf("GetActorSnapshotByTag = (%v, %v, %v), want tagged snapshot", byTag, resolvedTag, err) + } + if _, err := s.CreateActorSnapshot(ctx, &ateapipb.ActorSnapshot{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "other", Name: "snapshot-2"}, + }, "gs://private/snapshot-2"); err != nil { + t.Fatalf("CreateActorSnapshot second snapshot: %v", err) + } + otherTag := &ateapipb.ActorSnapshotTag{Metadata: &ateapipb.ResourceMetadata{Atespace: "other", Name: "before-upgrade"}, Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE} + if _, err := s.TagActorSnapshot(ctx, "other", "snapshot-2", otherTag); err != nil { + t.Fatalf("same tag name in another Atespace: %v", err) + } + if _, err := s.TagActorSnapshot(ctx, "other", "snapshot-2", tag); !errors.Is(err, store.ErrAlreadyExists) { + t.Fatalf("duplicate Atespace tag error = %v, want ErrAlreadyExists", err) + } + differentScope := proto.Clone(tag).(*ateapipb.ActorSnapshotTag) + differentScope.Scope = ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED + if _, err := s.TagActorSnapshot(ctx, testAtespace, "snapshot-1", differentScope); !errors.Is(err, store.ErrAlreadyExists) { + t.Fatalf("re-tag with different scope error = %v, want ErrAlreadyExists", err) + } + tagged, err = s.UpdateActorSnapshotTag(ctx, testAtespace, "before-upgrade", ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED) + if err != nil || tagged.GetScope() != ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED { + t.Fatalf("UpdateActorSnapshotTag = (%v, %v), want published", tagged, err) + } + if byTag, _, resolvedTag, err = s.GetActorSnapshotByTag(ctx, testAtespace, "before-upgrade"); err != nil || byTag.GetMetadata().GetUid() != created.GetMetadata().GetUid() || resolvedTag.GetScope() != ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED { + t.Fatalf("tag after publication = (%v, %v, %v), want same address and snapshot", byTag, resolvedTag, err) + } + listed, _, err := s.ListActorSnapshots(ctx, testAtespace, 10, "") + if err != nil || len(listed) != 1 { + t.Fatalf("ListActorSnapshots = (%v, %v), want one", listed, err) + } + + deleted, err := s.DeleteActorSnapshotTag(ctx, testAtespace, "before-upgrade") + if err != nil || deleted.GetMetadata().GetName() != "before-upgrade" { + t.Fatalf("DeleteActorSnapshotTag = (%v, %v)", deleted, err) + } + if _, _, _, err := s.GetActorSnapshotByTag(ctx, testAtespace, "before-upgrade"); !errors.Is(err, store.ErrNotFound) { + t.Fatalf("deleted tag lookup = %v, want ErrNotFound", err) + } + if got, _, err := s.GetActorSnapshot(ctx, testAtespace, "snapshot-1"); err != nil || got.GetMetadata().GetUid() != created.GetMetadata().GetUid() { + t.Fatalf("snapshot after tag deletion = (%v, %v), want retained metadata", got, err) + } +} + func TestUpdateWorker_Conflict(t *testing.T) { _, s, ctx := setupTest(t) @@ -1333,6 +1394,34 @@ func TestDeleteAtespace_Empty(t *testing.T) { } } +func TestDeleteAtespace_WithTags_Rejected(t *testing.T) { + _, s, ctx := setupTest(t) + + if _, err := s.CreateAtespace(ctx, newTestAtespace("team-a")); err != nil { + t.Fatalf("CreateAtespace: %v", err) + } + if _, err := s.CreateActorSnapshot(ctx, &ateapipb.ActorSnapshot{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "snapshot-1"}, + }, "gs://private/snapshot-1"); err != nil { + t.Fatalf("CreateActorSnapshot: %v", err) + } + if _, err := s.TagActorSnapshot(ctx, "team-a", "snapshot-1", &ateapipb.ActorSnapshotTag{ + Metadata: &ateapipb.ResourceMetadata{Atespace: "team-a", Name: "keep-me"}, + Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED, + }); err != nil { + t.Fatalf("TagActorSnapshot: %v", err) + } + if _, err := s.DeleteAtespace(ctx, "team-a"); !errors.Is(err, store.ErrFailedPrecondition) { + t.Fatalf("DeleteAtespace = %v, want ErrFailedPrecondition", err) + } + if _, _, _, err := s.GetActorSnapshotByTag(ctx, "team-a", "keep-me"); err != nil { + t.Fatalf("GetActorSnapshotByTag after rejected deletion: %v", err) + } + if _, err := s.GetAtespace(ctx, "team-a"); err != nil { + t.Fatalf("GetAtespace after rejected deletion: %v", err) + } +} + func TestDeleteAtespace_NotFound(t *testing.T) { _, s, ctx := setupTest(t) diff --git a/cmd/ateapi/internal/store/store.go b/cmd/ateapi/internal/store/store.go index 556eb1c3c..f849df397 100644 --- a/cmd/ateapi/internal/store/store.go +++ b/cmd/ateapi/internal/store/store.go @@ -64,6 +64,27 @@ type Interface interface { // empty. Returns a page of actors and a next page token. ListActors(ctx context.Context, atespace string, pageSize int32, pageToken string) ([]*ateapipb.Actor, string, error) + // Creates an immutable ActorSnapshot and stores its private physical location. + CreateActorSnapshot(ctx context.Context, snapshot *ateapipb.ActorSnapshot, location string) (*ateapipb.ActorSnapshot, error) + + // Fetches an ActorSnapshot and its private physical location. + GetActorSnapshot(ctx context.Context, atespace, name string) (*ateapipb.ActorSnapshot, string, error) + + // Resolves an Atespace-owned tag to an ActorSnapshot in constant time. + GetActorSnapshotByTag(ctx context.Context, atespace, name string) (*ateapipb.ActorSnapshot, string, *ateapipb.ActorSnapshotTag, error) + + // Lists ActorSnapshots in one atespace, or all atespaces when empty. + ListActorSnapshots(ctx context.Context, atespace string, pageSize int32, pageToken string) ([]*ateapipb.ActorSnapshot, string, error) + + // Adds an immutable Atespace-owned tag to an ActorSnapshot. + TagActorSnapshot(ctx context.Context, atespace, name string, tag *ateapipb.ActorSnapshotTag) (*ateapipb.ActorSnapshotTag, error) + + // Updates a tag's reuse scope. + UpdateActorSnapshotTag(ctx context.Context, atespace, name string, scope ateapipb.ActorSnapshotTagScope) (*ateapipb.ActorSnapshotTag, error) + + // Deletes and returns a tag. + DeleteActorSnapshotTag(ctx context.Context, atespace, name string) (*ateapipb.ActorSnapshotTag, error) + // Stores a new atespace and returns the stored resource with server-assigned // metadata (uid, version, timestamps). The input is not mutated. Returns // ErrAlreadyExists if the name is taken. diff --git a/cmd/atecontroller/internal/controllers/actortemplate_controller.go b/cmd/atecontroller/internal/controllers/actortemplate_controller.go index f5778fc5d..6be09b55e 100644 --- a/cmd/atecontroller/internal/controllers/actortemplate_controller.go +++ b/cmd/atecontroller/internal/controllers/actortemplate_controller.go @@ -161,12 +161,13 @@ func (r *ActorTemplateReconciler) Reconcile(ctx context.Context, req ctrl.Reques return ctrl.Result{}, fmt.Errorf("while suspending golden actor: %w", err) } - if resp.GetActor().GetLatestSnapshotInfo().GetExternal() == nil { - return ctrl.Result{}, fmt.Errorf("unexpected snapshot type for golden actor: %T", resp.GetActor().GetLatestSnapshotInfo().GetData()) + snapshot := resp.GetActor().GetLatestSnapshot() + if snapshot == nil { + return ctrl.Result{}, fmt.Errorf("suspending golden actor returned no ActorSnapshot") } // Transition to PhaseReady - at.Status.GoldenSnapshot = resp.GetActor().GetLatestSnapshotInfo().GetExternal().SnapshotUriPrefix + at.Status.GoldenSnapshot = snapshot.GetName() at.Status.Phase = atev1alpha1.PhaseReady meta.SetStatusCondition(&at.Status.Conditions, metav1.Condition{ Type: "Ready", diff --git a/docs/architecture.md b/docs/architecture.md index 8c734dce6..30212ebad 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -418,7 +418,7 @@ Triggered by an inbound request at the Gateway or an explicit API call. 2. **Assignment**: The Control Plane claims a warm worker from the `WorkerPool`. - 3. **Hydration**: The `atelet` supervisor coordinates with the `ateom` process inside the worker pod to restore the `GoldenSnapshot` (for first-run) or the `LatestSnapshotInfo` (for recurring runs) into the sandbox. + 3. **Hydration**: The `atelet` supervisor coordinates with the `ateom` process inside the worker pod to restore the ActorTemplate's golden `ActorSnapshot` (for first-run) or the Actor's latest `ActorSnapshot` (for recurring runs) into the sandbox. 4. **Status**: Status transitions to `STATUS_RUNNING`. The actor now has an active Worker IP. @@ -437,7 +437,13 @@ Triggered by an explicit `SuspendActor` call. 3. **Reclaim**: The physical worker is wiped and returned to the `WorkerPool`. 4. **Status**: Status transitions back to `STATUS_SUSPENDED`, now pointing to - the `LatestSnapshotInfo` for future resumptions. + an immutable `ActorSnapshot` resource and references it for future resumptions. + +Snapshots may be given tags owned and addressed by an Atespace. The same tag +name may exist in different Atespaces. A tag is an immutable alias and retention +pin: publishing it permits reuse from other Atespaces without changing its +`atespace/name` address. Deleting the owning Atespace deletes all of its tags, +including published tags, but leaves snapshot cleanup to garbage collection. ### Phase 4: Deletion diff --git a/pkg/proto/ateapipb/ateapi.pb.go b/pkg/proto/ateapipb/ateapi.pb.go index 3beca313d..a47b513b9 100644 --- a/pkg/proto/ateapipb/ateapi.pb.go +++ b/pkg/proto/ateapipb/ateapi.pb.go @@ -36,6 +36,107 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type SnapshotContentScope int32 + +const ( + // Defaults to FULL for compatibility with existing snapshot configuration. + SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_UNSPECIFIED SnapshotContentScope = 0 + // Captures process memory, root filesystem changes, and durable data. + SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_FULL SnapshotContentScope = 1 + // Captures durable data without process memory or root filesystem changes. + SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_DATA SnapshotContentScope = 2 +) + +// Enum value maps for SnapshotContentScope. +var ( + SnapshotContentScope_name = map[int32]string{ + 0: "SNAPSHOT_CONTENT_SCOPE_UNSPECIFIED", + 1: "SNAPSHOT_CONTENT_SCOPE_FULL", + 2: "SNAPSHOT_CONTENT_SCOPE_DATA", + } + SnapshotContentScope_value = map[string]int32{ + "SNAPSHOT_CONTENT_SCOPE_UNSPECIFIED": 0, + "SNAPSHOT_CONTENT_SCOPE_FULL": 1, + "SNAPSHOT_CONTENT_SCOPE_DATA": 2, + } +) + +func (x SnapshotContentScope) Enum() *SnapshotContentScope { + p := new(SnapshotContentScope) + *p = x + return p +} + +func (x SnapshotContentScope) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SnapshotContentScope) Descriptor() protoreflect.EnumDescriptor { + return file_ateapi_proto_enumTypes[0].Descriptor() +} + +func (SnapshotContentScope) Type() protoreflect.EnumType { + return &file_ateapi_proto_enumTypes[0] +} + +func (x SnapshotContentScope) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SnapshotContentScope.Descriptor instead. +func (SnapshotContentScope) EnumDescriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{0} +} + +type ActorSnapshotTagScope int32 + +const ( + // May initialize Actors only in the tag's owning Atespace. + ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE ActorSnapshotTagScope = 0 + // Published for use by Actors in any Atespace. The tag remains addressed + // through its owning Atespace. + ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED ActorSnapshotTagScope = 1 +) + +// Enum value maps for ActorSnapshotTagScope. +var ( + ActorSnapshotTagScope_name = map[int32]string{ + 0: "ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE", + 1: "ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED", + } + ActorSnapshotTagScope_value = map[string]int32{ + "ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE": 0, + "ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED": 1, + } +) + +func (x ActorSnapshotTagScope) Enum() *ActorSnapshotTagScope { + p := new(ActorSnapshotTagScope) + *p = x + return p +} + +func (x ActorSnapshotTagScope) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ActorSnapshotTagScope) Descriptor() protoreflect.EnumDescriptor { + return file_ateapi_proto_enumTypes[1].Descriptor() +} + +func (ActorSnapshotTagScope) Type() protoreflect.EnumType { + return &file_ateapi_proto_enumTypes[1] +} + +func (x ActorSnapshotTagScope) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ActorSnapshotTagScope.Descriptor instead. +func (ActorSnapshotTagScope) EnumDescriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{1} +} + type ExternalVolume_Status int32 const ( @@ -69,11 +170,11 @@ func (x ExternalVolume_Status) String() string { } func (ExternalVolume_Status) Descriptor() protoreflect.EnumDescriptor { - return file_ateapi_proto_enumTypes[0].Descriptor() + return file_ateapi_proto_enumTypes[2].Descriptor() } func (ExternalVolume_Status) Type() protoreflect.EnumType { - return &file_ateapi_proto_enumTypes[0] + return &file_ateapi_proto_enumTypes[2] } func (x ExternalVolume_Status) Number() protoreflect.EnumNumber { @@ -82,7 +183,7 @@ func (x ExternalVolume_Status) Number() protoreflect.EnumNumber { // Deprecated: Use ExternalVolume_Status.Descriptor instead. func (ExternalVolume_Status) EnumDescriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{5, 0} + return file_ateapi_proto_rawDescGZIP(), []int{3, 0} } type Actor_Status int32 @@ -133,11 +234,11 @@ func (x Actor_Status) String() string { } func (Actor_Status) Descriptor() protoreflect.EnumDescriptor { - return file_ateapi_proto_enumTypes[1].Descriptor() + return file_ateapi_proto_enumTypes[3].Descriptor() } func (Actor_Status) Type() protoreflect.EnumType { - return &file_ateapi_proto_enumTypes[1] + return &file_ateapi_proto_enumTypes[3] } func (x Actor_Status) Number() protoreflect.EnumNumber { @@ -146,7 +247,7 @@ func (x Actor_Status) Number() protoreflect.EnumNumber { // Deprecated: Use Actor_Status.Descriptor instead. func (Actor_Status) EnumDescriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{6, 0} + return file_ateapi_proto_rawDescGZIP(), []int{4, 0} } type Worker_State int32 @@ -182,11 +283,11 @@ func (x Worker_State) String() string { } func (Worker_State) Descriptor() protoreflect.EnumDescriptor { - return file_ateapi_proto_enumTypes[2].Descriptor() + return file_ateapi_proto_enumTypes[4].Descriptor() } func (Worker_State) Type() protoreflect.EnumType { - return &file_ateapi_proto_enumTypes[2] + return &file_ateapi_proto_enumTypes[4] } func (x Worker_State) Number() protoreflect.EnumNumber { @@ -195,51 +296,7 @@ func (x Worker_State) Number() protoreflect.EnumNumber { // Deprecated: Use Worker_State.Descriptor instead. func (Worker_State) EnumDescriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{29, 0} -} - -type ExternalSnapshotInfo struct { - state protoimpl.MessageState `protogen:"open.v1"` - SnapshotUriPrefix string `protobuf:"bytes,1,opt,name=snapshot_uri_prefix,json=snapshotUriPrefix,proto3" json:"snapshot_uri_prefix,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *ExternalSnapshotInfo) Reset() { - *x = ExternalSnapshotInfo{} - mi := &file_ateapi_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *ExternalSnapshotInfo) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ExternalSnapshotInfo) ProtoMessage() {} - -func (x *ExternalSnapshotInfo) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[0] - 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 ExternalSnapshotInfo.ProtoReflect.Descriptor instead. -func (*ExternalSnapshotInfo) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{0} -} - -func (x *ExternalSnapshotInfo) GetSnapshotUriPrefix() string { - if x != nil { - return x.SnapshotUriPrefix - } - return "" + return file_ateapi_proto_rawDescGZIP(), []int{36, 0} } type LocalSnapshotInfo struct { @@ -253,7 +310,7 @@ type LocalSnapshotInfo struct { func (x *LocalSnapshotInfo) Reset() { *x = LocalSnapshotInfo{} - mi := &file_ateapi_proto_msgTypes[1] + mi := &file_ateapi_proto_msgTypes[0] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -265,7 +322,7 @@ func (x *LocalSnapshotInfo) String() string { func (*LocalSnapshotInfo) ProtoMessage() {} func (x *LocalSnapshotInfo) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[1] + mi := &file_ateapi_proto_msgTypes[0] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -278,7 +335,7 @@ func (x *LocalSnapshotInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use LocalSnapshotInfo.ProtoReflect.Descriptor instead. func (*LocalSnapshotInfo) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{1} + return file_ateapi_proto_rawDescGZIP(), []int{0} } func (x *LocalSnapshotInfo) GetSnapshotPrefix() string { @@ -295,88 +352,6 @@ func (x *LocalSnapshotInfo) GetNodeVmsWithLocalSnapshots() []string { return nil } -type SnapshotInfo struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Types that are valid to be assigned to Data: - // - // *SnapshotInfo_External - // *SnapshotInfo_Local - Data isSnapshotInfo_Data `protobuf_oneof:"data"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache -} - -func (x *SnapshotInfo) Reset() { - *x = SnapshotInfo{} - mi := &file_ateapi_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) -} - -func (x *SnapshotInfo) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SnapshotInfo) ProtoMessage() {} - -func (x *SnapshotInfo) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[2] - 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 SnapshotInfo.ProtoReflect.Descriptor instead. -func (*SnapshotInfo) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{2} -} - -func (x *SnapshotInfo) GetData() isSnapshotInfo_Data { - if x != nil { - return x.Data - } - return nil -} - -func (x *SnapshotInfo) GetExternal() *ExternalSnapshotInfo { - if x != nil { - if x, ok := x.Data.(*SnapshotInfo_External); ok { - return x.External - } - } - return nil -} - -func (x *SnapshotInfo) GetLocal() *LocalSnapshotInfo { - if x != nil { - if x, ok := x.Data.(*SnapshotInfo_Local); ok { - return x.Local - } - } - return nil -} - -type isSnapshotInfo_Data interface { - isSnapshotInfo_Data() -} - -type SnapshotInfo_External struct { - External *ExternalSnapshotInfo `protobuf:"bytes,2,opt,name=external,proto3,oneof"` -} - -type SnapshotInfo_Local struct { - Local *LocalSnapshotInfo `protobuf:"bytes,3,opt,name=local,proto3,oneof"` -} - -func (*SnapshotInfo_External) isSnapshotInfo_Data() {} - -func (*SnapshotInfo_Local) isSnapshotInfo_Data() {} - // Selector matches worker pools by label. // Only equality-based matching is supported. type Selector struct { @@ -388,7 +363,7 @@ type Selector struct { func (x *Selector) Reset() { *x = Selector{} - mi := &file_ateapi_proto_msgTypes[3] + mi := &file_ateapi_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -400,7 +375,7 @@ func (x *Selector) String() string { func (*Selector) ProtoMessage() {} func (x *Selector) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[3] + mi := &file_ateapi_proto_msgTypes[1] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -413,7 +388,7 @@ func (x *Selector) ProtoReflect() protoreflect.Message { // Deprecated: Use Selector.ProtoReflect.Descriptor instead. func (*Selector) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{3} + return file_ateapi_proto_rawDescGZIP(), []int{1} } func (x *Selector) GetMatchLabels() map[string]string { @@ -447,7 +422,7 @@ type ResourceMetadata struct { func (x *ResourceMetadata) Reset() { *x = ResourceMetadata{} - mi := &file_ateapi_proto_msgTypes[4] + mi := &file_ateapi_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -459,7 +434,7 @@ func (x *ResourceMetadata) String() string { func (*ResourceMetadata) ProtoMessage() {} func (x *ResourceMetadata) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[4] + mi := &file_ateapi_proto_msgTypes[2] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -472,7 +447,7 @@ func (x *ResourceMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use ResourceMetadata.ProtoReflect.Descriptor instead. func (*ResourceMetadata) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{4} + return file_ateapi_proto_rawDescGZIP(), []int{2} } func (x *ResourceMetadata) GetAtespace() string { @@ -532,7 +507,7 @@ type ExternalVolume struct { func (x *ExternalVolume) Reset() { *x = ExternalVolume{} - mi := &file_ateapi_proto_msgTypes[5] + mi := &file_ateapi_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -544,7 +519,7 @@ func (x *ExternalVolume) String() string { func (*ExternalVolume) ProtoMessage() {} func (x *ExternalVolume) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[5] + mi := &file_ateapi_proto_msgTypes[3] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -557,7 +532,7 @@ func (x *ExternalVolume) ProtoReflect() protoreflect.Message { // Deprecated: Use ExternalVolume.ProtoReflect.Descriptor instead. func (*ExternalVolume) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{5} + return file_ateapi_proto_rawDescGZIP(), []int{3} } func (x *ExternalVolume) GetActorVolumeId() string { @@ -600,7 +575,6 @@ type Actor struct { AteomPodIp string `protobuf:"bytes,7,opt,name=ateom_pod_ip,json=ateomPodIp,proto3" json:"ateom_pod_ip,omitempty"` InProgressSnapshot string `protobuf:"bytes,8,opt,name=in_progress_snapshot,json=inProgressSnapshot,proto3" json:"in_progress_snapshot,omitempty"` AteomPodUid string `protobuf:"bytes,9,opt,name=ateom_pod_uid,json=ateomPodUid,proto3" json:"ateom_pod_uid,omitempty"` - LatestSnapshotInfo *SnapshotInfo `protobuf:"bytes,10,opt,name=latest_snapshot_info,json=latestSnapshotInfo,proto3" json:"latest_snapshot_info,omitempty"` // worker_selector is the per-actor placement constraint. The scheduler // evaluates the AND of this selector and the template's workerSelector to // find eligible pools. Set at CreateActor; may be updated at any time via @@ -613,6 +587,12 @@ type Actor struct { // suspend/pause since eligibility is no longer a single fixed pool // reference on the ActorTemplate. WorkerPoolName string `protobuf:"bytes,12,opt,name=worker_pool_name,json=workerPoolName,proto3" json:"worker_pool_name,omitempty"` + // The latest durable snapshot created for this Actor. + LatestSnapshot *ObjectRef `protobuf:"bytes,13,opt,name=latest_snapshot,json=latestSnapshot,proto3" json:"latest_snapshot,omitempty"` + // Node-local state used only while the Actor is paused. + LocalSnapshotInfo *LocalSnapshotInfo `protobuf:"bytes,14,opt,name=local_snapshot_info,json=localSnapshotInfo,proto3" json:"local_snapshot_info,omitempty"` + // Actor version captured when the current durable snapshot began. + InProgressSnapshotSourceActorVersion int64 `protobuf:"varint,15,opt,name=in_progress_snapshot_source_actor_version,json=inProgressSnapshotSourceActorVersion,proto3" json:"in_progress_snapshot_source_actor_version,omitempty"` // Volumes attached to the actor. These volumes only live as long as the actor. // They are deleted when the actor is deleted. ActorVolumes []*ExternalVolume `protobuf:"bytes,16,rep,name=actor_volumes,json=actorVolumes,proto3" json:"actor_volumes,omitempty"` @@ -622,7 +602,7 @@ type Actor struct { func (x *Actor) Reset() { *x = Actor{} - mi := &file_ateapi_proto_msgTypes[6] + mi := &file_ateapi_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -634,7 +614,7 @@ func (x *Actor) String() string { func (*Actor) ProtoMessage() {} func (x *Actor) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[6] + mi := &file_ateapi_proto_msgTypes[4] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -647,7 +627,7 @@ func (x *Actor) ProtoReflect() protoreflect.Message { // Deprecated: Use Actor.ProtoReflect.Descriptor instead. func (*Actor) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{6} + return file_ateapi_proto_rawDescGZIP(), []int{4} } func (x *Actor) GetMetadata() *ResourceMetadata { @@ -713,13 +693,6 @@ func (x *Actor) GetAteomPodUid() string { return "" } -func (x *Actor) GetLatestSnapshotInfo() *SnapshotInfo { - if x != nil { - return x.LatestSnapshotInfo - } - return nil -} - func (x *Actor) GetWorkerSelector() *Selector { if x != nil { return x.WorkerSelector @@ -734,38 +707,66 @@ func (x *Actor) GetWorkerPoolName() string { return "" } -func (x *Actor) GetActorVolumes() []*ExternalVolume { +func (x *Actor) GetLatestSnapshot() *ObjectRef { if x != nil { - return x.ActorVolumes + return x.LatestSnapshot } return nil } -// Atespace is the isolation boundary an Actor is created into. Global-scoped: -// metadata.atespace is always empty; the atespace's identity is metadata.name. -type Atespace struct { - state protoimpl.MessageState `protogen:"open.v1"` - // Common resource metadata: name, uid, version, timestamps. - Metadata *ResourceMetadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache +func (x *Actor) GetLocalSnapshotInfo() *LocalSnapshotInfo { + if x != nil { + return x.LocalSnapshotInfo + } + return nil } -func (x *Atespace) Reset() { - *x = Atespace{} - mi := &file_ateapi_proto_msgTypes[7] +func (x *Actor) GetInProgressSnapshotSourceActorVersion() int64 { + if x != nil { + return x.InProgressSnapshotSourceActorVersion + } + return 0 +} + +func (x *Actor) GetActorVolumes() []*ExternalVolume { + if x != nil { + return x.ActorVolumes + } + return nil +} + +// ActorSnapshot is an independently addressable durable Actor snapshot. Its +// contents are immutable. Its physical storage location is private to +// Substrate. +type ActorSnapshot struct { + state protoimpl.MessageState `protogen:"open.v1"` + Metadata *ResourceMetadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + SourceActor *ObjectRef `protobuf:"bytes,2,opt,name=source_actor,json=sourceActor,proto3" json:"source_actor,omitempty"` + SourceActorUid string `protobuf:"bytes,3,opt,name=source_actor_uid,json=sourceActorUid,proto3" json:"source_actor_uid,omitempty"` + SourceActorVersion int64 `protobuf:"varint,4,opt,name=source_actor_version,json=sourceActorVersion,proto3" json:"source_actor_version,omitempty"` + ActorTemplateNamespace string `protobuf:"bytes,5,opt,name=actor_template_namespace,json=actorTemplateNamespace,proto3" json:"actor_template_namespace,omitempty"` + ActorTemplateName string `protobuf:"bytes,6,opt,name=actor_template_name,json=actorTemplateName,proto3" json:"actor_template_name,omitempty"` + ActorTemplateUid string `protobuf:"bytes,7,opt,name=actor_template_uid,json=actorTemplateUid,proto3" json:"actor_template_uid,omitempty"` + ContentScope SnapshotContentScope `protobuf:"varint,8,opt,name=content_scope,json=contentScope,proto3,enum=ateapi.SnapshotContentScope" json:"content_scope,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ActorSnapshot) Reset() { + *x = ActorSnapshot{} + mi := &file_ateapi_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *Atespace) String() string { +func (x *ActorSnapshot) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Atespace) ProtoMessage() {} +func (*ActorSnapshot) ProtoMessage() {} -func (x *Atespace) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[7] +func (x *ActorSnapshot) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[5] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -776,48 +777,206 @@ func (x *Atespace) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Atespace.ProtoReflect.Descriptor instead. -func (*Atespace) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{7} +// Deprecated: Use ActorSnapshot.ProtoReflect.Descriptor instead. +func (*ActorSnapshot) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{5} } -func (x *Atespace) GetMetadata() *ResourceMetadata { +func (x *ActorSnapshot) GetMetadata() *ResourceMetadata { if x != nil { return x.Metadata } return nil } -// ObjectRef references a Substrate resource by its (atespace, name) identity. -type ObjectRef struct { - state protoimpl.MessageState `protogen:"open.v1"` - // The atespace where the resource lives. Empty if the resource is global-scoped. - Atespace string `protobuf:"bytes,1,opt,name=atespace,proto3" json:"atespace,omitempty"` - // The name of the resource. Required. Unique within an atespace, or globally - // unique if the resource is global-scoped. - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache +func (x *ActorSnapshot) GetSourceActor() *ObjectRef { + if x != nil { + return x.SourceActor + } + return nil } -func (x *ObjectRef) Reset() { - *x = ObjectRef{} - mi := &file_ateapi_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) +func (x *ActorSnapshot) GetSourceActorUid() string { + if x != nil { + return x.SourceActorUid + } + return "" } -func (x *ObjectRef) String() string { - return protoimpl.X.MessageStringOf(x) +func (x *ActorSnapshot) GetSourceActorVersion() int64 { + if x != nil { + return x.SourceActorVersion + } + return 0 } -func (*ObjectRef) ProtoMessage() {} - -func (x *ObjectRef) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[8] +func (x *ActorSnapshot) GetActorTemplateNamespace() string { if x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { + return x.ActorTemplateNamespace + } + return "" +} + +func (x *ActorSnapshot) GetActorTemplateName() string { + if x != nil { + return x.ActorTemplateName + } + return "" +} + +func (x *ActorSnapshot) GetActorTemplateUid() string { + if x != nil { + return x.ActorTemplateUid + } + return "" +} + +func (x *ActorSnapshot) GetContentScope() SnapshotContentScope { + if x != nil { + return x.ContentScope + } + return SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_UNSPECIFIED +} + +// ActorSnapshotTag is an immutable, Atespace-owned alias and retention pin. +// Its owning Atespace cannot be deleted until the tag is removed. +type ActorSnapshotTag struct { + state protoimpl.MessageState `protogen:"open.v1"` + Metadata *ResourceMetadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + Snapshot *ObjectRef `protobuf:"bytes,2,opt,name=snapshot,proto3" json:"snapshot,omitempty"` + Scope ActorSnapshotTagScope `protobuf:"varint,3,opt,name=scope,proto3,enum=ateapi.ActorSnapshotTagScope" json:"scope,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ActorSnapshotTag) Reset() { + *x = ActorSnapshotTag{} + mi := &file_ateapi_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ActorSnapshotTag) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ActorSnapshotTag) ProtoMessage() {} + +func (x *ActorSnapshotTag) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[6] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ActorSnapshotTag.ProtoReflect.Descriptor instead. +func (*ActorSnapshotTag) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{6} +} + +func (x *ActorSnapshotTag) GetMetadata() *ResourceMetadata { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *ActorSnapshotTag) GetSnapshot() *ObjectRef { + if x != nil { + return x.Snapshot + } + return nil +} + +func (x *ActorSnapshotTag) GetScope() ActorSnapshotTagScope { + if x != nil { + return x.Scope + } + return ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE +} + +// Atespace is the isolation boundary an Actor is created into. Global-scoped: +// metadata.atespace is always empty; the atespace's identity is metadata.name. +type Atespace struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Common resource metadata: name, uid, version, timestamps. + Metadata *ResourceMetadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Atespace) Reset() { + *x = Atespace{} + mi := &file_ateapi_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Atespace) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Atespace) ProtoMessage() {} + +func (x *Atespace) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[7] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Atespace.ProtoReflect.Descriptor instead. +func (*Atespace) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{7} +} + +func (x *Atespace) GetMetadata() *ResourceMetadata { + if x != nil { + return x.Metadata + } + return nil +} + +// ObjectRef references a Substrate resource by its (atespace, name) identity. +type ObjectRef struct { + state protoimpl.MessageState `protogen:"open.v1"` + // The atespace where the resource lives. Empty if the resource is global-scoped. + Atespace string `protobuf:"bytes,1,opt,name=atespace,proto3" json:"atespace,omitempty"` + // The name of the resource. Required. Unique within an atespace, or globally + // unique if the resource is global-scoped. + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ObjectRef) Reset() { + *x = ObjectRef{} + mi := &file_ateapi_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ObjectRef) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ObjectRef) ProtoMessage() {} + +func (x *ObjectRef) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[8] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) } return ms @@ -844,6 +1003,90 @@ func (x *ObjectRef) GetName() string { return "" } +// ActorSnapshotRef addresses a snapshot by its canonical identity or by an +// Atespace-owned tag. Tag addresses remain stable when tags are published. +type ActorSnapshotRef struct { + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Reference: + // + // *ActorSnapshotRef_Snapshot + // *ActorSnapshotRef_Tag + Reference isActorSnapshotRef_Reference `protobuf_oneof:"reference"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ActorSnapshotRef) Reset() { + *x = ActorSnapshotRef{} + mi := &file_ateapi_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ActorSnapshotRef) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ActorSnapshotRef) ProtoMessage() {} + +func (x *ActorSnapshotRef) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[9] + 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 ActorSnapshotRef.ProtoReflect.Descriptor instead. +func (*ActorSnapshotRef) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{9} +} + +func (x *ActorSnapshotRef) GetReference() isActorSnapshotRef_Reference { + if x != nil { + return x.Reference + } + return nil +} + +func (x *ActorSnapshotRef) GetSnapshot() *ObjectRef { + if x != nil { + if x, ok := x.Reference.(*ActorSnapshotRef_Snapshot); ok { + return x.Snapshot + } + } + return nil +} + +func (x *ActorSnapshotRef) GetTag() *ObjectRef { + if x != nil { + if x, ok := x.Reference.(*ActorSnapshotRef_Tag); ok { + return x.Tag + } + } + return nil +} + +type isActorSnapshotRef_Reference interface { + isActorSnapshotRef_Reference() +} + +type ActorSnapshotRef_Snapshot struct { + Snapshot *ObjectRef `protobuf:"bytes,1,opt,name=snapshot,proto3,oneof"` +} + +type ActorSnapshotRef_Tag struct { + Tag *ObjectRef `protobuf:"bytes,2,opt,name=tag,proto3,oneof"` +} + +func (*ActorSnapshotRef_Snapshot) isActorSnapshotRef_Reference() {} + +func (*ActorSnapshotRef_Tag) isActorSnapshotRef_Reference() {} + type CreateAtespaceRequest struct { state protoimpl.MessageState `protogen:"open.v1"` // The atespace to create. @@ -854,7 +1097,7 @@ type CreateAtespaceRequest struct { func (x *CreateAtespaceRequest) Reset() { *x = CreateAtespaceRequest{} - mi := &file_ateapi_proto_msgTypes[9] + mi := &file_ateapi_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -866,7 +1109,7 @@ func (x *CreateAtespaceRequest) String() string { func (*CreateAtespaceRequest) ProtoMessage() {} func (x *CreateAtespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[9] + mi := &file_ateapi_proto_msgTypes[10] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -879,7 +1122,7 @@ func (x *CreateAtespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateAtespaceRequest.ProtoReflect.Descriptor instead. func (*CreateAtespaceRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{9} + return file_ateapi_proto_rawDescGZIP(), []int{10} } func (x *CreateAtespaceRequest) GetAtespace() *Atespace { @@ -898,7 +1141,7 @@ type GetAtespaceRequest struct { func (x *GetAtespaceRequest) Reset() { *x = GetAtespaceRequest{} - mi := &file_ateapi_proto_msgTypes[10] + mi := &file_ateapi_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -910,7 +1153,7 @@ func (x *GetAtespaceRequest) String() string { func (*GetAtespaceRequest) ProtoMessage() {} func (x *GetAtespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[10] + mi := &file_ateapi_proto_msgTypes[11] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -923,7 +1166,7 @@ func (x *GetAtespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetAtespaceRequest.ProtoReflect.Descriptor instead. func (*GetAtespaceRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{10} + return file_ateapi_proto_rawDescGZIP(), []int{11} } func (x *GetAtespaceRequest) GetAtespace() *ObjectRef { @@ -948,7 +1191,7 @@ type ListAtespacesRequest struct { func (x *ListAtespacesRequest) Reset() { *x = ListAtespacesRequest{} - mi := &file_ateapi_proto_msgTypes[11] + mi := &file_ateapi_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -960,7 +1203,7 @@ func (x *ListAtespacesRequest) String() string { func (*ListAtespacesRequest) ProtoMessage() {} func (x *ListAtespacesRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[11] + mi := &file_ateapi_proto_msgTypes[12] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -973,7 +1216,7 @@ func (x *ListAtespacesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAtespacesRequest.ProtoReflect.Descriptor instead. func (*ListAtespacesRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{11} + return file_ateapi_proto_rawDescGZIP(), []int{12} } func (x *ListAtespacesRequest) GetPageSize() int32 { @@ -1002,7 +1245,7 @@ type ListAtespacesResponse struct { func (x *ListAtespacesResponse) Reset() { *x = ListAtespacesResponse{} - mi := &file_ateapi_proto_msgTypes[12] + mi := &file_ateapi_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1014,7 +1257,7 @@ func (x *ListAtespacesResponse) String() string { func (*ListAtespacesResponse) ProtoMessage() {} func (x *ListAtespacesResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[12] + mi := &file_ateapi_proto_msgTypes[13] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1027,7 +1270,7 @@ func (x *ListAtespacesResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListAtespacesResponse.ProtoReflect.Descriptor instead. func (*ListAtespacesResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{12} + return file_ateapi_proto_rawDescGZIP(), []int{13} } func (x *ListAtespacesResponse) GetAtespaces() []*Atespace { @@ -1053,7 +1296,7 @@ type DeleteAtespaceRequest struct { func (x *DeleteAtespaceRequest) Reset() { *x = DeleteAtespaceRequest{} - mi := &file_ateapi_proto_msgTypes[13] + mi := &file_ateapi_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1065,7 +1308,7 @@ func (x *DeleteAtespaceRequest) String() string { func (*DeleteAtespaceRequest) ProtoMessage() {} func (x *DeleteAtespaceRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[13] + mi := &file_ateapi_proto_msgTypes[14] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1078,7 +1321,7 @@ func (x *DeleteAtespaceRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteAtespaceRequest.ProtoReflect.Descriptor instead. func (*DeleteAtespaceRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{13} + return file_ateapi_proto_rawDescGZIP(), []int{14} } func (x *DeleteAtespaceRequest) GetAtespace() *ObjectRef { @@ -1097,7 +1340,7 @@ type GetActorRequest struct { func (x *GetActorRequest) Reset() { *x = GetActorRequest{} - mi := &file_ateapi_proto_msgTypes[14] + mi := &file_ateapi_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1109,7 +1352,7 @@ func (x *GetActorRequest) String() string { func (*GetActorRequest) ProtoMessage() {} func (x *GetActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[14] + mi := &file_ateapi_proto_msgTypes[15] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1122,7 +1365,7 @@ func (x *GetActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetActorRequest.ProtoReflect.Descriptor instead. func (*GetActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{14} + return file_ateapi_proto_rawDescGZIP(), []int{15} } func (x *GetActorRequest) GetActor() *ObjectRef { @@ -1136,14 +1379,16 @@ func (x *GetActorRequest) GetActor() *ObjectRef { type CreateActorRequest struct { state protoimpl.MessageState `protogen:"open.v1"` // The actor to create. - Actor *Actor `protobuf:"bytes,1,opt,name=actor,proto3" json:"actor,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + Actor *Actor `protobuf:"bytes,1,opt,name=actor,proto3" json:"actor,omitempty"` + // Optional durable snapshot used to initialize the Actor. + SourceSnapshot *ActorSnapshotRef `protobuf:"bytes,2,opt,name=source_snapshot,json=sourceSnapshot,proto3" json:"source_snapshot,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *CreateActorRequest) Reset() { *x = CreateActorRequest{} - mi := &file_ateapi_proto_msgTypes[15] + mi := &file_ateapi_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1155,7 +1400,7 @@ func (x *CreateActorRequest) String() string { func (*CreateActorRequest) ProtoMessage() {} func (x *CreateActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[15] + mi := &file_ateapi_proto_msgTypes[16] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1168,7 +1413,7 @@ func (x *CreateActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateActorRequest.ProtoReflect.Descriptor instead. func (*CreateActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{15} + return file_ateapi_proto_rawDescGZIP(), []int{16} } func (x *CreateActorRequest) GetActor() *Actor { @@ -1178,6 +1423,13 @@ func (x *CreateActorRequest) GetActor() *Actor { return nil } +func (x *CreateActorRequest) GetSourceSnapshot() *ActorSnapshotRef { + if x != nil { + return x.SourceSnapshot + } + return nil +} + // Request to update mutable fields on an existing Actor. // May be called regardless of the actor's current status. // Changes take effect on the next ResumeActor call. @@ -1193,7 +1445,7 @@ type UpdateActorRequest struct { func (x *UpdateActorRequest) Reset() { *x = UpdateActorRequest{} - mi := &file_ateapi_proto_msgTypes[16] + mi := &file_ateapi_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1205,7 +1457,7 @@ func (x *UpdateActorRequest) String() string { func (*UpdateActorRequest) ProtoMessage() {} func (x *UpdateActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[16] + mi := &file_ateapi_proto_msgTypes[17] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1218,45 +1470,318 @@ func (x *UpdateActorRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateActorRequest.ProtoReflect.Descriptor instead. func (*UpdateActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{16} + return file_ateapi_proto_rawDescGZIP(), []int{17} +} + +func (x *UpdateActorRequest) GetActor() *ObjectRef { + if x != nil { + return x.Actor + } + return nil +} + +func (x *UpdateActorRequest) GetWorkerSelector() *Selector { + if x != nil { + return x.WorkerSelector + } + return nil +} + +type UpdateActorResponse 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 *UpdateActorResponse) Reset() { + *x = UpdateActorResponse{} + mi := &file_ateapi_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *UpdateActorResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateActorResponse) ProtoMessage() {} + +func (x *UpdateActorResponse) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[18] + 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 UpdateActorResponse.ProtoReflect.Descriptor instead. +func (*UpdateActorResponse) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{18} +} + +func (x *UpdateActorResponse) GetActor() *Actor { + if x != nil { + return x.Actor + } + return nil +} + +type SuspendActorRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Actor *ObjectRef `protobuf:"bytes,1,opt,name=actor,proto3" json:"actor,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *SuspendActorRequest) Reset() { + *x = SuspendActorRequest{} + mi := &file_ateapi_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SuspendActorRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SuspendActorRequest) ProtoMessage() {} + +func (x *SuspendActorRequest) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[19] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SuspendActorRequest.ProtoReflect.Descriptor instead. +func (*SuspendActorRequest) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{19} +} + +func (x *SuspendActorRequest) GetActor() *ObjectRef { + if x != nil { + return x.Actor + } + return nil +} + +type SuspendActorResponse 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 *SuspendActorResponse) Reset() { + *x = SuspendActorResponse{} + mi := &file_ateapi_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *SuspendActorResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SuspendActorResponse) ProtoMessage() {} + +func (x *SuspendActorResponse) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[20] + 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 SuspendActorResponse.ProtoReflect.Descriptor instead. +func (*SuspendActorResponse) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{20} +} + +func (x *SuspendActorResponse) GetActor() *Actor { + if x != nil { + return x.Actor + } + return nil +} + +type PauseActorRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Actor *ObjectRef `protobuf:"bytes,1,opt,name=actor,proto3" json:"actor,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *PauseActorRequest) Reset() { + *x = PauseActorRequest{} + mi := &file_ateapi_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PauseActorRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PauseActorRequest) ProtoMessage() {} + +func (x *PauseActorRequest) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[21] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PauseActorRequest.ProtoReflect.Descriptor instead. +func (*PauseActorRequest) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{21} +} + +func (x *PauseActorRequest) GetActor() *ObjectRef { + if x != nil { + return x.Actor + } + return nil +} + +type PauseActorResponse 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 *PauseActorResponse) Reset() { + *x = PauseActorResponse{} + mi := &file_ateapi_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *PauseActorResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PauseActorResponse) ProtoMessage() {} + +func (x *PauseActorResponse) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[22] + 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 PauseActorResponse.ProtoReflect.Descriptor instead. +func (*PauseActorResponse) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{22} +} + +func (x *PauseActorResponse) GetActor() *Actor { + if x != nil { + return x.Actor + } + return nil +} + +type ResumeActorRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Actor *ObjectRef `protobuf:"bytes,1,opt,name=actor,proto3" json:"actor,omitempty"` + // If true, skip golden snapshot and boot the workload from scratch. + Boot bool `protobuf:"varint,2,opt,name=boot,proto3" json:"boot,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *ResumeActorRequest) Reset() { + *x = ResumeActorRequest{} + mi := &file_ateapi_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *ResumeActorRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ResumeActorRequest) ProtoMessage() {} + +func (x *ResumeActorRequest) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[23] + 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 ResumeActorRequest.ProtoReflect.Descriptor instead. +func (*ResumeActorRequest) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{23} } -func (x *UpdateActorRequest) GetActor() *ObjectRef { +func (x *ResumeActorRequest) GetActor() *ObjectRef { if x != nil { return x.Actor } return nil } -func (x *UpdateActorRequest) GetWorkerSelector() *Selector { +func (x *ResumeActorRequest) GetBoot() bool { if x != nil { - return x.WorkerSelector + return x.Boot } - return nil + return false } -type UpdateActorResponse struct { +type ResumeActorResponse 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 *UpdateActorResponse) Reset() { - *x = UpdateActorResponse{} - mi := &file_ateapi_proto_msgTypes[17] +func (x *ResumeActorResponse) Reset() { + *x = ResumeActorResponse{} + mi := &file_ateapi_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *UpdateActorResponse) String() string { +func (x *ResumeActorResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*UpdateActorResponse) ProtoMessage() {} +func (*ResumeActorResponse) ProtoMessage() {} -func (x *UpdateActorResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[17] +func (x *ResumeActorResponse) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[24] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1267,40 +1792,40 @@ func (x *UpdateActorResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use UpdateActorResponse.ProtoReflect.Descriptor instead. -func (*UpdateActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{17} +// Deprecated: Use ResumeActorResponse.ProtoReflect.Descriptor instead. +func (*ResumeActorResponse) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{24} } -func (x *UpdateActorResponse) GetActor() *Actor { +func (x *ResumeActorResponse) GetActor() *Actor { if x != nil { return x.Actor } return nil } -type SuspendActorRequest struct { +type DeleteActorRequest struct { state protoimpl.MessageState `protogen:"open.v1"` Actor *ObjectRef `protobuf:"bytes,1,opt,name=actor,proto3" json:"actor,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *SuspendActorRequest) Reset() { - *x = SuspendActorRequest{} - mi := &file_ateapi_proto_msgTypes[18] +func (x *DeleteActorRequest) Reset() { + *x = DeleteActorRequest{} + mi := &file_ateapi_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *SuspendActorRequest) String() string { +func (x *DeleteActorRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*SuspendActorRequest) ProtoMessage() {} +func (*DeleteActorRequest) ProtoMessage() {} -func (x *SuspendActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[18] +func (x *DeleteActorRequest) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[25] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1311,40 +1836,40 @@ func (x *SuspendActorRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use SuspendActorRequest.ProtoReflect.Descriptor instead. -func (*SuspendActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{18} +// Deprecated: Use DeleteActorRequest.ProtoReflect.Descriptor instead. +func (*DeleteActorRequest) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{25} } -func (x *SuspendActorRequest) GetActor() *ObjectRef { +func (x *DeleteActorRequest) GetActor() *ObjectRef { if x != nil { return x.Actor } return nil } -type SuspendActorResponse struct { +type GetActorSnapshotRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - Actor *Actor `protobuf:"bytes,1,opt,name=actor,proto3" json:"actor,omitempty"` + Snapshot *ActorSnapshotRef `protobuf:"bytes,1,opt,name=snapshot,proto3" json:"snapshot,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *SuspendActorResponse) Reset() { - *x = SuspendActorResponse{} - mi := &file_ateapi_proto_msgTypes[19] +func (x *GetActorSnapshotRequest) Reset() { + *x = GetActorSnapshotRequest{} + mi := &file_ateapi_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *SuspendActorResponse) String() string { +func (x *GetActorSnapshotRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*SuspendActorResponse) ProtoMessage() {} +func (*GetActorSnapshotRequest) ProtoMessage() {} -func (x *SuspendActorResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[19] +func (x *GetActorSnapshotRequest) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[26] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1355,40 +1880,42 @@ func (x *SuspendActorResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use SuspendActorResponse.ProtoReflect.Descriptor instead. -func (*SuspendActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{19} +// Deprecated: Use GetActorSnapshotRequest.ProtoReflect.Descriptor instead. +func (*GetActorSnapshotRequest) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{26} } -func (x *SuspendActorResponse) GetActor() *Actor { +func (x *GetActorSnapshotRequest) GetSnapshot() *ActorSnapshotRef { if x != nil { - return x.Actor + return x.Snapshot } return nil } -type PauseActorRequest struct { +type ListActorSnapshotsRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - Actor *ObjectRef `protobuf:"bytes,1,opt,name=actor,proto3" json:"actor,omitempty"` + Atespace string `protobuf:"bytes,1,opt,name=atespace,proto3" json:"atespace,omitempty"` + PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"` + PageToken string `protobuf:"bytes,3,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *PauseActorRequest) Reset() { - *x = PauseActorRequest{} - mi := &file_ateapi_proto_msgTypes[20] +func (x *ListActorSnapshotsRequest) Reset() { + *x = ListActorSnapshotsRequest{} + mi := &file_ateapi_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *PauseActorRequest) String() string { +func (x *ListActorSnapshotsRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*PauseActorRequest) ProtoMessage() {} +func (*ListActorSnapshotsRequest) ProtoMessage() {} -func (x *PauseActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[20] +func (x *ListActorSnapshotsRequest) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[27] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1399,40 +1926,55 @@ func (x *PauseActorRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use PauseActorRequest.ProtoReflect.Descriptor instead. -func (*PauseActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{20} +// Deprecated: Use ListActorSnapshotsRequest.ProtoReflect.Descriptor instead. +func (*ListActorSnapshotsRequest) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{27} } -func (x *PauseActorRequest) GetActor() *ObjectRef { +func (x *ListActorSnapshotsRequest) GetAtespace() string { if x != nil { - return x.Actor + return x.Atespace } - return nil + return "" } -type PauseActorResponse struct { +func (x *ListActorSnapshotsRequest) GetPageSize() int32 { + if x != nil { + return x.PageSize + } + return 0 +} + +func (x *ListActorSnapshotsRequest) GetPageToken() string { + if x != nil { + return x.PageToken + } + return "" +} + +type ListActorSnapshotsResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Actor *Actor `protobuf:"bytes,1,opt,name=actor,proto3" json:"actor,omitempty"` + Snapshots []*ActorSnapshot `protobuf:"bytes,1,rep,name=snapshots,proto3" json:"snapshots,omitempty"` + NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *PauseActorResponse) Reset() { - *x = PauseActorResponse{} - mi := &file_ateapi_proto_msgTypes[21] +func (x *ListActorSnapshotsResponse) Reset() { + *x = ListActorSnapshotsResponse{} + mi := &file_ateapi_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *PauseActorResponse) String() string { +func (x *ListActorSnapshotsResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*PauseActorResponse) ProtoMessage() {} +func (*ListActorSnapshotsResponse) ProtoMessage() {} -func (x *PauseActorResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[21] +func (x *ListActorSnapshotsResponse) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[28] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1443,42 +1985,48 @@ func (x *PauseActorResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use PauseActorResponse.ProtoReflect.Descriptor instead. -func (*PauseActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{21} +// Deprecated: Use ListActorSnapshotsResponse.ProtoReflect.Descriptor instead. +func (*ListActorSnapshotsResponse) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{28} } -func (x *PauseActorResponse) GetActor() *Actor { +func (x *ListActorSnapshotsResponse) GetSnapshots() []*ActorSnapshot { if x != nil { - return x.Actor + return x.Snapshots } return nil } -type ResumeActorRequest struct { - state protoimpl.MessageState `protogen:"open.v1"` - Actor *ObjectRef `protobuf:"bytes,1,opt,name=actor,proto3" json:"actor,omitempty"` - // If true, skip golden snapshot and boot the workload from scratch. - Boot bool `protobuf:"varint,2,opt,name=boot,proto3" json:"boot,omitempty"` +func (x *ListActorSnapshotsResponse) GetNextPageToken() string { + if x != nil { + return x.NextPageToken + } + return "" +} + +type TagActorSnapshotRequest struct { + state protoimpl.MessageState `protogen:"open.v1"` + Snapshot *ActorSnapshotRef `protobuf:"bytes,1,opt,name=snapshot,proto3" json:"snapshot,omitempty"` + Tag *ActorSnapshotTag `protobuf:"bytes,2,opt,name=tag,proto3" json:"tag,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *ResumeActorRequest) Reset() { - *x = ResumeActorRequest{} - mi := &file_ateapi_proto_msgTypes[22] +func (x *TagActorSnapshotRequest) Reset() { + *x = TagActorSnapshotRequest{} + mi := &file_ateapi_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *ResumeActorRequest) String() string { +func (x *TagActorSnapshotRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ResumeActorRequest) ProtoMessage() {} +func (*TagActorSnapshotRequest) ProtoMessage() {} -func (x *ResumeActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[22] +func (x *TagActorSnapshotRequest) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1489,47 +2037,48 @@ func (x *ResumeActorRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ResumeActorRequest.ProtoReflect.Descriptor instead. -func (*ResumeActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{22} +// Deprecated: Use TagActorSnapshotRequest.ProtoReflect.Descriptor instead. +func (*TagActorSnapshotRequest) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{29} } -func (x *ResumeActorRequest) GetActor() *ObjectRef { +func (x *TagActorSnapshotRequest) GetSnapshot() *ActorSnapshotRef { if x != nil { - return x.Actor + return x.Snapshot } return nil } -func (x *ResumeActorRequest) GetBoot() bool { +func (x *TagActorSnapshotRequest) GetTag() *ActorSnapshotTag { if x != nil { - return x.Boot + return x.Tag } - return false + return nil } -type ResumeActorResponse struct { +type UpdateActorSnapshotTagRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - Actor *Actor `protobuf:"bytes,1,opt,name=actor,proto3" json:"actor,omitempty"` + Tag *ObjectRef `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"` + Scope ActorSnapshotTagScope `protobuf:"varint,2,opt,name=scope,proto3,enum=ateapi.ActorSnapshotTagScope" json:"scope,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *ResumeActorResponse) Reset() { - *x = ResumeActorResponse{} - mi := &file_ateapi_proto_msgTypes[23] +func (x *UpdateActorSnapshotTagRequest) Reset() { + *x = UpdateActorSnapshotTagRequest{} + mi := &file_ateapi_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *ResumeActorResponse) String() string { +func (x *UpdateActorSnapshotTagRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*ResumeActorResponse) ProtoMessage() {} +func (*UpdateActorSnapshotTagRequest) ProtoMessage() {} -func (x *ResumeActorResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[23] +func (x *UpdateActorSnapshotTagRequest) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1540,40 +2089,47 @@ func (x *ResumeActorResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use ResumeActorResponse.ProtoReflect.Descriptor instead. -func (*ResumeActorResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{23} +// Deprecated: Use UpdateActorSnapshotTagRequest.ProtoReflect.Descriptor instead. +func (*UpdateActorSnapshotTagRequest) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{30} } -func (x *ResumeActorResponse) GetActor() *Actor { +func (x *UpdateActorSnapshotTagRequest) GetTag() *ObjectRef { if x != nil { - return x.Actor + return x.Tag } return nil } -type DeleteActorRequest struct { +func (x *UpdateActorSnapshotTagRequest) GetScope() ActorSnapshotTagScope { + if x != nil { + return x.Scope + } + return ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE +} + +type DeleteActorSnapshotTagRequest struct { state protoimpl.MessageState `protogen:"open.v1"` - Actor *ObjectRef `protobuf:"bytes,1,opt,name=actor,proto3" json:"actor,omitempty"` + Tag *ObjectRef `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } -func (x *DeleteActorRequest) Reset() { - *x = DeleteActorRequest{} - mi := &file_ateapi_proto_msgTypes[24] +func (x *DeleteActorSnapshotTagRequest) Reset() { + *x = DeleteActorSnapshotTagRequest{} + mi := &file_ateapi_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } -func (x *DeleteActorRequest) String() string { +func (x *DeleteActorSnapshotTagRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*DeleteActorRequest) ProtoMessage() {} +func (*DeleteActorSnapshotTagRequest) ProtoMessage() {} -func (x *DeleteActorRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[24] +func (x *DeleteActorSnapshotTagRequest) ProtoReflect() protoreflect.Message { + mi := &file_ateapi_proto_msgTypes[31] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1584,14 +2140,14 @@ func (x *DeleteActorRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use DeleteActorRequest.ProtoReflect.Descriptor instead. -func (*DeleteActorRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{24} +// Deprecated: Use DeleteActorSnapshotTagRequest.ProtoReflect.Descriptor instead. +func (*DeleteActorSnapshotTagRequest) Descriptor() ([]byte, []int) { + return file_ateapi_proto_rawDescGZIP(), []int{31} } -func (x *DeleteActorRequest) GetActor() *ObjectRef { +func (x *DeleteActorSnapshotTagRequest) GetTag() *ObjectRef { if x != nil { - return x.Actor + return x.Tag } return nil } @@ -1611,7 +2167,7 @@ type ListWorkersRequest struct { func (x *ListWorkersRequest) Reset() { *x = ListWorkersRequest{} - mi := &file_ateapi_proto_msgTypes[25] + mi := &file_ateapi_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1623,7 +2179,7 @@ func (x *ListWorkersRequest) String() string { func (*ListWorkersRequest) ProtoMessage() {} func (x *ListWorkersRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[25] + mi := &file_ateapi_proto_msgTypes[32] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1636,7 +2192,7 @@ func (x *ListWorkersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkersRequest.ProtoReflect.Descriptor instead. func (*ListWorkersRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{25} + return file_ateapi_proto_rawDescGZIP(), []int{32} } func (x *ListWorkersRequest) GetPageSize() int32 { @@ -1665,7 +2221,7 @@ type ListWorkersResponse struct { func (x *ListWorkersResponse) Reset() { *x = ListWorkersResponse{} - mi := &file_ateapi_proto_msgTypes[26] + mi := &file_ateapi_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1677,7 +2233,7 @@ func (x *ListWorkersResponse) String() string { func (*ListWorkersResponse) ProtoMessage() {} func (x *ListWorkersResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[26] + mi := &file_ateapi_proto_msgTypes[33] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1690,7 +2246,7 @@ func (x *ListWorkersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListWorkersResponse.ProtoReflect.Descriptor instead. func (*ListWorkersResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{26} + return file_ateapi_proto_rawDescGZIP(), []int{33} } func (x *ListWorkersResponse) GetWorkers() []*Worker { @@ -1726,7 +2282,7 @@ type ListActorsRequest struct { func (x *ListActorsRequest) Reset() { *x = ListActorsRequest{} - mi := &file_ateapi_proto_msgTypes[27] + mi := &file_ateapi_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1738,7 +2294,7 @@ func (x *ListActorsRequest) String() string { func (*ListActorsRequest) ProtoMessage() {} func (x *ListActorsRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[27] + mi := &file_ateapi_proto_msgTypes[34] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1751,7 +2307,7 @@ func (x *ListActorsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorsRequest.ProtoReflect.Descriptor instead. func (*ListActorsRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{27} + return file_ateapi_proto_rawDescGZIP(), []int{34} } func (x *ListActorsRequest) GetAtespace() string { @@ -1787,7 +2343,7 @@ type ListActorsResponse struct { func (x *ListActorsResponse) Reset() { *x = ListActorsResponse{} - mi := &file_ateapi_proto_msgTypes[28] + mi := &file_ateapi_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1799,7 +2355,7 @@ func (x *ListActorsResponse) String() string { func (*ListActorsResponse) ProtoMessage() {} func (x *ListActorsResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[28] + mi := &file_ateapi_proto_msgTypes[35] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1812,7 +2368,7 @@ func (x *ListActorsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListActorsResponse.ProtoReflect.Descriptor instead. func (*ListActorsResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{28} + return file_ateapi_proto_rawDescGZIP(), []int{35} } func (x *ListActorsResponse) GetActors() []*Actor { @@ -1848,7 +2404,7 @@ type Worker struct { func (x *Worker) Reset() { *x = Worker{} - mi := &file_ateapi_proto_msgTypes[29] + mi := &file_ateapi_proto_msgTypes[36] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1860,7 +2416,7 @@ func (x *Worker) String() string { func (*Worker) ProtoMessage() {} func (x *Worker) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[29] + mi := &file_ateapi_proto_msgTypes[36] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1873,7 +2429,7 @@ func (x *Worker) ProtoReflect() protoreflect.Message { // Deprecated: Use Worker.ProtoReflect.Descriptor instead. func (*Worker) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{29} + return file_ateapi_proto_rawDescGZIP(), []int{36} } func (x *Worker) GetWorkerNamespace() string { @@ -1963,7 +2519,7 @@ type Assignment struct { func (x *Assignment) Reset() { *x = Assignment{} - mi := &file_ateapi_proto_msgTypes[30] + mi := &file_ateapi_proto_msgTypes[37] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1975,7 +2531,7 @@ func (x *Assignment) String() string { func (*Assignment) ProtoMessage() {} func (x *Assignment) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[30] + mi := &file_ateapi_proto_msgTypes[37] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1988,7 +2544,7 @@ func (x *Assignment) ProtoReflect() protoreflect.Message { // Deprecated: Use Assignment.ProtoReflect.Descriptor instead. func (*Assignment) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{30} + return file_ateapi_proto_rawDescGZIP(), []int{37} } func (x *Assignment) GetActorTemplate() *KubeNamespacedObjectRef { @@ -2015,7 +2571,7 @@ type KubeNamespacedObjectRef struct { func (x *KubeNamespacedObjectRef) Reset() { *x = KubeNamespacedObjectRef{} - mi := &file_ateapi_proto_msgTypes[31] + mi := &file_ateapi_proto_msgTypes[38] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2027,7 +2583,7 @@ func (x *KubeNamespacedObjectRef) String() string { func (*KubeNamespacedObjectRef) ProtoMessage() {} func (x *KubeNamespacedObjectRef) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[31] + mi := &file_ateapi_proto_msgTypes[38] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2040,7 +2596,7 @@ func (x *KubeNamespacedObjectRef) ProtoReflect() protoreflect.Message { // Deprecated: Use KubeNamespacedObjectRef.ProtoReflect.Descriptor instead. func (*KubeNamespacedObjectRef) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{31} + return file_ateapi_proto_rawDescGZIP(), []int{38} } func (x *KubeNamespacedObjectRef) GetNamespace() string { @@ -2065,7 +2621,7 @@ type DebugClearRequest struct { func (x *DebugClearRequest) Reset() { *x = DebugClearRequest{} - mi := &file_ateapi_proto_msgTypes[32] + mi := &file_ateapi_proto_msgTypes[39] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2077,7 +2633,7 @@ func (x *DebugClearRequest) String() string { func (*DebugClearRequest) ProtoMessage() {} func (x *DebugClearRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[32] + mi := &file_ateapi_proto_msgTypes[39] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2090,7 +2646,7 @@ func (x *DebugClearRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DebugClearRequest.ProtoReflect.Descriptor instead. func (*DebugClearRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{32} + return file_ateapi_proto_rawDescGZIP(), []int{39} } type DebugClearResponse struct { @@ -2101,7 +2657,7 @@ type DebugClearResponse struct { func (x *DebugClearResponse) Reset() { *x = DebugClearResponse{} - mi := &file_ateapi_proto_msgTypes[33] + mi := &file_ateapi_proto_msgTypes[40] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2113,7 +2669,7 @@ func (x *DebugClearResponse) String() string { func (*DebugClearResponse) ProtoMessage() {} func (x *DebugClearResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[33] + mi := &file_ateapi_proto_msgTypes[40] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2126,7 +2682,7 @@ func (x *DebugClearResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DebugClearResponse.ProtoReflect.Descriptor instead. func (*DebugClearResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{33} + return file_ateapi_proto_rawDescGZIP(), []int{40} } type MintJWTRequest struct { @@ -2141,7 +2697,7 @@ type MintJWTRequest struct { func (x *MintJWTRequest) Reset() { *x = MintJWTRequest{} - mi := &file_ateapi_proto_msgTypes[34] + mi := &file_ateapi_proto_msgTypes[41] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2153,7 +2709,7 @@ func (x *MintJWTRequest) String() string { func (*MintJWTRequest) ProtoMessage() {} func (x *MintJWTRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[34] + mi := &file_ateapi_proto_msgTypes[41] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2166,7 +2722,7 @@ func (x *MintJWTRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintJWTRequest.ProtoReflect.Descriptor instead. func (*MintJWTRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{34} + return file_ateapi_proto_rawDescGZIP(), []int{41} } func (x *MintJWTRequest) GetAudience() []string { @@ -2226,7 +2782,7 @@ type MintJWTResponse struct { func (x *MintJWTResponse) Reset() { *x = MintJWTResponse{} - mi := &file_ateapi_proto_msgTypes[35] + mi := &file_ateapi_proto_msgTypes[42] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2238,7 +2794,7 @@ func (x *MintJWTResponse) String() string { func (*MintJWTResponse) ProtoMessage() {} func (x *MintJWTResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[35] + mi := &file_ateapi_proto_msgTypes[42] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2251,7 +2807,7 @@ func (x *MintJWTResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MintJWTResponse.ProtoReflect.Descriptor instead. func (*MintJWTResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{35} + return file_ateapi_proto_rawDescGZIP(), []int{42} } func (x *MintJWTResponse) GetActorJwt() string { @@ -2276,7 +2832,7 @@ type MintCertRequest struct { func (x *MintCertRequest) Reset() { *x = MintCertRequest{} - mi := &file_ateapi_proto_msgTypes[36] + mi := &file_ateapi_proto_msgTypes[43] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2288,7 +2844,7 @@ func (x *MintCertRequest) String() string { func (*MintCertRequest) ProtoMessage() {} func (x *MintCertRequest) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[36] + mi := &file_ateapi_proto_msgTypes[43] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2301,7 +2857,7 @@ func (x *MintCertRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use MintCertRequest.ProtoReflect.Descriptor instead. func (*MintCertRequest) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{36} + return file_ateapi_proto_rawDescGZIP(), []int{43} } func (x *MintCertRequest) GetAppId() string { @@ -2344,7 +2900,7 @@ type MintCertResponse struct { func (x *MintCertResponse) Reset() { *x = MintCertResponse{} - mi := &file_ateapi_proto_msgTypes[37] + mi := &file_ateapi_proto_msgTypes[44] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2356,7 +2912,7 @@ func (x *MintCertResponse) String() string { func (*MintCertResponse) ProtoMessage() {} func (x *MintCertResponse) ProtoReflect() protoreflect.Message { - mi := &file_ateapi_proto_msgTypes[37] + mi := &file_ateapi_proto_msgTypes[44] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2369,7 +2925,7 @@ func (x *MintCertResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use MintCertResponse.ProtoReflect.Descriptor instead. func (*MintCertResponse) Descriptor() ([]byte, []int) { - return file_ateapi_proto_rawDescGZIP(), []int{37} + return file_ateapi_proto_rawDescGZIP(), []int{44} } func (x *MintCertResponse) GetActorCertificates() [][]byte { @@ -2383,16 +2939,10 @@ var File_ateapi_proto protoreflect.FileDescriptor const file_ateapi_proto_rawDesc = "" + "\n" + - "\fateapi.proto\x12\x06ateapi\x1a\x1fgoogle/protobuf/timestamp.proto\"F\n" + - "\x14ExternalSnapshotInfo\x12.\n" + - "\x13snapshot_uri_prefix\x18\x01 \x01(\tR\x11snapshotUriPrefix\"~\n" + + "\fateapi.proto\x12\x06ateapi\x1a\x1fgoogle/protobuf/timestamp.proto\"~\n" + "\x11LocalSnapshotInfo\x12'\n" + "\x0fsnapshot_prefix\x18\x01 \x01(\tR\x0esnapshotPrefix\x12@\n" + - "\x1dnode_vms_with_local_snapshots\x18\x02 \x03(\tR\x19nodeVmsWithLocalSnapshots\"\x91\x01\n" + - "\fSnapshotInfo\x12:\n" + - "\bexternal\x18\x02 \x01(\v2\x1c.ateapi.ExternalSnapshotInfoH\x00R\bexternal\x121\n" + - "\x05local\x18\x03 \x01(\v2\x19.ateapi.LocalSnapshotInfoH\x00R\x05localB\x06\n" + - "\x04dataJ\x04\b\x01\x10\x02R\x04type\"\x90\x01\n" + + "\x1dnode_vms_with_local_snapshots\x18\x02 \x03(\tR\x19nodeVmsWithLocalSnapshots\"\x90\x01\n" + "\bSelector\x12D\n" + "\fmatch_labels\x18\x01 \x03(\v2!.ateapi.Selector.MatchLabelsEntryR\vmatchLabels\x1a>\n" + "\x10MatchLabelsEntry\x12\x10\n" + @@ -2416,7 +2966,7 @@ const file_ateapi_proto_rawDesc = "" + "\x06Status\x12\x10\n" + "\fPROVISIONING\x10\x00\x12\v\n" + "\aCREATED\x10\x01\x12\f\n" + - "\bDELETING\x10\x02\"\xc1\x06\n" + + "\bDELETING\x10\x02\"\xf5\a\n" + "\x05Actor\x124\n" + "\bmetadata\x18\x01 \x01(\v2\x18.ateapi.ResourceMetadataR\bmetadata\x128\n" + "\x18actor_template_namespace\x18\x02 \x01(\tR\x16actorTemplateNamespace\x12.\n" + @@ -2427,11 +2977,12 @@ const file_ateapi_proto_rawDesc = "" + "\fateom_pod_ip\x18\a \x01(\tR\n" + "ateomPodIp\x120\n" + "\x14in_progress_snapshot\x18\b \x01(\tR\x12inProgressSnapshot\x12\"\n" + - "\rateom_pod_uid\x18\t \x01(\tR\vateomPodUid\x12F\n" + - "\x14latest_snapshot_info\x18\n" + - " \x01(\v2\x14.ateapi.SnapshotInfoR\x12latestSnapshotInfo\x129\n" + + "\rateom_pod_uid\x18\t \x01(\tR\vateomPodUid\x129\n" + "\x0fworker_selector\x18\v \x01(\v2\x10.ateapi.SelectorR\x0eworkerSelector\x12(\n" + - "\x10worker_pool_name\x18\f \x01(\tR\x0eworkerPoolName\x12;\n" + + "\x10worker_pool_name\x18\f \x01(\tR\x0eworkerPoolName\x12:\n" + + "\x0flatest_snapshot\x18\r \x01(\v2\x11.ateapi.ObjectRefR\x0elatestSnapshot\x12I\n" + + "\x13local_snapshot_info\x18\x0e \x01(\v2\x19.ateapi.LocalSnapshotInfoR\x11localSnapshotInfo\x12W\n" + + ")in_progress_snapshot_source_actor_version\x18\x0f \x01(\x03R$inProgressSnapshotSourceActorVersion\x12;\n" + "\ractor_volumes\x18\x10 \x03(\v2\x16.ateapi.ExternalVolumeR\factorVolumes\"\xb1\x01\n" + "\x06Status\x12\x16\n" + "\x12STATUS_UNSPECIFIED\x10\x00\x12\x13\n" + @@ -2441,12 +2992,30 @@ const file_ateapi_proto_rawDesc = "" + "\x10STATUS_SUSPENDED\x10\x04\x12\x12\n" + "\x0eSTATUS_PAUSING\x10\x05\x12\x11\n" + "\rSTATUS_PAUSED\x10\x06\x12\x12\n" + - "\x0eSTATUS_CRASHED\x10\a\"@\n" + + "\x0eSTATUS_CRASHED\x10\aJ\x04\b\n" + + "\x10\vR\x14latest_snapshot_info\"\xb2\x03\n" + + "\rActorSnapshot\x124\n" + + "\bmetadata\x18\x01 \x01(\v2\x18.ateapi.ResourceMetadataR\bmetadata\x124\n" + + "\fsource_actor\x18\x02 \x01(\v2\x11.ateapi.ObjectRefR\vsourceActor\x12(\n" + + "\x10source_actor_uid\x18\x03 \x01(\tR\x0esourceActorUid\x120\n" + + "\x14source_actor_version\x18\x04 \x01(\x03R\x12sourceActorVersion\x128\n" + + "\x18actor_template_namespace\x18\x05 \x01(\tR\x16actorTemplateNamespace\x12.\n" + + "\x13actor_template_name\x18\x06 \x01(\tR\x11actorTemplateName\x12,\n" + + "\x12actor_template_uid\x18\a \x01(\tR\x10actorTemplateUid\x12A\n" + + "\rcontent_scope\x18\b \x01(\x0e2\x1c.ateapi.SnapshotContentScopeR\fcontentScope\"\xac\x01\n" + + "\x10ActorSnapshotTag\x124\n" + + "\bmetadata\x18\x01 \x01(\v2\x18.ateapi.ResourceMetadataR\bmetadata\x12-\n" + + "\bsnapshot\x18\x02 \x01(\v2\x11.ateapi.ObjectRefR\bsnapshot\x123\n" + + "\x05scope\x18\x03 \x01(\x0e2\x1d.ateapi.ActorSnapshotTagScopeR\x05scope\"@\n" + "\bAtespace\x124\n" + "\bmetadata\x18\x01 \x01(\v2\x18.ateapi.ResourceMetadataR\bmetadata\";\n" + "\tObjectRef\x12\x1a\n" + "\batespace\x18\x01 \x01(\tR\batespace\x12\x12\n" + - "\x04name\x18\x02 \x01(\tR\x04name\"E\n" + + "\x04name\x18\x02 \x01(\tR\x04name\"w\n" + + "\x10ActorSnapshotRef\x12/\n" + + "\bsnapshot\x18\x01 \x01(\v2\x11.ateapi.ObjectRefH\x00R\bsnapshot\x12%\n" + + "\x03tag\x18\x02 \x01(\v2\x11.ateapi.ObjectRefH\x00R\x03tagB\v\n" + + "\treference\"E\n" + "\x15CreateAtespaceRequest\x12,\n" + "\batespace\x18\x01 \x01(\v2\x10.ateapi.AtespaceR\batespace\"C\n" + "\x12GetAtespaceRequest\x12-\n" + @@ -2461,9 +3030,10 @@ const file_ateapi_proto_rawDesc = "" + "\x15DeleteAtespaceRequest\x12-\n" + "\batespace\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\batespace\":\n" + "\x0fGetActorRequest\x12'\n" + - "\x05actor\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\x05actor\"9\n" + + "\x05actor\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\x05actor\"|\n" + "\x12CreateActorRequest\x12#\n" + - "\x05actor\x18\x01 \x01(\v2\r.ateapi.ActorR\x05actor\"x\n" + + "\x05actor\x18\x01 \x01(\v2\r.ateapi.ActorR\x05actor\x12A\n" + + "\x0fsource_snapshot\x18\x02 \x01(\v2\x18.ateapi.ActorSnapshotRefR\x0esourceSnapshot\"x\n" + "\x12UpdateActorRequest\x12'\n" + "\x05actor\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\x05actor\x129\n" + "\x0fworker_selector\x18\x02 \x01(\v2\x10.ateapi.SelectorR\x0eworkerSelector\":\n" + @@ -2483,7 +3053,25 @@ const file_ateapi_proto_rawDesc = "" + "\x13ResumeActorResponse\x12#\n" + "\x05actor\x18\x01 \x01(\v2\r.ateapi.ActorR\x05actor\"=\n" + "\x12DeleteActorRequest\x12'\n" + - "\x05actor\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\x05actor\"P\n" + + "\x05actor\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\x05actor\"O\n" + + "\x17GetActorSnapshotRequest\x124\n" + + "\bsnapshot\x18\x01 \x01(\v2\x18.ateapi.ActorSnapshotRefR\bsnapshot\"s\n" + + "\x19ListActorSnapshotsRequest\x12\x1a\n" + + "\batespace\x18\x01 \x01(\tR\batespace\x12\x1b\n" + + "\tpage_size\x18\x02 \x01(\x05R\bpageSize\x12\x1d\n" + + "\n" + + "page_token\x18\x03 \x01(\tR\tpageToken\"y\n" + + "\x1aListActorSnapshotsResponse\x123\n" + + "\tsnapshots\x18\x01 \x03(\v2\x15.ateapi.ActorSnapshotR\tsnapshots\x12&\n" + + "\x0fnext_page_token\x18\x02 \x01(\tR\rnextPageToken\"{\n" + + "\x17TagActorSnapshotRequest\x124\n" + + "\bsnapshot\x18\x01 \x01(\v2\x18.ateapi.ActorSnapshotRefR\bsnapshot\x12*\n" + + "\x03tag\x18\x02 \x01(\v2\x18.ateapi.ActorSnapshotTagR\x03tag\"y\n" + + "\x1dUpdateActorSnapshotTagRequest\x12#\n" + + "\x03tag\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\x03tag\x123\n" + + "\x05scope\x18\x02 \x01(\x0e2\x1d.ateapi.ActorSnapshotTagScopeR\x05scope\"D\n" + + "\x1dDeleteActorSnapshotTagRequest\x12#\n" + + "\x03tag\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\x03tag\"P\n" + "\x12ListWorkersRequest\x12\x1b\n" + "\tpage_size\x18\x01 \x01(\x05R\bpageSize\x12\x1d\n" + "\n" + @@ -2545,7 +3133,15 @@ const file_ateapi_proto_rawDesc = "" + "\bactor_id\x18\x03 \x01(\tR\aactorId\x12>\n" + "\x1bcertificate_signing_request\x18\x04 \x01(\fR\x19certificateSigningRequest\"A\n" + "\x10MintCertResponse\x12-\n" + - "\x12actor_certificates\x18\x01 \x03(\fR\x11actorCertificates2\x89\a\n" + + "\x12actor_certificates\x18\x01 \x03(\fR\x11actorCertificates*\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*f\n" + + "\x15ActorSnapshotTagScope\x12%\n" + + "!ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE\x10\x00\x12&\n" + + "\"ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED\x10\x012\xc1\n" + + "\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\x12H\n" + @@ -2554,7 +3150,12 @@ const file_ateapi_proto_rawDesc = "" + "\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" + - "\vDeleteActor\x12\x1a.ateapi.DeleteActorRequest\x1a\r.ateapi.Actor\"\x00\x12H\n" + + "\vDeleteActor\x12\x1a.ateapi.DeleteActorRequest\x1a\r.ateapi.Actor\"\x00\x12L\n" + + "\x10GetActorSnapshot\x12\x1f.ateapi.GetActorSnapshotRequest\x1a\x15.ateapi.ActorSnapshot\"\x00\x12]\n" + + "\x12ListActorSnapshots\x12!.ateapi.ListActorSnapshotsRequest\x1a\".ateapi.ListActorSnapshotsResponse\"\x00\x12O\n" + + "\x10TagActorSnapshot\x12\x1f.ateapi.TagActorSnapshotRequest\x1a\x18.ateapi.ActorSnapshotTag\"\x00\x12[\n" + + "\x16UpdateActorSnapshotTag\x12%.ateapi.UpdateActorSnapshotTagRequest\x1a\x18.ateapi.ActorSnapshotTag\"\x00\x12[\n" + + "\x16DeleteActorSnapshotTag\x12%.ateapi.DeleteActorSnapshotTagRequest\x1a\x18.ateapi.ActorSnapshotTag\"\x00\x12H\n" + "\vListWorkers\x12\x1a.ateapi.ListWorkersRequest\x1a\x1b.ateapi.ListWorkersResponse\"\x00\x12E\n" + "\n" + "ListActors\x12\x19.ateapi.ListActorsRequest\x1a\x1a.ateapi.ListActorsResponse\"\x00\x12C\n" + @@ -2581,127 +3182,161 @@ func file_ateapi_proto_rawDescGZIP() []byte { return file_ateapi_proto_rawDescData } -var file_ateapi_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_ateapi_proto_msgTypes = make([]protoimpl.MessageInfo, 40) +var file_ateapi_proto_enumTypes = make([]protoimpl.EnumInfo, 5) +var file_ateapi_proto_msgTypes = make([]protoimpl.MessageInfo, 47) var file_ateapi_proto_goTypes = []any{ - (ExternalVolume_Status)(0), // 0: ateapi.ExternalVolume.Status - (Actor_Status)(0), // 1: ateapi.Actor.Status - (Worker_State)(0), // 2: ateapi.Worker.State - (*ExternalSnapshotInfo)(nil), // 3: ateapi.ExternalSnapshotInfo - (*LocalSnapshotInfo)(nil), // 4: ateapi.LocalSnapshotInfo - (*SnapshotInfo)(nil), // 5: ateapi.SnapshotInfo - (*Selector)(nil), // 6: ateapi.Selector - (*ResourceMetadata)(nil), // 7: ateapi.ResourceMetadata - (*ExternalVolume)(nil), // 8: ateapi.ExternalVolume - (*Actor)(nil), // 9: ateapi.Actor - (*Atespace)(nil), // 10: ateapi.Atespace - (*ObjectRef)(nil), // 11: ateapi.ObjectRef - (*CreateAtespaceRequest)(nil), // 12: ateapi.CreateAtespaceRequest - (*GetAtespaceRequest)(nil), // 13: ateapi.GetAtespaceRequest - (*ListAtespacesRequest)(nil), // 14: ateapi.ListAtespacesRequest - (*ListAtespacesResponse)(nil), // 15: ateapi.ListAtespacesResponse - (*DeleteAtespaceRequest)(nil), // 16: ateapi.DeleteAtespaceRequest - (*GetActorRequest)(nil), // 17: ateapi.GetActorRequest - (*CreateActorRequest)(nil), // 18: ateapi.CreateActorRequest - (*UpdateActorRequest)(nil), // 19: ateapi.UpdateActorRequest - (*UpdateActorResponse)(nil), // 20: ateapi.UpdateActorResponse - (*SuspendActorRequest)(nil), // 21: ateapi.SuspendActorRequest - (*SuspendActorResponse)(nil), // 22: ateapi.SuspendActorResponse - (*PauseActorRequest)(nil), // 23: ateapi.PauseActorRequest - (*PauseActorResponse)(nil), // 24: ateapi.PauseActorResponse - (*ResumeActorRequest)(nil), // 25: ateapi.ResumeActorRequest - (*ResumeActorResponse)(nil), // 26: ateapi.ResumeActorResponse - (*DeleteActorRequest)(nil), // 27: ateapi.DeleteActorRequest - (*ListWorkersRequest)(nil), // 28: ateapi.ListWorkersRequest - (*ListWorkersResponse)(nil), // 29: ateapi.ListWorkersResponse - (*ListActorsRequest)(nil), // 30: ateapi.ListActorsRequest - (*ListActorsResponse)(nil), // 31: ateapi.ListActorsResponse - (*Worker)(nil), // 32: ateapi.Worker - (*Assignment)(nil), // 33: ateapi.Assignment - (*KubeNamespacedObjectRef)(nil), // 34: ateapi.KubeNamespacedObjectRef - (*DebugClearRequest)(nil), // 35: ateapi.DebugClearRequest - (*DebugClearResponse)(nil), // 36: ateapi.DebugClearResponse - (*MintJWTRequest)(nil), // 37: ateapi.MintJWTRequest - (*MintJWTResponse)(nil), // 38: ateapi.MintJWTResponse - (*MintCertRequest)(nil), // 39: ateapi.MintCertRequest - (*MintCertResponse)(nil), // 40: ateapi.MintCertResponse - nil, // 41: ateapi.Selector.MatchLabelsEntry - nil, // 42: ateapi.Worker.LabelsEntry - (*timestamppb.Timestamp)(nil), // 43: google.protobuf.Timestamp + (SnapshotContentScope)(0), // 0: ateapi.SnapshotContentScope + (ActorSnapshotTagScope)(0), // 1: ateapi.ActorSnapshotTagScope + (ExternalVolume_Status)(0), // 2: ateapi.ExternalVolume.Status + (Actor_Status)(0), // 3: ateapi.Actor.Status + (Worker_State)(0), // 4: ateapi.Worker.State + (*LocalSnapshotInfo)(nil), // 5: ateapi.LocalSnapshotInfo + (*Selector)(nil), // 6: ateapi.Selector + (*ResourceMetadata)(nil), // 7: ateapi.ResourceMetadata + (*ExternalVolume)(nil), // 8: ateapi.ExternalVolume + (*Actor)(nil), // 9: ateapi.Actor + (*ActorSnapshot)(nil), // 10: ateapi.ActorSnapshot + (*ActorSnapshotTag)(nil), // 11: ateapi.ActorSnapshotTag + (*Atespace)(nil), // 12: ateapi.Atespace + (*ObjectRef)(nil), // 13: ateapi.ObjectRef + (*ActorSnapshotRef)(nil), // 14: ateapi.ActorSnapshotRef + (*CreateAtespaceRequest)(nil), // 15: ateapi.CreateAtespaceRequest + (*GetAtespaceRequest)(nil), // 16: ateapi.GetAtespaceRequest + (*ListAtespacesRequest)(nil), // 17: ateapi.ListAtespacesRequest + (*ListAtespacesResponse)(nil), // 18: ateapi.ListAtespacesResponse + (*DeleteAtespaceRequest)(nil), // 19: ateapi.DeleteAtespaceRequest + (*GetActorRequest)(nil), // 20: ateapi.GetActorRequest + (*CreateActorRequest)(nil), // 21: ateapi.CreateActorRequest + (*UpdateActorRequest)(nil), // 22: ateapi.UpdateActorRequest + (*UpdateActorResponse)(nil), // 23: ateapi.UpdateActorResponse + (*SuspendActorRequest)(nil), // 24: ateapi.SuspendActorRequest + (*SuspendActorResponse)(nil), // 25: ateapi.SuspendActorResponse + (*PauseActorRequest)(nil), // 26: ateapi.PauseActorRequest + (*PauseActorResponse)(nil), // 27: ateapi.PauseActorResponse + (*ResumeActorRequest)(nil), // 28: ateapi.ResumeActorRequest + (*ResumeActorResponse)(nil), // 29: ateapi.ResumeActorResponse + (*DeleteActorRequest)(nil), // 30: ateapi.DeleteActorRequest + (*GetActorSnapshotRequest)(nil), // 31: ateapi.GetActorSnapshotRequest + (*ListActorSnapshotsRequest)(nil), // 32: ateapi.ListActorSnapshotsRequest + (*ListActorSnapshotsResponse)(nil), // 33: ateapi.ListActorSnapshotsResponse + (*TagActorSnapshotRequest)(nil), // 34: ateapi.TagActorSnapshotRequest + (*UpdateActorSnapshotTagRequest)(nil), // 35: ateapi.UpdateActorSnapshotTagRequest + (*DeleteActorSnapshotTagRequest)(nil), // 36: ateapi.DeleteActorSnapshotTagRequest + (*ListWorkersRequest)(nil), // 37: ateapi.ListWorkersRequest + (*ListWorkersResponse)(nil), // 38: ateapi.ListWorkersResponse + (*ListActorsRequest)(nil), // 39: ateapi.ListActorsRequest + (*ListActorsResponse)(nil), // 40: ateapi.ListActorsResponse + (*Worker)(nil), // 41: ateapi.Worker + (*Assignment)(nil), // 42: ateapi.Assignment + (*KubeNamespacedObjectRef)(nil), // 43: ateapi.KubeNamespacedObjectRef + (*DebugClearRequest)(nil), // 44: ateapi.DebugClearRequest + (*DebugClearResponse)(nil), // 45: ateapi.DebugClearResponse + (*MintJWTRequest)(nil), // 46: ateapi.MintJWTRequest + (*MintJWTResponse)(nil), // 47: ateapi.MintJWTResponse + (*MintCertRequest)(nil), // 48: ateapi.MintCertRequest + (*MintCertResponse)(nil), // 49: ateapi.MintCertResponse + nil, // 50: ateapi.Selector.MatchLabelsEntry + nil, // 51: ateapi.Worker.LabelsEntry + (*timestamppb.Timestamp)(nil), // 52: google.protobuf.Timestamp } var file_ateapi_proto_depIdxs = []int32{ - 3, // 0: ateapi.SnapshotInfo.external:type_name -> ateapi.ExternalSnapshotInfo - 4, // 1: ateapi.SnapshotInfo.local:type_name -> ateapi.LocalSnapshotInfo - 41, // 2: ateapi.Selector.match_labels:type_name -> ateapi.Selector.MatchLabelsEntry - 43, // 3: ateapi.ResourceMetadata.create_time:type_name -> google.protobuf.Timestamp - 43, // 4: ateapi.ResourceMetadata.update_time:type_name -> google.protobuf.Timestamp - 0, // 5: ateapi.ExternalVolume.status:type_name -> ateapi.ExternalVolume.Status - 7, // 6: ateapi.Actor.metadata:type_name -> ateapi.ResourceMetadata - 1, // 7: ateapi.Actor.status:type_name -> ateapi.Actor.Status - 5, // 8: ateapi.Actor.latest_snapshot_info:type_name -> ateapi.SnapshotInfo - 6, // 9: ateapi.Actor.worker_selector:type_name -> ateapi.Selector - 8, // 10: ateapi.Actor.actor_volumes:type_name -> ateapi.ExternalVolume - 7, // 11: ateapi.Atespace.metadata:type_name -> ateapi.ResourceMetadata - 10, // 12: ateapi.CreateAtespaceRequest.atespace:type_name -> ateapi.Atespace - 11, // 13: ateapi.GetAtespaceRequest.atespace:type_name -> ateapi.ObjectRef - 10, // 14: ateapi.ListAtespacesResponse.atespaces:type_name -> ateapi.Atespace - 11, // 15: ateapi.DeleteAtespaceRequest.atespace:type_name -> ateapi.ObjectRef - 11, // 16: ateapi.GetActorRequest.actor:type_name -> ateapi.ObjectRef - 9, // 17: ateapi.CreateActorRequest.actor:type_name -> ateapi.Actor - 11, // 18: ateapi.UpdateActorRequest.actor:type_name -> ateapi.ObjectRef - 6, // 19: ateapi.UpdateActorRequest.worker_selector:type_name -> ateapi.Selector - 9, // 20: ateapi.UpdateActorResponse.actor:type_name -> ateapi.Actor - 11, // 21: ateapi.SuspendActorRequest.actor:type_name -> ateapi.ObjectRef - 9, // 22: ateapi.SuspendActorResponse.actor:type_name -> ateapi.Actor - 11, // 23: ateapi.PauseActorRequest.actor:type_name -> ateapi.ObjectRef - 9, // 24: ateapi.PauseActorResponse.actor:type_name -> ateapi.Actor - 11, // 25: ateapi.ResumeActorRequest.actor:type_name -> ateapi.ObjectRef - 9, // 26: ateapi.ResumeActorResponse.actor:type_name -> ateapi.Actor - 11, // 27: ateapi.DeleteActorRequest.actor:type_name -> ateapi.ObjectRef - 32, // 28: ateapi.ListWorkersResponse.workers:type_name -> ateapi.Worker - 9, // 29: ateapi.ListActorsResponse.actors:type_name -> ateapi.Actor - 33, // 30: ateapi.Worker.assignment:type_name -> ateapi.Assignment - 42, // 31: ateapi.Worker.labels:type_name -> ateapi.Worker.LabelsEntry - 2, // 32: ateapi.Worker.state:type_name -> ateapi.Worker.State - 34, // 33: ateapi.Assignment.actor_template:type_name -> ateapi.KubeNamespacedObjectRef - 11, // 34: ateapi.Assignment.actor:type_name -> ateapi.ObjectRef - 17, // 35: ateapi.Control.GetActor:input_type -> ateapi.GetActorRequest - 18, // 36: ateapi.Control.CreateActor:input_type -> ateapi.CreateActorRequest - 19, // 37: ateapi.Control.UpdateActor:input_type -> ateapi.UpdateActorRequest - 21, // 38: ateapi.Control.SuspendActor:input_type -> ateapi.SuspendActorRequest - 23, // 39: ateapi.Control.PauseActor:input_type -> ateapi.PauseActorRequest - 25, // 40: ateapi.Control.ResumeActor:input_type -> ateapi.ResumeActorRequest - 27, // 41: ateapi.Control.DeleteActor:input_type -> ateapi.DeleteActorRequest - 28, // 42: ateapi.Control.ListWorkers:input_type -> ateapi.ListWorkersRequest - 30, // 43: ateapi.Control.ListActors:input_type -> ateapi.ListActorsRequest - 12, // 44: ateapi.Control.CreateAtespace:input_type -> ateapi.CreateAtespaceRequest - 13, // 45: ateapi.Control.GetAtespace:input_type -> ateapi.GetAtespaceRequest - 14, // 46: ateapi.Control.ListAtespaces:input_type -> ateapi.ListAtespacesRequest - 16, // 47: ateapi.Control.DeleteAtespace:input_type -> ateapi.DeleteAtespaceRequest - 35, // 48: ateapi.Debug.DebugClear:input_type -> ateapi.DebugClearRequest - 37, // 49: ateapi.ActorIdentity.MintJWT:input_type -> ateapi.MintJWTRequest - 39, // 50: ateapi.ActorIdentity.MintCert:input_type -> ateapi.MintCertRequest - 9, // 51: ateapi.Control.GetActor:output_type -> ateapi.Actor - 9, // 52: ateapi.Control.CreateActor:output_type -> ateapi.Actor - 20, // 53: ateapi.Control.UpdateActor:output_type -> ateapi.UpdateActorResponse - 22, // 54: ateapi.Control.SuspendActor:output_type -> ateapi.SuspendActorResponse - 24, // 55: ateapi.Control.PauseActor:output_type -> ateapi.PauseActorResponse - 26, // 56: ateapi.Control.ResumeActor:output_type -> ateapi.ResumeActorResponse - 9, // 57: ateapi.Control.DeleteActor:output_type -> ateapi.Actor - 29, // 58: ateapi.Control.ListWorkers:output_type -> ateapi.ListWorkersResponse - 31, // 59: ateapi.Control.ListActors:output_type -> ateapi.ListActorsResponse - 10, // 60: ateapi.Control.CreateAtespace:output_type -> ateapi.Atespace - 10, // 61: ateapi.Control.GetAtespace:output_type -> ateapi.Atespace - 15, // 62: ateapi.Control.ListAtespaces:output_type -> ateapi.ListAtespacesResponse - 10, // 63: ateapi.Control.DeleteAtespace:output_type -> ateapi.Atespace - 36, // 64: ateapi.Debug.DebugClear:output_type -> ateapi.DebugClearResponse - 38, // 65: ateapi.ActorIdentity.MintJWT:output_type -> ateapi.MintJWTResponse - 40, // 66: ateapi.ActorIdentity.MintCert:output_type -> ateapi.MintCertResponse - 51, // [51:67] is the sub-list for method output_type - 35, // [35:51] is the sub-list for method input_type - 35, // [35:35] is the sub-list for extension type_name - 35, // [35:35] is the sub-list for extension extendee - 0, // [0:35] is the sub-list for field type_name + 50, // 0: ateapi.Selector.match_labels:type_name -> ateapi.Selector.MatchLabelsEntry + 52, // 1: ateapi.ResourceMetadata.create_time:type_name -> google.protobuf.Timestamp + 52, // 2: ateapi.ResourceMetadata.update_time:type_name -> google.protobuf.Timestamp + 2, // 3: ateapi.ExternalVolume.status:type_name -> ateapi.ExternalVolume.Status + 7, // 4: ateapi.Actor.metadata:type_name -> ateapi.ResourceMetadata + 3, // 5: ateapi.Actor.status:type_name -> ateapi.Actor.Status + 6, // 6: ateapi.Actor.worker_selector:type_name -> ateapi.Selector + 13, // 7: ateapi.Actor.latest_snapshot:type_name -> ateapi.ObjectRef + 5, // 8: ateapi.Actor.local_snapshot_info:type_name -> ateapi.LocalSnapshotInfo + 8, // 9: ateapi.Actor.actor_volumes:type_name -> ateapi.ExternalVolume + 7, // 10: ateapi.ActorSnapshot.metadata:type_name -> ateapi.ResourceMetadata + 13, // 11: ateapi.ActorSnapshot.source_actor:type_name -> ateapi.ObjectRef + 0, // 12: ateapi.ActorSnapshot.content_scope:type_name -> ateapi.SnapshotContentScope + 7, // 13: ateapi.ActorSnapshotTag.metadata:type_name -> ateapi.ResourceMetadata + 13, // 14: ateapi.ActorSnapshotTag.snapshot:type_name -> ateapi.ObjectRef + 1, // 15: ateapi.ActorSnapshotTag.scope:type_name -> ateapi.ActorSnapshotTagScope + 7, // 16: ateapi.Atespace.metadata:type_name -> ateapi.ResourceMetadata + 13, // 17: ateapi.ActorSnapshotRef.snapshot:type_name -> ateapi.ObjectRef + 13, // 18: ateapi.ActorSnapshotRef.tag:type_name -> ateapi.ObjectRef + 12, // 19: ateapi.CreateAtespaceRequest.atespace:type_name -> ateapi.Atespace + 13, // 20: ateapi.GetAtespaceRequest.atespace:type_name -> ateapi.ObjectRef + 12, // 21: ateapi.ListAtespacesResponse.atespaces:type_name -> ateapi.Atespace + 13, // 22: ateapi.DeleteAtespaceRequest.atespace:type_name -> ateapi.ObjectRef + 13, // 23: ateapi.GetActorRequest.actor:type_name -> ateapi.ObjectRef + 9, // 24: ateapi.CreateActorRequest.actor:type_name -> ateapi.Actor + 14, // 25: ateapi.CreateActorRequest.source_snapshot:type_name -> ateapi.ActorSnapshotRef + 13, // 26: ateapi.UpdateActorRequest.actor:type_name -> ateapi.ObjectRef + 6, // 27: ateapi.UpdateActorRequest.worker_selector:type_name -> ateapi.Selector + 9, // 28: ateapi.UpdateActorResponse.actor:type_name -> ateapi.Actor + 13, // 29: ateapi.SuspendActorRequest.actor:type_name -> ateapi.ObjectRef + 9, // 30: ateapi.SuspendActorResponse.actor:type_name -> ateapi.Actor + 13, // 31: ateapi.PauseActorRequest.actor:type_name -> ateapi.ObjectRef + 9, // 32: ateapi.PauseActorResponse.actor:type_name -> ateapi.Actor + 13, // 33: ateapi.ResumeActorRequest.actor:type_name -> ateapi.ObjectRef + 9, // 34: ateapi.ResumeActorResponse.actor:type_name -> ateapi.Actor + 13, // 35: ateapi.DeleteActorRequest.actor:type_name -> ateapi.ObjectRef + 14, // 36: ateapi.GetActorSnapshotRequest.snapshot:type_name -> ateapi.ActorSnapshotRef + 10, // 37: ateapi.ListActorSnapshotsResponse.snapshots:type_name -> ateapi.ActorSnapshot + 14, // 38: ateapi.TagActorSnapshotRequest.snapshot:type_name -> ateapi.ActorSnapshotRef + 11, // 39: ateapi.TagActorSnapshotRequest.tag:type_name -> ateapi.ActorSnapshotTag + 13, // 40: ateapi.UpdateActorSnapshotTagRequest.tag:type_name -> ateapi.ObjectRef + 1, // 41: ateapi.UpdateActorSnapshotTagRequest.scope:type_name -> ateapi.ActorSnapshotTagScope + 13, // 42: ateapi.DeleteActorSnapshotTagRequest.tag:type_name -> ateapi.ObjectRef + 41, // 43: ateapi.ListWorkersResponse.workers:type_name -> ateapi.Worker + 9, // 44: ateapi.ListActorsResponse.actors:type_name -> ateapi.Actor + 42, // 45: ateapi.Worker.assignment:type_name -> ateapi.Assignment + 51, // 46: ateapi.Worker.labels:type_name -> ateapi.Worker.LabelsEntry + 4, // 47: ateapi.Worker.state:type_name -> ateapi.Worker.State + 43, // 48: ateapi.Assignment.actor_template:type_name -> ateapi.KubeNamespacedObjectRef + 13, // 49: ateapi.Assignment.actor:type_name -> ateapi.ObjectRef + 20, // 50: ateapi.Control.GetActor:input_type -> ateapi.GetActorRequest + 21, // 51: ateapi.Control.CreateActor:input_type -> ateapi.CreateActorRequest + 22, // 52: ateapi.Control.UpdateActor:input_type -> ateapi.UpdateActorRequest + 24, // 53: ateapi.Control.SuspendActor:input_type -> ateapi.SuspendActorRequest + 26, // 54: ateapi.Control.PauseActor:input_type -> ateapi.PauseActorRequest + 28, // 55: ateapi.Control.ResumeActor:input_type -> ateapi.ResumeActorRequest + 30, // 56: ateapi.Control.DeleteActor:input_type -> ateapi.DeleteActorRequest + 31, // 57: ateapi.Control.GetActorSnapshot:input_type -> ateapi.GetActorSnapshotRequest + 32, // 58: ateapi.Control.ListActorSnapshots:input_type -> ateapi.ListActorSnapshotsRequest + 34, // 59: ateapi.Control.TagActorSnapshot:input_type -> ateapi.TagActorSnapshotRequest + 35, // 60: ateapi.Control.UpdateActorSnapshotTag:input_type -> ateapi.UpdateActorSnapshotTagRequest + 36, // 61: ateapi.Control.DeleteActorSnapshotTag:input_type -> ateapi.DeleteActorSnapshotTagRequest + 37, // 62: ateapi.Control.ListWorkers:input_type -> ateapi.ListWorkersRequest + 39, // 63: ateapi.Control.ListActors:input_type -> ateapi.ListActorsRequest + 15, // 64: ateapi.Control.CreateAtespace:input_type -> ateapi.CreateAtespaceRequest + 16, // 65: ateapi.Control.GetAtespace:input_type -> ateapi.GetAtespaceRequest + 17, // 66: ateapi.Control.ListAtespaces:input_type -> ateapi.ListAtespacesRequest + 19, // 67: ateapi.Control.DeleteAtespace:input_type -> ateapi.DeleteAtespaceRequest + 44, // 68: ateapi.Debug.DebugClear:input_type -> ateapi.DebugClearRequest + 46, // 69: ateapi.ActorIdentity.MintJWT:input_type -> ateapi.MintJWTRequest + 48, // 70: ateapi.ActorIdentity.MintCert:input_type -> ateapi.MintCertRequest + 9, // 71: ateapi.Control.GetActor:output_type -> ateapi.Actor + 9, // 72: ateapi.Control.CreateActor:output_type -> ateapi.Actor + 23, // 73: ateapi.Control.UpdateActor:output_type -> ateapi.UpdateActorResponse + 25, // 74: ateapi.Control.SuspendActor:output_type -> ateapi.SuspendActorResponse + 27, // 75: ateapi.Control.PauseActor:output_type -> ateapi.PauseActorResponse + 29, // 76: ateapi.Control.ResumeActor:output_type -> ateapi.ResumeActorResponse + 9, // 77: ateapi.Control.DeleteActor:output_type -> ateapi.Actor + 10, // 78: ateapi.Control.GetActorSnapshot:output_type -> ateapi.ActorSnapshot + 33, // 79: ateapi.Control.ListActorSnapshots:output_type -> ateapi.ListActorSnapshotsResponse + 11, // 80: ateapi.Control.TagActorSnapshot:output_type -> ateapi.ActorSnapshotTag + 11, // 81: ateapi.Control.UpdateActorSnapshotTag:output_type -> ateapi.ActorSnapshotTag + 11, // 82: ateapi.Control.DeleteActorSnapshotTag:output_type -> ateapi.ActorSnapshotTag + 38, // 83: ateapi.Control.ListWorkers:output_type -> ateapi.ListWorkersResponse + 40, // 84: ateapi.Control.ListActors:output_type -> ateapi.ListActorsResponse + 12, // 85: ateapi.Control.CreateAtespace:output_type -> ateapi.Atespace + 12, // 86: ateapi.Control.GetAtespace:output_type -> ateapi.Atespace + 18, // 87: ateapi.Control.ListAtespaces:output_type -> ateapi.ListAtespacesResponse + 12, // 88: ateapi.Control.DeleteAtespace:output_type -> ateapi.Atespace + 45, // 89: ateapi.Debug.DebugClear:output_type -> ateapi.DebugClearResponse + 47, // 90: ateapi.ActorIdentity.MintJWT:output_type -> ateapi.MintJWTResponse + 49, // 91: ateapi.ActorIdentity.MintCert:output_type -> ateapi.MintCertResponse + 71, // [71:92] is the sub-list for method output_type + 50, // [50:71] is the sub-list for method input_type + 50, // [50:50] is the sub-list for extension type_name + 50, // [50:50] is the sub-list for extension extendee + 0, // [0:50] is the sub-list for field type_name } func init() { file_ateapi_proto_init() } @@ -2709,17 +3344,17 @@ func file_ateapi_proto_init() { if File_ateapi_proto != nil { return } - file_ateapi_proto_msgTypes[2].OneofWrappers = []any{ - (*SnapshotInfo_External)(nil), - (*SnapshotInfo_Local)(nil), + file_ateapi_proto_msgTypes[9].OneofWrappers = []any{ + (*ActorSnapshotRef_Snapshot)(nil), + (*ActorSnapshotRef_Tag)(nil), } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_ateapi_proto_rawDesc), len(file_ateapi_proto_rawDesc)), - NumEnums: 3, - NumMessages: 40, + NumEnums: 5, + NumMessages: 47, NumExtensions: 0, NumServices: 3, }, diff --git a/pkg/proto/ateapipb/ateapi.proto b/pkg/proto/ateapipb/ateapi.proto index 8547286c0..b8a9a0f27 100644 --- a/pkg/proto/ateapipb/ateapi.proto +++ b/pkg/proto/ateapipb/ateapi.proto @@ -43,6 +43,25 @@ service Control { // Delete an actor. Only suspended actors can be deleted. rpc DeleteActor(DeleteActorRequest) returns (Actor) {} + // Get an ActorSnapshot. + rpc GetActorSnapshot(GetActorSnapshotRequest) returns (ActorSnapshot) {} + + // List ActorSnapshots. + rpc ListActorSnapshots(ListActorSnapshotsRequest) + returns (ListActorSnapshotsResponse) {} + + // Add an Atespace-owned, stable name for an ActorSnapshot. + rpc TagActorSnapshot(TagActorSnapshotRequest) returns (ActorSnapshotTag) {} + + // Publish or unpublish an ActorSnapshot tag without changing its address. + rpc UpdateActorSnapshotTag(UpdateActorSnapshotTagRequest) + returns (ActorSnapshotTag) {} + + // Delete an ActorSnapshot tag. The snapshot becomes garbage-collectable when + // its final tag is deleted. + rpc DeleteActorSnapshotTag(DeleteActorSnapshotTagRequest) + returns (ActorSnapshotTag) {} + // List Workers. rpc ListWorkers(ListWorkersRequest) returns (ListWorkersResponse) {} @@ -58,28 +77,32 @@ service Control { // List Atespaces. rpc ListAtespaces(ListAtespacesRequest) returns (ListAtespacesResponse) {} - // Delete an empty Atespace. Rejects (FailedPrecondition) if any actors remain. + // Delete an empty Atespace. Rejects (FailedPrecondition) if any Actors or + // ActorSnapshotTags remain. rpc DeleteAtespace(DeleteAtespaceRequest) returns (Atespace) {} } -message ExternalSnapshotInfo { - string snapshot_uri_prefix = 1; -} - message LocalSnapshotInfo { string snapshot_prefix = 1; // Node VMs that have local snapshots for this actor, while it's PAUSED. repeated string node_vms_with_local_snapshots = 2; } -message SnapshotInfo { - oneof data { - ExternalSnapshotInfo external = 2; - LocalSnapshotInfo local = 3; - } +enum SnapshotContentScope { + // Defaults to FULL for compatibility with existing snapshot configuration. + SNAPSHOT_CONTENT_SCOPE_UNSPECIFIED = 0; + // Captures process memory, root filesystem changes, and durable data. + SNAPSHOT_CONTENT_SCOPE_FULL = 1; + // Captures durable data without process memory or root filesystem changes. + SNAPSHOT_CONTENT_SCOPE_DATA = 2; +} - reserved 1; - reserved "type"; +enum ActorSnapshotTagScope { + // May initialize Actors only in the tag's owning Atespace. + ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE = 0; + // Published for use by Actors in any Atespace. The tag remains addressed + // through its owning Atespace. + ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED = 1; } // Selector matches worker pools by label. @@ -155,7 +178,8 @@ message Actor { string in_progress_snapshot = 8; string ateom_pod_uid = 9; - SnapshotInfo latest_snapshot_info = 10; + reserved 10; + reserved "latest_snapshot_info"; // worker_selector is the per-actor placement constraint. The scheduler // evaluates the AND of this selector and the template's workerSelector to @@ -171,11 +195,42 @@ message Actor { // reference on the ActorTemplate. string worker_pool_name = 12; + // The latest durable snapshot created for this Actor. + ObjectRef latest_snapshot = 13; + + // Node-local state used only while the Actor is paused. + LocalSnapshotInfo local_snapshot_info = 14; + + // Actor version captured when the current durable snapshot began. + int64 in_progress_snapshot_source_actor_version = 15; + // Volumes attached to the actor. These volumes only live as long as the actor. // They are deleted when the actor is deleted. repeated ExternalVolume actor_volumes = 16; } +// ActorSnapshot is an independently addressable durable Actor snapshot. Its +// contents are immutable. Its physical storage location is private to +// Substrate. +message ActorSnapshot { + ResourceMetadata metadata = 1; + ObjectRef source_actor = 2; + string source_actor_uid = 3; + int64 source_actor_version = 4; + string actor_template_namespace = 5; + string actor_template_name = 6; + string actor_template_uid = 7; + SnapshotContentScope content_scope = 8; +} + +// ActorSnapshotTag is an immutable, Atespace-owned alias and retention pin. +// Its owning Atespace cannot be deleted until the tag is removed. +message ActorSnapshotTag { + ResourceMetadata metadata = 1; + ObjectRef snapshot = 2; + ActorSnapshotTagScope scope = 3; +} + // Atespace is the isolation boundary an Actor is created into. Global-scoped: // metadata.atespace is always empty; the atespace's identity is metadata.name. message Atespace { @@ -192,6 +247,15 @@ message ObjectRef { string name = 2; } +// ActorSnapshotRef addresses a snapshot by its canonical identity or by an +// Atespace-owned tag. Tag addresses remain stable when tags are published. +message ActorSnapshotRef { + oneof reference { + ObjectRef snapshot = 1; + ObjectRef tag = 2; + } +} + message CreateAtespaceRequest { // The atespace to create. Atespace atespace = 1; @@ -232,6 +296,9 @@ message GetActorRequest { message CreateActorRequest { // The actor to create. Actor actor = 1; + + // Optional durable snapshot used to initialize the Actor. + ActorSnapshotRef source_snapshot = 2; } // Request to update mutable fields on an existing Actor. @@ -280,6 +347,35 @@ message DeleteActorRequest { ObjectRef actor = 1; } +message GetActorSnapshotRequest { + ActorSnapshotRef snapshot = 1; +} + +message ListActorSnapshotsRequest { + string atespace = 1; + int32 page_size = 2; + string page_token = 3; +} + +message ListActorSnapshotsResponse { + repeated ActorSnapshot snapshots = 1; + string next_page_token = 2; +} + +message TagActorSnapshotRequest { + ActorSnapshotRef snapshot = 1; + ActorSnapshotTag tag = 2; +} + +message UpdateActorSnapshotTagRequest { + ObjectRef tag = 1; + ActorSnapshotTagScope scope = 2; +} + +message DeleteActorSnapshotTagRequest { + ObjectRef tag = 1; +} + message ListWorkersRequest { // Requested page size; the server may return fewer, or occasionally // slightly more. If unspecified, defaults to a server-chosen value; diff --git a/pkg/proto/ateapipb/ateapi_grpc.pb.go b/pkg/proto/ateapipb/ateapi_grpc.pb.go index 58a03b383..ac87ac228 100644 --- a/pkg/proto/ateapipb/ateapi_grpc.pb.go +++ b/pkg/proto/ateapipb/ateapi_grpc.pb.go @@ -33,19 +33,24 @@ import ( const _ = grpc.SupportPackageIsVersion9 const ( - Control_GetActor_FullMethodName = "/ateapi.Control/GetActor" - Control_CreateActor_FullMethodName = "/ateapi.Control/CreateActor" - Control_UpdateActor_FullMethodName = "/ateapi.Control/UpdateActor" - Control_SuspendActor_FullMethodName = "/ateapi.Control/SuspendActor" - Control_PauseActor_FullMethodName = "/ateapi.Control/PauseActor" - Control_ResumeActor_FullMethodName = "/ateapi.Control/ResumeActor" - Control_DeleteActor_FullMethodName = "/ateapi.Control/DeleteActor" - Control_ListWorkers_FullMethodName = "/ateapi.Control/ListWorkers" - Control_ListActors_FullMethodName = "/ateapi.Control/ListActors" - Control_CreateAtespace_FullMethodName = "/ateapi.Control/CreateAtespace" - Control_GetAtespace_FullMethodName = "/ateapi.Control/GetAtespace" - Control_ListAtespaces_FullMethodName = "/ateapi.Control/ListAtespaces" - Control_DeleteAtespace_FullMethodName = "/ateapi.Control/DeleteAtespace" + Control_GetActor_FullMethodName = "/ateapi.Control/GetActor" + Control_CreateActor_FullMethodName = "/ateapi.Control/CreateActor" + Control_UpdateActor_FullMethodName = "/ateapi.Control/UpdateActor" + Control_SuspendActor_FullMethodName = "/ateapi.Control/SuspendActor" + Control_PauseActor_FullMethodName = "/ateapi.Control/PauseActor" + Control_ResumeActor_FullMethodName = "/ateapi.Control/ResumeActor" + Control_DeleteActor_FullMethodName = "/ateapi.Control/DeleteActor" + Control_GetActorSnapshot_FullMethodName = "/ateapi.Control/GetActorSnapshot" + Control_ListActorSnapshots_FullMethodName = "/ateapi.Control/ListActorSnapshots" + Control_TagActorSnapshot_FullMethodName = "/ateapi.Control/TagActorSnapshot" + Control_UpdateActorSnapshotTag_FullMethodName = "/ateapi.Control/UpdateActorSnapshotTag" + Control_DeleteActorSnapshotTag_FullMethodName = "/ateapi.Control/DeleteActorSnapshotTag" + Control_ListWorkers_FullMethodName = "/ateapi.Control/ListWorkers" + Control_ListActors_FullMethodName = "/ateapi.Control/ListActors" + Control_CreateAtespace_FullMethodName = "/ateapi.Control/CreateAtespace" + Control_GetAtespace_FullMethodName = "/ateapi.Control/GetAtespace" + Control_ListAtespaces_FullMethodName = "/ateapi.Control/ListAtespaces" + Control_DeleteAtespace_FullMethodName = "/ateapi.Control/DeleteAtespace" ) // ControlClient is the client API for Control service. @@ -68,6 +73,17 @@ type ControlClient interface { ResumeActor(ctx context.Context, in *ResumeActorRequest, opts ...grpc.CallOption) (*ResumeActorResponse, error) // Delete an actor. Only suspended actors can be deleted. DeleteActor(ctx context.Context, in *DeleteActorRequest, opts ...grpc.CallOption) (*Actor, error) + // Get an ActorSnapshot. + GetActorSnapshot(ctx context.Context, in *GetActorSnapshotRequest, opts ...grpc.CallOption) (*ActorSnapshot, error) + // List ActorSnapshots. + ListActorSnapshots(ctx context.Context, in *ListActorSnapshotsRequest, opts ...grpc.CallOption) (*ListActorSnapshotsResponse, error) + // Add an Atespace-owned, stable name for an ActorSnapshot. + TagActorSnapshot(ctx context.Context, in *TagActorSnapshotRequest, opts ...grpc.CallOption) (*ActorSnapshotTag, error) + // Publish or unpublish an ActorSnapshot tag without changing its address. + UpdateActorSnapshotTag(ctx context.Context, in *UpdateActorSnapshotTagRequest, opts ...grpc.CallOption) (*ActorSnapshotTag, error) + // Delete an ActorSnapshot tag. The snapshot becomes garbage-collectable when + // its final tag is deleted. + DeleteActorSnapshotTag(ctx context.Context, in *DeleteActorSnapshotTagRequest, opts ...grpc.CallOption) (*ActorSnapshotTag, error) // List Workers. ListWorkers(ctx context.Context, in *ListWorkersRequest, opts ...grpc.CallOption) (*ListWorkersResponse, error) // List Actors. @@ -78,7 +94,8 @@ type ControlClient interface { GetAtespace(ctx context.Context, in *GetAtespaceRequest, opts ...grpc.CallOption) (*Atespace, error) // List Atespaces. ListAtespaces(ctx context.Context, in *ListAtespacesRequest, opts ...grpc.CallOption) (*ListAtespacesResponse, error) - // Delete an empty Atespace. Rejects (FailedPrecondition) if any actors remain. + // Delete an empty Atespace. Rejects (FailedPrecondition) if any Actors or + // ActorSnapshotTags remain. DeleteAtespace(ctx context.Context, in *DeleteAtespaceRequest, opts ...grpc.CallOption) (*Atespace, error) } @@ -160,6 +177,56 @@ func (c *controlClient) DeleteActor(ctx context.Context, in *DeleteActorRequest, return out, nil } +func (c *controlClient) GetActorSnapshot(ctx context.Context, in *GetActorSnapshotRequest, opts ...grpc.CallOption) (*ActorSnapshot, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ActorSnapshot) + err := c.cc.Invoke(ctx, Control_GetActorSnapshot_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *controlClient) ListActorSnapshots(ctx context.Context, in *ListActorSnapshotsRequest, opts ...grpc.CallOption) (*ListActorSnapshotsResponse, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ListActorSnapshotsResponse) + err := c.cc.Invoke(ctx, Control_ListActorSnapshots_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *controlClient) TagActorSnapshot(ctx context.Context, in *TagActorSnapshotRequest, opts ...grpc.CallOption) (*ActorSnapshotTag, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ActorSnapshotTag) + err := c.cc.Invoke(ctx, Control_TagActorSnapshot_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *controlClient) UpdateActorSnapshotTag(ctx context.Context, in *UpdateActorSnapshotTagRequest, opts ...grpc.CallOption) (*ActorSnapshotTag, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ActorSnapshotTag) + err := c.cc.Invoke(ctx, Control_UpdateActorSnapshotTag_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *controlClient) DeleteActorSnapshotTag(ctx context.Context, in *DeleteActorSnapshotTagRequest, opts ...grpc.CallOption) (*ActorSnapshotTag, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(ActorSnapshotTag) + err := c.cc.Invoke(ctx, Control_DeleteActorSnapshotTag_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *controlClient) ListWorkers(ctx context.Context, in *ListWorkersRequest, opts ...grpc.CallOption) (*ListWorkersResponse, error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) out := new(ListWorkersResponse) @@ -240,6 +307,17 @@ type ControlServer interface { ResumeActor(context.Context, *ResumeActorRequest) (*ResumeActorResponse, error) // Delete an actor. Only suspended actors can be deleted. DeleteActor(context.Context, *DeleteActorRequest) (*Actor, error) + // Get an ActorSnapshot. + GetActorSnapshot(context.Context, *GetActorSnapshotRequest) (*ActorSnapshot, error) + // List ActorSnapshots. + ListActorSnapshots(context.Context, *ListActorSnapshotsRequest) (*ListActorSnapshotsResponse, error) + // Add an Atespace-owned, stable name for an ActorSnapshot. + TagActorSnapshot(context.Context, *TagActorSnapshotRequest) (*ActorSnapshotTag, error) + // Publish or unpublish an ActorSnapshot tag without changing its address. + UpdateActorSnapshotTag(context.Context, *UpdateActorSnapshotTagRequest) (*ActorSnapshotTag, error) + // Delete an ActorSnapshot tag. The snapshot becomes garbage-collectable when + // its final tag is deleted. + DeleteActorSnapshotTag(context.Context, *DeleteActorSnapshotTagRequest) (*ActorSnapshotTag, error) // List Workers. ListWorkers(context.Context, *ListWorkersRequest) (*ListWorkersResponse, error) // List Actors. @@ -250,7 +328,8 @@ type ControlServer interface { GetAtespace(context.Context, *GetAtespaceRequest) (*Atespace, error) // List Atespaces. ListAtespaces(context.Context, *ListAtespacesRequest) (*ListAtespacesResponse, error) - // Delete an empty Atespace. Rejects (FailedPrecondition) if any actors remain. + // Delete an empty Atespace. Rejects (FailedPrecondition) if any Actors or + // ActorSnapshotTags remain. DeleteAtespace(context.Context, *DeleteAtespaceRequest) (*Atespace, error) mustEmbedUnimplementedControlServer() } @@ -283,6 +362,21 @@ func (UnimplementedControlServer) ResumeActor(context.Context, *ResumeActorReque func (UnimplementedControlServer) DeleteActor(context.Context, *DeleteActorRequest) (*Actor, error) { return nil, status.Error(codes.Unimplemented, "method DeleteActor not implemented") } +func (UnimplementedControlServer) GetActorSnapshot(context.Context, *GetActorSnapshotRequest) (*ActorSnapshot, error) { + return nil, status.Error(codes.Unimplemented, "method GetActorSnapshot not implemented") +} +func (UnimplementedControlServer) ListActorSnapshots(context.Context, *ListActorSnapshotsRequest) (*ListActorSnapshotsResponse, error) { + return nil, status.Error(codes.Unimplemented, "method ListActorSnapshots not implemented") +} +func (UnimplementedControlServer) TagActorSnapshot(context.Context, *TagActorSnapshotRequest) (*ActorSnapshotTag, error) { + return nil, status.Error(codes.Unimplemented, "method TagActorSnapshot not implemented") +} +func (UnimplementedControlServer) UpdateActorSnapshotTag(context.Context, *UpdateActorSnapshotTagRequest) (*ActorSnapshotTag, error) { + return nil, status.Error(codes.Unimplemented, "method UpdateActorSnapshotTag not implemented") +} +func (UnimplementedControlServer) DeleteActorSnapshotTag(context.Context, *DeleteActorSnapshotTagRequest) (*ActorSnapshotTag, error) { + return nil, status.Error(codes.Unimplemented, "method DeleteActorSnapshotTag not implemented") +} func (UnimplementedControlServer) ListWorkers(context.Context, *ListWorkersRequest) (*ListWorkersResponse, error) { return nil, status.Error(codes.Unimplemented, "method ListWorkers not implemented") } @@ -448,6 +542,96 @@ func _Control_DeleteActor_Handler(srv interface{}, ctx context.Context, dec func return interceptor(ctx, in, info, handler) } +func _Control_GetActorSnapshot_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetActorSnapshotRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ControlServer).GetActorSnapshot(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Control_GetActorSnapshot_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ControlServer).GetActorSnapshot(ctx, req.(*GetActorSnapshotRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Control_ListActorSnapshots_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ListActorSnapshotsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ControlServer).ListActorSnapshots(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Control_ListActorSnapshots_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ControlServer).ListActorSnapshots(ctx, req.(*ListActorSnapshotsRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Control_TagActorSnapshot_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(TagActorSnapshotRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ControlServer).TagActorSnapshot(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Control_TagActorSnapshot_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ControlServer).TagActorSnapshot(ctx, req.(*TagActorSnapshotRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Control_UpdateActorSnapshotTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateActorSnapshotTagRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ControlServer).UpdateActorSnapshotTag(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Control_UpdateActorSnapshotTag_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ControlServer).UpdateActorSnapshotTag(ctx, req.(*UpdateActorSnapshotTagRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Control_DeleteActorSnapshotTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteActorSnapshotTagRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ControlServer).DeleteActorSnapshotTag(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: Control_DeleteActorSnapshotTag_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ControlServer).DeleteActorSnapshotTag(ctx, req.(*DeleteActorSnapshotTagRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Control_ListWorkers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(ListWorkersRequest) if err := dec(in); err != nil { @@ -591,6 +775,26 @@ var Control_ServiceDesc = grpc.ServiceDesc{ MethodName: "DeleteActor", Handler: _Control_DeleteActor_Handler, }, + { + MethodName: "GetActorSnapshot", + Handler: _Control_GetActorSnapshot_Handler, + }, + { + MethodName: "ListActorSnapshots", + Handler: _Control_ListActorSnapshots_Handler, + }, + { + MethodName: "TagActorSnapshot", + Handler: _Control_TagActorSnapshot_Handler, + }, + { + MethodName: "UpdateActorSnapshotTag", + Handler: _Control_UpdateActorSnapshotTag_Handler, + }, + { + MethodName: "DeleteActorSnapshotTag", + Handler: _Control_DeleteActorSnapshotTag_Handler, + }, { MethodName: "ListWorkers", Handler: _Control_ListWorkers_Handler,