mirror of
https://github.com/agent-substrate/substrate.git
synced 2026-10-02 03:24:42 +08:00
Add UNSPECIFIED zero value for ActorSnapshotTagScope (#898)
Fixes #897 - [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
@@ -139,6 +139,51 @@ class ControlStub:
|
||||
request_serializer=ateapi__pb2.DeleteAtespaceRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.Atespace.FromString,
|
||||
_registered_method=True)
|
||||
self.CreateActorTemplate = channel.unary_unary(
|
||||
'/ateapi.Control/CreateActorTemplate',
|
||||
request_serializer=ateapi__pb2.CreateActorTemplateRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.ActorTemplate.FromString,
|
||||
_registered_method=True)
|
||||
self.GetActorTemplate = channel.unary_unary(
|
||||
'/ateapi.Control/GetActorTemplate',
|
||||
request_serializer=ateapi__pb2.GetActorTemplateRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.ActorTemplate.FromString,
|
||||
_registered_method=True)
|
||||
self.UpdateActorTemplate = channel.unary_unary(
|
||||
'/ateapi.Control/UpdateActorTemplate',
|
||||
request_serializer=ateapi__pb2.UpdateActorTemplateRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.ActorTemplate.FromString,
|
||||
_registered_method=True)
|
||||
self.ListActorTemplates = channel.unary_unary(
|
||||
'/ateapi.Control/ListActorTemplates',
|
||||
request_serializer=ateapi__pb2.ListActorTemplatesRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.ListActorTemplatesResponse.FromString,
|
||||
_registered_method=True)
|
||||
self.DeleteActorTemplate = channel.unary_unary(
|
||||
'/ateapi.Control/DeleteActorTemplate',
|
||||
request_serializer=ateapi__pb2.DeleteActorTemplateRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.ActorTemplate.FromString,
|
||||
_registered_method=True)
|
||||
self.CreateActorTemplateVersion = channel.unary_unary(
|
||||
'/ateapi.Control/CreateActorTemplateVersion',
|
||||
request_serializer=ateapi__pb2.CreateActorTemplateVersionRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.ActorTemplateVersion.FromString,
|
||||
_registered_method=True)
|
||||
self.GetActorTemplateVersion = channel.unary_unary(
|
||||
'/ateapi.Control/GetActorTemplateVersion',
|
||||
request_serializer=ateapi__pb2.GetActorTemplateVersionRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.ActorTemplateVersion.FromString,
|
||||
_registered_method=True)
|
||||
self.ListActorTemplateVersions = channel.unary_unary(
|
||||
'/ateapi.Control/ListActorTemplateVersions',
|
||||
request_serializer=ateapi__pb2.ListActorTemplateVersionsRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.ListActorTemplateVersionsResponse.FromString,
|
||||
_registered_method=True)
|
||||
self.DeleteActorTemplateVersion = channel.unary_unary(
|
||||
'/ateapi.Control/DeleteActorTemplateVersion',
|
||||
request_serializer=ateapi__pb2.DeleteActorTemplateVersionRequest.SerializeToString,
|
||||
response_deserializer=ateapi__pb2.ActorTemplateVersion.FromString,
|
||||
_registered_method=True)
|
||||
|
||||
|
||||
class ControlServicer:
|
||||
@@ -167,7 +212,9 @@ class ControlServicer:
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def SuspendActor(self, request, context):
|
||||
"""Suspend a given actor to a new snapshot.
|
||||
"""Suspend a given actor to a new snapshot. A running actor is checkpointed
|
||||
on its worker; a paused actor's node-local snapshot is uploaded, narrowed
|
||||
to the template's commit scope where required (Full capture, Data commit).
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
@@ -273,6 +320,72 @@ class ControlServicer:
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def CreateActorTemplate(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetActorTemplate(self, request, context):
|
||||
"""Get an ActorTemplate by name.
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def UpdateActorTemplate(self, request, context):
|
||||
"""Update mutable fields on an existing ActorTemplate.
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def ListActorTemplates(self, request, context):
|
||||
"""Missing associated documentation comment in .proto file."""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def DeleteActorTemplate(self, request, context):
|
||||
"""Delete an ActorTemplate. Rejects (FailedPrecondition) while any of its
|
||||
ActorTemplateVersions exist.
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def CreateActorTemplateVersion(self, request, context):
|
||||
"""Create a new ActorTemplateVersion under an existing ActorTemplate
|
||||
(FailedPrecondition if the parent does not exist).
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def GetActorTemplateVersion(self, request, context):
|
||||
"""Get an ActorTemplateVersion by name.
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def ListActorTemplateVersions(self, request, context):
|
||||
"""List ActorTemplateVersions, optionally filtered to one ActorTemplate.
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
def DeleteActorTemplateVersion(self, request, context):
|
||||
"""Delete an ActorTemplateVersion together with its golden actor and golden
|
||||
snapshot in the reserved ate-golden atespace. Rejects (FailedPrecondition)
|
||||
while the version is its parent's default_version_on_create or while any
|
||||
Actor pins it.
|
||||
"""
|
||||
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
||||
context.set_details('Method not implemented!')
|
||||
raise NotImplementedError('Method not implemented!')
|
||||
|
||||
|
||||
def add_ControlServicer_to_server(servicer, server):
|
||||
rpc_method_handlers = {
|
||||
@@ -366,6 +479,51 @@ def add_ControlServicer_to_server(servicer, server):
|
||||
request_deserializer=ateapi__pb2.DeleteAtespaceRequest.FromString,
|
||||
response_serializer=ateapi__pb2.Atespace.SerializeToString,
|
||||
),
|
||||
'CreateActorTemplate': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.CreateActorTemplate,
|
||||
request_deserializer=ateapi__pb2.CreateActorTemplateRequest.FromString,
|
||||
response_serializer=ateapi__pb2.ActorTemplate.SerializeToString,
|
||||
),
|
||||
'GetActorTemplate': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetActorTemplate,
|
||||
request_deserializer=ateapi__pb2.GetActorTemplateRequest.FromString,
|
||||
response_serializer=ateapi__pb2.ActorTemplate.SerializeToString,
|
||||
),
|
||||
'UpdateActorTemplate': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.UpdateActorTemplate,
|
||||
request_deserializer=ateapi__pb2.UpdateActorTemplateRequest.FromString,
|
||||
response_serializer=ateapi__pb2.ActorTemplate.SerializeToString,
|
||||
),
|
||||
'ListActorTemplates': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.ListActorTemplates,
|
||||
request_deserializer=ateapi__pb2.ListActorTemplatesRequest.FromString,
|
||||
response_serializer=ateapi__pb2.ListActorTemplatesResponse.SerializeToString,
|
||||
),
|
||||
'DeleteActorTemplate': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.DeleteActorTemplate,
|
||||
request_deserializer=ateapi__pb2.DeleteActorTemplateRequest.FromString,
|
||||
response_serializer=ateapi__pb2.ActorTemplate.SerializeToString,
|
||||
),
|
||||
'CreateActorTemplateVersion': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.CreateActorTemplateVersion,
|
||||
request_deserializer=ateapi__pb2.CreateActorTemplateVersionRequest.FromString,
|
||||
response_serializer=ateapi__pb2.ActorTemplateVersion.SerializeToString,
|
||||
),
|
||||
'GetActorTemplateVersion': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.GetActorTemplateVersion,
|
||||
request_deserializer=ateapi__pb2.GetActorTemplateVersionRequest.FromString,
|
||||
response_serializer=ateapi__pb2.ActorTemplateVersion.SerializeToString,
|
||||
),
|
||||
'ListActorTemplateVersions': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.ListActorTemplateVersions,
|
||||
request_deserializer=ateapi__pb2.ListActorTemplateVersionsRequest.FromString,
|
||||
response_serializer=ateapi__pb2.ListActorTemplateVersionsResponse.SerializeToString,
|
||||
),
|
||||
'DeleteActorTemplateVersion': grpc.unary_unary_rpc_method_handler(
|
||||
servicer.DeleteActorTemplateVersion,
|
||||
request_deserializer=ateapi__pb2.DeleteActorTemplateVersionRequest.FromString,
|
||||
response_serializer=ateapi__pb2.ActorTemplateVersion.SerializeToString,
|
||||
),
|
||||
}
|
||||
generic_handler = grpc.method_handlers_generic_handler(
|
||||
'ateapi.Control', rpc_method_handlers)
|
||||
@@ -864,6 +1022,249 @@ class Control:
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def CreateActorTemplate(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/ateapi.Control/CreateActorTemplate',
|
||||
ateapi__pb2.CreateActorTemplateRequest.SerializeToString,
|
||||
ateapi__pb2.ActorTemplate.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetActorTemplate(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/ateapi.Control/GetActorTemplate',
|
||||
ateapi__pb2.GetActorTemplateRequest.SerializeToString,
|
||||
ateapi__pb2.ActorTemplate.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def UpdateActorTemplate(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/ateapi.Control/UpdateActorTemplate',
|
||||
ateapi__pb2.UpdateActorTemplateRequest.SerializeToString,
|
||||
ateapi__pb2.ActorTemplate.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def ListActorTemplates(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/ateapi.Control/ListActorTemplates',
|
||||
ateapi__pb2.ListActorTemplatesRequest.SerializeToString,
|
||||
ateapi__pb2.ListActorTemplatesResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def DeleteActorTemplate(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/ateapi.Control/DeleteActorTemplate',
|
||||
ateapi__pb2.DeleteActorTemplateRequest.SerializeToString,
|
||||
ateapi__pb2.ActorTemplate.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def CreateActorTemplateVersion(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/ateapi.Control/CreateActorTemplateVersion',
|
||||
ateapi__pb2.CreateActorTemplateVersionRequest.SerializeToString,
|
||||
ateapi__pb2.ActorTemplateVersion.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def GetActorTemplateVersion(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/ateapi.Control/GetActorTemplateVersion',
|
||||
ateapi__pb2.GetActorTemplateVersionRequest.SerializeToString,
|
||||
ateapi__pb2.ActorTemplateVersion.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def ListActorTemplateVersions(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/ateapi.Control/ListActorTemplateVersions',
|
||||
ateapi__pb2.ListActorTemplateVersionsRequest.SerializeToString,
|
||||
ateapi__pb2.ListActorTemplateVersionsResponse.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
@staticmethod
|
||||
def DeleteActorTemplateVersion(request,
|
||||
target,
|
||||
options=(),
|
||||
channel_credentials=None,
|
||||
call_credentials=None,
|
||||
insecure=False,
|
||||
compression=None,
|
||||
wait_for_ready=None,
|
||||
timeout=None,
|
||||
metadata=None):
|
||||
return grpc.experimental.unary_unary(
|
||||
request,
|
||||
target,
|
||||
'/ateapi.Control/DeleteActorTemplateVersion',
|
||||
ateapi__pb2.DeleteActorTemplateVersionRequest.SerializeToString,
|
||||
ateapi__pb2.ActorTemplateVersion.FromString,
|
||||
options,
|
||||
channel_credentials,
|
||||
insecure,
|
||||
call_credentials,
|
||||
compression,
|
||||
wait_for_ready,
|
||||
timeout,
|
||||
metadata,
|
||||
_registered_method=True)
|
||||
|
||||
|
||||
class DebugStub:
|
||||
"""Debug is the RPC interface for administrative and debugging operations
|
||||
@@ -947,20 +1348,10 @@ class Debug:
|
||||
class ActorIdentityStub:
|
||||
"""ActorIdentity allows substrate workloads to exchange their
|
||||
infrastructure-level credentials (k8s service account token, etc.) for a
|
||||
substrate actor-level credential. A given substrate actor might migrate
|
||||
substrate actor-level credential. A given substrate actor might migrate
|
||||
between many different physical workers over the course of its lifecycle,
|
||||
whereas the actor credential's identity will be stable for the life of the
|
||||
actor.
|
||||
|
||||
This service requires authentication. You can authenticate with a Kubernetes
|
||||
service account token in an `Authorization: Bearer` header, or you can
|
||||
authenticate with a Kubernetes service account certificate as an mTLS
|
||||
certificate. (Kubernetes service account certificates do not currently exist
|
||||
upstream, but we will provide a polyfill based on Pod Certificates).
|
||||
|
||||
The broker will check that the service credentials you authenticated with
|
||||
belong to a Pod that is currently mapped to the requested actor in the
|
||||
actor database.
|
||||
"""
|
||||
|
||||
def __init__(self, channel):
|
||||
@@ -984,20 +1375,10 @@ class ActorIdentityStub:
|
||||
class ActorIdentityServicer:
|
||||
"""ActorIdentity allows substrate workloads to exchange their
|
||||
infrastructure-level credentials (k8s service account token, etc.) for a
|
||||
substrate actor-level credential. A given substrate actor might migrate
|
||||
substrate actor-level credential. A given substrate actor might migrate
|
||||
between many different physical workers over the course of its lifecycle,
|
||||
whereas the actor credential's identity will be stable for the life of the
|
||||
actor.
|
||||
|
||||
This service requires authentication. You can authenticate with a Kubernetes
|
||||
service account token in an `Authorization: Bearer` header, or you can
|
||||
authenticate with a Kubernetes service account certificate as an mTLS
|
||||
certificate. (Kubernetes service account certificates do not currently exist
|
||||
upstream, but we will provide a polyfill based on Pod Certificates).
|
||||
|
||||
The broker will check that the service credentials you authenticated with
|
||||
belong to a Pod that is currently mapped to the requested actor in the
|
||||
actor database.
|
||||
"""
|
||||
|
||||
def MintJWT(self, request, context):
|
||||
@@ -1017,10 +1398,9 @@ class ActorIdentityServicer:
|
||||
it on the actor's behalf, authenticating with its own client certificate
|
||||
rather than a bearer token.
|
||||
|
||||
Authorization is decided on that client certificate: it must identify the
|
||||
atelet running on the same node as the worker Pod that currently hosts the
|
||||
requested actor, and the actor must still be running. Any other caller is
|
||||
rejected with PERMISSION_DENIED.
|
||||
Authorization is decided on that client certificate and the worker
|
||||
identity attested by atelet. Ateapi verifies that the worker is assigned to
|
||||
the actor and that the actor points back to that exact worker before signing.
|
||||
|
||||
The certificate in the response is the actor's identity, not the atelet's.
|
||||
"""
|
||||
@@ -1052,20 +1432,10 @@ def add_ActorIdentityServicer_to_server(servicer, server):
|
||||
class ActorIdentity:
|
||||
"""ActorIdentity allows substrate workloads to exchange their
|
||||
infrastructure-level credentials (k8s service account token, etc.) for a
|
||||
substrate actor-level credential. A given substrate actor might migrate
|
||||
substrate actor-level credential. A given substrate actor might migrate
|
||||
between many different physical workers over the course of its lifecycle,
|
||||
whereas the actor credential's identity will be stable for the life of the
|
||||
actor.
|
||||
|
||||
This service requires authentication. You can authenticate with a Kubernetes
|
||||
service account token in an `Authorization: Bearer` header, or you can
|
||||
authenticate with a Kubernetes service account certificate as an mTLS
|
||||
certificate. (Kubernetes service account certificates do not currently exist
|
||||
upstream, but we will provide a polyfill based on Pod Certificates).
|
||||
|
||||
The broker will check that the service credentials you authenticated with
|
||||
belong to a Pod that is currently mapped to the requested actor in the
|
||||
actor database.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/agent-substrate/substrate/cmd/ateapi/internal/store"
|
||||
"github.com/agent-substrate/substrate/internal/fieldmask"
|
||||
@@ -30,6 +31,8 @@ import (
|
||||
)
|
||||
|
||||
// actorSnapshotTagScopes lists the scopes a client may set on an ActorSnapshotTag.
|
||||
// ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED is deliberately absent: scope is required
|
||||
// on the wire, not defaulted. See validateActorSnapshotTagScope.
|
||||
var actorSnapshotTagScopes = []ateapipb.ActorSnapshotTagScope{
|
||||
ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE,
|
||||
ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED,
|
||||
@@ -184,9 +187,7 @@ func validateUpdateActorSnapshotTagRequest(req *ateapipb.UpdateActorSnapshotTagR
|
||||
|
||||
errs = append(errs, fieldmask.Validate(req.GetUpdateMask(), actorSnapshotTagMutableFields, field.NewPath("update_mask"))...)
|
||||
|
||||
if scope, p := tag.GetScope(), tagPath.Child("scope"); validateActorSnapshotTagScope(scope) != nil {
|
||||
errs = append(errs, field.NotSupported(p, scope.String(), actorSnapshotTagScopeNames))
|
||||
}
|
||||
errs = append(errs, validateActorSnapshotTagScope(tag.GetScope(), tagPath.Child("scope"))...)
|
||||
|
||||
return errs
|
||||
}
|
||||
@@ -271,12 +272,19 @@ func validateActorSnapshotTag(tag *ateapipb.ActorSnapshotTag, name string) error
|
||||
if errs := resources.ValidateObjectRef(&ateapipb.ObjectRef{Atespace: tag.GetMetadata().GetAtespace(), Name: tag.GetMetadata().GetName()}, p.Child("metadata")); len(errs) > 0 {
|
||||
return status.Error(codes.InvalidArgument, errs.ToAggregate().Error())
|
||||
}
|
||||
return validateActorSnapshotTagScope(tag.GetScope())
|
||||
if errs := validateActorSnapshotTagScope(tag.GetScope(), p.Child("scope")); len(errs) > 0 {
|
||||
return status.Error(codes.InvalidArgument, errs.ToAggregate().Error())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateActorSnapshotTagScope(scope ateapipb.ActorSnapshotTagScope) error {
|
||||
if slices.Contains(actorSnapshotTagScopes, scope) {
|
||||
return nil
|
||||
// validateActorSnapshotTagScope checks that scope is one a client may set.
|
||||
func validateActorSnapshotTagScope(scope ateapipb.ActorSnapshotTagScope, p *field.Path) field.ErrorList {
|
||||
switch {
|
||||
case scope == ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED:
|
||||
return field.ErrorList{field.Required(p, "must be one of: "+strings.Join(actorSnapshotTagScopeNames, ", "))}
|
||||
case !slices.Contains(actorSnapshotTagScopes, scope):
|
||||
return field.ErrorList{field.NotSupported(p, scope.String(), actorSnapshotTagScopeNames)}
|
||||
}
|
||||
return status.Error(codes.InvalidArgument, "invalid ActorSnapshot tag scope")
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -202,7 +202,6 @@ func TestValidateUpdateActorSnapshotTagRequest(t *testing.T) {
|
||||
wantError: field.ErrorList{field.NotSupported(field.NewPath("update_mask"), "snapshot", mutableFields)},
|
||||
},
|
||||
{
|
||||
// The zero value is ATESPACE, so leaving scope unset unpublishes the tag.
|
||||
name: "unset tag.scope",
|
||||
req: &ateapipb.UpdateActorSnapshotTagRequest{
|
||||
Tag: &ateapipb.ActorSnapshotTag{
|
||||
@@ -210,6 +209,28 @@ func TestValidateUpdateActorSnapshotTagRequest(t *testing.T) {
|
||||
},
|
||||
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"scope"}},
|
||||
},
|
||||
wantError: field.ErrorList{field.Required(field.NewPath("tag", "scope"), "")},
|
||||
},
|
||||
{
|
||||
name: "explicit tag.scope UNSPECIFIED",
|
||||
req: &ateapipb.UpdateActorSnapshotTagRequest{
|
||||
Tag: &ateapipb.ActorSnapshotTag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: "ns1", Name: "tag1"},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED,
|
||||
},
|
||||
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"scope"}},
|
||||
},
|
||||
wantError: field.ErrorList{field.Required(field.NewPath("tag", "scope"), "")},
|
||||
},
|
||||
{
|
||||
name: "tag.scope ATESPACE explicitly unpublishes",
|
||||
req: &ateapipb.UpdateActorSnapshotTagRequest{
|
||||
Tag: &ateapipb.ActorSnapshotTag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: "ns1", Name: "tag1"},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE,
|
||||
},
|
||||
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"scope"}},
|
||||
},
|
||||
wantError: nil,
|
||||
},
|
||||
{
|
||||
@@ -240,18 +261,18 @@ func TestUpdateActorSnapshotTag_FieldMasks(t *testing.T) {
|
||||
want *ateapipb.ActorSnapshotTag
|
||||
}{
|
||||
{
|
||||
name: "mask sets scope",
|
||||
stored: &ateapipb.ActorSnapshotTag{},
|
||||
name: "mask publishes an atespace-scoped tag",
|
||||
stored: &ateapipb.ActorSnapshotTag{Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE},
|
||||
req: &ateapipb.ActorSnapshotTag{Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED},
|
||||
maskPaths: []string{"scope"},
|
||||
want: &ateapipb.ActorSnapshotTag{Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED},
|
||||
},
|
||||
{
|
||||
name: "mask clears scope left unset on request, resetting to the zero value",
|
||||
name: "mask unpublishes a published tag",
|
||||
stored: &ateapipb.ActorSnapshotTag{Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED},
|
||||
req: &ateapipb.ActorSnapshotTag{},
|
||||
req: &ateapipb.ActorSnapshotTag{Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE},
|
||||
maskPaths: []string{"scope"},
|
||||
want: &ateapipb.ActorSnapshotTag{},
|
||||
want: &ateapipb.ActorSnapshotTag{Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -280,6 +301,59 @@ func TestUpdateActorSnapshotTag_FieldMasks(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestUpdateActorSnapshotTag_UnsetScopeDoesNotUnpublish checks that masking
|
||||
// scope without populating it is rejected.
|
||||
func TestUpdateActorSnapshotTag_UnsetScopeDoesNotUnpublish(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
svc, stored := serviceWithActorSnapshotTag(t, &ateapipb.ActorSnapshotTag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "tag1"},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED,
|
||||
})
|
||||
|
||||
_, err := svc.UpdateActorSnapshotTag(ctx, &ateapipb.UpdateActorSnapshotTagRequest{
|
||||
Tag: &ateapipb.ActorSnapshotTag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "tag1"},
|
||||
},
|
||||
UpdateMask: &fieldmaskpb.FieldMask{Paths: []string{"scope"}},
|
||||
})
|
||||
if code := status.Code(err); code != codes.InvalidArgument {
|
||||
t.Errorf("UpdateActorSnapshotTag error = %v (code %v), want code InvalidArgument", err, code)
|
||||
}
|
||||
|
||||
_, current, err := svc.persistence.GetActorSnapshotByTag(ctx, testAtespace, "tag1")
|
||||
if err != nil {
|
||||
t.Fatalf("GetActorSnapshotByTag: %v", err)
|
||||
}
|
||||
if got, want := current.GetScope(), ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED; got != want {
|
||||
t.Errorf("stored scope = %v, want %v: the rejected update must not have unpublished the tag", got, want)
|
||||
}
|
||||
if got, want := current.GetMetadata().GetVersion(), stored.GetMetadata().GetVersion(); got != want {
|
||||
t.Errorf("stored version = %d, want %d: the rejected update must not have written", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// TestTagActorSnapshot_RejectsUnsetScope checks that scope is required at
|
||||
// creation.
|
||||
func TestTagActorSnapshot_RejectsUnsetScope(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
svc, stored := serviceWithActorSnapshotTag(t, &ateapipb.ActorSnapshotTag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "tag1"},
|
||||
Scope: ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE,
|
||||
})
|
||||
|
||||
_, err := svc.TagActorSnapshot(ctx, &ateapipb.TagActorSnapshotRequest{
|
||||
Snapshot: &ateapipb.ActorSnapshotRef{
|
||||
Reference: &ateapipb.ActorSnapshotRef_Snapshot{Snapshot: stored.GetSnapshot()},
|
||||
},
|
||||
Tag: &ateapipb.ActorSnapshotTag{
|
||||
Metadata: &ateapipb.ResourceMetadata{Atespace: testAtespace, Name: "tag2"},
|
||||
},
|
||||
})
|
||||
if code := status.Code(err); code != codes.InvalidArgument {
|
||||
t.Errorf("TagActorSnapshot error = %v (code %v), want code InvalidArgument", err, code)
|
||||
}
|
||||
}
|
||||
|
||||
// serviceWithActorSnapshotTag seeds an ActorSnapshot and a tag pointing at it
|
||||
// in a miniredis-backed store, and returns a Service over it.
|
||||
func serviceWithActorSnapshotTag(t *testing.T, tag *ateapipb.ActorSnapshotTag) (*Service, *ateapipb.ActorSnapshotTag) {
|
||||
|
||||
@@ -190,7 +190,7 @@ func parseActorSnapshotTagScope(value string) (ateapipb.ActorSnapshotTagScope, e
|
||||
case "published":
|
||||
return ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("invalid scope %q; must be atespace or published", value)
|
||||
return ateapipb.ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED, fmt.Errorf("invalid scope %q; must be atespace or published", value)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,22 +92,26 @@ func (SnapshotContentScope) EnumDescriptor() ([]byte, []int) {
|
||||
type ActorSnapshotTagScope int32
|
||||
|
||||
const (
|
||||
// Not set and rejected wherever a client supplies a scope
|
||||
ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED ActorSnapshotTagScope = 0
|
||||
// May initialize Actors only in the tag's owning Atespace.
|
||||
ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE ActorSnapshotTagScope = 0
|
||||
ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE ActorSnapshotTagScope = 1
|
||||
// Published for use by Actors in any Atespace. The tag remains addressed
|
||||
// through its owning Atespace.
|
||||
ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED ActorSnapshotTagScope = 1
|
||||
ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED ActorSnapshotTagScope = 2
|
||||
)
|
||||
|
||||
// Enum value maps for ActorSnapshotTagScope.
|
||||
var (
|
||||
ActorSnapshotTagScope_name = map[int32]string{
|
||||
0: "ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE",
|
||||
1: "ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED",
|
||||
0: "ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED",
|
||||
1: "ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE",
|
||||
2: "ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED",
|
||||
}
|
||||
ActorSnapshotTagScope_value = map[string]int32{
|
||||
"ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE": 0,
|
||||
"ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED": 1,
|
||||
"ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED": 0,
|
||||
"ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE": 1,
|
||||
"ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED": 2,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1229,7 +1233,7 @@ func (x *ActorSnapshotTag) GetScope() ActorSnapshotTagScope {
|
||||
if x != nil {
|
||||
return x.Scope
|
||||
}
|
||||
return ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE
|
||||
return ActorSnapshotTagScope_ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED
|
||||
}
|
||||
|
||||
// Atespace is the isolation boundary an Actor is created into. Global-scoped:
|
||||
@@ -5450,10 +5454,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*f\n" +
|
||||
"\x15ActorSnapshotTagScope\x12%\n" +
|
||||
"!ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE\x10\x00\x12&\n" +
|
||||
"\"ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED\x10\x01*b\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*b\n" +
|
||||
"\fSandboxClass\x12\x1d\n" +
|
||||
"\x19SANDBOX_CLASS_UNSPECIFIED\x10\x00\x12\x18\n" +
|
||||
"\x14SANDBOX_CLASS_GVISOR\x10\x01\x12\x19\n" +
|
||||
|
||||
@@ -135,11 +135,13 @@ enum SnapshotContentScope {
|
||||
}
|
||||
|
||||
enum ActorSnapshotTagScope {
|
||||
// Not set and rejected wherever a client supplies a scope
|
||||
ACTOR_SNAPSHOT_TAG_SCOPE_UNSPECIFIED = 0;
|
||||
// May initialize Actors only in the tag's owning Atespace.
|
||||
ACTOR_SNAPSHOT_TAG_SCOPE_ATESPACE = 0;
|
||||
ACTOR_SNAPSHOT_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 = 1;
|
||||
ACTOR_SNAPSHOT_TAG_SCOPE_PUBLISHED = 2;
|
||||
}
|
||||
|
||||
// Selector matches worker pools by label.
|
||||
|
||||
Reference in New Issue
Block a user