Local aliases OSS patch (#12848)

* Local aliases OSS patch

* build fix
This commit is contained in:
Vishal Nayak 2021-10-15 15:20:00 -04:00 committed by GitHub
parent 70a9636575
commit 476fb08e0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1144 additions and 403 deletions

View File

@ -45,6 +45,16 @@ func (e *Entity) Clone() (*Entity, error) {
return &clonedEntity, nil
}
func (e *Entity) UpsertAlias(alias *Alias) {
for i, item := range e.Aliases {
if item.ID == alias.ID {
e.Aliases[i] = alias
return
}
}
e.Aliases = append(e.Aliases, alias)
}
func (p *Alias) Clone() (*Alias, error) {
if p == nil {
return nil, fmt.Errorf("nil alias")

View File

@ -204,6 +204,55 @@ func (x *Group) GetNamespaceID() string {
return ""
}
// LocalAliases holds the aliases belonging to an entity that are local to the
// cluster.
type LocalAliases struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Aliases []*Alias `protobuf:"bytes,1,rep,name=aliases,proto3" json:"aliases,omitempty"`
}
func (x *LocalAliases) Reset() {
*x = LocalAliases{}
if protoimpl.UnsafeEnabled {
mi := &file_helper_identity_types_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *LocalAliases) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*LocalAliases) ProtoMessage() {}
func (x *LocalAliases) ProtoReflect() protoreflect.Message {
mi := &file_helper_identity_types_proto_msgTypes[1]
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 LocalAliases.ProtoReflect.Descriptor instead.
func (*LocalAliases) Descriptor() ([]byte, []int) {
return file_helper_identity_types_proto_rawDescGZIP(), []int{1}
}
func (x *LocalAliases) GetAliases() []*Alias {
if x != nil {
return x.Aliases
}
return nil
}
// Entity represents an entity that gets persisted and indexed.
// Entity is fundamentally composed of zero or many aliases.
type Entity struct {
@ -274,7 +323,7 @@ type Entity struct {
func (x *Entity) Reset() {
*x = Entity{}
if protoimpl.UnsafeEnabled {
mi := &file_helper_identity_types_proto_msgTypes[1]
mi := &file_helper_identity_types_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -287,7 +336,7 @@ func (x *Entity) String() string {
func (*Entity) ProtoMessage() {}
func (x *Entity) ProtoReflect() protoreflect.Message {
mi := &file_helper_identity_types_proto_msgTypes[1]
mi := &file_helper_identity_types_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -300,7 +349,7 @@ func (x *Entity) ProtoReflect() protoreflect.Message {
// Deprecated: Use Entity.ProtoReflect.Descriptor instead.
func (*Entity) Descriptor() ([]byte, []int) {
return file_helper_identity_types_proto_rawDescGZIP(), []int{1}
return file_helper_identity_types_proto_rawDescGZIP(), []int{2}
}
func (x *Entity) GetAliases() []*Alias {
@ -444,12 +493,22 @@ type Alias struct {
// Custom Metadata represents the custom data tied to this alias
// @inject_tag: sentinel:"-"
CustomMetadata map[string]string `protobuf:"bytes,12,rep,name=custom_metadata,json=customMetadata,proto3" json:"custom_metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3" sentinel:"-"`
// Local indicates if the alias only belongs to the cluster where it was
// created. If true, the alias will be stored in a location that is ignored by
// the performance replication subsystem.
// @inject_tag: sentinel:"-"
Local bool `protobuf:"varint,13,opt,name=local,proto3" json:"local,omitempty" sentinel:"-"`
// LocalBucketKey is the identifying element of the location where this alias
// is stored in the storage packer. This helps in querying local aliases
// during invalidation of local aliases in performance standbys.
// @inject_tag: sentinel:"-"
LocalBucketKey string `protobuf:"bytes,14,opt,name=local_bucket_key,json=localBucketKey,proto3" json:"local_bucket_key,omitempty" sentinel:"-"`
}
func (x *Alias) Reset() {
*x = Alias{}
if protoimpl.UnsafeEnabled {
mi := &file_helper_identity_types_proto_msgTypes[2]
mi := &file_helper_identity_types_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -462,7 +521,7 @@ func (x *Alias) String() string {
func (*Alias) ProtoMessage() {}
func (x *Alias) ProtoReflect() protoreflect.Message {
mi := &file_helper_identity_types_proto_msgTypes[2]
mi := &file_helper_identity_types_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -475,7 +534,7 @@ func (x *Alias) ProtoReflect() protoreflect.Message {
// Deprecated: Use Alias.ProtoReflect.Descriptor instead.
func (*Alias) Descriptor() ([]byte, []int) {
return file_helper_identity_types_proto_rawDescGZIP(), []int{2}
return file_helper_identity_types_proto_rawDescGZIP(), []int{3}
}
func (x *Alias) GetID() string {
@ -562,6 +621,20 @@ func (x *Alias) GetCustomMetadata() map[string]string {
return nil
}
func (x *Alias) GetLocal() bool {
if x != nil {
return x.Local
}
return false
}
func (x *Alias) GetLocalBucketKey() string {
if x != nil {
return x.LocalBucketKey
}
return ""
}
// Deprecated. Retained for backwards compatibility.
type EntityStorageEntry struct {
state protoimpl.MessageState
@ -583,7 +656,7 @@ type EntityStorageEntry struct {
func (x *EntityStorageEntry) Reset() {
*x = EntityStorageEntry{}
if protoimpl.UnsafeEnabled {
mi := &file_helper_identity_types_proto_msgTypes[3]
mi := &file_helper_identity_types_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -596,7 +669,7 @@ func (x *EntityStorageEntry) String() string {
func (*EntityStorageEntry) ProtoMessage() {}
func (x *EntityStorageEntry) ProtoReflect() protoreflect.Message {
mi := &file_helper_identity_types_proto_msgTypes[3]
mi := &file_helper_identity_types_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -609,7 +682,7 @@ func (x *EntityStorageEntry) ProtoReflect() protoreflect.Message {
// Deprecated: Use EntityStorageEntry.ProtoReflect.Descriptor instead.
func (*EntityStorageEntry) Descriptor() ([]byte, []int) {
return file_helper_identity_types_proto_rawDescGZIP(), []int{3}
return file_helper_identity_types_proto_rawDescGZIP(), []int{4}
}
func (x *EntityStorageEntry) GetPersonas() []*PersonaIndexEntry {
@ -703,7 +776,7 @@ type PersonaIndexEntry struct {
func (x *PersonaIndexEntry) Reset() {
*x = PersonaIndexEntry{}
if protoimpl.UnsafeEnabled {
mi := &file_helper_identity_types_proto_msgTypes[4]
mi := &file_helper_identity_types_proto_msgTypes[5]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@ -716,7 +789,7 @@ func (x *PersonaIndexEntry) String() string {
func (*PersonaIndexEntry) ProtoMessage() {}
func (x *PersonaIndexEntry) ProtoReflect() protoreflect.Message {
mi := &file_helper_identity_types_proto_msgTypes[4]
mi := &file_helper_identity_types_proto_msgTypes[5]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@ -729,7 +802,7 @@ func (x *PersonaIndexEntry) ProtoReflect() protoreflect.Message {
// Deprecated: Use PersonaIndexEntry.ProtoReflect.Descriptor instead.
func (*PersonaIndexEntry) Descriptor() ([]byte, []int) {
return file_helper_identity_types_proto_rawDescGZIP(), []int{4}
return file_helper_identity_types_proto_rawDescGZIP(), []int{5}
}
func (x *PersonaIndexEntry) GetID() string {
@ -847,166 +920,174 @@ var file_helper_identity_types_proto_rawDesc = []byte{
0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14,
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x8c, 0x05, 0x0a, 0x06, 0x45, 0x6e, 0x74,
0x69, 0x74, 0x79, 0x12, 0x29, 0x0a, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e,
0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, 0x0e,
0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12,
0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61,
0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e,
0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x3f,
0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18,
0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d,
0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12,
0x44, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74,
0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x39, 0x0a, 0x0c, 0x4c, 0x6f, 0x63, 0x61,
0x6c, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, 0x29, 0x0a, 0x07, 0x61, 0x6c, 0x69, 0x61,
0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x69, 0x64, 0x65, 0x6e,
0x74, 0x69, 0x74, 0x79, 0x2e, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x07, 0x61, 0x6c, 0x69, 0x61,
0x73, 0x65, 0x73, 0x22, 0x8c, 0x05, 0x0a, 0x06, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x29,
0x0a, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x0f, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x41, 0x6c, 0x69, 0x61, 0x73,
0x52, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d,
0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a,
0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x1e, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74,
0x79, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52,
0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x3f, 0x0a, 0x0d, 0x63, 0x72, 0x65,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72,
0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x44, 0x0a, 0x10, 0x6c, 0x61,
0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
0x52, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65,
0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x64, 0x5f, 0x65, 0x6e, 0x74, 0x69, 0x74,
0x79, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x6d, 0x65, 0x72,
0x67, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x73, 0x12, 0x1a, 0x0a, 0x08,
0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08,
0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x75, 0x63, 0x6b,
0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x62, 0x75,
0x63, 0x6b, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x41, 0x0a, 0x0b, 0x6d, 0x66, 0x61, 0x5f, 0x73,
0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x69,
0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x4d,
0x66, 0x61, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a,
0x6d, 0x66, 0x61, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x69,
0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x64, 0x69,
0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70,
0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x61,
0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74,
0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4a, 0x0a, 0x0f, 0x4d, 0x66, 0x61, 0x53, 0x65, 0x63,
0x72, 0x65, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x21, 0x0a, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x6d, 0x66, 0x61,
0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
0x38, 0x01, 0x22, 0xe1, 0x05, 0x0a, 0x05, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x0e, 0x0a, 0x02,
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c,
0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x0b, 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x12,
0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20,
0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x25,
0x0a, 0x0e, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72,
0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x63, 0x63,
0x65, 0x73, 0x73, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70,
0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x75, 0x6e, 0x74,
0x50, 0x61, 0x74, 0x68, 0x12, 0x39, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74,
0x79, 0x2e, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12,
0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e,
0x61, 0x6d, 0x65, 0x12, 0x3f, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f,
0x74, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d,
0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x54, 0x69, 0x6d, 0x65, 0x12, 0x44, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64,
0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x6c, 0x61, 0x73, 0x74,
0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x19, 0x6d, 0x65,
0x72, 0x67, 0x65, 0x64, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69,
0x63, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x16, 0x6d,
0x65, 0x72, 0x67, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x43, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63,
0x61, 0x6c, 0x49, 0x64, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61,
0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x61, 0x6d,
0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x4c, 0x0a, 0x0f, 0x63, 0x75, 0x73, 0x74,
0x6f, 0x6d, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0c, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x23, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x41, 0x6c, 0x69,
0x61, 0x73, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65,
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x18,
0x0d, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x12, 0x28, 0x0a, 0x10,
0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x5f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79,
0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x42, 0x75, 0x63,
0x6b, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
0x02, 0x38, 0x01, 0x1a, 0x41, 0x0a, 0x13, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x74,
0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x88, 0x05, 0x0a, 0x12, 0x45, 0x6e, 0x74, 0x69, 0x74,
0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x37, 0x0a,
0x08, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32,
0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x50, 0x65, 0x72, 0x73, 0x6f,
0x6e, 0x61, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x70, 0x65,
0x72, 0x73, 0x6f, 0x6e, 0x61, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x46, 0x0a, 0x08, 0x6d, 0x65,
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x69,
0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x74,
0x6f, 0x72, 0x61, 0x67, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61,
0x74, 0x61, 0x12, 0x3f, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74,
0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74,
0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x64, 0x5f,
0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09,
0x52, 0x0f, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64,
0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x08, 0x20,
0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x1d, 0x0a,
0x0a, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28,
0x09, 0x52, 0x09, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x12, 0x41, 0x0a, 0x0b,
0x6d, 0x66, 0x61, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x20, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x45, 0x6e, 0x74,
0x69, 0x74, 0x79, 0x2e, 0x4d, 0x66, 0x61, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x66, 0x61, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x12,
0x1a, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28,
0x08, 0x52, 0x08, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x6e,
0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x1a, 0x3b,
0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4a, 0x0a, 0x0f, 0x4d,
0x66, 0x61, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
0x12, 0x21, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x0b, 0x2e, 0x6d, 0x66, 0x61, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xa1, 0x05, 0x0a, 0x05, 0x41, 0x6c, 0x69, 0x61,
0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69,
0x64, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x69,
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63,
0x61, 0x6c, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x74, 0x79,
0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54,
0x69, 0x6d, 0x65, 0x12, 0x44, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61,
0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x55,
0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x65, 0x72,
0x67, 0x65, 0x64, 0x5f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x07,
0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x69,
0x74, 0x79, 0x49, 0x64, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65,
0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x69, 0x65,
0x73, 0x12, 0x26, 0x0a, 0x0f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x5f,
0x68, 0x61, 0x73, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x62, 0x75, 0x63, 0x6b,
0x65, 0x74, 0x4b, 0x65, 0x79, 0x48, 0x61, 0x73, 0x68, 0x12, 0x4d, 0x0a, 0x0b, 0x6d, 0x66, 0x61,
0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c,
0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79,
0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x66, 0x61,
0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0a, 0x6d, 0x66,
0x61, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61,
0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4a, 0x0a, 0x0f, 0x4d, 0x66, 0x61, 0x53, 0x65, 0x63, 0x72,
0x65, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x21, 0x0a, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x6d, 0x66, 0x61, 0x2e,
0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
0x01, 0x22, 0xf9, 0x03, 0x0a, 0x11, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x49, 0x6e, 0x64,
0x65, 0x78, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74,
0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69,
0x74, 0x79, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x74, 0x79,
0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x54,
0x79, 0x70, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x63, 0x63,
0x65, 0x73, 0x73, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6d, 0x6f, 0x75,
0x6e, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f,
0x75, 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09,
0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x39, 0x0a, 0x08, 0x6d, 0x65, 0x74,
0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x69, 0x64,
0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x2e, 0x4d, 0x65, 0x74,
0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61,
0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3f, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x45, 0x0a, 0x08, 0x6d, 0x65, 0x74,
0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x69, 0x64,
0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x49, 0x6e,
0x64, 0x65, 0x78, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3f, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69,
0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x44, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x75, 0x70,
0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x44, 0x0a, 0x10, 0x6c, 0x61, 0x73,
0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20,
0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52,
0x0e, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12,
0x39, 0x0a, 0x19, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x64, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x63,
0x61, 0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0a, 0x20, 0x03,
0x28, 0x09, 0x52, 0x16, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x43, 0x61,
0x6e, 0x6f, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x49, 0x64, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x61,
0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x4c, 0x0a,
0x0f, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74,
0x79, 0x2e, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x2e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65,
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x63, 0x75, 0x73,
0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d,
0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03,
0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14,
0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x41, 0x0a, 0x13, 0x43, 0x75, 0x73, 0x74,
0x6f, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x88, 0x05, 0x0a, 0x12,
0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x45, 0x6e, 0x74,
0x72, 0x79, 0x12, 0x37, 0x0a, 0x08, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x73, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e,
0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x52, 0x08, 0x70, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x73, 0x12, 0x0e, 0x0a, 0x02, 0x69,
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e,
0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12,
0x46, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x2a, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x45, 0x6e, 0x74,
0x69, 0x74, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x2e,
0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d,
0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x3f, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a,
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x44, 0x0a, 0x10, 0x6c, 0x61, 0x73, 0x74,
0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e,
0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x2a,
0x0a, 0x11, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x64, 0x5f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f,
0x69, 0x64, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x6d, 0x65, 0x72, 0x67, 0x65,
0x64, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x6f,
0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x70, 0x6f,
0x6c, 0x69, 0x63, 0x69, 0x65, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74,
0x5f, 0x6b, 0x65, 0x79, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0d, 0x62, 0x75, 0x63, 0x6b, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x48, 0x61, 0x73, 0x68, 0x12, 0x4d,
0x0a, 0x0b, 0x6d, 0x66, 0x61, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x18, 0x0a, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x45,
0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x2e, 0x4d, 0x66, 0x61, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x52, 0x0a, 0x6d, 0x66, 0x61, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x1a, 0x3b, 0x0a,
0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x4a, 0x0a, 0x0f, 0x4d, 0x66,
0x61, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
0x21, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0b,
0x2e, 0x6d, 0x66, 0x61, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x52, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xf9, 0x03, 0x0a, 0x11, 0x50, 0x65, 0x72, 0x73, 0x6f,
0x6e, 0x61, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x0e, 0x0a, 0x02,
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09,
0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x75,
0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d,
0x6f, 0x75, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x6f, 0x75, 0x6e,
0x74, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0d, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72, 0x12,
0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x05, 0x20,
0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x45,
0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b,
0x32, 0x29, 0x2e, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x50, 0x65, 0x72, 0x73,
0x6f, 0x6e, 0x61, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x4d, 0x65,
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74,
0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x07, 0x20,
0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3f, 0x0a, 0x0d, 0x63, 0x72, 0x65,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72,
0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x44, 0x0a, 0x10, 0x6c, 0x61,
0x73, 0x74, 0x5f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70,
0x52, 0x0e, 0x6c, 0x61, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65,
0x12, 0x33, 0x0a, 0x16, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x64, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f,
0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09,
0x52, 0x13, 0x6d, 0x65, 0x72, 0x67, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x45, 0x6e, 0x74, 0x69,
0x74, 0x79, 0x49, 0x64, 0x73, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02,
0x38, 0x01, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x76, 0x61, 0x75, 0x6c, 0x74,
0x2f, 0x68, 0x65, 0x6c, 0x70, 0x65, 0x72, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79,
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x6c, 0x61, 0x73,
0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x33, 0x0a, 0x16, 0x6d,
0x65, 0x72, 0x67, 0x65, 0x64, 0x5f, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x65, 0x6e, 0x74, 0x69, 0x74,
0x79, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x6d, 0x65, 0x72,
0x67, 0x65, 0x64, 0x46, 0x72, 0x6f, 0x6d, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x73,
0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x2c, 0x5a,
0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68,
0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2f, 0x68, 0x65, 0x6c, 0x70,
0x65, 0x72, 0x2f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33,
}
var (
@ -1021,53 +1102,55 @@ func file_helper_identity_types_proto_rawDescGZIP() []byte {
return file_helper_identity_types_proto_rawDescData
}
var file_helper_identity_types_proto_msgTypes = make([]protoimpl.MessageInfo, 13)
var file_helper_identity_types_proto_msgTypes = make([]protoimpl.MessageInfo, 14)
var file_helper_identity_types_proto_goTypes = []interface{}{
(*Group)(nil), // 0: identity.Group
(*Entity)(nil), // 1: identity.Entity
(*Alias)(nil), // 2: identity.Alias
(*EntityStorageEntry)(nil), // 3: identity.EntityStorageEntry
(*PersonaIndexEntry)(nil), // 4: identity.PersonaIndexEntry
nil, // 5: identity.Group.MetadataEntry
nil, // 6: identity.Entity.MetadataEntry
nil, // 7: identity.Entity.MFASecretsEntry
nil, // 8: identity.Alias.MetadataEntry
nil, // 9: identity.Alias.CustomMetadataEntry
nil, // 10: identity.EntityStorageEntry.MetadataEntry
nil, // 11: identity.EntityStorageEntry.MFASecretsEntry
nil, // 12: identity.PersonaIndexEntry.MetadataEntry
(*timestamppb.Timestamp)(nil), // 13: google.protobuf.Timestamp
(*mfa.Secret)(nil), // 14: mfa.Secret
(*LocalAliases)(nil), // 1: identity.LocalAliases
(*Entity)(nil), // 2: identity.Entity
(*Alias)(nil), // 3: identity.Alias
(*EntityStorageEntry)(nil), // 4: identity.EntityStorageEntry
(*PersonaIndexEntry)(nil), // 5: identity.PersonaIndexEntry
nil, // 6: identity.Group.MetadataEntry
nil, // 7: identity.Entity.MetadataEntry
nil, // 8: identity.Entity.MFASecretsEntry
nil, // 9: identity.Alias.MetadataEntry
nil, // 10: identity.Alias.CustomMetadataEntry
nil, // 11: identity.EntityStorageEntry.MetadataEntry
nil, // 12: identity.EntityStorageEntry.MFASecretsEntry
nil, // 13: identity.PersonaIndexEntry.MetadataEntry
(*timestamppb.Timestamp)(nil), // 14: google.protobuf.Timestamp
(*mfa.Secret)(nil), // 15: mfa.Secret
}
var file_helper_identity_types_proto_depIDxs = []int32{
5, // 0: identity.Group.metadata:type_name -> identity.Group.MetadataEntry
13, // 1: identity.Group.creation_time:type_name -> google.protobuf.Timestamp
13, // 2: identity.Group.last_update_time:type_name -> google.protobuf.Timestamp
2, // 3: identity.Group.alias:type_name -> identity.Alias
2, // 4: identity.Entity.aliases:type_name -> identity.Alias
6, // 5: identity.Entity.metadata:type_name -> identity.Entity.MetadataEntry
13, // 6: identity.Entity.creation_time:type_name -> google.protobuf.Timestamp
13, // 7: identity.Entity.last_update_time:type_name -> google.protobuf.Timestamp
7, // 8: identity.Entity.mfa_secrets:type_name -> identity.Entity.MFASecretsEntry
8, // 9: identity.Alias.metadata:type_name -> identity.Alias.MetadataEntry
13, // 10: identity.Alias.creation_time:type_name -> google.protobuf.Timestamp
13, // 11: identity.Alias.last_update_time:type_name -> google.protobuf.Timestamp
9, // 12: identity.Alias.custom_metadata:type_name -> identity.Alias.CustomMetadataEntry
4, // 13: identity.EntityStorageEntry.personas:type_name -> identity.PersonaIndexEntry
10, // 14: identity.EntityStorageEntry.metadata:type_name -> identity.EntityStorageEntry.MetadataEntry
13, // 15: identity.EntityStorageEntry.creation_time:type_name -> google.protobuf.Timestamp
13, // 16: identity.EntityStorageEntry.last_update_time:type_name -> google.protobuf.Timestamp
11, // 17: identity.EntityStorageEntry.mfa_secrets:type_name -> identity.EntityStorageEntry.MFASecretsEntry
12, // 18: identity.PersonaIndexEntry.metadata:type_name -> identity.PersonaIndexEntry.MetadataEntry
13, // 19: identity.PersonaIndexEntry.creation_time:type_name -> google.protobuf.Timestamp
13, // 20: identity.PersonaIndexEntry.last_update_time:type_name -> google.protobuf.Timestamp
14, // 21: identity.Entity.MFASecretsEntry.value:type_name -> mfa.Secret
14, // 22: identity.EntityStorageEntry.MFASecretsEntry.value:type_name -> mfa.Secret
23, // [23:23] is the sub-list for method output_type
23, // [23:23] is the sub-list for method input_type
23, // [23:23] is the sub-list for extension type_name
23, // [23:23] is the sub-list for extension extendee
0, // [0:23] is the sub-list for field type_name
6, // 0: identity.Group.metadata:type_name -> identity.Group.MetadataEntry
14, // 1: identity.Group.creation_time:type_name -> google.protobuf.Timestamp
14, // 2: identity.Group.last_update_time:type_name -> google.protobuf.Timestamp
3, // 3: identity.Group.alias:type_name -> identity.Alias
3, // 4: identity.LocalAliases.aliases:type_name -> identity.Alias
3, // 5: identity.Entity.aliases:type_name -> identity.Alias
7, // 6: identity.Entity.metadata:type_name -> identity.Entity.MetadataEntry
14, // 7: identity.Entity.creation_time:type_name -> google.protobuf.Timestamp
14, // 8: identity.Entity.last_update_time:type_name -> google.protobuf.Timestamp
8, // 9: identity.Entity.mfa_secrets:type_name -> identity.Entity.MFASecretsEntry
9, // 10: identity.Alias.metadata:type_name -> identity.Alias.MetadataEntry
14, // 11: identity.Alias.creation_time:type_name -> google.protobuf.Timestamp
14, // 12: identity.Alias.last_update_time:type_name -> google.protobuf.Timestamp
10, // 13: identity.Alias.custom_metadata:type_name -> identity.Alias.CustomMetadataEntry
5, // 14: identity.EntityStorageEntry.personas:type_name -> identity.PersonaIndexEntry
11, // 15: identity.EntityStorageEntry.metadata:type_name -> identity.EntityStorageEntry.MetadataEntry
14, // 16: identity.EntityStorageEntry.creation_time:type_name -> google.protobuf.Timestamp
14, // 17: identity.EntityStorageEntry.last_update_time:type_name -> google.protobuf.Timestamp
12, // 18: identity.EntityStorageEntry.mfa_secrets:type_name -> identity.EntityStorageEntry.MFASecretsEntry
13, // 19: identity.PersonaIndexEntry.metadata:type_name -> identity.PersonaIndexEntry.MetadataEntry
14, // 20: identity.PersonaIndexEntry.creation_time:type_name -> google.protobuf.Timestamp
14, // 21: identity.PersonaIndexEntry.last_update_time:type_name -> google.protobuf.Timestamp
15, // 22: identity.Entity.MFASecretsEntry.value:type_name -> mfa.Secret
15, // 23: identity.EntityStorageEntry.MFASecretsEntry.value:type_name -> mfa.Secret
24, // [24:24] is the sub-list for method output_type
24, // [24:24] is the sub-list for method input_type
24, // [24:24] is the sub-list for extension type_name
24, // [24:24] is the sub-list for extension extendee
0, // [0:24] is the sub-list for field type_name
}
func init() { file_helper_identity_types_proto_init() }
@ -1089,7 +1172,7 @@ func file_helper_identity_types_proto_init() {
}
}
file_helper_identity_types_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Entity); i {
switch v := v.(*LocalAliases); i {
case 0:
return &v.state
case 1:
@ -1101,7 +1184,7 @@ func file_helper_identity_types_proto_init() {
}
}
file_helper_identity_types_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Alias); i {
switch v := v.(*Entity); i {
case 0:
return &v.state
case 1:
@ -1113,7 +1196,7 @@ func file_helper_identity_types_proto_init() {
}
}
file_helper_identity_types_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*EntityStorageEntry); i {
switch v := v.(*Alias); i {
case 0:
return &v.state
case 1:
@ -1125,6 +1208,18 @@ func file_helper_identity_types_proto_init() {
}
}
file_helper_identity_types_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*EntityStorageEntry); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_helper_identity_types_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*PersonaIndexEntry); i {
case 0:
return &v.state
@ -1143,7 +1238,7 @@ func file_helper_identity_types_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_helper_identity_types_proto_rawDesc,
NumEnums: 0,
NumMessages: 13,
NumMessages: 14,
NumExtensions: 0,
NumServices: 0,
},

View File

@ -74,6 +74,12 @@ message Group {
string namespace_id = 13;
}
// LocalAliases holds the aliases belonging to an entity that are local to the
// cluster.
message LocalAliases {
repeated Alias aliases = 1;
}
// Entity represents an entity that gets persisted and indexed.
// Entity is fundamentally composed of zero or many aliases.
message Entity {
@ -212,6 +218,18 @@ message Alias {
// Custom Metadata represents the custom data tied to this alias
// @inject_tag: sentinel:"-"
map<string, string> custom_metadata = 12;
// Local indicates if the alias only belongs to the cluster where it was
// created. If true, the alias will be stored in a location that is ignored by
// the performance replication subsystem.
// @inject_tag: sentinel:"-"
bool local = 13;
// LocalBucketKey is the identifying element of the location where this alias
// is stored in the storage packer. This helps in querying local aliases
// during invalidation of local aliases in performance standbys.
// @inject_tag: sentinel:"-"
string local_bucket_key = 14;
}
// Deprecated. Retained for backwards compatibility.

View File

@ -140,6 +140,10 @@ type Alias struct {
NamespaceID string `protobuf:"bytes,6,opt,name=namespace_id,json=namespaceID,proto3" json:"namespace_id,omitempty"`
// Custom Metadata represents the custom data tied to this alias
CustomMetadata map[string]string `protobuf:"bytes,7,rep,name=custom_metadata,json=customMetadata,proto3" json:"custom_metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
// Local indicates if the alias only belongs to the cluster where it was
// created. If true, the alias will be stored in a location that are ignored
// by the performance replication subsystem.
Local bool `protobuf:"varint,8,opt,name=local,proto3" json:"local,omitempty"`
}
func (x *Alias) Reset() {
@ -223,6 +227,13 @@ func (x *Alias) GetCustomMetadata() map[string]string {
return nil
}
func (x *Alias) GetLocal() bool {
if x != nil {
return x.Local
}
return false
}
type Group struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@ -321,7 +332,7 @@ var file_sdk_logical_identity_proto_rawDesc = []byte{
0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x9b, 0x03, 0x0a, 0x05, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12,
0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xb1, 0x03, 0x0a, 0x05, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12,
0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x25,
0x0a, 0x0e, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x6f, 0x72,
@ -339,30 +350,32 @@ var file_sdk_logical_identity_proto_rawDesc = []byte{
0x22, 0x2e, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x2e, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x2e,
0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e,
0x74, 0x72, 0x79, 0x52, 0x0e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45,
0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
0x1a, 0x41, 0x0a, 0x13, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
0x02, 0x38, 0x01, 0x22, 0xc5, 0x01, 0x0a, 0x05, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x0e, 0x0a,
0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x44, 0x12, 0x12, 0x0a,
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d,
0x65, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20,
0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x2e, 0x47, 0x72,
0x6f, 0x75, 0x70, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x6e,
0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x1a, 0x3b,
0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65,
0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x28, 0x5a, 0x26, 0x67,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63,
0x6f, 0x72, 0x70, 0x2f, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2f, 0x73, 0x64, 0x6b, 0x2f, 0x6c, 0x6f,
0x67, 0x69, 0x63, 0x61, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x18, 0x08, 0x20, 0x01,
0x28, 0x08, 0x52, 0x05, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74,
0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65,
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c,
0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x41, 0x0a, 0x13, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d,
0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a,
0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12,
0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0xc5, 0x01, 0x0a, 0x05, 0x47, 0x72,
0x6f, 0x75, 0x70, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x02, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64,
0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x6c, 0x6f, 0x67, 0x69,
0x63, 0x61, 0x6c, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61,
0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74,
0x61, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69,
0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61,
0x63, 0x65, 0x49, 0x64, 0x1a, 0x3b, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38,
0x01, 0x42, 0x28, 0x5a, 0x26, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x76, 0x61, 0x75, 0x6c, 0x74, 0x2f,
0x73, 0x64, 0x6b, 0x2f, 0x6c, 0x6f, 0x67, 0x69, 0x63, 0x61, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33,
}
var (

View File

@ -53,6 +53,11 @@ message Alias {
// Custom Metadata represents the custom data tied to this alias
map<string, string> custom_metadata = 7;
// Local indicates if the alias only belongs to the cluster where it was
// created. If true, the alias will be stored in a location that are ignored
// by the performance replication subsystem.
bool local = 8;
}
message Group {

View File

@ -5,63 +5,12 @@ import (
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/builtin/credential/github"
credLdap "github.com/hashicorp/vault/builtin/credential/ldap"
"github.com/hashicorp/vault/builtin/credential/userpass"
vaulthttp "github.com/hashicorp/vault/http"
"github.com/hashicorp/vault/sdk/logical"
"github.com/hashicorp/vault/vault"
)
func TestIdentityStore_EntityAliasLocalMount(t *testing.T) {
coreConfig := &vault.CoreConfig{
CredentialBackends: map[string]logical.Factory{
"ldap": credLdap.Factory,
},
}
cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{
HandlerFunc: vaulthttp.Handler,
})
cluster.Start()
defer cluster.Cleanup()
core := cluster.Cores[0].Core
vault.TestWaitActive(t, core)
client := cluster.Cores[0].Client
// Create a local auth mount
err := client.Sys().EnableAuthWithOptions("ldap", &api.EnableAuthOptions{
Type: "ldap",
Local: true,
})
if err != nil {
t.Fatal(err)
}
// Extract out the mount accessor for LDAP auth
auths, err := client.Sys().ListAuth()
if err != nil {
t.Fatal(err)
}
ldapMountAccessor := auths["ldap/"].Accessor
// Create an entity
secret, err := client.Logical().Write("identity/entity", nil)
if err != nil {
t.Fatal(err)
}
entityID := secret.Data["id"].(string)
// Attempt to create an entity alias against a local mount should fail
secret, err = client.Logical().Write("identity/entity-alias", map[string]interface{}{
"name": "testuser",
"mount_accessor": ldapMountAccessor,
"canonical_id": entityID,
})
if err == nil {
t.Fatalf("expected error since mount is local")
}
}
func TestIdentityStore_ListAlias(t *testing.T) {
coreConfig := &vault.CoreConfig{
CredentialBackends: map[string]logical.Factory{

View File

@ -22,7 +22,8 @@ import (
)
const (
groupBucketsPrefix = "packer/group/buckets/"
groupBucketsPrefix = "packer/group/buckets/"
localAliasesBucketsPrefix = "packer/local-aliases/buckets/"
)
var (
@ -58,6 +59,7 @@ func NewIdentityStore(ctx context.Context, core *Core, config *logical.BackendCo
totpPersister: core,
groupUpdater: core,
tokenStorer: core,
entityCreator: core,
}
// Create a memdb instance, which by default, operates on lower cased
@ -69,13 +71,21 @@ func NewIdentityStore(ctx context.Context, core *Core, config *logical.BackendCo
entitiesPackerLogger := iStore.logger.Named("storagepacker").Named("entities")
core.AddLogger(entitiesPackerLogger)
localAliasesPackerLogger := iStore.logger.Named("storagepacker").Named("local-aliases")
core.AddLogger(localAliasesPackerLogger)
groupsPackerLogger := iStore.logger.Named("storagepacker").Named("groups")
core.AddLogger(groupsPackerLogger)
iStore.entityPacker, err = storagepacker.NewStoragePacker(iStore.view, entitiesPackerLogger, "")
if err != nil {
return nil, fmt.Errorf("failed to create entity packer: %w", err)
}
iStore.localAliasPacker, err = storagepacker.NewStoragePacker(iStore.view, localAliasesPackerLogger, localAliasesBucketsPrefix)
if err != nil {
return nil, fmt.Errorf("failed to create local alias packer: %w", err)
}
iStore.groupPacker, err = storagepacker.NewStoragePacker(iStore.view, groupsPackerLogger, groupBucketsPrefix)
if err != nil {
return nil, fmt.Errorf("failed to create group packer: %w", err)
@ -92,6 +102,9 @@ func NewIdentityStore(ctx context.Context, core *Core, config *logical.BackendCo
"oidc/provider/+/.well-known/*",
"oidc/provider/+/token",
},
LocalStorage: []string{
localAliasesBucketsPrefix,
},
},
PeriodicFunc: func(ctx context.Context, req *logical.Request) error {
iStore.oidcPeriodicFunc(ctx)
@ -237,6 +250,7 @@ func (i *IdentityStore) Invalidate(ctx context.Context, key string) {
// storage entry is non-nil, its an indication of an update. In this
// case, entities in the updated bucket needs to be reinserted into
// MemDB.
entityIDs := make([]string, 0, len(bucket.Items))
if bucket != nil {
for _, item := range bucket.Items {
entity, err := i.parseEntityFromBucketItem(ctx, item)
@ -245,12 +259,53 @@ func (i *IdentityStore) Invalidate(ctx context.Context, key string) {
return
}
localAliases, err := i.parseLocalAliases(entity.ID)
if err != nil {
i.logger.Error("failed to load local aliases from storage", "error", err)
return
}
if localAliases != nil {
for _, alias := range localAliases.Aliases {
entity.UpsertAlias(alias)
}
}
// Only update MemDB and don't touch the storage
err = i.upsertEntityInTxn(ctx, txn, entity, nil, false)
if err != nil {
i.logger.Error("failed to update entity in MemDB", "error", err)
return
}
// If we are a secondary, the entity created by the secondary
// via the CreateEntity RPC would have been cached. Now that the
// invalidation of the same has hit, there is no need of the
// cache. Clearing the cache. Writing to storage can't be
// performed by perf standbys. So only doing this in the active
// node of the secondary.
if i.localNode.ReplicationState().HasState(consts.ReplicationPerformanceSecondary) && i.localNode.HAState() != consts.PerfStandby {
if err := i.localAliasPacker.DeleteItem(ctx, entity.ID+tmpSuffix); err != nil {
i.logger.Error("failed to clear local alias entity cache", "error", err, "entity_id", entity.ID)
return
}
}
entityIDs = append(entityIDs, entity.ID)
}
}
// entitiesFetched are the entities before invalidation. entityIDs
// represent entities that are valid after invalidation. Clear the
// storage entries of local aliases for those entities that are
// indicated deleted by this invalidation.
if i.localNode.ReplicationState().HasState(consts.ReplicationPerformanceSecondary) && i.localNode.HAState() != consts.PerfStandby {
for _, entity := range entitiesFetched {
if !strutil.StrListContains(entityIDs, entity.ID) {
if err := i.localAliasPacker.DeleteItem(ctx, entity.ID); err != nil {
i.logger.Error("failed to clear local alias for entity", "error", err, "entity_id", entity.ID)
return
}
}
}
}
@ -258,6 +313,7 @@ func (i *IdentityStore) Invalidate(ctx context.Context, key string) {
return
// Check if the key is a storage entry key for an group bucket
// For those entities that are deleted, clear up the local alias entries
case strings.HasPrefix(key, groupBucketsPrefix):
// Create a MemDB transaction
txn := i.db.Txn(true)
@ -351,9 +407,127 @@ func (i *IdentityStore) Invalidate(ctx context.Context, key string) {
i.logger.Error("error invalidating client", "error", err, "key", key)
return
}
case strings.HasPrefix(key, localAliasesBucketsPrefix):
//
// This invalidation only happens on perf standbys
//
txn := i.db.Txn(true)
defer txn.Abort()
// Find all the local aliases belonging to this bucket and remove it
// both from aliases table and entities table. We will add the local
// aliases back by parsing the storage key. This way the deletion
// invalidation gets handled.
aliases, err := i.MemDBLocalAliasesByBucketKeyInTxn(txn, key)
if err != nil {
i.logger.Error("failed to fetch entities using the bucket key", "key", key)
return
}
for _, alias := range aliases {
entity, err := i.MemDBEntityByIDInTxn(txn, alias.CanonicalID, true)
if err != nil {
i.logger.Error("failed to fetch entity during local alias invalidation", "entity_id", alias.CanonicalID, "error", err)
return
}
// Delete local aliases from the entity.
err = i.deleteAliasesInEntityInTxn(txn, entity, []*identity.Alias{alias})
if err != nil {
i.logger.Error("failed to delete aliases in entity", "entity_id", entity.ID, "error", err)
return
}
// Update the entity with removed alias.
if err := i.MemDBUpsertEntityInTxn(txn, entity); err != nil {
i.logger.Error("failed to delete entity from MemDB", "entity_id", entity.ID, "error", err)
return
}
}
// Now read the invalidated storage key
bucket, err := i.localAliasPacker.GetBucket(ctx, key)
if err != nil {
i.logger.Error("failed to refresh local aliases", "key", key, "error", err)
return
}
if bucket != nil {
for _, item := range bucket.Items {
if strings.HasSuffix(item.ID, tmpSuffix) {
continue
}
var localAliases identity.LocalAliases
err = ptypes.UnmarshalAny(item.Message, &localAliases)
if err != nil {
i.logger.Error("failed to parse local aliases during invalidation", "error", err)
return
}
for _, alias := range localAliases.Aliases {
// Add to the aliases table
if err := i.MemDBUpsertAliasInTxn(txn, alias, false); err != nil {
i.logger.Error("failed to insert local alias to memdb during invalidation", "error", err)
return
}
// Fetch the associated entity and add the alias to that too.
entity, err := i.MemDBEntityByIDInTxn(txn, alias.CanonicalID, false)
if err != nil {
i.logger.Error("failed to fetch entity during local alias invalidation", "error", err)
return
}
if entity == nil {
cachedEntityItem, err := i.localAliasPacker.GetItem(alias.CanonicalID + tmpSuffix)
if err != nil {
i.logger.Error("failed to fetch cached entity", "key", key, "error", err)
return
}
if cachedEntityItem != nil {
entity, err = i.parseCachedEntity(cachedEntityItem)
if err != nil {
i.logger.Error("failed to parse cached entity", "key", key, "error", err)
return
}
}
}
if entity == nil {
i.logger.Error("received local alias invalidation for an invalid entity", "item.ID", item.ID)
return
}
entity.UpsertAlias(alias)
// Update the entities table
if err := i.MemDBUpsertEntityInTxn(txn, entity); err != nil {
i.logger.Error("failed to upsert entity during local alias invalidation", "error", err)
return
}
}
}
}
txn.Commit()
return
}
}
func (i *IdentityStore) parseLocalAliases(entityID string) (*identity.LocalAliases, error) {
item, err := i.localAliasPacker.GetItem(entityID)
if err != nil {
return nil, err
}
if item == nil {
return nil, nil
}
var localAliases identity.LocalAliases
err = ptypes.UnmarshalAny(item.Message, &localAliases)
if err != nil {
return nil, err
}
return &localAliases, nil
}
func (i *IdentityStore) parseEntityFromBucketItem(ctx context.Context, item *storagepacker.Item) (*identity.Entity, error) {
if item == nil {
return nil, fmt.Errorf("nil item")
@ -400,7 +574,7 @@ func (i *IdentityStore) parseEntityFromBucketItem(ctx context.Context, item *sto
newAlias.CreationTime = oldAlias.CreationTime
newAlias.LastUpdateTime = oldAlias.LastUpdateTime
newAlias.MergedFromCanonicalIDs = oldAlias.MergedFromEntityIDs
entity.Aliases = append(entity.Aliases, &newAlias)
entity.UpsertAlias(&newAlias)
}
persistNeeded = true
@ -439,6 +613,24 @@ func (i *IdentityStore) parseEntityFromBucketItem(ctx context.Context, item *sto
return &entity, nil
}
func (i *IdentityStore) parseCachedEntity(item *storagepacker.Item) (*identity.Entity, error) {
if item == nil {
return nil, fmt.Errorf("nil item")
}
var entity identity.Entity
err := ptypes.UnmarshalAny(item.Message, &entity)
if err != nil {
return nil, fmt.Errorf("failed to decode cached entity from storage bucket item: %w", err)
}
if entity.NamespaceID == "" {
entity.NamespaceID = namespace.RootNamespaceID
}
return &entity, nil
}
func (i *IdentityStore) parseGroupFromBucketItem(item *storagepacker.Item) (*identity.Group, error) {
if item == nil {
return nil, fmt.Errorf("nil item")
@ -500,6 +692,37 @@ func (i *IdentityStore) entityByAliasFactorsInTxn(txn *memdb.Txn, mountAccessor,
return i.MemDBEntityByAliasIDInTxn(txn, alias.ID, clone)
}
// CreateEntity creates a new entity.
func (i *IdentityStore) CreateEntity(ctx context.Context) (*identity.Entity, error) {
defer metrics.MeasureSince([]string{"identity", "create_entity"}, time.Now())
entity := new(identity.Entity)
err := i.sanitizeEntity(ctx, entity)
if err != nil {
return nil, err
}
if err := i.upsertEntity(ctx, entity, nil, true); err != nil {
return nil, err
}
// Emit a metric for the new entity
ns, err := i.namespacer.NamespaceByID(ctx, entity.NamespaceID)
var nsLabel metrics.Label
if err != nil {
nsLabel = metrics.Label{"namespace", "unknown"}
} else {
nsLabel = metricsutil.NamespaceLabel(ns)
}
i.metrics.IncrCounterWithLabels(
[]string{"identity", "entity", "creation"},
1,
[]metrics.Label{
nsLabel,
})
return entity, nil
}
// CreateOrFetchEntity creates a new entity. This is used by core to
// associate each login attempt by an alias to a unified entity in Vault.
func (i *IdentityStore) CreateOrFetchEntity(ctx context.Context, alias *logical.Alias) (*identity.Entity, error) {
@ -522,10 +745,6 @@ func (i *IdentityStore) CreateOrFetchEntity(ctx context.Context, alias *logical.
return nil, fmt.Errorf("invalid mount accessor %q", alias.MountAccessor)
}
if mountValidationResp.MountLocal {
return nil, fmt.Errorf("mount_accessor %q is of a local mount", alias.MountAccessor)
}
if mountValidationResp.MountType != alias.MountType {
return nil, fmt.Errorf("mount accessor %q is not a mount of type %q", alias.MountAccessor, alias.MountType)
}
@ -578,6 +797,7 @@ func (i *IdentityStore) CreateOrFetchEntity(ctx context.Context, alias *logical.
Metadata: alias.Metadata,
MountPath: mountValidationResp.MountPath,
MountType: mountValidationResp.MountType,
Local: alias.Local,
}
err = i.sanitizeAlias(ctx, newAlias)

View File

@ -188,7 +188,6 @@ func (i *IdentityStore) handleAliasCreateUpdate() framework.OperationFunc {
name = alias.Name
mountAccessor = alias.MountAccessor
customMetadata = alias.CustomMetadata
case mountAccessor == "":
// No change to mount accessor
mountAccessor = alias.MountAccessor
@ -198,11 +197,10 @@ func (i *IdentityStore) handleAliasCreateUpdate() framework.OperationFunc {
case len(customMetadata) == 0:
// No change to custom metadata
customMetadata = alias.CustomMetadata
default:
// mountAccessor, name and customMetadata provided
}
return i.handleAliasUpdate(ctx, req, canonicalID, name, mountAccessor, alias, customMetadata)
return i.handleAliasUpdate(ctx, canonicalID, name, mountAccessor, alias, customMetadata)
}
}
@ -216,9 +214,6 @@ func (i *IdentityStore) handleAliasCreateUpdate() framework.OperationFunc {
if mountEntry == nil {
return logical.ErrorResponse(fmt.Sprintf("invalid mount accessor %q", mountAccessor)), nil
}
if mountEntry.Local {
return logical.ErrorResponse(fmt.Sprintf("mount accessor %q is of a local mount", mountAccessor)), nil
}
if mountEntry.NamespaceID != ns.ID {
return logical.ErrorResponse("matching mount is in a different namespace than request"), logical.ErrPermissionDenied
}
@ -230,30 +225,20 @@ func (i *IdentityStore) handleAliasCreateUpdate() framework.OperationFunc {
if alias.NamespaceID != ns.ID {
return logical.ErrorResponse("cannot modify aliases across namespaces"), logical.ErrPermissionDenied
}
return i.handleAliasUpdate(ctx, req, alias.CanonicalID, name, mountAccessor, alias, customMetadata)
return i.handleAliasUpdate(ctx, canonicalID, name, mountAccessor, alias, customMetadata)
}
// At this point we know it's a new creation request
return i.handleAliasCreate(ctx, req, canonicalID, name, mountAccessor, customMetadata)
return i.handleAliasCreate(ctx, canonicalID, name, mountAccessor, mountEntry.Local, customMetadata)
}
}
func (i *IdentityStore) handleAliasCreate(ctx context.Context, req *logical.Request, canonicalID, name, mountAccessor string, customMetadata map[string]string) (*logical.Response, error) {
func (i *IdentityStore) handleAliasCreate(ctx context.Context, canonicalID, name, mountAccessor string, local bool, customMetadata map[string]string) (*logical.Response, error) {
ns, err := namespace.FromContext(ctx)
if err != nil {
return nil, err
}
alias := &identity.Alias{
MountAccessor: mountAccessor,
Name: name,
CustomMetadata: customMetadata,
}
entity := &identity.Entity{}
// If a canonical ID is provided pull up the entity and make sure we're in
// the right NS
var entity *identity.Entity
if canonicalID != "" {
entity, err = i.MemDBEntityByID(canonicalID, true)
if err != nil {
@ -267,35 +252,62 @@ func (i *IdentityStore) handleAliasCreate(ctx context.Context, req *logical.Requ
}
}
if entity == nil && local {
// Check to see if the entity creation should be forwarded.
entity, err = i.entityCreator.CreateEntity(ctx)
if err != nil {
return nil, err
}
}
persist := false
// If the request was not forwarded, then this is the active node of the
// primary. Create the entity here itself.
if entity == nil {
persist = true
entity = new(identity.Entity)
err = i.sanitizeEntity(ctx, entity)
if err != nil {
return nil, err
}
}
for _, currentAlias := range entity.Aliases {
if currentAlias.MountAccessor == mountAccessor {
return logical.ErrorResponse("Alias already exists for requested entity and mount accessor"), nil
}
}
entity.Aliases = append(entity.Aliases, alias)
// ID creation and other validations; This is more useful for new entities
// and may not perform anything for the existing entities. Placing the
// check here to make the flow common for both new and existing entities.
err = i.sanitizeEntity(ctx, entity)
if err != nil {
return nil, err
}
// Set the canonical ID in the alias index. This should be done after
// sanitizing entity in case it's a new entity that didn't have an ID.
alias.CanonicalID = entity.ID
// ID creation and other validations
err = i.sanitizeAlias(ctx, alias)
if err != nil {
return nil, err
var alias *identity.Alias
switch local {
case true:
alias, err = i.processLocalAlias(ctx, &logical.Alias{
MountAccessor: mountAccessor,
Name: name,
Local: local,
CustomMetadata: customMetadata,
}, entity, false)
if err != nil {
return nil, err
}
default:
alias = &identity.Alias{
MountAccessor: mountAccessor,
Name: name,
CustomMetadata: customMetadata,
CanonicalID: entity.ID,
}
err = i.sanitizeAlias(ctx, alias)
if err != nil {
return nil, err
}
entity.UpsertAlias(alias)
persist = true
}
// Index entity and its aliases in MemDB and persist entity along with
// aliases in storage.
if err := i.upsertEntity(ctx, entity, nil, true); err != nil {
if err := i.upsertEntity(ctx, entity, nil, persist); err != nil {
return nil, err
}
@ -308,7 +320,7 @@ func (i *IdentityStore) handleAliasCreate(ctx context.Context, req *logical.Requ
}, nil
}
func (i *IdentityStore) handleAliasUpdate(ctx context.Context, req *logical.Request, canonicalID, name, mountAccessor string, alias *identity.Alias, customMetadata map[string]string) (*logical.Response, error) {
func (i *IdentityStore) handleAliasUpdate(ctx context.Context, canonicalID, name, mountAccessor string, alias *identity.Alias, customMetadata map[string]string) (*logical.Response, error) {
if name == alias.Name &&
mountAccessor == alias.MountAccessor &&
(canonicalID == alias.CanonicalID || canonicalID == "") && (strutil.EqualStringMaps(customMetadata, alias.CustomMetadata)) {
@ -350,9 +362,6 @@ func (i *IdentityStore) handleAliasUpdate(ctx context.Context, req *logical.Requ
if mountEntry == nil {
return logical.ErrorResponse(fmt.Sprintf("invalid mount accessor %q", mountAccessor)), nil
}
if mountEntry.Local {
return logical.ErrorResponse(fmt.Sprintf("mount_accessor %q is of a local mount", mountAccessor)), nil
}
if mountEntry.NamespaceID != alias.NamespaceID {
return logical.ErrorResponse("given mount accessor is not in the same namespace as the existing alias"), logical.ErrPermissionDenied
}
@ -373,8 +382,18 @@ func (i *IdentityStore) handleAliasUpdate(ctx context.Context, req *logical.Requ
alias.CustomMetadata = customMetadata
}
mountValidationResp := i.router.ValidateMountByAccessor(alias.MountAccessor)
if mountValidationResp == nil {
return nil, fmt.Errorf("invalid mount accessor %q", alias.MountAccessor)
}
newEntity := currentEntity
if canonicalID != "" && canonicalID != alias.CanonicalID {
// Don't allow moving local aliases between entities.
if mountValidationResp.MountLocal {
return logical.ErrorResponse("local aliases can't be moved between entities"), nil
}
newEntity, err = i.MemDBEntityByID(canonicalID, true)
if err != nil {
return nil, err
@ -417,6 +436,25 @@ func (i *IdentityStore) handleAliasUpdate(ctx context.Context, req *logical.Requ
currentEntity = nil
}
if mountValidationResp.MountLocal {
alias, err = i.processLocalAlias(ctx, &logical.Alias{
MountAccessor: mountAccessor,
Name: name,
Local: mountValidationResp.MountLocal,
CustomMetadata: customMetadata,
}, newEntity, true)
if err != nil {
return nil, err
}
return &logical.Response{
Data: map[string]interface{}{
"id": alias.ID,
"canonical_id": newEntity.ID,
},
}, nil
}
// Index entity and its aliases in MemDB and persist entity along with
// aliases in storage. If the alias is being transferred over from
// one entity to another, previous entity needs to get refreshed in MemDB
@ -523,6 +561,7 @@ func (i *IdentityStore) handleAliasReadCommon(ctx context.Context, alias *identi
respData["name"] = alias.Name
respData["merged_from_canonical_ids"] = alias.MergedFromCanonicalIDs
respData["namespace_id"] = alias.NamespaceID
respData["local"] = alias.Local
if mountValidationResp := i.router.ValidateMountByAccessor(alias.MountAccessor); mountValidationResp != nil {
respData["mount_path"] = mountValidationResp.MountPath
@ -599,19 +638,39 @@ func (i *IdentityStore) pathAliasIDDelete() framework.OperationFunc {
return nil, err
}
// Persist the entity object
entityAsAny, err := ptypes.MarshalAny(entity)
if err != nil {
return nil, err
}
item := &storagepacker.Item{
ID: entity.ID,
Message: entityAsAny,
}
switch alias.Local {
case true:
localAliases, err := i.parseLocalAliases(entity.ID)
if err != nil {
return nil, err
}
err = i.entityPacker.PutItem(ctx, item)
if err != nil {
return nil, err
if localAliases == nil {
return nil, nil
}
for i, item := range localAliases.Aliases {
if item.ID == alias.ID {
localAliases.Aliases = append(localAliases.Aliases[:i], localAliases.Aliases[i+1:]...)
break
}
}
marshaledAliases, err := ptypes.MarshalAny(localAliases)
if err != nil {
return nil, err
}
if err := i.localAliasPacker.PutItem(ctx, &storagepacker.Item{
ID: entity.ID,
Message: marshaledAliases,
}); err != nil {
return nil, err
}
default:
if err := i.persistEntity(ctx, entity); err != nil {
return nil, err
}
}
// Committing the transaction *after* successfully updating entity in

View File

@ -240,6 +240,7 @@ func TestIdentityStore_MemDBAliasIndexes(t *testing.T) {
"testkey1": "testmetadatavalue1",
"testkey2": "testmetadatavalue2",
},
LocalBucketKey: is.localAliasPacker.BucketKey(entity.ID),
}
txn = is.db.Txn(true)
@ -278,6 +279,7 @@ func TestIdentityStore_MemDBAliasIndexes(t *testing.T) {
"testkey1": "testmetadatavalue1",
"testkey3": "testmetadatavalue3",
},
LocalBucketKey: is.localAliasPacker.BucketKey(entity.ID),
}
txn = is.db.Txn(true)

View File

@ -373,6 +373,8 @@ func (i *IdentityStore) handleEntityReadCommon(ctx context.Context, entity *iden
aliasMap["merged_from_canonical_ids"] = alias.MergedFromCanonicalIDs
aliasMap["creation_time"] = ptypes.TimestampString(alias.CreationTime)
aliasMap["last_update_time"] = ptypes.TimestampString(alias.LastUpdateTime)
aliasMap["local"] = alias.Local
aliasMap["custom_metadata"] = alias.CustomMetadata
if mountValidationResp := i.router.ValidateMountByAccessor(alias.MountAccessor); mountValidationResp != nil {
aliasMap["mount_type"] = mountValidationResp.MountType

View File

@ -15,3 +15,7 @@ func (c *Core) PersistTOTPKey(context.Context, string, string, string) error {
func (c *Core) SendGroupUpdate(context.Context, *identity.Group) (bool, error) {
return false, nil
}
func (c *Core) CreateEntity(ctx context.Context) (*identity.Entity, error) {
return nil, nil
}

View File

@ -70,6 +70,12 @@ func aliasesTableSchema(lowerCaseName bool) *memdb.TableSchema {
Field: "NamespaceID",
},
},
"local_bucket_key": {
Name: "local_bucket_key",
Indexer: &memdb.StringFieldIndex{
Field: "LocalBucketKey",
},
},
},
}
}

View File

@ -76,6 +76,12 @@ type IdentityStore struct {
// buckets
entityPacker *storagepacker.StoragePacker
// localAliasPacker is used to pack multiple local alias entries into lesser
// storage entries. This is also used to cache entities in the secondary
// clusters, those entities which were created by the primary but hasn't
// reached secondary via invalidations.
localAliasPacker *storagepacker.StoragePacker
// groupPacker is used to pack multiple group storage entries into 256
// buckets
groupPacker *storagepacker.StoragePacker
@ -92,6 +98,7 @@ type IdentityStore struct {
totpPersister TOTPPersister
groupUpdater GroupUpdater
tokenStorer TokenStorer
entityCreator EntityCreator
}
type groupDiff struct {
@ -136,3 +143,9 @@ type TokenStorer interface {
}
var _ TokenStorer = &Core{}
type EntityCreator interface {
CreateEntity(ctx context.Context) (*identity.Entity, error)
}
var _ EntityCreator = &Core{}

View File

@ -39,11 +39,12 @@ func TestIdentityStore_UnsealingWhenConflictingAliasNames(t *testing.T) {
}
alias := &identity.Alias{
ID: "alias1",
CanonicalID: "entity1",
MountType: "github",
MountAccessor: meGH.Accessor,
Name: "githubuser",
ID: "alias1",
CanonicalID: "entity1",
MountType: "github",
MountAccessor: meGH.Accessor,
Name: "githubuser",
LocalBucketKey: c.identityStore.localAliasPacker.BucketKey("entity1"),
}
entity := &identity.Entity{
ID: "entity1",
@ -53,8 +54,8 @@ func TestIdentityStore_UnsealingWhenConflictingAliasNames(t *testing.T) {
alias,
},
NamespaceID: namespace.RootNamespaceID,
BucketKey: c.identityStore.entityPacker.BucketKey("entity1"),
}
entity.BucketKey = c.identityStore.entityPacker.BucketKey(entity.ID)
err = c.identityStore.upsertEntity(namespace.RootContext(nil), entity, nil, true)
if err != nil {
@ -62,11 +63,12 @@ func TestIdentityStore_UnsealingWhenConflictingAliasNames(t *testing.T) {
}
alias2 := &identity.Alias{
ID: "alias2",
CanonicalID: "entity2",
MountType: "github",
MountAccessor: meGH.Accessor,
Name: "GITHUBUSER",
ID: "alias2",
CanonicalID: "entity2",
MountType: "github",
MountAccessor: meGH.Accessor,
Name: "GITHUBUSER",
LocalBucketKey: c.identityStore.localAliasPacker.BucketKey("entity2"),
}
entity2 := &identity.Entity{
ID: "entity2",
@ -76,8 +78,8 @@ func TestIdentityStore_UnsealingWhenConflictingAliasNames(t *testing.T) {
alias2,
},
NamespaceID: namespace.RootNamespaceID,
BucketKey: c.identityStore.entityPacker.BucketKey("entity2"),
}
entity2.BucketKey = c.identityStore.entityPacker.BucketKey(entity2.ID)
// Persist the second entity directly without the regular flow. This will skip
// merging of these enties.
@ -494,11 +496,12 @@ func TestIdentityStore_MergeConflictingAliases(t *testing.T) {
}
alias := &identity.Alias{
ID: "alias1",
CanonicalID: "entity1",
MountType: "github",
MountAccessor: meGH.Accessor,
Name: "githubuser",
ID: "alias1",
CanonicalID: "entity1",
MountType: "github",
MountAccessor: meGH.Accessor,
Name: "githubuser",
LocalBucketKey: c.identityStore.localAliasPacker.BucketKey("entity1"),
}
entity := &identity.Entity{
ID: "entity1",
@ -508,19 +511,20 @@ func TestIdentityStore_MergeConflictingAliases(t *testing.T) {
alias,
},
NamespaceID: namespace.RootNamespaceID,
BucketKey: c.identityStore.entityPacker.BucketKey("entity1"),
}
entity.BucketKey = c.identityStore.entityPacker.BucketKey(entity.ID)
err = c.identityStore.upsertEntity(namespace.RootContext(nil), entity, nil, true)
if err != nil {
t.Fatal(err)
}
alias2 := &identity.Alias{
ID: "alias2",
CanonicalID: "entity2",
MountType: "github",
MountAccessor: meGH.Accessor,
Name: "githubuser",
ID: "alias2",
CanonicalID: "entity2",
MountType: "github",
MountAccessor: meGH.Accessor,
Name: "githubuser",
LocalBucketKey: c.identityStore.localAliasPacker.BucketKey("entity2"),
}
entity2 := &identity.Entity{
ID: "entity2",
@ -530,10 +534,9 @@ func TestIdentityStore_MergeConflictingAliases(t *testing.T) {
alias2,
},
NamespaceID: namespace.RootNamespaceID,
BucketKey: c.identityStore.entityPacker.BucketKey("entity2"),
}
entity2.BucketKey = c.identityStore.entityPacker.BucketKey(entity2.ID)
err = c.identityStore.upsertEntity(namespace.RootContext(nil), entity2, nil, true)
if err != nil {
t.Fatal(err)

View File

@ -23,6 +23,7 @@ import (
)
var errDuplicateIdentityName = errors.New("duplicate identity name")
var tmpSuffix = ".tmp"
func (c *Core) SetLoadCaseSensitiveIdentityStore(caseSensitive bool) {
c.loadCaseSensitiveIdentityStore = caseSensitive
@ -35,15 +36,20 @@ func (c *Core) loadIdentityStoreArtifacts(ctx context.Context) error {
}
loadFunc := func(context.Context) error {
err := c.identityStore.loadEntities(ctx)
if err != nil {
if err := c.identityStore.loadEntities(ctx); err != nil {
return err
}
err = c.identityStore.loadGroups(ctx)
if err != nil {
if err := c.identityStore.loadGroups(ctx); err != nil {
return err
}
return c.identityStore.loadOIDCClients(ctx)
if err := c.identityStore.loadOIDCClients(ctx); err != nil {
return err
}
if err := c.identityStore.loadCachedEntitiesOfLocalAliases(ctx); err != nil {
return err
}
return nil
}
if !c.loadCaseSensitiveIdentityStore {
@ -53,7 +59,7 @@ func (c *Core) loadIdentityStoreArtifacts(ctx context.Context) error {
case err == nil:
// If it succeeds, all is well
return nil
case err != nil && !errwrap.Contains(err, errDuplicateIdentityName.Error()):
case !errwrap.Contains(err, errDuplicateIdentityName.Error()):
return err
}
}
@ -213,6 +219,134 @@ func (i *IdentityStore) loadGroups(ctx context.Context) error {
return nil
}
func (i *IdentityStore) loadCachedEntitiesOfLocalAliases(ctx context.Context) error {
// If we are performance secondary, load from temporary location those
// entities that were created by the secondary via RPCs to the primary, and
// also happen to have not yet been shipped to the secondary through
// performance replication.
if !i.localNode.ReplicationState().HasState(consts.ReplicationPerformanceSecondary) {
return nil
}
i.logger.Debug("loading cached entities of local aliases")
existing, err := i.localAliasPacker.View().List(ctx, localAliasesBucketsPrefix)
if err != nil {
return fmt.Errorf("failed to scan for cached entities of local alias: %w", err)
}
i.logger.Debug("cached entities of local alias entries", "num_buckets", len(existing))
// Make the channels used for the worker pool
broker := make(chan string)
quit := make(chan bool)
// Buffer these channels to prevent deadlocks
errs := make(chan error, len(existing))
result := make(chan *storagepacker.Bucket, len(existing))
// Use a wait group
wg := &sync.WaitGroup{}
// Create 64 workers to distribute work to
for j := 0; j < consts.ExpirationRestoreWorkerCount; j++ {
wg.Add(1)
go func() {
defer wg.Done()
for {
select {
case key, ok := <-broker:
// broker has been closed, we are done
if !ok {
return
}
bucket, err := i.localAliasPacker.GetBucket(ctx, localAliasesBucketsPrefix+key)
if err != nil {
errs <- err
continue
}
// Write results out to the result channel
result <- bucket
// quit early
case <-quit:
return
}
}
}()
}
// Distribute the collected keys to the workers in a go routine
wg.Add(1)
go func() {
defer wg.Done()
for j, key := range existing {
if j%500 == 0 {
i.logger.Debug("cached entities of local aliases loading", "progress", j)
}
select {
case <-quit:
return
default:
broker <- key
}
}
// Close the broker, causing worker routines to exit
close(broker)
}()
// Restore each key by pulling from the result chan
for j := 0; j < len(existing); j++ {
select {
case err := <-errs:
// Close all go routines
close(quit)
return err
case bucket := <-result:
// If there is no entry, nothing to restore
if bucket == nil {
continue
}
for _, item := range bucket.Items {
if !strings.HasSuffix(item.ID, tmpSuffix) {
continue
}
entity, err := i.parseCachedEntity(item)
if err != nil {
return err
}
ns, err := i.namespacer.NamespaceByID(ctx, entity.NamespaceID)
if err != nil {
return err
}
nsCtx := namespace.ContextWithNamespace(ctx, ns)
err = i.upsertEntity(nsCtx, entity, nil, false)
if err != nil {
return fmt.Errorf("failed to update entity in MemDB: %w", err)
}
}
}
}
// Let all go routines finish
wg.Wait()
if i.logger.IsInfo() {
i.logger.Info("cached entities of local aliases restored")
}
return nil
}
func (i *IdentityStore) loadEntities(ctx context.Context) error {
// Accumulate existing entities
i.logger.Debug("loading entities")
@ -349,6 +483,17 @@ func (i *IdentityStore) loadEntities(ctx context.Context) error {
duplicatedAccessors[accessor] = struct{}{}
}
}
localAliases, err := i.parseLocalAliases(entity.ID)
if err != nil {
return fmt.Errorf("failed to load local aliases from storage: %v", err)
}
if localAliases != nil {
for _, alias := range localAliases.Aliases {
entity.UpsertAlias(alias)
}
}
// Only update MemDB and don't hit the storage again
err = i.upsertEntity(nsCtx, entity, nil, false)
if err != nil {
@ -491,7 +636,7 @@ func (i *IdentityStore) upsertEntityInTxn(ctx context.Context, txn *memdb.Txn, e
}
if strutil.StrListContains(aliasFactors, i.sanitizeName(alias.Name)+alias.MountAccessor) {
i.logger.Warn(errDuplicateIdentityName.Error(), "alias_name", alias.Name, "mount_accessor", alias.MountAccessor, "entity_name", entity.Name, "action", "delete one of the duplicate aliases")
i.logger.Warn(errDuplicateIdentityName.Error(), "alias_name", alias.Name, "mount_accessor", alias.MountAccessor, "local", alias.Local, "entity_name", entity.Name, "action", "delete one of the duplicate aliases")
if !i.disableLowerCasedNames {
return errDuplicateIdentityName
}
@ -515,15 +660,7 @@ func (i *IdentityStore) upsertEntityInTxn(ctx context.Context, txn *memdb.Txn, e
if persist {
// Persist the previous entity object
marshaledPreviousEntity, err := ptypes.MarshalAny(previousEntity)
if err != nil {
return err
}
err = i.entityPacker.PutItem(ctx, &storagepacker.Item{
ID: previousEntity.ID,
Message: marshaledPreviousEntity,
})
if err != nil {
if err := i.persistEntity(ctx, previousEntity); err != nil {
return err
}
}
@ -536,20 +673,178 @@ func (i *IdentityStore) upsertEntityInTxn(ctx context.Context, txn *memdb.Txn, e
}
if persist {
entityAsAny, err := ptypes.MarshalAny(entity)
if err != nil {
if err := i.persistEntity(ctx, entity); err != nil {
return err
}
item := &storagepacker.Item{
ID: entity.ID,
Message: entityAsAny,
}
}
// Persist the entity object
err = i.entityPacker.PutItem(ctx, item)
return nil
}
func (i *IdentityStore) processLocalAlias(ctx context.Context, lAlias *logical.Alias, entity *identity.Entity, updateDb bool) (*identity.Alias, error) {
if !lAlias.Local {
return nil, fmt.Errorf("alias is not local")
}
mountValidationResp := i.router.ValidateMountByAccessor(lAlias.MountAccessor)
if mountValidationResp == nil {
return nil, fmt.Errorf("invalid mount accessor %q", lAlias.MountAccessor)
}
if !mountValidationResp.MountLocal {
return nil, fmt.Errorf("mount accessor %q is not local", lAlias.MountAccessor)
}
alias, err := i.MemDBAliasByFactors(lAlias.MountAccessor, lAlias.Name, false, false)
if err != nil {
return nil, err
}
if alias == nil {
alias = &identity.Alias{}
}
alias.CanonicalID = entity.ID
alias.Name = lAlias.Name
alias.MountAccessor = lAlias.MountAccessor
alias.Metadata = lAlias.Metadata
alias.MountPath = mountValidationResp.MountPath
alias.MountType = mountValidationResp.MountType
alias.Local = lAlias.Local
alias.CustomMetadata = lAlias.CustomMetadata
if err := i.sanitizeAlias(ctx, alias); err != nil {
return nil, err
}
entity.UpsertAlias(alias)
localAliases, err := i.parseLocalAliases(entity.ID)
if err != nil {
return nil, err
}
if localAliases == nil {
localAliases = &identity.LocalAliases{}
}
updated := false
for i, item := range localAliases.Aliases {
if item.ID == alias.ID {
localAliases.Aliases[i] = alias
updated = true
break
}
}
if !updated {
localAliases.Aliases = append(localAliases.Aliases, alias)
}
marshaledAliases, err := ptypes.MarshalAny(localAliases)
if err != nil {
return nil, err
}
if err := i.localAliasPacker.PutItem(ctx, &storagepacker.Item{
ID: entity.ID,
Message: marshaledAliases,
}); err != nil {
return nil, err
}
if updateDb {
txn := i.db.Txn(true)
defer txn.Abort()
if err := i.MemDBUpsertAliasInTxn(txn, alias, false); err != nil {
return nil, err
}
if err := i.upsertEntityInTxn(ctx, txn, entity, nil, false); err != nil {
return nil, err
}
txn.Commit()
}
return alias, nil
}
// cacheTemporaryEntity stores in secondary's storage, the entity returned by
// the primary cluster via the CreateEntity RPC. This is so that the secondary
// cluster knows and retains information about the existence of these entities
// before the replication invalidation informs the secondary of the same. This
// also happens to cover the case where the secondary's replication is lagging
// behind the primary by hours and/or days which sometimes may happen. Even if
// the nodes of the secondary are restarted in the interim, the cluster would
// still be aware of the entities. This temporary cache will be cleared when the
// invalidation hits the secondary nodes.
func (i *IdentityStore) cacheTemporaryEntity(ctx context.Context, entity *identity.Entity) error {
if i.localNode.ReplicationState().HasState(consts.ReplicationPerformanceSecondary) && i.localNode.HAState() != consts.PerfStandby {
marshaledEntity, err := ptypes.MarshalAny(entity)
if err != nil {
return err
}
if err := i.localAliasPacker.PutItem(ctx, &storagepacker.Item{
ID: entity.ID + tmpSuffix,
Message: marshaledEntity,
}); err != nil {
return err
}
}
return nil
}
func (i *IdentityStore) persistEntity(ctx context.Context, entity *identity.Entity) error {
// If the entity that is passed into this function is resulting from a memdb
// query without cloning, then modifying it will result in a direct DB edit,
// bypassing the transaction. To avoid any surprises arising from this
// effect, work on a replica of the entity struct.
var err error
entity, err = entity.Clone()
if err != nil {
return err
}
// Separate the local and non-local aliases.
var localAliases []*identity.Alias
var nonLocalAliases []*identity.Alias
for _, alias := range entity.Aliases {
switch alias.Local {
case true:
localAliases = append(localAliases, alias)
default:
nonLocalAliases = append(nonLocalAliases, alias)
}
}
// Store the entity with non-local aliases.
entity.Aliases = nonLocalAliases
marshaledEntity, err := ptypes.MarshalAny(entity)
if err != nil {
return err
}
if err := i.entityPacker.PutItem(ctx, &storagepacker.Item{
ID: entity.ID,
Message: marshaledEntity,
}); err != nil {
return err
}
if len(localAliases) == 0 {
return nil
}
// Store the local aliases separately.
aliases := &identity.LocalAliases{
Aliases: localAliases,
}
marshaledAliases, err := ptypes.MarshalAny(aliases)
if err != nil {
return err
}
if err := i.localAliasPacker.PutItem(ctx, &storagepacker.Item{
ID: entity.ID,
Message: marshaledAliases,
}); err != nil {
return err
}
return nil
@ -875,6 +1170,31 @@ func (i *IdentityStore) MemDBEntityByNameInTxn(ctx context.Context, txn *memdb.T
return entity, nil
}
func (i *IdentityStore) MemDBLocalAliasesByBucketKeyInTxn(txn *memdb.Txn, bucketKey string) ([]*identity.Alias, error) {
if txn == nil {
return nil, fmt.Errorf("nil txn")
}
if bucketKey == "" {
return nil, fmt.Errorf("empty bucket key")
}
iter, err := txn.Get(entityAliasesTable, "local_bucket_key", bucketKey)
if err != nil {
return nil, fmt.Errorf("failed to lookup aliases using local bucket entry key hash: %w", err)
}
var aliases []*identity.Alias
for item := iter.Next(); item != nil; item = iter.Next() {
alias := item.(*identity.Alias)
if alias.Local {
aliases = append(aliases, alias)
}
}
return aliases, nil
}
func (i *IdentityStore) MemDBEntitiesByBucketKeyInTxn(txn *memdb.Txn, bucketKey string) ([]*identity.Entity, error) {
if txn == nil {
return nil, fmt.Errorf("nil txn")
@ -890,8 +1210,12 @@ func (i *IdentityStore) MemDBEntitiesByBucketKeyInTxn(txn *memdb.Txn, bucketKey
}
var entities []*identity.Entity
for entity := entitiesIter.Next(); entity != nil; entity = entitiesIter.Next() {
entities = append(entities, entity.(*identity.Entity))
for item := entitiesIter.Next(); item != nil; item = entitiesIter.Next() {
entity, err := item.(*identity.Entity).Clone()
if err != nil {
return nil, err
}
entities = append(entities, entity)
}
return entities, nil
@ -1029,6 +1353,8 @@ func (i *IdentityStore) sanitizeAlias(ctx context.Context, alias *identity.Alias
if err != nil {
return fmt.Errorf("failed to generate alias ID")
}
alias.LocalBucketKey = i.localAliasPacker.BucketKey(alias.CanonicalID)
}
if alias.NamespaceID == "" {
@ -2160,6 +2486,7 @@ func (i *IdentityStore) handleAliasListCommon(ctx context.Context, groupAlias bo
"canonical_id": alias.CanonicalID,
"mount_accessor": alias.MountAccessor,
"custom_metadata": alias.CustomMetadata,
"local": alias.Local,
}
mi, ok := mountAccessorMap[alias.MountAccessor]

View File

@ -1326,24 +1326,32 @@ func (c *Core) handleLoginRequest(ctx context.Context, req *logical.Request) (re
if auth.Alias != nil &&
mEntry != nil &&
!mEntry.Local &&
c.identityStore != nil {
// Overwrite the mount type and mount path in the alias
// information
auth.Alias.MountType = req.MountType
auth.Alias.MountAccessor = req.MountAccessor
auth.Alias.Local = mEntry.Local
if auth.Alias.Name == "" {
return nil, nil, fmt.Errorf("missing name in alias")
}
var err error
// Fetch the entity for the alias, or create an entity if one
// doesn't exist.
entity, err = c.identityStore.CreateOrFetchEntity(ctx, auth.Alias)
if err != nil {
entity, err = possiblyForwardAliasCreation(ctx, c, err, auth, entity)
switch auth.Alias.Local {
case true:
entity, err = possiblyForwardEntityCreation(ctx, c, err, auth, entity)
if err != nil && strings.Contains(err.Error(), errCreateEntityUnimplemented) {
resp.AddWarning("primary cluster doesn't yet issue entities for local auth mounts; falling back to not issuing entities for local auth mounts")
goto CREATE_TOKEN
}
default:
entity, err = possiblyForwardAliasCreation(ctx, c, err, auth, entity)
}
}
if err != nil {
return nil, nil, err
@ -1364,6 +1372,7 @@ func (c *Core) handleLoginRequest(ctx context.Context, req *logical.Request) (re
auth.GroupAliases = validAliases
}
CREATE_TOKEN:
// Determine the source of the login
source := c.router.MatchingMount(ctx, req.Path)
source = strings.TrimPrefix(source, credentialRoutePrefix)

View File

@ -53,3 +53,9 @@ func getAuthRegisterFunc(c *Core) (RegisterAuthFunc, error) {
func possiblyForwardAliasCreation(ctx context.Context, c *Core, inErr error, auth *logical.Auth, entity *identity.Entity) (*identity.Entity, error) {
return entity, inErr
}
var errCreateEntityUnimplemented = "create entity unimplemented in the server"
func possiblyForwardEntityCreation(ctx context.Context, c *Core, inErr error, auth *logical.Auth, entity *identity.Entity) (*identity.Entity, error) {
return entity, inErr
}