Create tombstone on resource `Delete` (#17108)

This commit is contained in:
Semir Patel 2023-04-28 10:49:08 -05:00 committed by GitHub
parent 6d024775a0
commit 896c39d98c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 511 additions and 280 deletions

View File

@ -6,11 +6,17 @@ package resource
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"time"
"github.com/golang/protobuf/proto"
"github.com/oklog/ulid/v2"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/anypb"
"github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/internal/resource"
"github.com/hashicorp/consul/internal/storage" "github.com/hashicorp/consul/internal/storage"
"github.com/hashicorp/consul/proto-public/pbresource" "github.com/hashicorp/consul/proto-public/pbresource"
) )
@ -21,8 +27,6 @@ import (
// - Delete of a previously deleted or non-existent resource is a no-op to support idempotency. // - Delete of a previously deleted or non-existent resource is a no-op to support idempotency.
// - Errors with Aborted if the requested Version does not match the stored Version. // - Errors with Aborted if the requested Version does not match the stored Version.
// - Errors with PermissionDenied if ACL check fails // - Errors with PermissionDenied if ACL check fails
//
// TODO(spatel): Move docs to the proto file
func (s *Server) Delete(ctx context.Context, req *pbresource.DeleteRequest) (*pbresource.DeleteResponse, error) { func (s *Server) Delete(ctx context.Context, req *pbresource.DeleteRequest) (*pbresource.DeleteResponse, error) {
if err := validateDeleteRequest(req); err != nil { if err := validateDeleteRequest(req); err != nil {
return nil, err return nil, err
@ -69,6 +73,10 @@ func (s *Server) Delete(ctx context.Context, req *pbresource.DeleteRequest) (*pb
} }
} }
if err := s.maybeCreateTombstone(ctx, deleteId); err != nil {
return nil, err
}
err = s.Backend.DeleteCAS(ctx, deleteId, deleteVersion) err = s.Backend.DeleteCAS(ctx, deleteId, deleteVersion)
switch { switch {
case err == nil: case err == nil:
@ -80,6 +88,62 @@ func (s *Server) Delete(ctx context.Context, req *pbresource.DeleteRequest) (*pb
} }
} }
// Create a tombstone to capture the intent to delete child resources.
// Tombstones are created preemptively to prevent partial failures even though
// we are currently unaware of the success/failure/no-op of DeleteCAS. In
// the failure and no-op cases the tombstone is effectively a no-op and will
// still be deleted from the system by the reaper controller.
func (s *Server) maybeCreateTombstone(ctx context.Context, deleteId *pbresource.ID) error {
// Don't create a tombstone when the resource being deleted is itself a tombstone.
if proto.Equal(resource.TypeV1Tombstone, deleteId.Type) {
return nil
}
data, err := anypb.New(&pbresource.Tombstone{Owner: deleteId})
if err != nil {
return status.Errorf(codes.Internal, "failed creating tombstone: %v", err)
}
// Since a tombstone is an internal resource type that should not be visible
// or accessible by users, we're writing to the backend directly instead of
// using the resource service's Write endpoint. This bypasses resource level
// concerns that are either not relevant (valiation and mutation hooks) or
// futher complicate the implementation (user provided tokens having
// awareness of tombstone ACLs).
//
// ErrCASFailure should never happen since an empty Version is always passed.
//
// TODO(spatel): Probably a good idea to block writes of TypeV1Tombstone
// on the ResourceService.Write() endpoint to lock things down?
_, err = s.Backend.WriteCAS(ctx, &pbresource.Resource{
Id: &pbresource.ID{
Type: resource.TypeV1Tombstone,
Tenancy: deleteId.Tenancy,
Name: tombstoneName(deleteId),
Uid: ulid.Make().String(),
},
Generation: ulid.Make().String(),
Data: data,
Metadata: map[string]string{
"generated_at": time.Now().Format(time.RFC3339),
},
})
switch {
case err == nil:
// Success!
return nil
case errors.Is(err, storage.ErrWrongUid):
// Backend has detected that we're trying to change the Uid for an
// existing tombstone (probably created from a previously failed Delete
// where the tombstone WriteCAS succeeded but the resource DeleteCAS
// failed). The fact that the tombstone already exists means we're good.
return nil
default:
return status.Errorf(codes.Internal, "failed writing tombstone: %v", err)
}
}
func validateDeleteRequest(req *pbresource.DeleteRequest) error { func validateDeleteRequest(req *pbresource.DeleteRequest) error {
if req.Id == nil { if req.Id == nil {
return status.Errorf(codes.InvalidArgument, "id is required") return status.Errorf(codes.InvalidArgument, "id is required")
@ -90,3 +154,10 @@ func validateDeleteRequest(req *pbresource.DeleteRequest) error {
} }
return nil return nil
} }
// Maintains a deterministic mapping between a resource and it's tombstone's
// name by embedding the resources's Uid in the name.
func tombstoneName(deleteId *pbresource.ID) string {
// deleteId.Name is just included for easier identification
return fmt.Sprintf("tombstone-%v-%v", deleteId.Name, deleteId.Uid)
}

View File

@ -13,6 +13,7 @@ import (
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"github.com/hashicorp/consul/acl/resolver" "github.com/hashicorp/consul/acl/resolver"
"github.com/hashicorp/consul/internal/resource"
"github.com/hashicorp/consul/internal/resource/demo" "github.com/hashicorp/consul/internal/resource/demo"
"github.com/hashicorp/consul/internal/storage" "github.com/hashicorp/consul/internal/storage"
"github.com/hashicorp/consul/proto-public/pbresource" "github.com/hashicorp/consul/proto-public/pbresource"
@ -139,10 +140,58 @@ func TestDelete_Success(t *testing.T) {
_, err = server.Backend.Read(ctx, storage.StrongConsistency, artistId) _, err = server.Backend.Read(ctx, storage.StrongConsistency, artistId)
require.Error(t, err) require.Error(t, err)
require.ErrorIs(t, err, storage.ErrNotFound) require.ErrorIs(t, err, storage.ErrNotFound)
// verify tombstone created
_, err = client.Read(ctx, &pbresource.ReadRequest{
Id: &pbresource.ID{
Name: tombstoneName(artistId),
Type: resource.TypeV1Tombstone,
Tenancy: artist.Id.Tenancy,
},
})
require.NoError(t, err)
}) })
} }
} }
func TestDelete_TombstoneDeletionDoesNotCreateNewTombstone(t *testing.T) {
t.Parallel()
server, client, ctx := testDeps(t)
demo.RegisterTypes(server.Registry)
artist, err := demo.GenerateV2Artist()
require.NoError(t, err)
rsp, err := client.Write(ctx, &pbresource.WriteRequest{Resource: artist})
require.NoError(t, err)
artist = rsp.Resource
// delete artist
_, err = client.Delete(ctx, &pbresource.DeleteRequest{Id: artist.Id, Version: ""})
require.NoError(t, err)
// verify artist's tombstone created
rsp2, err := client.Read(ctx, &pbresource.ReadRequest{
Id: &pbresource.ID{
Name: tombstoneName(artist.Id),
Type: resource.TypeV1Tombstone,
Tenancy: artist.Id.Tenancy,
},
})
require.NoError(t, err)
tombstone := rsp2.Resource
// delete artist's tombstone
_, err = client.Delete(ctx, &pbresource.DeleteRequest{Id: tombstone.Id, Version: tombstone.Version})
require.NoError(t, err)
// verify no new tombstones created and artist's existing tombstone deleted
rsp3, err := client.List(ctx, &pbresource.ListRequest{Type: resource.TypeV1Tombstone, Tenancy: artist.Id.Tenancy})
require.NoError(t, err)
require.Empty(t, rsp3.Resources)
}
func TestDelete_NotFound(t *testing.T) { func TestDelete_NotFound(t *testing.T) {
t.Parallel() t.Parallel()

View File

@ -68,9 +68,17 @@ type TypeRegistry struct {
} }
func NewRegistry() Registry { func NewRegistry() Registry {
return &TypeRegistry{ registry := &TypeRegistry{registrations: make(map[string]Registration)}
registrations: make(map[string]Registration), // Tombstone is an implicitly registered type since it is used to implement
} // the cascading deletion of resources. ACLs end up being defaulted to
// operator:<read,write>. It is useful to note that tombstone creation
// does not get routed through the resource service and bypasses ACLs
// as part of the Delete endpoint.
registry.Register(Registration{
Type: TypeV1Tombstone,
Proto: &pbresource.Tombstone{},
})
return registry
} }
func (r *TypeRegistry) Register(registration Registration) { func (r *TypeRegistry) Register(registration Registration) {

View File

@ -11,52 +11,53 @@ import (
"github.com/hashicorp/consul/internal/resource" "github.com/hashicorp/consul/internal/resource"
"github.com/hashicorp/consul/internal/resource/demo" "github.com/hashicorp/consul/internal/resource/demo"
"github.com/hashicorp/consul/proto-public/pbresource" "github.com/hashicorp/consul/proto-public/pbresource"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
) )
func TestRegister(t *testing.T) { func TestRegister(t *testing.T) {
r := resource.NewRegistry() r := resource.NewRegistry()
serviceType := &pbresource.Type{
Group: "mesh",
GroupVersion: "v1",
Kind: "service",
}
// register success // register success
serviceRegistration := resource.Registration{Type: serviceType} reg := resource.Registration{Type: demo.TypeV2Artist}
r.Register(serviceRegistration) r.Register(reg)
actual, ok := r.Resolve(demo.TypeV2Artist)
require.True(t, ok)
require.True(t, proto.Equal(demo.TypeV2Artist, actual.Type))
// register existing should panic // register existing should panic
assertRegisterPanics(t, r.Register, serviceRegistration, "resource type mesh.v1.service already registered") require.PanicsWithValue(t, "resource type demo.v2.artist already registered", func() {
r.Register(reg)
})
// register empty Group should panic // type missing required fields should panic
assertRegisterPanics(t, r.Register, resource.Registration{ testcases := map[string]*pbresource.Type{
Type: &pbresource.Type{ "empty group": {
Group: "", Group: "",
GroupVersion: "v1", GroupVersion: "v2",
Kind: "service", Kind: "artist",
}, },
}, "type field(s) cannot be empty") "empty group version": {
Group: "",
// register empty GroupVersion should panic GroupVersion: "v2",
assertRegisterPanics(t, r.Register, resource.Registration{ Kind: "artist",
Type: &pbresource.Type{
Group: "mesh",
GroupVersion: "",
Kind: "service",
}, },
}, "type field(s) cannot be empty") "empty kind": {
Group: "demo",
// register empty Kind should panic GroupVersion: "v2",
assertRegisterPanics(t, r.Register, resource.Registration{
Type: &pbresource.Type{
Group: "mesh",
GroupVersion: "v1",
Kind: "", Kind: "",
}, },
}, "type field(s) cannot be empty") }
for desc, typ := range testcases {
t.Run(desc, func(t *testing.T) {
require.PanicsWithValue(t, "type field(s) cannot be empty", func() {
r.Register(resource.Registration{Type: typ})
})
})
}
} }
func TestRegister_Defaults(t *testing.T) { func TestRegister_Defaults(t *testing.T) {
@ -87,21 +88,12 @@ func TestRegister_Defaults(t *testing.T) {
require.NoError(t, reg.Mutate(nil)) require.NoError(t, reg.Mutate(nil))
} }
func assertRegisterPanics(t *testing.T, registerFn func(reg resource.Registration), registration resource.Registration, panicString string) { func TestNewRegistry(t *testing.T) {
defer func() { r := resource.NewRegistry()
if r := recover(); r == nil {
t.Errorf("expected panic, but none occurred")
} else {
errstr, ok := r.(string)
if !ok {
t.Errorf("unexpected error type returned from panic")
} else if errstr != panicString {
t.Errorf("expected %s error message but got: %s", panicString, errstr)
}
}
}()
registerFn(registration) // verify tombstone type registered implicitly
_, ok := r.Resolve(resource.TypeV1Tombstone)
require.True(t, ok)
} }
func TestResolve(t *testing.T) { func TestResolve(t *testing.T) {

View File

@ -0,0 +1,11 @@
package resource
import "github.com/hashicorp/consul/proto-public/pbresource"
var (
TypeV1Tombstone = &pbresource.Type{
Group: "internal",
GroupVersion: "v1",
Kind: "tombstone",
}
)

View File

@ -77,6 +77,16 @@ func (msg *Reference) UnmarshalBinary(b []byte) error {
return proto.Unmarshal(b, msg) return proto.Unmarshal(b, msg)
} }
// MarshalBinary implements encoding.BinaryMarshaler
func (msg *Tombstone) MarshalBinary() ([]byte, error) {
return proto.Marshal(msg)
}
// UnmarshalBinary implements encoding.BinaryUnmarshaler
func (msg *Tombstone) UnmarshalBinary(b []byte) error {
return proto.Unmarshal(b, msg)
}
// MarshalBinary implements encoding.BinaryMarshaler // MarshalBinary implements encoding.BinaryMarshaler
func (msg *ReadRequest) MarshalBinary() ([]byte, error) { func (msg *ReadRequest) MarshalBinary() ([]byte, error) {
return proto.Marshal(msg) return proto.Marshal(msg)

View File

@ -133,7 +133,7 @@ func (x WatchEvent_Operation) Number() protoreflect.EnumNumber {
// Deprecated: Use WatchEvent_Operation.Descriptor instead. // Deprecated: Use WatchEvent_Operation.Descriptor instead.
func (WatchEvent_Operation) EnumDescriptor() ([]byte, []int) { func (WatchEvent_Operation) EnumDescriptor() ([]byte, []int) {
return file_pbresource_resource_proto_rawDescGZIP(), []int{18, 0} return file_pbresource_resource_proto_rawDescGZIP(), []int{19, 0}
} }
// Type describes a resource's type. It follows the GVK (Group Version Kind) // Type describes a resource's type. It follows the GVK (Group Version Kind)
@ -722,6 +722,56 @@ func (x *Reference) GetSection() string {
return "" return ""
} }
// Tombstone represents a promise to delete all of a resource's immediately
// owned (child) resources, if any.
type Tombstone struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Owner resource identifier.
Owner *ID `protobuf:"bytes,1,opt,name=owner,proto3" json:"owner,omitempty"`
}
func (x *Tombstone) Reset() {
*x = Tombstone{}
if protoimpl.UnsafeEnabled {
mi := &file_pbresource_resource_proto_msgTypes[7]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *Tombstone) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*Tombstone) ProtoMessage() {}
func (x *Tombstone) ProtoReflect() protoreflect.Message {
mi := &file_pbresource_resource_proto_msgTypes[7]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use Tombstone.ProtoReflect.Descriptor instead.
func (*Tombstone) Descriptor() ([]byte, []int) {
return file_pbresource_resource_proto_rawDescGZIP(), []int{7}
}
func (x *Tombstone) GetOwner() *ID {
if x != nil {
return x.Owner
}
return nil
}
// ReadRequest contains the parameters to the Read endpoint. // ReadRequest contains the parameters to the Read endpoint.
type ReadRequest struct { type ReadRequest struct {
state protoimpl.MessageState state protoimpl.MessageState
@ -735,7 +785,7 @@ type ReadRequest struct {
func (x *ReadRequest) Reset() { func (x *ReadRequest) Reset() {
*x = ReadRequest{} *x = ReadRequest{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_pbresource_resource_proto_msgTypes[7] mi := &file_pbresource_resource_proto_msgTypes[8]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -748,7 +798,7 @@ func (x *ReadRequest) String() string {
func (*ReadRequest) ProtoMessage() {} func (*ReadRequest) ProtoMessage() {}
func (x *ReadRequest) ProtoReflect() protoreflect.Message { func (x *ReadRequest) ProtoReflect() protoreflect.Message {
mi := &file_pbresource_resource_proto_msgTypes[7] mi := &file_pbresource_resource_proto_msgTypes[8]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -761,7 +811,7 @@ func (x *ReadRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use ReadRequest.ProtoReflect.Descriptor instead. // Deprecated: Use ReadRequest.ProtoReflect.Descriptor instead.
func (*ReadRequest) Descriptor() ([]byte, []int) { func (*ReadRequest) Descriptor() ([]byte, []int) {
return file_pbresource_resource_proto_rawDescGZIP(), []int{7} return file_pbresource_resource_proto_rawDescGZIP(), []int{8}
} }
func (x *ReadRequest) GetId() *ID { func (x *ReadRequest) GetId() *ID {
@ -784,7 +834,7 @@ type ReadResponse struct {
func (x *ReadResponse) Reset() { func (x *ReadResponse) Reset() {
*x = ReadResponse{} *x = ReadResponse{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_pbresource_resource_proto_msgTypes[8] mi := &file_pbresource_resource_proto_msgTypes[9]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -797,7 +847,7 @@ func (x *ReadResponse) String() string {
func (*ReadResponse) ProtoMessage() {} func (*ReadResponse) ProtoMessage() {}
func (x *ReadResponse) ProtoReflect() protoreflect.Message { func (x *ReadResponse) ProtoReflect() protoreflect.Message {
mi := &file_pbresource_resource_proto_msgTypes[8] mi := &file_pbresource_resource_proto_msgTypes[9]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -810,7 +860,7 @@ func (x *ReadResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use ReadResponse.ProtoReflect.Descriptor instead. // Deprecated: Use ReadResponse.ProtoReflect.Descriptor instead.
func (*ReadResponse) Descriptor() ([]byte, []int) { func (*ReadResponse) Descriptor() ([]byte, []int) {
return file_pbresource_resource_proto_rawDescGZIP(), []int{8} return file_pbresource_resource_proto_rawDescGZIP(), []int{9}
} }
func (x *ReadResponse) GetResource() *Resource { func (x *ReadResponse) GetResource() *Resource {
@ -839,7 +889,7 @@ type ListRequest struct {
func (x *ListRequest) Reset() { func (x *ListRequest) Reset() {
*x = ListRequest{} *x = ListRequest{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_pbresource_resource_proto_msgTypes[9] mi := &file_pbresource_resource_proto_msgTypes[10]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -852,7 +902,7 @@ func (x *ListRequest) String() string {
func (*ListRequest) ProtoMessage() {} func (*ListRequest) ProtoMessage() {}
func (x *ListRequest) ProtoReflect() protoreflect.Message { func (x *ListRequest) ProtoReflect() protoreflect.Message {
mi := &file_pbresource_resource_proto_msgTypes[9] mi := &file_pbresource_resource_proto_msgTypes[10]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -865,7 +915,7 @@ func (x *ListRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use ListRequest.ProtoReflect.Descriptor instead. // Deprecated: Use ListRequest.ProtoReflect.Descriptor instead.
func (*ListRequest) Descriptor() ([]byte, []int) { func (*ListRequest) Descriptor() ([]byte, []int) {
return file_pbresource_resource_proto_rawDescGZIP(), []int{9} return file_pbresource_resource_proto_rawDescGZIP(), []int{10}
} }
func (x *ListRequest) GetType() *Type { func (x *ListRequest) GetType() *Type {
@ -902,7 +952,7 @@ type ListResponse struct {
func (x *ListResponse) Reset() { func (x *ListResponse) Reset() {
*x = ListResponse{} *x = ListResponse{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_pbresource_resource_proto_msgTypes[10] mi := &file_pbresource_resource_proto_msgTypes[11]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -915,7 +965,7 @@ func (x *ListResponse) String() string {
func (*ListResponse) ProtoMessage() {} func (*ListResponse) ProtoMessage() {}
func (x *ListResponse) ProtoReflect() protoreflect.Message { func (x *ListResponse) ProtoReflect() protoreflect.Message {
mi := &file_pbresource_resource_proto_msgTypes[10] mi := &file_pbresource_resource_proto_msgTypes[11]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -928,7 +978,7 @@ func (x *ListResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use ListResponse.ProtoReflect.Descriptor instead. // Deprecated: Use ListResponse.ProtoReflect.Descriptor instead.
func (*ListResponse) Descriptor() ([]byte, []int) { func (*ListResponse) Descriptor() ([]byte, []int) {
return file_pbresource_resource_proto_rawDescGZIP(), []int{10} return file_pbresource_resource_proto_rawDescGZIP(), []int{11}
} }
func (x *ListResponse) GetResources() []*Resource { func (x *ListResponse) GetResources() []*Resource {
@ -951,7 +1001,7 @@ type WriteRequest struct {
func (x *WriteRequest) Reset() { func (x *WriteRequest) Reset() {
*x = WriteRequest{} *x = WriteRequest{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_pbresource_resource_proto_msgTypes[11] mi := &file_pbresource_resource_proto_msgTypes[12]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -964,7 +1014,7 @@ func (x *WriteRequest) String() string {
func (*WriteRequest) ProtoMessage() {} func (*WriteRequest) ProtoMessage() {}
func (x *WriteRequest) ProtoReflect() protoreflect.Message { func (x *WriteRequest) ProtoReflect() protoreflect.Message {
mi := &file_pbresource_resource_proto_msgTypes[11] mi := &file_pbresource_resource_proto_msgTypes[12]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -977,7 +1027,7 @@ func (x *WriteRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use WriteRequest.ProtoReflect.Descriptor instead. // Deprecated: Use WriteRequest.ProtoReflect.Descriptor instead.
func (*WriteRequest) Descriptor() ([]byte, []int) { func (*WriteRequest) Descriptor() ([]byte, []int) {
return file_pbresource_resource_proto_rawDescGZIP(), []int{11} return file_pbresource_resource_proto_rawDescGZIP(), []int{12}
} }
func (x *WriteRequest) GetResource() *Resource { func (x *WriteRequest) GetResource() *Resource {
@ -1000,7 +1050,7 @@ type WriteResponse struct {
func (x *WriteResponse) Reset() { func (x *WriteResponse) Reset() {
*x = WriteResponse{} *x = WriteResponse{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_pbresource_resource_proto_msgTypes[12] mi := &file_pbresource_resource_proto_msgTypes[13]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1013,7 +1063,7 @@ func (x *WriteResponse) String() string {
func (*WriteResponse) ProtoMessage() {} func (*WriteResponse) ProtoMessage() {}
func (x *WriteResponse) ProtoReflect() protoreflect.Message { func (x *WriteResponse) ProtoReflect() protoreflect.Message {
mi := &file_pbresource_resource_proto_msgTypes[12] mi := &file_pbresource_resource_proto_msgTypes[13]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1026,7 +1076,7 @@ func (x *WriteResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use WriteResponse.ProtoReflect.Descriptor instead. // Deprecated: Use WriteResponse.ProtoReflect.Descriptor instead.
func (*WriteResponse) Descriptor() ([]byte, []int) { func (*WriteResponse) Descriptor() ([]byte, []int) {
return file_pbresource_resource_proto_rawDescGZIP(), []int{12} return file_pbresource_resource_proto_rawDescGZIP(), []int{13}
} }
func (x *WriteResponse) GetResource() *Resource { func (x *WriteResponse) GetResource() *Resource {
@ -1063,7 +1113,7 @@ type WriteStatusRequest struct {
func (x *WriteStatusRequest) Reset() { func (x *WriteStatusRequest) Reset() {
*x = WriteStatusRequest{} *x = WriteStatusRequest{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_pbresource_resource_proto_msgTypes[13] mi := &file_pbresource_resource_proto_msgTypes[14]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1076,7 +1126,7 @@ func (x *WriteStatusRequest) String() string {
func (*WriteStatusRequest) ProtoMessage() {} func (*WriteStatusRequest) ProtoMessage() {}
func (x *WriteStatusRequest) ProtoReflect() protoreflect.Message { func (x *WriteStatusRequest) ProtoReflect() protoreflect.Message {
mi := &file_pbresource_resource_proto_msgTypes[13] mi := &file_pbresource_resource_proto_msgTypes[14]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1089,7 +1139,7 @@ func (x *WriteStatusRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use WriteStatusRequest.ProtoReflect.Descriptor instead. // Deprecated: Use WriteStatusRequest.ProtoReflect.Descriptor instead.
func (*WriteStatusRequest) Descriptor() ([]byte, []int) { func (*WriteStatusRequest) Descriptor() ([]byte, []int) {
return file_pbresource_resource_proto_rawDescGZIP(), []int{13} return file_pbresource_resource_proto_rawDescGZIP(), []int{14}
} }
func (x *WriteStatusRequest) GetId() *ID { func (x *WriteStatusRequest) GetId() *ID {
@ -1133,7 +1183,7 @@ type WriteStatusResponse struct {
func (x *WriteStatusResponse) Reset() { func (x *WriteStatusResponse) Reset() {
*x = WriteStatusResponse{} *x = WriteStatusResponse{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_pbresource_resource_proto_msgTypes[14] mi := &file_pbresource_resource_proto_msgTypes[15]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1146,7 +1196,7 @@ func (x *WriteStatusResponse) String() string {
func (*WriteStatusResponse) ProtoMessage() {} func (*WriteStatusResponse) ProtoMessage() {}
func (x *WriteStatusResponse) ProtoReflect() protoreflect.Message { func (x *WriteStatusResponse) ProtoReflect() protoreflect.Message {
mi := &file_pbresource_resource_proto_msgTypes[14] mi := &file_pbresource_resource_proto_msgTypes[15]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1159,7 +1209,7 @@ func (x *WriteStatusResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use WriteStatusResponse.ProtoReflect.Descriptor instead. // Deprecated: Use WriteStatusResponse.ProtoReflect.Descriptor instead.
func (*WriteStatusResponse) Descriptor() ([]byte, []int) { func (*WriteStatusResponse) Descriptor() ([]byte, []int) {
return file_pbresource_resource_proto_rawDescGZIP(), []int{14} return file_pbresource_resource_proto_rawDescGZIP(), []int{15}
} }
func (x *WriteStatusResponse) GetResource() *Resource { func (x *WriteStatusResponse) GetResource() *Resource {
@ -1186,7 +1236,7 @@ type DeleteRequest struct {
func (x *DeleteRequest) Reset() { func (x *DeleteRequest) Reset() {
*x = DeleteRequest{} *x = DeleteRequest{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_pbresource_resource_proto_msgTypes[15] mi := &file_pbresource_resource_proto_msgTypes[16]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1199,7 +1249,7 @@ func (x *DeleteRequest) String() string {
func (*DeleteRequest) ProtoMessage() {} func (*DeleteRequest) ProtoMessage() {}
func (x *DeleteRequest) ProtoReflect() protoreflect.Message { func (x *DeleteRequest) ProtoReflect() protoreflect.Message {
mi := &file_pbresource_resource_proto_msgTypes[15] mi := &file_pbresource_resource_proto_msgTypes[16]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1212,7 +1262,7 @@ func (x *DeleteRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use DeleteRequest.ProtoReflect.Descriptor instead. // Deprecated: Use DeleteRequest.ProtoReflect.Descriptor instead.
func (*DeleteRequest) Descriptor() ([]byte, []int) { func (*DeleteRequest) Descriptor() ([]byte, []int) {
return file_pbresource_resource_proto_rawDescGZIP(), []int{15} return file_pbresource_resource_proto_rawDescGZIP(), []int{16}
} }
func (x *DeleteRequest) GetId() *ID { func (x *DeleteRequest) GetId() *ID {
@ -1239,7 +1289,7 @@ type DeleteResponse struct {
func (x *DeleteResponse) Reset() { func (x *DeleteResponse) Reset() {
*x = DeleteResponse{} *x = DeleteResponse{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_pbresource_resource_proto_msgTypes[16] mi := &file_pbresource_resource_proto_msgTypes[17]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1252,7 +1302,7 @@ func (x *DeleteResponse) String() string {
func (*DeleteResponse) ProtoMessage() {} func (*DeleteResponse) ProtoMessage() {}
func (x *DeleteResponse) ProtoReflect() protoreflect.Message { func (x *DeleteResponse) ProtoReflect() protoreflect.Message {
mi := &file_pbresource_resource_proto_msgTypes[16] mi := &file_pbresource_resource_proto_msgTypes[17]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1265,7 +1315,7 @@ func (x *DeleteResponse) ProtoReflect() protoreflect.Message {
// Deprecated: Use DeleteResponse.ProtoReflect.Descriptor instead. // Deprecated: Use DeleteResponse.ProtoReflect.Descriptor instead.
func (*DeleteResponse) Descriptor() ([]byte, []int) { func (*DeleteResponse) Descriptor() ([]byte, []int) {
return file_pbresource_resource_proto_rawDescGZIP(), []int{16} return file_pbresource_resource_proto_rawDescGZIP(), []int{17}
} }
// WatchListRequest contains the parameters to the WatchList endpoint. // WatchListRequest contains the parameters to the WatchList endpoint.
@ -1287,7 +1337,7 @@ type WatchListRequest struct {
func (x *WatchListRequest) Reset() { func (x *WatchListRequest) Reset() {
*x = WatchListRequest{} *x = WatchListRequest{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_pbresource_resource_proto_msgTypes[17] mi := &file_pbresource_resource_proto_msgTypes[18]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1300,7 +1350,7 @@ func (x *WatchListRequest) String() string {
func (*WatchListRequest) ProtoMessage() {} func (*WatchListRequest) ProtoMessage() {}
func (x *WatchListRequest) ProtoReflect() protoreflect.Message { func (x *WatchListRequest) ProtoReflect() protoreflect.Message {
mi := &file_pbresource_resource_proto_msgTypes[17] mi := &file_pbresource_resource_proto_msgTypes[18]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1313,7 +1363,7 @@ func (x *WatchListRequest) ProtoReflect() protoreflect.Message {
// Deprecated: Use WatchListRequest.ProtoReflect.Descriptor instead. // Deprecated: Use WatchListRequest.ProtoReflect.Descriptor instead.
func (*WatchListRequest) Descriptor() ([]byte, []int) { func (*WatchListRequest) Descriptor() ([]byte, []int) {
return file_pbresource_resource_proto_rawDescGZIP(), []int{17} return file_pbresource_resource_proto_rawDescGZIP(), []int{18}
} }
func (x *WatchListRequest) GetType() *Type { func (x *WatchListRequest) GetType() *Type {
@ -1352,7 +1402,7 @@ type WatchEvent struct {
func (x *WatchEvent) Reset() { func (x *WatchEvent) Reset() {
*x = WatchEvent{} *x = WatchEvent{}
if protoimpl.UnsafeEnabled { if protoimpl.UnsafeEnabled {
mi := &file_pbresource_resource_proto_msgTypes[18] mi := &file_pbresource_resource_proto_msgTypes[19]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi) ms.StoreMessageInfo(mi)
} }
@ -1365,7 +1415,7 @@ func (x *WatchEvent) String() string {
func (*WatchEvent) ProtoMessage() {} func (*WatchEvent) ProtoMessage() {}
func (x *WatchEvent) ProtoReflect() protoreflect.Message { func (x *WatchEvent) ProtoReflect() protoreflect.Message {
mi := &file_pbresource_resource_proto_msgTypes[18] mi := &file_pbresource_resource_proto_msgTypes[19]
if protoimpl.UnsafeEnabled && x != nil { if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil { if ms.LoadMessageInfo() == nil {
@ -1378,7 +1428,7 @@ func (x *WatchEvent) ProtoReflect() protoreflect.Message {
// Deprecated: Use WatchEvent.ProtoReflect.Descriptor instead. // Deprecated: Use WatchEvent.ProtoReflect.Descriptor instead.
func (*WatchEvent) Descriptor() ([]byte, []int) { func (*WatchEvent) Descriptor() ([]byte, []int) {
return file_pbresource_resource_proto_rawDescGZIP(), []int{18} return file_pbresource_resource_proto_rawDescGZIP(), []int{19}
} }
func (x *WatchEvent) GetOperation() WatchEvent_Operation { func (x *WatchEvent) GetOperation() WatchEvent_Operation {
@ -1496,146 +1546,150 @@ var file_pbresource_resource_proto_rawDesc = []byte{
0x63, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x63, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f,
0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e,
0x22, 0x3c, 0x0a, 0x0b, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x40, 0x0a, 0x09, 0x54, 0x6f, 0x6d, 0x62, 0x73, 0x74, 0x6f, 0x6e, 0x65, 0x12, 0x33, 0x0a,
0x2d, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x68, 0x61, 0x05, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x68,
0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e,
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x49, 0x44, 0x52, 0x02, 0x69, 0x64, 0x22, 0x4f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x49, 0x44, 0x52, 0x05, 0x6f, 0x77, 0x6e,
0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x65, 0x72, 0x22, 0x3c, 0x0a, 0x0b, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x74, 0x12, 0x2d, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e,
0x32, 0x23, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e,
0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73,
0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22,
0xa1, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x33, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e,
0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c,
0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x49, 0x44, 0x52, 0x02, 0x69, 0x64,
0x74, 0x79, 0x70, 0x65, 0x12, 0x3c, 0x0a, 0x07, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x79, 0x18, 0x22, 0x4f, 0x0a, 0x0c, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x12, 0x3f, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01,
0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63,
0x65, 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x79, 0x52, 0x07, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52,
0x63, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x50, 0x72, 0x65, 0x65, 0x22, 0xa1, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x66, 0x69, 0x78, 0x22, 0x51, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x74, 0x12, 0x33, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x1f, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73,
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65,
0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x3c, 0x0a, 0x07, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63,
0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63,
0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x0c, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x72, 0x63, 0x65, 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x79, 0x52, 0x07, 0x74, 0x65, 0x6e,
0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x61, 0x6e, 0x63, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x70, 0x72, 0x65,
0x66, 0x69, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x50,
0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0x51, 0x0a, 0x0c, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69,
0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f,
0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x08, 0x72, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72,
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x50, 0x0a, 0x0d, 0x57, 0x72, 0x69, 0x74, 0x65, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x22, 0x4f, 0x0a, 0x0c, 0x57, 0x72, 0x69, 0x74,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3f, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f,
0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x68, 0x61, 0x73, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x68, 0x61, 0x73,
0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65,
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52,
0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0xaa, 0x01, 0x0a, 0x12, 0x57, 0x72, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x50, 0x0a, 0x0d, 0x57, 0x72, 0x69,
0x69, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x08, 0x72, 0x65,
0x12, 0x2d, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x68, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x68,
0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e,
0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x49, 0x44, 0x52, 0x02, 0x69, 0x64, 0x12, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0xaa, 0x01, 0x0a, 0x12,
0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x57, 0x72, 0x69, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x39, 0x0a, 0x06, 0x73, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d,
0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x68, 0x61, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75,
0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x49, 0x44, 0x52, 0x02, 0x69,
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01,
0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x56, 0x0a, 0x13, 0x57, 0x72, 0x69, 0x74, 0x65, 0x53, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x6b,
0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x39, 0x0a,
0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e,
0x23, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73,
0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f,
0x75, 0x72, 0x63, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x58,
0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x2d, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x68, 0x61,
0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72,
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x49, 0x44, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18,
0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x10, 0x0a, 0x0e, 0x44, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xa6, 0x01, 0x0a, 0x10, 0x57,
0x61, 0x74, 0x63, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x33, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e,
0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c,
0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
0x74, 0x79, 0x70, 0x65, 0x12, 0x3c, 0x0a, 0x07, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x79, 0x18, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x56, 0x0a, 0x13, 0x57, 0x72, 0x69, 0x74,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x3f, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
0x0b, 0x32, 0x23, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f,
0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65,
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
0x22, 0x58, 0x0a, 0x0d, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x2d, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e,
0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c,
0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x49, 0x44, 0x52, 0x02, 0x69, 0x64,
0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x10, 0x0a, 0x0e, 0x44, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xa6, 0x01, 0x0a,
0x10, 0x57, 0x61, 0x74, 0x63, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x33, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1f, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73,
0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x54, 0x79, 0x70, 0x65,
0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x3c, 0x0a, 0x07, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x63,
0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63,
0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75,
0x72, 0x63, 0x65, 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x79, 0x52, 0x07, 0x74, 0x65, 0x6e,
0x61, 0x6e, 0x63, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x70, 0x72, 0x65,
0x66, 0x69, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x50,
0x72, 0x65, 0x66, 0x69, 0x78, 0x22, 0xf0, 0x01, 0x0a, 0x0a, 0x57, 0x61, 0x74, 0x63, 0x68, 0x45,
0x76, 0x65, 0x6e, 0x74, 0x12, 0x4d, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63,
0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75,
0x72, 0x63, 0x65, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x4f,
0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x12, 0x3f, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72,
0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
0x65, 0x2e, 0x54, 0x65, 0x6e, 0x61, 0x6e, 0x63, 0x79, 0x52, 0x07, 0x74, 0x65, 0x6e, 0x61, 0x6e, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f,
0x63, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x5f, 0x70, 0x72, 0x65, 0x66, 0x69, 0x75, 0x72, 0x63, 0x65, 0x22, 0x52, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6e, 0x61, 0x6d, 0x65, 0x50, 0x72, 0x65, 0x6e, 0x12, 0x19, 0x0a, 0x15, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55,
0x66, 0x69, 0x78, 0x22, 0xf0, 0x01, 0x0a, 0x0a, 0x57, 0x61, 0x74, 0x63, 0x68, 0x45, 0x76, 0x65, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10,
0x6e, 0x74, 0x12, 0x4d, 0x0a, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x50, 0x53, 0x45, 0x52, 0x54,
0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f,
0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x02, 0x32, 0x8b, 0x05, 0x0a, 0x0f, 0x52, 0x65, 0x73,
0x65, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x4f, 0x70, 0x65, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x61, 0x0a, 0x04,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x09, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x52, 0x65, 0x61, 0x64, 0x12, 0x26, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70,
0x6e, 0x12, 0x3f, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e,
0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e,
0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
0x63, 0x65, 0x22, 0x52, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12,
0x19, 0x0a, 0x15, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53,
0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x4f, 0x50,
0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x50, 0x53, 0x45, 0x52, 0x54, 0x10, 0x01,
0x12, 0x14, 0x0a, 0x10, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45,
0x4c, 0x45, 0x54, 0x45, 0x10, 0x02, 0x32, 0x8b, 0x05, 0x0a, 0x0f, 0x52, 0x65, 0x73, 0x6f, 0x75,
0x72, 0x63, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x61, 0x0a, 0x04, 0x52, 0x65,
0x61, 0x64, 0x12, 0x26, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63,
0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52,
0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x68, 0x61, 0x73,
0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65,
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x08, 0xe2, 0x86, 0x04, 0x04, 0x08, 0x02, 0x10, 0x0b, 0x12, 0x64, 0x0a,
0x05, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x27, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f,
0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
0x63, 0x65, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x28, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73,
0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x72, 0x69, 0x74,
0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08, 0xe2, 0x86, 0x04, 0x04, 0x08,
0x03, 0x10, 0x0b, 0x12, 0x76, 0x0a, 0x0b, 0x57, 0x72, 0x69, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74,
0x75, 0x73, 0x12, 0x2d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63,
0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57,
0x72, 0x69, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x2e, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f,
0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x72,
0x69, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x08, 0xe2, 0x86, 0x04, 0x04, 0x08, 0x03, 0x10, 0x0b, 0x12, 0x61, 0x0a, 0x04, 0x4c,
0x69, 0x73, 0x74, 0x12, 0x26, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e,
0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e,
0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x68, 0x61,
0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72,
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08, 0xe2, 0x86, 0x04, 0x04, 0x08, 0x02, 0x10, 0x0b, 0x12, 0x67,
0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x28, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69,
0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f,
0x75, 0x72, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63,
0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x44,
0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08, 0xe2,
0x86, 0x04, 0x04, 0x08, 0x03, 0x10, 0x0b, 0x12, 0x6b, 0x0a, 0x09, 0x57, 0x61, 0x74, 0x63, 0x68,
0x4c, 0x69, 0x73, 0x74, 0x12, 0x2b, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70,
0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e, 0x68,
0x74, 0x1a, 0x25, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e,
0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x61, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73,
0x74, 0x63, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x08, 0xe2, 0x86, 0x04, 0x04, 0x08, 0x02, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08, 0xe2, 0x86, 0x04, 0x04, 0x08, 0x02, 0x10, 0x0b, 0x12,
0x10, 0x0b, 0x30, 0x01, 0x42, 0xe9, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x61, 0x73, 0x64, 0x0a, 0x05, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x27, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69,
0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f,
0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x28, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f,
0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x57, 0x72,
0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08, 0xe2, 0x86, 0x04,
0x04, 0x08, 0x03, 0x10, 0x0b, 0x12, 0x76, 0x0a, 0x0b, 0x57, 0x72, 0x69, 0x74, 0x65, 0x53, 0x74,
0x61, 0x74, 0x75, 0x73, 0x12, 0x2d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70,
0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e,
0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e,
0x57, 0x72, 0x69, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x08, 0xe2, 0x86, 0x04, 0x04, 0x08, 0x03, 0x10, 0x0b, 0x12, 0x61, 0x0a,
0x04, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x26, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72,
0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x27, 0x2e,
0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c,
0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x08, 0xe2, 0x86, 0x04, 0x04, 0x08, 0x02, 0x10, 0x0b,
0x12, 0x67, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x28, 0x2e, 0x68, 0x61, 0x73,
0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65,
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x42, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71,
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70,
0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
0x63, 0x2f, 0x70, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0xa2, 0x02, 0x03, 0x48, 0x08, 0xe2, 0x86, 0x04, 0x04, 0x08, 0x03, 0x10, 0x0b, 0x12, 0x6b, 0x0a, 0x09, 0x57, 0x61, 0x74,
0x43, 0x52, 0xaa, 0x02, 0x19, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, 0x63, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x2b, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f,
0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0xca, 0x02, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72,
0x19, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x63, 0x65, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75,
0x6c, 0x5c, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0xe2, 0x02, 0x25, 0x48, 0x61, 0x73, 0x65, 0x73, 0x74, 0x1a, 0x25, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e,
0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e,
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x57, 0x61, 0x74, 0x63, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x08, 0xe2, 0x86, 0x04, 0x04,
0x74, 0x61, 0xea, 0x02, 0x1b, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x08, 0x02, 0x10, 0x0b, 0x30, 0x01, 0x42, 0xe9, 0x01, 0x0a, 0x1d, 0x63, 0x6f, 0x6d, 0x2e, 0x68,
0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x42, 0x0d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75,
0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f,
0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x70, 0x75, 0x62,
0x6c, 0x69, 0x63, 0x2f, 0x70, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0xa2, 0x02,
0x03, 0x48, 0x43, 0x52, 0xaa, 0x02, 0x19, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70,
0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65,
0xca, 0x02, 0x19, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e,
0x73, 0x75, 0x6c, 0x5c, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0xe2, 0x02, 0x25, 0x48,
0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c,
0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61,
0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1b, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70,
0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72,
0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
} }
var ( var (
@ -1651,7 +1705,7 @@ func file_pbresource_resource_proto_rawDescGZIP() []byte {
} }
var file_pbresource_resource_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_pbresource_resource_proto_enumTypes = make([]protoimpl.EnumInfo, 2)
var file_pbresource_resource_proto_msgTypes = make([]protoimpl.MessageInfo, 21) var file_pbresource_resource_proto_msgTypes = make([]protoimpl.MessageInfo, 22)
var file_pbresource_resource_proto_goTypes = []interface{}{ var file_pbresource_resource_proto_goTypes = []interface{}{
(Condition_State)(0), // 0: hashicorp.consul.resource.Condition.State (Condition_State)(0), // 0: hashicorp.consul.resource.Condition.State
(WatchEvent_Operation)(0), // 1: hashicorp.consul.resource.WatchEvent.Operation (WatchEvent_Operation)(0), // 1: hashicorp.consul.resource.WatchEvent.Operation
@ -1662,68 +1716,70 @@ var file_pbresource_resource_proto_goTypes = []interface{}{
(*Status)(nil), // 6: hashicorp.consul.resource.Status (*Status)(nil), // 6: hashicorp.consul.resource.Status
(*Condition)(nil), // 7: hashicorp.consul.resource.Condition (*Condition)(nil), // 7: hashicorp.consul.resource.Condition
(*Reference)(nil), // 8: hashicorp.consul.resource.Reference (*Reference)(nil), // 8: hashicorp.consul.resource.Reference
(*ReadRequest)(nil), // 9: hashicorp.consul.resource.ReadRequest (*Tombstone)(nil), // 9: hashicorp.consul.resource.Tombstone
(*ReadResponse)(nil), // 10: hashicorp.consul.resource.ReadResponse (*ReadRequest)(nil), // 10: hashicorp.consul.resource.ReadRequest
(*ListRequest)(nil), // 11: hashicorp.consul.resource.ListRequest (*ReadResponse)(nil), // 11: hashicorp.consul.resource.ReadResponse
(*ListResponse)(nil), // 12: hashicorp.consul.resource.ListResponse (*ListRequest)(nil), // 12: hashicorp.consul.resource.ListRequest
(*WriteRequest)(nil), // 13: hashicorp.consul.resource.WriteRequest (*ListResponse)(nil), // 13: hashicorp.consul.resource.ListResponse
(*WriteResponse)(nil), // 14: hashicorp.consul.resource.WriteResponse (*WriteRequest)(nil), // 14: hashicorp.consul.resource.WriteRequest
(*WriteStatusRequest)(nil), // 15: hashicorp.consul.resource.WriteStatusRequest (*WriteResponse)(nil), // 15: hashicorp.consul.resource.WriteResponse
(*WriteStatusResponse)(nil), // 16: hashicorp.consul.resource.WriteStatusResponse (*WriteStatusRequest)(nil), // 16: hashicorp.consul.resource.WriteStatusRequest
(*DeleteRequest)(nil), // 17: hashicorp.consul.resource.DeleteRequest (*WriteStatusResponse)(nil), // 17: hashicorp.consul.resource.WriteStatusResponse
(*DeleteResponse)(nil), // 18: hashicorp.consul.resource.DeleteResponse (*DeleteRequest)(nil), // 18: hashicorp.consul.resource.DeleteRequest
(*WatchListRequest)(nil), // 19: hashicorp.consul.resource.WatchListRequest (*DeleteResponse)(nil), // 19: hashicorp.consul.resource.DeleteResponse
(*WatchEvent)(nil), // 20: hashicorp.consul.resource.WatchEvent (*WatchListRequest)(nil), // 20: hashicorp.consul.resource.WatchListRequest
nil, // 21: hashicorp.consul.resource.Resource.MetadataEntry (*WatchEvent)(nil), // 21: hashicorp.consul.resource.WatchEvent
nil, // 22: hashicorp.consul.resource.Resource.StatusEntry nil, // 22: hashicorp.consul.resource.Resource.MetadataEntry
(*anypb.Any)(nil), // 23: google.protobuf.Any nil, // 23: hashicorp.consul.resource.Resource.StatusEntry
(*anypb.Any)(nil), // 24: google.protobuf.Any
} }
var file_pbresource_resource_proto_depIdxs = []int32{ var file_pbresource_resource_proto_depIdxs = []int32{
2, // 0: hashicorp.consul.resource.ID.type:type_name -> hashicorp.consul.resource.Type 2, // 0: hashicorp.consul.resource.ID.type:type_name -> hashicorp.consul.resource.Type
3, // 1: hashicorp.consul.resource.ID.tenancy:type_name -> hashicorp.consul.resource.Tenancy 3, // 1: hashicorp.consul.resource.ID.tenancy:type_name -> hashicorp.consul.resource.Tenancy
4, // 2: hashicorp.consul.resource.Resource.id:type_name -> hashicorp.consul.resource.ID 4, // 2: hashicorp.consul.resource.Resource.id:type_name -> hashicorp.consul.resource.ID
4, // 3: hashicorp.consul.resource.Resource.owner:type_name -> hashicorp.consul.resource.ID 4, // 3: hashicorp.consul.resource.Resource.owner:type_name -> hashicorp.consul.resource.ID
21, // 4: hashicorp.consul.resource.Resource.metadata:type_name -> hashicorp.consul.resource.Resource.MetadataEntry 22, // 4: hashicorp.consul.resource.Resource.metadata:type_name -> hashicorp.consul.resource.Resource.MetadataEntry
22, // 5: hashicorp.consul.resource.Resource.status:type_name -> hashicorp.consul.resource.Resource.StatusEntry 23, // 5: hashicorp.consul.resource.Resource.status:type_name -> hashicorp.consul.resource.Resource.StatusEntry
23, // 6: hashicorp.consul.resource.Resource.data:type_name -> google.protobuf.Any 24, // 6: hashicorp.consul.resource.Resource.data:type_name -> google.protobuf.Any
7, // 7: hashicorp.consul.resource.Status.conditions:type_name -> hashicorp.consul.resource.Condition 7, // 7: hashicorp.consul.resource.Status.conditions:type_name -> hashicorp.consul.resource.Condition
0, // 8: hashicorp.consul.resource.Condition.state:type_name -> hashicorp.consul.resource.Condition.State 0, // 8: hashicorp.consul.resource.Condition.state:type_name -> hashicorp.consul.resource.Condition.State
8, // 9: hashicorp.consul.resource.Condition.resource:type_name -> hashicorp.consul.resource.Reference 8, // 9: hashicorp.consul.resource.Condition.resource:type_name -> hashicorp.consul.resource.Reference
2, // 10: hashicorp.consul.resource.Reference.type:type_name -> hashicorp.consul.resource.Type 2, // 10: hashicorp.consul.resource.Reference.type:type_name -> hashicorp.consul.resource.Type
3, // 11: hashicorp.consul.resource.Reference.tenancy:type_name -> hashicorp.consul.resource.Tenancy 3, // 11: hashicorp.consul.resource.Reference.tenancy:type_name -> hashicorp.consul.resource.Tenancy
4, // 12: hashicorp.consul.resource.ReadRequest.id:type_name -> hashicorp.consul.resource.ID 4, // 12: hashicorp.consul.resource.Tombstone.owner:type_name -> hashicorp.consul.resource.ID
5, // 13: hashicorp.consul.resource.ReadResponse.resource:type_name -> hashicorp.consul.resource.Resource 4, // 13: hashicorp.consul.resource.ReadRequest.id:type_name -> hashicorp.consul.resource.ID
2, // 14: hashicorp.consul.resource.ListRequest.type:type_name -> hashicorp.consul.resource.Type 5, // 14: hashicorp.consul.resource.ReadResponse.resource:type_name -> hashicorp.consul.resource.Resource
3, // 15: hashicorp.consul.resource.ListRequest.tenancy:type_name -> hashicorp.consul.resource.Tenancy 2, // 15: hashicorp.consul.resource.ListRequest.type:type_name -> hashicorp.consul.resource.Type
5, // 16: hashicorp.consul.resource.ListResponse.resources:type_name -> hashicorp.consul.resource.Resource 3, // 16: hashicorp.consul.resource.ListRequest.tenancy:type_name -> hashicorp.consul.resource.Tenancy
5, // 17: hashicorp.consul.resource.WriteRequest.resource:type_name -> hashicorp.consul.resource.Resource 5, // 17: hashicorp.consul.resource.ListResponse.resources:type_name -> hashicorp.consul.resource.Resource
5, // 18: hashicorp.consul.resource.WriteResponse.resource:type_name -> hashicorp.consul.resource.Resource 5, // 18: hashicorp.consul.resource.WriteRequest.resource:type_name -> hashicorp.consul.resource.Resource
4, // 19: hashicorp.consul.resource.WriteStatusRequest.id:type_name -> hashicorp.consul.resource.ID 5, // 19: hashicorp.consul.resource.WriteResponse.resource:type_name -> hashicorp.consul.resource.Resource
6, // 20: hashicorp.consul.resource.WriteStatusRequest.status:type_name -> hashicorp.consul.resource.Status 4, // 20: hashicorp.consul.resource.WriteStatusRequest.id:type_name -> hashicorp.consul.resource.ID
5, // 21: hashicorp.consul.resource.WriteStatusResponse.resource:type_name -> hashicorp.consul.resource.Resource 6, // 21: hashicorp.consul.resource.WriteStatusRequest.status:type_name -> hashicorp.consul.resource.Status
4, // 22: hashicorp.consul.resource.DeleteRequest.id:type_name -> hashicorp.consul.resource.ID 5, // 22: hashicorp.consul.resource.WriteStatusResponse.resource:type_name -> hashicorp.consul.resource.Resource
2, // 23: hashicorp.consul.resource.WatchListRequest.type:type_name -> hashicorp.consul.resource.Type 4, // 23: hashicorp.consul.resource.DeleteRequest.id:type_name -> hashicorp.consul.resource.ID
3, // 24: hashicorp.consul.resource.WatchListRequest.tenancy:type_name -> hashicorp.consul.resource.Tenancy 2, // 24: hashicorp.consul.resource.WatchListRequest.type:type_name -> hashicorp.consul.resource.Type
1, // 25: hashicorp.consul.resource.WatchEvent.operation:type_name -> hashicorp.consul.resource.WatchEvent.Operation 3, // 25: hashicorp.consul.resource.WatchListRequest.tenancy:type_name -> hashicorp.consul.resource.Tenancy
5, // 26: hashicorp.consul.resource.WatchEvent.resource:type_name -> hashicorp.consul.resource.Resource 1, // 26: hashicorp.consul.resource.WatchEvent.operation:type_name -> hashicorp.consul.resource.WatchEvent.Operation
6, // 27: hashicorp.consul.resource.Resource.StatusEntry.value:type_name -> hashicorp.consul.resource.Status 5, // 27: hashicorp.consul.resource.WatchEvent.resource:type_name -> hashicorp.consul.resource.Resource
9, // 28: hashicorp.consul.resource.ResourceService.Read:input_type -> hashicorp.consul.resource.ReadRequest 6, // 28: hashicorp.consul.resource.Resource.StatusEntry.value:type_name -> hashicorp.consul.resource.Status
13, // 29: hashicorp.consul.resource.ResourceService.Write:input_type -> hashicorp.consul.resource.WriteRequest 10, // 29: hashicorp.consul.resource.ResourceService.Read:input_type -> hashicorp.consul.resource.ReadRequest
15, // 30: hashicorp.consul.resource.ResourceService.WriteStatus:input_type -> hashicorp.consul.resource.WriteStatusRequest 14, // 30: hashicorp.consul.resource.ResourceService.Write:input_type -> hashicorp.consul.resource.WriteRequest
11, // 31: hashicorp.consul.resource.ResourceService.List:input_type -> hashicorp.consul.resource.ListRequest 16, // 31: hashicorp.consul.resource.ResourceService.WriteStatus:input_type -> hashicorp.consul.resource.WriteStatusRequest
17, // 32: hashicorp.consul.resource.ResourceService.Delete:input_type -> hashicorp.consul.resource.DeleteRequest 12, // 32: hashicorp.consul.resource.ResourceService.List:input_type -> hashicorp.consul.resource.ListRequest
19, // 33: hashicorp.consul.resource.ResourceService.WatchList:input_type -> hashicorp.consul.resource.WatchListRequest 18, // 33: hashicorp.consul.resource.ResourceService.Delete:input_type -> hashicorp.consul.resource.DeleteRequest
10, // 34: hashicorp.consul.resource.ResourceService.Read:output_type -> hashicorp.consul.resource.ReadResponse 20, // 34: hashicorp.consul.resource.ResourceService.WatchList:input_type -> hashicorp.consul.resource.WatchListRequest
14, // 35: hashicorp.consul.resource.ResourceService.Write:output_type -> hashicorp.consul.resource.WriteResponse 11, // 35: hashicorp.consul.resource.ResourceService.Read:output_type -> hashicorp.consul.resource.ReadResponse
16, // 36: hashicorp.consul.resource.ResourceService.WriteStatus:output_type -> hashicorp.consul.resource.WriteStatusResponse 15, // 36: hashicorp.consul.resource.ResourceService.Write:output_type -> hashicorp.consul.resource.WriteResponse
12, // 37: hashicorp.consul.resource.ResourceService.List:output_type -> hashicorp.consul.resource.ListResponse 17, // 37: hashicorp.consul.resource.ResourceService.WriteStatus:output_type -> hashicorp.consul.resource.WriteStatusResponse
18, // 38: hashicorp.consul.resource.ResourceService.Delete:output_type -> hashicorp.consul.resource.DeleteResponse 13, // 38: hashicorp.consul.resource.ResourceService.List:output_type -> hashicorp.consul.resource.ListResponse
20, // 39: hashicorp.consul.resource.ResourceService.WatchList:output_type -> hashicorp.consul.resource.WatchEvent 19, // 39: hashicorp.consul.resource.ResourceService.Delete:output_type -> hashicorp.consul.resource.DeleteResponse
34, // [34:40] is the sub-list for method output_type 21, // 40: hashicorp.consul.resource.ResourceService.WatchList:output_type -> hashicorp.consul.resource.WatchEvent
28, // [28:34] is the sub-list for method input_type 35, // [35:41] is the sub-list for method output_type
28, // [28:28] is the sub-list for extension type_name 29, // [29:35] is the sub-list for method input_type
28, // [28:28] is the sub-list for extension extendee 29, // [29:29] is the sub-list for extension type_name
0, // [0:28] is the sub-list for field type_name 29, // [29:29] is the sub-list for extension extendee
0, // [0:29] is the sub-list for field type_name
} }
func init() { file_pbresource_resource_proto_init() } func init() { file_pbresource_resource_proto_init() }
@ -1817,7 +1873,7 @@ func file_pbresource_resource_proto_init() {
} }
} }
file_pbresource_resource_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { file_pbresource_resource_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ReadRequest); i { switch v := v.(*Tombstone); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1829,7 +1885,7 @@ func file_pbresource_resource_proto_init() {
} }
} }
file_pbresource_resource_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { file_pbresource_resource_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ReadResponse); i { switch v := v.(*ReadRequest); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1841,7 +1897,7 @@ func file_pbresource_resource_proto_init() {
} }
} }
file_pbresource_resource_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { file_pbresource_resource_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ListRequest); i { switch v := v.(*ReadResponse); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1853,7 +1909,7 @@ func file_pbresource_resource_proto_init() {
} }
} }
file_pbresource_resource_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { file_pbresource_resource_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ListResponse); i { switch v := v.(*ListRequest); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1865,7 +1921,7 @@ func file_pbresource_resource_proto_init() {
} }
} }
file_pbresource_resource_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { file_pbresource_resource_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*WriteRequest); i { switch v := v.(*ListResponse); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1877,7 +1933,7 @@ func file_pbresource_resource_proto_init() {
} }
} }
file_pbresource_resource_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { file_pbresource_resource_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*WriteResponse); i { switch v := v.(*WriteRequest); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1889,7 +1945,7 @@ func file_pbresource_resource_proto_init() {
} }
} }
file_pbresource_resource_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { file_pbresource_resource_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*WriteStatusRequest); i { switch v := v.(*WriteResponse); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1901,7 +1957,7 @@ func file_pbresource_resource_proto_init() {
} }
} }
file_pbresource_resource_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { file_pbresource_resource_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*WriteStatusResponse); i { switch v := v.(*WriteStatusRequest); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1913,7 +1969,7 @@ func file_pbresource_resource_proto_init() {
} }
} }
file_pbresource_resource_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { file_pbresource_resource_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DeleteRequest); i { switch v := v.(*WriteStatusResponse); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1925,7 +1981,7 @@ func file_pbresource_resource_proto_init() {
} }
} }
file_pbresource_resource_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { file_pbresource_resource_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*DeleteResponse); i { switch v := v.(*DeleteRequest); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1937,7 +1993,7 @@ func file_pbresource_resource_proto_init() {
} }
} }
file_pbresource_resource_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { file_pbresource_resource_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*WatchListRequest); i { switch v := v.(*DeleteResponse); i {
case 0: case 0:
return &v.state return &v.state
case 1: case 1:
@ -1949,6 +2005,18 @@ func file_pbresource_resource_proto_init() {
} }
} }
file_pbresource_resource_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { file_pbresource_resource_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*WatchListRequest); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_pbresource_resource_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*WatchEvent); i { switch v := v.(*WatchEvent); i {
case 0: case 0:
return &v.state return &v.state
@ -1967,7 +2035,7 @@ func file_pbresource_resource_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(), GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_pbresource_resource_proto_rawDesc, RawDescriptor: file_pbresource_resource_proto_rawDesc,
NumEnums: 2, NumEnums: 2,
NumMessages: 21, NumMessages: 22,
NumExtensions: 0, NumExtensions: 0,
NumServices: 1, NumServices: 1,
}, },

View File

@ -181,6 +181,13 @@ message Reference {
string section = 4; string section = 4;
} }
// Tombstone represents a promise to delete all of a resource's immediately
// owned (child) resources, if any.
message Tombstone {
// Owner resource identifier.
ID owner = 1;
}
// ResourceService provides the shared primitives for storing, querying, and // ResourceService provides the shared primitives for storing, querying, and
// watching resources of different types. // watching resources of different types.
// //
@ -230,6 +237,11 @@ service ResourceService {
// version in the Resource.Version field. If the given version doesn't match // version in the Resource.Version field. If the given version doesn't match
// what is currently stored, an Aborted error code will be returned. // what is currently stored, an Aborted error code will be returned.
// //
// To perform a blanket write (update regardless of the stored version),
// provide an empty Version in the Resource.Version field. Note that the
// write may still fail due to not being able to internally do a CAS write
// and return an Aborted error code.
//
// Resource.Id.Uid can (and by controllers, should) be provided to avoid // Resource.Id.Uid can (and by controllers, should) be provided to avoid
// accidentally modifying a resource if it has been deleted and recreated. // accidentally modifying a resource if it has been deleted and recreated.
// If the given Uid doesn't match what is stored, a FailedPrecondition error // If the given Uid doesn't match what is stored, a FailedPrecondition error

View File

@ -34,6 +34,11 @@ type ResourceServiceClient interface {
// version in the Resource.Version field. If the given version doesn't match // version in the Resource.Version field. If the given version doesn't match
// what is currently stored, an Aborted error code will be returned. // what is currently stored, an Aborted error code will be returned.
// //
// To perform a blanket write (update regardless of the stored version),
// provide an empty Version in the Resource.Version field. Note that the
// write may still fail due to not being able to internally do a CAS write
// and return an Aborted error code.
//
// Resource.Id.Uid can (and by controllers, should) be provided to avoid // Resource.Id.Uid can (and by controllers, should) be provided to avoid
// accidentally modifying a resource if it has been deleted and recreated. // accidentally modifying a resource if it has been deleted and recreated.
// If the given Uid doesn't match what is stored, a FailedPrecondition error // If the given Uid doesn't match what is stored, a FailedPrecondition error
@ -193,6 +198,11 @@ type ResourceServiceServer interface {
// version in the Resource.Version field. If the given version doesn't match // version in the Resource.Version field. If the given version doesn't match
// what is currently stored, an Aborted error code will be returned. // what is currently stored, an Aborted error code will be returned.
// //
// To perform a blanket write (update regardless of the stored version),
// provide an empty Version in the Resource.Version field. Note that the
// write may still fail due to not being able to internally do a CAS write
// and return an Aborted error code.
//
// Resource.Id.Uid can (and by controllers, should) be provided to avoid // Resource.Id.Uid can (and by controllers, should) be provided to avoid
// accidentally modifying a resource if it has been deleted and recreated. // accidentally modifying a resource if it has been deleted and recreated.
// If the given Uid doesn't match what is stored, a FailedPrecondition error // If the given Uid doesn't match what is stored, a FailedPrecondition error