mirror of
https://github.com/agent-substrate/substrate.git
synced 2026-10-03 03:48:23 +08:00
Rename ActorSnapshotTag to Tag (#1491)
Renames the proto message, its status message and scope enum, the five RPCs and their request and response messages, the actor_snapshot_tag request fields, and Actor.source_snapshot_tag to source_tag. The store interface, its Postgres table, the object-storage prefix segment and the kubectl-ate verbs follow, so nothing keeps the old spelling. https://github.com/agent-substrate/substrate/issues/664 > It's a good idea to open an issue first for discussion. - [x] Tests pass - [x] Appropriate changes to documentation are included in the PR
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -104,30 +104,30 @@ class ControlStub:
|
||||
request_serializer=ateapi__pb2.DeleteActorEgressPolicyRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.EgressPolicy.FromString,
|
||||
_registered_method=True)
|
||||
self.CreateActorSnapshotTag = channel.unary_unary(
|
||||
'/ateapi.Control/CreateActorSnapshotTag',
|
||||
request_serializer=ateapi__pb2.CreateActorSnapshotTagRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.ActorSnapshotTag.FromString,
|
||||
self.CreateTag = channel.unary_unary(
|
||||
'/ateapi.Control/CreateTag',
|
||||
request_serializer=ateapi__pb2.CreateTagRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.Tag.FromString,
|
||||
_registered_method=True)
|
||||
self.GetActorSnapshotTag = channel.unary_unary(
|
||||
'/ateapi.Control/GetActorSnapshotTag',
|
||||
request_serializer=ateapi__pb2.GetActorSnapshotTagRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.ActorSnapshotTag.FromString,
|
||||
self.GetTag = channel.unary_unary(
|
||||
'/ateapi.Control/GetTag',
|
||||
request_serializer=ateapi__pb2.GetTagRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.Tag.FromString,
|
||||
_registered_method=True)
|
||||
self.ListActorSnapshotTags = channel.unary_unary(
|
||||
'/ateapi.Control/ListActorSnapshotTags',
|
||||
request_serializer=ateapi__pb2.ListActorSnapshotTagsRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.ListActorSnapshotTagsResponse.FromString,
|
||||
self.ListTags = channel.unary_unary(
|
||||
'/ateapi.Control/ListTags',
|
||||
request_serializer=ateapi__pb2.ListTagsRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.ListTagsResponse.FromString,
|
||||
_registered_method=True)
|
||||
self.UpdateActorSnapshotTag = channel.unary_unary(
|
||||
'/ateapi.Control/UpdateActorSnapshotTag',
|
||||
request_serializer=ateapi__pb2.UpdateActorSnapshotTagRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.ActorSnapshotTag.FromString,
|
||||
self.UpdateTag = channel.unary_unary(
|
||||
'/ateapi.Control/UpdateTag',
|
||||
request_serializer=ateapi__pb2.UpdateTagRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.Tag.FromString,
|
||||
_registered_method=True)
|
||||
self.DeleteActorSnapshotTag = channel.unary_unary(
|
||||
'/ateapi.Control/DeleteActorSnapshotTag',
|
||||
request_serializer=ateapi__pb2.DeleteActorSnapshotTagRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.ActorSnapshotTag.FromString,
|
||||
self.DeleteTag = channel.unary_unary(
|
||||
'/ateapi.Control/DeleteTag',
|
||||
request_serializer=ateapi__pb2.DeleteTagRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.Tag.FromString,
|
||||
_registered_method=True)
|
||||
self.ListWorkers = channel.unary_unary(
|
||||
'/ateapi.Control/ListWorkers',
|
||||
@@ -294,7 +294,7 @@ class ControlServicer:
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def CreateActorSnapshotTag(self, request, context):
|
||||
def CreateTag(self, request, context):
|
||||
"""Tag the external snapshot a suspended Actor holds. The tag gets its own
|
||||
copy of that snapshot, so suspending or deleting the Actor afterwards
|
||||
cannot collect it.
|
||||
@@ -303,32 +303,31 @@ class ControlServicer:
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetActorSnapshotTag(self, request, context):
|
||||
"""Get an ActorSnapshot tag.
|
||||
def GetTag(self, request, context):
|
||||
"""Get a Tag.
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def ListActorSnapshotTags(self, request, context):
|
||||
"""List ActorSnapshot tags.
|
||||
def ListTags(self, request, context):
|
||||
"""List Tags.
|
||||
"""
|
||||
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.
|
||||
def UpdateTag(self, request, context):
|
||||
"""Publish or unpublish a 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 and the external snapshot it owns. Actors
|
||||
created from the tag that have not yet been suspended still point at that
|
||||
external snapshot and become unrecoverable, so do not delete a tag while
|
||||
such Actors exist.
|
||||
def DeleteTag(self, request, context):
|
||||
"""Delete a Tag and the external snapshot it owns. Actors created from the
|
||||
tag that have not yet been suspended still point at that external snapshot
|
||||
and become unrecoverable, so do not delete a tag while such Actors exist.
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
@@ -416,7 +415,7 @@ class ControlServicer:
|
||||
|
||||
def DeleteAtespace(self, request, context):
|
||||
"""Delete an empty Atespace. Rejects (FailedPrecondition) if any Actors or
|
||||
ActorSnapshotTags remain.
|
||||
Tags remain.
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
@@ -506,30 +505,30 @@ def add_ControlServicer_to_server(servicer, server):
|
||||
request_deserializer=ateapi__pb2.DeleteActorEgressPolicyRequest.FromString,
|
||||
response_serializer=ateapi__pb2.EgressPolicy.SerializeToString,
|
||||
),
|
||||
'CreateActorSnapshotTag': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.CreateActorSnapshotTag,
|
||||
request_deserializer=ateapi__pb2.CreateActorSnapshotTagRequest.FromString,
|
||||
response_serializer=ateapi__pb2.ActorSnapshotTag.SerializeToString,
|
||||
'CreateTag': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.CreateTag,
|
||||
request_deserializer=ateapi__pb2.CreateTagRequest.FromString,
|
||||
response_serializer=ateapi__pb2.Tag.SerializeToString,
|
||||
),
|
||||
'GetActorSnapshotTag': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetActorSnapshotTag,
|
||||
request_deserializer=ateapi__pb2.GetActorSnapshotTagRequest.FromString,
|
||||
response_serializer=ateapi__pb2.ActorSnapshotTag.SerializeToString,
|
||||
'GetTag': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetTag,
|
||||
request_deserializer=ateapi__pb2.GetTagRequest.FromString,
|
||||
response_serializer=ateapi__pb2.Tag.SerializeToString,
|
||||
),
|
||||
'ListActorSnapshotTags': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.ListActorSnapshotTags,
|
||||
request_deserializer=ateapi__pb2.ListActorSnapshotTagsRequest.FromString,
|
||||
response_serializer=ateapi__pb2.ListActorSnapshotTagsResponse.SerializeToString,
|
||||
'ListTags': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.ListTags,
|
||||
request_deserializer=ateapi__pb2.ListTagsRequest.FromString,
|
||||
response_serializer=ateapi__pb2.ListTagsResponse.SerializeToString,
|
||||
),
|
||||
'UpdateActorSnapshotTag': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.UpdateActorSnapshotTag,
|
||||
request_deserializer=ateapi__pb2.UpdateActorSnapshotTagRequest.FromString,
|
||||
response_serializer=ateapi__pb2.ActorSnapshotTag.SerializeToString,
|
||||
'UpdateTag': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.UpdateTag,
|
||||
request_deserializer=ateapi__pb2.UpdateTagRequest.FromString,
|
||||
response_serializer=ateapi__pb2.Tag.SerializeToString,
|
||||
),
|
||||
'DeleteActorSnapshotTag': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.DeleteActorSnapshotTag,
|
||||
request_deserializer=ateapi__pb2.DeleteActorSnapshotTagRequest.FromString,
|
||||
response_serializer=ateapi__pb2.ActorSnapshotTag.SerializeToString,
|
||||
'DeleteTag': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.DeleteTag,
|
||||
request_deserializer=ateapi__pb2.DeleteTagRequest.FromString,
|
||||
response_serializer=ateapi__pb2.Tag.SerializeToString,
|
||||
),
|
||||
'ListWorkers': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.ListWorkers,
|
||||
@@ -921,7 +920,7 @@ class Control:
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def CreateActorSnapshotTag(request,
|
||||
def CreateTag(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
@@ -934,9 +933,9 @@ class Control:
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/ateapi.Control/CreateActorSnapshotTag',
|
||||
ateapi__pb2.CreateActorSnapshotTagRequest.SerializeToString,
|
||||
ateapi__pb2.ActorSnapshotTag.FromString,
|
||||
'/ateapi.Control/CreateTag',
|
||||
ateapi__pb2.CreateTagRequest.SerializeToString,
|
||||
ateapi__pb2.Tag.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
@@ -948,7 +947,7 @@ class Control:
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetActorSnapshotTag(request,
|
||||
def GetTag(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
@@ -961,9 +960,9 @@ class Control:
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/ateapi.Control/GetActorSnapshotTag',
|
||||
ateapi__pb2.GetActorSnapshotTagRequest.SerializeToString,
|
||||
ateapi__pb2.ActorSnapshotTag.FromString,
|
||||
'/ateapi.Control/GetTag',
|
||||
ateapi__pb2.GetTagRequest.SerializeToString,
|
||||
ateapi__pb2.Tag.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
@@ -975,7 +974,7 @@ class Control:
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def ListActorSnapshotTags(request,
|
||||
def ListTags(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
@@ -988,9 +987,9 @@ class Control:
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/ateapi.Control/ListActorSnapshotTags',
|
||||
ateapi__pb2.ListActorSnapshotTagsRequest.SerializeToString,
|
||||
ateapi__pb2.ListActorSnapshotTagsResponse.FromString,
|
||||
'/ateapi.Control/ListTags',
|
||||
ateapi__pb2.ListTagsRequest.SerializeToString,
|
||||
ateapi__pb2.ListTagsResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
@@ -1002,7 +1001,7 @@ class Control:
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def UpdateActorSnapshotTag(request,
|
||||
def UpdateTag(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
@@ -1015,9 +1014,9 @@ class Control:
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/ateapi.Control/UpdateActorSnapshotTag',
|
||||
ateapi__pb2.UpdateActorSnapshotTagRequest.SerializeToString,
|
||||
ateapi__pb2.ActorSnapshotTag.FromString,
|
||||
'/ateapi.Control/UpdateTag',
|
||||
ateapi__pb2.UpdateTagRequest.SerializeToString,
|
||||
ateapi__pb2.Tag.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
@@ -1029,7 +1028,7 @@ class Control:
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def DeleteActorSnapshotTag(request,
|
||||
def DeleteTag(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
@@ -1042,9 +1041,9 @@ class Control:
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/ateapi.Control/DeleteActorSnapshotTag',
|
||||
ateapi__pb2.DeleteActorSnapshotTagRequest.SerializeToString,
|
||||
ateapi__pb2.ActorSnapshotTag.FromString,
|
||||
'/ateapi.Control/DeleteTag',
|
||||
ateapi__pb2.DeleteTagRequest.SerializeToString,
|
||||
ateapi__pb2.Tag.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
|
||||
@@ -77,11 +77,11 @@ func (s *ServiceImpl) CreateActor(ctx context.Context, inActor *ateapipb.Actor)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// If a source snapshot tag is requested, resolve it to the external
|
||||
// If a source tag is requested, resolve it to the external
|
||||
// snapshot the new Actor starts from.
|
||||
var sourceTag *ateapipb.ActorSnapshotTag
|
||||
if tagRef := inActor.GetSourceSnapshotTag(); tagRef != nil {
|
||||
sourceTag, err = s.resolveSnapshotTagSource(ctx, inActor.GetMetadata().GetAtespace(), tagRef, template)
|
||||
var sourceTag *ateapipb.Tag
|
||||
if tagRef := inActor.GetSourceTag(); tagRef != nil {
|
||||
sourceTag, err = s.resolveTagSource(ctx, inActor.GetMetadata().GetAtespace(), tagRef, template)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -135,38 +135,38 @@ func (s *ServiceImpl) CreateActor(ctx context.Context, inActor *ateapipb.Actor)
|
||||
return stored, nil
|
||||
}
|
||||
|
||||
// resolveSnapshotTagSource resolves a CreateActor request's source snapshot tag
|
||||
// resolveTagSource resolves a CreateActor request's source tag
|
||||
// and checks that the tag is usable for creating an Actor in actorAtespace
|
||||
// from template.
|
||||
func (s *ServiceImpl) resolveSnapshotTagSource(ctx context.Context, actorAtespace string, tagRef *ateapipb.ObjectRef, template *ateapipb.ActorTemplate) (*ateapipb.ActorSnapshotTag, error) {
|
||||
tag, err := s.store.GetActorSnapshotTag(ctx, resources.ActorSnapshotTagRefFromObjectRef(tagRef))
|
||||
func (s *ServiceImpl) resolveTagSource(ctx context.Context, actorAtespace string, tagRef *ateapipb.ObjectRef, template *ateapipb.ActorTemplate) (*ateapipb.Tag, error) {
|
||||
tag, err := s.store.GetTag(ctx, resources.TagRefFromObjectRef(tagRef))
|
||||
if errors.Is(err, store.ErrNotFound) {
|
||||
return nil, status.Error(codes.NotFound, "ActorSnapshotTag not found")
|
||||
return nil, status.Error(codes.NotFound, "Tag not found")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("while getting actor snapshot tag: %w", err)
|
||||
return nil, fmt.Errorf("while getting tag: %w", err)
|
||||
}
|
||||
switch tag.GetScope() {
|
||||
case ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE:
|
||||
case ateapipb.TagScope_TAG_SCOPE_ATESPACE:
|
||||
if tag.GetMetadata().GetAtespace() != actorAtespace {
|
||||
return nil, status.Error(codes.FailedPrecondition, "ActorSnapshotTag is not published outside its Atespace")
|
||||
return nil, status.Error(codes.FailedPrecondition, "Tag is not published outside its Atespace")
|
||||
}
|
||||
case ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED:
|
||||
case ateapipb.TagScope_TAG_SCOPE_PUBLISHED:
|
||||
default:
|
||||
return nil, status.Error(codes.FailedPrecondition, "source ActorSnapshotTag has an invalid scope")
|
||||
return nil, status.Error(codes.FailedPrecondition, "source Tag has an invalid scope")
|
||||
}
|
||||
// A tag might have an empty Snapshot URI if the tag creation failed or is ongoing.
|
||||
if tag.GetStatus().GetSnapshot().GetSnapshotUri() == "" {
|
||||
return nil, status.Error(codes.FailedPrecondition, "source ActorSnapshotTag is still being created or failed creation")
|
||||
return nil, status.Error(codes.FailedPrecondition, "source Tag is still being created or failed creation")
|
||||
}
|
||||
// TODO: Permit compatible DATA snapshots when runtimes can extract portable data.
|
||||
if tag.GetStatus().GetActorTemplateUid() != template.GetMetadata().GetUid() {
|
||||
return nil, status.Errorf(codes.FailedPrecondition, "source ActorSnapshotTag must be taken from an actor with ActorTemplate uid %q", tag.GetStatus().GetActorTemplateUid())
|
||||
return nil, status.Errorf(codes.FailedPrecondition, "source Tag must be taken from an actor with ActorTemplate uid %q", tag.GetStatus().GetActorTemplateUid())
|
||||
}
|
||||
for _, volume := range template.GetVolumes() {
|
||||
if volume.GetExternalVolumeTemplate() != nil {
|
||||
// TODO: Permit cloning after CSI volume snapshots are supported.
|
||||
return nil, status.Error(codes.FailedPrecondition, "ActorSnapshotTag cloning does not support ActorTemplates with external volumes")
|
||||
return nil, status.Error(codes.FailedPrecondition, "Tag cloning does not support ActorTemplates with external volumes")
|
||||
}
|
||||
}
|
||||
return tag, nil
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -48,7 +48,7 @@ func TestValidateCreateActorRequest(t *testing.T) {
|
||||
withStatus := withActorStatus
|
||||
withMetadata := withActorMetadata
|
||||
withActorTemplate := withActorActorTemplate
|
||||
withSourceSnapshotTag := withActorSourceSnapshotTag
|
||||
withSourceTag := withActorSourceTag
|
||||
withWorkerSelector := withActorWorkerSelector
|
||||
|
||||
tests := []struct {
|
||||
@@ -140,25 +140,25 @@ func TestValidateCreateActorRequest(t *testing.T) {
|
||||
validReq(validActor(withWorkerSelector(map[string]string{"tier": "not valid!"}))),
|
||||
field.ErrorList{field.Invalid(field.NewPath("actor", "worker_selector", "match_labels").Key("tier"), "not valid!", "").WithOrigin("format=k8s-label-value")},
|
||||
}, {
|
||||
"valid actor.source_snapshot_tag",
|
||||
validReq(validActor(withSourceSnapshotTag("as", "tag"))),
|
||||
"valid actor.source_tag",
|
||||
validReq(validActor(withSourceTag("as", "tag"))),
|
||||
nil,
|
||||
}, {
|
||||
"missing actor.source_snapshot_tag.atespace",
|
||||
validReq(validActor(withSourceSnapshotTag("", "tag"))),
|
||||
field.ErrorList{field.Required(field.NewPath("actor", "source_snapshot_tag", "atespace"), "")},
|
||||
"missing actor.source_tag.atespace",
|
||||
validReq(validActor(withSourceTag("", "tag"))),
|
||||
field.ErrorList{field.Required(field.NewPath("actor", "source_tag", "atespace"), "")},
|
||||
}, {
|
||||
"invalid actor.source_snapshot_tag.atespace",
|
||||
validReq(validActor(withSourceSnapshotTag("invalid value", "tag"))),
|
||||
field.ErrorList{field.Invalid(field.NewPath("actor", "source_snapshot_tag", "atespace"), nil, "").WithOrigin("format=k8s-short-name")},
|
||||
"invalid actor.source_tag.atespace",
|
||||
validReq(validActor(withSourceTag("invalid value", "tag"))),
|
||||
field.ErrorList{field.Invalid(field.NewPath("actor", "source_tag", "atespace"), nil, "").WithOrigin("format=k8s-short-name")},
|
||||
}, {
|
||||
"missing actor.source_snapshot_tag.name",
|
||||
validReq(validActor(withSourceSnapshotTag("as", ""))),
|
||||
field.ErrorList{field.Required(field.NewPath("actor", "source_snapshot_tag", "name"), "")},
|
||||
"missing actor.source_tag.name",
|
||||
validReq(validActor(withSourceTag("as", ""))),
|
||||
field.ErrorList{field.Required(field.NewPath("actor", "source_tag", "name"), "")},
|
||||
}, {
|
||||
"invalid actor.source_snapshot_tag.name",
|
||||
validReq(validActor(withSourceSnapshotTag("as", "invalid value"))),
|
||||
field.ErrorList{field.Invalid(field.NewPath("actor", "source_snapshot_tag", "name"), nil, "").WithOrigin("format=k8s-short-name")},
|
||||
"invalid actor.source_tag.name",
|
||||
validReq(validActor(withSourceTag("as", "invalid value"))),
|
||||
field.ErrorList{field.Invalid(field.NewPath("actor", "source_tag", "name"), nil, "").WithOrigin("format=k8s-short-name")},
|
||||
}}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
@@ -182,7 +182,7 @@ func TestValidateActorUpdate(t *testing.T) {
|
||||
withMetadata := withActorMetadata
|
||||
withWorkerSelector := withActorWorkerSelector
|
||||
withActorTemplate := withActorActorTemplate
|
||||
withSourceSnapshotTag := withActorSourceSnapshotTag
|
||||
withSourceTag := withActorSourceTag
|
||||
withWorkerAssignment := withActorWorkerAssignment
|
||||
|
||||
tests := []struct {
|
||||
@@ -237,20 +237,20 @@ func TestValidateActorUpdate(t *testing.T) {
|
||||
validOutput(func(a *ateapipb.Actor) { a.ActorTemplate = nil }),
|
||||
field.ErrorList{field.Required(field.NewPath("actor_template"), "")},
|
||||
}, {
|
||||
"add actor.source_snapshot_tag",
|
||||
"add actor.source_tag",
|
||||
validInput(),
|
||||
validOutput(withSourceSnapshotTag("as", "nm")),
|
||||
field.ErrorList{field.Invalid(field.NewPath("source_snapshot_tag"), nil, "").WithOrigin("immutable")},
|
||||
validOutput(withSourceTag("as", "nm")),
|
||||
field.ErrorList{field.Invalid(field.NewPath("source_tag"), nil, "").WithOrigin("immutable")},
|
||||
}, {
|
||||
"clear actor.source_snapshot_tag",
|
||||
validInput(withSourceSnapshotTag("as", "nm")),
|
||||
validOutput(func(a *ateapipb.Actor) { a.SourceSnapshotTag = nil }),
|
||||
field.ErrorList{field.Invalid(field.NewPath("source_snapshot_tag"), nil, "").WithOrigin("immutable")},
|
||||
"clear actor.source_tag",
|
||||
validInput(withSourceTag("as", "nm")),
|
||||
validOutput(func(a *ateapipb.Actor) { a.SourceTag = nil }),
|
||||
field.ErrorList{field.Invalid(field.NewPath("source_tag"), nil, "").WithOrigin("immutable")},
|
||||
}, {
|
||||
"change actor.source_snapshot_tag",
|
||||
validInput(withSourceSnapshotTag("as1", "nm1")),
|
||||
validOutput(withSourceSnapshotTag("as2", "nm2")),
|
||||
field.ErrorList{field.Invalid(field.NewPath("source_snapshot_tag"), nil, "").WithOrigin("immutable")},
|
||||
"change actor.source_tag",
|
||||
validInput(withSourceTag("as1", "nm1")),
|
||||
validOutput(withSourceTag("as2", "nm2")),
|
||||
field.ErrorList{field.Invalid(field.NewPath("source_tag"), nil, "").WithOrigin("immutable")},
|
||||
}, {
|
||||
"set valid worker_selector",
|
||||
validInput(),
|
||||
@@ -287,20 +287,20 @@ func TestValidateActorUpdate(t *testing.T) {
|
||||
validOutput(withWorkerSelector(selectorLabelsOfSize(11))),
|
||||
field.ErrorList{field.TooMany(field.NewPath("worker_selector", "match_labels"), 11, 10).WithOrigin("maxProperties")},
|
||||
}, {
|
||||
"add actor.source_snapshot_tag",
|
||||
"add actor.source_tag",
|
||||
validInput(),
|
||||
validOutput(withSourceSnapshotTag("as", "nm")),
|
||||
field.ErrorList{field.Invalid(field.NewPath("source_snapshot_tag"), nil, "").WithOrigin("immutable")},
|
||||
validOutput(withSourceTag("as", "nm")),
|
||||
field.ErrorList{field.Invalid(field.NewPath("source_tag"), nil, "").WithOrigin("immutable")},
|
||||
}, {
|
||||
"clear actor.source_snapshot_tag",
|
||||
validInput(withSourceSnapshotTag("as", "nm")),
|
||||
validOutput(func(a *ateapipb.Actor) { a.SourceSnapshotTag = nil }),
|
||||
field.ErrorList{field.Invalid(field.NewPath("source_snapshot_tag"), nil, "").WithOrigin("immutable")},
|
||||
"clear actor.source_tag",
|
||||
validInput(withSourceTag("as", "nm")),
|
||||
validOutput(func(a *ateapipb.Actor) { a.SourceTag = nil }),
|
||||
field.ErrorList{field.Invalid(field.NewPath("source_tag"), nil, "").WithOrigin("immutable")},
|
||||
}, {
|
||||
"change actor.source_snapshot_tag",
|
||||
validInput(withSourceSnapshotTag("as1", "nm1")),
|
||||
validOutput(withSourceSnapshotTag("as2", "nm2")),
|
||||
field.ErrorList{field.Invalid(field.NewPath("source_snapshot_tag"), nil, "").WithOrigin("immutable")},
|
||||
"change actor.source_tag",
|
||||
validInput(withSourceTag("as1", "nm1")),
|
||||
validOutput(withSourceTag("as2", "nm2")),
|
||||
field.ErrorList{field.Invalid(field.NewPath("source_tag"), nil, "").WithOrigin("immutable")},
|
||||
}, {
|
||||
"unspecified actor.status",
|
||||
validInput(withStatus()),
|
||||
@@ -748,16 +748,16 @@ func TestUpdateActor(t *testing.T) {
|
||||
want: &ateapipb.Actor{},
|
||||
},
|
||||
{
|
||||
name: "SourceSnapshotTag immutable field is kept",
|
||||
stored: &ateapipb.Actor{SourceSnapshotTag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tag1"}},
|
||||
name: "SourceTag immutable field is kept",
|
||||
stored: &ateapipb.Actor{SourceTag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tag1"}},
|
||||
req: &ateapipb.Actor{
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: templateNS, Name: templateName},
|
||||
SourceSnapshotTag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tag1"},
|
||||
WorkerSelector: &ateapipb.Selector{MatchLabels: map[string]string{"tier": "paid"}},
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: templateNS, Name: templateName},
|
||||
SourceTag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tag1"},
|
||||
WorkerSelector: &ateapipb.Selector{MatchLabels: map[string]string{"tier": "paid"}},
|
||||
},
|
||||
want: &ateapipb.Actor{
|
||||
SourceSnapshotTag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tag1"},
|
||||
WorkerSelector: &ateapipb.Selector{MatchLabels: map[string]string{"tier": "paid"}},
|
||||
SourceTag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tag1"},
|
||||
WorkerSelector: &ateapipb.Selector{MatchLabels: map[string]string{"tier": "paid"}},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -771,19 +771,19 @@ func TestUpdateActor(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "an omitted immutable field is rejected",
|
||||
stored: &ateapipb.Actor{SourceSnapshotTag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tag1"}},
|
||||
stored: &ateapipb.Actor{SourceTag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tag1"}},
|
||||
req: &ateapipb.Actor{
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: templateNS, Name: templateName},
|
||||
// Omitted SourceSnapshotTag
|
||||
// Omitted SourceTag
|
||||
},
|
||||
wantCode: codes.InvalidArgument,
|
||||
},
|
||||
{
|
||||
name: "an immutable field the request rewrites is rejected",
|
||||
stored: &ateapipb.Actor{SourceSnapshotTag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tag1"}},
|
||||
stored: &ateapipb.Actor{SourceTag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tag1"}},
|
||||
req: &ateapipb.Actor{
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: "attacker-ns", Name: "attacker-tmpl"},
|
||||
SourceSnapshotTag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tag2"},
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: "attacker-ns", Name: "attacker-tmpl"},
|
||||
SourceTag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tag2"},
|
||||
},
|
||||
wantCode: codes.InvalidArgument,
|
||||
},
|
||||
@@ -1254,10 +1254,10 @@ func withActorActorTemplate(atespace, name string) func(*ateapipb.Actor) {
|
||||
return func(a *ateapipb.Actor) { a.ActorTemplate = &ateapipb.ObjectRef{Atespace: atespace, Name: name} }
|
||||
}
|
||||
|
||||
// withActorSourceSnapshotTag returns a modifier func (see validActor) which sets
|
||||
// the actor's source_snapshot_tag to a valid value.
|
||||
func withActorSourceSnapshotTag(atespace, name string) func(*ateapipb.Actor) {
|
||||
return func(a *ateapipb.Actor) { a.SourceSnapshotTag = &ateapipb.ObjectRef{Atespace: atespace, Name: name} }
|
||||
// withActorSourceTag returns a modifier func (see validActor) which sets
|
||||
// the actor's source_tag to a valid value.
|
||||
func withActorSourceTag(atespace, name string) func(*ateapipb.Actor) {
|
||||
return func(a *ateapipb.Actor) { a.SourceTag = &ateapipb.ObjectRef{Atespace: atespace, Name: name} }
|
||||
}
|
||||
|
||||
// withActorWorkerAssignment returns a modifier func (see validActor) which sets
|
||||
|
||||
@@ -282,16 +282,16 @@ func TestCreateActor_RejectsDifferentTemplateForDataSnapshot(t *testing.T) {
|
||||
tmpl := createTemplate(t, tc, ns)
|
||||
createTemplateWithSelector(t, tc, "tmpl2", nil)
|
||||
|
||||
seedActorSnapshotTag(t, tc, "data-source", "data-snapshot", func(tag *ateapipb.ActorSnapshotTag) {
|
||||
seedTag(t, tc, "data-source", "data-snapshot", func(tag *ateapipb.Tag) {
|
||||
tag.Status.Snapshot.ContentScope = ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_DATA
|
||||
tag.Status.ActorTemplateUid = tmpl.GetMetadata().GetUid()
|
||||
})
|
||||
|
||||
_, err := tc.service.CreateActor(context.Background(), &ateapipb.CreateActorRequest{
|
||||
Actor: &ateapipb.Actor{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "clone"},
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl2"},
|
||||
SourceSnapshotTag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "data-snapshot"},
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "clone"},
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl2"},
|
||||
SourceTag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "data-snapshot"},
|
||||
},
|
||||
})
|
||||
if status.Code(err) != codes.FailedPrecondition {
|
||||
@@ -326,16 +326,16 @@ func TestCreateActor_RejectsSnapshotWithExternalVolumes(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("Create ActorTemplate: %v", err)
|
||||
}
|
||||
seedActorSnapshotTag(t, tc, "external-volume-source", "external-volume-snapshot", func(tag *ateapipb.ActorSnapshotTag) {
|
||||
seedTag(t, tc, "external-volume-source", "external-volume-snapshot", func(tag *ateapipb.Tag) {
|
||||
tag.Status.ActorTemplateUid = template.GetMetadata().GetUid()
|
||||
})
|
||||
tagRef := &ateapipb.ObjectRef{Atespace: testAtespace, Name: "external-volume-snapshot"}
|
||||
|
||||
_, err = tc.service.CreateActor(context.Background(), &ateapipb.CreateActorRequest{
|
||||
Actor: &ateapipb.Actor{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "clone"},
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"},
|
||||
SourceSnapshotTag: tagRef,
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "clone"},
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"},
|
||||
SourceTag: tagRef,
|
||||
},
|
||||
})
|
||||
if status.Code(err) != codes.FailedPrecondition {
|
||||
@@ -343,11 +343,11 @@ func TestCreateActor_RejectsSnapshotWithExternalVolumes(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestCreateActor_PendingSnapshotTag verifies an Actor cannot be created from a
|
||||
// TestCreateActor_PendingTag verifies an Actor cannot be created from a
|
||||
// tag whose create never finished: the tag names a copy that may be partial, so
|
||||
// it only becomes a source once the create completes.
|
||||
func TestCreateActor_PendingSnapshotTag(t *testing.T) {
|
||||
ns := namespaceForTest("ns-pending-snapshot-tag")
|
||||
func TestCreateActor_PendingTag(t *testing.T) {
|
||||
ns := namespaceForTest("ns-pending-tag")
|
||||
tc := setupTest(t, ns)
|
||||
defer tc.cleanup()
|
||||
ctx := context.Background()
|
||||
@@ -355,7 +355,7 @@ func TestCreateActor_PendingSnapshotTag(t *testing.T) {
|
||||
|
||||
// Simulates a tag creation that failed in while writing the snapshot to
|
||||
// external storage.
|
||||
pending := seedActorSnapshotTag(t, tc, "pending-source", "pending", func(tag *ateapipb.ActorSnapshotTag) {
|
||||
pending := seedTag(t, tc, "pending-source", "pending", func(tag *ateapipb.Tag) {
|
||||
tag.Status.InProgressSnapshotUri = tag.GetStatus().GetSnapshot().GetSnapshotUri()
|
||||
tag.Status.Snapshot = nil
|
||||
tag.Status.ActorTemplateUid = tmpl.GetMetadata().GetUid()
|
||||
@@ -364,17 +364,17 @@ func TestCreateActor_PendingSnapshotTag(t *testing.T) {
|
||||
|
||||
// seeding an actor from the pending tag must fail.
|
||||
_, err := tc.client.CreateActor(ctx, &ateapipb.CreateActorRequest{Actor: &ateapipb.Actor{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "clone"},
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"},
|
||||
SourceSnapshotTag: tagRef,
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "clone"},
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"},
|
||||
SourceTag: tagRef,
|
||||
}})
|
||||
assertGrpcError(t, err, codes.FailedPrecondition, "source ActorSnapshotTag is still being created or failed creation")
|
||||
assertGrpcError(t, err, codes.FailedPrecondition, "source Tag is still being created or failed creation")
|
||||
|
||||
// Finishing the tag creation, so now the tag is qualified to be a tag source.
|
||||
snapshotURI := pending.GetStatus().GetInProgressSnapshotUri()
|
||||
if _, err := tc.persistence.UpdateActorSnapshotTag(ctx,
|
||||
resources.ActorSnapshotTagRefFromActorSnapshotTag(pending), store.PreconditionFrom(pending),
|
||||
func(toUpdate *ateapipb.ActorSnapshotTag) error {
|
||||
if _, err := tc.persistence.UpdateTag(ctx,
|
||||
resources.TagRefFromTag(pending), store.PreconditionFrom(pending),
|
||||
func(toUpdate *ateapipb.Tag) error {
|
||||
toUpdate.Status.Snapshot = &ateapipb.ExternalSnapshot{
|
||||
SnapshotUri: snapshotURI,
|
||||
ContentScope: ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_FULL,
|
||||
@@ -387,9 +387,9 @@ func TestCreateActor_PendingSnapshotTag(t *testing.T) {
|
||||
|
||||
// The tag was finalized. Now, actor creation should succeed.
|
||||
clone, err := tc.client.CreateActor(ctx, &ateapipb.CreateActorRequest{Actor: &ateapipb.Actor{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "clone"},
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"},
|
||||
SourceSnapshotTag: tagRef,
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "clone"},
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"},
|
||||
SourceTag: tagRef,
|
||||
}})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateActor from the finished tag failed: %v", err)
|
||||
@@ -1348,8 +1348,8 @@ func TestValidation_Actor(t *testing.T) {
|
||||
assertGrpcError(t, err, codes.InvalidArgument, "invalid page_token")
|
||||
})
|
||||
|
||||
t.Run("ListActorSnapshotTags invalid token", func(t *testing.T) {
|
||||
_, err := tc.client.ListActorSnapshotTags(context.Background(), &ateapipb.ListActorSnapshotTagsRequest{PageToken: "%%%"})
|
||||
t.Run("ListTags invalid token", func(t *testing.T) {
|
||||
_, err := tc.client.ListTags(context.Background(), &ateapipb.ListTagsRequest{PageToken: "%%%"})
|
||||
assertGrpcError(t, err, codes.InvalidArgument, "invalid page_token")
|
||||
})
|
||||
}
|
||||
@@ -2185,15 +2185,15 @@ func TestSuspendActor(t *testing.T) {
|
||||
// which here is the one the suspend above left behind.
|
||||
const tagName = "before-upgrade"
|
||||
tagRef := &ateapipb.ObjectRef{Atespace: testAtespace, Name: tagName}
|
||||
tagged, err := tc.client.CreateActorSnapshotTag(context.Background(), &ateapipb.CreateActorSnapshotTagRequest{
|
||||
ActorSnapshotTag: &ateapipb.ActorSnapshotTag{
|
||||
tagged, err := tc.client.CreateTag(context.Background(), &ateapipb.CreateTagRequest{
|
||||
Tag: &ateapipb.Tag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: tagName},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE,
|
||||
Scope: ateapipb.TagScope_TAG_SCOPE_ATESPACE,
|
||||
SourceActor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: name},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateActorSnapshotTag failed: %v", err)
|
||||
t.Fatalf("CreateTag failed: %v", err)
|
||||
}
|
||||
|
||||
// The tag owns a copy of its own, so the Actor's later suspends and its
|
||||
@@ -2205,26 +2205,26 @@ func TestSuspendActor(t *testing.T) {
|
||||
assertSnapshotPresent(t, tc, snapshotURI)
|
||||
assertSnapshotPresent(t, tc, tagSnapshotURI)
|
||||
|
||||
wantTag := &ateapipb.ActorSnapshotTag{
|
||||
wantTag := &ateapipb.Tag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: tagName},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE,
|
||||
Scope: ateapipb.TagScope_TAG_SCOPE_ATESPACE,
|
||||
SourceActor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: name},
|
||||
Status: &ateapipb.ActorSnapshotTagStatus{
|
||||
Status: &ateapipb.TagStatus{
|
||||
Snapshot: &ateapipb.ExternalSnapshot{SnapshotUri: tagSnapshotURI, ContentScope: sourceActor.GetStatus().GetExternalSnapshot().GetContentScope()},
|
||||
ActorTemplateUid: tmpl.GetMetadata().GetUid(),
|
||||
SourceActorUid: sourceActor.GetMetadata().GetUid(),
|
||||
},
|
||||
}
|
||||
stored, err := tc.client.GetActorSnapshotTag(context.Background(), &ateapipb.GetActorSnapshotTagRequest{ActorSnapshotTag: tagRef})
|
||||
stored, err := tc.client.GetTag(context.Background(), &ateapipb.GetTagRequest{Tag: tagRef})
|
||||
if err != nil {
|
||||
t.Fatalf("GetActorSnapshotTag failed: %v", err)
|
||||
t.Fatalf("GetTag failed: %v", err)
|
||||
}
|
||||
if diff := cmp.Diff(wantTag, stored, protocmp.Transform(), ignoreUID, ignoreVersion, ignoreTimestamps); diff != "" {
|
||||
t.Errorf("stored tag mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
listed, err := tc.client.ListActorSnapshotTags(context.Background(), &ateapipb.ListActorSnapshotTagsRequest{Atespace: testAtespace, PageSize: 1})
|
||||
if err != nil || len(listed.GetActorSnapshotTags()) != 1 {
|
||||
t.Fatalf("ListActorSnapshotTags = (%v, %v), want one", listed, err)
|
||||
listed, err := tc.client.ListTags(context.Background(), &ateapipb.ListTagsRequest{Atespace: testAtespace, PageSize: 1})
|
||||
if err != nil || len(listed.GetTags()) != 1 {
|
||||
t.Fatalf("ListTags = (%v, %v), want one", listed, err)
|
||||
}
|
||||
|
||||
// A tag is born ATESPACE-scoped, so it cannot seed an Actor elsewhere until
|
||||
@@ -2232,20 +2232,20 @@ func TestSuspendActor(t *testing.T) {
|
||||
createAtespace(t, tc, "other")
|
||||
crossAtespaceClone := &ateapipb.CreateActorRequest{
|
||||
Actor: &ateapipb.Actor{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: "other", Name: "cross-atespace"},
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"},
|
||||
SourceSnapshotTag: tagRef,
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: "other", Name: "cross-atespace"},
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"},
|
||||
SourceTag: tagRef,
|
||||
},
|
||||
}
|
||||
if _, err := tc.client.CreateActor(context.Background(), crossAtespaceClone); status.Code(err) != codes.FailedPrecondition {
|
||||
t.Fatalf("cross-atespace CreateActor status = %v, want FailedPrecondition", status.Code(err))
|
||||
}
|
||||
tagged.Scope = ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED
|
||||
updated, err := tc.client.UpdateActorSnapshotTag(context.Background(), &ateapipb.UpdateActorSnapshotTagRequest{
|
||||
ActorSnapshotTag: tagged,
|
||||
tagged.Scope = ateapipb.TagScope_TAG_SCOPE_PUBLISHED
|
||||
updated, err := tc.client.UpdateTag(context.Background(), &ateapipb.UpdateTagRequest{
|
||||
Tag: tagged,
|
||||
})
|
||||
if err != nil || updated.GetScope() != ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED {
|
||||
t.Fatalf("UpdateActorSnapshotTag = (%v, %v), want published", updated, err)
|
||||
if err != nil || updated.GetScope() != ateapipb.TagScope_TAG_SCOPE_PUBLISHED {
|
||||
t.Fatalf("UpdateTag = (%v, %v), want published", updated, err)
|
||||
}
|
||||
if updated.GetStatus().GetSnapshot().GetSnapshotUri() != tagSnapshotURI {
|
||||
t.Errorf("tag snapshot uri after publication = %q, want %q", updated.GetStatus().GetSnapshot().GetSnapshotUri(), tagSnapshotURI)
|
||||
@@ -2259,9 +2259,9 @@ func TestSuspendActor(t *testing.T) {
|
||||
// lifecycle from ever releasing it.
|
||||
clone, err := tc.client.CreateActor(context.Background(), &ateapipb.CreateActorRequest{
|
||||
Actor: &ateapipb.Actor{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "clone"},
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"},
|
||||
SourceSnapshotTag: tagRef,
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "clone"},
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"},
|
||||
SourceTag: tagRef,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
@@ -2273,8 +2273,8 @@ func TestSuspendActor(t *testing.T) {
|
||||
if snapshotOwnedByActor(t, clone, tagSnapshotURI) {
|
||||
t.Errorf("clone snapshot %s sits under the clone's own prefix, want it left under the tag's", tagSnapshotURI)
|
||||
}
|
||||
if !proto.Equal(clone.GetSourceSnapshotTag(), tagRef) {
|
||||
t.Errorf("clone source snapshot tag = %v, want %v", clone.GetSourceSnapshotTag(), tagRef)
|
||||
if !proto.Equal(clone.GetSourceTag(), tagRef) {
|
||||
t.Errorf("clone source tag = %v, want %v", clone.GetSourceTag(), tagRef)
|
||||
}
|
||||
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)
|
||||
@@ -2298,9 +2298,9 @@ func TestSuspendActor(t *testing.T) {
|
||||
assertSnapshotPresent(t, tc, tagSnapshotURI)
|
||||
assertSnapshotPresent(t, tc, cloneSnapshotURI)
|
||||
// The untagged suspend created no tag.
|
||||
listed, err = tc.client.ListActorSnapshotTags(context.Background(), &ateapipb.ListActorSnapshotTagsRequest{Atespace: testAtespace})
|
||||
if err != nil || len(listed.GetActorSnapshotTags()) != 1 {
|
||||
t.Fatalf("ListActorSnapshotTags after clone suspension = (%v, %v), want one", listed, err)
|
||||
listed, err = tc.client.ListTags(context.Background(), &ateapipb.ListTagsRequest{Atespace: testAtespace})
|
||||
if err != nil || len(listed.GetTags()) != 1 {
|
||||
t.Fatalf("ListTags after clone suspension = (%v, %v), want one", listed, err)
|
||||
}
|
||||
|
||||
getResp, err := tc.client.GetActor(context.Background(), &ateapipb.GetActorRequest{
|
||||
@@ -2332,17 +2332,17 @@ func TestSuspendActor(t *testing.T) {
|
||||
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.GetActorSnapshotTag(context.Background(), &ateapipb.GetActorSnapshotTagRequest{ActorSnapshotTag: tagRef}); err != nil {
|
||||
t.Fatalf("source snapshot tag disappeared with source Actor: %v", err)
|
||||
if _, err := tc.client.GetTag(context.Background(), &ateapipb.GetTagRequest{Tag: tagRef}); err != nil {
|
||||
t.Fatalf("source tag disappeared with source Actor: %v", err)
|
||||
}
|
||||
// The Actor took only what it owned with it.
|
||||
assertSnapshotCollected(t, tc, snapshotURI)
|
||||
assertSnapshotPresent(t, tc, tagSnapshotURI)
|
||||
|
||||
if deleted, err := tc.client.DeleteActorSnapshotTag(context.Background(), &ateapipb.DeleteActorSnapshotTagRequest{ActorSnapshotTag: tagRef}); err != nil || deleted.GetMetadata().GetName() != tagRef.GetName() {
|
||||
t.Fatalf("DeleteActorSnapshotTag = (%v, %v)", deleted, err)
|
||||
if deleted, err := tc.client.DeleteTag(context.Background(), &ateapipb.DeleteTagRequest{Tag: tagRef}); err != nil || deleted.GetMetadata().GetName() != tagRef.GetName() {
|
||||
t.Fatalf("DeleteTag = (%v, %v)", deleted, err)
|
||||
}
|
||||
if _, err := tc.client.GetActorSnapshotTag(context.Background(), &ateapipb.GetActorSnapshotTagRequest{ActorSnapshotTag: tagRef}); status.Code(err) != codes.NotFound {
|
||||
if _, err := tc.client.GetTag(context.Background(), &ateapipb.GetTagRequest{Tag: tagRef}); status.Code(err) != codes.NotFound {
|
||||
t.Fatalf("deleted tag status = %v, want NotFound", status.Code(err))
|
||||
}
|
||||
// Deleting the tag is what ends its snapshot's life. The clone that
|
||||
@@ -2352,7 +2352,7 @@ func TestSuspendActor(t *testing.T) {
|
||||
}
|
||||
|
||||
// TestResumeActor_RepointTemplateBeforeResume checks what an Actor cloned from
|
||||
// a snapshot tag asks atelet to restore on its first resume.
|
||||
// a tag asks atelet to restore on its first resume.
|
||||
//
|
||||
// The clone borrows a snapshot taken under the tag's template. Left on that
|
||||
// template, it restores in Full: memory and filesystem come back as they were.
|
||||
@@ -2416,14 +2416,14 @@ func TestResumeActor_RepointTemplateBeforeResume(t *testing.T) {
|
||||
waitForWorkerAvailable(t, tc, worker)
|
||||
|
||||
const tagName = "before-upgrade"
|
||||
if _, err := tc.client.CreateActorSnapshotTag(ctx, &ateapipb.CreateActorSnapshotTagRequest{
|
||||
ActorSnapshotTag: &ateapipb.ActorSnapshotTag{
|
||||
if _, err := tc.client.CreateTag(ctx, &ateapipb.CreateTagRequest{
|
||||
Tag: &ateapipb.Tag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: tagName},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE,
|
||||
Scope: ateapipb.TagScope_TAG_SCOPE_ATESPACE,
|
||||
SourceActor: actorRef,
|
||||
},
|
||||
}); err != nil {
|
||||
t.Fatalf("CreateActorSnapshotTag failed: %v", err)
|
||||
t.Fatalf("CreateTag failed: %v", err)
|
||||
}
|
||||
|
||||
const cloneActorName = "clone"
|
||||
@@ -2431,7 +2431,7 @@ func TestResumeActor_RepointTemplateBeforeResume(t *testing.T) {
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: cloneActorName},
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "tmpl1"},
|
||||
// Seeded from the tag.
|
||||
SourceSnapshotTag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: tagName},
|
||||
SourceTag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: tagName},
|
||||
}})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateActor from tag failed: %v", err)
|
||||
|
||||
+51
-51
@@ -28,11 +28,11 @@ import (
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
)
|
||||
|
||||
// seedActorSnapshotTag seeds a suspended actor holding an external snapshot plus
|
||||
// a finished tag over a copy of it: the state CreateActorSnapshotTag leaves
|
||||
// seedTag seeds a suspended actor holding an external snapshot plus
|
||||
// a finished tag over a copy of it: the state CreateTag leaves
|
||||
// behind. actorName must be unique within the test, since a tag records the
|
||||
// actor it was taken from; opts adjust the tag before it is written.
|
||||
func seedActorSnapshotTag(t *testing.T, tc *testContext, actorName, tagName string, opts ...func(*ateapipb.ActorSnapshotTag)) *ateapipb.ActorSnapshotTag {
|
||||
func seedTag(t *testing.T, tc *testContext, actorName, tagName string, opts ...func(*ateapipb.Tag)) *ateapipb.Tag {
|
||||
t.Helper()
|
||||
ctx := context.Background()
|
||||
actor := storetest.MustCreateActor(t, ctx, tc.persistence, &ateapipb.Actor{
|
||||
@@ -58,11 +58,11 @@ func seedActorSnapshotTag(t *testing.T, tc *testContext, actorName, tagName stri
|
||||
if err != nil {
|
||||
t.Fatalf("NewTagSnapshotURI: %v", err)
|
||||
}
|
||||
tag := &ateapipb.ActorSnapshotTag{
|
||||
tag := &ateapipb.Tag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: tagName},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE,
|
||||
Scope: ateapipb.TagScope_TAG_SCOPE_ATESPACE,
|
||||
SourceActor: resources.ActorRefFromActor(actor).ToObjectRef(),
|
||||
Status: &ateapipb.ActorSnapshotTagStatus{
|
||||
Status: &ateapipb.TagStatus{
|
||||
Snapshot: &ateapipb.ExternalSnapshot{SnapshotUri: tagSnapshotURI.String(), ContentScope: actor.GetStatus().GetExternalSnapshot().GetContentScope()},
|
||||
SourceActorUid: actor.GetMetadata().GetUid(),
|
||||
},
|
||||
@@ -70,14 +70,14 @@ func seedActorSnapshotTag(t *testing.T, tc *testContext, actorName, tagName stri
|
||||
for _, opt := range opts {
|
||||
opt(tag)
|
||||
}
|
||||
return storetest.MustCreateActorSnapshotTag(t, ctx, tc.persistence, tag)
|
||||
return storetest.MustCreateTag(t, ctx, tc.persistence, tag)
|
||||
}
|
||||
|
||||
// TestCreateActorSnapshotTag_ReusedTagName tests that a tag does not move
|
||||
// TestCreateTag_ReusedTagName tests that a tag does not move
|
||||
// between external snapshots. A tag name that is already taken must be reported
|
||||
// as taken, and the objects the existing tag names must be exactly what its own
|
||||
// creator wrote, because the rejected create reserves the name before it copies anything.
|
||||
func TestCreateActorSnapshotTag_ReusedTagName(t *testing.T) {
|
||||
func TestCreateTag_ReusedTagName(t *testing.T) {
|
||||
ns := namespaceForTest("ns-tag-reused-name")
|
||||
tc := setupTest(t, ns)
|
||||
defer tc.cleanup()
|
||||
@@ -88,15 +88,15 @@ func TestCreateActorSnapshotTag_ReusedTagName(t *testing.T) {
|
||||
// Actor A is suspended and tagged, the ordinary way.
|
||||
const tagName = "before-upgrade"
|
||||
actorFirstSnapshotURI := suspendActorForTest(t, tc, workerName, "actor-a")
|
||||
first, err := tc.client.CreateActorSnapshotTag(context.Background(), &ateapipb.CreateActorSnapshotTagRequest{
|
||||
ActorSnapshotTag: &ateapipb.ActorSnapshotTag{
|
||||
first, err := tc.client.CreateTag(context.Background(), &ateapipb.CreateTagRequest{
|
||||
Tag: &ateapipb.Tag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: tagName},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE,
|
||||
Scope: ateapipb.TagScope_TAG_SCOPE_ATESPACE,
|
||||
SourceActor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "actor-a"},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateActorSnapshotTag(actor-a) failed: %v", err)
|
||||
t.Fatalf("CreateTag(actor-a) failed: %v", err)
|
||||
}
|
||||
tagSnapshotURI := first.GetStatus().GetSnapshot().GetSnapshotUri()
|
||||
// Tag owns a snapshot. So it must not be empty.
|
||||
@@ -111,22 +111,22 @@ func TestCreateActorSnapshotTag_ReusedTagName(t *testing.T) {
|
||||
if secondSnapshotURI == actorFirstSnapshotURI {
|
||||
t.Fatalf("both actors suspended to %s, want distinct external snapshots", secondSnapshotURI)
|
||||
}
|
||||
_, err = tc.client.CreateActorSnapshotTag(context.Background(), &ateapipb.CreateActorSnapshotTagRequest{
|
||||
ActorSnapshotTag: &ateapipb.ActorSnapshotTag{
|
||||
_, err = tc.client.CreateTag(context.Background(), &ateapipb.CreateTagRequest{
|
||||
Tag: &ateapipb.Tag{
|
||||
// Same tagName that was written before.
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: tagName},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE,
|
||||
Scope: ateapipb.TagScope_TAG_SCOPE_ATESPACE,
|
||||
SourceActor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "actor-b"},
|
||||
},
|
||||
})
|
||||
assertGrpcError(t, err, codes.AlreadyExists, fmt.Sprintf("ActorSnapshotTag %s/%s already exists; delete it and create it again to retry", testAtespace, tagName))
|
||||
assertGrpcError(t, err, codes.AlreadyExists, fmt.Sprintf("Tag %s/%s already exists; delete it and create it again to retry", testAtespace, tagName))
|
||||
|
||||
// The row still contains actor A's tag
|
||||
stored, err := tc.client.GetActorSnapshotTag(context.Background(), &ateapipb.GetActorSnapshotTagRequest{
|
||||
ActorSnapshotTag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: tagName},
|
||||
stored, err := tc.client.GetTag(context.Background(), &ateapipb.GetTagRequest{
|
||||
Tag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: tagName},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("GetActorSnapshotTag failed: %v", err)
|
||||
t.Fatalf("GetTag failed: %v", err)
|
||||
}
|
||||
if diff := cmp.Diff(first, stored, protocmp.Transform()); diff != "" {
|
||||
t.Errorf("the rejected create modified the tag (-before +after):\n%s", diff)
|
||||
@@ -139,14 +139,14 @@ func TestCreateActorSnapshotTag_ReusedTagName(t *testing.T) {
|
||||
assertSnapshotPresent(t, tc, secondSnapshotURI)
|
||||
|
||||
// The collision is not a dead end: a free name works.
|
||||
if _, err := tc.client.CreateActorSnapshotTag(context.Background(), &ateapipb.CreateActorSnapshotTagRequest{
|
||||
ActorSnapshotTag: &ateapipb.ActorSnapshotTag{
|
||||
if _, err := tc.client.CreateTag(context.Background(), &ateapipb.CreateTagRequest{
|
||||
Tag: &ateapipb.Tag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "after-upgrade"},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE,
|
||||
Scope: ateapipb.TagScope_TAG_SCOPE_ATESPACE,
|
||||
SourceActor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "actor-b"},
|
||||
},
|
||||
}); err != nil {
|
||||
t.Fatalf("CreateActorSnapshotTag under a free name failed: %v", err)
|
||||
t.Fatalf("CreateTag under a free name failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,9 +183,9 @@ func suspendActorForTest(t *testing.T, tc *testContext, workerName, name string)
|
||||
return uri
|
||||
}
|
||||
|
||||
// TestUpdateActorSnapshotTag_Preconditions verifies the required version and uid
|
||||
// TestUpdateTag_Preconditions verifies the required version and uid
|
||||
// guards carried in the tag's metadata.
|
||||
func TestUpdateActorSnapshotTag_Preconditions(t *testing.T) {
|
||||
func TestUpdateTag_Preconditions(t *testing.T) {
|
||||
ns := namespaceForTest("ns-update-tag-preconditions")
|
||||
tc := setupTest(t, ns)
|
||||
defer tc.cleanup()
|
||||
@@ -199,10 +199,10 @@ func TestUpdateActorSnapshotTag_Preconditions(t *testing.T) {
|
||||
// observable write that bumps the version.
|
||||
// The tag under test is seeded from actor-2; source_actor is immutable, so
|
||||
// every update has to echo it back.
|
||||
update := func(meta *ateapipb.ResourceMetadata, scope ateapipb.ActorSnapshotTagScope) (*ateapipb.ActorSnapshotTag, error) {
|
||||
update := func(meta *ateapipb.ResourceMetadata, scope ateapipb.TagScope) (*ateapipb.Tag, error) {
|
||||
meta.Atespace, meta.Name = testAtespace, tagName
|
||||
return tc.client.UpdateActorSnapshotTag(context.Background(), &ateapipb.UpdateActorSnapshotTagRequest{
|
||||
ActorSnapshotTag: &ateapipb.ActorSnapshotTag{
|
||||
return tc.client.UpdateTag(context.Background(), &ateapipb.UpdateTagRequest{
|
||||
Tag: &ateapipb.Tag{
|
||||
Metadata: meta,
|
||||
Scope: scope,
|
||||
SourceActor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "actor-2"},
|
||||
@@ -212,54 +212,54 @@ func TestUpdateActorSnapshotTag_Preconditions(t *testing.T) {
|
||||
|
||||
// Delete and recreate the same atespace/name tag, so the first lifecycle's
|
||||
// uid becomes stale.
|
||||
staleUID := seedActorSnapshotTag(t, tc, "actor-1", tagName).GetMetadata().GetUid()
|
||||
if _, err := tc.client.DeleteActorSnapshotTag(ctx, &ateapipb.DeleteActorSnapshotTagRequest{
|
||||
ActorSnapshotTag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: tagName},
|
||||
staleUID := seedTag(t, tc, "actor-1", tagName).GetMetadata().GetUid()
|
||||
if _, err := tc.client.DeleteTag(ctx, &ateapipb.DeleteTagRequest{
|
||||
Tag: &ateapipb.ObjectRef{Atespace: testAtespace, Name: tagName},
|
||||
}); err != nil {
|
||||
t.Fatalf("DeleteActorSnapshotTag failed: %v", err)
|
||||
t.Fatalf("DeleteTag failed: %v", err)
|
||||
}
|
||||
|
||||
tagged := seedActorSnapshotTag(t, tc, "actor-2", tagName)
|
||||
tagged := seedTag(t, tc, "actor-2", tagName)
|
||||
staleVersion := tagged.GetMetadata().GetVersion()
|
||||
uid := tagged.GetMetadata().GetUid()
|
||||
if uid == staleUID {
|
||||
t.Fatalf("recreated tag reused uid %s, want a fresh one", uid)
|
||||
}
|
||||
// No preconditions
|
||||
_, err := update(&ateapipb.ResourceMetadata{}, ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED)
|
||||
assertGrpcError(t, err, codes.InvalidArgument, fmt.Sprintf("while updating actor snapshot tag %s/%s: persistence: precondition required: uid", testAtespace, tagName))
|
||||
_, err := update(&ateapipb.ResourceMetadata{}, ateapipb.TagScope_TAG_SCOPE_PUBLISHED)
|
||||
assertGrpcError(t, err, codes.InvalidArgument, fmt.Sprintf("while updating tag %s/%s: persistence: precondition required: uid", testAtespace, tagName))
|
||||
|
||||
// The uid from the deleted lifecycle must be rejected, even though the
|
||||
// atespace/name it was observed under still resolves and the version it
|
||||
// guards on matches the recreated tag's.
|
||||
_, err = update(&ateapipb.ResourceMetadata{Uid: staleUID, Version: staleVersion}, ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED)
|
||||
assertGrpcError(t, err, codes.Aborted, fmt.Sprintf("ActorSnapshotTag %s/%s not found with uid %s", testAtespace, tagName, staleUID))
|
||||
_, err = update(&ateapipb.ResourceMetadata{Uid: staleUID, Version: staleVersion}, ateapipb.TagScope_TAG_SCOPE_PUBLISHED)
|
||||
assertGrpcError(t, err, codes.Aborted, fmt.Sprintf("Tag %s/%s not found with uid %s", testAtespace, tagName, staleUID))
|
||||
|
||||
// Both guards matching the observed state: the update goes through, and
|
||||
// moves the tag past the version observed above.
|
||||
first, err := update(&ateapipb.ResourceMetadata{Uid: uid, Version: staleVersion}, ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED)
|
||||
first, err := update(&ateapipb.ResourceMetadata{Uid: uid, Version: staleVersion}, ateapipb.TagScope_TAG_SCOPE_PUBLISHED)
|
||||
if err != nil {
|
||||
t.Fatalf("UpdateActorSnapshotTag(matching guards) failed: %v", err)
|
||||
t.Fatalf("UpdateTag(matching guards) failed: %v", err)
|
||||
}
|
||||
currentVersion := first.GetMetadata().GetVersion()
|
||||
if currentVersion <= staleVersion {
|
||||
t.Fatalf("version = %d, want greater than %d after an update", currentVersion, staleVersion)
|
||||
}
|
||||
if got, want := first.GetScope(), ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED; got != want {
|
||||
if got, want := first.GetScope(), ateapipb.TagScope_TAG_SCOPE_PUBLISHED; got != want {
|
||||
t.Errorf("scope = %v, want %v", got, want)
|
||||
}
|
||||
|
||||
// The version observed before that write is now stale: rejected rather than
|
||||
// silently overwriting the concurrent change.
|
||||
_, err = update(&ateapipb.ResourceMetadata{Uid: uid, Version: staleVersion}, ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE)
|
||||
_, err = update(&ateapipb.ResourceMetadata{Uid: uid, Version: staleVersion}, ateapipb.TagScope_TAG_SCOPE_ATESPACE)
|
||||
assertGrpcError(t, err, codes.Aborted, "concurrent update conflict, please retry")
|
||||
|
||||
// Guarding on the version the last write produced succeeds again.
|
||||
updated, err := update(&ateapipb.ResourceMetadata{Uid: uid, Version: currentVersion}, ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE)
|
||||
updated, err := update(&ateapipb.ResourceMetadata{Uid: uid, Version: currentVersion}, ateapipb.TagScope_TAG_SCOPE_ATESPACE)
|
||||
if err != nil {
|
||||
t.Fatalf("UpdateActorSnapshotTag(matching guards) failed: %v", err)
|
||||
t.Fatalf("UpdateTag(matching guards) failed: %v", err)
|
||||
}
|
||||
if got, want := updated.GetScope(), ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE; got != want {
|
||||
if got, want := updated.GetScope(), ateapipb.TagScope_TAG_SCOPE_ATESPACE; got != want {
|
||||
t.Errorf("scope = %v, want %v", got, want)
|
||||
}
|
||||
if updated.GetMetadata().GetVersion() <= currentVersion {
|
||||
@@ -267,17 +267,17 @@ func TestUpdateActorSnapshotTag_Preconditions(t *testing.T) {
|
||||
}
|
||||
|
||||
// The guard the client just satisfied is now stale in turn.
|
||||
_, err = update(&ateapipb.ResourceMetadata{Uid: uid, Version: currentVersion}, ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED)
|
||||
_, err = update(&ateapipb.ResourceMetadata{Uid: uid, Version: currentVersion}, ateapipb.TagScope_TAG_SCOPE_PUBLISHED)
|
||||
assertGrpcError(t, err, codes.Aborted, "concurrent update conflict, please retry")
|
||||
}
|
||||
|
||||
func TestUpdateActorSnapshotTag_NotFound(t *testing.T) {
|
||||
func TestUpdateTag_NotFound(t *testing.T) {
|
||||
ns := namespaceForTest("ns-update-tag-notfound")
|
||||
tc := setupTest(t, ns)
|
||||
defer tc.cleanup()
|
||||
|
||||
_, err := tc.client.UpdateActorSnapshotTag(context.Background(), &ateapipb.UpdateActorSnapshotTagRequest{
|
||||
ActorSnapshotTag: &ateapipb.ActorSnapshotTag{
|
||||
_, err := tc.client.UpdateTag(context.Background(), &ateapipb.UpdateTagRequest{
|
||||
Tag: &ateapipb.Tag{
|
||||
Metadata: &ateapipb.ResourceMetadata{
|
||||
Atespace: testAtespace,
|
||||
Name: "does-not-exist",
|
||||
@@ -285,9 +285,9 @@ func TestUpdateActorSnapshotTag_NotFound(t *testing.T) {
|
||||
Uid: "9a2b1c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d",
|
||||
Version: 1,
|
||||
},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED,
|
||||
Scope: ateapipb.TagScope_TAG_SCOPE_PUBLISHED,
|
||||
SourceActor: &ateapipb.ObjectRef{Atespace: testAtespace, Name: "actor-1"},
|
||||
},
|
||||
})
|
||||
assertGrpcError(t, err, codes.NotFound, "ActorSnapshotTag test-atespace/does-not-exist not found")
|
||||
assertGrpcError(t, err, codes.NotFound, "Tag test-atespace/does-not-exist not found")
|
||||
}
|
||||
@@ -105,10 +105,10 @@ type serviceStore interface {
|
||||
GetEgressPolicy(ctx context.Context, actorRef resources.ActorRef) (*ateapipb.EgressPolicy, error)
|
||||
UpdateEgressPolicy(ctx context.Context, actorRef resources.ActorRef, precondition store.Precondition, mutate func(*ateapipb.EgressPolicy) error) (*ateapipb.EgressPolicy, error)
|
||||
DeleteEgressPolicy(ctx context.Context, actorRef resources.ActorRef) (*ateapipb.EgressPolicy, error)
|
||||
GetActorSnapshotTag(ctx context.Context, tagRef resources.ActorSnapshotTagRef) (*ateapipb.ActorSnapshotTag, error)
|
||||
ListActorSnapshotTags(ctx context.Context, atespace string, opts store.ListOptions) (store.ListResponse[*ateapipb.ActorSnapshotTag], error)
|
||||
UpdateActorSnapshotTag(ctx context.Context, tagRef resources.ActorSnapshotTagRef, precondition store.Precondition, mutate func(toUpdate *ateapipb.ActorSnapshotTag) error) (*ateapipb.ActorSnapshotTag, error)
|
||||
DeleteActorSnapshotTag(ctx context.Context, tagRef resources.ActorSnapshotTagRef) (*ateapipb.ActorSnapshotTag, error)
|
||||
GetTag(ctx context.Context, tagRef resources.TagRef) (*ateapipb.Tag, error)
|
||||
ListTags(ctx context.Context, atespace string, opts store.ListOptions) (store.ListResponse[*ateapipb.Tag], error)
|
||||
UpdateTag(ctx context.Context, tagRef resources.TagRef, precondition store.Precondition, mutate func(toUpdate *ateapipb.Tag) error) (*ateapipb.Tag, error)
|
||||
DeleteTag(ctx context.Context, tagRef resources.TagRef) (*ateapipb.Tag, error)
|
||||
CreateAtespace(ctx context.Context, atespace *ateapipb.Atespace) (*ateapipb.Atespace, error)
|
||||
GetAtespace(ctx context.Context, name string) (*ateapipb.Atespace, error)
|
||||
ListAtespaces(ctx context.Context, opts store.ListOptions) (store.ListResponse[*ateapipb.Atespace], error)
|
||||
|
||||
+69
-69
@@ -31,25 +31,25 @@ import (
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
)
|
||||
|
||||
// CreateActorSnapshotTag tags the external snapshot a suspended Actor holds,
|
||||
// giving the tag its own copy of that snapshot so the Actor being suspended
|
||||
// CreateTag tags the external snapshot a suspended Actor holds, giving the
|
||||
// tag its own copy of that snapshot so the Actor being suspended
|
||||
// again or deleted cannot collect it. The work is a workflow because it spans
|
||||
// two transactions around an object copy; see TagActorSnapshot.
|
||||
func (s *RPCService) CreateActorSnapshotTag(ctx context.Context, req *ateapipb.CreateActorSnapshotTagRequest) (*ateapipb.ActorSnapshotTag, error) {
|
||||
func (s *RPCService) CreateTag(ctx context.Context, req *ateapipb.CreateTagRequest) (*ateapipb.Tag, error) {
|
||||
// First scrub any fields that users are not allowed to set.
|
||||
inTag := req.ActorSnapshotTag
|
||||
inTag := req.Tag
|
||||
if inTag != nil { // otherwise validation will flag it
|
||||
scrubResourceMetadataForCreate(inTag.Metadata)
|
||||
inTag.Status = nil
|
||||
}
|
||||
|
||||
if errs := validateCreateActorSnapshotTagRequest(ctx, req); len(errs) > 0 {
|
||||
if errs := validateCreateTagRequest(ctx, req); len(errs) > 0 {
|
||||
return nil, toGRPCStatusError(errs)
|
||||
}
|
||||
actorRef := resources.ActorRefFromObjectRef(req.GetActorSnapshotTag().GetSourceActor())
|
||||
actorRef := resources.ActorRefFromObjectRef(req.GetTag().GetSourceActor())
|
||||
setSpanActorRefAttributes(ctx, actorRef)
|
||||
|
||||
tag, err := s.actorWorkflow.TagActorSnapshot(ctx, req.GetActorSnapshotTag())
|
||||
tag, err := s.actorWorkflow.TagActorSnapshot(ctx, req.GetTag())
|
||||
if err != nil {
|
||||
if errors.Is(err, store.ErrNotFound) {
|
||||
return nil, status.Errorf(codes.NotFound, "Actor %s not found", actorRef)
|
||||
@@ -59,18 +59,18 @@ func (s *RPCService) CreateActorSnapshotTag(ctx context.Context, req *ateapipb.C
|
||||
return tag, nil
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) CreateActorSnapshotTag(ctx context.Context, tag *ateapipb.ActorSnapshotTag) (*ateapipb.ActorSnapshotTag, error) {
|
||||
func (s *ServiceImpl) CreateTag(ctx context.Context, tag *ateapipb.Tag) (*ateapipb.Tag, error) {
|
||||
// TODO: implement this
|
||||
return s.store.CreateActorSnapshotTag(ctx, tag)
|
||||
return s.store.CreateTag(ctx, tag)
|
||||
}
|
||||
|
||||
func validateCreateActorSnapshotTagRequest(ctx context.Context, req *ateapipb.CreateActorSnapshotTagRequest) field.ErrorList {
|
||||
func validateCreateTagRequest(ctx context.Context, req *ateapipb.CreateTagRequest) field.ErrorList {
|
||||
op := operation.Operation{Type: operation.Create}
|
||||
return Validate_CreateActorSnapshotTagRequest(ctx, op, nil, req, nil)
|
||||
return Validate_CreateTagRequest(ctx, op, nil, req, nil)
|
||||
}
|
||||
|
||||
func ValidateCustom_CreateActorSnapshotTagRequest(_ context.Context, _ operation.Operation, p *field.Path, req, _ *ateapipb.CreateActorSnapshotTagRequest) field.ErrorList {
|
||||
tag := req.GetActorSnapshotTag()
|
||||
func ValidateCustom_CreateTagRequest(_ context.Context, _ operation.Operation, p *field.Path, req, _ *ateapipb.CreateTagRequest) field.ErrorList {
|
||||
tag := req.GetTag()
|
||||
sourceActorAtespace := tag.GetSourceActor().GetAtespace()
|
||||
tagAtespace := tag.GetMetadata().GetAtespace()
|
||||
if sourceActorAtespace == "" || tagAtespace == "" {
|
||||
@@ -78,77 +78,77 @@ func ValidateCustom_CreateActorSnapshotTagRequest(_ context.Context, _ operation
|
||||
}
|
||||
if tagAtespace != sourceActorAtespace {
|
||||
return field.ErrorList{
|
||||
field.Invalid(p.Child("actor_snapshot_tag", "metadata", "atespace"), tagAtespace, "must match source_actor.atespace"),
|
||||
field.Invalid(p.Child("tag", "metadata", "atespace"), tagAtespace, "must match source_actor.atespace"),
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *RPCService) GetActorSnapshotTag(ctx context.Context, req *ateapipb.GetActorSnapshotTagRequest) (*ateapipb.ActorSnapshotTag, error) {
|
||||
if errs := validateGetActorSnapshotTagRequest(ctx, req); len(errs) > 0 {
|
||||
func (s *RPCService) GetTag(ctx context.Context, req *ateapipb.GetTagRequest) (*ateapipb.Tag, error) {
|
||||
if errs := validateGetTagRequest(ctx, req); len(errs) > 0 {
|
||||
return nil, toGRPCStatusError(errs)
|
||||
}
|
||||
tag, err := s.impl.GetActorSnapshotTag(ctx, resources.ActorSnapshotTagRefFromObjectRef(req.GetActorSnapshotTag()))
|
||||
tag, err := s.impl.GetTag(ctx, resources.TagRefFromObjectRef(req.GetTag()))
|
||||
if errors.Is(err, store.ErrNotFound) {
|
||||
return nil, status.Error(codes.NotFound, "ActorSnapshotTag not found")
|
||||
return nil, status.Error(codes.NotFound, "Tag not found")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("while getting actor snapshot tag: %w", err)
|
||||
return nil, fmt.Errorf("while getting tag: %w", err)
|
||||
}
|
||||
return tag, nil
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) GetActorSnapshotTag(ctx context.Context, tagRef resources.ActorSnapshotTagRef) (*ateapipb.ActorSnapshotTag, error) {
|
||||
func (s *ServiceImpl) GetTag(ctx context.Context, tagRef resources.TagRef) (*ateapipb.Tag, error) {
|
||||
// TODO: implement this
|
||||
return s.store.GetActorSnapshotTag(ctx, tagRef)
|
||||
return s.store.GetTag(ctx, tagRef)
|
||||
}
|
||||
|
||||
func validateGetActorSnapshotTagRequest(ctx context.Context, req *ateapipb.GetActorSnapshotTagRequest) field.ErrorList {
|
||||
func validateGetTagRequest(ctx context.Context, req *ateapipb.GetTagRequest) field.ErrorList {
|
||||
op := operation.Operation{Type: operation.Create}
|
||||
return Validate_GetActorSnapshotTagRequest(ctx, op, nil, req, nil)
|
||||
return Validate_GetTagRequest(ctx, op, nil, req, nil)
|
||||
}
|
||||
|
||||
func (s *RPCService) ListActorSnapshotTags(ctx context.Context, req *ateapipb.ListActorSnapshotTagsRequest) (*ateapipb.ListActorSnapshotTagsResponse, error) {
|
||||
if errs := validateListActorSnapshotTagsRequest(ctx, req); len(errs) > 0 {
|
||||
func (s *RPCService) ListTags(ctx context.Context, req *ateapipb.ListTagsRequest) (*ateapipb.ListTagsResponse, error) {
|
||||
if errs := validateListTagsRequest(ctx, req); len(errs) > 0 {
|
||||
return nil, toGRPCStatusError(errs)
|
||||
}
|
||||
page, err := s.impl.ListActorSnapshotTags(ctx, req.GetAtespace(), store.ListOptions{PageSize: effectivePageSize(req.GetPageSize()), PageToken: req.GetPageToken()})
|
||||
page, err := s.impl.ListTags(ctx, req.GetAtespace(), store.ListOptions{PageSize: effectivePageSize(req.GetPageSize()), PageToken: req.GetPageToken()})
|
||||
if err != nil {
|
||||
return nil, mapListError(fmt.Errorf("while listing actor snapshot tags: %w", err))
|
||||
return nil, mapListError(fmt.Errorf("while listing tags: %w", err))
|
||||
}
|
||||
return &ateapipb.ListActorSnapshotTagsResponse{ActorSnapshotTags: page.Items, NextPageToken: page.NextPageToken}, nil
|
||||
return &ateapipb.ListTagsResponse{Tags: page.Items, NextPageToken: page.NextPageToken}, nil
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) ListActorSnapshotTags(ctx context.Context, atespace string, opts store.ListOptions) (store.ListResponse[*ateapipb.ActorSnapshotTag], error) {
|
||||
func (s *ServiceImpl) ListTags(ctx context.Context, atespace string, opts store.ListOptions) (store.ListResponse[*ateapipb.Tag], error) {
|
||||
// TODO: implement this
|
||||
return s.store.ListActorSnapshotTags(ctx, atespace, opts)
|
||||
return s.store.ListTags(ctx, atespace, opts)
|
||||
}
|
||||
|
||||
func validateListActorSnapshotTagsRequest(ctx context.Context, req *ateapipb.ListActorSnapshotTagsRequest) field.ErrorList {
|
||||
func validateListTagsRequest(ctx context.Context, req *ateapipb.ListTagsRequest) field.ErrorList {
|
||||
op := operation.Operation{Type: operation.Create}
|
||||
return Validate_ListActorSnapshotTagsRequest(ctx, op, nil, req, nil)
|
||||
return Validate_ListTagsRequest(ctx, op, nil, req, nil)
|
||||
}
|
||||
|
||||
// errTagPending is what the update's mutate closure returns when the stored
|
||||
// tag's create never finished, so the caller can tell it apart from a store
|
||||
// failure and answer FAILED_PRECONDITION.
|
||||
var errTagPending = errors.New("ActorSnapshotTag is still being created")
|
||||
var errTagPending = errors.New("tag is still being created")
|
||||
|
||||
func (s *RPCService) UpdateActorSnapshotTag(ctx context.Context, req *ateapipb.UpdateActorSnapshotTagRequest) (*ateapipb.ActorSnapshotTag, error) {
|
||||
func (s *RPCService) UpdateTag(ctx context.Context, req *ateapipb.UpdateTagRequest) (*ateapipb.Tag, error) {
|
||||
// First scrub any fields that users are not allowed to set.
|
||||
inTag := req.ActorSnapshotTag
|
||||
inTag := req.Tag
|
||||
if inTag != nil { // otherwise validation will flag it
|
||||
scrubResourceMetadataForUpdate(inTag.Metadata)
|
||||
inTag.Status = nil
|
||||
}
|
||||
|
||||
if errs := validateUpdateActorSnapshotTagRequest(ctx, req); len(errs) > 0 {
|
||||
if errs := validateUpdateTagRequest(ctx, req); len(errs) > 0 {
|
||||
return nil, toGRPCStatusError(errs)
|
||||
}
|
||||
in := req.GetActorSnapshotTag()
|
||||
tagRef := resources.ActorSnapshotTagRefFromActorSnapshotTag(in)
|
||||
in := req.GetTag()
|
||||
tagRef := resources.TagRefFromTag(in)
|
||||
|
||||
storedTag, err := s.impl.UpdateActorSnapshotTag(ctx, tagRef, store.PreconditionFrom(in), func(toUpdate *ateapipb.ActorSnapshotTag) error {
|
||||
storedTag, err := s.impl.UpdateTag(ctx, tagRef, store.PreconditionFrom(in), func(toUpdate *ateapipb.Tag) error {
|
||||
// A tag whose create never finished names a partial copy. Publishing it
|
||||
// — or changing its scope at all — would hand out content that is still
|
||||
// being written, or may never be.
|
||||
@@ -172,30 +172,30 @@ func (s *RPCService) UpdateActorSnapshotTag(ctx context.Context, req *ateapipb.U
|
||||
})
|
||||
if err != nil {
|
||||
if errors.Is(err, errTagPending) {
|
||||
return nil, status.Errorf(codes.FailedPrecondition, "ActorSnapshotTag %s/%s is still being created", tagRef.Atespace, tagRef.Name)
|
||||
return nil, status.Errorf(codes.FailedPrecondition, "Tag %s/%s is still being created", tagRef.Atespace, tagRef.Name)
|
||||
}
|
||||
if errors.Is(err, store.ErrImmutableField) {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "while updating actor snapshot tag %s/%s: %v", tagRef.Atespace, tagRef.Name, err)
|
||||
return nil, status.Errorf(codes.InvalidArgument, "while updating tag %s/%s: %v", tagRef.Atespace, tagRef.Name, err)
|
||||
}
|
||||
if errors.Is(err, store.ErrVersionConflict) {
|
||||
return nil, status.Error(codes.Aborted, "concurrent update conflict, please retry")
|
||||
}
|
||||
if errors.Is(err, store.ErrUIDConflict) {
|
||||
return nil, status.Errorf(codes.Aborted, "ActorSnapshotTag %s/%s not found with uid %s", tagRef.Atespace, tagRef.Name, in.GetMetadata().GetUid())
|
||||
return nil, status.Errorf(codes.Aborted, "Tag %s/%s not found with uid %s", tagRef.Atespace, tagRef.Name, in.GetMetadata().GetUid())
|
||||
}
|
||||
if errors.Is(err, store.ErrNotFound) {
|
||||
return nil, status.Errorf(codes.NotFound, "ActorSnapshotTag %s/%s not found", tagRef.Atespace, tagRef.Name)
|
||||
return nil, status.Errorf(codes.NotFound, "Tag %s/%s not found", tagRef.Atespace, tagRef.Name)
|
||||
}
|
||||
if errors.Is(err, store.ErrPreconditionRequired) {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "while updating actor snapshot tag %s/%s: %v", tagRef.Atespace, tagRef.Name, err)
|
||||
return nil, status.Errorf(codes.InvalidArgument, "while updating tag %s/%s: %v", tagRef.Atespace, tagRef.Name, err)
|
||||
}
|
||||
return nil, fmt.Errorf("while updating actor snapshot tag: %w", err)
|
||||
return nil, fmt.Errorf("while updating tag: %w", err)
|
||||
}
|
||||
return storedTag, nil
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) UpdateActorSnapshotTag(ctx context.Context, tagRef resources.ActorSnapshotTagRef, precondition store.Precondition, mutate func(toUpdate *ateapipb.ActorSnapshotTag) error) (*ateapipb.ActorSnapshotTag, error) {
|
||||
return s.store.UpdateActorSnapshotTag(ctx, tagRef, precondition, func(toUpdate *ateapipb.ActorSnapshotTag) error {
|
||||
func (s *ServiceImpl) UpdateTag(ctx context.Context, tagRef resources.TagRef, precondition store.Precondition, mutate func(toUpdate *ateapipb.Tag) error) (*ateapipb.Tag, error) {
|
||||
return s.store.UpdateTag(ctx, tagRef, precondition, func(toUpdate *ateapipb.Tag) error {
|
||||
// Apply the mutation function to the stored value.
|
||||
oldVal := proto.CloneOf(toUpdate)
|
||||
if err := mutate(toUpdate); err != nil {
|
||||
@@ -205,29 +205,29 @@ func (s *ServiceImpl) UpdateActorSnapshotTag(ctx context.Context, tagRef resourc
|
||||
// Validate the merged tag against the one it replaces. This is where
|
||||
// the rules the request could not be checked against land: scope, and
|
||||
// the immutability of metadata and source_actor.
|
||||
if errs := validateActorSnapshotTagUpdate(ctx, field.NewPath("actor_snapshot_tag"), toUpdate, oldVal); len(errs) > 0 {
|
||||
if errs := validateTagUpdate(ctx, field.NewPath("tag"), toUpdate, oldVal); len(errs) > 0 {
|
||||
return toGRPCStatusError(errs)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func validateUpdateActorSnapshotTagRequest(ctx context.Context, req *ateapipb.UpdateActorSnapshotTagRequest) field.ErrorList {
|
||||
func validateUpdateTagRequest(ctx context.Context, req *ateapipb.UpdateTagRequest) field.ErrorList {
|
||||
// We model this as a create rather than an update because updates assume
|
||||
// the existence of a "current" value, which we do not have yet. This is
|
||||
// validating the request itself. The result will be validated later, after
|
||||
// we have a current value to compare against.
|
||||
op := operation.Operation{Type: operation.Create}
|
||||
return Validate_UpdateActorSnapshotTagRequest(ctx, op, nil, req, nil)
|
||||
return Validate_UpdateTagRequest(ctx, op, nil, req, nil)
|
||||
}
|
||||
|
||||
func validateActorSnapshotTagUpdate(ctx context.Context, fldPath *field.Path, newVal, oldVal *ateapipb.ActorSnapshotTag) field.ErrorList {
|
||||
func validateTagUpdate(ctx context.Context, fldPath *field.Path, newVal, oldVal *ateapipb.Tag) field.ErrorList {
|
||||
op := operation.Operation{Type: operation.Update}
|
||||
return Validate_ActorSnapshotTag(ctx, op, fldPath, newVal, oldVal)
|
||||
return Validate_Tag(ctx, op, fldPath, newVal, oldVal)
|
||||
}
|
||||
|
||||
// This exists only because nested subfield tags are not supported yet.
|
||||
func ValidateCustom_UpdateActorSnapshotTagRequest_ActorSnapshotTag(ctx context.Context, op operation.Operation, fldPath *field.Path, tag, _ *ateapipb.ActorSnapshotTag) field.ErrorList {
|
||||
func ValidateCustom_UpdateTagRequest_Tag(ctx context.Context, op operation.Operation, fldPath *field.Path, tag, _ *ateapipb.Tag) field.ErrorList {
|
||||
if tag == nil || tag.Metadata == nil {
|
||||
return nil // handled by DV
|
||||
}
|
||||
@@ -242,7 +242,7 @@ func ValidateCustom_UpdateActorSnapshotTagRequest_ActorSnapshotTag(ctx context.C
|
||||
return errs
|
||||
}
|
||||
|
||||
// DeleteActorSnapshotTag releases the external snapshot the tag owns and then
|
||||
// DeleteTag releases the external snapshot the tag owns and then
|
||||
// removes the row, in that order: the row is the only handle on that snapshot,
|
||||
// so dropping it first would leak. A failure at any point fails the whole RPC;
|
||||
// the client retries the same delete, which rediscovers the work from the row
|
||||
@@ -255,38 +255,38 @@ func ValidateCustom_UpdateActorSnapshotTagRequest_ActorSnapshotTag(ctx context.C
|
||||
// Note that this destroys the external snapshot: an Actor created from the tag
|
||||
// and never suspended is still borrowing it and becomes unrecoverable. Do not
|
||||
// delete a tag while clones of it exist.
|
||||
func (s *RPCService) DeleteActorSnapshotTag(ctx context.Context, req *ateapipb.DeleteActorSnapshotTagRequest) (*ateapipb.ActorSnapshotTag, error) {
|
||||
func (s *RPCService) DeleteTag(ctx context.Context, req *ateapipb.DeleteTagRequest) (*ateapipb.Tag, error) {
|
||||
// TODO: mode delete orchestration to a workflow.
|
||||
if errs := validateDeleteActorSnapshotTagRequest(ctx, req); len(errs) > 0 {
|
||||
if errs := validateDeleteTagRequest(ctx, req); len(errs) > 0 {
|
||||
return nil, toGRPCStatusError(errs)
|
||||
}
|
||||
tagRef := resources.ActorSnapshotTagRefFromObjectRef(req.GetActorSnapshotTag())
|
||||
tagRef := resources.TagRefFromObjectRef(req.GetTag())
|
||||
|
||||
// Serializes against a create of the same tag, whose copy would otherwise
|
||||
// keep writing into the prefix this is collecting.
|
||||
ctx, lease, err := acquireActorSnapshotTagLease(ctx, s.impl, tagRef)
|
||||
ctx, lease, err := acquireTagLease(ctx, s.impl, tagRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer lease.Close()
|
||||
|
||||
stored, err := s.impl.GetActorSnapshotTag(ctx, tagRef)
|
||||
stored, err := s.impl.GetTag(ctx, tagRef)
|
||||
if err != nil {
|
||||
if errors.Is(err, store.ErrNotFound) {
|
||||
return nil, status.Errorf(codes.NotFound, "ActorSnapshotTag %s/%s not found", tagRef.Atespace, tagRef.Name)
|
||||
return nil, status.Errorf(codes.NotFound, "Tag %s/%s not found", tagRef.Atespace, tagRef.Name)
|
||||
}
|
||||
return nil, fmt.Errorf("while getting actor snapshot tag: %w", err)
|
||||
return nil, fmt.Errorf("while getting tag: %w", err)
|
||||
}
|
||||
if err := s.releaseTagSnapshot(ctx, stored); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tag, err := s.impl.DeleteActorSnapshotTag(ctx, tagRef)
|
||||
tag, err := s.impl.DeleteTag(ctx, tagRef)
|
||||
if errors.Is(err, store.ErrNotFound) {
|
||||
return nil, status.Errorf(codes.NotFound, "ActorSnapshotTag %s/%s not found", tagRef.Atespace, tagRef.Name)
|
||||
return nil, status.Errorf(codes.NotFound, "Tag %s/%s not found", tagRef.Atespace, tagRef.Name)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("while deleting actor snapshot tag: %w", err)
|
||||
return nil, fmt.Errorf("while deleting tag: %w", err)
|
||||
}
|
||||
return tag, nil
|
||||
}
|
||||
@@ -294,7 +294,7 @@ func (s *RPCService) DeleteActorSnapshotTag(ctx context.Context, req *ateapipb.D
|
||||
// releaseTagSnapshot deletes the objects the tag's external snapshot is made
|
||||
// of. It tolerates a partly-collected snapshot, so a retry finishes cleanly.
|
||||
// It collects the in-progress snapshot too.
|
||||
func (s *RPCService) releaseTagSnapshot(ctx context.Context, tag *ateapipb.ActorSnapshotTag) error {
|
||||
func (s *RPCService) releaseTagSnapshot(ctx context.Context, tag *ateapipb.Tag) error {
|
||||
if s.objectStore == nil {
|
||||
return nil
|
||||
}
|
||||
@@ -317,12 +317,12 @@ func (s *RPCService) releaseTagSnapshot(ctx context.Context, tag *ateapipb.Actor
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServiceImpl) DeleteActorSnapshotTag(ctx context.Context, tagRef resources.ActorSnapshotTagRef) (*ateapipb.ActorSnapshotTag, error) {
|
||||
func (s *ServiceImpl) DeleteTag(ctx context.Context, tagRef resources.TagRef) (*ateapipb.Tag, error) {
|
||||
// TODO: implement this
|
||||
return s.store.DeleteActorSnapshotTag(ctx, tagRef)
|
||||
return s.store.DeleteTag(ctx, tagRef)
|
||||
}
|
||||
|
||||
func validateDeleteActorSnapshotTagRequest(ctx context.Context, req *ateapipb.DeleteActorSnapshotTagRequest) field.ErrorList {
|
||||
func validateDeleteTagRequest(ctx context.Context, req *ateapipb.DeleteTagRequest) field.ErrorList {
|
||||
op := operation.Operation{Type: operation.Create}
|
||||
return Validate_DeleteActorSnapshotTagRequest(ctx, op, nil, req, nil)
|
||||
return Validate_DeleteTagRequest(ctx, op, nil, req, nil)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1198,14 +1198,14 @@ func TestValidateNestedExternalSnapshot(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "actor_snapshot_tag.status.snapshot",
|
||||
name: "tag.status.snapshot",
|
||||
path: field.NewPath("status", "snapshot"),
|
||||
validate: func(ctx context.Context) field.ErrorList {
|
||||
op := operation.Operation{Type: operation.Create}
|
||||
obj := validActorSnapshotTag(func(tag *ateapipb.ActorSnapshotTag) {
|
||||
obj := validTag(func(tag *ateapipb.Tag) {
|
||||
tag.Status.Snapshot = badExternalSnapshot()
|
||||
})
|
||||
return Validate_ActorSnapshotTag(ctx, op, nil, obj, nil)
|
||||
return Validate_Tag(ctx, op, nil, obj, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1233,11 +1233,11 @@ func TestValidateNestedExternalSnapshot(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func validActorSnapshotTag(mutate ...func(*ateapipb.ActorSnapshotTag)) *ateapipb.ActorSnapshotTag {
|
||||
tag := &ateapipb.ActorSnapshotTag{
|
||||
func validTag(mutate ...func(*ateapipb.Tag)) *ateapipb.Tag {
|
||||
tag := &ateapipb.Tag{
|
||||
Metadata: validResourceMetadata(),
|
||||
Status: &ateapipb.ActorSnapshotTagStatus{Snapshot: validExternalSnapshot()},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE,
|
||||
Status: &ateapipb.TagStatus{Snapshot: validExternalSnapshot()},
|
||||
Scope: ateapipb.TagScope_TAG_SCOPE_ATESPACE,
|
||||
SourceActor: &ateapipb.ObjectRef{Atespace: "as", Name: "nm"},
|
||||
}
|
||||
for _, m := range mutate {
|
||||
@@ -1246,15 +1246,15 @@ func validActorSnapshotTag(mutate ...func(*ateapipb.ActorSnapshotTag)) *ateapipb
|
||||
return tag
|
||||
}
|
||||
|
||||
func TestValidateActorSnapshotTag(t *testing.T) {
|
||||
valid := validActorSnapshotTag
|
||||
func TestValidateTag(t *testing.T) {
|
||||
valid := validTag
|
||||
metadataPath := field.NewPath("metadata")
|
||||
scopePath := field.NewPath("scope")
|
||||
sourceActorPath := field.NewPath("source_actor")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
obj *ateapipb.ActorSnapshotTag
|
||||
obj *ateapipb.Tag
|
||||
want field.ErrorList
|
||||
}{
|
||||
{
|
||||
@@ -1263,74 +1263,74 @@ func TestValidateActorSnapshotTag(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "valid scope: published",
|
||||
obj: valid(func(tag *ateapipb.ActorSnapshotTag) {
|
||||
tag.Scope = ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED
|
||||
obj: valid(func(tag *ateapipb.Tag) {
|
||||
tag.Scope = ateapipb.TagScope_TAG_SCOPE_PUBLISHED
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "missing status",
|
||||
obj: valid(func(tag *ateapipb.ActorSnapshotTag) { tag.Status = nil }),
|
||||
obj: valid(func(tag *ateapipb.Tag) { tag.Status = nil }),
|
||||
},
|
||||
{
|
||||
name: "missing metadata",
|
||||
obj: valid(func(tag *ateapipb.ActorSnapshotTag) { tag.Metadata = nil }),
|
||||
obj: valid(func(tag *ateapipb.Tag) { tag.Metadata = nil }),
|
||||
want: field.ErrorList{field.Required(metadataPath, "")},
|
||||
},
|
||||
{
|
||||
// A tag is addressed through the atespace that owns it, so unlike a
|
||||
// global-scoped resource it always has to name one.
|
||||
name: "missing metadata.atespace",
|
||||
obj: valid(func(tag *ateapipb.ActorSnapshotTag) { tag.Metadata.Atespace = "" }),
|
||||
obj: valid(func(tag *ateapipb.Tag) { tag.Metadata.Atespace = "" }),
|
||||
want: field.ErrorList{field.Required(metadataPath.Child("atespace"), "")},
|
||||
},
|
||||
{
|
||||
name: "invalid nested metadata.name",
|
||||
obj: valid(func(tag *ateapipb.ActorSnapshotTag) { tag.Metadata.Name = "" }),
|
||||
obj: valid(func(tag *ateapipb.Tag) { tag.Metadata.Name = "" }),
|
||||
want: field.ErrorList{field.Required(metadataPath.Child("name"), "")},
|
||||
},
|
||||
{
|
||||
name: "unspecified scope",
|
||||
obj: valid(func(tag *ateapipb.ActorSnapshotTag) {
|
||||
tag.Scope = ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED
|
||||
obj: valid(func(tag *ateapipb.Tag) {
|
||||
tag.Scope = ateapipb.TagScope_TAG_SCOPE_UNSPECIFIED
|
||||
}),
|
||||
want: field.ErrorList{field.Required(scopePath, "")},
|
||||
},
|
||||
{
|
||||
name: "scope above the enum",
|
||||
obj: valid(func(tag *ateapipb.ActorSnapshotTag) { tag.Scope = ateapipb.ActorSnapshotTagScope(3) }),
|
||||
obj: valid(func(tag *ateapipb.Tag) { tag.Scope = ateapipb.TagScope(3) }),
|
||||
want: field.ErrorList{field.Invalid(scopePath, nil, "").WithOrigin("maximum")},
|
||||
},
|
||||
{
|
||||
name: "negative scope",
|
||||
obj: valid(func(tag *ateapipb.ActorSnapshotTag) { tag.Scope = ateapipb.ActorSnapshotTagScope(-1) }),
|
||||
obj: valid(func(tag *ateapipb.Tag) { tag.Scope = ateapipb.TagScope(-1) }),
|
||||
want: field.ErrorList{field.Invalid(scopePath, nil, "").WithOrigin("minimum")},
|
||||
},
|
||||
{
|
||||
name: "missing source_actor",
|
||||
obj: valid(func(tag *ateapipb.ActorSnapshotTag) { tag.SourceActor = nil }),
|
||||
obj: valid(func(tag *ateapipb.Tag) { tag.SourceActor = nil }),
|
||||
want: field.ErrorList{field.Required(sourceActorPath, "")},
|
||||
},
|
||||
{
|
||||
name: "missing source_actor.atespace",
|
||||
obj: valid(func(tag *ateapipb.ActorSnapshotTag) { tag.SourceActor.Atespace = "" }),
|
||||
obj: valid(func(tag *ateapipb.Tag) { tag.SourceActor.Atespace = "" }),
|
||||
want: field.ErrorList{field.Required(sourceActorPath.Child("atespace"), "")},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
op := operation.Operation{Type: operation.Create}
|
||||
assertValidateErr(t, Validate_ActorSnapshotTag(context.Background(), op, nil, tt.obj, nil), tt.want)
|
||||
assertValidateErr(t, Validate_Tag(context.Background(), op, nil, tt.obj, nil), tt.want)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateActorSnapshotTagUpdate(t *testing.T) {
|
||||
valid := validActorSnapshotTag
|
||||
func TestValidateTagUpdate(t *testing.T) {
|
||||
valid := validTag
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
oldObj *ateapipb.ActorSnapshotTag // should always be valid
|
||||
newObj *ateapipb.ActorSnapshotTag
|
||||
oldObj *ateapipb.Tag // should always be valid
|
||||
newObj *ateapipb.Tag
|
||||
want field.ErrorList
|
||||
}{
|
||||
{
|
||||
@@ -1343,39 +1343,39 @@ func TestValidateActorSnapshotTagUpdate(t *testing.T) {
|
||||
// every reference to it.
|
||||
name: "metadata.atespace changed",
|
||||
oldObj: valid(),
|
||||
newObj: valid(func(tag *ateapipb.ActorSnapshotTag) { tag.Metadata.Atespace = "other" }),
|
||||
newObj: valid(func(tag *ateapipb.Tag) { tag.Metadata.Atespace = "other" }),
|
||||
want: field.ErrorList{field.Invalid(field.NewPath("metadata", "atespace"), nil, "").WithOrigin("immutable")},
|
||||
},
|
||||
{
|
||||
name: "source_actor changed",
|
||||
oldObj: valid(),
|
||||
newObj: valid(func(tag *ateapipb.ActorSnapshotTag) { tag.SourceActor.Name = "other" }),
|
||||
newObj: valid(func(tag *ateapipb.Tag) { tag.SourceActor.Name = "other" }),
|
||||
want: field.ErrorList{field.Invalid(field.NewPath("source_actor"), nil, "").WithOrigin("immutable")},
|
||||
},
|
||||
{
|
||||
name: "scope changed",
|
||||
oldObj: valid(),
|
||||
newObj: valid(func(tag *ateapipb.ActorSnapshotTag) {
|
||||
tag.Scope = ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED
|
||||
newObj: valid(func(tag *ateapipb.Tag) {
|
||||
tag.Scope = ateapipb.TagScope_TAG_SCOPE_PUBLISHED
|
||||
}),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
op := operation.Operation{Type: operation.Update}
|
||||
assertValidateErr(t, Validate_ActorSnapshotTag(context.Background(), op, nil, tt.newObj, tt.oldObj), tt.want)
|
||||
assertValidateErr(t, Validate_Tag(context.Background(), op, nil, tt.newObj, tt.oldObj), tt.want)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestValidateActorSnapshotTagRequestPayloads covers the generated rules on the
|
||||
// TestValidateTagRequestPayloads covers the generated rules on the
|
||||
// tag requests. The RPCs call these directly (see
|
||||
// validateCreateActorSnapshotTagRequest), so these guard the schema against
|
||||
// drift; actor_snapshot_tag_test.go covers what the handlers make of it.
|
||||
func TestValidateActorSnapshotTagRequestPayloads(t *testing.T) {
|
||||
validTag := validActorSnapshotTag
|
||||
// validateCreateTagRequest), so these guard the schema against
|
||||
// drift; tag_test.go covers what the handlers make of it.
|
||||
func TestValidateTagRequestPayloads(t *testing.T) {
|
||||
validTag := validTag
|
||||
validRef := func() *ateapipb.ObjectRef { return &ateapipb.ObjectRef{Atespace: "as", Name: "nm"} }
|
||||
tagPath := field.NewPath("actor_snapshot_tag")
|
||||
tagPath := field.NewPath("tag")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -1385,15 +1385,15 @@ func TestValidateActorSnapshotTagRequestPayloads(t *testing.T) {
|
||||
{
|
||||
name: "create: valid",
|
||||
validate: func(ctx context.Context, op operation.Operation) field.ErrorList {
|
||||
req := &ateapipb.CreateActorSnapshotTagRequest{ActorSnapshotTag: validTag()}
|
||||
return Validate_CreateActorSnapshotTagRequest(ctx, op, nil, req, nil)
|
||||
req := &ateapipb.CreateTagRequest{Tag: validTag()}
|
||||
return Validate_CreateTagRequest(ctx, op, nil, req, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "create: missing actor_snapshot_tag",
|
||||
name: "create: missing tag",
|
||||
validate: func(ctx context.Context, op operation.Operation) field.ErrorList {
|
||||
req := &ateapipb.CreateActorSnapshotTagRequest{}
|
||||
return Validate_CreateActorSnapshotTagRequest(ctx, op, nil, req, nil)
|
||||
req := &ateapipb.CreateTagRequest{}
|
||||
return Validate_CreateTagRequest(ctx, op, nil, req, nil)
|
||||
},
|
||||
want: field.ErrorList{field.Required(tagPath, "")},
|
||||
},
|
||||
@@ -1402,8 +1402,8 @@ func TestValidateActorSnapshotTagRequestPayloads(t *testing.T) {
|
||||
validate: func(ctx context.Context, op operation.Operation) field.ErrorList {
|
||||
tag := validTag()
|
||||
tag.Status.Snapshot = badExternalSnapshot()
|
||||
req := &ateapipb.CreateActorSnapshotTagRequest{ActorSnapshotTag: tag}
|
||||
return Validate_CreateActorSnapshotTagRequest(ctx, op, nil, req, nil)
|
||||
req := &ateapipb.CreateTagRequest{Tag: tag}
|
||||
return Validate_CreateTagRequest(ctx, op, nil, req, nil)
|
||||
},
|
||||
want: field.ErrorList{
|
||||
field.Required(tagPath.Child("status", "snapshot", "snapshot_uri"), ""),
|
||||
@@ -1413,15 +1413,15 @@ func TestValidateActorSnapshotTagRequestPayloads(t *testing.T) {
|
||||
{
|
||||
name: "update: valid",
|
||||
validate: func(ctx context.Context, op operation.Operation) field.ErrorList {
|
||||
req := &ateapipb.UpdateActorSnapshotTagRequest{ActorSnapshotTag: validTag()}
|
||||
return Validate_UpdateActorSnapshotTagRequest(ctx, op, nil, req, nil)
|
||||
req := &ateapipb.UpdateTagRequest{Tag: validTag()}
|
||||
return Validate_UpdateTagRequest(ctx, op, nil, req, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "update: missing actor_snapshot_tag",
|
||||
name: "update: missing tag",
|
||||
validate: func(ctx context.Context, op operation.Operation) field.ErrorList {
|
||||
req := &ateapipb.UpdateActorSnapshotTagRequest{}
|
||||
return Validate_UpdateActorSnapshotTagRequest(ctx, op, nil, req, nil)
|
||||
req := &ateapipb.UpdateTagRequest{}
|
||||
return Validate_UpdateTagRequest(ctx, op, nil, req, nil)
|
||||
},
|
||||
want: field.ErrorList{field.Required(tagPath, "")},
|
||||
},
|
||||
@@ -1432,63 +1432,63 @@ func TestValidateActorSnapshotTagRequestPayloads(t *testing.T) {
|
||||
validate: func(ctx context.Context, op operation.Operation) field.ErrorList {
|
||||
tag := validTag()
|
||||
tag.Status.Snapshot = badExternalSnapshot()
|
||||
req := &ateapipb.UpdateActorSnapshotTagRequest{ActorSnapshotTag: tag}
|
||||
return Validate_UpdateActorSnapshotTagRequest(ctx, op, nil, req, nil)
|
||||
req := &ateapipb.UpdateTagRequest{Tag: tag}
|
||||
return Validate_UpdateTagRequest(ctx, op, nil, req, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "get: valid",
|
||||
validate: func(ctx context.Context, op operation.Operation) field.ErrorList {
|
||||
req := &ateapipb.GetActorSnapshotTagRequest{ActorSnapshotTag: validRef()}
|
||||
return Validate_GetActorSnapshotTagRequest(ctx, op, nil, req, nil)
|
||||
req := &ateapipb.GetTagRequest{Tag: validRef()}
|
||||
return Validate_GetTagRequest(ctx, op, nil, req, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "get: missing actor_snapshot_tag",
|
||||
name: "get: missing tag",
|
||||
validate: func(ctx context.Context, op operation.Operation) field.ErrorList {
|
||||
req := &ateapipb.GetActorSnapshotTagRequest{}
|
||||
return Validate_GetActorSnapshotTagRequest(ctx, op, nil, req, nil)
|
||||
req := &ateapipb.GetTagRequest{}
|
||||
return Validate_GetTagRequest(ctx, op, nil, req, nil)
|
||||
},
|
||||
want: field.ErrorList{field.Required(tagPath, "")},
|
||||
},
|
||||
{
|
||||
// A tag is addressed through the atespace that owns it, so a ref
|
||||
// naming only a name does not name a tag.
|
||||
name: "get: missing actor_snapshot_tag.atespace",
|
||||
name: "get: missing tag.atespace",
|
||||
validate: func(ctx context.Context, op operation.Operation) field.ErrorList {
|
||||
req := &ateapipb.GetActorSnapshotTagRequest{ActorSnapshotTag: &ateapipb.ObjectRef{Name: "nm"}}
|
||||
return Validate_GetActorSnapshotTagRequest(ctx, op, nil, req, nil)
|
||||
req := &ateapipb.GetTagRequest{Tag: &ateapipb.ObjectRef{Name: "nm"}}
|
||||
return Validate_GetTagRequest(ctx, op, nil, req, nil)
|
||||
},
|
||||
want: field.ErrorList{field.Required(tagPath.Child("atespace"), "")},
|
||||
},
|
||||
{
|
||||
name: "get: invalid actor_snapshot_tag.name",
|
||||
name: "get: invalid tag.name",
|
||||
validate: func(ctx context.Context, op operation.Operation) field.ErrorList {
|
||||
req := &ateapipb.GetActorSnapshotTagRequest{ActorSnapshotTag: &ateapipb.ObjectRef{Atespace: "as", Name: "NM"}}
|
||||
return Validate_GetActorSnapshotTagRequest(ctx, op, nil, req, nil)
|
||||
req := &ateapipb.GetTagRequest{Tag: &ateapipb.ObjectRef{Atespace: "as", Name: "NM"}}
|
||||
return Validate_GetTagRequest(ctx, op, nil, req, nil)
|
||||
},
|
||||
want: field.ErrorList{field.Invalid(tagPath.Child("name"), nil, "").WithOrigin("format=k8s-short-name")},
|
||||
},
|
||||
{
|
||||
name: "delete: valid",
|
||||
validate: func(ctx context.Context, op operation.Operation) field.ErrorList {
|
||||
req := &ateapipb.DeleteActorSnapshotTagRequest{ActorSnapshotTag: validRef()}
|
||||
return Validate_DeleteActorSnapshotTagRequest(ctx, op, nil, req, nil)
|
||||
req := &ateapipb.DeleteTagRequest{Tag: validRef()}
|
||||
return Validate_DeleteTagRequest(ctx, op, nil, req, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "delete: missing actor_snapshot_tag",
|
||||
name: "delete: missing tag",
|
||||
validate: func(ctx context.Context, op operation.Operation) field.ErrorList {
|
||||
req := &ateapipb.DeleteActorSnapshotTagRequest{}
|
||||
return Validate_DeleteActorSnapshotTagRequest(ctx, op, nil, req, nil)
|
||||
req := &ateapipb.DeleteTagRequest{}
|
||||
return Validate_DeleteTagRequest(ctx, op, nil, req, nil)
|
||||
},
|
||||
want: field.ErrorList{field.Required(tagPath, "")},
|
||||
},
|
||||
{
|
||||
name: "delete: missing actor_snapshot_tag.atespace",
|
||||
name: "delete: missing tag.atespace",
|
||||
validate: func(ctx context.Context, op operation.Operation) field.ErrorList {
|
||||
req := &ateapipb.DeleteActorSnapshotTagRequest{ActorSnapshotTag: &ateapipb.ObjectRef{Name: "nm"}}
|
||||
return Validate_DeleteActorSnapshotTagRequest(ctx, op, nil, req, nil)
|
||||
req := &ateapipb.DeleteTagRequest{Tag: &ateapipb.ObjectRef{Name: "nm"}}
|
||||
return Validate_DeleteTagRequest(ctx, op, nil, req, nil)
|
||||
},
|
||||
want: field.ErrorList{field.Required(tagPath.Child("atespace"), "")},
|
||||
},
|
||||
@@ -1497,31 +1497,31 @@ func TestValidateActorSnapshotTagRequestPayloads(t *testing.T) {
|
||||
// how a client asks for every atespace at once.
|
||||
name: "list: empty request",
|
||||
validate: func(ctx context.Context, op operation.Operation) field.ErrorList {
|
||||
req := &ateapipb.ListActorSnapshotTagsRequest{}
|
||||
return Validate_ListActorSnapshotTagsRequest(ctx, op, nil, req, nil)
|
||||
req := &ateapipb.ListTagsRequest{}
|
||||
return Validate_ListTagsRequest(ctx, op, nil, req, nil)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "list: invalid atespace",
|
||||
validate: func(ctx context.Context, op operation.Operation) field.ErrorList {
|
||||
req := &ateapipb.ListActorSnapshotTagsRequest{Atespace: "AS"}
|
||||
return Validate_ListActorSnapshotTagsRequest(ctx, op, nil, req, nil)
|
||||
req := &ateapipb.ListTagsRequest{Atespace: "AS"}
|
||||
return Validate_ListTagsRequest(ctx, op, nil, req, nil)
|
||||
},
|
||||
want: field.ErrorList{field.Invalid(field.NewPath("atespace"), nil, "").WithOrigin("format=k8s-short-name")},
|
||||
},
|
||||
{
|
||||
name: "list: negative page_size",
|
||||
validate: func(ctx context.Context, op operation.Operation) field.ErrorList {
|
||||
req := &ateapipb.ListActorSnapshotTagsRequest{PageSize: -1}
|
||||
return Validate_ListActorSnapshotTagsRequest(ctx, op, nil, req, nil)
|
||||
req := &ateapipb.ListTagsRequest{PageSize: -1}
|
||||
return Validate_ListTagsRequest(ctx, op, nil, req, nil)
|
||||
},
|
||||
want: field.ErrorList{field.Invalid(field.NewPath("page_size"), nil, "").WithOrigin("minimum")},
|
||||
},
|
||||
{
|
||||
name: "list: over-long page_token",
|
||||
validate: func(ctx context.Context, op operation.Operation) field.ErrorList {
|
||||
req := &ateapipb.ListActorSnapshotTagsRequest{PageToken: strings.Repeat("t", 257)}
|
||||
return Validate_ListActorSnapshotTagsRequest(ctx, op, nil, req, nil)
|
||||
req := &ateapipb.ListTagsRequest{PageToken: strings.Repeat("t", 257)}
|
||||
return Validate_ListTagsRequest(ctx, op, nil, req, nil)
|
||||
},
|
||||
want: field.ErrorList{field.TooLong(field.NewPath("page_token"), nil, 256).WithOrigin("maxLength")},
|
||||
},
|
||||
|
||||
@@ -126,9 +126,9 @@ type actorWorkflowStore interface {
|
||||
// Read from the records rather than the Worker's status: only the service
|
||||
// layer attaches assignments on read, and this workflow holds the store.
|
||||
ListWorkerAssignments(ctx context.Context, workerName string, opts store.ListOptions) (store.ListResponse[*ateapipb.ActorAssignment], error)
|
||||
CreateActorSnapshotTag(ctx context.Context, tag *ateapipb.ActorSnapshotTag) (*ateapipb.ActorSnapshotTag, error)
|
||||
GetActorSnapshotTag(ctx context.Context, tagRef resources.ActorSnapshotTagRef) (*ateapipb.ActorSnapshotTag, error)
|
||||
UpdateActorSnapshotTag(ctx context.Context, tagRef resources.ActorSnapshotTagRef, precondition store.Precondition, mutate func(toUpdate *ateapipb.ActorSnapshotTag) error) (*ateapipb.ActorSnapshotTag, error)
|
||||
CreateTag(ctx context.Context, tag *ateapipb.Tag) (*ateapipb.Tag, error)
|
||||
GetTag(ctx context.Context, tagRef resources.TagRef) (*ateapipb.Tag, error)
|
||||
UpdateTag(ctx context.Context, tagRef resources.TagRef, precondition store.Precondition, mutate func(toUpdate *ateapipb.Tag) error) (*ateapipb.Tag, error)
|
||||
GetActorTemplate(ctx context.Context, templateRef resources.ActorTemplateRef) (*ateapipb.ActorTemplate, error)
|
||||
AcquireLease(ctx context.Context, key string) (*store.Lease, error)
|
||||
}
|
||||
@@ -183,6 +183,6 @@ func (w *ActorWorkflow) acquireActorLease(ctx context.Context, actorRef resource
|
||||
return acquireLease(ctx, w.store, "lease:actor:"+actorRef.Atespace+":"+actorRef.Name, "actor")
|
||||
}
|
||||
|
||||
func acquireActorSnapshotTagLease(ctx context.Context, holder leaseHolder, tagRef resources.ActorSnapshotTagRef) (context.Context, *store.Lease, error) {
|
||||
return acquireLease(ctx, holder, "lease:actor-snapshot-tag:"+tagRef.Atespace+":"+tagRef.Name, "ActorSnapshotTag")
|
||||
func acquireTagLease(ctx context.Context, holder leaseHolder, tagRef resources.TagRef) (context.Context, *store.Lease, error) {
|
||||
return acquireLease(ctx, holder, "lease:tag:"+tagRef.Atespace+":"+tagRef.Name, "Tag")
|
||||
}
|
||||
|
||||
@@ -441,9 +441,9 @@ func (c *conflictInjectingStore) UpdateActor(ctx context.Context, actorRef resou
|
||||
return c.Interface.UpdateActor(ctx, actorRef, precondition, mutate)
|
||||
}
|
||||
|
||||
func (c *conflictInjectingStore) UpdateActorSnapshotTag(ctx context.Context, tagRef resources.ActorSnapshotTagRef, precondition store.Precondition, mutate func(*ateapipb.ActorSnapshotTag) error) (*ateapipb.ActorSnapshotTag, error) {
|
||||
func (c *conflictInjectingStore) UpdateTag(ctx context.Context, tagRef resources.TagRef, precondition store.Precondition, mutate func(*ateapipb.Tag) error) (*ateapipb.Tag, error) {
|
||||
c.once.Do(c.inject)
|
||||
return c.Interface.UpdateActorSnapshotTag(ctx, tagRef, precondition, mutate)
|
||||
return c.Interface.UpdateTag(ctx, tagRef, precondition, mutate)
|
||||
}
|
||||
|
||||
// seedAssignFixture stores one free gvisor worker and a SUSPENDED actor and
|
||||
|
||||
+18
-18
@@ -46,7 +46,7 @@ import (
|
||||
// dies after it leaves a pending tag and every later create under that name is
|
||||
// AlreadyExists. To retry, delete the tag, which collects whatever the failed
|
||||
// attempt stranded, and create it again.
|
||||
func (w *ActorWorkflow) TagActorSnapshot(ctx context.Context, tag *ateapipb.ActorSnapshotTag) (*ateapipb.ActorSnapshotTag, error) {
|
||||
func (w *ActorWorkflow) TagActorSnapshot(ctx context.Context, tag *ateapipb.Tag) (*ateapipb.Tag, error) {
|
||||
actorRef := resources.ActorRefFromObjectRef(tag.GetSourceActor())
|
||||
|
||||
// Serializes against a suspend of the same actor, which would otherwise
|
||||
@@ -59,8 +59,8 @@ func (w *ActorWorkflow) TagActorSnapshot(ctx context.Context, tag *ateapipb.Acto
|
||||
|
||||
// Serializes against a delete of the tag this creates, which would
|
||||
// otherwise collect the copy while it is being written.
|
||||
tagRef := resources.ActorSnapshotTagRef{Atespace: actorRef.Atespace, Name: tag.GetMetadata().GetName()}
|
||||
leaseCtx, tagLease, err := acquireActorSnapshotTagLease(leaseCtx, w.store, tagRef)
|
||||
tagRef := resources.TagRef{Atespace: actorRef.Atespace, Name: tag.GetMetadata().GetName()}
|
||||
leaseCtx, tagLease, err := acquireTagLease(leaseCtx, w.store, tagRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -123,19 +123,19 @@ func (w *ActorWorkflow) loadActorForTag(ctx context.Context, actorRef resources.
|
||||
// deciding whether the objects under it still belong to the snapshot being
|
||||
// tagged, and the row may not even be this actor's; deleting the tag collects
|
||||
// them and frees the name, so a retry is a delete followed by a create.
|
||||
func (w *ActorWorkflow) ensureTagReserved(ctx context.Context, tagRef resources.ActorSnapshotTagRef, actor *ateapipb.Actor, actorTemplate *ateapipb.ActorTemplate, tag *ateapipb.ActorSnapshotTag) (_ *ateapipb.ActorSnapshotTag, err error) {
|
||||
ctx, done := stepSpan(ctx, "ReserveSnapshotTag")
|
||||
func (w *ActorWorkflow) ensureTagReserved(ctx context.Context, tagRef resources.TagRef, actor *ateapipb.Actor, actorTemplate *ateapipb.ActorTemplate, tag *ateapipb.Tag) (_ *ateapipb.Tag, err error) {
|
||||
ctx, done := stepSpan(ctx, "ReserveTag")
|
||||
defer func() { err = done(err) }()
|
||||
|
||||
dst, err := resources.NewTagSnapshotURI(actorTemplate.GetSnapshotsConfig().GetStorageLocation(), tagRef.Atespace, resources.NewSnapshotName())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("while building the snapshot URI for tag %s: %w", tagRef, err)
|
||||
}
|
||||
tagToCreate := &ateapipb.ActorSnapshotTag{
|
||||
tagToCreate := &ateapipb.Tag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: tagRef.Atespace, Name: tagRef.Name},
|
||||
Scope: tag.GetScope(),
|
||||
SourceActor: resources.ActorRefFromActor(actor).ToObjectRef(),
|
||||
Status: &ateapipb.ActorSnapshotTagStatus{
|
||||
Status: &ateapipb.TagStatus{
|
||||
// The tag records the template the snapshot's guest state was built under, not
|
||||
// the one the actor currently points at. A suspended actor can be repointed,
|
||||
// and a tag that claimed the new template would hand clones the old template's
|
||||
@@ -147,23 +147,23 @@ func (w *ActorWorkflow) ensureTagReserved(ctx context.Context, tagRef resources.
|
||||
},
|
||||
}
|
||||
|
||||
stored, err := w.store.CreateActorSnapshotTag(ctx, tagToCreate)
|
||||
stored, err := w.store.CreateTag(ctx, tagToCreate)
|
||||
switch {
|
||||
case err == nil:
|
||||
return stored, nil
|
||||
case errors.Is(err, store.ErrFailedPrecondition):
|
||||
return nil, status.Errorf(codes.FailedPrecondition, "Atespace %s not found", tagRef.Atespace)
|
||||
case errors.Is(err, store.ErrAlreadyExists):
|
||||
return nil, status.Errorf(codes.AlreadyExists, "ActorSnapshotTag %s already exists; delete it and create it again to retry", tagRef)
|
||||
return nil, status.Errorf(codes.AlreadyExists, "Tag %s already exists; delete it and create it again to retry", tagRef)
|
||||
}
|
||||
return nil, fmt.Errorf("while reserving actor snapshot tag %s: %w", tagRef, err)
|
||||
return nil, fmt.Errorf("while reserving tag %s: %w", tagRef, err)
|
||||
}
|
||||
|
||||
// ensureTagSnapshotCopied copies the actor's external snapshot to the tag's own
|
||||
// prefix, the one the reserved row names. That prefix is freshly minted, so it
|
||||
// is empty by construction and the copy never blends with objects some other
|
||||
// attempt left.
|
||||
func (w *ActorWorkflow) ensureTagSnapshotCopied(ctx context.Context, tag *ateapipb.ActorSnapshotTag, snapshot *ateapipb.ExternalSnapshot) (err error) {
|
||||
func (w *ActorWorkflow) ensureTagSnapshotCopied(ctx context.Context, tag *ateapipb.Tag, snapshot *ateapipb.ExternalSnapshot) (err error) {
|
||||
ctx, done := stepSpan(ctx, "CopyTagSnapshot")
|
||||
defer func() { err = done(err) }()
|
||||
|
||||
@@ -171,7 +171,7 @@ func (w *ActorWorkflow) ensureTagSnapshotCopied(ctx context.Context, tag *ateapi
|
||||
markSkipped(ctx, "no object store configured")
|
||||
return nil
|
||||
}
|
||||
tagRef := resources.ActorSnapshotTagRefFromActorSnapshotTag(tag)
|
||||
tagRef := resources.TagRefFromTag(tag)
|
||||
src, err := resources.ParseSnapshotURI(snapshot.GetSnapshotUri())
|
||||
if err != nil {
|
||||
return fmt.Errorf("while parsing the external snapshot %q of the source actor: %w", snapshot.GetSnapshotUri(), err)
|
||||
@@ -190,17 +190,17 @@ func (w *ActorWorkflow) ensureTagSnapshotCopied(ctx context.Context, tag *ateapi
|
||||
// row already names and clears status.in_progress_snapshot_uri. Until this
|
||||
// lands the tag is pending — visible, unusable, and naming exactly the objects
|
||||
// an unfinished create stranded, so deleting it collects them.
|
||||
func (w *ActorWorkflow) ensureTagFinalized(ctx context.Context, tag *ateapipb.ActorSnapshotTag, snapshot *ateapipb.ExternalSnapshot) (_ *ateapipb.ActorSnapshotTag, err error) {
|
||||
ctx, done := stepSpan(ctx, "FinalizeSnapshotTag")
|
||||
func (w *ActorWorkflow) ensureTagFinalized(ctx context.Context, tag *ateapipb.Tag, snapshot *ateapipb.ExternalSnapshot) (_ *ateapipb.Tag, err error) {
|
||||
ctx, done := stepSpan(ctx, "FinalizeTag")
|
||||
defer func() { err = done(err) }()
|
||||
|
||||
tagRef := resources.ActorSnapshotTagRefFromActorSnapshotTag(tag)
|
||||
tagRef := resources.TagRefFromTag(tag)
|
||||
// The copy is byte-identical to the source, so it carries the same content.
|
||||
finalSnapshot := &ateapipb.ExternalSnapshot{
|
||||
SnapshotUri: tag.GetStatus().GetInProgressSnapshotUri(),
|
||||
ContentScope: snapshot.GetContentScope(),
|
||||
}
|
||||
stored, err := w.store.UpdateActorSnapshotTag(ctx, tagRef, store.PreconditionFrom(tag), func(toUpdate *ateapipb.ActorSnapshotTag) error {
|
||||
stored, err := w.store.UpdateTag(ctx, tagRef, store.PreconditionFrom(tag), func(toUpdate *ateapipb.Tag) error {
|
||||
toUpdate.Status.Snapshot = finalSnapshot
|
||||
toUpdate.Status.InProgressSnapshotUri = ""
|
||||
return nil
|
||||
@@ -210,9 +210,9 @@ func (w *ActorWorkflow) ensureTagFinalized(ctx context.Context, tag *ateapipb.Ac
|
||||
return nil, status.Error(codes.Aborted, "concurrent update conflict, please retry")
|
||||
}
|
||||
if errors.Is(err, store.ErrNotFound) || errors.Is(err, store.ErrUIDConflict) {
|
||||
return nil, status.Errorf(codes.Aborted, "ActorSnapshotTag %s was deleted while it was being created, please retry", tagRef)
|
||||
return nil, status.Errorf(codes.Aborted, "Tag %s was deleted while it was being created, please retry", tagRef)
|
||||
}
|
||||
return nil, fmt.Errorf("while finalizing actor snapshot tag %s: %w", tagRef, err)
|
||||
return nil, fmt.Errorf("while finalizing tag %s: %w", tagRef, err)
|
||||
}
|
||||
return stored, nil
|
||||
}
|
||||
+25
-25
@@ -50,11 +50,11 @@ func seedTagSource(t *testing.T, ctx context.Context, persistence store.Interfac
|
||||
return actor, uri
|
||||
}
|
||||
|
||||
// tagToCreate is the part of an ActorSnapshotTag a client owns on create.
|
||||
func tagToCreate(sourceActor resources.ActorRef, name string) *ateapipb.ActorSnapshotTag {
|
||||
return &ateapipb.ActorSnapshotTag{
|
||||
// tagToCreate is the part of a Tag a client owns on create.
|
||||
func tagToCreate(sourceActor resources.ActorRef, name string) *ateapipb.Tag {
|
||||
return &ateapipb.Tag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Name: name},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE,
|
||||
Scope: ateapipb.TagScope_TAG_SCOPE_ATESPACE,
|
||||
SourceActor: sourceActor.ToObjectRef(),
|
||||
}
|
||||
}
|
||||
@@ -209,8 +209,8 @@ func TestTagActorSnapshot_Preconditions(t *testing.T) {
|
||||
t.Fatalf("TagActorSnapshot error = %v (code %v), want code %v", err, code, tt.wantCode)
|
||||
}
|
||||
// A rejected create takes the name with it.
|
||||
if _, err := persistence.GetActorSnapshotTag(ctx, resources.ActorSnapshotTagRef{Atespace: "team-a", Name: "v1"}); !errors.Is(err, store.ErrNotFound) {
|
||||
t.Errorf("GetActorSnapshotTag = %v, want ErrNotFound: the rejected create reserved the name", err)
|
||||
if _, err := persistence.GetTag(ctx, resources.TagRef{Atespace: "team-a", Name: "v1"}); !errors.Is(err, store.ErrNotFound) {
|
||||
t.Errorf("GetTag = %v, want ErrNotFound: the rejected create reserved the name", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -230,7 +230,7 @@ func TestTagActorSnapshot_RecreateAfterCopyFailure(t *testing.T) {
|
||||
|
||||
actor, _ := seedTagSource(t, ctx, persistence, objects, template, "actor-1", "manifest.json", "memory.zst")
|
||||
actorRef := resources.ActorRefFromActor(actor)
|
||||
tagRef := resources.ActorSnapshotTagRef{Atespace: "team-a", Name: "v1"}
|
||||
tagRef := resources.TagRef{Atespace: "team-a", Name: "v1"}
|
||||
|
||||
// The copy dies halfway through: the first object lands, the second does not.
|
||||
objects.OnCopy = func(_, srcObject, _, _ string) error {
|
||||
@@ -244,9 +244,9 @@ func TestTagActorSnapshot_RecreateAfterCopyFailure(t *testing.T) {
|
||||
}
|
||||
objects.OnCopy = nil
|
||||
|
||||
pending, err := persistence.GetActorSnapshotTag(ctx, tagRef)
|
||||
pending, err := persistence.GetTag(ctx, tagRef)
|
||||
if err != nil {
|
||||
t.Fatalf("GetActorSnapshotTag after the external store failure: %v", err)
|
||||
t.Fatalf("GetTag after the external store failure: %v", err)
|
||||
}
|
||||
if got := pending.GetStatus().GetSnapshot().GetSnapshotUri(); got != "" {
|
||||
t.Errorf("snapshot uri after the failure = %q, want unset: the copy never finished", got)
|
||||
@@ -266,9 +266,9 @@ func TestTagActorSnapshot_RecreateAfterCopyFailure(t *testing.T) {
|
||||
if code := status.Code(err); code != codes.AlreadyExists {
|
||||
t.Fatalf("TagActorSnapshot over the pending tag = %v (code %v), want code AlreadyExists", err, code)
|
||||
}
|
||||
stillPending, err := persistence.GetActorSnapshotTag(ctx, tagRef)
|
||||
stillPending, err := persistence.GetTag(ctx, tagRef)
|
||||
if err != nil {
|
||||
t.Fatalf("GetActorSnapshotTag after the refused create: %v", err)
|
||||
t.Fatalf("GetTag after the refused create: %v", err)
|
||||
}
|
||||
if got := stillPending.GetStatus().GetInProgressSnapshotUri(); got != stranded {
|
||||
t.Errorf("in-progress snapshot uri after the refused create = %q, want the prefix the row already named, %q", got, stranded)
|
||||
@@ -278,8 +278,8 @@ func TestTagActorSnapshot_RecreateAfterCopyFailure(t *testing.T) {
|
||||
}
|
||||
|
||||
// Deleting the tag collects the partial copy and frees the name.
|
||||
if _, err := svc.DeleteActorSnapshotTag(ctx, &ateapipb.DeleteActorSnapshotTagRequest{ActorSnapshotTag: tagRef.ToObjectRef()}); err != nil {
|
||||
t.Fatalf("DeleteActorSnapshotTag on the pending tag: %v", err)
|
||||
if _, err := svc.DeleteTag(ctx, &ateapipb.DeleteTagRequest{Tag: tagRef.ToObjectRef()}); err != nil {
|
||||
t.Fatalf("DeleteTag on the pending tag: %v", err)
|
||||
}
|
||||
if got := objects.Snapshot(t, strandedURI); len(got) != 0 {
|
||||
t.Errorf("the stranded prefix after the delete = %v, want collected", got)
|
||||
@@ -319,7 +319,7 @@ func TestTagActorSnapshot_RacesDelete(t *testing.T) {
|
||||
|
||||
actor, _ := seedTagSource(t, ctx, persistence, objects, template, "actor-1", "manifest.json", "memory.zst")
|
||||
actorRef := resources.ActorRefFromActor(actor)
|
||||
tagRef := resources.ActorSnapshotTagRef{Atespace: "team-a", Name: "v1"}
|
||||
tagRef := resources.TagRef{Atespace: "team-a", Name: "v1"}
|
||||
|
||||
var once sync.Once
|
||||
var pendingURI string
|
||||
@@ -328,13 +328,13 @@ func TestTagActorSnapshot_RacesDelete(t *testing.T) {
|
||||
// the file copy to GCS/S3.
|
||||
objects.OnCopy = func(_, _, _, _ string) error {
|
||||
once.Do(func() {
|
||||
reserved, err := persistence.GetActorSnapshotTag(ctx, tagRef)
|
||||
reserved, err := persistence.GetTag(ctx, tagRef)
|
||||
if err != nil {
|
||||
t.Errorf("GetActorSnapshotTag during the copy: %v", err)
|
||||
t.Errorf("GetTag during the copy: %v", err)
|
||||
return
|
||||
}
|
||||
pendingURI = reserved.GetStatus().GetInProgressSnapshotUri()
|
||||
_, deleteErr = svc.DeleteActorSnapshotTag(ctx, &ateapipb.DeleteActorSnapshotTagRequest{ActorSnapshotTag: tagRef.ToObjectRef()})
|
||||
_, deleteErr = svc.DeleteTag(ctx, &ateapipb.DeleteTagRequest{Tag: tagRef.ToObjectRef()})
|
||||
})
|
||||
return nil
|
||||
}
|
||||
@@ -349,7 +349,7 @@ func TestTagActorSnapshot_RacesDelete(t *testing.T) {
|
||||
// The delete is refused rather than queued behind the copy: the create
|
||||
// holds the tag's lease until it has finished writing.
|
||||
if code := status.Code(deleteErr); code != codes.Aborted {
|
||||
t.Errorf("DeleteActorSnapshotTag during the copy = %v (code %v), want code Aborted", deleteErr, code)
|
||||
t.Errorf("DeleteTag during the copy = %v (code %v), want code Aborted", deleteErr, code)
|
||||
}
|
||||
|
||||
// Nothing was collected out from under the copy, and the row in the store it
|
||||
@@ -360,8 +360,8 @@ func TestTagActorSnapshot_RacesDelete(t *testing.T) {
|
||||
if diff := cmp.Diff([]string{"manifest.json", "memory.zst"}, objects.Snapshot(t, mustParseSnapshotURI(t, pendingURI))); diff != "" {
|
||||
t.Errorf("the tag's external snapshot mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
if _, err := persistence.GetActorSnapshotTag(ctx, tagRef); err != nil {
|
||||
t.Errorf("GetActorSnapshotTag after the race: %v", err)
|
||||
if _, err := persistence.GetTag(ctx, tagRef); err != nil {
|
||||
t.Errorf("GetTag after the race: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,7 +377,7 @@ func TestTagActorSnapshot_NameTakenByAnotherActor(t *testing.T) {
|
||||
|
||||
first, _ := seedTagSource(t, ctx, persistence, objects, template, "actor-1", "manifest.json", "memory.zst")
|
||||
second, secondSnapshot := seedTagSource(t, ctx, persistence, objects, template, "actor-2", "other.json")
|
||||
tagRef := resources.ActorSnapshotTagRef{Atespace: "team-a", Name: "v1"}
|
||||
tagRef := resources.TagRef{Atespace: "team-a", Name: "v1"}
|
||||
|
||||
// The first actor reserves the name, then dies in the copy.
|
||||
objects.OnCopy = func(_, srcObject, _, _ string) error {
|
||||
@@ -389,9 +389,9 @@ func TestTagActorSnapshot_NameTakenByAnotherActor(t *testing.T) {
|
||||
if _, err := w.TagActorSnapshot(ctx, tagToCreate(resources.ActorRefFromActor(first), "v1")); !errors.Is(err, errObjectStore) {
|
||||
t.Fatalf("TagActorSnapshot(actor-1) = %v, want an error wrapping %v", err, errObjectStore)
|
||||
}
|
||||
pending, err := persistence.GetActorSnapshotTag(ctx, tagRef)
|
||||
pending, err := persistence.GetTag(ctx, tagRef)
|
||||
if err != nil {
|
||||
t.Fatalf("GetActorSnapshotTag: %v", err)
|
||||
t.Fatalf("GetTag: %v", err)
|
||||
}
|
||||
strandedURI := mustParseSnapshotURI(t, pending.GetStatus().GetInProgressSnapshotUri())
|
||||
|
||||
@@ -405,9 +405,9 @@ func TestTagActorSnapshot_NameTakenByAnotherActor(t *testing.T) {
|
||||
if diff := cmp.Diff([]string{"manifest.json"}, objects.Snapshot(t, strandedURI)); diff != "" {
|
||||
t.Errorf("the rejected create wrote into the pending tag's prefix (-want +got):\n%s", diff)
|
||||
}
|
||||
stored, err := persistence.GetActorSnapshotTag(ctx, tagRef)
|
||||
stored, err := persistence.GetTag(ctx, tagRef)
|
||||
if err != nil {
|
||||
t.Fatalf("GetActorSnapshotTag after the rejected create: %v", err)
|
||||
t.Fatalf("GetTag after the rejected create: %v", err)
|
||||
}
|
||||
if got, want := stored.GetStatus().GetSourceActorUid(), first.GetMetadata().GetUid(); got != want {
|
||||
t.Errorf("source actor uid = %q, want the first actor's %q", got, want)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -986,46 +986,46 @@ func unmarshalEgressPolicy(uid string, version int64, protoBytes []byte) (*ateap
|
||||
return policy, nil
|
||||
}
|
||||
|
||||
// --- Actor snapshot tags ---
|
||||
// --- Actor tags ---
|
||||
|
||||
func (p *Persistence) GetActorSnapshotTag(ctx context.Context, tagRef resources.ActorSnapshotTagRef) (*ateapipb.ActorSnapshotTag, error) {
|
||||
func (p *Persistence) GetTag(ctx context.Context, tagRef resources.TagRef) (*ateapipb.Tag, error) {
|
||||
atespace, name := tagRef.Atespace, tagRef.Name
|
||||
var protoBytes []byte
|
||||
if err := p.pool.QueryRow(ctx, `
|
||||
SELECT proto FROM actor_snapshot_tags
|
||||
SELECT proto FROM tags
|
||||
WHERE atespace = $1 AND name = $2`, atespace, name).Scan(&protoBytes); err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return nil, store.ErrNotFound
|
||||
}
|
||||
return nil, fmt.Errorf("getting actor snapshot tag %s/%s: %w", atespace, name, err)
|
||||
return nil, fmt.Errorf("getting tag %s/%s: %w", atespace, name, err)
|
||||
}
|
||||
tag := &ateapipb.ActorSnapshotTag{}
|
||||
tag := &ateapipb.Tag{}
|
||||
if err := unmarshalStored(protoBytes, tag); err != nil {
|
||||
return nil, fmt.Errorf("unmarshaling actor snapshot tag: %w", err)
|
||||
return nil, fmt.Errorf("unmarshaling tag: %w", err)
|
||||
}
|
||||
return tag, nil
|
||||
}
|
||||
|
||||
func (p *Persistence) ListActorSnapshotTags(ctx context.Context, atespace string, opts store.ListOptions) (store.ListResponse[*ateapipb.ActorSnapshotTag], error) {
|
||||
func (p *Persistence) ListTags(ctx context.Context, atespace string, opts store.ListOptions) (store.ListResponse[*ateapipb.Tag], error) {
|
||||
opts, err := store.NormalizeListOptions(opts)
|
||||
if err != nil {
|
||||
return store.ListResponse[*ateapipb.ActorSnapshotTag]{}, err
|
||||
return store.ListResponse[*ateapipb.Tag]{}, err
|
||||
}
|
||||
var items []*ateapipb.ActorSnapshotTag
|
||||
var items []*ateapipb.Tag
|
||||
var nextToken string
|
||||
if atespace != "" {
|
||||
items, nextToken, err = p.listActorSnapshotTagsScoped(ctx, atespace, opts.PageSize, opts.PageToken)
|
||||
items, nextToken, err = p.listTagsScoped(ctx, atespace, opts.PageSize, opts.PageToken)
|
||||
} else {
|
||||
items, nextToken, err = p.listActorSnapshotTagsGlobal(ctx, opts.PageSize, opts.PageToken)
|
||||
items, nextToken, err = p.listTagsGlobal(ctx, opts.PageSize, opts.PageToken)
|
||||
}
|
||||
if err != nil {
|
||||
return store.ListResponse[*ateapipb.ActorSnapshotTag]{}, err
|
||||
return store.ListResponse[*ateapipb.Tag]{}, err
|
||||
}
|
||||
return store.ListResponse[*ateapipb.ActorSnapshotTag]{Items: items, NextPageToken: nextToken}, nil
|
||||
return store.ListResponse[*ateapipb.Tag]{Items: items, NextPageToken: nextToken}, nil
|
||||
}
|
||||
|
||||
func (p *Persistence) listActorSnapshotTagsScoped(ctx context.Context, atespace string, pageSize int32, pageTokenStr string) ([]*ateapipb.ActorSnapshotTag, string, error) {
|
||||
token, err := decodePageToken(pageTokenStr, kindSnapshotTag, atespace, 1)
|
||||
func (p *Persistence) listTagsScoped(ctx context.Context, atespace string, pageSize int32, pageTokenStr string) ([]*ateapipb.Tag, string, error) {
|
||||
token, err := decodePageToken(pageTokenStr, kindTag, atespace, 1)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -1034,43 +1034,43 @@ func (p *Persistence) listActorSnapshotTagsScoped(ctx context.Context, atespace
|
||||
last = &token.Last[0]
|
||||
}
|
||||
rows, err := p.pool.Query(ctx, `
|
||||
SELECT name, proto FROM actor_snapshot_tags
|
||||
SELECT name, proto FROM tags
|
||||
WHERE atespace = $1 AND ($2::text IS NULL OR name > $2)
|
||||
ORDER BY name
|
||||
LIMIT $3`, atespace, last, int64(pageSize)+1)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("listing actor snapshot tags in %q: %w", atespace, err)
|
||||
return nil, "", fmt.Errorf("listing tags in %q: %w", atespace, err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var names []string
|
||||
var result []*ateapipb.ActorSnapshotTag
|
||||
var result []*ateapipb.Tag
|
||||
for rows.Next() {
|
||||
var name string
|
||||
var protoBytes []byte
|
||||
if err := rows.Scan(&name, &protoBytes); err != nil {
|
||||
return nil, "", fmt.Errorf("scanning actor snapshot tag row: %w", err)
|
||||
return nil, "", fmt.Errorf("scanning tag row: %w", err)
|
||||
}
|
||||
tag := &ateapipb.ActorSnapshotTag{}
|
||||
tag := &ateapipb.Tag{}
|
||||
if err := unmarshalStored(protoBytes, tag); err != nil {
|
||||
return nil, "", fmt.Errorf("unmarshaling actor snapshot tag: %w", err)
|
||||
return nil, "", fmt.Errorf("unmarshaling tag: %w", err)
|
||||
}
|
||||
result = append(result, tag)
|
||||
names = append(names, name)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, "", fmt.Errorf("listing actor snapshot tags in %q: %w", atespace, err)
|
||||
return nil, "", fmt.Errorf("listing tags in %q: %w", atespace, err)
|
||||
}
|
||||
var nextToken string
|
||||
if len(result) > int(pageSize) {
|
||||
result = result[:pageSize]
|
||||
nextToken = encodePageToken(kindSnapshotTag, atespace, []string{names[pageSize-1]})
|
||||
nextToken = encodePageToken(kindTag, atespace, []string{names[pageSize-1]})
|
||||
}
|
||||
return result, nextToken, nil
|
||||
}
|
||||
|
||||
func (p *Persistence) listActorSnapshotTagsGlobal(ctx context.Context, pageSize int32, pageTokenStr string) ([]*ateapipb.ActorSnapshotTag, string, error) {
|
||||
token, err := decodePageToken(pageTokenStr, kindSnapshotTag, "", 2)
|
||||
func (p *Persistence) listTagsGlobal(ctx context.Context, pageSize int32, pageTokenStr string) ([]*ateapipb.Tag, string, error) {
|
||||
token, err := decodePageToken(pageTokenStr, kindTag, "", 2)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
@@ -1079,55 +1079,55 @@ func (p *Persistence) listActorSnapshotTagsGlobal(ctx context.Context, pageSize
|
||||
lastAtespace, lastName = &token.Last[0], &token.Last[1]
|
||||
}
|
||||
rows, err := p.pool.Query(ctx, `
|
||||
SELECT atespace, name, proto FROM actor_snapshot_tags
|
||||
SELECT atespace, name, proto FROM tags
|
||||
WHERE $1::text IS NULL OR (atespace, name) > ($1, $2)
|
||||
ORDER BY atespace, name
|
||||
LIMIT $3`, lastAtespace, lastName, int64(pageSize)+1)
|
||||
if err != nil {
|
||||
return nil, "", fmt.Errorf("listing actor snapshot tags: %w", err)
|
||||
return nil, "", fmt.Errorf("listing tags: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
type key struct{ atespace, name string }
|
||||
var keys []key
|
||||
var result []*ateapipb.ActorSnapshotTag
|
||||
var result []*ateapipb.Tag
|
||||
for rows.Next() {
|
||||
var k key
|
||||
var protoBytes []byte
|
||||
if err := rows.Scan(&k.atespace, &k.name, &protoBytes); err != nil {
|
||||
return nil, "", fmt.Errorf("scanning actor snapshot tag row: %w", err)
|
||||
return nil, "", fmt.Errorf("scanning tag row: %w", err)
|
||||
}
|
||||
tag := &ateapipb.ActorSnapshotTag{}
|
||||
tag := &ateapipb.Tag{}
|
||||
if err := unmarshalStored(protoBytes, tag); err != nil {
|
||||
return nil, "", fmt.Errorf("unmarshaling actor snapshot tag: %w", err)
|
||||
return nil, "", fmt.Errorf("unmarshaling tag: %w", err)
|
||||
}
|
||||
result = append(result, tag)
|
||||
keys = append(keys, k)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, "", fmt.Errorf("listing actor snapshot tags: %w", err)
|
||||
return nil, "", fmt.Errorf("listing tags: %w", err)
|
||||
}
|
||||
var nextToken string
|
||||
if len(result) > int(pageSize) {
|
||||
result = result[:pageSize]
|
||||
last := keys[pageSize-1]
|
||||
nextToken = encodePageToken(kindSnapshotTag, "", []string{last.atespace, last.name})
|
||||
nextToken = encodePageToken(kindTag, "", []string{last.atespace, last.name})
|
||||
}
|
||||
return result, nextToken, nil
|
||||
}
|
||||
|
||||
func (p *Persistence) CreateActorSnapshotTag(ctx context.Context, tag *ateapipb.ActorSnapshotTag) (*ateapipb.ActorSnapshotTag, error) {
|
||||
func (p *Persistence) CreateTag(ctx context.Context, tag *ateapipb.Tag) (*ateapipb.Tag, error) {
|
||||
atespace := tag.GetMetadata().GetAtespace()
|
||||
name := tag.GetMetadata().GetName()
|
||||
dbTag := proto.CloneOf(tag)
|
||||
dbTag.Metadata = newCreateMetadata(atespace, name)
|
||||
protoBytes, err := proto.Marshal(dbTag)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("marshaling actor snapshot tag: %w", err)
|
||||
return nil, fmt.Errorf("marshaling tag: %w", err)
|
||||
}
|
||||
|
||||
_, err = p.pool.Exec(ctx, `
|
||||
INSERT INTO actor_snapshot_tags (atespace, name, uid, version, proto)
|
||||
INSERT INTO tags (atespace, name, uid, version, proto)
|
||||
VALUES ($1, $2, $3, $4, $5)`, atespace, name,
|
||||
dbTag.GetMetadata().GetUid(), dbTag.GetMetadata().GetVersion(), protoBytes)
|
||||
if err != nil {
|
||||
@@ -1136,18 +1136,18 @@ func (p *Persistence) CreateActorSnapshotTag(ctx context.Context, tag *ateapipb.
|
||||
}
|
||||
if isForeignKeyViolation(err) {
|
||||
switch pgErrConstraint(err) {
|
||||
case "actor_snapshot_tags_atespace_fk":
|
||||
case "tags_atespace_fk":
|
||||
return nil, store.ErrFailedPrecondition
|
||||
default:
|
||||
return nil, fmt.Errorf("inserting actor snapshot tag %s/%s violated unknown foreign key %q: %w", atespace, name, pgErrConstraint(err), err)
|
||||
return nil, fmt.Errorf("inserting tag %s/%s violated unknown foreign key %q: %w", atespace, name, pgErrConstraint(err), err)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("inserting actor snapshot tag %s/%s: %w", atespace, name, err)
|
||||
return nil, fmt.Errorf("inserting tag %s/%s: %w", atespace, name, err)
|
||||
}
|
||||
return dbTag, nil
|
||||
}
|
||||
|
||||
func validateUpdateActorSnapshotTagMutation(storedTag, mutatedTag *ateapipb.ActorSnapshotTag) error {
|
||||
func validateUpdateTagMutation(storedTag, mutatedTag *ateapipb.Tag) error {
|
||||
if stored, mutated := storedTag.GetMetadata().GetAtespace(), mutatedTag.GetMetadata().GetAtespace(); stored != mutated {
|
||||
return fmt.Errorf("metadata.atespace is immutable: mutation changed it from %q to %q", stored, mutated)
|
||||
}
|
||||
@@ -1169,7 +1169,7 @@ func validateUpdateActorSnapshotTagMutation(storedTag, mutatedTag *ateapipb.Acto
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Persistence) UpdateActorSnapshotTag(ctx context.Context, tagRef resources.ActorSnapshotTagRef, precondition store.Precondition, mutate func(*ateapipb.ActorSnapshotTag) error) (*ateapipb.ActorSnapshotTag, error) {
|
||||
func (p *Persistence) UpdateTag(ctx context.Context, tagRef resources.TagRef, precondition store.Precondition, mutate func(*ateapipb.Tag) error) (*ateapipb.Tag, error) {
|
||||
if err := precondition.Validate(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1178,29 +1178,29 @@ func (p *Persistence) UpdateActorSnapshotTag(ctx context.Context, tagRef resourc
|
||||
var currentVersion int64
|
||||
var currentBytes []byte
|
||||
if err := p.pool.QueryRow(ctx, `
|
||||
SELECT uid, version, proto FROM actor_snapshot_tags
|
||||
SELECT uid, version, proto FROM tags
|
||||
WHERE atespace = $1 AND name = $2`, atespace, name).Scan(¤tUID, ¤tVersion, ¤tBytes); err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return nil, store.ErrNotFound
|
||||
}
|
||||
return nil, fmt.Errorf("getting actor snapshot tag %s/%s for update: %w", atespace, name, err)
|
||||
return nil, fmt.Errorf("getting tag %s/%s for update: %w", atespace, name, err)
|
||||
}
|
||||
|
||||
dbTag := &ateapipb.ActorSnapshotTag{}
|
||||
dbTag := &ateapipb.Tag{}
|
||||
if err := unmarshalStored(currentBytes, dbTag); err != nil {
|
||||
return nil, fmt.Errorf("unmarshaling actor snapshot tag: %w", err)
|
||||
return nil, fmt.Errorf("unmarshaling tag: %w", err)
|
||||
}
|
||||
if err := validateProtoMetadataMatchesColumns(fmt.Sprintf("actor snapshot tag %s/%s", atespace, name), dbTag.GetMetadata(), currentUID, currentVersion); err != nil {
|
||||
if err := validateProtoMetadataMatchesColumns(fmt.Sprintf("tag %s/%s", atespace, name), dbTag.GetMetadata(), currentUID, currentVersion); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := precondition.Check(dbTag.GetMetadata()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tagBeforeMutation := proto.Clone(dbTag).(*ateapipb.ActorSnapshotTag)
|
||||
tagBeforeMutation := proto.Clone(dbTag).(*ateapipb.Tag)
|
||||
if err := mutate(dbTag); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := validateUpdateActorSnapshotTagMutation(tagBeforeMutation, dbTag); err != nil {
|
||||
if err := validateUpdateTagMutation(tagBeforeMutation, dbTag); err != nil {
|
||||
return nil, fmt.Errorf("%w: %w", store.ErrImmutableField, err)
|
||||
}
|
||||
// Stored metadata is authoritative; discard any metadata edits made by the
|
||||
@@ -1209,40 +1209,40 @@ func (p *Persistence) UpdateActorSnapshotTag(ctx context.Context, tagRef resourc
|
||||
|
||||
updatedBytes, err := proto.Marshal(dbTag)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("marshaling actor snapshot tag: %w", err)
|
||||
return nil, fmt.Errorf("marshaling tag: %w", err)
|
||||
}
|
||||
commandTag, err := p.pool.Exec(ctx, `
|
||||
UPDATE actor_snapshot_tags
|
||||
UPDATE tags
|
||||
SET version = $1, proto = $2
|
||||
WHERE atespace = $3 AND name = $4 AND uid = $5 AND version = $6`,
|
||||
dbTag.GetMetadata().GetVersion(), updatedBytes, atespace, name, currentUID, currentVersion)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("updating actor snapshot tag %s/%s: %w", atespace, name, err)
|
||||
return nil, fmt.Errorf("updating tag %s/%s: %w", atespace, name, err)
|
||||
}
|
||||
if commandTag.RowsAffected() == 0 {
|
||||
return nil, store.ErrVersionConflict
|
||||
}
|
||||
if commandTag.RowsAffected() != 1 {
|
||||
return nil, fmt.Errorf("updating actor snapshot tag %s/%s affected %d rows, want 1", atespace, name, commandTag.RowsAffected())
|
||||
return nil, fmt.Errorf("updating tag %s/%s affected %d rows, want 1", atespace, name, commandTag.RowsAffected())
|
||||
}
|
||||
return dbTag, nil
|
||||
}
|
||||
|
||||
func (p *Persistence) DeleteActorSnapshotTag(ctx context.Context, tagRef resources.ActorSnapshotTagRef) (*ateapipb.ActorSnapshotTag, error) {
|
||||
func (p *Persistence) DeleteTag(ctx context.Context, tagRef resources.TagRef) (*ateapipb.Tag, error) {
|
||||
atespace, name := tagRef.Atespace, tagRef.Name
|
||||
var protoBytes []byte
|
||||
if err := p.pool.QueryRow(ctx, `
|
||||
DELETE FROM actor_snapshot_tags
|
||||
DELETE FROM tags
|
||||
WHERE atespace = $1 AND name = $2
|
||||
RETURNING proto`, atespace, name).Scan(&protoBytes); err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return nil, store.ErrNotFound
|
||||
}
|
||||
return nil, fmt.Errorf("deleting actor snapshot tag %s/%s: %w", atespace, name, err)
|
||||
return nil, fmt.Errorf("deleting tag %s/%s: %w", atespace, name, err)
|
||||
}
|
||||
tag := &ateapipb.ActorSnapshotTag{}
|
||||
tag := &ateapipb.Tag{}
|
||||
if err := unmarshalStored(protoBytes, tag); err != nil {
|
||||
return nil, fmt.Errorf("unmarshaling deleted actor snapshot tag: %w", err)
|
||||
return nil, fmt.Errorf("unmarshaling deleted tag: %w", err)
|
||||
}
|
||||
return tag, nil
|
||||
}
|
||||
|
||||
@@ -464,7 +464,7 @@ func appliedMigrationVersions(t *testing.T, pool *pgxpool.Pool) []int64 {
|
||||
// state, so the statement lives here rather than on Persistence.
|
||||
func clearAll(t *testing.T, p *Persistence) {
|
||||
t.Helper()
|
||||
if _, err := p.pool.Exec(context.Background(), `TRUNCATE atespaces, actors, actor_egress_policies, actor_templates, actor_snapshot_tags, workers, worker_assignments, leases, worker_outbox, worker_outbox_trim`); err != nil {
|
||||
if _, err := p.pool.Exec(context.Background(), `TRUNCATE atespaces, actors, actor_egress_policies, actor_templates, tags, workers, worker_assignments, leases, worker_outbox, worker_outbox_trim`); err != nil {
|
||||
t.Fatalf("truncating tables: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -597,7 +597,7 @@ func TestUpdateActorTemplate_ConcurrentWriteReturnsConflict(t *testing.T) {
|
||||
}
|
||||
|
||||
// createTestSuspendedActor seeds an actor holding an external snapshot, which
|
||||
// is what CreateActorSnapshotTag tags.
|
||||
// is what CreateTag tags.
|
||||
func createTestSuspendedActor(t *testing.T, s *Persistence, atespace, name string) *ateapipb.Actor {
|
||||
t.Helper()
|
||||
created, err := s.CreateActor(context.Background(), &ateapipb.Actor{
|
||||
@@ -614,69 +614,69 @@ func createTestSuspendedActor(t *testing.T, s *Persistence, atespace, name strin
|
||||
return created
|
||||
}
|
||||
|
||||
// createTestActorSnapshotTag creates tagName over its own copy of actor's
|
||||
// createTestTag creates tagName over its own copy of actor's
|
||||
// external snapshot, already finalized.
|
||||
func createTestActorSnapshotTag(t *testing.T, s *Persistence, actor *ateapipb.Actor, tagAtespace, tagName string) *ateapipb.ActorSnapshotTag {
|
||||
func createTestTag(t *testing.T, s *Persistence, actor *ateapipb.Actor, tagAtespace, tagName string) *ateapipb.Tag {
|
||||
t.Helper()
|
||||
tag, err := s.CreateActorSnapshotTag(context.Background(), &ateapipb.ActorSnapshotTag{
|
||||
tag, err := s.CreateTag(context.Background(), &ateapipb.Tag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: tagAtespace, Name: tagName},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE,
|
||||
Status: &ateapipb.ActorSnapshotTagStatus{
|
||||
Snapshot: &ateapipb.ExternalSnapshot{SnapshotUri: "gs://bucket/atespaces/" + tagAtespace + "/actor-snapshot-tags/" + tagName},
|
||||
Scope: ateapipb.TagScope_TAG_SCOPE_ATESPACE,
|
||||
Status: &ateapipb.TagStatus{
|
||||
Snapshot: &ateapipb.ExternalSnapshot{SnapshotUri: "gs://bucket/atespaces/" + tagAtespace + "/tags/" + tagName},
|
||||
SourceActorUid: actor.GetMetadata().GetUid(),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateActorSnapshotTag(%s/%s) failed: %v", tagAtespace, tagName, err)
|
||||
t.Fatalf("CreateTag(%s/%s) failed: %v", tagAtespace, tagName, err)
|
||||
}
|
||||
return tag
|
||||
}
|
||||
|
||||
func TestUpdateActorSnapshotTag_CASPreventsDeleteRecreateABA(t *testing.T) {
|
||||
func TestUpdateTag_CASPreventsDeleteRecreateABA(t *testing.T) {
|
||||
s := setupPostgresPersistence(t)
|
||||
ctx := context.Background()
|
||||
createTestAtespace(t, s, "team-a")
|
||||
actorA := createTestSuspendedActor(t, s, "team-a", "actor-a")
|
||||
actorB := createTestSuspendedActor(t, s, "team-a", "actor-b")
|
||||
original := createTestActorSnapshotTag(t, s, actorA, "team-a", "tag-a")
|
||||
original := createTestTag(t, s, actorA, "team-a", "tag-a")
|
||||
|
||||
mutations := 0
|
||||
var recreated *ateapipb.ActorSnapshotTag
|
||||
_, err := s.UpdateActorSnapshotTag(ctx, resources.ActorSnapshotTagRef{Atespace: "team-a", Name: "tag-a"}, store.PreconditionFrom(original), func(toUpdate *ateapipb.ActorSnapshotTag) error {
|
||||
var recreated *ateapipb.Tag
|
||||
_, err := s.UpdateTag(ctx, resources.TagRef{Atespace: "team-a", Name: "tag-a"}, store.PreconditionFrom(original), func(toUpdate *ateapipb.Tag) error {
|
||||
mutations++
|
||||
if _, err := s.DeleteActorSnapshotTag(ctx, resources.ActorSnapshotTagRef{Atespace: "team-a", Name: "tag-a"}); err != nil {
|
||||
if _, err := s.DeleteTag(ctx, resources.TagRef{Atespace: "team-a", Name: "tag-a"}); err != nil {
|
||||
return fmt.Errorf("deleting original tag: %w", err)
|
||||
}
|
||||
recreated = createTestActorSnapshotTag(t, s, actorB, "team-a", "tag-a")
|
||||
toUpdate.Scope = ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED
|
||||
recreated = createTestTag(t, s, actorB, "team-a", "tag-a")
|
||||
toUpdate.Scope = ateapipb.TagScope_TAG_SCOPE_PUBLISHED
|
||||
return nil
|
||||
})
|
||||
if !errors.Is(err, store.ErrVersionConflict) {
|
||||
t.Fatalf("UpdateActorSnapshotTag error = %v, want ErrVersionConflict", err)
|
||||
t.Fatalf("UpdateTag error = %v, want ErrVersionConflict", err)
|
||||
}
|
||||
if mutations != 1 {
|
||||
t.Errorf("guarded mutation ran %d times, want 1", mutations)
|
||||
}
|
||||
stored, err := s.GetActorSnapshotTag(ctx, resources.ActorSnapshotTagRef{Atespace: "team-a", Name: "tag-a"})
|
||||
stored, err := s.GetTag(ctx, resources.TagRef{Atespace: "team-a", Name: "tag-a"})
|
||||
if err != nil {
|
||||
t.Fatalf("GetActorSnapshotTag failed: %v", err)
|
||||
t.Fatalf("GetTag failed: %v", err)
|
||||
}
|
||||
if diff := cmp.Diff(recreated, stored, protocmp.Transform()); diff != "" {
|
||||
t.Errorf("recreated tag was overwritten (-want +got):\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateActorSnapshotTag_TagForeignKeyErrors(t *testing.T) {
|
||||
func TestCreateTag_TagForeignKeyErrors(t *testing.T) {
|
||||
s := setupPostgresPersistence(t)
|
||||
ctx := context.Background()
|
||||
createTestAtespace(t, s, "team-a")
|
||||
actor := createTestSuspendedActor(t, s, "team-a", "actor-a")
|
||||
|
||||
// A tag in an atespace that does not exist trips the tag's atespace FK.
|
||||
_, err := s.CreateActorSnapshotTag(ctx, &ateapipb.ActorSnapshotTag{
|
||||
_, err := s.CreateTag(ctx, &ateapipb.Tag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: "gone", Name: "latest"},
|
||||
Status: &ateapipb.ActorSnapshotTagStatus{
|
||||
InProgressSnapshotUri: "gs://bucket/atespaces/gone/actor-snapshot-tags/latest",
|
||||
Status: &ateapipb.TagStatus{
|
||||
InProgressSnapshotUri: "gs://bucket/atespaces/gone/tags/latest",
|
||||
SourceActorUid: actor.GetMetadata().GetUid(),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -52,14 +52,14 @@ CREATE TABLE actor_templates (
|
||||
PRIMARY KEY (atespace, name)
|
||||
);
|
||||
|
||||
CREATE TABLE actor_snapshot_tags (
|
||||
CREATE TABLE tags (
|
||||
atespace text NOT NULL,
|
||||
name text NOT NULL,
|
||||
uid text NOT NULL,
|
||||
version bigint NOT NULL,
|
||||
proto bytea NOT NULL,
|
||||
PRIMARY KEY (atespace, name),
|
||||
CONSTRAINT actor_snapshot_tags_atespace_fk
|
||||
CONSTRAINT tags_atespace_fk
|
||||
FOREIGN KEY (atespace) REFERENCES atespaces(name) ON DELETE RESTRICT
|
||||
);
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ const (
|
||||
kindAtespace resourceKind = "atespace"
|
||||
kindActor resourceKind = "actor"
|
||||
kindActorTemplate resourceKind = "actor-template"
|
||||
kindSnapshotTag resourceKind = "snapshot-tag"
|
||||
kindTag resourceKind = "tag"
|
||||
kindWorker resourceKind = "worker"
|
||||
kindWorkerAssign resourceKind = "worker-assignment"
|
||||
)
|
||||
|
||||
@@ -114,22 +114,22 @@ type Interface interface {
|
||||
// Deletes and returns an Actor's policy subresource.
|
||||
DeleteEgressPolicy(ctx context.Context, actorRef resources.ActorRef) (*ateapipb.EgressPolicy, error)
|
||||
|
||||
// CreateActorSnapshotTag creates an immutable tag to an actor snapshot.
|
||||
// CreateTag creates an immutable tag to an actor snapshot.
|
||||
//
|
||||
// Returns ErrAlreadyExists if the name is taken — including by the caller's
|
||||
// own unfinished attempt, which it can then read back and resume — or
|
||||
// ErrFailedPrecondition if the tag's atespace does not exist.
|
||||
CreateActorSnapshotTag(ctx context.Context, tag *ateapipb.ActorSnapshotTag) (*ateapipb.ActorSnapshotTag, error)
|
||||
CreateTag(ctx context.Context, tag *ateapipb.Tag) (*ateapipb.Tag, error)
|
||||
|
||||
// Fetches an Atespace-owned tag by reference. Returns ErrNotFound if
|
||||
// missing.
|
||||
GetActorSnapshotTag(ctx context.Context, tagRef resources.ActorSnapshotTagRef) (*ateapipb.ActorSnapshotTag, error)
|
||||
GetTag(ctx context.Context, tagRef resources.TagRef) (*ateapipb.Tag, error)
|
||||
|
||||
// Lists ActorSnapshotTags in one atespace, or all atespaces when empty.
|
||||
ListActorSnapshotTags(ctx context.Context, atespace string, opts ListOptions) (ListResponse[*ateapipb.ActorSnapshotTag], error)
|
||||
// Lists Tags in one atespace, or all atespaces when empty.
|
||||
ListTags(ctx context.Context, atespace string, opts ListOptions) (ListResponse[*ateapipb.Tag], error)
|
||||
|
||||
// UpdateActorSnapshotTag performs a transactional read-modify-write on the tag
|
||||
// addressed by tagRef, and returns the stored ActorSnapshotTag with
|
||||
// UpdateTag performs a transactional read-modify-write on the tag
|
||||
// addressed by tagRef, and returns the stored Tag with
|
||||
// advanced metadata (version, update_time).
|
||||
//
|
||||
// precondition guards the write against landing on unexpected state: it is
|
||||
@@ -149,10 +149,10 @@ type Interface interface {
|
||||
// immutable for its lifetime, or the mutate's error verbatim otherwise.
|
||||
//
|
||||
// status.snapshot is immutable once set
|
||||
UpdateActorSnapshotTag(ctx context.Context, tagRef resources.ActorSnapshotTagRef, precondition Precondition, mutate func(toUpdate *ateapipb.ActorSnapshotTag) error) (*ateapipb.ActorSnapshotTag, error)
|
||||
UpdateTag(ctx context.Context, tagRef resources.TagRef, precondition Precondition, mutate func(toUpdate *ateapipb.Tag) error) (*ateapipb.Tag, error)
|
||||
|
||||
// Deletes and returns a tag.
|
||||
DeleteActorSnapshotTag(ctx context.Context, tagRef resources.ActorSnapshotTagRef) (*ateapipb.ActorSnapshotTag, error)
|
||||
DeleteTag(ctx context.Context, tagRef resources.TagRef) (*ateapipb.Tag, error)
|
||||
|
||||
// Stores a new atespace and returns the stored resource with server-assigned
|
||||
// metadata (uid, version, timestamps). The input is not mutated. Returns
|
||||
|
||||
@@ -56,7 +56,7 @@ func testActorSnapshotURI(location, atespace, name string) string {
|
||||
}
|
||||
|
||||
func testTagSnapshotURI(location, atespace, name string) string {
|
||||
return location + "/atespaces/" + atespace + "/actor-snapshot-tags/" + name
|
||||
return location + "/atespaces/" + atespace + "/tags/" + name
|
||||
}
|
||||
|
||||
// Worker resource names. They are opaque to the store, which only ever uses
|
||||
@@ -206,7 +206,7 @@ func RunContractTests(t *testing.T, setup func(t *testing.T) store.Interface) {
|
||||
runWorkerAssignmentContractTests(t, setup)
|
||||
runAtespaceContractTests(t, setup)
|
||||
runActorTemplateContractTests(t, setup)
|
||||
runActorSnapshotTagContractTests(t, setup)
|
||||
runTagContractTests(t, setup)
|
||||
runLeaseContractTests(t, setup)
|
||||
runListOptionsContractTests(t, setup)
|
||||
runUnknownFieldContractTests(t, setup)
|
||||
@@ -329,7 +329,7 @@ func runListOptionsContractTests(t *testing.T, setup func(t *testing.T) store.In
|
||||
{"atespaces", func(opts store.ListOptions) error { _, err := s.ListAtespaces(ctx, opts); return err }},
|
||||
{"actors", func(opts store.ListOptions) error { _, err := s.ListActors(ctx, "", opts); return err }},
|
||||
{"actor templates", func(opts store.ListOptions) error { _, err := s.ListActorTemplates(ctx, "", opts); return err }},
|
||||
{"actor snapshot tags", func(opts store.ListOptions) error { _, err := s.ListActorSnapshotTags(ctx, "", opts); return err }},
|
||||
{"tags", func(opts store.ListOptions) error { _, err := s.ListTags(ctx, "", opts); return err }},
|
||||
{"workers", func(opts store.ListOptions) error { _, err := s.ListWorkers(ctx, opts); return err }},
|
||||
}
|
||||
for _, call := range calls {
|
||||
@@ -354,7 +354,7 @@ func runListOptionsContractTests(t *testing.T, setup func(t *testing.T) store.In
|
||||
{"atespaces", func(opts store.ListOptions) error { _, err := s.ListAtespaces(ctx, opts); return err }},
|
||||
{"actors", func(opts store.ListOptions) error { _, err := s.ListActors(ctx, "", opts); return err }},
|
||||
{"actor templates", func(opts store.ListOptions) error { _, err := s.ListActorTemplates(ctx, "", opts); return err }},
|
||||
{"actor snapshot tags", func(opts store.ListOptions) error { _, err := s.ListActorSnapshotTags(ctx, "", opts); return err }},
|
||||
{"tags", func(opts store.ListOptions) error { _, err := s.ListTags(ctx, "", opts); return err }},
|
||||
{"workers", func(opts store.ListOptions) error { _, err := s.ListWorkers(ctx, opts); return err }},
|
||||
}
|
||||
for _, call := range calls {
|
||||
@@ -981,7 +981,7 @@ func runActorTemplateContractTests(t *testing.T, setup func(t *testing.T) store.
|
||||
}
|
||||
|
||||
// newTestSuspendedActor builds an actor that already holds an external
|
||||
// snapshot, the state CreateActorSnapshotTag tags from.
|
||||
// snapshot, the state CreateTag tags from.
|
||||
func newTestSuspendedActor(atespace, name string) *ateapipb.Actor {
|
||||
return &ateapipb.Actor{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: atespace, Name: name},
|
||||
@@ -996,15 +996,15 @@ func newTestSuspendedActor(atespace, name string) *ateapipb.Actor {
|
||||
}
|
||||
}
|
||||
|
||||
// newTestInProgressSnapshotTag builds the row CreateActorSnapshotTag reserves for a
|
||||
// newTestInProgressTag builds the row CreateTag reserves for a
|
||||
// tag of actor: ATESPACE-scoped, with no snapshot yet and the destination of
|
||||
// the copy still to come recorded in status.in_progress_snapshot_uri.
|
||||
func newTestInProgressSnapshotTag(name string, actor *ateapipb.Actor) *ateapipb.ActorSnapshotTag {
|
||||
func newTestInProgressTag(name string, actor *ateapipb.Actor) *ateapipb.Tag {
|
||||
atespace := actor.GetMetadata().GetAtespace()
|
||||
return &ateapipb.ActorSnapshotTag{
|
||||
return &ateapipb.Tag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: atespace, Name: name},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE,
|
||||
Status: &ateapipb.ActorSnapshotTagStatus{
|
||||
Scope: ateapipb.TagScope_TAG_SCOPE_ATESPACE,
|
||||
Status: &ateapipb.TagStatus{
|
||||
ActorTemplateUid: "template-uid",
|
||||
InProgressSnapshotUri: testTagSnapshotURI("gs://private", atespace, name),
|
||||
SourceActorUid: actor.GetMetadata().GetUid(),
|
||||
@@ -1012,7 +1012,7 @@ func newTestInProgressSnapshotTag(name string, actor *ateapipb.Actor) *ateapipb.
|
||||
}
|
||||
}
|
||||
|
||||
func runActorSnapshotTagContractTests(t *testing.T, setup func(t *testing.T) store.Interface) {
|
||||
func runTagContractTests(t *testing.T, setup func(t *testing.T) store.Interface) {
|
||||
t.Helper()
|
||||
|
||||
// seedSuspendedActor seeds an atespace and an actor holding an external
|
||||
@@ -1027,26 +1027,26 @@ func runActorSnapshotTagContractTests(t *testing.T, setup func(t *testing.T) sto
|
||||
return actor
|
||||
}
|
||||
|
||||
t.Run("ActorSnapshotTag_Lifecycle", func(t *testing.T) {
|
||||
t.Run("Tag_Lifecycle", func(t *testing.T) {
|
||||
s := setup(t)
|
||||
ctx := context.Background()
|
||||
actor := seedSuspendedActor(t, s, "team-a", "actor-1")
|
||||
|
||||
inProgressTag := newTestInProgressSnapshotTag("production", actor)
|
||||
pending, err := s.CreateActorSnapshotTag(ctx, inProgressTag)
|
||||
inProgressTag := newTestInProgressTag("production", actor)
|
||||
pending, err := s.CreateTag(ctx, inProgressTag)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateActorSnapshotTag failed: %v", err)
|
||||
t.Fatalf("CreateTag failed: %v", err)
|
||||
}
|
||||
if pending.GetMetadata().GetVersion() != 1 || pending.GetMetadata().GetUid() == "" {
|
||||
t.Errorf("created tag metadata = %v, want server-owned uid and version 1", pending.GetMetadata())
|
||||
}
|
||||
if inProgressTag.GetMetadata().GetUid() != "" || inProgressTag.GetMetadata().GetVersion() != 0 {
|
||||
t.Errorf("CreateActorSnapshotTag mutated its input metadata: %v", inProgressTag.GetMetadata())
|
||||
t.Errorf("CreateTag mutated its input metadata: %v", inProgressTag.GetMetadata())
|
||||
}
|
||||
|
||||
tag, err := s.GetActorSnapshotTag(ctx, resources.ActorSnapshotTagRef{Atespace: "team-a", Name: "production"})
|
||||
tag, err := s.GetTag(ctx, resources.TagRef{Atespace: "team-a", Name: "production"})
|
||||
if err != nil {
|
||||
t.Fatalf("GetActorSnapshotTag failed: %v", err)
|
||||
t.Fatalf("GetTag failed: %v", err)
|
||||
}
|
||||
// A reserved tag names where its copy is going and nothing else: it is
|
||||
// not usable until the copy lands and finalize names it.
|
||||
@@ -1058,15 +1058,15 @@ func runActorSnapshotTagContractTests(t *testing.T, setup func(t *testing.T) sto
|
||||
}
|
||||
|
||||
// Try to get a tag that doens't exist
|
||||
if _, err := s.GetActorSnapshotTag(ctx, resources.ActorSnapshotTagRef{Atespace: "team-a", Name: "missing"}); !errors.Is(err, store.ErrNotFound) {
|
||||
t.Errorf("missing GetActorSnapshotTag = %v, want ErrNotFound", err)
|
||||
if _, err := s.GetTag(ctx, resources.TagRef{Atespace: "team-a", Name: "missing"}); !errors.Is(err, store.ErrNotFound) {
|
||||
t.Errorf("missing GetTag = %v, want ErrNotFound", err)
|
||||
}
|
||||
|
||||
// Finalize: naming the snapshot and clearing the in-progress URI
|
||||
// together is the one transition status.snapshot is allowed.
|
||||
ready, err := s.UpdateActorSnapshotTag(ctx, resources.ActorSnapshotTagRef{Atespace: "team-a", Name: "production"}, store.PreconditionFrom(tag), finalizeTag)
|
||||
ready, err := s.UpdateTag(ctx, resources.TagRef{Atespace: "team-a", Name: "production"}, store.PreconditionFrom(tag), finalizeTag)
|
||||
if err != nil {
|
||||
t.Fatalf("finalizing actor snapshot tag failed: %v", err)
|
||||
t.Fatalf("finalizing tag failed: %v", err)
|
||||
}
|
||||
// Check if the pending URI was promoted to the Snapshot field.
|
||||
if ready.GetStatus().GetSnapshot().GetSnapshotUri() != tag.GetStatus().GetInProgressSnapshotUri() {
|
||||
@@ -1076,133 +1076,133 @@ func runActorSnapshotTagContractTests(t *testing.T, setup func(t *testing.T) sto
|
||||
t.Errorf("finalized tag in-progress uri = %q, want it cleared", ready.GetStatus().GetInProgressSnapshotUri())
|
||||
}
|
||||
|
||||
updated, err := s.UpdateActorSnapshotTag(ctx, resources.ActorSnapshotTagRef{Atespace: "team-a", Name: "production"}, store.PreconditionFrom(ready), func(toUpdate *ateapipb.ActorSnapshotTag) error {
|
||||
toUpdate.Scope = ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED
|
||||
updated, err := s.UpdateTag(ctx, resources.TagRef{Atespace: "team-a", Name: "production"}, store.PreconditionFrom(ready), func(toUpdate *ateapipb.Tag) error {
|
||||
toUpdate.Scope = ateapipb.TagScope_TAG_SCOPE_PUBLISHED
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("UpdateActorSnapshotTag failed: %v", err)
|
||||
t.Fatalf("UpdateTag failed: %v", err)
|
||||
}
|
||||
if updated.GetScope() != ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED || updated.GetMetadata().GetVersion() != ready.GetMetadata().GetVersion()+1 {
|
||||
if updated.GetScope() != ateapipb.TagScope_TAG_SCOPE_PUBLISHED || updated.GetMetadata().GetVersion() != ready.GetMetadata().GetVersion()+1 {
|
||||
t.Errorf("updated tag = %v, want published scope and advanced version", updated)
|
||||
}
|
||||
if _, err := s.UpdateActorSnapshotTag(ctx, resources.ActorSnapshotTagRef{Atespace: "team-a", Name: "production"}, store.PreconditionFrom(ready), func(toUpdate *ateapipb.ActorSnapshotTag) error {
|
||||
if _, err := s.UpdateTag(ctx, resources.TagRef{Atespace: "team-a", Name: "production"}, store.PreconditionFrom(ready), func(toUpdate *ateapipb.Tag) error {
|
||||
toUpdate.Scope = ready.GetScope()
|
||||
return nil
|
||||
}); !errors.Is(err, store.ErrVersionConflict) {
|
||||
t.Errorf("stale UpdateActorSnapshotTag = %v, want ErrVersionConflict", err)
|
||||
t.Errorf("stale UpdateTag = %v, want ErrVersionConflict", err)
|
||||
}
|
||||
if _, err := s.DeleteAtespace(ctx, "team-a"); !errors.Is(err, store.ErrFailedPrecondition) {
|
||||
t.Errorf("DeleteAtespace with tag = %v, want ErrFailedPrecondition", err)
|
||||
}
|
||||
|
||||
deleted, err := s.DeleteActorSnapshotTag(ctx, resources.ActorSnapshotTagRef{Atespace: "team-a", Name: "production"})
|
||||
deleted, err := s.DeleteTag(ctx, resources.TagRef{Atespace: "team-a", Name: "production"})
|
||||
if err != nil || !proto.Equal(deleted, updated) {
|
||||
t.Errorf("DeleteActorSnapshotTag = (%v, %v), want updated tag", deleted, err)
|
||||
t.Errorf("DeleteTag = (%v, %v), want updated tag", deleted, err)
|
||||
}
|
||||
if _, err := s.GetActorSnapshotTag(ctx, resources.ActorSnapshotTagRef{Atespace: "team-a", Name: "production"}); !errors.Is(err, store.ErrNotFound) {
|
||||
t.Errorf("deleted GetActorSnapshotTag = %v, want ErrNotFound", err)
|
||||
if _, err := s.GetTag(ctx, resources.TagRef{Atespace: "team-a", Name: "production"}); !errors.Is(err, store.ErrNotFound) {
|
||||
t.Errorf("deleted GetTag = %v, want ErrNotFound", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ActorSnapshotTag_ImmutableFields", func(t *testing.T) {
|
||||
t.Run("Tag_ImmutableFields", func(t *testing.T) {
|
||||
s := setup(t)
|
||||
ctx := context.Background()
|
||||
actor := seedSuspendedActor(t, s, "team-a", "actor-1")
|
||||
tag := storeTag(t, s, newTestInProgressSnapshotTag("production", actor))
|
||||
tag := storeTag(t, s, newTestInProgressTag("production", actor))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
mutate func(*ateapipb.ActorSnapshotTag)
|
||||
mutate func(*ateapipb.Tag)
|
||||
}{
|
||||
{
|
||||
name: "snapshot uri",
|
||||
mutate: func(toUpdate *ateapipb.ActorSnapshotTag) {
|
||||
mutate: func(toUpdate *ateapipb.Tag) {
|
||||
toUpdate.Status.Snapshot.SnapshotUri = "gs://private/elsewhere"
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "snapshot content scope",
|
||||
mutate: func(toUpdate *ateapipb.ActorSnapshotTag) {
|
||||
mutate: func(toUpdate *ateapipb.Tag) {
|
||||
toUpdate.Status.Snapshot.ContentScope = ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_DATA
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "clearing the snapshot",
|
||||
mutate: func(toUpdate *ateapipb.ActorSnapshotTag) {
|
||||
mutate: func(toUpdate *ateapipb.Tag) {
|
||||
toUpdate.Status.Snapshot = nil
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "reopening the in-progress snapshot uri",
|
||||
mutate: func(toUpdate *ateapipb.ActorSnapshotTag) {
|
||||
mutate: func(toUpdate *ateapipb.Tag) {
|
||||
toUpdate.Status.InProgressSnapshotUri = testTagSnapshotURI("gs://private", "team-a", "again")
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "actor template uid",
|
||||
mutate: func(toUpdate *ateapipb.ActorSnapshotTag) { toUpdate.Status.ActorTemplateUid = "other-template-uid" },
|
||||
mutate: func(toUpdate *ateapipb.Tag) { toUpdate.Status.ActorTemplateUid = "other-template-uid" },
|
||||
},
|
||||
{
|
||||
name: "source actor uid",
|
||||
mutate: func(toUpdate *ateapipb.ActorSnapshotTag) { toUpdate.Status.SourceActorUid = "other-actor-uid" },
|
||||
mutate: func(toUpdate *ateapipb.Tag) { toUpdate.Status.SourceActorUid = "other-actor-uid" },
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := s.UpdateActorSnapshotTag(ctx, resources.ActorSnapshotTagRef{Atespace: "team-a", Name: "production"}, store.PreconditionFrom(tag), func(toUpdate *ateapipb.ActorSnapshotTag) error {
|
||||
_, err := s.UpdateTag(ctx, resources.TagRef{Atespace: "team-a", Name: "production"}, store.PreconditionFrom(tag), func(toUpdate *ateapipb.Tag) error {
|
||||
tt.mutate(toUpdate)
|
||||
return nil
|
||||
})
|
||||
if !errors.Is(err, store.ErrImmutableField) {
|
||||
t.Errorf("UpdateActorSnapshotTag error = %v, want one matching store.ErrImmutableField", err)
|
||||
t.Errorf("UpdateTag error = %v, want one matching store.ErrImmutableField", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("CreateActorSnapshotTag_ReusedTagName", func(t *testing.T) {
|
||||
t.Run("CreateTag_ReusedTagName", func(t *testing.T) {
|
||||
s := setup(t)
|
||||
ctx := context.Background()
|
||||
actor := seedSuspendedActor(t, s, "team-a", "actor-1")
|
||||
tagInput := newTestInProgressSnapshotTag("production", actor)
|
||||
if _, err := s.CreateActorSnapshotTag(ctx, tagInput); err != nil {
|
||||
t.Fatalf("CreateActorSnapshotTag failed: %v", err)
|
||||
tagInput := newTestInProgressTag("production", actor)
|
||||
if _, err := s.CreateTag(ctx, tagInput); err != nil {
|
||||
t.Fatalf("CreateTag failed: %v", err)
|
||||
}
|
||||
|
||||
// Create the same tag
|
||||
if _, err := s.CreateActorSnapshotTag(ctx, tagInput); !errors.Is(err, store.ErrAlreadyExists) {
|
||||
t.Errorf("duplicate CreateActorSnapshotTag = %v, want ErrAlreadyExists", err)
|
||||
if _, err := s.CreateTag(ctx, tagInput); !errors.Is(err, store.ErrAlreadyExists) {
|
||||
t.Errorf("duplicate CreateTag = %v, want ErrAlreadyExists", err)
|
||||
}
|
||||
|
||||
// Stored row is untouched
|
||||
stored, err := s.GetActorSnapshotTag(ctx, resources.ActorSnapshotTagRef{Atespace: "team-a", Name: "production"})
|
||||
stored, err := s.GetTag(ctx, resources.TagRef{Atespace: "team-a", Name: "production"})
|
||||
if err != nil {
|
||||
t.Fatalf("GetActorSnapshotTag failed: %v", err)
|
||||
t.Fatalf("GetTag failed: %v", err)
|
||||
}
|
||||
if stored.GetMetadata().GetVersion() != 1 {
|
||||
t.Errorf("tag version after rejected create = %d, want 1", stored.GetMetadata().GetVersion())
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("CreateActorSnapshotTag_UnknownAtespace", func(t *testing.T) {
|
||||
t.Run("CreateTag_UnknownAtespace", func(t *testing.T) {
|
||||
s := setup(t)
|
||||
ctx := context.Background()
|
||||
actor := seedSuspendedActor(t, s, "team-a", "actor-1")
|
||||
|
||||
tag := newTestInProgressSnapshotTag("production", actor)
|
||||
tag := newTestInProgressTag("production", actor)
|
||||
tag.Metadata.Atespace = "team-missing"
|
||||
if _, err := s.CreateActorSnapshotTag(ctx, tag); !errors.Is(err, store.ErrFailedPrecondition) {
|
||||
t.Errorf("CreateActorSnapshotTag in an unknown atespace = %v, want ErrFailedPrecondition", err)
|
||||
if _, err := s.CreateTag(ctx, tag); !errors.Is(err, store.ErrFailedPrecondition) {
|
||||
t.Errorf("CreateTag in an unknown atespace = %v, want ErrFailedPrecondition", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("UpdateActorSnapshotTag_MissingPrecondition", func(t *testing.T) {
|
||||
t.Run("UpdateTag_MissingPrecondition", func(t *testing.T) {
|
||||
s := setup(t)
|
||||
ctx := context.Background()
|
||||
actor := seedSuspendedActor(t, s, "team-a", "actor-1")
|
||||
created := storeTag(t, s, newTestInProgressSnapshotTag("production", actor))
|
||||
created := storeTag(t, s, newTestInProgressTag("production", actor))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -1224,32 +1224,32 @@ func runActorSnapshotTagContractTests(t *testing.T, setup func(t *testing.T) sto
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := s.UpdateActorSnapshotTag(ctx, resources.ActorSnapshotTagRef{Atespace: "team-a", Name: "production"}, tt.precondition, func(toUpdate *ateapipb.ActorSnapshotTag) error {
|
||||
_, err := s.UpdateTag(ctx, resources.TagRef{Atespace: "team-a", Name: "production"}, tt.precondition, func(toUpdate *ateapipb.Tag) error {
|
||||
t.Fatal("mutate ran for a blind write")
|
||||
return nil
|
||||
})
|
||||
if !errors.Is(err, store.ErrPreconditionRequired) {
|
||||
t.Errorf("UpdateActorSnapshotTag error = %v, want one matching store.ErrPreconditionRequired", err)
|
||||
t.Errorf("UpdateTag error = %v, want one matching store.ErrPreconditionRequired", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("ListActorSnapshotTags_PaginationAndScope", func(t *testing.T) {
|
||||
t.Run("ListTags_PaginationAndScope", func(t *testing.T) {
|
||||
s := setup(t)
|
||||
ctx := context.Background()
|
||||
for _, atespace := range []string{"team-a", "team-b"} {
|
||||
actor := seedSuspendedActor(t, s, atespace, "actor-1")
|
||||
for i := 0; i < 3; i++ {
|
||||
storeTag(t, s, newTestInProgressSnapshotTag(fmt.Sprintf("tag-%d", i), actor))
|
||||
storeTag(t, s, newTestInProgressTag(fmt.Sprintf("tag-%d", i), actor))
|
||||
}
|
||||
}
|
||||
|
||||
var scoped []*ateapipb.ActorSnapshotTag
|
||||
var scoped []*ateapipb.Tag
|
||||
for token := ""; ; {
|
||||
page, err := s.ListActorSnapshotTags(ctx, "team-a", store.ListOptions{PageSize: 2, PageToken: token})
|
||||
page, err := s.ListTags(ctx, "team-a", store.ListOptions{PageSize: 2, PageToken: token})
|
||||
if err != nil {
|
||||
t.Fatalf("scoped ListActorSnapshotTags failed: %v", err)
|
||||
t.Fatalf("scoped ListTags failed: %v", err)
|
||||
}
|
||||
scoped = append(scoped, page.Items...)
|
||||
if page.NextPageToken == "" {
|
||||
@@ -1258,14 +1258,14 @@ func runActorSnapshotTagContractTests(t *testing.T, setup func(t *testing.T) sto
|
||||
token = page.NextPageToken
|
||||
}
|
||||
if len(scoped) != 3 {
|
||||
t.Errorf("scoped ListActorSnapshotTags returned %d tags, want 3", len(scoped))
|
||||
t.Errorf("scoped ListTags returned %d tags, want 3", len(scoped))
|
||||
}
|
||||
|
||||
var global []*ateapipb.ActorSnapshotTag
|
||||
var global []*ateapipb.Tag
|
||||
for token := ""; ; {
|
||||
page, err := s.ListActorSnapshotTags(ctx, "", store.ListOptions{PageSize: 2, PageToken: token})
|
||||
page, err := s.ListTags(ctx, "", store.ListOptions{PageSize: 2, PageToken: token})
|
||||
if err != nil {
|
||||
t.Fatalf("global ListActorSnapshotTags failed: %v", err)
|
||||
t.Fatalf("global ListTags failed: %v", err)
|
||||
}
|
||||
global = append(global, page.Items...)
|
||||
if page.NextPageToken == "" {
|
||||
@@ -1274,7 +1274,7 @@ func runActorSnapshotTagContractTests(t *testing.T, setup func(t *testing.T) sto
|
||||
token = page.NextPageToken
|
||||
}
|
||||
if len(global) != 6 {
|
||||
t.Errorf("global ListActorSnapshotTags returned %d tags, want 6", len(global))
|
||||
t.Errorf("global ListTags returned %d tags, want 6", len(global))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1282,7 +1282,7 @@ func runActorSnapshotTagContractTests(t *testing.T, setup func(t *testing.T) sto
|
||||
// finalizeTag mutates a reserved tag the way the tag workflow's second
|
||||
// transaction does: it names the copy that landed and clears the in-progress
|
||||
// URI, in one update.
|
||||
func finalizeTag(toUpdate *ateapipb.ActorSnapshotTag) error {
|
||||
func finalizeTag(toUpdate *ateapipb.Tag) error {
|
||||
toUpdate.Status.Snapshot = &ateapipb.ExternalSnapshot{
|
||||
SnapshotUri: toUpdate.GetStatus().GetInProgressSnapshotUri(),
|
||||
ContentScope: ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_FULL,
|
||||
@@ -1293,15 +1293,15 @@ func finalizeTag(toUpdate *ateapipb.ActorSnapshotTag) error {
|
||||
|
||||
// storeTag reserves and finalizes tag, for tests whose subject is a usable tag
|
||||
// rather than the two-phase create itself.
|
||||
func storeTag(t *testing.T, s store.Interface, tag *ateapipb.ActorSnapshotTag) *ateapipb.ActorSnapshotTag {
|
||||
func storeTag(t *testing.T, s store.Interface, tag *ateapipb.Tag) *ateapipb.Tag {
|
||||
t.Helper()
|
||||
reserved, err := s.CreateActorSnapshotTag(context.Background(), tag)
|
||||
reserved, err := s.CreateTag(context.Background(), tag)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateActorSnapshotTag(%q) failed: %v", tag.GetMetadata().GetName(), err)
|
||||
t.Fatalf("CreateTag(%q) failed: %v", tag.GetMetadata().GetName(), err)
|
||||
}
|
||||
stored, err := s.UpdateActorSnapshotTag(context.Background(), resources.ActorSnapshotTagRefFromActorSnapshotTag(reserved), store.PreconditionFrom(reserved), finalizeTag)
|
||||
stored, err := s.UpdateTag(context.Background(), resources.TagRefFromTag(reserved), store.PreconditionFrom(reserved), finalizeTag)
|
||||
if err != nil {
|
||||
t.Fatalf("finalizing actor snapshot tag %q failed: %v", tag.GetMetadata().GetName(), err)
|
||||
t.Fatalf("finalizing tag %q failed: %v", tag.GetMetadata().GetName(), err)
|
||||
}
|
||||
return stored
|
||||
}
|
||||
@@ -2889,7 +2889,7 @@ func runUnknownFieldContractTests(t *testing.T, setup func(t *testing.T) store.I
|
||||
assertPruned(t, "DeleteEgressPolicy", created, deleted)
|
||||
})
|
||||
|
||||
t.Run("UnknownFields_ActorSnapshotTag", func(t *testing.T) {
|
||||
t.Run("UnknownFields_Tag", func(t *testing.T) {
|
||||
s := setup(t)
|
||||
ctx := context.Background()
|
||||
mustCreateAtespace(t, s, testAtespace)
|
||||
@@ -2898,41 +2898,41 @@ func runUnknownFieldContractTests(t *testing.T, setup func(t *testing.T) store.I
|
||||
t.Fatalf("CreateActor failed: %v", err)
|
||||
}
|
||||
|
||||
tagRef := resources.ActorSnapshotTagRef{Atespace: testAtespace, Name: "production"}
|
||||
tag := withUnknownField(newTestInProgressSnapshotTag(tagRef.Name, actor))
|
||||
tagRef := resources.TagRef{Atespace: testAtespace, Name: "production"}
|
||||
tag := withUnknownField(newTestInProgressTag(tagRef.Name, actor))
|
||||
withUnknownField(tag.Metadata)
|
||||
withUnknownField(tag.Status)
|
||||
created, err := s.CreateActorSnapshotTag(ctx, tag)
|
||||
created, err := s.CreateTag(ctx, tag)
|
||||
if err != nil {
|
||||
t.Fatalf("CreateActorSnapshotTag failed: %v", err)
|
||||
t.Fatalf("CreateTag failed: %v", err)
|
||||
}
|
||||
|
||||
got, err := s.GetActorSnapshotTag(ctx, tagRef)
|
||||
got, err := s.GetTag(ctx, tagRef)
|
||||
if err != nil {
|
||||
t.Fatalf("GetActorSnapshotTag failed: %v", err)
|
||||
t.Fatalf("GetTag failed: %v", err)
|
||||
}
|
||||
assertPruned(t, "GetActorSnapshotTag", created, got)
|
||||
assertPruned(t, "GetTag", created, got)
|
||||
|
||||
list, err := s.ListActorSnapshotTags(ctx, testAtespace, store.ListOptions{})
|
||||
list, err := s.ListTags(ctx, testAtespace, store.ListOptions{})
|
||||
if err != nil || len(list.Items) != 1 {
|
||||
t.Fatalf("ListActorSnapshotTags = %d items, %v; want 1", len(list.Items), err)
|
||||
t.Fatalf("ListTags = %d items, %v; want 1", len(list.Items), err)
|
||||
}
|
||||
assertPruned(t, "ListActorSnapshotTags", created, list.Items[0])
|
||||
assertPruned(t, "ListTags", created, list.Items[0])
|
||||
|
||||
updated, err := s.UpdateActorSnapshotTag(ctx, tagRef, store.PreconditionFrom(got), func(toUpdate *ateapipb.ActorSnapshotTag) error {
|
||||
requireNoUnknownFields(t, "UpdateActorSnapshotTag mutation input", toUpdate)
|
||||
updated, err := s.UpdateTag(ctx, tagRef, store.PreconditionFrom(got), func(toUpdate *ateapipb.Tag) error {
|
||||
requireNoUnknownFields(t, "UpdateTag mutation input", toUpdate)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("UpdateActorSnapshotTag failed: %v", err)
|
||||
t.Fatalf("UpdateTag failed: %v", err)
|
||||
}
|
||||
assertPruned(t, "UpdateActorSnapshotTag", created, updated)
|
||||
assertPruned(t, "UpdateTag", created, updated)
|
||||
|
||||
deleted, err := s.DeleteActorSnapshotTag(ctx, tagRef)
|
||||
deleted, err := s.DeleteTag(ctx, tagRef)
|
||||
if err != nil {
|
||||
t.Fatalf("DeleteActorSnapshotTag failed: %v", err)
|
||||
t.Fatalf("DeleteTag failed: %v", err)
|
||||
}
|
||||
assertPruned(t, "DeleteActorSnapshotTag", created, deleted)
|
||||
assertPruned(t, "DeleteTag", created, deleted)
|
||||
})
|
||||
|
||||
t.Run("UnknownFields_Atespace", func(t *testing.T) {
|
||||
|
||||
@@ -108,18 +108,18 @@ func MustCreateActor(t *testing.T, ctx context.Context, s store.Interface, actor
|
||||
return created
|
||||
}
|
||||
|
||||
// MustCreateActorSnapshotTag ensures tag's parent atespace exists, then stores
|
||||
// MustCreateTag ensures tag's parent atespace exists, then stores
|
||||
// tag as given — ready or still pending, whichever state the test needs to
|
||||
// start from. Use the store method directly only in tests that exercise
|
||||
// missing-parent behavior.
|
||||
func MustCreateActorSnapshotTag(t *testing.T, ctx context.Context, s store.Interface, tag *ateapipb.ActorSnapshotTag) *ateapipb.ActorSnapshotTag {
|
||||
func MustCreateTag(t *testing.T, ctx context.Context, s store.Interface, tag *ateapipb.Tag) *ateapipb.Tag {
|
||||
t.Helper()
|
||||
atespace := tag.GetMetadata().GetAtespace()
|
||||
name := tag.GetMetadata().GetName()
|
||||
MustCreateAtespace(t, ctx, s, atespace)
|
||||
created, err := s.CreateActorSnapshotTag(ctx, tag)
|
||||
created, err := s.CreateTag(ctx, tag)
|
||||
if err != nil {
|
||||
t.Fatalf("creating test actor snapshot tag %q/%q: %v", atespace, name, err)
|
||||
t.Fatalf("creating test tag %q/%q: %v", atespace, name, err)
|
||||
}
|
||||
return created
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ kubectl ate get atespace <atespace>
|
||||
kubectl ate delete atespace <atespace>
|
||||
```
|
||||
|
||||
> **Note:** `create actor … -a <atespace>` requires the atespace to already exist, otherwise it fails with `FailedPrecondition`. `delete atespace` only removes an **empty** atespace; delete its actors and snapshot tags first (cascade delete is not yet supported).
|
||||
> **Note:** `create actor … -a <atespace>` requires the atespace to already exist, otherwise it fails with `FailedPrecondition`. `delete atespace` only removes an **empty** atespace; delete its actors and tags first (cascade delete is not yet supported).
|
||||
|
||||
#### `kubectl ate get atespace` output columns
|
||||
|
||||
@@ -220,18 +220,18 @@ so suspending or deleting the actor afterwards cannot collect it.
|
||||
|
||||
```bash
|
||||
# List an Atespace's tags, all Atespaces' tags, or resolve tags by name.
|
||||
kubectl ate get snapshot-tags -a <atespace>
|
||||
kubectl ate get snapshot-tags -A
|
||||
kubectl ate get snapshot-tag <tag-name> [<tag-name> ...] -a <atespace>
|
||||
kubectl ate get tags -a <atespace>
|
||||
kubectl ate get tags -A
|
||||
kubectl ate get tag <tag-name> [<tag-name> ...] -a <atespace>
|
||||
|
||||
# Tag the snapshot a suspended actor holds, then publish or unpublish the tag.
|
||||
kubectl ate create snapshot-tag <tag-name> -a <atespace> --actor <actor-name> [--scope published]
|
||||
kubectl ate update snapshot-tag <tag-name> -a <atespace> --scope published
|
||||
kubectl ate update snapshot-tag <tag-name> -a <atespace> --scope atespace
|
||||
kubectl ate create tag <tag-name> -a <atespace> --actor <actor-name> [--scope published]
|
||||
kubectl ate update tag <tag-name> -a <atespace> --scope published
|
||||
kubectl ate update tag <tag-name> -a <atespace> --scope atespace
|
||||
|
||||
# Create an actor from a tag and remove the tag when it is no longer needed.
|
||||
kubectl ate create actor <actor-name> -a <atespace> --template-ref <template-name> --snapshot-tag <tag-atespace/tag-name>
|
||||
kubectl ate delete snapshot-tag <tag-name> -a <atespace>
|
||||
kubectl ate create actor <actor-name> -a <atespace> --template-ref <template-name> --tag <tag-atespace/tag-name>
|
||||
kubectl ate delete tag <tag-name> -a <atespace>
|
||||
```
|
||||
|
||||
### Logs
|
||||
|
||||
@@ -1,235 +0,0 @@
|
||||
// Copyright 2026 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/agent-substrate/substrate/cmd/kubectl-ate/internal/printer"
|
||||
"github.com/agent-substrate/substrate/internal/ateclient"
|
||||
"github.com/agent-substrate/substrate/pkg/proto/ateapipb"
|
||||
"github.com/spf13/cobra"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
var (
|
||||
tagAtespaceFlag string
|
||||
tagAllAtespacesFlag bool
|
||||
createTagAtespaceFlag string
|
||||
createTagActorFlag string
|
||||
createTagScopeFlag string
|
||||
updateTagAtespaceFlag string
|
||||
updateTagScopeFlag string
|
||||
deleteTagAtespaceFlag string
|
||||
)
|
||||
|
||||
var updateCmd = &cobra.Command{Use: "update", Short: "Update a resource"}
|
||||
|
||||
var getActorSnapshotTagsCmd = &cobra.Command{
|
||||
Use: "actor-snapshot-tags [tag-name ...]",
|
||||
Aliases: []string{"actor-snapshot-tag", "snapshot-tags", "snapshot-tag"},
|
||||
Short: "List or get actor snapshot tags",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if tagAllAtespacesFlag && tagAtespaceFlag != "" {
|
||||
return fmt.Errorf("--atespace and -A/--all-atespaces are mutually exclusive")
|
||||
}
|
||||
if len(args) > 0 && tagAtespaceFlag == "" {
|
||||
return fmt.Errorf("--atespace is required when getting snapshot tags")
|
||||
}
|
||||
if len(args) == 0 && !tagAllAtespacesFlag && tagAtespaceFlag == "" {
|
||||
return fmt.Errorf("specify --atespace <name>, or -A/--all-atespaces")
|
||||
}
|
||||
|
||||
ctx := cmd.Context()
|
||||
client, err := ateclient.NewClient(ctx, kubeconfig, k8sContext, endpoint, tokenFile, traceEnabled)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to ate-api-server: %w", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
var tags []*ateapipb.ActorSnapshotTag
|
||||
if len(args) > 0 {
|
||||
for _, name := range args {
|
||||
tag, err := client.GetActorSnapshotTag(ctx, &ateapipb.GetActorSnapshotTagRequest{
|
||||
ActorSnapshotTag: &ateapipb.ObjectRef{Atespace: tagAtespaceFlag, Name: name},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get actor snapshot tag %q: %w", name, err)
|
||||
}
|
||||
tags = append(tags, tag)
|
||||
}
|
||||
} else {
|
||||
pageToken := ""
|
||||
for {
|
||||
resp, err := client.ListActorSnapshotTags(ctx, &ateapipb.ListActorSnapshotTagsRequest{Atespace: tagAtespaceFlag, PageSize: 1000, PageToken: pageToken})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list actor snapshot tags: %w", err)
|
||||
}
|
||||
tags = append(tags, resp.GetActorSnapshotTags()...)
|
||||
pageToken = resp.GetNextPageToken()
|
||||
if pageToken == "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return printer.PrintActorSnapshotTags(tags, outputFmt)
|
||||
},
|
||||
}
|
||||
|
||||
var createActorSnapshotTagCmd = &cobra.Command{
|
||||
Use: "actor-snapshot-tag <tag-name>",
|
||||
Aliases: []string{"snapshot-tag"},
|
||||
Short: "Tag the external snapshot a suspended actor holds",
|
||||
Long: "Tag the external snapshot a suspended actor holds.\n\n" +
|
||||
"The tag gets its own copy of that snapshot, so suspending the actor\n" +
|
||||
"again or deleting it cannot collect what the tag names.",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
scope, err := parseActorSnapshotTagScope(createTagScopeFlag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx := cmd.Context()
|
||||
client, err := ateclient.NewClient(ctx, kubeconfig, k8sContext, endpoint, tokenFile, traceEnabled)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to ate-api-server: %w", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
tag, err := client.CreateActorSnapshotTag(ctx, &ateapipb.CreateActorSnapshotTagRequest{
|
||||
ActorSnapshotTag: &ateapipb.ActorSnapshotTag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: createTagAtespaceFlag, Name: args[0]},
|
||||
Scope: scope,
|
||||
SourceActor: &ateapipb.ObjectRef{Atespace: createTagAtespaceFlag, Name: createTagActorFlag},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create actor snapshot tag: %w", err)
|
||||
}
|
||||
return printer.PrintActorSnapshotTag(tag, outputFmt)
|
||||
},
|
||||
}
|
||||
|
||||
var updateActorSnapshotTagCmd = &cobra.Command{
|
||||
Use: "actor-snapshot-tag <tag-name>",
|
||||
Aliases: []string{"snapshot-tag"},
|
||||
Short: "Publish or unpublish an actor snapshot tag",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
scope, err := parseActorSnapshotTagScope(updateTagScopeFlag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx := cmd.Context()
|
||||
client, err := ateclient.NewClient(ctx, kubeconfig, k8sContext, endpoint, tokenFile, traceEnabled)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to ate-api-server: %w", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
ref := &ateapipb.ObjectRef{Atespace: updateTagAtespaceFlag, Name: args[0]}
|
||||
resp, err := updateActorSnapshotTagScope(ctx, client, ref, scope)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printer.PrintActorSnapshotTag(resp, outputFmt)
|
||||
},
|
||||
}
|
||||
|
||||
var deleteActorSnapshotTagCmd = &cobra.Command{
|
||||
Use: "actor-snapshot-tag <tag-name>",
|
||||
Aliases: []string{"snapshot-tag"},
|
||||
Short: "Delete an actor snapshot tag",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
client, err := ateclient.NewClient(ctx, kubeconfig, k8sContext, endpoint, tokenFile, traceEnabled)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to ate-api-server: %w", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
_, err = client.DeleteActorSnapshotTag(ctx, &ateapipb.DeleteActorSnapshotTagRequest{ActorSnapshotTag: &ateapipb.ObjectRef{Atespace: deleteTagAtespaceFlag, Name: args[0]}})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete actor snapshot tag: %w", err)
|
||||
}
|
||||
fmt.Printf("actor snapshot tag %q deleted\n", args[0])
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
type actorSnapshotTagClient interface {
|
||||
GetActorSnapshotTag(ctx context.Context, in *ateapipb.GetActorSnapshotTagRequest, opts ...grpc.CallOption) (*ateapipb.ActorSnapshotTag, error)
|
||||
UpdateActorSnapshotTag(ctx context.Context, in *ateapipb.UpdateActorSnapshotTagRequest, opts ...grpc.CallOption) (*ateapipb.ActorSnapshotTag, error)
|
||||
}
|
||||
|
||||
func updateActorSnapshotTagScope(ctx context.Context, client actorSnapshotTagClient, ref *ateapipb.ObjectRef, scope ateapipb.ActorSnapshotTagScope) (*ateapipb.ActorSnapshotTag, error) {
|
||||
tag, err := client.GetActorSnapshotTag(ctx, &ateapipb.GetActorSnapshotTagRequest{ActorSnapshotTag: ref})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get actor snapshot tag %q: %w", ref.GetName(), err)
|
||||
}
|
||||
tag.Scope = scope
|
||||
|
||||
resp, err := client.UpdateActorSnapshotTag(ctx, &ateapipb.UpdateActorSnapshotTagRequest{ActorSnapshotTag: tag})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update actor snapshot tag: %w", err)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func parseActorSnapshotTagScope(value string) (ateapipb.ActorSnapshotTagScope, error) {
|
||||
switch strings.ToLower(value) {
|
||||
case "atespace":
|
||||
return ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE, nil
|
||||
case "published":
|
||||
return ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED, nil
|
||||
default:
|
||||
return ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED, fmt.Errorf("invalid scope %q; must be atespace or published", value)
|
||||
}
|
||||
}
|
||||
|
||||
func parseNamespacedName(value string) (*ateapipb.ObjectRef, error) {
|
||||
atespace, name, ok := strings.Cut(value, "/")
|
||||
if !ok || atespace == "" || name == "" || strings.Contains(name, "/") {
|
||||
return nil, fmt.Errorf("malformed reference %q (expected <atespace>/<name>)", value)
|
||||
}
|
||||
return &ateapipb.ObjectRef{Atespace: atespace, Name: name}, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
getActorSnapshotTagsCmd.Flags().StringVarP(&tagAtespaceFlag, "atespace", "a", "", "Atespace to list/get snapshot tags in")
|
||||
getActorSnapshotTagsCmd.Flags().BoolVarP(&tagAllAtespacesFlag, "all-atespaces", "A", false, "List snapshot tags across all atespaces")
|
||||
getCmd.AddCommand(getActorSnapshotTagsCmd)
|
||||
|
||||
createActorSnapshotTagCmd.Flags().StringVarP(&createTagAtespaceFlag, "atespace", "a", "", "Atespace the actor lives in; the tag is created here (required)")
|
||||
_ = createActorSnapshotTagCmd.MarkFlagRequired("atespace")
|
||||
createActorSnapshotTagCmd.Flags().StringVar(&createTagActorFlag, "actor", "", "Name of the suspended actor whose external snapshot to tag (required)")
|
||||
_ = createActorSnapshotTagCmd.MarkFlagRequired("actor")
|
||||
createActorSnapshotTagCmd.Flags().StringVar(&createTagScopeFlag, "scope", "atespace", "Tag scope: atespace or published")
|
||||
createCmd.AddCommand(createActorSnapshotTagCmd)
|
||||
|
||||
rootCmd.AddCommand(updateCmd)
|
||||
updateActorSnapshotTagCmd.Flags().StringVarP(&updateTagAtespaceFlag, "atespace", "a", "", "Atespace owning the tag (required)")
|
||||
updateActorSnapshotTagCmd.Flags().StringVar(&updateTagScopeFlag, "scope", "", "Tag scope: atespace or published (required)")
|
||||
_ = updateActorSnapshotTagCmd.MarkFlagRequired("atespace")
|
||||
_ = updateActorSnapshotTagCmd.MarkFlagRequired("scope")
|
||||
updateCmd.AddCommand(updateActorSnapshotTagCmd)
|
||||
|
||||
deleteActorSnapshotTagCmd.Flags().StringVarP(&deleteTagAtespaceFlag, "atespace", "a", "", "Atespace owning the tag (required)")
|
||||
_ = deleteActorSnapshotTagCmd.MarkFlagRequired("atespace")
|
||||
deleteCmd.AddCommand(deleteActorSnapshotTagCmd)
|
||||
}
|
||||
@@ -25,14 +25,14 @@ import (
|
||||
|
||||
var templateRefFlag string
|
||||
var atespaceFlag string
|
||||
var sourceSnapshotTagFlag string
|
||||
var sourceTagFlag string
|
||||
|
||||
var createActorCmd = &cobra.Command{
|
||||
Use: "actor <actor-name>",
|
||||
Short: "Create an actor",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
request, err := buildCreateActorRequest(args[0], atespaceFlag, templateRefFlag, sourceSnapshotTagFlag)
|
||||
request, err := buildCreateActorRequest(args[0], atespaceFlag, templateRefFlag, sourceTagFlag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -55,7 +55,7 @@ var createActorCmd = &cobra.Command{
|
||||
|
||||
// buildCreateActorRequest assembles the CreateActor request from the command
|
||||
// flags.
|
||||
func buildCreateActorRequest(actorName, atespace, templateName, snapshotTag string) (*ateapipb.CreateActorRequest, error) {
|
||||
func buildCreateActorRequest(actorName, atespace, templateName, tag string) (*ateapipb.CreateActorRequest, error) {
|
||||
actor := &ateapipb.Actor{
|
||||
Metadata: &ateapipb.ResourceMetadata{
|
||||
Atespace: atespace,
|
||||
@@ -67,12 +67,12 @@ func buildCreateActorRequest(actorName, atespace, templateName, snapshotTag stri
|
||||
},
|
||||
}
|
||||
|
||||
if snapshotTag != "" {
|
||||
ref, err := parseNamespacedName(snapshotTag)
|
||||
if tag != "" {
|
||||
ref, err := parseNamespacedName(tag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
actor.SourceSnapshotTag = ref
|
||||
actor.SourceTag = ref
|
||||
}
|
||||
return &ateapipb.CreateActorRequest{Actor: actor}, nil
|
||||
}
|
||||
@@ -83,6 +83,6 @@ func init() {
|
||||
_ = createActorCmd.MarkFlagRequired("template-ref")
|
||||
createActorCmd.Flags().StringVarP(&atespaceFlag, "atespace", "a", "", "Atespace to create the actor in (required)")
|
||||
_ = createActorCmd.MarkFlagRequired("atespace")
|
||||
createActorCmd.Flags().StringVar(&sourceSnapshotTagFlag, "snapshot-tag", "", "Initialize from an ActorSnapshotTag in <atespace>/<name> format")
|
||||
createActorCmd.Flags().StringVar(&sourceTagFlag, "tag", "", "Initialize from a Tag in <atespace>/<name> format")
|
||||
createCmd.AddCommand(createActorCmd)
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ func TestBuildCreateActorRequest(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
templateRef string
|
||||
snapshotTag string
|
||||
tag string
|
||||
want *ateapipb.Actor
|
||||
wantErr bool
|
||||
}{
|
||||
@@ -39,21 +39,21 @@ func TestBuildCreateActorRequest(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "template ref with snapshot tag",
|
||||
name: "template ref with tag",
|
||||
templateRef: "counter",
|
||||
snapshotTag: "demo/before-upgrade",
|
||||
tag: "demo/before-upgrade",
|
||||
want: &ateapipb.Actor{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: "demo", Name: "my-counter"},
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: "demo", Name: "counter"},
|
||||
SourceSnapshotTag: &ateapipb.ObjectRef{Atespace: "demo", Name: "before-upgrade"},
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: "demo", Name: "my-counter"},
|
||||
ActorTemplate: &ateapipb.ObjectRef{Atespace: "demo", Name: "counter"},
|
||||
SourceTag: &ateapipb.ObjectRef{Atespace: "demo", Name: "before-upgrade"},
|
||||
},
|
||||
},
|
||||
{name: "malformed snapshot tag", templateRef: "counter", snapshotTag: "before-upgrade", wantErr: true},
|
||||
{name: "malformed tag", templateRef: "counter", tag: "before-upgrade", wantErr: true},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
got, err := buildCreateActorRequest("my-counter", "demo", test.templateRef, test.snapshotTag)
|
||||
got, err := buildCreateActorRequest("my-counter", "demo", test.templateRef, test.tag)
|
||||
if (err != nil) != test.wantErr {
|
||||
t.Fatalf("buildCreateActorRequest error = %v, wantErr %t", err, test.wantErr)
|
||||
}
|
||||
|
||||
@@ -57,11 +57,11 @@ func TestGetCommandArgs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestParseActorSnapshotFlags(t *testing.T) {
|
||||
if got, err := parseActorSnapshotTagScope("published"); err != nil || got != ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED {
|
||||
t.Fatalf("parseActorSnapshotTagScope(published) = (%v, %v)", got, err)
|
||||
if got, err := parseTagScope("published"); err != nil || got != ateapipb.TagScope_TAG_SCOPE_PUBLISHED {
|
||||
t.Fatalf("parseTagScope(published) = (%v, %v)", got, err)
|
||||
}
|
||||
if _, err := parseActorSnapshotTagScope("global"); err == nil {
|
||||
t.Fatal("parseActorSnapshotTagScope(global) succeeded")
|
||||
if _, err := parseTagScope("global"); err == nil {
|
||||
t.Fatal("parseTagScope(global) succeeded")
|
||||
}
|
||||
ref, err := parseNamespacedName("team-a/before-upgrade")
|
||||
if err != nil || ref.GetAtespace() != "team-a" || ref.GetName() != "before-upgrade" {
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
// Copyright 2026 Google LLC
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/agent-substrate/substrate/cmd/kubectl-ate/internal/printer"
|
||||
"github.com/agent-substrate/substrate/internal/ateclient"
|
||||
"github.com/agent-substrate/substrate/pkg/proto/ateapipb"
|
||||
"github.com/spf13/cobra"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
var (
|
||||
tagAtespaceFlag string
|
||||
tagAllAtespacesFlag bool
|
||||
createTagAtespaceFlag string
|
||||
createTagActorFlag string
|
||||
createTagScopeFlag string
|
||||
updateTagAtespaceFlag string
|
||||
updateTagScopeFlag string
|
||||
deleteTagAtespaceFlag string
|
||||
)
|
||||
|
||||
var updateCmd = &cobra.Command{Use: "update", Short: "Update a resource"}
|
||||
|
||||
var getTagsCmd = &cobra.Command{
|
||||
Use: "tags [tag-name ...]",
|
||||
Aliases: []string{"tag"},
|
||||
Short: "List or get tags",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if tagAllAtespacesFlag && tagAtespaceFlag != "" {
|
||||
return fmt.Errorf("--atespace and -A/--all-atespaces are mutually exclusive")
|
||||
}
|
||||
if len(args) > 0 && tagAtespaceFlag == "" {
|
||||
return fmt.Errorf("--atespace is required when getting tags")
|
||||
}
|
||||
if len(args) == 0 && !tagAllAtespacesFlag && tagAtespaceFlag == "" {
|
||||
return fmt.Errorf("specify --atespace <name>, or -A/--all-atespaces")
|
||||
}
|
||||
|
||||
ctx := cmd.Context()
|
||||
client, err := ateclient.NewClient(ctx, kubeconfig, k8sContext, endpoint, tokenFile, traceEnabled)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to ate-api-server: %w", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
var tags []*ateapipb.Tag
|
||||
if len(args) > 0 {
|
||||
for _, name := range args {
|
||||
tag, err := client.GetTag(ctx, &ateapipb.GetTagRequest{
|
||||
Tag: &ateapipb.ObjectRef{Atespace: tagAtespaceFlag, Name: name},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get tag %q: %w", name, err)
|
||||
}
|
||||
tags = append(tags, tag)
|
||||
}
|
||||
} else {
|
||||
pageToken := ""
|
||||
for {
|
||||
resp, err := client.ListTags(ctx, &ateapipb.ListTagsRequest{Atespace: tagAtespaceFlag, PageSize: 1000, PageToken: pageToken})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to list tags: %w", err)
|
||||
}
|
||||
tags = append(tags, resp.GetTags()...)
|
||||
pageToken = resp.GetNextPageToken()
|
||||
if pageToken == "" {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return printer.PrintTags(tags, outputFmt)
|
||||
},
|
||||
}
|
||||
|
||||
var createTagCmd = &cobra.Command{
|
||||
Use: "tag <tag-name>",
|
||||
Aliases: []string{"tags"},
|
||||
Short: "Tag the external snapshot a suspended actor holds",
|
||||
Long: "Tag the external snapshot a suspended actor holds.\n\n" +
|
||||
"The tag gets its own copy of that snapshot, so suspending the actor\n" +
|
||||
"again or deleting it cannot collect what the tag names.",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
scope, err := parseTagScope(createTagScopeFlag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx := cmd.Context()
|
||||
client, err := ateclient.NewClient(ctx, kubeconfig, k8sContext, endpoint, tokenFile, traceEnabled)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to ate-api-server: %w", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
tag, err := client.CreateTag(ctx, &ateapipb.CreateTagRequest{
|
||||
Tag: &ateapipb.Tag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: createTagAtespaceFlag, Name: args[0]},
|
||||
Scope: scope,
|
||||
SourceActor: &ateapipb.ObjectRef{Atespace: createTagAtespaceFlag, Name: createTagActorFlag},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create tag: %w", err)
|
||||
}
|
||||
return printer.PrintTag(tag, outputFmt)
|
||||
},
|
||||
}
|
||||
|
||||
var updateTagCmd = &cobra.Command{
|
||||
Use: "tag <tag-name>",
|
||||
Aliases: []string{"tags"},
|
||||
Short: "Publish or unpublish a tag",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
scope, err := parseTagScope(updateTagScopeFlag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ctx := cmd.Context()
|
||||
client, err := ateclient.NewClient(ctx, kubeconfig, k8sContext, endpoint, tokenFile, traceEnabled)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to ate-api-server: %w", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
ref := &ateapipb.ObjectRef{Atespace: updateTagAtespaceFlag, Name: args[0]}
|
||||
resp, err := updateTagScope(ctx, client, ref, scope)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return printer.PrintTag(resp, outputFmt)
|
||||
},
|
||||
}
|
||||
|
||||
var deleteTagCmd = &cobra.Command{
|
||||
Use: "tag <tag-name>",
|
||||
Aliases: []string{"tags"},
|
||||
Short: "Delete a tag",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
client, err := ateclient.NewClient(ctx, kubeconfig, k8sContext, endpoint, tokenFile, traceEnabled)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to ate-api-server: %w", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
_, err = client.DeleteTag(ctx, &ateapipb.DeleteTagRequest{Tag: &ateapipb.ObjectRef{Atespace: deleteTagAtespaceFlag, Name: args[0]}})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete tag: %w", err)
|
||||
}
|
||||
fmt.Printf("tag %q deleted\n", args[0])
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
type tagClient interface {
|
||||
GetTag(ctx context.Context, in *ateapipb.GetTagRequest, opts ...grpc.CallOption) (*ateapipb.Tag, error)
|
||||
UpdateTag(ctx context.Context, in *ateapipb.UpdateTagRequest, opts ...grpc.CallOption) (*ateapipb.Tag, error)
|
||||
}
|
||||
|
||||
func updateTagScope(ctx context.Context, client tagClient, ref *ateapipb.ObjectRef, scope ateapipb.TagScope) (*ateapipb.Tag, error) {
|
||||
tag, err := client.GetTag(ctx, &ateapipb.GetTagRequest{Tag: ref})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get tag %q: %w", ref.GetName(), err)
|
||||
}
|
||||
tag.Scope = scope
|
||||
|
||||
resp, err := client.UpdateTag(ctx, &ateapipb.UpdateTagRequest{Tag: tag})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to update tag: %w", err)
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func parseTagScope(value string) (ateapipb.TagScope, error) {
|
||||
switch strings.ToLower(value) {
|
||||
case "atespace":
|
||||
return ateapipb.TagScope_TAG_SCOPE_ATESPACE, nil
|
||||
case "published":
|
||||
return ateapipb.TagScope_TAG_SCOPE_PUBLISHED, nil
|
||||
default:
|
||||
return ateapipb.TagScope_TAG_SCOPE_UNSPECIFIED, fmt.Errorf("invalid scope %q; must be atespace or published", value)
|
||||
}
|
||||
}
|
||||
|
||||
func parseNamespacedName(value string) (*ateapipb.ObjectRef, error) {
|
||||
atespace, name, ok := strings.Cut(value, "/")
|
||||
if !ok || atespace == "" || name == "" || strings.Contains(name, "/") {
|
||||
return nil, fmt.Errorf("malformed reference %q (expected <atespace>/<name>)", value)
|
||||
}
|
||||
return &ateapipb.ObjectRef{Atespace: atespace, Name: name}, nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
getTagsCmd.Flags().StringVarP(&tagAtespaceFlag, "atespace", "a", "", "Atespace to list/get tags in")
|
||||
getTagsCmd.Flags().BoolVarP(&tagAllAtespacesFlag, "all-atespaces", "A", false, "List tags across all atespaces")
|
||||
getCmd.AddCommand(getTagsCmd)
|
||||
|
||||
createTagCmd.Flags().StringVarP(&createTagAtespaceFlag, "atespace", "a", "", "Atespace the actor lives in; the tag is created here (required)")
|
||||
_ = createTagCmd.MarkFlagRequired("atespace")
|
||||
createTagCmd.Flags().StringVar(&createTagActorFlag, "actor", "", "Name of the suspended actor whose external snapshot to tag (required)")
|
||||
_ = createTagCmd.MarkFlagRequired("actor")
|
||||
createTagCmd.Flags().StringVar(&createTagScopeFlag, "scope", "atespace", "Tag scope: atespace or published")
|
||||
createCmd.AddCommand(createTagCmd)
|
||||
|
||||
rootCmd.AddCommand(updateCmd)
|
||||
updateTagCmd.Flags().StringVarP(&updateTagAtespaceFlag, "atespace", "a", "", "Atespace owning the tag (required)")
|
||||
updateTagCmd.Flags().StringVar(&updateTagScopeFlag, "scope", "", "Tag scope: atespace or published (required)")
|
||||
_ = updateTagCmd.MarkFlagRequired("atespace")
|
||||
_ = updateTagCmd.MarkFlagRequired("scope")
|
||||
updateCmd.AddCommand(updateTagCmd)
|
||||
|
||||
deleteTagCmd.Flags().StringVarP(&deleteTagAtespaceFlag, "atespace", "a", "", "Atespace owning the tag (required)")
|
||||
_ = deleteTagCmd.MarkFlagRequired("atespace")
|
||||
deleteCmd.AddCommand(deleteTagCmd)
|
||||
}
|
||||
+17
-17
@@ -25,56 +25,56 @@ import (
|
||||
"google.golang.org/protobuf/testing/protocmp"
|
||||
)
|
||||
|
||||
// fakeTagClient serves GetActorSnapshotTag from a stored tag and records the
|
||||
// fakeTagClient serves GetTag from a stored tag and records the
|
||||
// update it is asked to make.
|
||||
type fakeTagClient struct {
|
||||
tag *ateapipb.ActorSnapshotTag
|
||||
tag *ateapipb.Tag
|
||||
|
||||
getCalls int
|
||||
updateReq *ateapipb.UpdateActorSnapshotTagRequest
|
||||
updateReq *ateapipb.UpdateTagRequest
|
||||
}
|
||||
|
||||
func (f *fakeTagClient) GetActorSnapshotTag(_ context.Context, _ *ateapipb.GetActorSnapshotTagRequest, _ ...grpc.CallOption) (*ateapipb.ActorSnapshotTag, error) {
|
||||
func (f *fakeTagClient) GetTag(_ context.Context, _ *ateapipb.GetTagRequest, _ ...grpc.CallOption) (*ateapipb.Tag, error) {
|
||||
f.getCalls++
|
||||
return proto.Clone(f.tag).(*ateapipb.ActorSnapshotTag), nil
|
||||
return proto.Clone(f.tag).(*ateapipb.Tag), nil
|
||||
}
|
||||
|
||||
func (f *fakeTagClient) UpdateActorSnapshotTag(_ context.Context, in *ateapipb.UpdateActorSnapshotTagRequest, _ ...grpc.CallOption) (*ateapipb.ActorSnapshotTag, error) {
|
||||
func (f *fakeTagClient) UpdateTag(_ context.Context, in *ateapipb.UpdateTagRequest, _ ...grpc.CallOption) (*ateapipb.Tag, error) {
|
||||
f.updateReq = in
|
||||
// Bump the version the way a real server does, so the returned tag is
|
||||
// distinguishable from the one the caller sent.
|
||||
updated := proto.Clone(in.GetActorSnapshotTag()).(*ateapipb.ActorSnapshotTag)
|
||||
updated := proto.Clone(in.GetTag()).(*ateapipb.Tag)
|
||||
updated.Metadata.Version++
|
||||
return updated, nil
|
||||
}
|
||||
|
||||
// TestUpdateActorSnapshotTagScope checks the read-modify-write wiring: the scope
|
||||
// TestUpdateTagScope checks the read-modify-write wiring: the scope
|
||||
// change is written against the uid and version that were just read.
|
||||
func TestUpdateActorSnapshotTagScope(t *testing.T) {
|
||||
testTag := &ateapipb.ActorSnapshotTag{
|
||||
func TestUpdateTagScope(t *testing.T) {
|
||||
testTag := &ateapipb.Tag{
|
||||
Metadata: &ateapipb.ResourceMetadata{
|
||||
Atespace: "space-1",
|
||||
Name: "tag-1",
|
||||
Uid: "8ba9b6ee-2e1a-4c0f-9f4e-2f0a0f1c3d55",
|
||||
Version: 1,
|
||||
},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE,
|
||||
Status: &ateapipb.ActorSnapshotTagStatus{
|
||||
Snapshot: &ateapipb.ExternalSnapshot{SnapshotUri: "gs://private/atespaces/space-1/actor-snapshot-tags/tag-1"},
|
||||
Scope: ateapipb.TagScope_TAG_SCOPE_ATESPACE,
|
||||
Status: &ateapipb.TagStatus{
|
||||
Snapshot: &ateapipb.ExternalSnapshot{SnapshotUri: "gs://private/atespaces/space-1/tags/tag-1"},
|
||||
},
|
||||
}
|
||||
|
||||
client := &fakeTagClient{tag: testTag}
|
||||
ref := &ateapipb.ObjectRef{Atespace: "space-1", Name: "tag-1"}
|
||||
want := ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED
|
||||
want := ateapipb.TagScope_TAG_SCOPE_PUBLISHED
|
||||
|
||||
resp, err := updateActorSnapshotTagScope(context.Background(), client, ref, want)
|
||||
resp, err := updateTagScope(context.Background(), client, ref, want)
|
||||
if err != nil {
|
||||
t.Fatalf("updateActorSnapshotTagScope() error = %v", err)
|
||||
t.Fatalf("updateTagScope() error = %v", err)
|
||||
}
|
||||
|
||||
if client.getCalls != 1 {
|
||||
t.Errorf("GetActorSnapshotTag called %d times, want 1", client.getCalls)
|
||||
t.Errorf("GetTag called %d times, want 1", client.getCalls)
|
||||
}
|
||||
|
||||
wantResp := testTag
|
||||
@@ -286,16 +286,16 @@ func PrintActorTemplate(template *ateapipb.ActorTemplate, format string) error {
|
||||
return PrintActorTemplates([]*ateapipb.ActorTemplate{template}, format)
|
||||
}
|
||||
|
||||
// PrintActorSnapshotTags prints actor snapshot tags to stdout in the requested
|
||||
// PrintTags prints tags to stdout in the requested
|
||||
// format.
|
||||
func PrintActorSnapshotTags(tags []*ateapipb.ActorSnapshotTag, format string) error {
|
||||
return PrintActorSnapshotTagsTo(os.Stdout, tags, format)
|
||||
func PrintTags(tags []*ateapipb.Tag, format string) error {
|
||||
return PrintTagsTo(os.Stdout, tags, format)
|
||||
}
|
||||
|
||||
// PrintActorSnapshotTagsTo prints a slice of actor snapshot tags to the
|
||||
// PrintTagsTo prints a slice of tags to the
|
||||
// provided writer.
|
||||
func PrintActorSnapshotTagsTo(out io.Writer, tags []*ateapipb.ActorSnapshotTag, format string) error {
|
||||
slices.SortFunc(tags, func(a, b *ateapipb.ActorSnapshotTag) int {
|
||||
func PrintTagsTo(out io.Writer, tags []*ateapipb.Tag, format string) error {
|
||||
slices.SortFunc(tags, func(a, b *ateapipb.Tag) int {
|
||||
if c := cmp.Compare(a.GetMetadata().GetAtespace(), b.GetMetadata().GetAtespace()); c != 0 {
|
||||
return c
|
||||
}
|
||||
@@ -303,7 +303,7 @@ func PrintActorSnapshotTagsTo(out io.Writer, tags []*ateapipb.ActorSnapshotTag,
|
||||
})
|
||||
switch format {
|
||||
case "json", "yaml":
|
||||
return printProto(out, &ateapipb.ListActorSnapshotTagsResponse{ActorSnapshotTags: tags}, format)
|
||||
return printProto(out, &ateapipb.ListTagsResponse{Tags: tags}, format)
|
||||
case "table":
|
||||
w := tabwriter.NewWriter(out, 0, 0, 3, ' ', 0)
|
||||
fmt.Fprintln(w, "ATESPACE\tNAME\tSCOPE\tSTATE\tSNAPSHOT\tCONTENT SCOPE\tAGE")
|
||||
@@ -317,7 +317,7 @@ func PrintActorSnapshotTagsTo(out io.Writer, tags []*ateapipb.ActorSnapshotTag,
|
||||
}
|
||||
fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
|
||||
tag.GetMetadata().GetAtespace(), tag.GetMetadata().GetName(), tag.GetScope(),
|
||||
actorSnapshotTagState(tag), snapshotURI, contentScope,
|
||||
tagState(tag), snapshotURI, contentScope,
|
||||
formatAge(tag.GetMetadata().GetCreateTime()))
|
||||
}
|
||||
return w.Flush()
|
||||
@@ -326,22 +326,22 @@ func PrintActorSnapshotTagsTo(out io.Writer, tags []*ateapipb.ActorSnapshotTag,
|
||||
}
|
||||
}
|
||||
|
||||
// actorSnapshotTagState reports whether a tag is usable. A tag is Pending until
|
||||
// tagState reports whether a tag is usable. A tag is Pending until
|
||||
// the copy of its own snapshot lands; until then it names nothing an Actor can
|
||||
// be created from, and deleting it collects whatever the create stranded.
|
||||
func actorSnapshotTagState(tag *ateapipb.ActorSnapshotTag) string {
|
||||
func tagState(tag *ateapipb.Tag) string {
|
||||
if tag.GetStatus().GetSnapshot().GetSnapshotUri() == "" {
|
||||
return "Pending"
|
||||
}
|
||||
return "Ready"
|
||||
}
|
||||
|
||||
// PrintActorSnapshotTag prints a single actor snapshot tag to stdout.
|
||||
func PrintActorSnapshotTag(tag *ateapipb.ActorSnapshotTag, format string) error {
|
||||
// PrintTag prints a single tag to stdout.
|
||||
func PrintTag(tag *ateapipb.Tag, format string) error {
|
||||
if format == "json" || format == "yaml" {
|
||||
return printProto(os.Stdout, tag, format)
|
||||
}
|
||||
return PrintActorSnapshotTags([]*ateapipb.ActorSnapshotTag{tag}, format)
|
||||
return PrintTags([]*ateapipb.Tag{tag}, format)
|
||||
}
|
||||
|
||||
// PrintAtespaces prints a slice of atespaces to stdout in the requested format.
|
||||
|
||||
@@ -451,21 +451,21 @@ func TestPrintActorTemplatesTo_Invalid(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrintActorSnapshotTagsTo_Table(t *testing.T) {
|
||||
func TestPrintTagsTo_Table(t *testing.T) {
|
||||
now := time.Date(2026, 1, 1, 12, 0, 0, 0, time.UTC)
|
||||
pinNow(t, now)
|
||||
|
||||
var buf bytes.Buffer
|
||||
tags := []*ateapipb.ActorSnapshotTag{
|
||||
tags := []*ateapipb.Tag{
|
||||
{
|
||||
Metadata: &ateapipb.ResourceMetadata{
|
||||
Atespace: "team-a",
|
||||
Name: "v2",
|
||||
CreateTime: timestamppb.New(now.Add(-5 * time.Minute)),
|
||||
},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED,
|
||||
Status: &ateapipb.ActorSnapshotTagStatus{
|
||||
Snapshot: &ateapipb.ExternalSnapshot{SnapshotUri: "gs://private/atespaces/team-a/actor-snapshot-tags/v2", ContentScope: ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_FULL},
|
||||
Scope: ateapipb.TagScope_TAG_SCOPE_PUBLISHED,
|
||||
Status: &ateapipb.TagStatus{
|
||||
Snapshot: &ateapipb.ExternalSnapshot{SnapshotUri: "gs://private/atespaces/team-a/tags/v2", ContentScope: ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_FULL},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -474,9 +474,9 @@ func TestPrintActorSnapshotTagsTo_Table(t *testing.T) {
|
||||
Name: "v1",
|
||||
CreateTime: timestamppb.New(now.Add(-5 * time.Hour)),
|
||||
},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE,
|
||||
Status: &ateapipb.ActorSnapshotTagStatus{
|
||||
Snapshot: &ateapipb.ExternalSnapshot{SnapshotUri: "gs://private/atespaces/team-a/actor-snapshot-tags/v1", ContentScope: ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_FULL},
|
||||
Scope: ateapipb.TagScope_TAG_SCOPE_ATESPACE,
|
||||
Status: &ateapipb.TagStatus{
|
||||
Snapshot: &ateapipb.ExternalSnapshot{SnapshotUri: "gs://private/atespaces/team-a/tags/v1", ContentScope: ateapipb.SnapshotContentScope_SNAPSHOT_CONTENT_SCOPE_FULL},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -487,31 +487,31 @@ func TestPrintActorSnapshotTagsTo_Table(t *testing.T) {
|
||||
Name: "v3",
|
||||
CreateTime: timestamppb.New(now.Add(-30 * time.Second)),
|
||||
},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE,
|
||||
Status: &ateapipb.ActorSnapshotTagStatus{
|
||||
InProgressSnapshotUri: "gs://private/atespaces/team-a/actor-snapshot-tags/9f1c",
|
||||
Scope: ateapipb.TagScope_TAG_SCOPE_ATESPACE,
|
||||
Status: &ateapipb.TagStatus{
|
||||
InProgressSnapshotUri: "gs://private/atespaces/team-a/tags/9f1c",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if err := PrintActorSnapshotTagsTo(&buf, tags, "table"); err != nil {
|
||||
if err := PrintTagsTo(&buf, tags, "table"); err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// Sorted by atespace, then name.
|
||||
expected := `ATESPACE NAME SCOPE STATE SNAPSHOT CONTENT SCOPE AGE
|
||||
team-a v1 ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE Ready gs://private/atespaces/team-a/actor-snapshot-tags/v1 SNAPSHOT_CONTENT_SCOPE_FULL 5h
|
||||
team-a v2 ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED Ready gs://private/atespaces/team-a/actor-snapshot-tags/v2 SNAPSHOT_CONTENT_SCOPE_FULL 5m
|
||||
team-a v3 ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE Pending <none> <none> 30s
|
||||
expected := `ATESPACE NAME SCOPE STATE SNAPSHOT CONTENT SCOPE AGE
|
||||
team-a v1 TAG_SCOPE_ATESPACE Ready gs://private/atespaces/team-a/tags/v1 SNAPSHOT_CONTENT_SCOPE_FULL 5h
|
||||
team-a v2 TAG_SCOPE_PUBLISHED Ready gs://private/atespaces/team-a/tags/v2 SNAPSHOT_CONTENT_SCOPE_FULL 5m
|
||||
team-a v3 TAG_SCOPE_ATESPACE Pending <none> <none> 30s
|
||||
`
|
||||
if diff := cmp.Diff(expected, buf.String()); diff != "" {
|
||||
t.Errorf("output mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrintActorSnapshotTagsTo_Invalid(t *testing.T) {
|
||||
func TestPrintTagsTo_Invalid(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
if err := PrintActorSnapshotTagsTo(&buf, nil, "xml"); err == nil {
|
||||
if err := PrintTagsTo(&buf, nil, "xml"); err == nil {
|
||||
t.Errorf("expected error for invalid format, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -327,16 +327,16 @@ snapshotsConfig:
|
||||
|
||||
```
|
||||
<location>/atespaces/<atespace>/actors/<actor uid>/snapshots/<snapshot name>
|
||||
<location>/atespaces/<atespace>/actor-snapshot-tags/<snapshot name>
|
||||
<location>/atespaces/<atespace>/tags/<snapshot name>
|
||||
```
|
||||
|
||||
The objects of a snapshot (its manifest, memory image, durable-data tar) are named below it. So for the template above, a snapshot of an actor in atespace `team-a` is stored at `gs://my-bucket/secret-agent/atespaces/team-a/actors/3f8b…/snapshots/f47ac10b-…`, and the template's golden snapshot — the golden actor lives in the reserved `ate-golden` atespace — under `gs://my-bucket/secret-agent/atespaces/ate-golden/actors/<uid>/snapshots/<name>`.
|
||||
|
||||
An actor takes a series of snapshots over its life, so it gets a prefix of its own and each snapshot sits below it. A tag holds exactly one, so the tag's prefix *is* its snapshot's. The actor level is keyed on the UID rather than the name, so an actor recreated under a name that was used before never inherits its predecessor's objects.
|
||||
|
||||
An owner is collected by deleting everything under its prefix, and it can delete nothing else. That is what makes a borrowed snapshot safe: an actor created from a tag points at a URI under `actor-snapshot-tags/`, which its own prefix does not cover. See [Snapshot lifetime](#snapshot-lifetime).
|
||||
An owner is collected by deleting everything under its prefix, and it can delete nothing else. That is what makes a borrowed snapshot safe: an actor created from a tag points at a URI under `tags/`, which its own prefix does not cover. See [Snapshot lifetime](#snapshot-lifetime).
|
||||
|
||||
An `Actor` reports its current snapshot in the server-managed `status.externalSnapshot`, an `ActorSnapshotTag` in `status.snapshot`, and an `ActorTemplate` its golden one in `status.goldenSnapshotStatus.goldenSnapshot` — each an `ExternalSnapshot` carrying `snapshotUri` and the `contentScope` it captured. The URI is recorded when the snapshot is written, not recomputed on read, so the layout can change in future versions without stranding existing snapshots. All three are server-owned: do not send them on input, and parse a URI only against the scheme above.
|
||||
An `Actor` reports its current snapshot in the server-managed `status.externalSnapshot`, a `Tag` in `status.snapshot`, and an `ActorTemplate` its golden one in `status.goldenSnapshotStatus.goldenSnapshot` — each an `ExternalSnapshot` carrying `snapshotUri` and the `contentScope` it captured. The URI is recorded when the snapshot is written, not recomputed on read, so the layout can change in future versions without stranding existing snapshots. All three are server-owned: do not send them on input, and parse a URI only against the scheme above.
|
||||
|
||||
An `ActorTemplate` belongs to one atespace, but one `storageLocation` still holds snapshots for many atespaces: the golden actor lives in the reserved `ate-golden` atespace, and a `PUBLISHED` snapshot may be cloned from other atespaces. The `<atespace>` level exists so that access can be granted per tenant: an object-storage policy can only condition on an **object-name prefix**, and cannot read the identity recorded inside a snapshot's manifest. Binding a per-atespace grant on GCS looks like:
|
||||
|
||||
@@ -431,13 +431,13 @@ The Substrate Control Plane (`ate-api-server`) exposes a gRPC interface for mana
|
||||
Registers a new logical actor in the system.
|
||||
* **Request:** `CreateActorRequest`
|
||||
* `actor`: `Actor` — the actor to create. Its `metadata` carries the atespace and name (name must be a DNS-1123 label); the `actor_template` ref (atespace + name) selects the `ActorTemplate`.
|
||||
* `actor.source_snapshot_tag`: (Optional) `ObjectRef` of an `ActorSnapshotTag` to seed the actor from. The tag must be taken under the same `ActorTemplate`, and either in the actor's own atespace or `PUBLISHED`. Nothing is copied: the new actor's `status.externalSnapshot` points at the tag's snapshot, under the tag's prefix, until its own first suspend.
|
||||
* `actor.source_tag`: (Optional) `ObjectRef` of a `Tag` to seed the actor from. The tag must be taken under the same `ActorTemplate`, and either in the actor's own atespace or `PUBLISHED`. Nothing is copied: the new actor's `status.externalSnapshot` points at the tag's snapshot, under the tag's prefix, until its own first suspend.
|
||||
* **Response:** the initialized `Actor`.
|
||||
|
||||
#### `UpdateActor`
|
||||
Replaces the mutable fields of an existing actor with the ones in the request.
|
||||
* **Request:** `UpdateActorRequest`
|
||||
* `actor`: `Actor` — the complete replacement actor. `metadata.atespace` and `metadata.name` identify the resource; `metadata.uid` and `metadata.version` are **required** preconditions. `metadata` and `status` are server-owned and whatever the request carries in them is ignored. `source_snapshot_tag` is immutable.
|
||||
* `actor`: `Actor` — the complete replacement actor. `metadata.atespace` and `metadata.name` identify the resource; `metadata.uid` and `metadata.version` are **required** preconditions. `metadata` and `status` are server-owned and whatever the request carries in them is ignored. `source_tag` is immutable.
|
||||
* **Response:** the updated `Actor`.
|
||||
* **Errors:** `INVALID_ARGUMENT` if `uid` or `version` is unset, or if the request changes an immutable field — including by leaving one unset; `ABORTED` if either guard no longer matches the stored resource.
|
||||
|
||||
@@ -455,7 +455,7 @@ Hibernate a running actor, capturing its current RAM and disk state into a snaps
|
||||
* **Request:** `SuspendActorRequest`
|
||||
* `actor`: `ObjectRef` of the actor to suspend.
|
||||
* **Response:** `SuspendActorResponse` containing the `Actor` object in `ACTOR_STATE_SUSPENDED`, with its snapshot in `status.externalSnapshot`.
|
||||
* A successful suspend releases the actor's previous external snapshot: an actor keeps one, and only tags outlive it. To keep the snapshot a suspend just wrote, tag it with `CreateActorSnapshotTag` while the actor is still suspended.
|
||||
* A successful suspend releases the actor's previous external snapshot: an actor keeps one, and only tags outlive it. To keep the snapshot a suspend just wrote, tag it with `CreateTag` while the actor is still suspended.
|
||||
|
||||
#### Snapshot lifetime
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ Rules:
|
||||
- Request message name **must** match the RPC name with a `Request` suffix.
|
||||
- Response **must** be the resource itself — not a `GetActorResponse` wrapper.
|
||||
- Request **must** identify the resource with a single `ObjectRef` field (for both atespace-scoped and global-scoped resources).
|
||||
- That field **must** be named after the resource's own snake_case type name (e.g. `actor` for `Actor`, `actor_snapshot_tag` for `ActorSnapshotTag`), not a generic name like `name` or `ref`.
|
||||
- That field **must** be named after the resource's own snake_case type name (e.g. `actor` for `Actor`, `tag` for `Tag`), not a generic name like `name` or `ref`.
|
||||
- If the resource does not exist: return `NOT_FOUND`.
|
||||
|
||||
### 3.2 List
|
||||
@@ -278,7 +278,7 @@ Rules:
|
||||
- RPC name **must** begin with `Delete` followed by the singular resource name.
|
||||
- Response **must** be the deleted resource.
|
||||
- Request **must** identify the resource with an `ObjectRef` field (for both atespace-scoped and global-scoped resources).
|
||||
- That field **must** be named after the resource's own snake_case type name (e.g. `actor` for `Actor`, `actor_snapshot_tag` for `ActorSnapshotTag`), not a generic name like `name` or `ref`.
|
||||
- That field **must** be named after the resource's own snake_case type name (e.g. `actor` for `Actor`, `tag` for `Tag`), not a generic name like `name` or `ref`.
|
||||
- If the resource does not exist: return `NOT_FOUND`.
|
||||
- `version` and `uid` preconditions are honored via a `DeleteOptions` field (see section #7). Both are optional; the zero value skips the check.
|
||||
- Further non-resource "control" fields (e.g. dry-run) belong in `DeleteOptions`, not as loose top-level fields on the request.
|
||||
|
||||
@@ -125,7 +125,7 @@ func TestActorSnapshotLifecycle(t *testing.T) {
|
||||
|
||||
tagRef := &ateapipb.ObjectRef{Atespace: demoAtespace, Name: "e2e-" + nsObj.Name}
|
||||
t.Cleanup(func() {
|
||||
_, _ = clients.SubstrateAPI.DeleteActorSnapshotTag(context.Background(), &ateapipb.DeleteActorSnapshotTagRequest{ActorSnapshotTag: tagRef})
|
||||
_, _ = clients.SubstrateAPI.DeleteTag(context.Background(), &ateapipb.DeleteTagRequest{Tag: tagRef})
|
||||
})
|
||||
suspended, err := clients.SubstrateAPI.SuspendActor(ctx, &ateapipb.SuspendActorRequest{
|
||||
Actor: &ateapipb.ObjectRef{Atespace: demoAtespace, Name: sourceName},
|
||||
@@ -139,52 +139,52 @@ func TestActorSnapshotLifecycle(t *testing.T) {
|
||||
}
|
||||
// The tag is given its own copy of the snapshot the suspend just wrote, so
|
||||
// it survives the Actor being suspended again or deleted.
|
||||
tagToUpdate, err := clients.SubstrateAPI.CreateActorSnapshotTag(ctx, &ateapipb.CreateActorSnapshotTagRequest{
|
||||
ActorSnapshotTag: &ateapipb.ActorSnapshotTag{
|
||||
tagToUpdate, err := clients.SubstrateAPI.CreateTag(ctx, &ateapipb.CreateTagRequest{
|
||||
Tag: &ateapipb.Tag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: demoAtespace, Name: tagRef.GetName()},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE,
|
||||
Scope: ateapipb.TagScope_TAG_SCOPE_ATESPACE,
|
||||
SourceActor: &ateapipb.ObjectRef{Atespace: demoAtespace, Name: sourceName},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create the ActorSnapshotTag: %v", err)
|
||||
t.Fatalf("failed to create the Tag: %v", err)
|
||||
}
|
||||
if got := tagToUpdate.GetStatus().GetSnapshot().GetSnapshotUri(); got == "" || got == snapshotURI {
|
||||
t.Fatalf("ActorSnapshotTag %s snapshot uri = %q, want a copy of its own", tagRef.GetName(), got)
|
||||
t.Fatalf("Tag %s snapshot uri = %q, want a copy of its own", tagRef.GetName(), got)
|
||||
}
|
||||
if got := tagToUpdate.GetStatus().GetInProgressSnapshotUri(); got != "" {
|
||||
t.Fatalf("ActorSnapshotTag %s in-progress snapshot uri = %q, want it cleared", tagRef.GetName(), got)
|
||||
t.Fatalf("Tag %s in-progress snapshot uri = %q, want it cleared", tagRef.GetName(), got)
|
||||
}
|
||||
listed, err := clients.SubstrateAPI.ListActorSnapshotTags(ctx, &ateapipb.ListActorSnapshotTagsRequest{Atespace: demoAtespace})
|
||||
listed, err := clients.SubstrateAPI.ListTags(ctx, &ateapipb.ListTagsRequest{Atespace: demoAtespace})
|
||||
if err != nil {
|
||||
t.Fatalf("failed to list ActorSnapshotTags: %v", err)
|
||||
t.Fatalf("failed to list Tags: %v", err)
|
||||
}
|
||||
found := false
|
||||
for _, candidate := range listed.GetActorSnapshotTags() {
|
||||
for _, candidate := range listed.GetTags() {
|
||||
if candidate.GetMetadata().GetName() == tagRef.GetName() {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatalf("tag %q missing from ListActorSnapshotTags", tagRef.GetName())
|
||||
t.Fatalf("tag %q missing from ListTags", tagRef.GetName())
|
||||
}
|
||||
|
||||
tagToUpdate.Scope = ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED
|
||||
if _, err := clients.SubstrateAPI.UpdateActorSnapshotTag(ctx, &ateapipb.UpdateActorSnapshotTagRequest{
|
||||
ActorSnapshotTag: tagToUpdate,
|
||||
tagToUpdate.Scope = ateapipb.TagScope_TAG_SCOPE_PUBLISHED
|
||||
if _, err := clients.SubstrateAPI.UpdateTag(ctx, &ateapipb.UpdateTagRequest{
|
||||
Tag: tagToUpdate,
|
||||
}); err != nil {
|
||||
t.Fatalf("failed to publish ActorSnapshotTag: %v", err)
|
||||
t.Fatalf("failed to publish Tag: %v", err)
|
||||
}
|
||||
|
||||
if _, err := clients.SubstrateAPI.CreateActor(ctx, &ateapipb.CreateActorRequest{
|
||||
Actor: &ateapipb.Actor{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: demoAtespace, Name: cloneName},
|
||||
ActorTemplate: e2e.TemplateRef(at),
|
||||
SourceSnapshotTag: tagRef,
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: demoAtespace, Name: cloneName},
|
||||
ActorTemplate: e2e.TemplateRef(at),
|
||||
SourceTag: tagRef,
|
||||
},
|
||||
}); err != nil {
|
||||
t.Fatalf("failed to create Actor from ActorSnapshotTag: %v", err)
|
||||
t.Fatalf("failed to create Actor from Tag: %v", err)
|
||||
}
|
||||
if _, err := e2e.ResumeActorAwaitCapacity(t, ctx, clients, &ateapipb.ResumeActorRequest{Actor: &ateapipb.ObjectRef{Atespace: demoAtespace, Name: cloneName}}); err != nil {
|
||||
t.Fatalf("failed to resume cloned Actor: %v", err)
|
||||
@@ -196,8 +196,8 @@ func TestActorSnapshotLifecycle(t *testing.T) {
|
||||
}
|
||||
validateCounterResponse(t, response, "clone", 2, 2)
|
||||
|
||||
if _, err := clients.SubstrateAPI.DeleteActorSnapshotTag(ctx, &ateapipb.DeleteActorSnapshotTagRequest{ActorSnapshotTag: tagRef}); err != nil {
|
||||
t.Fatalf("failed to delete ActorSnapshotTag: %v", err)
|
||||
if _, err := clients.SubstrateAPI.DeleteTag(ctx, &ateapipb.DeleteTagRequest{Tag: tagRef}); err != nil {
|
||||
t.Fatalf("failed to delete Tag: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ func TestDeletePrefix(t *testing.T) {
|
||||
mustTagSnapshotURI(t, testLocation, "team-a", "snap-2"): {"manifest.json"},
|
||||
},
|
||||
target: mustOwnerPrefix(t, resources.ActorSnapshotOwner("team-a", "actor-1"), testLocation),
|
||||
wantRemaining: []string{"bucket/root/atespaces/team-a/actor-snapshot-tags/snap-2/manifest.json"},
|
||||
wantRemaining: []string{"bucket/root/atespaces/team-a/tags/snap-2/manifest.json"},
|
||||
},
|
||||
{
|
||||
name: "an already collected snapshot succeeds",
|
||||
@@ -235,7 +235,7 @@ func TestCopyPrefix_AcrossBuckets(t *testing.T) {
|
||||
t.Fatalf("CopyPrefix(%s, %s) = %v, want nil", src, dst, err)
|
||||
}
|
||||
want := []string{
|
||||
"new-bucket/atespaces/team-a/actor-snapshot-tags/snap-2/manifest.json",
|
||||
"new-bucket/atespaces/team-a/tags/snap-2/manifest.json",
|
||||
"old-bucket/root/atespaces/team-a/actors/actor-1/snapshots/snap-1/manifest.json",
|
||||
}
|
||||
if diff := cmp.Diff(want, fake.Objects()); diff != "" {
|
||||
@@ -319,7 +319,7 @@ func TestBucketPrefix(t *testing.T) {
|
||||
name: "a tag's prefix",
|
||||
prefix: mustTagSnapshotURI(t, "gs://bucket/root", "team-a", "snap-1").Prefix(),
|
||||
wantBucket: "bucket",
|
||||
wantPrefix: "root/atespaces/team-a/actor-snapshot-tags/snap-1/",
|
||||
wantPrefix: "root/atespaces/team-a/tags/snap-1/",
|
||||
},
|
||||
{
|
||||
name: "the zero prefix",
|
||||
|
||||
@@ -141,18 +141,17 @@ func ActorTemplateRefFromActorTemplate(t *ateapipb.ActorTemplate) ActorTemplateR
|
||||
}
|
||||
}
|
||||
|
||||
// ActorSnapshotTagRef identifies an ActorSnapshotTag by the (atespace, name).
|
||||
type ActorSnapshotTagRef = ResourceRef[*ateapipb.ActorSnapshotTag]
|
||||
// TagRef identifies a Tag by the (atespace, name).
|
||||
type TagRef = ResourceRef[*ateapipb.Tag]
|
||||
|
||||
// ActorSnapshotTagRefFromObjectRef converts an Ibjectref to an ActorSnapshotTagRef.
|
||||
func ActorSnapshotTagRefFromObjectRef(ref *ateapipb.ObjectRef) ActorSnapshotTagRef {
|
||||
return resourceRefFromObjectRef[*ateapipb.ActorSnapshotTag](ref)
|
||||
// TagRefFromObjectRef converts an ObjectRef to a TagRef.
|
||||
func TagRefFromObjectRef(ref *ateapipb.ObjectRef) TagRef {
|
||||
return resourceRefFromObjectRef[*ateapipb.Tag](ref)
|
||||
}
|
||||
|
||||
// ActorSnapshotTagRefFromActorSnapshotTag returns the reference addressing the
|
||||
// given tag.
|
||||
func ActorSnapshotTagRefFromActorSnapshotTag(t *ateapipb.ActorSnapshotTag) ActorSnapshotTagRef {
|
||||
return ActorSnapshotTagRef{
|
||||
// TagRefFromTag returns the reference addressing the given tag.
|
||||
func TagRefFromTag(t *ateapipb.Tag) TagRef {
|
||||
return TagRef{
|
||||
Atespace: t.GetMetadata().GetAtespace(),
|
||||
Name: t.GetMetadata().GetName(),
|
||||
}
|
||||
|
||||
@@ -27,9 +27,9 @@ import (
|
||||
// is expected.
|
||||
func TestRefAliasesAreDistinctTypes(t *testing.T) {
|
||||
types := map[string]reflect.Type{
|
||||
"ActorRef": reflect.TypeFor[ActorRef](),
|
||||
"ActorTemplateRef": reflect.TypeFor[ActorTemplateRef](),
|
||||
"ActorSnapshotTagRef": reflect.TypeFor[ActorSnapshotTagRef](),
|
||||
"ActorRef": reflect.TypeFor[ActorRef](),
|
||||
"ActorTemplateRef": reflect.TypeFor[ActorTemplateRef](),
|
||||
"TagRef": reflect.TypeFor[TagRef](),
|
||||
}
|
||||
seen := make(map[reflect.Type]string)
|
||||
for name, typ := range types {
|
||||
@@ -224,46 +224,46 @@ func TestActorTemplateRefFromActorTemplate(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestActorSnapshotTagRefString(t *testing.T) {
|
||||
got := ActorSnapshotTagRef{Atespace: "team-a", Name: "tag-1"}.String()
|
||||
func TestTagRefString(t *testing.T) {
|
||||
got := TagRef{Atespace: "team-a", Name: "tag-1"}.String()
|
||||
if want := "team-a/tag-1"; got != want {
|
||||
t.Errorf("String() = %q, want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActorSnapshotTagRefObjectRefRoundTrip(t *testing.T) {
|
||||
tagRef := ActorSnapshotTagRef{Atespace: "team-a", Name: "tag-1"}
|
||||
func TestTagRefObjectRefRoundTrip(t *testing.T) {
|
||||
tagRef := TagRef{Atespace: "team-a", Name: "tag-1"}
|
||||
|
||||
obj := tagRef.ToObjectRef()
|
||||
if obj.GetAtespace() != "team-a" || obj.GetName() != "tag-1" {
|
||||
t.Errorf("ToObjectRef() = (%q, %q), want (team-a, tag-1)", obj.GetAtespace(), obj.GetName())
|
||||
}
|
||||
if got := ActorSnapshotTagRefFromObjectRef(obj); got != tagRef {
|
||||
if got := TagRefFromObjectRef(obj); got != tagRef {
|
||||
t.Errorf("round-trip = %+v, want %+v", got, tagRef)
|
||||
}
|
||||
}
|
||||
|
||||
func TestActorSnapshotTagRefFromActorSnapshotTag(t *testing.T) {
|
||||
func TestTagRefFromTag(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
tag *ateapipb.ActorSnapshotTag
|
||||
want ActorSnapshotTagRef
|
||||
tag *ateapipb.Tag
|
||||
want TagRef
|
||||
}{
|
||||
{
|
||||
name: "populated",
|
||||
tag: &ateapipb.ActorSnapshotTag{Metadata: &ateapipb.ResourceMetadata{
|
||||
tag: &ateapipb.Tag{Metadata: &ateapipb.ResourceMetadata{
|
||||
Atespace: "team-a",
|
||||
Name: "tag-1",
|
||||
}},
|
||||
want: ActorSnapshotTagRef{Atespace: "team-a", Name: "tag-1"},
|
||||
want: TagRef{Atespace: "team-a", Name: "tag-1"},
|
||||
},
|
||||
{"nil tag", nil, ActorSnapshotTagRef{}},
|
||||
{"nil metadata", &ateapipb.ActorSnapshotTag{}, ActorSnapshotTagRef{}},
|
||||
{"nil tag", nil, TagRef{}},
|
||||
{"nil metadata", &ateapipb.Tag{}, TagRef{}},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if got := ActorSnapshotTagRefFromActorSnapshotTag(tt.tag); got != tt.want {
|
||||
t.Errorf("ActorSnapshotTagRefFromActorSnapshotTag() = %+v, want %+v", got, tt.want)
|
||||
if got := TagRefFromTag(tt.tag); got != tt.want {
|
||||
t.Errorf("TagRefFromTag() = %+v, want %+v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ const (
|
||||
// from an object's name, so a collector can tell whose objects it is
|
||||
// looking at without consulting the store.
|
||||
actorsOwnerKind = "actors"
|
||||
tagsOwnerKind = "actor-snapshot-tags"
|
||||
tagsOwnerKind = "tags"
|
||||
)
|
||||
|
||||
// NewSnapshotName returns a unique name for a new snapshot, durable or
|
||||
@@ -53,10 +53,10 @@ func (p StoragePrefix) IsZero() bool { return p == StoragePrefix{} }
|
||||
func (p StoragePrefix) String() string { return p.uri }
|
||||
|
||||
// SnapshotOwner is the resource whose objects a snapshot's prefix holds: the
|
||||
// Actor that took it, or the ActorSnapshotTag that copied it. Deletion is
|
||||
// expressed as "collect everything under my own prefix", so an owner cannot
|
||||
// name another's objects, and a borrowed snapshot is recognized by the URI
|
||||
// alone rather than by a flag the two have to keep in sync.
|
||||
// Actor that took it, or the Tag that copied it. Deletion is expressed as
|
||||
// "collect everything under my own prefix", so an owner cannot name another's
|
||||
// objects, and a borrowed snapshot is recognized by the URI alone rather than
|
||||
// by a flag the two have to keep in sync.
|
||||
type SnapshotOwner struct {
|
||||
kind string
|
||||
atespace string
|
||||
@@ -73,10 +73,10 @@ func ActorSnapshotOwner(atespace, actorUID string) SnapshotOwner {
|
||||
return SnapshotOwner{kind: actorsOwnerKind, atespace: atespace, id: actorUID}
|
||||
}
|
||||
|
||||
// TagSnapshotOwner returns the owner of the one snapshot an ActorSnapshotTag
|
||||
// holds. A tag never takes a second snapshot, so its prefix is that snapshot's
|
||||
// prefix, and the name is minted fresh rather than derived from the tag: a
|
||||
// recreated tag cannot compute its way onto the objects its predecessor left.
|
||||
// TagSnapshotOwner returns the owner of the one snapshot a Tag holds. A tag
|
||||
// never takes a second snapshot, so its prefix is that snapshot's prefix, and
|
||||
// the name is minted fresh rather than derived from the tag: a recreated tag
|
||||
// cannot compute its way onto the objects its predecessor left.
|
||||
func TagSnapshotOwner(atespace, snapshotName string) SnapshotOwner {
|
||||
return SnapshotOwner{kind: tagsOwnerKind, atespace: atespace, id: snapshotName}
|
||||
}
|
||||
@@ -129,8 +129,8 @@ func (o SnapshotOwner) Prefix(location string) (StoragePrefix, error) {
|
||||
// gs://bucket/root location
|
||||
// gs://bucket/root/atespaces/team-a/actors/<uid> an Actor's prefix
|
||||
// gs://bucket/root/atespaces/team-a/actors/<uid>/snapshots/<name> one of its snapshots
|
||||
// gs://bucket/root/atespaces/team-a/actor-snapshot-tags/<name> a tag's prefix, and its
|
||||
// only snapshot
|
||||
// gs://bucket/root/atespaces/team-a/tags/<name> a tag's prefix, and
|
||||
// its only snapshot
|
||||
type SnapshotURI struct {
|
||||
uri string
|
||||
location string
|
||||
@@ -157,9 +157,9 @@ func NewActorSnapshotURI(location, atespace, actorUID, name string) (SnapshotURI
|
||||
return SnapshotURI{uri: uri, location: location, owner: owner, ownerPrefix: prefix.String(), name: name}, nil
|
||||
}
|
||||
|
||||
// NewTagSnapshotURI returns the URI of the snapshot an ActorSnapshotTag owns,
|
||||
// stored under an ActorTemplate's snapshotsConfig.location. The tag's prefix
|
||||
// and its snapshot's are the same: a tag holds exactly one snapshot.
|
||||
// NewTagSnapshotURI returns the URI of the snapshot a Tag owns, stored under
|
||||
// an ActorTemplate's snapshotsConfig.location. The tag's prefix and its
|
||||
// snapshot's are the same: a tag holds exactly one snapshot.
|
||||
func NewTagSnapshotURI(location, atespace, name string) (SnapshotURI, error) {
|
||||
owner := TagSnapshotOwner(atespace, name)
|
||||
prefix, err := owner.Prefix(location)
|
||||
@@ -184,8 +184,8 @@ func ParseSnapshotURI(uri string) (SnapshotURI, error) {
|
||||
case n >= 6 && segments[n-6] == atespacesPathSegment && segments[n-4] == actorsOwnerKind && segments[n-2] == snapshotsPathSegment:
|
||||
u.Path = strings.Join(segments[:n-6], "/")
|
||||
return NewActorSnapshotURI(u.String(), segments[n-5], segments[n-3], segments[n-1])
|
||||
// /root/atespaces/team-a/actor-snapshot-tags/<name>
|
||||
// n-4 n-3 n-2 n-1
|
||||
// /root/atespaces/team-a/tags/<name>
|
||||
// n-4 n-3 n-2 n-1
|
||||
case n >= 4 && segments[n-4] == atespacesPathSegment && segments[n-2] == tagsOwnerKind:
|
||||
u.Path = strings.Join(segments[:n-4], "/")
|
||||
return NewTagSnapshotURI(u.String(), segments[n-3], segments[n-1])
|
||||
|
||||
@@ -173,21 +173,21 @@ func TestNewTagSnapshotURI(t *testing.T) {
|
||||
location: "gs://bucket/root",
|
||||
atespace: "team-a",
|
||||
snapshot: "snap-1",
|
||||
want: "gs://bucket/root/atespaces/team-a/actor-snapshot-tags/snap-1",
|
||||
want: "gs://bucket/root/atespaces/team-a/tags/snap-1",
|
||||
},
|
||||
{
|
||||
name: "trailing slash",
|
||||
location: "gs://bucket/root/",
|
||||
atespace: "team-a",
|
||||
snapshot: "snap-1",
|
||||
want: "gs://bucket/root/atespaces/team-a/actor-snapshot-tags/snap-1",
|
||||
want: "gs://bucket/root/atespaces/team-a/tags/snap-1",
|
||||
},
|
||||
{
|
||||
name: "bucket only",
|
||||
location: "gs://bucket",
|
||||
atespace: "team-a",
|
||||
snapshot: "snap-1",
|
||||
want: "gs://bucket/atespaces/team-a/actor-snapshot-tags/snap-1",
|
||||
want: "gs://bucket/atespaces/team-a/tags/snap-1",
|
||||
},
|
||||
{
|
||||
name: "empty location",
|
||||
@@ -320,7 +320,7 @@ func TestSnapshotOwnerPrefix(t *testing.T) {
|
||||
name: "tag",
|
||||
owner: TagSnapshotOwner("team-a", "snap-1"),
|
||||
location: "gs://bucket/root",
|
||||
want: "gs://bucket/root/atespaces/team-a/actor-snapshot-tags/snap-1",
|
||||
want: "gs://bucket/root/atespaces/team-a/tags/snap-1",
|
||||
},
|
||||
{
|
||||
name: "the zero owner has no prefix",
|
||||
@@ -386,7 +386,7 @@ func TestParseSnapshotURI(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "reads a tag snapshot",
|
||||
uri: "gs://bucket/root/atespaces/team-a/actor-snapshot-tags/snap-1",
|
||||
uri: "gs://bucket/root/atespaces/team-a/tags/snap-1",
|
||||
wantLocation: "gs://bucket/root",
|
||||
wantAtespace: "team-a",
|
||||
wantName: "snap-1",
|
||||
@@ -428,7 +428,7 @@ func TestParseSnapshotURI(t *testing.T) {
|
||||
},
|
||||
{
|
||||
name: "rejects an object within a tag snapshot",
|
||||
uri: "gs://bucket/root/atespaces/team-a/actor-snapshot-tags/snap-1/manifest.json",
|
||||
uri: "gs://bucket/root/atespaces/team-a/tags/snap-1/manifest.json",
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
@@ -551,7 +551,7 @@ func TestSnapshotURIObject(t *testing.T) {
|
||||
name: "tag snapshot object",
|
||||
uri: tagURI,
|
||||
objectName: "manifest.json",
|
||||
want: "gs://bucket/root/atespaces/team-a/actor-snapshot-tags/snap-2/manifest.json",
|
||||
want: "gs://bucket/root/atespaces/team-a/tags/snap-2/manifest.json",
|
||||
},
|
||||
{
|
||||
name: "malformed escape",
|
||||
|
||||
+218
-220
@@ -89,56 +89,56 @@ func (SnapshotContentScope) EnumDescriptor() ([]byte, []int) {
|
||||
return file_ateapi_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type ActorSnapshotTagScope int32
|
||||
type TagScope int32
|
||||
|
||||
const (
|
||||
// Not set and rejected wherever a client supplies a scope
|
||||
ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED ActorSnapshotTagScope = 0
|
||||
TagScope_TAG_SCOPE_UNSPECIFIED TagScope = 0
|
||||
// May initialize Actors only in the tag's owning Atespace.
|
||||
ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE ActorSnapshotTagScope = 1
|
||||
TagScope_TAG_SCOPE_ATESPACE TagScope = 1
|
||||
// Published for use by Actors in any Atespace. The tag remains addressed
|
||||
// through its owning Atespace.
|
||||
ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED ActorSnapshotTagScope = 2
|
||||
TagScope_TAG_SCOPE_PUBLISHED TagScope = 2
|
||||
)
|
||||
|
||||
// Enum value maps for ActorSnapshotTagScope.
|
||||
// Enum value maps for TagScope.
|
||||
var (
|
||||
ActorSnapshotTagScope_name = map[int32]string{
|
||||
0: "ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED",
|
||||
1: "ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE",
|
||||
2: "ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED",
|
||||
TagScope_name = map[int32]string{
|
||||
0: "TAG_SCOPE_UNSPECIFIED",
|
||||
1: "TAG_SCOPE_ATESPACE",
|
||||
2: "TAG_SCOPE_PUBLISHED",
|
||||
}
|
||||
ActorSnapshotTagScope_value = map[string]int32{
|
||||
"ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED": 0,
|
||||
"ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE": 1,
|
||||
"ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED": 2,
|
||||
TagScope_value = map[string]int32{
|
||||
"TAG_SCOPE_UNSPECIFIED": 0,
|
||||
"TAG_SCOPE_ATESPACE": 1,
|
||||
"TAG_SCOPE_PUBLISHED": 2,
|
||||
}
|
||||
)
|
||||
|
||||
func (x ActorSnapshotTagScope) Enum() *ActorSnapshotTagScope {
|
||||
p := new(ActorSnapshotTagScope)
|
||||
func (x TagScope) Enum() *TagScope {
|
||||
p := new(TagScope)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x ActorSnapshotTagScope) String() string {
|
||||
func (x TagScope) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (ActorSnapshotTagScope) Descriptor() protoreflect.EnumDescriptor {
|
||||
func (TagScope) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_ateapi_proto_enumTypes[1].Descriptor()
|
||||
}
|
||||
|
||||
func (ActorSnapshotTagScope) Type() protoreflect.EnumType {
|
||||
func (TagScope) Type() protoreflect.EnumType {
|
||||
return &file_ateapi_proto_enumTypes[1]
|
||||
}
|
||||
|
||||
func (x ActorSnapshotTagScope) Number() protoreflect.EnumNumber {
|
||||
func (x TagScope) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ActorSnapshotTagScope.Descriptor instead.
|
||||
func (ActorSnapshotTagScope) EnumDescriptor() ([]byte, []int) {
|
||||
// Deprecated: Use TagScope.Descriptor instead.
|
||||
func (TagScope) EnumDescriptor() ([]byte, []int) {
|
||||
return file_ateapi_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
@@ -991,7 +991,7 @@ type Actor struct {
|
||||
// +k8s:optional
|
||||
// +k8s:subfield(atespace)=+k8s:required
|
||||
// +k8s:immutable
|
||||
SourceSnapshotTag *ObjectRef `protobuf:"bytes,6,opt,name=source_snapshot_tag,json=sourceSnapshotTag,proto3" json:"source_snapshot_tag,omitempty"`
|
||||
SourceTag *ObjectRef `protobuf:"bytes,6,opt,name=source_tag,json=sourceTag,proto3" json:"source_tag,omitempty"`
|
||||
// status is the system-managed state of the Actor. It is updated by the
|
||||
// server and ignored on input. It is always present in output.
|
||||
//
|
||||
@@ -1052,9 +1052,9 @@ func (x *Actor) GetWorkerSelector() *Selector {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Actor) GetSourceSnapshotTag() *ObjectRef {
|
||||
func (x *Actor) GetSourceTag() *ObjectRef {
|
||||
if x != nil {
|
||||
return x.SourceSnapshotTag
|
||||
return x.SourceTag
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1493,9 +1493,9 @@ type ActorStatus struct {
|
||||
// +k8s:format=k8s-short-name
|
||||
InProgressSnapshotName string `protobuf:"bytes,3,opt,name=in_progress_snapshot_name,json=inProgressSnapshotName,proto3" json:"in_progress_snapshot_name,omitempty"`
|
||||
// external_snapshot is the Actor's current external snapshot.
|
||||
// If the Actor was created from an ActorSnapshotTag this is the tag's
|
||||
// snapshot, borrowed until the Actor's first suspend writes one of its own.
|
||||
// Otherwise it is unset until the Actor is first suspended.
|
||||
// If the Actor was created from a Tag this is the tag's snapshot, borrowed
|
||||
// until the Actor's first suspend writes one of its own. Otherwise it is
|
||||
// unset until the Actor is first suspended.
|
||||
// +k8s:optional
|
||||
ExternalSnapshot *ExternalSnapshot `protobuf:"bytes,4,opt,name=external_snapshot,json=externalSnapshot,proto3" json:"external_snapshot,omitempty"`
|
||||
// Node-local state used only while the Actor is paused.
|
||||
@@ -1521,9 +1521,9 @@ type ActorStatus struct {
|
||||
InProgressLocalSnapshotName string `protobuf:"bytes,8,opt,name=in_progress_local_snapshot_name,json=inProgressLocalSnapshotName,proto3" json:"in_progress_local_snapshot_name,omitempty"`
|
||||
// The UID of the actor template the Actor's guest state is currently built
|
||||
// on: the one its latest sprint booted with, recorded when the resume (or
|
||||
// first boot) commits RUNNING, or at creation for an Actor seeded from a
|
||||
// snapshot tag, since that Actor borrows guest state that was already built.
|
||||
// Empty means the Actor has no guest state yet.
|
||||
// first boot) commits RUNNING, or at creation for an Actor seeded from a tag,
|
||||
// since that Actor borrows guest state that was already built. Empty means
|
||||
// the Actor has no guest state yet.
|
||||
// Diverges from the UID of the Actor's actor_template ref when a suspended
|
||||
// Actor is repointed at a replacement template, which forces the next
|
||||
// restore to data-only.
|
||||
@@ -1741,10 +1741,10 @@ func (x *WorkerAssignment) GetWorkerPodIp() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// ActorSnapshotTagStatus is the server-owned state of an ActorSnapshotTag.
|
||||
// TagStatus is the server-owned state of a Tag.
|
||||
// The tag is fixed to one external snapshot once its creation completes, so
|
||||
// the rest is immutable provenance.
|
||||
type ActorSnapshotTagStatus struct {
|
||||
type TagStatus struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// snapshot is the external snapshot this tag points at. Unset while the tag
|
||||
// is still being created, and immutable once set: a tag never moves between
|
||||
@@ -1755,11 +1755,10 @@ type ActorSnapshotTagStatus struct {
|
||||
// UID of the ActorTemplate the snapshot was taken under. Actors can only be
|
||||
// seeded from a tag under the same template.
|
||||
ActorTemplateUid string `protobuf:"bytes,2,opt,name=actor_template_uid,json=actorTemplateUid,proto3" json:"actor_template_uid,omitempty"`
|
||||
// in_progress_snapshot_uri is where CreateActorSnapshotTag is copying the
|
||||
// tag's own snapshot to. It is minted before a single object is written and
|
||||
// cleared once snapshot is set, so a tag left with it set names exactly the
|
||||
// objects its unfinished create stranded, and deleting the tag collects
|
||||
// them.
|
||||
// in_progress_snapshot_uri is where CreateTag is copying the tag's own
|
||||
// snapshot to. It is minted before a single object is written and cleared
|
||||
// once snapshot is set, so a tag left with it set names exactly the objects
|
||||
// its unfinished create stranded, and deleting the tag collects them.
|
||||
InProgressSnapshotUri string `protobuf:"bytes,3,opt,name=in_progress_snapshot_uri,json=inProgressSnapshotUri,proto3" json:"in_progress_snapshot_uri,omitempty"`
|
||||
// source_actor_uid is the UID of the Actor this tag's snapshot was copied
|
||||
// from.
|
||||
@@ -1768,20 +1767,20 @@ type ActorSnapshotTagStatus struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ActorSnapshotTagStatus) Reset() {
|
||||
*x = ActorSnapshotTagStatus{}
|
||||
func (x *TagStatus) Reset() {
|
||||
*x = TagStatus{}
|
||||
mi := &file_ateapi_proto_msgTypes[14]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ActorSnapshotTagStatus) String() string {
|
||||
func (x *TagStatus) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ActorSnapshotTagStatus) ProtoMessage() {}
|
||||
func (*TagStatus) ProtoMessage() {}
|
||||
|
||||
func (x *ActorSnapshotTagStatus) ProtoReflect() protoreflect.Message {
|
||||
func (x *TagStatus) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ateapi_proto_msgTypes[14]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
@@ -1793,45 +1792,44 @@ func (x *ActorSnapshotTagStatus) ProtoReflect() protoreflect.Message {
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ActorSnapshotTagStatus.ProtoReflect.Descriptor instead.
|
||||
func (*ActorSnapshotTagStatus) Descriptor() ([]byte, []int) {
|
||||
// Deprecated: Use TagStatus.ProtoReflect.Descriptor instead.
|
||||
func (*TagStatus) Descriptor() ([]byte, []int) {
|
||||
return file_ateapi_proto_rawDescGZIP(), []int{14}
|
||||
}
|
||||
|
||||
func (x *ActorSnapshotTagStatus) GetSnapshot() *ExternalSnapshot {
|
||||
func (x *TagStatus) GetSnapshot() *ExternalSnapshot {
|
||||
if x != nil {
|
||||
return x.Snapshot
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ActorSnapshotTagStatus) GetActorTemplateUid() string {
|
||||
func (x *TagStatus) GetActorTemplateUid() string {
|
||||
if x != nil {
|
||||
return x.ActorTemplateUid
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ActorSnapshotTagStatus) GetInProgressSnapshotUri() string {
|
||||
func (x *TagStatus) GetInProgressSnapshotUri() string {
|
||||
if x != nil {
|
||||
return x.InProgressSnapshotUri
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ActorSnapshotTagStatus) GetSourceActorUid() string {
|
||||
func (x *TagStatus) GetSourceActorUid() string {
|
||||
if x != nil {
|
||||
return x.SourceActorUid
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// ActorSnapshotTag is an Atespace-owned, stable name for one external
|
||||
// snapshot. The external snapshot pointed by a tag is a copy of an actor snapshot.
|
||||
// The snapshot is copied when the tag is
|
||||
// created, and deleted when the tag is. Its owning Atespace cannot be deleted
|
||||
// until the tag is removed.
|
||||
type ActorSnapshotTag struct {
|
||||
// Tag is an Atespace-owned, stable name for one external snapshot. The
|
||||
// external snapshot pointed by a tag is a copy of an actor snapshot. The
|
||||
// snapshot is copied when the tag is created, and deleted when the tag is. Its
|
||||
// owning Atespace cannot be deleted until the tag is removed.
|
||||
type Tag struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Common resource metadata: atespace, name, uid, version, timestamps.
|
||||
//
|
||||
@@ -1841,13 +1839,13 @@ type ActorSnapshotTag struct {
|
||||
// status is set by the control plane; it is ignored on write.
|
||||
//
|
||||
// +k8s:optional
|
||||
Status *ActorSnapshotTagStatus `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"`
|
||||
Status *TagStatus `protobuf:"bytes,2,opt,name=status,proto3" json:"status,omitempty"`
|
||||
// scope controls who may create an Actor from this tag.
|
||||
//
|
||||
// +k8s:required
|
||||
// +k8s:minimum=1
|
||||
// +k8s:maximum=2 # keep this in sync with the ActorSnapshotTagScope enum
|
||||
Scope ActorSnapshotTagScope `protobuf:"varint,3,opt,name=scope,proto3,enum=ateapi.ActorSnapshotTagScope" json:"scope,omitempty"`
|
||||
// +k8s:maximum=2 # keep this in sync with the TagScope enum
|
||||
Scope TagScope `protobuf:"varint,3,opt,name=scope,proto3,enum=ateapi.TagScope" json:"scope,omitempty"`
|
||||
// source_actor is the suspended Actor whose external snapshot this tag
|
||||
// captures. The tag lives in this Actor's Atespace. Set once at creation and
|
||||
// immutable afterward.
|
||||
@@ -1860,20 +1858,20 @@ type ActorSnapshotTag struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ActorSnapshotTag) Reset() {
|
||||
*x = ActorSnapshotTag{}
|
||||
func (x *Tag) Reset() {
|
||||
*x = Tag{}
|
||||
mi := &file_ateapi_proto_msgTypes[15]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ActorSnapshotTag) String() string {
|
||||
func (x *Tag) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ActorSnapshotTag) ProtoMessage() {}
|
||||
func (*Tag) ProtoMessage() {}
|
||||
|
||||
func (x *ActorSnapshotTag) ProtoReflect() protoreflect.Message {
|
||||
func (x *Tag) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ateapi_proto_msgTypes[15]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
@@ -1885,33 +1883,33 @@ func (x *ActorSnapshotTag) ProtoReflect() protoreflect.Message {
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ActorSnapshotTag.ProtoReflect.Descriptor instead.
|
||||
func (*ActorSnapshotTag) Descriptor() ([]byte, []int) {
|
||||
// Deprecated: Use Tag.ProtoReflect.Descriptor instead.
|
||||
func (*Tag) Descriptor() ([]byte, []int) {
|
||||
return file_ateapi_proto_rawDescGZIP(), []int{15}
|
||||
}
|
||||
|
||||
func (x *ActorSnapshotTag) GetMetadata() *ResourceMetadata {
|
||||
func (x *Tag) GetMetadata() *ResourceMetadata {
|
||||
if x != nil {
|
||||
return x.Metadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ActorSnapshotTag) GetStatus() *ActorSnapshotTagStatus {
|
||||
func (x *Tag) GetStatus() *TagStatus {
|
||||
if x != nil {
|
||||
return x.Status
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ActorSnapshotTag) GetScope() ActorSnapshotTagScope {
|
||||
func (x *Tag) GetScope() TagScope {
|
||||
if x != nil {
|
||||
return x.Scope
|
||||
}
|
||||
return ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED
|
||||
return TagScope_TAG_SCOPE_UNSPECIFIED
|
||||
}
|
||||
|
||||
func (x *ActorSnapshotTag) GetSourceActor() *ObjectRef {
|
||||
func (x *Tag) GetSourceActor() *ObjectRef {
|
||||
if x != nil {
|
||||
return x.SourceActor
|
||||
}
|
||||
@@ -4900,29 +4898,29 @@ func (x *DeleteActorEgressPolicyRequest) GetActor() *ObjectRef {
|
||||
return nil
|
||||
}
|
||||
|
||||
type GetActorSnapshotTagRequest struct {
|
||||
type GetTagRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// +k8s:required
|
||||
// +k8s:subfield(atespace)=+k8s:required
|
||||
ActorSnapshotTag *ObjectRef `protobuf:"bytes,1,opt,name=actor_snapshot_tag,json=actorSnapshotTag,proto3" json:"actor_snapshot_tag,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
Tag *ObjectRef `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *GetActorSnapshotTagRequest) Reset() {
|
||||
*x = GetActorSnapshotTagRequest{}
|
||||
func (x *GetTagRequest) Reset() {
|
||||
*x = GetTagRequest{}
|
||||
mi := &file_ateapi_proto_msgTypes[66]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *GetActorSnapshotTagRequest) String() string {
|
||||
func (x *GetTagRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetActorSnapshotTagRequest) ProtoMessage() {}
|
||||
func (*GetTagRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetActorSnapshotTagRequest) ProtoReflect() protoreflect.Message {
|
||||
func (x *GetTagRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ateapi_proto_msgTypes[66]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
@@ -4934,19 +4932,19 @@ func (x *GetActorSnapshotTagRequest) ProtoReflect() protoreflect.Message {
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use GetActorSnapshotTagRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetActorSnapshotTagRequest) Descriptor() ([]byte, []int) {
|
||||
// Deprecated: Use GetTagRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetTagRequest) Descriptor() ([]byte, []int) {
|
||||
return file_ateapi_proto_rawDescGZIP(), []int{66}
|
||||
}
|
||||
|
||||
func (x *GetActorSnapshotTagRequest) GetActorSnapshotTag() *ObjectRef {
|
||||
func (x *GetTagRequest) GetTag() *ObjectRef {
|
||||
if x != nil {
|
||||
return x.ActorSnapshotTag
|
||||
return x.Tag
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ListActorSnapshotTagsRequest struct {
|
||||
type ListTagsRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// The atespace to list tags from. Empty lists across all atespaces.
|
||||
//
|
||||
@@ -4960,7 +4958,7 @@ type ListActorSnapshotTagsRequest struct {
|
||||
// +k8s:optional
|
||||
// +k8s:minimum=1
|
||||
PageSize int32 `protobuf:"varint,2,opt,name=page_size,json=pageSize,proto3" json:"page_size,omitempty"`
|
||||
// Pagination token from a previous ListActorSnapshotTags response.
|
||||
// Pagination token from a previous ListTags response.
|
||||
// Omit or leave empty for the first request.
|
||||
//
|
||||
// +k8s:optional
|
||||
@@ -4970,20 +4968,20 @@ type ListActorSnapshotTagsRequest struct {
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ListActorSnapshotTagsRequest) Reset() {
|
||||
*x = ListActorSnapshotTagsRequest{}
|
||||
func (x *ListTagsRequest) Reset() {
|
||||
*x = ListTagsRequest{}
|
||||
mi := &file_ateapi_proto_msgTypes[67]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListActorSnapshotTagsRequest) String() string {
|
||||
func (x *ListTagsRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListActorSnapshotTagsRequest) ProtoMessage() {}
|
||||
func (*ListTagsRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ListActorSnapshotTagsRequest) ProtoReflect() protoreflect.Message {
|
||||
func (x *ListTagsRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ateapi_proto_msgTypes[67]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
@@ -4995,54 +4993,54 @@ func (x *ListActorSnapshotTagsRequest) ProtoReflect() protoreflect.Message {
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListActorSnapshotTagsRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ListActorSnapshotTagsRequest) Descriptor() ([]byte, []int) {
|
||||
// Deprecated: Use ListTagsRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ListTagsRequest) Descriptor() ([]byte, []int) {
|
||||
return file_ateapi_proto_rawDescGZIP(), []int{67}
|
||||
}
|
||||
|
||||
func (x *ListActorSnapshotTagsRequest) GetAtespace() string {
|
||||
func (x *ListTagsRequest) GetAtespace() string {
|
||||
if x != nil {
|
||||
return x.Atespace
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ListActorSnapshotTagsRequest) GetPageSize() int32 {
|
||||
func (x *ListTagsRequest) GetPageSize() int32 {
|
||||
if x != nil {
|
||||
return x.PageSize
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ListActorSnapshotTagsRequest) GetPageToken() string {
|
||||
func (x *ListTagsRequest) GetPageToken() string {
|
||||
if x != nil {
|
||||
return x.PageToken
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ListActorSnapshotTagsResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
ActorSnapshotTags []*ActorSnapshotTag `protobuf:"bytes,1,rep,name=actor_snapshot_tags,json=actorSnapshotTags,proto3" json:"actor_snapshot_tags,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
|
||||
type ListTagsResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Tags []*Tag `protobuf:"bytes,1,rep,name=tags,proto3" json:"tags,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 *ListActorSnapshotTagsResponse) Reset() {
|
||||
*x = ListActorSnapshotTagsResponse{}
|
||||
func (x *ListTagsResponse) Reset() {
|
||||
*x = ListTagsResponse{}
|
||||
mi := &file_ateapi_proto_msgTypes[68]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ListActorSnapshotTagsResponse) String() string {
|
||||
func (x *ListTagsResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ListActorSnapshotTagsResponse) ProtoMessage() {}
|
||||
func (*ListTagsResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ListActorSnapshotTagsResponse) ProtoReflect() protoreflect.Message {
|
||||
func (x *ListTagsResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ateapi_proto_msgTypes[68]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
@@ -5054,19 +5052,19 @@ func (x *ListActorSnapshotTagsResponse) ProtoReflect() protoreflect.Message {
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ListActorSnapshotTagsResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ListActorSnapshotTagsResponse) Descriptor() ([]byte, []int) {
|
||||
// Deprecated: Use ListTagsResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ListTagsResponse) Descriptor() ([]byte, []int) {
|
||||
return file_ateapi_proto_rawDescGZIP(), []int{68}
|
||||
}
|
||||
|
||||
func (x *ListActorSnapshotTagsResponse) GetActorSnapshotTags() []*ActorSnapshotTag {
|
||||
func (x *ListTagsResponse) GetTags() []*Tag {
|
||||
if x != nil {
|
||||
return x.ActorSnapshotTags
|
||||
return x.Tags
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ListActorSnapshotTagsResponse) GetNextPageToken() string {
|
||||
func (x *ListTagsResponse) GetNextPageToken() string {
|
||||
if x != nil {
|
||||
return x.NextPageToken
|
||||
}
|
||||
@@ -5087,32 +5085,32 @@ func (x *ListActorSnapshotTagsResponse) GetNextPageToken() string {
|
||||
// which collects whatever that attempt stranded, and create it again.
|
||||
//
|
||||
// +k8s:customValidation # metadata.atespace must match source_actor.atespace
|
||||
type CreateActorSnapshotTagRequest struct {
|
||||
type CreateTagRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// The tag to create. metadata.atespace, metadata.name, scope and source_actor
|
||||
// are honored; metadata.atespace must match source_actor's, and status is
|
||||
// ignored on write.
|
||||
//
|
||||
// +k8s:required
|
||||
ActorSnapshotTag *ActorSnapshotTag `protobuf:"bytes,1,opt,name=actor_snapshot_tag,json=actorSnapshotTag,proto3" json:"actor_snapshot_tag,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
Tag *Tag `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *CreateActorSnapshotTagRequest) Reset() {
|
||||
*x = CreateActorSnapshotTagRequest{}
|
||||
func (x *CreateTagRequest) Reset() {
|
||||
*x = CreateTagRequest{}
|
||||
mi := &file_ateapi_proto_msgTypes[69]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *CreateActorSnapshotTagRequest) String() string {
|
||||
func (x *CreateTagRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CreateActorSnapshotTagRequest) ProtoMessage() {}
|
||||
func (*CreateTagRequest) ProtoMessage() {}
|
||||
|
||||
func (x *CreateActorSnapshotTagRequest) ProtoReflect() protoreflect.Message {
|
||||
func (x *CreateTagRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ateapi_proto_msgTypes[69]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
@@ -5124,51 +5122,50 @@ func (x *CreateActorSnapshotTagRequest) ProtoReflect() protoreflect.Message {
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use CreateActorSnapshotTagRequest.ProtoReflect.Descriptor instead.
|
||||
func (*CreateActorSnapshotTagRequest) Descriptor() ([]byte, []int) {
|
||||
// Deprecated: Use CreateTagRequest.ProtoReflect.Descriptor instead.
|
||||
func (*CreateTagRequest) Descriptor() ([]byte, []int) {
|
||||
return file_ateapi_proto_rawDescGZIP(), []int{69}
|
||||
}
|
||||
|
||||
func (x *CreateActorSnapshotTagRequest) GetActorSnapshotTag() *ActorSnapshotTag {
|
||||
func (x *CreateTagRequest) GetTag() *Tag {
|
||||
if x != nil {
|
||||
return x.ActorSnapshotTag
|
||||
return x.Tag
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Request to update mutable fields on an existing ActorSnapshotTag.
|
||||
// Request to update mutable fields on an existing Tag.
|
||||
// The tag keeps its address: the snapshot it points at cannot be changed.
|
||||
type UpdateActorSnapshotTagRequest struct {
|
||||
type UpdateTagRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// The tag to update.
|
||||
// actor_snapshot_tag.metadata.atespace and actor_snapshot_tag.metadata.name
|
||||
// identify which resource to update.
|
||||
// actor_snapshot_tag.metadata.version and actor_snapshot_tag.metadata.uid
|
||||
// are required preconditions
|
||||
// tag.metadata.atespace and tag.metadata.name identify which resource to
|
||||
// update.
|
||||
// tag.metadata.version and tag.metadata.uid are required preconditions
|
||||
//
|
||||
// +k8s:required
|
||||
// +k8s:opaqueType # updates are handled in 2 steps, do not descend
|
||||
// +k8s:subfield(metadata)=+k8s:required
|
||||
// +k8s:customValidation # TODO: when we get nested subfields, require metadata.atespace
|
||||
ActorSnapshotTag *ActorSnapshotTag `protobuf:"bytes,1,opt,name=actor_snapshot_tag,json=actorSnapshotTag,proto3" json:"actor_snapshot_tag,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
Tag *Tag `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *UpdateActorSnapshotTagRequest) Reset() {
|
||||
*x = UpdateActorSnapshotTagRequest{}
|
||||
func (x *UpdateTagRequest) Reset() {
|
||||
*x = UpdateTagRequest{}
|
||||
mi := &file_ateapi_proto_msgTypes[70]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *UpdateActorSnapshotTagRequest) String() string {
|
||||
func (x *UpdateTagRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UpdateActorSnapshotTagRequest) ProtoMessage() {}
|
||||
func (*UpdateTagRequest) ProtoMessage() {}
|
||||
|
||||
func (x *UpdateActorSnapshotTagRequest) ProtoReflect() protoreflect.Message {
|
||||
func (x *UpdateTagRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ateapi_proto_msgTypes[70]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
@@ -5180,41 +5177,41 @@ func (x *UpdateActorSnapshotTagRequest) ProtoReflect() protoreflect.Message {
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use UpdateActorSnapshotTagRequest.ProtoReflect.Descriptor instead.
|
||||
func (*UpdateActorSnapshotTagRequest) Descriptor() ([]byte, []int) {
|
||||
// Deprecated: Use UpdateTagRequest.ProtoReflect.Descriptor instead.
|
||||
func (*UpdateTagRequest) Descriptor() ([]byte, []int) {
|
||||
return file_ateapi_proto_rawDescGZIP(), []int{70}
|
||||
}
|
||||
|
||||
func (x *UpdateActorSnapshotTagRequest) GetActorSnapshotTag() *ActorSnapshotTag {
|
||||
func (x *UpdateTagRequest) GetTag() *Tag {
|
||||
if x != nil {
|
||||
return x.ActorSnapshotTag
|
||||
return x.Tag
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type DeleteActorSnapshotTagRequest struct {
|
||||
type DeleteTagRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// +k8s:required
|
||||
// +k8s:subfield(atespace)=+k8s:required
|
||||
ActorSnapshotTag *ObjectRef `protobuf:"bytes,1,opt,name=actor_snapshot_tag,json=actorSnapshotTag,proto3" json:"actor_snapshot_tag,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
Tag *ObjectRef `protobuf:"bytes,1,opt,name=tag,proto3" json:"tag,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *DeleteActorSnapshotTagRequest) Reset() {
|
||||
*x = DeleteActorSnapshotTagRequest{}
|
||||
func (x *DeleteTagRequest) Reset() {
|
||||
*x = DeleteTagRequest{}
|
||||
mi := &file_ateapi_proto_msgTypes[71]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *DeleteActorSnapshotTagRequest) String() string {
|
||||
func (x *DeleteTagRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DeleteActorSnapshotTagRequest) ProtoMessage() {}
|
||||
func (*DeleteTagRequest) ProtoMessage() {}
|
||||
|
||||
func (x *DeleteActorSnapshotTagRequest) ProtoReflect() protoreflect.Message {
|
||||
func (x *DeleteTagRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_ateapi_proto_msgTypes[71]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
@@ -5226,14 +5223,14 @@ func (x *DeleteActorSnapshotTagRequest) ProtoReflect() protoreflect.Message {
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use DeleteActorSnapshotTagRequest.ProtoReflect.Descriptor instead.
|
||||
func (*DeleteActorSnapshotTagRequest) Descriptor() ([]byte, []int) {
|
||||
// Deprecated: Use DeleteTagRequest.ProtoReflect.Descriptor instead.
|
||||
func (*DeleteTagRequest) Descriptor() ([]byte, []int) {
|
||||
return file_ateapi_proto_rawDescGZIP(), []int{71}
|
||||
}
|
||||
|
||||
func (x *DeleteActorSnapshotTagRequest) GetActorSnapshotTag() *ObjectRef {
|
||||
func (x *DeleteTagRequest) GetTag() *ObjectRef {
|
||||
if x != nil {
|
||||
return x.ActorSnapshotTag
|
||||
return x.Tag
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -6791,12 +6788,13 @@ const file_ateapi_proto_rawDesc = "" +
|
||||
"\x12STATUS_UNSPECIFIED\x10\x00\x12\x12\n" +
|
||||
"\x0eSTATUS_PENDING\x10\x01\x12\x12\n" +
|
||||
"\x0eSTATUS_CREATED\x10\x02\x12\x13\n" +
|
||||
"\x0fSTATUS_DELETING\x10\x03\"\xa2\x02\n" +
|
||||
"\x0fSTATUS_DELETING\x10\x03\"\x91\x02\n" +
|
||||
"\x05Actor\x124\n" +
|
||||
"\bmetadata\x18\x01 \x01(\v2\x18.ateapi.ResourceMetadataR\bmetadata\x128\n" +
|
||||
"\x0eactor_template\x18\x04 \x01(\v2\x11.ateapi.ObjectRefR\ractorTemplate\x129\n" +
|
||||
"\x0fworker_selector\x18\x05 \x01(\v2\x10.ateapi.SelectorR\x0eworkerSelector\x12A\n" +
|
||||
"\x13source_snapshot_tag\x18\x06 \x01(\v2\x11.ateapi.ObjectRefR\x11sourceSnapshotTag\x12+\n" +
|
||||
"\x0fworker_selector\x18\x05 \x01(\v2\x10.ateapi.SelectorR\x0eworkerSelector\x120\n" +
|
||||
"\n" +
|
||||
"source_tag\x18\x06 \x01(\v2\x11.ateapi.ObjectRefR\tsourceTag\x12+\n" +
|
||||
"\x06status\x18\a \x01(\v2\x13.ateapi.ActorStatusR\x06status\"n\n" +
|
||||
"\fEgressPolicy\x124\n" +
|
||||
"\bmetadata\x18\x01 \x01(\v2\x18.ateapi.ResourceMetadataR\bmetadata\x12(\n" +
|
||||
@@ -6834,16 +6832,16 @@ const file_ateapi_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"worker_pod\x18\x03 \x01(\tR\tworkerPod\x12$\n" +
|
||||
"\x0eworker_pod_uid\x18\x04 \x01(\tR\fworkerPodUid\x12\"\n" +
|
||||
"\rworker_pod_ip\x18\x05 \x01(\tR\vworkerPodIp\"\xdf\x01\n" +
|
||||
"\x16ActorSnapshotTagStatus\x124\n" +
|
||||
"\rworker_pod_ip\x18\x05 \x01(\tR\vworkerPodIp\"\xd2\x01\n" +
|
||||
"\tTagStatus\x124\n" +
|
||||
"\bsnapshot\x18\x01 \x01(\v2\x18.ateapi.ExternalSnapshotR\bsnapshot\x12,\n" +
|
||||
"\x12actor_template_uid\x18\x02 \x01(\tR\x10actorTemplateUid\x127\n" +
|
||||
"\x18in_progress_snapshot_uri\x18\x03 \x01(\tR\x15inProgressSnapshotUri\x12(\n" +
|
||||
"\x10source_actor_uid\x18\x04 \x01(\tR\x0esourceActorUid\"\xeb\x01\n" +
|
||||
"\x10ActorSnapshotTag\x124\n" +
|
||||
"\bmetadata\x18\x01 \x01(\v2\x18.ateapi.ResourceMetadataR\bmetadata\x126\n" +
|
||||
"\x06status\x18\x02 \x01(\v2\x1e.ateapi.ActorSnapshotTagStatusR\x06status\x123\n" +
|
||||
"\x05scope\x18\x03 \x01(\x0e2\x1d.ateapi.ActorSnapshotTagScopeR\x05scope\x124\n" +
|
||||
"\x10source_actor_uid\x18\x04 \x01(\tR\x0esourceActorUid\"\xc4\x01\n" +
|
||||
"\x03Tag\x124\n" +
|
||||
"\bmetadata\x18\x01 \x01(\v2\x18.ateapi.ResourceMetadataR\bmetadata\x12)\n" +
|
||||
"\x06status\x18\x02 \x01(\v2\x11.ateapi.TagStatusR\x06status\x12&\n" +
|
||||
"\x05scope\x18\x03 \x01(\x0e2\x10.ateapi.TagScopeR\x05scope\x124\n" +
|
||||
"\fsource_actor\x18\x04 \x01(\v2\x11.ateapi.ObjectRefR\vsourceActor\"@\n" +
|
||||
"\bAtespace\x124\n" +
|
||||
"\bmetadata\x18\x01 \x01(\v2\x18.ateapi.ResourceMetadataR\bmetadata\";\n" +
|
||||
@@ -6997,23 +6995,23 @@ const file_ateapi_proto_rawDesc = "" +
|
||||
"\x05actor\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\x05actor\x129\n" +
|
||||
"\regress_policy\x18\x02 \x01(\v2\x14.ateapi.EgressPolicyR\fegressPolicy\"I\n" +
|
||||
"\x1eDeleteActorEgressPolicyRequest\x12'\n" +
|
||||
"\x05actor\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\x05actor\"]\n" +
|
||||
"\x1aGetActorSnapshotTagRequest\x12?\n" +
|
||||
"\x12actor_snapshot_tag\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\x10actorSnapshotTag\"v\n" +
|
||||
"\x1cListActorSnapshotTagsRequest\x12\x1a\n" +
|
||||
"\x05actor\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\x05actor\"4\n" +
|
||||
"\rGetTagRequest\x12#\n" +
|
||||
"\x03tag\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\x03tag\"i\n" +
|
||||
"\x0fListTagsRequest\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\"\x91\x01\n" +
|
||||
"\x1dListActorSnapshotTagsResponse\x12H\n" +
|
||||
"\x13actor_snapshot_tags\x18\x01 \x03(\v2\x18.ateapi.ActorSnapshotTagR\x11actorSnapshotTags\x12&\n" +
|
||||
"\x0fnext_page_token\x18\x02 \x01(\tR\rnextPageToken\"g\n" +
|
||||
"\x1dCreateActorSnapshotTagRequest\x12F\n" +
|
||||
"\x12actor_snapshot_tag\x18\x01 \x01(\v2\x18.ateapi.ActorSnapshotTagR\x10actorSnapshotTag\"g\n" +
|
||||
"\x1dUpdateActorSnapshotTagRequest\x12F\n" +
|
||||
"\x12actor_snapshot_tag\x18\x01 \x01(\v2\x18.ateapi.ActorSnapshotTagR\x10actorSnapshotTag\"`\n" +
|
||||
"\x1dDeleteActorSnapshotTagRequest\x12?\n" +
|
||||
"\x12actor_snapshot_tag\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\x10actorSnapshotTag\";\n" +
|
||||
"page_token\x18\x03 \x01(\tR\tpageToken\"[\n" +
|
||||
"\x10ListTagsResponse\x12\x1f\n" +
|
||||
"\x04tags\x18\x01 \x03(\v2\v.ateapi.TagR\x04tags\x12&\n" +
|
||||
"\x0fnext_page_token\x18\x02 \x01(\tR\rnextPageToken\"1\n" +
|
||||
"\x10CreateTagRequest\x12\x1d\n" +
|
||||
"\x03tag\x18\x01 \x01(\v2\v.ateapi.TagR\x03tag\"1\n" +
|
||||
"\x10UpdateTagRequest\x12\x1d\n" +
|
||||
"\x03tag\x18\x01 \x01(\v2\v.ateapi.TagR\x03tag\"7\n" +
|
||||
"\x10DeleteTagRequest\x12#\n" +
|
||||
"\x03tag\x18\x01 \x01(\v2\x11.ateapi.ObjectRefR\x03tag\";\n" +
|
||||
"\rDeleteOptions\x12\x18\n" +
|
||||
"\aversion\x18\x01 \x01(\x03R\aversion\x12\x10\n" +
|
||||
"\x03uid\x18\x02 \x01(\tR\x03uid\"\x8a\x01\n" +
|
||||
@@ -7103,11 +7101,11 @@ const file_ateapi_proto_rawDesc = "" +
|
||||
"\x14SnapshotContentScope\x12&\n" +
|
||||
"\"SNAPSHOT_CONTENT_SCOPE_UNSPECIFIED\x10\x00\x12\x1f\n" +
|
||||
"\x1bSNAPSHOT_CONTENT_SCOPE_FULL\x10\x01\x12\x1f\n" +
|
||||
"\x1bSNAPSHOT_CONTENT_SCOPE_DATA\x10\x02*\x90\x01\n" +
|
||||
"\x15ActorSnapshotTagScope\x12(\n" +
|
||||
"$ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED\x10\x00\x12%\n" +
|
||||
"!ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE\x10\x01\x12&\n" +
|
||||
"\"ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED\x10\x02*\xf7\x01\n" +
|
||||
"\x1bSNAPSHOT_CONTENT_SCOPE_DATA\x10\x02*V\n" +
|
||||
"\bTagScope\x12\x19\n" +
|
||||
"\x15TAG_SCOPE_UNSPECIFIED\x10\x00\x12\x16\n" +
|
||||
"\x12TAG_SCOPE_ATESPACE\x10\x01\x12\x17\n" +
|
||||
"\x13TAG_SCOPE_PUBLISHED\x10\x02*\xf7\x01\n" +
|
||||
"\n" +
|
||||
"ActorState\x12\x1b\n" +
|
||||
"\x17ACTOR_STATE_UNSPECIFIED\x10\x00\x12\x18\n" +
|
||||
@@ -7138,7 +7136,7 @@ const file_ateapi_proto_rawDesc = "" +
|
||||
"\x15WORKER_STATE_DRAINING\x10\x02*k\n" +
|
||||
"\x17ActorCertificatePurpose\x12)\n" +
|
||||
"%ACTOR_CERTIFICATE_PURPOSE_UNSPECIFIED\x10\x00\x12%\n" +
|
||||
"!ACTOR_CERTIFICATE_PURPOSE_ATUNNEL\x10\x012\xb6\x13\n" +
|
||||
"!ACTOR_CERTIFICATE_PURPOSE_ATUNNEL\x10\x012\xf3\x11\n" +
|
||||
"\aControl\x124\n" +
|
||||
"\bGetActor\x12\x17.ateapi.GetActorRequest\x1a\r.ateapi.Actor\"\x00\x12:\n" +
|
||||
"\vCreateActor\x12\x1a.ateapi.CreateActorRequest\x1a\r.ateapi.Actor\"\x00\x12:\n" +
|
||||
@@ -7151,12 +7149,12 @@ const file_ateapi_proto_rawDesc = "" +
|
||||
"\x14GetActorEgressPolicy\x12#.ateapi.GetActorEgressPolicyRequest\x1a\x14.ateapi.EgressPolicy\"\x00\x12Y\n" +
|
||||
"\x17CreateActorEgressPolicy\x12&.ateapi.CreateActorEgressPolicyRequest\x1a\x14.ateapi.EgressPolicy\"\x00\x12Y\n" +
|
||||
"\x17UpdateActorEgressPolicy\x12&.ateapi.UpdateActorEgressPolicyRequest\x1a\x14.ateapi.EgressPolicy\"\x00\x12Y\n" +
|
||||
"\x17DeleteActorEgressPolicy\x12&.ateapi.DeleteActorEgressPolicyRequest\x1a\x14.ateapi.EgressPolicy\"\x00\x12[\n" +
|
||||
"\x16CreateActorSnapshotTag\x12%.ateapi.CreateActorSnapshotTagRequest\x1a\x18.ateapi.ActorSnapshotTag\"\x00\x12U\n" +
|
||||
"\x13GetActorSnapshotTag\x12\".ateapi.GetActorSnapshotTagRequest\x1a\x18.ateapi.ActorSnapshotTag\"\x00\x12f\n" +
|
||||
"\x15ListActorSnapshotTags\x12$.ateapi.ListActorSnapshotTagsRequest\x1a%.ateapi.ListActorSnapshotTagsResponse\"\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" +
|
||||
"\x17DeleteActorEgressPolicy\x12&.ateapi.DeleteActorEgressPolicyRequest\x1a\x14.ateapi.EgressPolicy\"\x00\x124\n" +
|
||||
"\tCreateTag\x12\x18.ateapi.CreateTagRequest\x1a\v.ateapi.Tag\"\x00\x12.\n" +
|
||||
"\x06GetTag\x12\x15.ateapi.GetTagRequest\x1a\v.ateapi.Tag\"\x00\x12?\n" +
|
||||
"\bListTags\x12\x17.ateapi.ListTagsRequest\x1a\x18.ateapi.ListTagsResponse\"\x00\x124\n" +
|
||||
"\tUpdateTag\x12\x18.ateapi.UpdateTagRequest\x1a\v.ateapi.Tag\"\x00\x124\n" +
|
||||
"\tDeleteTag\x12\x18.ateapi.DeleteTagRequest\x1a\v.ateapi.Tag\"\x00\x12H\n" +
|
||||
"\vListWorkers\x12\x1a.ateapi.ListWorkersRequest\x1a\x1b.ateapi.ListWorkersResponse\"\x00\x127\n" +
|
||||
"\tGetWorker\x12\x18.ateapi.GetWorkerRequest\x1a\x0e.ateapi.Worker\"\x00\x12=\n" +
|
||||
"\fCreateWorker\x12\x1b.ateapi.CreateWorkerRequest\x1a\x0e.ateapi.Worker\"\x00\x12=\n" +
|
||||
@@ -7196,7 +7194,7 @@ var file_ateapi_proto_enumTypes = make([]protoimpl.EnumInfo, 9)
|
||||
var file_ateapi_proto_msgTypes = make([]protoimpl.MessageInfo, 97)
|
||||
var file_ateapi_proto_goTypes = []any{
|
||||
(SnapshotContentScope)(0), // 0: ateapi.SnapshotContentScope
|
||||
(ActorSnapshotTagScope)(0), // 1: ateapi.ActorSnapshotTagScope
|
||||
(TagScope)(0), // 1: ateapi.TagScope
|
||||
(ActorState)(0), // 2: ateapi.ActorState
|
||||
(SandboxClass)(0), // 3: ateapi.SandboxClass
|
||||
(ResumeSource)(0), // 4: ateapi.ResumeSource
|
||||
@@ -7218,8 +7216,8 @@ var file_ateapi_proto_goTypes = []any{
|
||||
(*CredentialHeaderInjection)(nil), // 20: ateapi.CredentialHeaderInjection
|
||||
(*ActorStatus)(nil), // 21: ateapi.ActorStatus
|
||||
(*WorkerAssignment)(nil), // 22: ateapi.WorkerAssignment
|
||||
(*ActorSnapshotTagStatus)(nil), // 23: ateapi.ActorSnapshotTagStatus
|
||||
(*ActorSnapshotTag)(nil), // 24: ateapi.ActorSnapshotTag
|
||||
(*TagStatus)(nil), // 23: ateapi.TagStatus
|
||||
(*Tag)(nil), // 24: ateapi.Tag
|
||||
(*Atespace)(nil), // 25: ateapi.Atespace
|
||||
(*ObjectRef)(nil), // 26: ateapi.ObjectRef
|
||||
(*ActorTemplate)(nil), // 27: ateapi.ActorTemplate
|
||||
@@ -7270,12 +7268,12 @@ var file_ateapi_proto_goTypes = []any{
|
||||
(*CreateActorEgressPolicyRequest)(nil), // 72: ateapi.CreateActorEgressPolicyRequest
|
||||
(*UpdateActorEgressPolicyRequest)(nil), // 73: ateapi.UpdateActorEgressPolicyRequest
|
||||
(*DeleteActorEgressPolicyRequest)(nil), // 74: ateapi.DeleteActorEgressPolicyRequest
|
||||
(*GetActorSnapshotTagRequest)(nil), // 75: ateapi.GetActorSnapshotTagRequest
|
||||
(*ListActorSnapshotTagsRequest)(nil), // 76: ateapi.ListActorSnapshotTagsRequest
|
||||
(*ListActorSnapshotTagsResponse)(nil), // 77: ateapi.ListActorSnapshotTagsResponse
|
||||
(*CreateActorSnapshotTagRequest)(nil), // 78: ateapi.CreateActorSnapshotTagRequest
|
||||
(*UpdateActorSnapshotTagRequest)(nil), // 79: ateapi.UpdateActorSnapshotTagRequest
|
||||
(*DeleteActorSnapshotTagRequest)(nil), // 80: ateapi.DeleteActorSnapshotTagRequest
|
||||
(*GetTagRequest)(nil), // 75: ateapi.GetTagRequest
|
||||
(*ListTagsRequest)(nil), // 76: ateapi.ListTagsRequest
|
||||
(*ListTagsResponse)(nil), // 77: ateapi.ListTagsResponse
|
||||
(*CreateTagRequest)(nil), // 78: ateapi.CreateTagRequest
|
||||
(*UpdateTagRequest)(nil), // 79: ateapi.UpdateTagRequest
|
||||
(*DeleteTagRequest)(nil), // 80: ateapi.DeleteTagRequest
|
||||
(*DeleteOptions)(nil), // 81: ateapi.DeleteOptions
|
||||
(*ListWorkerActorAssignmentsRequest)(nil), // 82: ateapi.ListWorkerActorAssignmentsRequest
|
||||
(*ListWorkerActorAssignmentsResponse)(nil), // 83: ateapi.ListWorkerActorAssignmentsResponse
|
||||
@@ -7315,7 +7313,7 @@ var file_ateapi_proto_depIdxs = []int32{
|
||||
12, // 7: ateapi.Actor.metadata:type_name -> ateapi.ResourceMetadata
|
||||
26, // 8: ateapi.Actor.actor_template:type_name -> ateapi.ObjectRef
|
||||
11, // 9: ateapi.Actor.worker_selector:type_name -> ateapi.Selector
|
||||
26, // 10: ateapi.Actor.source_snapshot_tag:type_name -> ateapi.ObjectRef
|
||||
26, // 10: ateapi.Actor.source_tag:type_name -> ateapi.ObjectRef
|
||||
21, // 11: ateapi.Actor.status:type_name -> ateapi.ActorStatus
|
||||
12, // 12: ateapi.EgressPolicy.metadata:type_name -> ateapi.ResourceMetadata
|
||||
16, // 13: ateapi.EgressPolicy.rules:type_name -> ateapi.EgressRule
|
||||
@@ -7330,11 +7328,11 @@ var file_ateapi_proto_depIdxs = []int32{
|
||||
10, // 22: ateapi.ActorStatus.local_snapshot_info:type_name -> ateapi.LocalSnapshotInfo
|
||||
13, // 23: ateapi.ActorStatus.actor_volumes:type_name -> ateapi.ExternalVolume
|
||||
26, // 24: ateapi.WorkerAssignment.worker:type_name -> ateapi.ObjectRef
|
||||
9, // 25: ateapi.ActorSnapshotTagStatus.snapshot:type_name -> ateapi.ExternalSnapshot
|
||||
12, // 26: ateapi.ActorSnapshotTag.metadata:type_name -> ateapi.ResourceMetadata
|
||||
23, // 27: ateapi.ActorSnapshotTag.status:type_name -> ateapi.ActorSnapshotTagStatus
|
||||
1, // 28: ateapi.ActorSnapshotTag.scope:type_name -> ateapi.ActorSnapshotTagScope
|
||||
26, // 29: ateapi.ActorSnapshotTag.source_actor:type_name -> ateapi.ObjectRef
|
||||
9, // 25: ateapi.TagStatus.snapshot:type_name -> ateapi.ExternalSnapshot
|
||||
12, // 26: ateapi.Tag.metadata:type_name -> ateapi.ResourceMetadata
|
||||
23, // 27: ateapi.Tag.status:type_name -> ateapi.TagStatus
|
||||
1, // 28: ateapi.Tag.scope:type_name -> ateapi.TagScope
|
||||
26, // 29: ateapi.Tag.source_actor:type_name -> ateapi.ObjectRef
|
||||
12, // 30: ateapi.Atespace.metadata:type_name -> ateapi.ResourceMetadata
|
||||
12, // 31: ateapi.ActorTemplate.metadata:type_name -> ateapi.ResourceMetadata
|
||||
11, // 32: ateapi.ActorTemplate.worker_selector:type_name -> ateapi.Selector
|
||||
@@ -7393,11 +7391,11 @@ var file_ateapi_proto_depIdxs = []int32{
|
||||
26, // 85: ateapi.UpdateActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef
|
||||
15, // 86: ateapi.UpdateActorEgressPolicyRequest.egress_policy:type_name -> ateapi.EgressPolicy
|
||||
26, // 87: ateapi.DeleteActorEgressPolicyRequest.actor:type_name -> ateapi.ObjectRef
|
||||
26, // 88: ateapi.GetActorSnapshotTagRequest.actor_snapshot_tag:type_name -> ateapi.ObjectRef
|
||||
24, // 89: ateapi.ListActorSnapshotTagsResponse.actor_snapshot_tags:type_name -> ateapi.ActorSnapshotTag
|
||||
24, // 90: ateapi.CreateActorSnapshotTagRequest.actor_snapshot_tag:type_name -> ateapi.ActorSnapshotTag
|
||||
24, // 91: ateapi.UpdateActorSnapshotTagRequest.actor_snapshot_tag:type_name -> ateapi.ActorSnapshotTag
|
||||
26, // 92: ateapi.DeleteActorSnapshotTagRequest.actor_snapshot_tag:type_name -> ateapi.ObjectRef
|
||||
26, // 88: ateapi.GetTagRequest.tag:type_name -> ateapi.ObjectRef
|
||||
24, // 89: ateapi.ListTagsResponse.tags:type_name -> ateapi.Tag
|
||||
24, // 90: ateapi.CreateTagRequest.tag:type_name -> ateapi.Tag
|
||||
24, // 91: ateapi.UpdateTagRequest.tag:type_name -> ateapi.Tag
|
||||
26, // 92: ateapi.DeleteTagRequest.tag:type_name -> ateapi.ObjectRef
|
||||
26, // 93: ateapi.ListWorkerActorAssignmentsRequest.worker:type_name -> ateapi.ObjectRef
|
||||
96, // 94: ateapi.ListWorkerActorAssignmentsResponse.actor_assignments:type_name -> ateapi.ActorAssignment
|
||||
93, // 95: ateapi.ListWorkersResponse.workers:type_name -> ateapi.Worker
|
||||
@@ -7435,11 +7433,11 @@ var file_ateapi_proto_depIdxs = []int32{
|
||||
72, // 127: ateapi.Control.CreateActorEgressPolicy:input_type -> ateapi.CreateActorEgressPolicyRequest
|
||||
73, // 128: ateapi.Control.UpdateActorEgressPolicy:input_type -> ateapi.UpdateActorEgressPolicyRequest
|
||||
74, // 129: ateapi.Control.DeleteActorEgressPolicy:input_type -> ateapi.DeleteActorEgressPolicyRequest
|
||||
78, // 130: ateapi.Control.CreateActorSnapshotTag:input_type -> ateapi.CreateActorSnapshotTagRequest
|
||||
75, // 131: ateapi.Control.GetActorSnapshotTag:input_type -> ateapi.GetActorSnapshotTagRequest
|
||||
76, // 132: ateapi.Control.ListActorSnapshotTags:input_type -> ateapi.ListActorSnapshotTagsRequest
|
||||
79, // 133: ateapi.Control.UpdateActorSnapshotTag:input_type -> ateapi.UpdateActorSnapshotTagRequest
|
||||
80, // 134: ateapi.Control.DeleteActorSnapshotTag:input_type -> ateapi.DeleteActorSnapshotTagRequest
|
||||
78, // 130: ateapi.Control.CreateTag:input_type -> ateapi.CreateTagRequest
|
||||
75, // 131: ateapi.Control.GetTag:input_type -> ateapi.GetTagRequest
|
||||
76, // 132: ateapi.Control.ListTags:input_type -> ateapi.ListTagsRequest
|
||||
79, // 133: ateapi.Control.UpdateTag:input_type -> ateapi.UpdateTagRequest
|
||||
80, // 134: ateapi.Control.DeleteTag:input_type -> ateapi.DeleteTagRequest
|
||||
84, // 135: ateapi.Control.ListWorkers:input_type -> ateapi.ListWorkersRequest
|
||||
86, // 136: ateapi.Control.GetWorker:input_type -> ateapi.GetWorkerRequest
|
||||
87, // 137: ateapi.Control.CreateWorker:input_type -> ateapi.CreateWorkerRequest
|
||||
@@ -7470,11 +7468,11 @@ var file_ateapi_proto_depIdxs = []int32{
|
||||
15, // 162: ateapi.Control.CreateActorEgressPolicy:output_type -> ateapi.EgressPolicy
|
||||
15, // 163: ateapi.Control.UpdateActorEgressPolicy:output_type -> ateapi.EgressPolicy
|
||||
15, // 164: ateapi.Control.DeleteActorEgressPolicy:output_type -> ateapi.EgressPolicy
|
||||
24, // 165: ateapi.Control.CreateActorSnapshotTag:output_type -> ateapi.ActorSnapshotTag
|
||||
24, // 166: ateapi.Control.GetActorSnapshotTag:output_type -> ateapi.ActorSnapshotTag
|
||||
77, // 167: ateapi.Control.ListActorSnapshotTags:output_type -> ateapi.ListActorSnapshotTagsResponse
|
||||
24, // 168: ateapi.Control.UpdateActorSnapshotTag:output_type -> ateapi.ActorSnapshotTag
|
||||
24, // 169: ateapi.Control.DeleteActorSnapshotTag:output_type -> ateapi.ActorSnapshotTag
|
||||
24, // 165: ateapi.Control.CreateTag:output_type -> ateapi.Tag
|
||||
24, // 166: ateapi.Control.GetTag:output_type -> ateapi.Tag
|
||||
77, // 167: ateapi.Control.ListTags:output_type -> ateapi.ListTagsResponse
|
||||
24, // 168: ateapi.Control.UpdateTag:output_type -> ateapi.Tag
|
||||
24, // 169: ateapi.Control.DeleteTag:output_type -> ateapi.Tag
|
||||
85, // 170: ateapi.Control.ListWorkers:output_type -> ateapi.ListWorkersResponse
|
||||
93, // 171: ateapi.Control.GetWorker:output_type -> ateapi.Worker
|
||||
93, // 172: ateapi.Control.CreateWorker:output_type -> ateapi.Worker
|
||||
|
||||
@@ -61,22 +61,21 @@ service Control {
|
||||
// Tag the external snapshot a suspended Actor holds. The tag gets its own
|
||||
// copy of that snapshot, so suspending or deleting the Actor afterwards
|
||||
// cannot collect it.
|
||||
rpc CreateActorSnapshotTag(CreateActorSnapshotTagRequest) returns (ActorSnapshotTag) {}
|
||||
rpc CreateTag(CreateTagRequest) returns (Tag) {}
|
||||
|
||||
// Get an ActorSnapshot tag.
|
||||
rpc GetActorSnapshotTag(GetActorSnapshotTagRequest) returns (ActorSnapshotTag) {}
|
||||
// Get a Tag.
|
||||
rpc GetTag(GetTagRequest) returns (Tag) {}
|
||||
|
||||
// List ActorSnapshot tags.
|
||||
rpc ListActorSnapshotTags(ListActorSnapshotTagsRequest) returns (ListActorSnapshotTagsResponse) {}
|
||||
// List Tags.
|
||||
rpc ListTags(ListTagsRequest) returns (ListTagsResponse) {}
|
||||
|
||||
// Publish or unpublish an ActorSnapshot tag without changing its address.
|
||||
rpc UpdateActorSnapshotTag(UpdateActorSnapshotTagRequest) returns (ActorSnapshotTag) {}
|
||||
// Publish or unpublish a Tag without changing its address.
|
||||
rpc UpdateTag(UpdateTagRequest) returns (Tag) {}
|
||||
|
||||
// Delete an ActorSnapshot tag and the external snapshot it owns. Actors
|
||||
// created from the tag that have not yet been suspended still point at that
|
||||
// external snapshot and become unrecoverable, so do not delete a tag while
|
||||
// such Actors exist.
|
||||
rpc DeleteActorSnapshotTag(DeleteActorSnapshotTagRequest) returns (ActorSnapshotTag) {}
|
||||
// Delete a Tag and the external snapshot it owns. Actors created from the
|
||||
// tag that have not yet been suspended still point at that external snapshot
|
||||
// and become unrecoverable, so do not delete a tag while such Actors exist.
|
||||
rpc DeleteTag(DeleteTagRequest) returns (Tag) {}
|
||||
|
||||
// List Workers.
|
||||
rpc ListWorkers(ListWorkersRequest) returns (ListWorkersResponse) {}
|
||||
@@ -115,7 +114,7 @@ service Control {
|
||||
rpc ListAtespaces(ListAtespacesRequest) returns (ListAtespacesResponse) {}
|
||||
|
||||
// Delete an empty Atespace. Rejects (FailedPrecondition) if any Actors or
|
||||
// ActorSnapshotTags remain.
|
||||
// Tags remain.
|
||||
rpc DeleteAtespace(DeleteAtespaceRequest) returns (Atespace) {}
|
||||
|
||||
rpc CreateActorTemplate(CreateActorTemplateRequest) returns (ActorTemplate) {}
|
||||
@@ -183,14 +182,14 @@ enum SnapshotContentScope {
|
||||
// Keep this in sync with the maximums on fields of this type.
|
||||
}
|
||||
|
||||
enum ActorSnapshotTagScope {
|
||||
enum TagScope {
|
||||
// Not set and rejected wherever a client supplies a scope
|
||||
ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED = 0;
|
||||
TAG_SCOPE_UNSPECIFIED = 0;
|
||||
// May initialize Actors only in the tag's owning Atespace.
|
||||
ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE = 1;
|
||||
TAG_SCOPE_ATESPACE = 1;
|
||||
// Published for use by Actors in any Atespace. The tag remains addressed
|
||||
// through its owning Atespace.
|
||||
ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED = 2;
|
||||
TAG_SCOPE_PUBLISHED = 2;
|
||||
}
|
||||
|
||||
// Selector matches worker pools by label.
|
||||
@@ -361,7 +360,7 @@ message Actor {
|
||||
// +k8s:optional
|
||||
// +k8s:subfield(atespace)=+k8s:required
|
||||
// +k8s:immutable
|
||||
ObjectRef source_snapshot_tag = 6;
|
||||
ObjectRef source_tag = 6;
|
||||
|
||||
// status is the system-managed state of the Actor. It is updated by the
|
||||
// server and ignored on input. It is always present in output.
|
||||
@@ -537,9 +536,9 @@ message ActorStatus {
|
||||
string in_progress_snapshot_name = 3;
|
||||
|
||||
// external_snapshot is the Actor's current external snapshot.
|
||||
// If the Actor was created from an ActorSnapshotTag this is the tag's
|
||||
// snapshot, borrowed until the Actor's first suspend writes one of its own.
|
||||
// Otherwise it is unset until the Actor is first suspended.
|
||||
// If the Actor was created from a Tag this is the tag's snapshot, borrowed
|
||||
// until the Actor's first suspend writes one of its own. Otherwise it is
|
||||
// unset until the Actor is first suspended.
|
||||
// +k8s:optional
|
||||
ExternalSnapshot external_snapshot = 4;
|
||||
|
||||
@@ -569,9 +568,9 @@ message ActorStatus {
|
||||
|
||||
// The UID of the actor template the Actor's guest state is currently built
|
||||
// on: the one its latest sprint booted with, recorded when the resume (or
|
||||
// first boot) commits RUNNING, or at creation for an Actor seeded from a
|
||||
// snapshot tag, since that Actor borrows guest state that was already built.
|
||||
// Empty means the Actor has no guest state yet.
|
||||
// first boot) commits RUNNING, or at creation for an Actor seeded from a tag,
|
||||
// since that Actor borrows guest state that was already built. Empty means
|
||||
// the Actor has no guest state yet.
|
||||
// Diverges from the UID of the Actor's actor_template ref when a suspended
|
||||
// Actor is repointed at a replacement template, which forces the next
|
||||
// restore to data-only.
|
||||
@@ -631,10 +630,10 @@ message WorkerAssignment {
|
||||
string worker_pod_ip = 5;
|
||||
}
|
||||
|
||||
// ActorSnapshotTagStatus is the server-owned state of an ActorSnapshotTag.
|
||||
// TagStatus is the server-owned state of a Tag.
|
||||
// The tag is fixed to one external snapshot once its creation completes, so
|
||||
// the rest is immutable provenance.
|
||||
message ActorSnapshotTagStatus {
|
||||
message TagStatus {
|
||||
// snapshot is the external snapshot this tag points at. Unset while the tag
|
||||
// is still being created, and immutable once set: a tag never moves between
|
||||
// snapshots. A tag is usable only once this is set.
|
||||
@@ -646,11 +645,10 @@ message ActorSnapshotTagStatus {
|
||||
// seeded from a tag under the same template.
|
||||
string actor_template_uid = 2;
|
||||
|
||||
// in_progress_snapshot_uri is where CreateActorSnapshotTag is copying the
|
||||
// tag's own snapshot to. It is minted before a single object is written and
|
||||
// cleared once snapshot is set, so a tag left with it set names exactly the
|
||||
// objects its unfinished create stranded, and deleting the tag collects
|
||||
// them.
|
||||
// in_progress_snapshot_uri is where CreateTag is copying the tag's own
|
||||
// snapshot to. It is minted before a single object is written and cleared
|
||||
// once snapshot is set, so a tag left with it set names exactly the objects
|
||||
// its unfinished create stranded, and deleting the tag collects them.
|
||||
string in_progress_snapshot_uri = 3;
|
||||
|
||||
// source_actor_uid is the UID of the Actor this tag's snapshot was copied
|
||||
@@ -658,12 +656,11 @@ message ActorSnapshotTagStatus {
|
||||
string source_actor_uid = 4;
|
||||
}
|
||||
|
||||
// ActorSnapshotTag is an Atespace-owned, stable name for one external
|
||||
// snapshot. The external snapshot pointed by a tag is a copy of an actor snapshot.
|
||||
// The snapshot is copied when the tag is
|
||||
// created, and deleted when the tag is. Its owning Atespace cannot be deleted
|
||||
// until the tag is removed.
|
||||
message ActorSnapshotTag {
|
||||
// Tag is an Atespace-owned, stable name for one external snapshot. The
|
||||
// external snapshot pointed by a tag is a copy of an actor snapshot. The
|
||||
// snapshot is copied when the tag is created, and deleted when the tag is. Its
|
||||
// owning Atespace cannot be deleted until the tag is removed.
|
||||
message Tag {
|
||||
// Common resource metadata: atespace, name, uid, version, timestamps.
|
||||
//
|
||||
// +k8s:required
|
||||
@@ -673,14 +670,14 @@ message ActorSnapshotTag {
|
||||
// status is set by the control plane; it is ignored on write.
|
||||
//
|
||||
// +k8s:optional
|
||||
ActorSnapshotTagStatus status = 2;
|
||||
TagStatus status = 2;
|
||||
|
||||
// scope controls who may create an Actor from this tag.
|
||||
//
|
||||
// +k8s:required
|
||||
// +k8s:minimum=1
|
||||
// +k8s:maximum=2 # keep this in sync with the ActorSnapshotTagScope enum
|
||||
ActorSnapshotTagScope scope = 3;
|
||||
// +k8s:maximum=2 # keep this in sync with the TagScope enum
|
||||
TagScope scope = 3;
|
||||
|
||||
// source_actor is the suspended Actor whose external snapshot this tag
|
||||
// captures. The tag lives in this Actor's Atespace. Set once at creation and
|
||||
@@ -1435,13 +1432,13 @@ message DeleteActorEgressPolicyRequest {
|
||||
ObjectRef actor = 1;
|
||||
}
|
||||
|
||||
message GetActorSnapshotTagRequest {
|
||||
message GetTagRequest {
|
||||
// +k8s:required
|
||||
// +k8s:subfield(atespace)=+k8s:required
|
||||
ObjectRef actor_snapshot_tag = 1;
|
||||
ObjectRef tag = 1;
|
||||
}
|
||||
|
||||
message ListActorSnapshotTagsRequest {
|
||||
message ListTagsRequest {
|
||||
// The atespace to list tags from. Empty lists across all atespaces.
|
||||
//
|
||||
// +k8s:optional
|
||||
@@ -1456,7 +1453,7 @@ message ListActorSnapshotTagsRequest {
|
||||
// +k8s:minimum=1
|
||||
int32 page_size = 2;
|
||||
|
||||
// Pagination token from a previous ListActorSnapshotTags response.
|
||||
// Pagination token from a previous ListTags response.
|
||||
// Omit or leave empty for the first request.
|
||||
//
|
||||
// +k8s:optional
|
||||
@@ -1464,8 +1461,8 @@ message ListActorSnapshotTagsRequest {
|
||||
string page_token = 3;
|
||||
}
|
||||
|
||||
message ListActorSnapshotTagsResponse {
|
||||
repeated ActorSnapshotTag actor_snapshot_tags = 1;
|
||||
message ListTagsResponse {
|
||||
repeated Tag tags = 1;
|
||||
string next_page_token = 2;
|
||||
}
|
||||
|
||||
@@ -1483,35 +1480,34 @@ message ListActorSnapshotTagsResponse {
|
||||
// which collects whatever that attempt stranded, and create it again.
|
||||
//
|
||||
// +k8s:customValidation # metadata.atespace must match source_actor.atespace
|
||||
message CreateActorSnapshotTagRequest {
|
||||
message CreateTagRequest {
|
||||
// The tag to create. metadata.atespace, metadata.name, scope and source_actor
|
||||
// are honored; metadata.atespace must match source_actor's, and status is
|
||||
// ignored on write.
|
||||
//
|
||||
// +k8s:required
|
||||
ActorSnapshotTag actor_snapshot_tag = 1;
|
||||
Tag tag = 1;
|
||||
}
|
||||
|
||||
// Request to update mutable fields on an existing ActorSnapshotTag.
|
||||
// Request to update mutable fields on an existing Tag.
|
||||
// The tag keeps its address: the snapshot it points at cannot be changed.
|
||||
message UpdateActorSnapshotTagRequest {
|
||||
message UpdateTagRequest {
|
||||
// The tag to update.
|
||||
// actor_snapshot_tag.metadata.atespace and actor_snapshot_tag.metadata.name
|
||||
// identify which resource to update.
|
||||
// actor_snapshot_tag.metadata.version and actor_snapshot_tag.metadata.uid
|
||||
// are required preconditions
|
||||
// tag.metadata.atespace and tag.metadata.name identify which resource to
|
||||
// update.
|
||||
// tag.metadata.version and tag.metadata.uid are required preconditions
|
||||
//
|
||||
// +k8s:required
|
||||
// +k8s:opaqueType # updates are handled in 2 steps, do not descend
|
||||
// +k8s:subfield(metadata)=+k8s:required
|
||||
// +k8s:customValidation # TODO: when we get nested subfields, require metadata.atespace
|
||||
ActorSnapshotTag actor_snapshot_tag = 1;
|
||||
Tag tag = 1;
|
||||
}
|
||||
|
||||
message DeleteActorSnapshotTagRequest {
|
||||
message DeleteTagRequest {
|
||||
// +k8s:required
|
||||
// +k8s:subfield(atespace)=+k8s:required
|
||||
ObjectRef actor_snapshot_tag = 1;
|
||||
ObjectRef tag = 1;
|
||||
}
|
||||
|
||||
// DeleteOptions carries per-delete controls. Today it holds optional
|
||||
|
||||
@@ -44,11 +44,11 @@ const (
|
||||
Control_CreateActorEgressPolicy_FullMethodName = "/ateapi.Control/CreateActorEgressPolicy"
|
||||
Control_UpdateActorEgressPolicy_FullMethodName = "/ateapi.Control/UpdateActorEgressPolicy"
|
||||
Control_DeleteActorEgressPolicy_FullMethodName = "/ateapi.Control/DeleteActorEgressPolicy"
|
||||
Control_CreateActorSnapshotTag_FullMethodName = "/ateapi.Control/CreateActorSnapshotTag"
|
||||
Control_GetActorSnapshotTag_FullMethodName = "/ateapi.Control/GetActorSnapshotTag"
|
||||
Control_ListActorSnapshotTags_FullMethodName = "/ateapi.Control/ListActorSnapshotTags"
|
||||
Control_UpdateActorSnapshotTag_FullMethodName = "/ateapi.Control/UpdateActorSnapshotTag"
|
||||
Control_DeleteActorSnapshotTag_FullMethodName = "/ateapi.Control/DeleteActorSnapshotTag"
|
||||
Control_CreateTag_FullMethodName = "/ateapi.Control/CreateTag"
|
||||
Control_GetTag_FullMethodName = "/ateapi.Control/GetTag"
|
||||
Control_ListTags_FullMethodName = "/ateapi.Control/ListTags"
|
||||
Control_UpdateTag_FullMethodName = "/ateapi.Control/UpdateTag"
|
||||
Control_DeleteTag_FullMethodName = "/ateapi.Control/DeleteTag"
|
||||
Control_ListWorkers_FullMethodName = "/ateapi.Control/ListWorkers"
|
||||
Control_GetWorker_FullMethodName = "/ateapi.Control/GetWorker"
|
||||
Control_CreateWorker_FullMethodName = "/ateapi.Control/CreateWorker"
|
||||
@@ -100,18 +100,17 @@ type ControlClient interface {
|
||||
// Tag the external snapshot a suspended Actor holds. The tag gets its own
|
||||
// copy of that snapshot, so suspending or deleting the Actor afterwards
|
||||
// cannot collect it.
|
||||
CreateActorSnapshotTag(ctx context.Context, in *CreateActorSnapshotTagRequest, opts ...grpc.CallOption) (*ActorSnapshotTag, error)
|
||||
// Get an ActorSnapshot tag.
|
||||
GetActorSnapshotTag(ctx context.Context, in *GetActorSnapshotTagRequest, opts ...grpc.CallOption) (*ActorSnapshotTag, error)
|
||||
// List ActorSnapshot tags.
|
||||
ListActorSnapshotTags(ctx context.Context, in *ListActorSnapshotTagsRequest, opts ...grpc.CallOption) (*ListActorSnapshotTagsResponse, 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 and the external snapshot it owns. Actors
|
||||
// created from the tag that have not yet been suspended still point at that
|
||||
// external snapshot and become unrecoverable, so do not delete a tag while
|
||||
// such Actors exist.
|
||||
DeleteActorSnapshotTag(ctx context.Context, in *DeleteActorSnapshotTagRequest, opts ...grpc.CallOption) (*ActorSnapshotTag, error)
|
||||
CreateTag(ctx context.Context, in *CreateTagRequest, opts ...grpc.CallOption) (*Tag, error)
|
||||
// Get a Tag.
|
||||
GetTag(ctx context.Context, in *GetTagRequest, opts ...grpc.CallOption) (*Tag, error)
|
||||
// List Tags.
|
||||
ListTags(ctx context.Context, in *ListTagsRequest, opts ...grpc.CallOption) (*ListTagsResponse, error)
|
||||
// Publish or unpublish a Tag without changing its address.
|
||||
UpdateTag(ctx context.Context, in *UpdateTagRequest, opts ...grpc.CallOption) (*Tag, error)
|
||||
// Delete a Tag and the external snapshot it owns. Actors created from the
|
||||
// tag that have not yet been suspended still point at that external snapshot
|
||||
// and become unrecoverable, so do not delete a tag while such Actors exist.
|
||||
DeleteTag(ctx context.Context, in *DeleteTagRequest, opts ...grpc.CallOption) (*Tag, error)
|
||||
// List Workers.
|
||||
ListWorkers(ctx context.Context, in *ListWorkersRequest, opts ...grpc.CallOption) (*ListWorkersResponse, error)
|
||||
// Get a Worker.
|
||||
@@ -138,7 +137,7 @@ type ControlClient interface {
|
||||
// List Atespaces.
|
||||
ListAtespaces(ctx context.Context, in *ListAtespacesRequest, opts ...grpc.CallOption) (*ListAtespacesResponse, error)
|
||||
// Delete an empty Atespace. Rejects (FailedPrecondition) if any Actors or
|
||||
// ActorSnapshotTags remain.
|
||||
// Tags remain.
|
||||
DeleteAtespace(ctx context.Context, in *DeleteAtespaceRequest, opts ...grpc.CallOption) (*Atespace, error)
|
||||
CreateActorTemplate(ctx context.Context, in *CreateActorTemplateRequest, opts ...grpc.CallOption) (*ActorTemplate, error)
|
||||
GetActorTemplate(ctx context.Context, in *GetActorTemplateRequest, opts ...grpc.CallOption) (*ActorTemplate, error)
|
||||
@@ -266,50 +265,50 @@ func (c *controlClient) DeleteActorEgressPolicy(ctx context.Context, in *DeleteA
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *controlClient) CreateActorSnapshotTag(ctx context.Context, in *CreateActorSnapshotTagRequest, opts ...grpc.CallOption) (*ActorSnapshotTag, error) {
|
||||
func (c *controlClient) CreateTag(ctx context.Context, in *CreateTagRequest, opts ...grpc.CallOption) (*Tag, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ActorSnapshotTag)
|
||||
err := c.cc.Invoke(ctx, Control_CreateActorSnapshotTag_FullMethodName, in, out, cOpts...)
|
||||
out := new(Tag)
|
||||
err := c.cc.Invoke(ctx, Control_CreateTag_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *controlClient) GetActorSnapshotTag(ctx context.Context, in *GetActorSnapshotTagRequest, opts ...grpc.CallOption) (*ActorSnapshotTag, error) {
|
||||
func (c *controlClient) GetTag(ctx context.Context, in *GetTagRequest, opts ...grpc.CallOption) (*Tag, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ActorSnapshotTag)
|
||||
err := c.cc.Invoke(ctx, Control_GetActorSnapshotTag_FullMethodName, in, out, cOpts...)
|
||||
out := new(Tag)
|
||||
err := c.cc.Invoke(ctx, Control_GetTag_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *controlClient) ListActorSnapshotTags(ctx context.Context, in *ListActorSnapshotTagsRequest, opts ...grpc.CallOption) (*ListActorSnapshotTagsResponse, error) {
|
||||
func (c *controlClient) ListTags(ctx context.Context, in *ListTagsRequest, opts ...grpc.CallOption) (*ListTagsResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListActorSnapshotTagsResponse)
|
||||
err := c.cc.Invoke(ctx, Control_ListActorSnapshotTags_FullMethodName, in, out, cOpts...)
|
||||
out := new(ListTagsResponse)
|
||||
err := c.cc.Invoke(ctx, Control_ListTags_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) {
|
||||
func (c *controlClient) UpdateTag(ctx context.Context, in *UpdateTagRequest, opts ...grpc.CallOption) (*Tag, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ActorSnapshotTag)
|
||||
err := c.cc.Invoke(ctx, Control_UpdateActorSnapshotTag_FullMethodName, in, out, cOpts...)
|
||||
out := new(Tag)
|
||||
err := c.cc.Invoke(ctx, Control_UpdateTag_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) {
|
||||
func (c *controlClient) DeleteTag(ctx context.Context, in *DeleteTagRequest, opts ...grpc.CallOption) (*Tag, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ActorSnapshotTag)
|
||||
err := c.cc.Invoke(ctx, Control_DeleteActorSnapshotTag_FullMethodName, in, out, cOpts...)
|
||||
out := new(Tag)
|
||||
err := c.cc.Invoke(ctx, Control_DeleteTag_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -509,18 +508,17 @@ type ControlServer interface {
|
||||
// Tag the external snapshot a suspended Actor holds. The tag gets its own
|
||||
// copy of that snapshot, so suspending or deleting the Actor afterwards
|
||||
// cannot collect it.
|
||||
CreateActorSnapshotTag(context.Context, *CreateActorSnapshotTagRequest) (*ActorSnapshotTag, error)
|
||||
// Get an ActorSnapshot tag.
|
||||
GetActorSnapshotTag(context.Context, *GetActorSnapshotTagRequest) (*ActorSnapshotTag, error)
|
||||
// List ActorSnapshot tags.
|
||||
ListActorSnapshotTags(context.Context, *ListActorSnapshotTagsRequest) (*ListActorSnapshotTagsResponse, error)
|
||||
// Publish or unpublish an ActorSnapshot tag without changing its address.
|
||||
UpdateActorSnapshotTag(context.Context, *UpdateActorSnapshotTagRequest) (*ActorSnapshotTag, error)
|
||||
// Delete an ActorSnapshot tag and the external snapshot it owns. Actors
|
||||
// created from the tag that have not yet been suspended still point at that
|
||||
// external snapshot and become unrecoverable, so do not delete a tag while
|
||||
// such Actors exist.
|
||||
DeleteActorSnapshotTag(context.Context, *DeleteActorSnapshotTagRequest) (*ActorSnapshotTag, error)
|
||||
CreateTag(context.Context, *CreateTagRequest) (*Tag, error)
|
||||
// Get a Tag.
|
||||
GetTag(context.Context, *GetTagRequest) (*Tag, error)
|
||||
// List Tags.
|
||||
ListTags(context.Context, *ListTagsRequest) (*ListTagsResponse, error)
|
||||
// Publish or unpublish a Tag without changing its address.
|
||||
UpdateTag(context.Context, *UpdateTagRequest) (*Tag, error)
|
||||
// Delete a Tag and the external snapshot it owns. Actors created from the
|
||||
// tag that have not yet been suspended still point at that external snapshot
|
||||
// and become unrecoverable, so do not delete a tag while such Actors exist.
|
||||
DeleteTag(context.Context, *DeleteTagRequest) (*Tag, error)
|
||||
// List Workers.
|
||||
ListWorkers(context.Context, *ListWorkersRequest) (*ListWorkersResponse, error)
|
||||
// Get a Worker.
|
||||
@@ -547,7 +545,7 @@ type ControlServer interface {
|
||||
// List Atespaces.
|
||||
ListAtespaces(context.Context, *ListAtespacesRequest) (*ListAtespacesResponse, error)
|
||||
// Delete an empty Atespace. Rejects (FailedPrecondition) if any Actors or
|
||||
// ActorSnapshotTags remain.
|
||||
// Tags remain.
|
||||
DeleteAtespace(context.Context, *DeleteAtespaceRequest) (*Atespace, error)
|
||||
CreateActorTemplate(context.Context, *CreateActorTemplateRequest) (*ActorTemplate, error)
|
||||
GetActorTemplate(context.Context, *GetActorTemplateRequest) (*ActorTemplate, error)
|
||||
@@ -598,20 +596,20 @@ func (UnimplementedControlServer) UpdateActorEgressPolicy(context.Context, *Upda
|
||||
func (UnimplementedControlServer) DeleteActorEgressPolicy(context.Context, *DeleteActorEgressPolicyRequest) (*EgressPolicy, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method DeleteActorEgressPolicy not implemented")
|
||||
}
|
||||
func (UnimplementedControlServer) CreateActorSnapshotTag(context.Context, *CreateActorSnapshotTagRequest) (*ActorSnapshotTag, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateActorSnapshotTag not implemented")
|
||||
func (UnimplementedControlServer) CreateTag(context.Context, *CreateTagRequest) (*Tag, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method CreateTag not implemented")
|
||||
}
|
||||
func (UnimplementedControlServer) GetActorSnapshotTag(context.Context, *GetActorSnapshotTagRequest) (*ActorSnapshotTag, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetActorSnapshotTag not implemented")
|
||||
func (UnimplementedControlServer) GetTag(context.Context, *GetTagRequest) (*Tag, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetTag not implemented")
|
||||
}
|
||||
func (UnimplementedControlServer) ListActorSnapshotTags(context.Context, *ListActorSnapshotTagsRequest) (*ListActorSnapshotTagsResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method ListActorSnapshotTags not implemented")
|
||||
func (UnimplementedControlServer) ListTags(context.Context, *ListTagsRequest) (*ListTagsResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method ListTags not implemented")
|
||||
}
|
||||
func (UnimplementedControlServer) UpdateActorSnapshotTag(context.Context, *UpdateActorSnapshotTagRequest) (*ActorSnapshotTag, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateActorSnapshotTag not implemented")
|
||||
func (UnimplementedControlServer) UpdateTag(context.Context, *UpdateTagRequest) (*Tag, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method UpdateTag not implemented")
|
||||
}
|
||||
func (UnimplementedControlServer) DeleteActorSnapshotTag(context.Context, *DeleteActorSnapshotTagRequest) (*ActorSnapshotTag, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method DeleteActorSnapshotTag not implemented")
|
||||
func (UnimplementedControlServer) DeleteTag(context.Context, *DeleteTagRequest) (*Tag, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method DeleteTag not implemented")
|
||||
}
|
||||
func (UnimplementedControlServer) ListWorkers(context.Context, *ListWorkersRequest) (*ListWorkersResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method ListWorkers not implemented")
|
||||
@@ -880,92 +878,92 @@ func _Control_DeleteActorEgressPolicy_Handler(srv interface{}, ctx context.Conte
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Control_CreateActorSnapshotTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CreateActorSnapshotTagRequest)
|
||||
func _Control_CreateTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CreateTagRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ControlServer).CreateActorSnapshotTag(ctx, in)
|
||||
return srv.(ControlServer).CreateTag(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Control_CreateActorSnapshotTag_FullMethodName,
|
||||
FullMethod: Control_CreateTag_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ControlServer).CreateActorSnapshotTag(ctx, req.(*CreateActorSnapshotTagRequest))
|
||||
return srv.(ControlServer).CreateTag(ctx, req.(*CreateTagRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Control_GetActorSnapshotTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetActorSnapshotTagRequest)
|
||||
func _Control_GetTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetTagRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ControlServer).GetActorSnapshotTag(ctx, in)
|
||||
return srv.(ControlServer).GetTag(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Control_GetActorSnapshotTag_FullMethodName,
|
||||
FullMethod: Control_GetTag_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ControlServer).GetActorSnapshotTag(ctx, req.(*GetActorSnapshotTagRequest))
|
||||
return srv.(ControlServer).GetTag(ctx, req.(*GetTagRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Control_ListActorSnapshotTags_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListActorSnapshotTagsRequest)
|
||||
func _Control_ListTags_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListTagsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ControlServer).ListActorSnapshotTags(ctx, in)
|
||||
return srv.(ControlServer).ListTags(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Control_ListActorSnapshotTags_FullMethodName,
|
||||
FullMethod: Control_ListTags_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ControlServer).ListActorSnapshotTags(ctx, req.(*ListActorSnapshotTagsRequest))
|
||||
return srv.(ControlServer).ListTags(ctx, req.(*ListTagsRequest))
|
||||
}
|
||||
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)
|
||||
func _Control_UpdateTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(UpdateTagRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ControlServer).UpdateActorSnapshotTag(ctx, in)
|
||||
return srv.(ControlServer).UpdateTag(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Control_UpdateActorSnapshotTag_FullMethodName,
|
||||
FullMethod: Control_UpdateTag_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ControlServer).UpdateActorSnapshotTag(ctx, req.(*UpdateActorSnapshotTagRequest))
|
||||
return srv.(ControlServer).UpdateTag(ctx, req.(*UpdateTagRequest))
|
||||
}
|
||||
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)
|
||||
func _Control_DeleteTag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(DeleteTagRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ControlServer).DeleteActorSnapshotTag(ctx, in)
|
||||
return srv.(ControlServer).DeleteTag(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Control_DeleteActorSnapshotTag_FullMethodName,
|
||||
FullMethod: Control_DeleteTag_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ControlServer).DeleteActorSnapshotTag(ctx, req.(*DeleteActorSnapshotTagRequest))
|
||||
return srv.(ControlServer).DeleteTag(ctx, req.(*DeleteTagRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
@@ -1310,24 +1308,24 @@ var Control_ServiceDesc = grpc.ServiceDesc{
|
||||
Handler: _Control_DeleteActorEgressPolicy_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CreateActorSnapshotTag",
|
||||
Handler: _Control_CreateActorSnapshotTag_Handler,
|
||||
MethodName: "CreateTag",
|
||||
Handler: _Control_CreateTag_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetActorSnapshotTag",
|
||||
Handler: _Control_GetActorSnapshotTag_Handler,
|
||||
MethodName: "GetTag",
|
||||
Handler: _Control_GetTag_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListActorSnapshotTags",
|
||||
Handler: _Control_ListActorSnapshotTags_Handler,
|
||||
MethodName: "ListTags",
|
||||
Handler: _Control_ListTags_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "UpdateActorSnapshotTag",
|
||||
Handler: _Control_UpdateActorSnapshotTag_Handler,
|
||||
MethodName: "UpdateTag",
|
||||
Handler: _Control_UpdateTag_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "DeleteActorSnapshotTag",
|
||||
Handler: _Control_DeleteActorSnapshotTag_Handler,
|
||||
MethodName: "DeleteTag",
|
||||
Handler: _Control_DeleteTag_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListWorkers",
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
},
|
||||
{
|
||||
"rule": "documented",
|
||||
"subject": "ateapi.ActorSnapshotTagScope",
|
||||
"subject": "ateapi.TagScope",
|
||||
"message": "enum has no doc comment"
|
||||
},
|
||||
{
|
||||
@@ -121,12 +121,12 @@
|
||||
},
|
||||
{
|
||||
"rule": "documented",
|
||||
"subject": "ateapi.DeleteActorSnapshotTagRequest",
|
||||
"subject": "ateapi.DeleteTagRequest",
|
||||
"message": "message has no doc comment"
|
||||
},
|
||||
{
|
||||
"rule": "documented",
|
||||
"subject": "ateapi.DeleteActorSnapshotTagRequest.actor_snapshot_tag",
|
||||
"subject": "ateapi.DeleteTagRequest.tag",
|
||||
"message": "field has no doc comment"
|
||||
},
|
||||
{
|
||||
@@ -186,12 +186,12 @@
|
||||
},
|
||||
{
|
||||
"rule": "documented",
|
||||
"subject": "ateapi.GetActorSnapshotTagRequest",
|
||||
"subject": "ateapi.GetTagRequest",
|
||||
"message": "message has no doc comment"
|
||||
},
|
||||
{
|
||||
"rule": "documented",
|
||||
"subject": "ateapi.GetActorSnapshotTagRequest.actor_snapshot_tag",
|
||||
"subject": "ateapi.GetTagRequest.tag",
|
||||
"message": "field has no doc comment"
|
||||
},
|
||||
{
|
||||
@@ -246,22 +246,22 @@
|
||||
},
|
||||
{
|
||||
"rule": "documented",
|
||||
"subject": "ateapi.ListActorSnapshotTagsRequest",
|
||||
"subject": "ateapi.ListTagsRequest",
|
||||
"message": "message has no doc comment"
|
||||
},
|
||||
{
|
||||
"rule": "documented",
|
||||
"subject": "ateapi.ListActorSnapshotTagsResponse",
|
||||
"subject": "ateapi.ListTagsResponse",
|
||||
"message": "message has no doc comment"
|
||||
},
|
||||
{
|
||||
"rule": "documented",
|
||||
"subject": "ateapi.ListActorSnapshotTagsResponse.actor_snapshot_tags",
|
||||
"subject": "ateapi.ListTagsResponse.tags",
|
||||
"message": "field has no doc comment"
|
||||
},
|
||||
{
|
||||
"rule": "documented",
|
||||
"subject": "ateapi.ListActorSnapshotTagsResponse.next_page_token",
|
||||
"subject": "ateapi.ListTagsResponse.next_page_token",
|
||||
"message": "field has no doc comment"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -554,7 +554,7 @@ func Resources(api *API) ([]Resource, error) {
|
||||
var resourceNames = []string{
|
||||
"Actor",
|
||||
"ActorSnapshot",
|
||||
"ActorSnapshotTag",
|
||||
"Tag",
|
||||
"ActorTemplate",
|
||||
"Atespace",
|
||||
"Worker",
|
||||
|
||||
Reference in New Issue
Block a user