diff --git a/api/go/gosdn/conflict/conflict.pb.go b/api/go/gosdn/conflict/conflict.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..ee721fffb0cfbab32110663d3bd465173b731a89 --- /dev/null +++ b/api/go/gosdn/conflict/conflict.pb.go @@ -0,0 +1,150 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1 +// protoc (unknown) +// source: gosdn/conflict/conflict.proto + +package conflict + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + _ "google.golang.org/protobuf/types/descriptorpb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type Metadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ResourceVersion int64 `protobuf:"varint,1,opt,name=resourceVersion,proto3" json:"resourceVersion,omitempty"` +} + +func (x *Metadata) Reset() { + *x = Metadata{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_conflict_conflict_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Metadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Metadata) ProtoMessage() {} + +func (x *Metadata) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_conflict_conflict_proto_msgTypes[0] + 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 Metadata.ProtoReflect.Descriptor instead. +func (*Metadata) Descriptor() ([]byte, []int) { + return file_gosdn_conflict_conflict_proto_rawDescGZIP(), []int{0} +} + +func (x *Metadata) GetResourceVersion() int64 { + if x != nil { + return x.ResourceVersion + } + return 0 +} + +var File_gosdn_conflict_conflict_proto protoreflect.FileDescriptor + +var file_gosdn_conflict_conflict_proto_rawDesc = []byte{ + 0x0a, 0x1d, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, + 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x0e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x1a, + 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0x34, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x28, 0x0a, + 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x34, 0x5a, 0x32, 0x63, 0x6f, 0x64, 0x65, 0x2e, + 0x66, 0x62, 0x69, 0x2e, 0x68, 0x2d, 0x64, 0x61, 0x2e, 0x64, 0x65, 0x2f, 0x64, 0x61, 0x6e, 0x65, + 0x74, 0x2f, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x67, + 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_gosdn_conflict_conflict_proto_rawDescOnce sync.Once + file_gosdn_conflict_conflict_proto_rawDescData = file_gosdn_conflict_conflict_proto_rawDesc +) + +func file_gosdn_conflict_conflict_proto_rawDescGZIP() []byte { + file_gosdn_conflict_conflict_proto_rawDescOnce.Do(func() { + file_gosdn_conflict_conflict_proto_rawDescData = protoimpl.X.CompressGZIP(file_gosdn_conflict_conflict_proto_rawDescData) + }) + return file_gosdn_conflict_conflict_proto_rawDescData +} + +var file_gosdn_conflict_conflict_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_gosdn_conflict_conflict_proto_goTypes = []interface{}{ + (*Metadata)(nil), // 0: gosdn.conflict.Metadata +} +var file_gosdn_conflict_conflict_proto_depIdxs = []int32{ + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_gosdn_conflict_conflict_proto_init() } +func file_gosdn_conflict_conflict_proto_init() { + if File_gosdn_conflict_conflict_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_gosdn_conflict_conflict_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Metadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_gosdn_conflict_conflict_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_gosdn_conflict_conflict_proto_goTypes, + DependencyIndexes: file_gosdn_conflict_conflict_proto_depIdxs, + MessageInfos: file_gosdn_conflict_conflict_proto_msgTypes, + }.Build() + File_gosdn_conflict_conflict_proto = out.File + file_gosdn_conflict_conflict_proto_rawDesc = nil + file_gosdn_conflict_conflict_proto_goTypes = nil + file_gosdn_conflict_conflict_proto_depIdxs = nil +} diff --git a/api/go/gosdn/rbac/user.pb.go b/api/go/gosdn/rbac/user.pb.go index ef2f31b24e1600f2bb8f43c9ffd20442610dc423..320cbbedd1bd893d9103ce37aab12ba132de071d 100644 --- a/api/go/gosdn/rbac/user.pb.go +++ b/api/go/gosdn/rbac/user.pb.go @@ -7,6 +7,7 @@ package rbac import ( + conflict "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/conflict" _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -28,11 +29,12 @@ type User struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Roles map[string]string `protobuf:"bytes,3,rep,name=roles,proto3" json:"roles,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // Key = pnd uuid, value= role name - Password string `protobuf:"bytes,4,opt,name=password,proto3" json:"password,omitempty"` - Token string `protobuf:"bytes,5,opt,name=token,proto3" json:"token,omitempty"` + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Roles map[string]string `protobuf:"bytes,3,rep,name=roles,proto3" json:"roles,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // Key = pnd uuid, value= role name + Password string `protobuf:"bytes,4,opt,name=password,proto3" json:"password,omitempty"` + Token string `protobuf:"bytes,5,opt,name=token,proto3" json:"token,omitempty"` + Metadata *conflict.Metadata `protobuf:"bytes,6,opt,name=metadata,proto3" json:"metadata,omitempty"` } func (x *User) Reset() { @@ -102,6 +104,13 @@ func (x *User) GetToken() string { return "" } +func (x *User) GetMetadata() *conflict.Metadata { + if x != nil { + return x.Metadata + } + return nil +} + // CreateUsers type CreateUsersRequest struct { state protoimpl.MessageState @@ -686,114 +695,120 @@ var file_gosdn_rbac_user_proto_rawDesc = []byte{ 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x72, 0x62, 0x61, 0x63, 0x2f, - 0x72, 0x62, 0x61, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc9, 0x01, 0x0a, 0x04, 0x55, - 0x73, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x31, 0x0a, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, - 0x62, 0x61, 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x45, 0x6e, - 0x74, 0x72, 0x79, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, - 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, - 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x1a, 0x38, 0x0a, 0x0a, - 0x52, 0x6f, 0x6c, 0x65, 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, 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, 0x58, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x24, 0x0a, 0x04, 0x75, 0x73, - 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, - 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, - 0x22, 0x5f, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, - 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x22, 0x52, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x81, 0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, - 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, - 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, - 0x72, 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x24, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x55, - 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x2f, 0x0a, 0x0f, 0x47, 0x65, 0x74, - 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, + 0x72, 0x62, 0x61, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1d, 0x67, 0x6f, 0x73, 0x64, + 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x6c, + 0x69, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xff, 0x01, 0x0a, 0x04, 0x55, 0x73, + 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x31, 0x0a, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, + 0x61, 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, + 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, + 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x34, 0x0a, 0x08, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, + 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x63, 0x6f, 0x6e, 0x66, 0x6c, 0x69, 0x63, 0x74, 0x2e, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x1a, 0x38, 0x0a, 0x0a, 0x52, 0x6f, 0x6c, 0x65, 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, 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, 0x58, 0x0a, 0x12, 0x43, + 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x24, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, + 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, + 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x5f, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, + 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x82, 0x01, 0x0a, 0x10, 0x47, - 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, - 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x24, 0x0a, 0x04, 0x75, 0x73, 0x65, - 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, - 0x72, 0x62, 0x61, 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, - 0x58, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, + 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x52, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x81, 0x01, 0x0a, 0x0f, 0x47, + 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, + 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, + 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x24, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, + 0x62, 0x61, 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x2f, + 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, + 0x82, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x24, + 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x67, + 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, + 0x75, 0x73, 0x65, 0x72, 0x22, 0x58, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, + 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x24, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, + 0x62, 0x61, 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x5f, + 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, + 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, + 0x4e, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x12, 0x24, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x55, - 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x5f, 0x0a, 0x13, 0x55, 0x70, 0x64, + 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, + 0x5f, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, + 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x32, 0xf7, 0x03, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x12, 0x68, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, + 0x1e, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, - 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, - 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x4e, 0x0a, 0x12, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, - 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x5f, 0x0a, 0x13, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, - 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x32, 0xf7, 0x03, 0x0a, 0x0b, - 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x68, 0x0a, 0x0b, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x73, - 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, - 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x6f, 0x73, - 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, - 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x12, 0x3a, 0x01, 0x2a, 0x22, 0x0d, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x56, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, - 0x12, 0x1a, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x47, 0x65, - 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x67, - 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, - 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x0c, 0x12, 0x0a, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x67, 0x65, 0x74, 0x12, 0x55, 0x0a, - 0x08, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1b, 0x2e, 0x67, 0x6f, 0x73, 0x64, - 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, - 0x62, 0x61, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x08, 0x12, 0x06, 0x2f, 0x75, - 0x73, 0x65, 0x72, 0x73, 0x12, 0x68, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, - 0x65, 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, - 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, - 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x3a, 0x01, 0x2a, 0x22, - 0x0d, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x65, - 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1e, 0x2e, - 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, - 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x15, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x2a, 0x0d, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x64, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x30, 0x5a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x66, 0x62, - 0x69, 0x2e, 0x68, 0x2d, 0x64, 0x61, 0x2e, 0x64, 0x65, 0x2f, 0x64, 0x61, 0x6e, 0x65, 0x74, 0x2f, - 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x67, 0x6f, 0x73, - 0x64, 0x6e, 0x2f, 0x72, 0x62, 0x61, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x3a, 0x01, 0x2a, 0x22, 0x0d, 0x2f, 0x75, 0x73, + 0x65, 0x72, 0x73, 0x2f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x56, 0x0a, 0x07, 0x47, 0x65, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, + 0x61, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1b, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x47, + 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x67, + 0x65, 0x74, 0x12, 0x55, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1b, + 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x55, + 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, + 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0e, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x08, 0x12, 0x06, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x68, 0x0a, 0x0b, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, + 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, + 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x12, 0x3a, 0x01, 0x2a, 0x22, 0x0d, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x75, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x12, 0x65, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, + 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x2a, 0x0d, 0x2f, 0x75, 0x73, + 0x65, 0x72, 0x73, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x30, 0x5a, 0x2e, 0x63, 0x6f, + 0x64, 0x65, 0x2e, 0x66, 0x62, 0x69, 0x2e, 0x68, 0x2d, 0x64, 0x61, 0x2e, 0x64, 0x65, 0x2f, 0x64, + 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, + 0x6f, 0x2f, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x72, 0x62, 0x61, 0x63, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -822,34 +837,36 @@ var file_gosdn_rbac_user_proto_goTypes = []interface{}{ (*DeleteUsersRequest)(nil), // 9: gosdn.rbac.DeleteUsersRequest (*DeleteUsersResponse)(nil), // 10: gosdn.rbac.DeleteUsersResponse nil, // 11: gosdn.rbac.User.RolesEntry - (Status)(0), // 12: gosdn.rbac.Status + (*conflict.Metadata)(nil), // 12: gosdn.conflict.Metadata + (Status)(0), // 13: gosdn.rbac.Status } var file_gosdn_rbac_user_proto_depIdxs = []int32{ 11, // 0: gosdn.rbac.User.roles:type_name -> gosdn.rbac.User.RolesEntry - 0, // 1: gosdn.rbac.CreateUsersRequest.user:type_name -> gosdn.rbac.User - 12, // 2: gosdn.rbac.CreateUsersResponse.status:type_name -> gosdn.rbac.Status - 12, // 3: gosdn.rbac.GetUserResponse.status:type_name -> gosdn.rbac.Status - 0, // 4: gosdn.rbac.GetUserResponse.user:type_name -> gosdn.rbac.User - 12, // 5: gosdn.rbac.GetUsersResponse.status:type_name -> gosdn.rbac.Status - 0, // 6: gosdn.rbac.GetUsersResponse.user:type_name -> gosdn.rbac.User - 0, // 7: gosdn.rbac.UpdateUsersRequest.user:type_name -> gosdn.rbac.User - 12, // 8: gosdn.rbac.UpdateUsersResponse.status:type_name -> gosdn.rbac.Status - 12, // 9: gosdn.rbac.DeleteUsersResponse.status:type_name -> gosdn.rbac.Status - 1, // 10: gosdn.rbac.UserService.CreateUsers:input_type -> gosdn.rbac.CreateUsersRequest - 3, // 11: gosdn.rbac.UserService.GetUser:input_type -> gosdn.rbac.GetUserRequest - 5, // 12: gosdn.rbac.UserService.GetUsers:input_type -> gosdn.rbac.GetUsersRequest - 7, // 13: gosdn.rbac.UserService.UpdateUsers:input_type -> gosdn.rbac.UpdateUsersRequest - 9, // 14: gosdn.rbac.UserService.DeleteUsers:input_type -> gosdn.rbac.DeleteUsersRequest - 2, // 15: gosdn.rbac.UserService.CreateUsers:output_type -> gosdn.rbac.CreateUsersResponse - 4, // 16: gosdn.rbac.UserService.GetUser:output_type -> gosdn.rbac.GetUserResponse - 6, // 17: gosdn.rbac.UserService.GetUsers:output_type -> gosdn.rbac.GetUsersResponse - 8, // 18: gosdn.rbac.UserService.UpdateUsers:output_type -> gosdn.rbac.UpdateUsersResponse - 10, // 19: gosdn.rbac.UserService.DeleteUsers:output_type -> gosdn.rbac.DeleteUsersResponse - 15, // [15:20] is the sub-list for method output_type - 10, // [10:15] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name + 12, // 1: gosdn.rbac.User.metadata:type_name -> gosdn.conflict.Metadata + 0, // 2: gosdn.rbac.CreateUsersRequest.user:type_name -> gosdn.rbac.User + 13, // 3: gosdn.rbac.CreateUsersResponse.status:type_name -> gosdn.rbac.Status + 13, // 4: gosdn.rbac.GetUserResponse.status:type_name -> gosdn.rbac.Status + 0, // 5: gosdn.rbac.GetUserResponse.user:type_name -> gosdn.rbac.User + 13, // 6: gosdn.rbac.GetUsersResponse.status:type_name -> gosdn.rbac.Status + 0, // 7: gosdn.rbac.GetUsersResponse.user:type_name -> gosdn.rbac.User + 0, // 8: gosdn.rbac.UpdateUsersRequest.user:type_name -> gosdn.rbac.User + 13, // 9: gosdn.rbac.UpdateUsersResponse.status:type_name -> gosdn.rbac.Status + 13, // 10: gosdn.rbac.DeleteUsersResponse.status:type_name -> gosdn.rbac.Status + 1, // 11: gosdn.rbac.UserService.CreateUsers:input_type -> gosdn.rbac.CreateUsersRequest + 3, // 12: gosdn.rbac.UserService.GetUser:input_type -> gosdn.rbac.GetUserRequest + 5, // 13: gosdn.rbac.UserService.GetUsers:input_type -> gosdn.rbac.GetUsersRequest + 7, // 14: gosdn.rbac.UserService.UpdateUsers:input_type -> gosdn.rbac.UpdateUsersRequest + 9, // 15: gosdn.rbac.UserService.DeleteUsers:input_type -> gosdn.rbac.DeleteUsersRequest + 2, // 16: gosdn.rbac.UserService.CreateUsers:output_type -> gosdn.rbac.CreateUsersResponse + 4, // 17: gosdn.rbac.UserService.GetUser:output_type -> gosdn.rbac.GetUserResponse + 6, // 18: gosdn.rbac.UserService.GetUsers:output_type -> gosdn.rbac.GetUsersResponse + 8, // 19: gosdn.rbac.UserService.UpdateUsers:output_type -> gosdn.rbac.UpdateUsersResponse + 10, // 20: gosdn.rbac.UserService.DeleteUsers:output_type -> gosdn.rbac.DeleteUsersResponse + 16, // [16:21] is the sub-list for method output_type + 11, // [11:16] is the sub-list for method input_type + 11, // [11:11] is the sub-list for extension type_name + 11, // [11:11] is the sub-list for extension extendee + 0, // [0:11] is the sub-list for field type_name } func init() { file_gosdn_rbac_user_proto_init() } diff --git a/api/go/gosdn/topology/node.pb.go b/api/go/gosdn/topology/node.pb.go index 0c9330271dd3e7d66d7f8454d254091c32961090..b24ecce2e4d1e47314008fb302435a5d48af6533 100644 --- a/api/go/gosdn/topology/node.pb.go +++ b/api/go/gosdn/topology/node.pb.go @@ -23,6 +23,53 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +type Metadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ResourceVersion int64 `protobuf:"varint,1,opt,name=resourceVersion,proto3" json:"resourceVersion,omitempty"` +} + +func (x *Metadata) Reset() { + *x = Metadata{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_topology_node_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Metadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Metadata) ProtoMessage() {} + +func (x *Metadata) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_topology_node_proto_msgTypes[0] + 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 Metadata.ProtoReflect.Descriptor instead. +func (*Metadata) Descriptor() ([]byte, []int) { + return file_gosdn_topology_node_proto_rawDescGZIP(), []int{0} +} + +func (x *Metadata) GetResourceVersion() int64 { + if x != nil { + return x.ResourceVersion + } + return 0 +} + type Node struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -35,7 +82,7 @@ type Node struct { func (x *Node) Reset() { *x = Node{} if protoimpl.UnsafeEnabled { - mi := &file_gosdn_topology_node_proto_msgTypes[0] + mi := &file_gosdn_topology_node_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -48,7 +95,7 @@ func (x *Node) String() string { func (*Node) ProtoMessage() {} func (x *Node) ProtoReflect() protoreflect.Message { - mi := &file_gosdn_topology_node_proto_msgTypes[0] + mi := &file_gosdn_topology_node_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -61,7 +108,7 @@ func (x *Node) ProtoReflect() protoreflect.Message { // Deprecated: Use Node.ProtoReflect.Descriptor instead. func (*Node) Descriptor() ([]byte, []int) { - return file_gosdn_topology_node_proto_rawDescGZIP(), []int{0} + return file_gosdn_topology_node_proto_rawDescGZIP(), []int{1} } func (x *Node) GetId() string { @@ -90,14 +137,17 @@ var file_gosdn_topology_node_proto_rawDesc = []byte{ 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x2a, 0x0a, 0x04, 0x4e, - 0x6f, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x34, 0x5a, 0x32, 0x63, 0x6f, 0x64, 0x65, 0x2e, - 0x66, 0x62, 0x69, 0x2e, 0x68, 0x2d, 0x64, 0x61, 0x2e, 0x64, 0x65, 0x2f, 0x64, 0x61, 0x6e, 0x65, - 0x74, 0x2f, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x67, - 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x74, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x34, 0x0a, 0x08, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x28, 0x0a, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x22, 0x2a, 0x0a, 0x04, 0x4e, 0x6f, 0x64, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x34, 0x5a, + 0x32, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x66, 0x62, 0x69, 0x2e, 0x68, 0x2d, 0x64, 0x61, 0x2e, 0x64, + 0x65, 0x2f, 0x64, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x61, 0x70, + 0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x74, 0x6f, 0x70, 0x6f, 0x6c, + 0x6f, 0x67, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -112,9 +162,10 @@ func file_gosdn_topology_node_proto_rawDescGZIP() []byte { return file_gosdn_topology_node_proto_rawDescData } -var file_gosdn_topology_node_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_gosdn_topology_node_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_gosdn_topology_node_proto_goTypes = []interface{}{ - (*Node)(nil), // 0: gosdn.topology.Node + (*Metadata)(nil), // 0: gosdn.topology.Metadata + (*Node)(nil), // 1: gosdn.topology.Node } var file_gosdn_topology_node_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type @@ -131,6 +182,18 @@ func file_gosdn_topology_node_proto_init() { } if !protoimpl.UnsafeEnabled { file_gosdn_topology_node_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Metadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_topology_node_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Node); i { case 0: return &v.state @@ -149,7 +212,7 @@ func file_gosdn_topology_node_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_gosdn_topology_node_proto_rawDesc, NumEnums: 0, - NumMessages: 1, + NumMessages: 2, NumExtensions: 0, NumServices: 0, }, diff --git a/api/openapiv2/gosdn_northbound.swagger.json b/api/openapiv2/gosdn_northbound.swagger.json index 1e83ff86a42e2c5caa0874196388e5bccc5a3fc2..7732e02a12841b8fe2961ac65d566017e288ab05 100644 --- a/api/openapiv2/gosdn_northbound.swagger.json +++ b/api/openapiv2/gosdn_northbound.swagger.json @@ -2921,6 +2921,15 @@ ], "default": "STATUS_UNSPECIFIED" }, + "gosdnconflictMetadata": { + "type": "object", + "properties": { + "resourceVersion": { + "type": "string", + "format": "int64" + } + } + }, "gosdncoreStatus": { "type": "string", "enum": [ @@ -3937,6 +3946,9 @@ }, "token": { "type": "string" + }, + "metadata": { + "$ref": "#/definitions/gosdnconflictMetadata" } } }, diff --git a/api/proto/gosdn/conflict/conflict.proto b/api/proto/gosdn/conflict/conflict.proto new file mode 100644 index 0000000000000000000000000000000000000000..d95c41e1705b775e2ef88c04241e0633b3cb8e15 --- /dev/null +++ b/api/proto/gosdn/conflict/conflict.proto @@ -0,0 +1,11 @@ +syntax = "proto3"; + +package gosdn.conflict; + +import "google/protobuf/descriptor.proto"; + +option go_package = "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/conflict"; + +message Metadata { + int64 resourceVersion = 1; +} diff --git a/api/proto/gosdn/rbac/user.proto b/api/proto/gosdn/rbac/user.proto index 8de04465cc4add2b4223930157118d5e6858cab1..71d578117095d3b51f32d511920b0b7925ccc8bd 100644 --- a/api/proto/gosdn/rbac/user.proto +++ b/api/proto/gosdn/rbac/user.proto @@ -7,6 +7,7 @@ import "google/protobuf/descriptor.proto"; import "protoc-gen-openapiv2/options/annotations.proto"; import "gosdn/rbac/rbac.proto"; +import "gosdn/conflict/conflict.proto"; option go_package = "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac"; @@ -61,6 +62,7 @@ message User { map<string, string> roles = 3; // Key = pnd uuid, value= role name string password = 4; string token = 5; + conflict.Metadata metadata = 6; } // CreateUsers diff --git a/api/proto/gosdn/topology/node.proto b/api/proto/gosdn/topology/node.proto index ca06fab019f59cd8584b2dbe4f6b4d40b34dd267..e6ac7e2702f2863a9a0ca18e0ce26734a0a5d00a 100644 --- a/api/proto/gosdn/topology/node.proto +++ b/api/proto/gosdn/topology/node.proto @@ -9,6 +9,10 @@ import "protoc-gen-openapiv2/options/annotations.proto"; option go_package = "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/topology"; +message Metadata { + int64 resourceVersion = 1; +} + message Node { string id = 1; string name = 2; diff --git a/cli/cmd/userUpdate.go b/cli/cmd/userUpdate.go index dc1d5d48a86bfde6e341270846c049705216f5f1..7ff50486c9fb9fa8e9ea41138c9d6cbd8dad3211 100644 --- a/cli/cmd/userUpdate.go +++ b/cli/cmd/userUpdate.go @@ -34,6 +34,7 @@ package cmd import ( apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac" "code.fbi.h-da.de/danet/gosdn/controller/api" + "github.com/google/uuid" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -48,6 +49,15 @@ var userUpdateCmd = &cobra.Command{ role is optional but needed to operate on PNDs.`, RunE: func(cmd *cobra.Command, args []string) error { + exisitingUser, err := api.GetUser( + createContextWithAuthorization(), + viper.GetString("controllerAPIEndpoint"), + nbUserName, + uuid.Nil, + ) + if err != nil { + return err + } roles := map[string]string{} // only active pnd for now, add option for additional param later @@ -57,6 +67,7 @@ var userUpdateCmd = &cobra.Command{ users := []*apb.User{ { Id: nbUserID, + Metadata: exisitingUser.User.Metadata, Name: nbUserName, Password: nbUserPwd, Roles: roles, diff --git a/controller/api/apiUtil_test.go b/controller/api/apiUtil_test.go index cc01aebb9dae75ae39d959bf59deaf155bc8db1e..78ae66d8bfbcc64121370f53f05840feaf702f6f 100644 --- a/controller/api/apiUtil_test.go +++ b/controller/api/apiUtil_test.go @@ -4,6 +4,7 @@ import ( "encoding/base64" "time" + "code.fbi.h-da.de/danet/gosdn/controller/conflict" "code.fbi.h-da.de/danet/gosdn/controller/rbac" rbacImpl "code.fbi.h-da.de/danet/gosdn/controller/rbac" "code.fbi.h-da.de/danet/gosdn/controller/store" @@ -82,7 +83,7 @@ func createTestUsers() error { } for _, u := range users { - err := userService.Add(rbacImpl.NewUser(u.ID(), u.Name(), u.Roles, u.Password, "", salt)) + err := userService.Add(rbacImpl.NewUser(u.ID(), u.Name(), u.Roles, u.Password, "", salt, conflict.Metadata{ResourceVersion: 0})) if err != nil { return err } diff --git a/controller/api/user_test.go b/controller/api/user_test.go index afa2f6dc6aa0f3bc9edbde0030dab5f20d74b31d..b08407e6745d939714700f9a69e5eef50da0caa2 100644 --- a/controller/api/user_test.go +++ b/controller/api/user_test.go @@ -5,6 +5,7 @@ import ( "reflect" "testing" + "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/conflict" apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac" "github.com/google/uuid" "google.golang.org/grpc/metadata" @@ -38,6 +39,9 @@ func TestCreateUsers(t *testing.T) { Roles: map[string]string{pndID: "s"}, Password: "roh", Token: "da", + Metadata: &conflict.Metadata{ + ResourceVersion: 1, + }, }, }, }, @@ -208,8 +212,9 @@ func TestUpdateUsers(t *testing.T) { addr: testAPIEndpoint, users: []*apb.User{ { - Id: adminID, - Name: "sth Else", + Id: adminID, + Name: "sth Else", + Metadata: &conflict.Metadata{}, }, }, }, diff --git a/controller/conflict/versioning.go b/controller/conflict/versioning.go new file mode 100644 index 0000000000000000000000000000000000000000..1d65c29dfba6d8b19408ad9b4cefeda4f3e38df4 --- /dev/null +++ b/controller/conflict/versioning.go @@ -0,0 +1,10 @@ +package conflict + +import "time" + +// Metadata are additional information that every entity persisted in a store must provide. +type Metadata struct { + ResourceVersion int `json:"resource_version,omitempty" bson:"resource_version,omitempty"` + LastUpdated time.Time `json:"last_updated,omitempty" bson:"last_updated,omitempty"` + CreatedAt time.Time `json:"created_at,omitempty" bson:"created_at,omitempty"` +} diff --git a/controller/controller.go b/controller/controller.go index 6ea0fb68c34168df90896266c35353811ef7196a..fbc888b9c1e19804fa7edcaa55127bfcb4527f06 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -32,6 +32,7 @@ import ( apps "code.fbi.h-da.de/danet/gosdn/controller/app" "code.fbi.h-da.de/danet/gosdn/controller/config" + "code.fbi.h-da.de/danet/gosdn/controller/conflict" eventservice "code.fbi.h-da.de/danet/gosdn/controller/eventService" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkdomain" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkelement" @@ -304,7 +305,7 @@ func ensureDefaultUserExists() error { hashedPassword := base64.RawStdEncoding.EncodeToString(argon2.IDKey([]byte(generatedPassword), []byte(salt), 1, 64*1024, 4, 32)) - err = c.userService.Add(rbacImpl.NewUser(uuid.New(), defaultUserName, map[string]string{config.BasePndUUID.String(): "admin"}, string(hashedPassword), "", salt)) + err = c.userService.Add(rbacImpl.NewUser(uuid.New(), defaultUserName, map[string]string{config.BasePndUUID.String(): "admin"}, string(hashedPassword), "", salt, conflict.Metadata{})) if err != nil { return err } diff --git a/controller/interfaces/rbac/rbacService.go b/controller/interfaces/rbac/rbacService.go index eddfbfce11efd9775a5ca018831997e65ae9d6d9..8aadf7f09d6ac1a79761d1caa97f37400abfdccb 100644 --- a/controller/interfaces/rbac/rbacService.go +++ b/controller/interfaces/rbac/rbacService.go @@ -1,6 +1,7 @@ package rbac import ( + "code.fbi.h-da.de/danet/gosdn/controller/conflict" "code.fbi.h-da.de/danet/gosdn/controller/store" ) @@ -21,6 +22,7 @@ type LoadedUser struct { Password string `json:"password"` Token string `json:"token,omitempty"` Salt string `json:"salt" bson:"salt"` + Metadata conflict.Metadata `json:"metadata" bson:"metadata"` } // RoleService describes an interface for role service implementations. diff --git a/controller/interfaces/rbac/user.go b/controller/interfaces/rbac/user.go index 0cec5417b5bb991ce448c53bee34461742043d30..51051b4dda64cc0d8d1d4dd94304d67945112827 100644 --- a/controller/interfaces/rbac/user.go +++ b/controller/interfaces/rbac/user.go @@ -1,6 +1,10 @@ package rbac -import "github.com/google/uuid" +import ( + "github.com/google/uuid" + + "code.fbi.h-da.de/danet/gosdn/controller/conflict" +) // User represents an User which is managed by rbac. type User interface { @@ -11,4 +15,5 @@ type User interface { GetToken() string SetToken(string) GetSalt() string + GetMetadata() conflict.Metadata } diff --git a/controller/northbound/server/test_util_test.go b/controller/northbound/server/test_util_test.go index 4a4202e0470fea150b8ad3aa74f3cb28f022c2ea..e32c7d8011801a4bfdccc6200663e5df2a487572 100644 --- a/controller/northbound/server/test_util_test.go +++ b/controller/northbound/server/test_util_test.go @@ -7,6 +7,7 @@ import ( "testing" spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound" + "code.fbi.h-da.de/danet/gosdn/controller/conflict" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkdomain" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkelement" rbacInterfaces "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac" @@ -110,7 +111,7 @@ func createTestUsers(userService rbacInterfaces.UserService) error { } for _, u := range users { - err := userService.Add(rbac.NewUser(u.ID(), u.Name(), u.Roles, u.Password, "", salt)) + err := userService.Add(rbac.NewUser(u.ID(), u.Name(), u.Roles, u.Password, "", salt, conflict.Metadata{ResourceVersion: 0})) if err != nil { return err } diff --git a/controller/northbound/server/user.go b/controller/northbound/server/user.go index 3288087fd768ece35405e6f63a82096de102e1a8..239823c2568c971e929b167f7aba0671e0bf9055 100644 --- a/controller/northbound/server/user.go +++ b/controller/northbound/server/user.go @@ -6,7 +6,9 @@ import ( "fmt" "time" + cpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/conflict" apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac" + "code.fbi.h-da.de/danet/gosdn/controller/conflict" "code.fbi.h-da.de/danet/gosdn/controller/metrics" "code.fbi.h-da.de/danet/gosdn/controller/rbac" "code.fbi.h-da.de/danet/gosdn/controller/store" @@ -63,7 +65,9 @@ func (u UserServer) CreateUsers(ctx context.Context, request *apb.CreateUsersReq hashedPassword := base64.RawStdEncoding.EncodeToString(argon2.IDKey([]byte(user.Password), []byte(salt), 1, 64*1024, 4, 32)) - user := rbac.NewUser(uuid.New(), user.Name, roles, string(hashedPassword), user.Token, salt) + user := rbac.NewUser(uuid.New(), user.Name, roles, string(hashedPassword), user.Token, salt, conflict.Metadata{ + ResourceVersion: int(user.Metadata.ResourceVersion), + }) err = u.userService.Add(user) if err != nil { log.Error(err) @@ -97,6 +101,9 @@ func (u UserServer) GetUser(ctx context.Context, request *apb.GetUserRequest) (* Id: userData.ID().String(), Name: userData.Name(), Roles: userData.GetRoles(), + Metadata: &cpb.Metadata{ + ResourceVersion: int64(userData.GetMetadata().ResourceVersion), + }, } return &apb.GetUserResponse{ @@ -123,6 +130,9 @@ func (u UserServer) GetUsers(ctx context.Context, request *apb.GetUsersRequest) Id: u.ID().String(), Name: u.Name(), Roles: u.GetRoles(), + Metadata: &cpb.Metadata{ + ResourceVersion: int64(u.GetMetadata().ResourceVersion), + }, }) } @@ -152,9 +162,13 @@ func (u UserServer) UpdateUsers(ctx context.Context, request *apb.UpdateUsersReq hashedPassword := base64.RawStdEncoding.EncodeToString(argon2.IDKey([]byte(user.Password), []byte(storedUser.GetSalt()), 1, 64*1024, 4, 32)) - userToUpdate := rbac.NewUser(uid, user.Name, user.Roles, string(hashedPassword), user.Token, storedUser.GetSalt()) + userToUpdate := rbac.NewUser(uid, user.Name, user.Roles, string(hashedPassword), user.Token, storedUser.GetSalt(), conflict.Metadata{ + ResourceVersion: int(user.Metadata.ResourceVersion)}) + + usr, _ := userToUpdate.(*rbac.User) + usr.Metadata.ResourceVersion = int(user.Metadata.ResourceVersion) - err = u.userService.Update(userToUpdate) + err = u.userService.Update(usr) if err != nil { return nil, status.Errorf(codes.Aborted, "could not update user %v", err) } diff --git a/controller/northbound/server/user_test.go b/controller/northbound/server/user_test.go index 1e447266e3c8503ceccaa6afd87794eddf40cfcc..41ffef625d1b955148353dc85da944c113461264 100644 --- a/controller/northbound/server/user_test.go +++ b/controller/northbound/server/user_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/conflict" apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac" eventservice "code.fbi.h-da.de/danet/gosdn/controller/eventService" "code.fbi.h-da.de/danet/gosdn/controller/rbac" @@ -53,6 +54,9 @@ func TestUser_CreateUsers(t *testing.T) { Roles: map[string]string{pndID: "userTestRole"}, Password: "pass", Token: "", + Metadata: &conflict.Metadata{ + ResourceVersion: 0, + }, }, }, }, @@ -214,8 +218,11 @@ func TestUser_UpdateUsers(t *testing.T) { name: "default update user", args: args{ctx: context.TODO(), request: &apb.UpdateUsersRequest{User: []*apb.User{ - {Id: adminID, - Name: "sth Else"}, + { + Id: adminID, + Name: "sth Else", + Metadata: &conflict.Metadata{}, + }, }, }, }, @@ -227,8 +234,11 @@ func TestUser_UpdateUsers(t *testing.T) { name: "error update user", args: args{ctx: context.TODO(), request: &apb.UpdateUsersRequest{User: []*apb.User{ - {Id: uuid.NewString(), - Name: "not a user"}, + { + Id: uuid.NewString(), + Name: "not a user", + Metadata: &conflict.Metadata{}, + }, }, }, }, diff --git a/controller/rbac/databaseUserStore.go b/controller/rbac/databaseUserStore.go index c478610e680913bc979a77fd03b93efbfd8d6625..fe39f26c2b12a2cbb4981ce3b2d89b970db0bac8 100644 --- a/controller/rbac/databaseUserStore.go +++ b/controller/rbac/databaseUserStore.go @@ -13,6 +13,7 @@ import ( "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/mongo/writeconcern" ) // DatabaseUserStore is used to store users in database. @@ -187,24 +188,69 @@ func (s *DatabaseUserStore) Update(userToUpdate rbac.User) (err error) { } }() - update := bson.D{primitive.E{Key: "$set", Value: userToUpdate}} + // 1. Start Transaction + wcMajority := writeconcern.New(writeconcern.WMajority()) + wcMajorityCollectionOpts := options.Collection().SetWriteConcern(wcMajority) + userCollection := client.Database(database.DatabaseName).Collection(s.userStoreName, wcMajorityCollectionOpts) - upsert := false - after := options.After - opt := options.FindOneAndUpdateOptions{ - Upsert: &upsert, - ReturnDocument: &after, + session, err := client.StartSession() + if err != nil { + return err } + defer session.EndSession(ctx) - err = client.Database(database.DatabaseName). - Collection(s.userStoreName). - FindOneAndUpdate( - ctx, bson.M{"_id": userToUpdate.ID().String()}, update, &opt). - Decode(&updatedLoadedUser) + // 2. Fetch exisiting Entity + existingNode, err := s.getByID(userToUpdate.ID()) if err != nil { - log.Printf("Could not update User: %v", err) + return err + } + + // 3. Check if Entity.Metadata.ResourceVersion == UpdatedEntity.Metadata.ResourceVersion + if userToUpdate.GetMetadata().ResourceVersion != existingNode.Metadata.ResourceVersion { + // 3.1.1 End transaction + // 3.1.2 If no -> return error + + return fmt.Errorf( + "resource version %d of provided user %s is older or newer than %d in the store", + userToUpdate.GetMetadata().ResourceVersion, + userToUpdate.ID().String(), existingNode.Metadata.ResourceVersion, + ) + } + + // 3.2.1 If yes -> Update entity in callback + callback := func(sessCtx mongo.SessionContext) (interface{}, error) { + // Important: You must pass sessCtx as the Context parameter to the operations for them to be executed in the + // transaction. + + u, _ := userToUpdate.(*User) + u.Metadata.ResourceVersion = u.Metadata.ResourceVersion + 1 + + update := bson.D{primitive.E{Key: "$set", Value: u}} - return customerrs.CouldNotUpdateError{Identifier: userToUpdate.ID(), Type: userToUpdate, Err: err} + upsert := false + after := options.After + opt := options.FindOneAndUpdateOptions{ + Upsert: &upsert, + ReturnDocument: &after, + } + + err = userCollection. + FindOneAndUpdate( + ctx, bson.M{"_id": userToUpdate.ID().String()}, update, &opt). + Decode(&updatedLoadedUser) + if err != nil { + log.Printf("Could not update User: %v", err) + + return nil, customerrs.CouldNotUpdateError{Identifier: userToUpdate.ID(), Type: userToUpdate, Err: err} + } + + // 3.2.2 End transaction + return "", nil + } + + _, err = session.WithTransaction(ctx, callback) + if err != nil { + return err } return nil diff --git a/controller/rbac/rbacService.go b/controller/rbac/rbacService.go index 414ad1884b8fcfe43e6f5c16c6c6ddc3ff26d9da..0a1d26a478b030824173a2e1d70589c6248ee308 100644 --- a/controller/rbac/rbacService.go +++ b/controller/rbac/rbacService.go @@ -126,7 +126,7 @@ func (s *UserService) GetAll() ([]rbac.User, error) { } func (s *UserService) createUserFromStore(loadedUser rbac.LoadedUser) rbac.User { - return NewUser(uuid.MustParse(loadedUser.ID), loadedUser.UserName, loadedUser.Roles, loadedUser.Password, loadedUser.Token, loadedUser.Salt) + return NewUser(uuid.MustParse(loadedUser.ID), loadedUser.UserName, loadedUser.Roles, loadedUser.Password, loadedUser.Token, loadedUser.Salt, loadedUser.Metadata) } // RoleService provides a role service implementation. diff --git a/controller/rbac/user.go b/controller/rbac/user.go index 19d9dc4f6e3e7ba79fbd19821248e0ac3528d3df..d0b5ae14fa35d299db531500a0b0d286d127fc89 100644 --- a/controller/rbac/user.go +++ b/controller/rbac/user.go @@ -3,6 +3,7 @@ package rbac import ( "encoding/json" + "code.fbi.h-da.de/danet/gosdn/controller/conflict" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac" "github.com/google/uuid" "go.mongodb.org/mongo-driver/bson" @@ -11,6 +12,7 @@ import ( // User represents the data of a user for access control and is stored in a storage. type User struct { UserID uuid.UUID `json:"_id"` + Metadata conflict.Metadata `json:"metadata"` UserName string `json:"username"` Roles map[string]string `json:"roles,omitempty"` Password string `json:"password"` @@ -24,7 +26,9 @@ func NewUser(id uuid.UUID, roles map[string]string, pw string, token string, - salt string) rbac.User { + salt string, + metadata conflict.Metadata, +) rbac.User { return &User{ UserID: id, UserName: name, @@ -32,6 +36,7 @@ func NewUser(id uuid.UUID, Password: pw, Token: token, Salt: salt, + Metadata: metadata, } } @@ -40,6 +45,11 @@ func (u *User) ID() uuid.UUID { return u.UserID } +// GetMetadata returns the metadata of a user. +func (u *User) GetMetadata() conflict.Metadata { + return u.Metadata +} + // Name returns the name of the user. func (u *User) Name() string { return u.UserName @@ -84,6 +94,7 @@ func (u *User) MarshalJSON() ([]byte, error) { Password string `json:"password"` Token string `json:"token,omitempty"` Salt string `json:"salt"` + Metadata conflict.Metadata `json:"metadata"` }{ UserID: u.ID(), UserName: u.Name(), @@ -91,6 +102,7 @@ func (u *User) MarshalJSON() ([]byte, error) { Password: u.Password, Token: u.Token, Salt: u.Salt, + Metadata: u.Metadata, }) } @@ -103,6 +115,7 @@ func (u *User) MarshalBSON() ([]byte, error) { Password string `bson:"password"` Token string `bson:"token,omitempty"` Salt string `bson:"salt"` + Metadata conflict.Metadata `bson:"metadata"` }{ UserID: u.ID().String(), UserName: u.Name(), @@ -110,5 +123,6 @@ func (u *User) MarshalBSON() ([]byte, error) { Password: u.Password, Token: u.Token, Salt: u.Salt, + Metadata: u.Metadata, }) } diff --git a/controller/rbac/userFileSystemStore_test.go b/controller/rbac/userFileSystemStore_test.go index 29f76a6c3d019fb1940765677a91538f916e0830..847d2be830b558624871a00c75c5496fe9eab324 100644 --- a/controller/rbac/userFileSystemStore_test.go +++ b/controller/rbac/userFileSystemStore_test.go @@ -4,6 +4,7 @@ import ( "reflect" "testing" + "code.fbi.h-da.de/danet/gosdn/controller/conflict" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac" "code.fbi.h-da.de/danet/gosdn/controller/store" "github.com/google/uuid" @@ -17,7 +18,7 @@ func TestFileSystemUserStore_Add(t *testing.T) { } var idtest uuid.UUID var role map[string]string - testingUser := NewUser(idtest, "testUser", role, "xyz", "svsvsfbdwbwbev", "svswvasfbw") + testingUser := NewUser(idtest, "testUser", role, "xyz", "svsvsfbdwbwbev", "svswvasfbw", conflict.Metadata{}) tests := []struct { name string args args @@ -48,7 +49,7 @@ func TestFileSystemUserStore_Delete(t *testing.T) { } var idtest uuid.UUID var role map[string]string - testingUser := NewUser(idtest, "", role, "xyz", "svsvsfbdwbwbev", "svswvasfbw") + testingUser := NewUser(idtest, "", role, "xyz", "svsvsfbdwbwbev", "svswvasfbw", conflict.Metadata{}) tests := []struct { name string args args @@ -81,7 +82,7 @@ func TestFileSystemUserStore_Get(t *testing.T) { } var idtest uuid.UUID var role map[string]string - testingUser := NewUser(idtest, "", role, "xyz", "svsvsfbdwbwbev", "svswvasfbw") + testingUser := NewUser(idtest, "", role, "xyz", "svsvsfbdwbwbev", "svswvasfbw", conflict.Metadata{}) tests := []struct { name string args args @@ -120,9 +121,9 @@ func TestFileSystemUserStore_GetAll(t *testing.T) { var idtest uuid.UUID var role map[string]string - testingUser1 := NewUser(idtest, "", role, "xyz", "svsvsfbdwbwbevasf", "svswvasfbwasv") - testingUser2 := NewUser(idtest, "", role, "abc", "svsvsfbdwbwbevsav", "svswvasfbwadf") - testingUser3 := NewUser(idtest, "", role, "lmn", "svsvsfbdwbwbevscv", "svswvasfbwasd") + testingUser1 := NewUser(idtest, "", role, "xyz", "svsvsfbdwbwbevasf", "svswvasfbwasv", conflict.Metadata{}) + testingUser2 := NewUser(idtest, "", role, "abc", "svsvsfbdwbwbevsav", "svswvasfbwadf", conflict.Metadata{}) + testingUser3 := NewUser(idtest, "", role, "lmn", "svsvsfbdwbwbevscv", "svswvasfbwasd", conflict.Metadata{}) tests := []struct { name string want []rbac.LoadedUser @@ -172,7 +173,7 @@ func TestFileSystemUserStore_Update(t *testing.T) { } var idtest uuid.UUID var role map[string]string - testingUser := NewUser(idtest, "", role, "xyz", "svsvsfbdwbwbev", "svswvasfbw") + testingUser := NewUser(idtest, "", role, "xyz", "svsvsfbdwbwbev", "svswvasfbw", conflict.Metadata{}) tests := []struct { name string args args diff --git a/controller/topology/links/link.go b/controller/topology/links/link.go index be6a79d06441cd71129f75ba24464d1afdcd5154..44b071fd40cfe743c13d20bb6892fdaee152c2a4 100644 --- a/controller/topology/links/link.go +++ b/controller/topology/links/link.go @@ -1,6 +1,7 @@ package links import ( + "code.fbi.h-da.de/danet/gosdn/controller/conflict" "code.fbi.h-da.de/danet/gosdn/controller/topology/nodes" "code.fbi.h-da.de/danet/gosdn/controller/topology/ports" "github.com/google/uuid" @@ -8,12 +9,13 @@ import ( // Link is a representation of a physical or virtual link between two nodes and their ports. type Link struct { - ID uuid.UUID `bson:"_id"` - Name string `bson:"name,omitempty"` - SourceNode nodes.Node `bson:"source_node,omitempty"` - TargetNode nodes.Node `bson:"target_node,omitempty"` - SourcePort ports.Port `bson:"source_port,omitempty"` - TargetPort ports.Port `bson:"target_port,omitempty"` + ID uuid.UUID `bson:"_id"` + Metadata conflict.Metadata `bson:"metadata"` + Name string `bson:"name,omitempty"` + SourceNode nodes.Node `bson:"source_node,omitempty"` + TargetNode nodes.Node `bson:"target_node,omitempty"` + SourcePort ports.Port `bson:"source_port,omitempty"` + TargetPort ports.Port `bson:"target_port,omitempty"` } // GetID returns the id of a link. diff --git a/controller/topology/nodes/node.go b/controller/topology/nodes/node.go index a9c836fcd8e316bb3b74f31d7ae894c9c718a630..90f689c785b3df313ffff360ef0088c176e1db1a 100644 --- a/controller/topology/nodes/node.go +++ b/controller/topology/nodes/node.go @@ -1,13 +1,15 @@ package nodes import ( + "code.fbi.h-da.de/danet/gosdn/controller/conflict" "github.com/google/uuid" ) // Node is a representation of a network element. type Node struct { - ID uuid.UUID `bson:"_id"` - Name string `bson:"name"` + ID uuid.UUID `bson:"_id"` + Metadata conflict.Metadata `bson:"metadata"` + Name string `bson:"name"` } // GetID returns the id of a node. diff --git a/controller/topology/nodes/nodeService_test.go b/controller/topology/nodes/nodeService_test.go index a64a1e240cddd74efb9bdaefc9b69ae6c9ded7a4..3eca6b3684c55db9c0ec42e20b3c80a2768fff65 100644 --- a/controller/topology/nodes/nodeService_test.go +++ b/controller/topology/nodes/nodeService_test.go @@ -4,6 +4,7 @@ import ( "reflect" "testing" + "code.fbi.h-da.de/danet/gosdn/controller/conflict" eventservice "code.fbi.h-da.de/danet/gosdn/controller/eventService" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/event" query "code.fbi.h-da.de/danet/gosdn/controller/store" @@ -16,6 +17,9 @@ func getTestNode() Node { return Node{ ID: uuid.MustParse("44fb4aa4-c53c-4cf9-a081-5aabc61c7610"), Name: "Test-Node", + Metadata: conflict.Metadata{ + ResourceVersion: 0, + }, } } @@ -163,7 +167,7 @@ func TestNodeService_Update(t *testing.T) { t.Errorf("NodeService.Update() error = %v, wantErr %v", err, tt.wantErr) } - updatedNode, err := p.Get(query.Query(tt.args.node)) + updatedNode, err := p.Get(query.Query{ID: tt.args.node.ID, Name: tt.args.node.Name}) if err != nil { t.Errorf("NodeService.Get() failed %v", err) } diff --git a/controller/topology/nodes/nodeStore.go b/controller/topology/nodes/nodeStore.go index cd4f28fbcbda6ec972deddee4235426e8cccee6e..f5bb7f4c77ff04e48f2a40bfe94b58bfda34a4a8 100644 --- a/controller/topology/nodes/nodeStore.go +++ b/controller/topology/nodes/nodeStore.go @@ -2,6 +2,7 @@ package nodes import ( "fmt" + "time" "code.fbi.h-da.de/danet/gosdn/controller/customerrs" "code.fbi.h-da.de/danet/gosdn/controller/nucleus/database" @@ -10,7 +11,9 @@ import ( "github.com/google/uuid" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" + "go.mongodb.org/mongo-driver/mongo/writeconcern" ) // Store defines a NodeStore interface. @@ -150,6 +153,10 @@ func (s *DatabaseNodeStore) Add(node Node) (err error) { } }() + node.Metadata.ResourceVersion = 0 + node.Metadata.CreatedAt = time.Now() + node.Metadata.LastUpdated = time.Now() + _, err = client.Database(database.DatabaseName). Collection(s.storeName). InsertOne(ctx, node) @@ -173,22 +180,63 @@ func (s *DatabaseNodeStore) Update(node Node) (err error) { } }() - update := bson.D{primitive.E{Key: "$set", Value: node}} + // 1. Start Transaction + wcMajority := writeconcern.New(writeconcern.WMajority()) + wcMajorityCollectionOpts := options.Collection().SetWriteConcern(wcMajority) + nodeCollection := client.Database(database.DatabaseName).Collection(s.storeName, wcMajorityCollectionOpts) - upsert := false - after := options.After - opt := options.FindOneAndUpdateOptions{ - Upsert: &upsert, - ReturnDocument: &after, + session, err := client.StartSession() + if err != nil { + return err } + defer session.EndSession(ctx) - err = client.Database(database.DatabaseName). - Collection(s.storeName). - FindOneAndUpdate( - ctx, bson.M{"_id": node.ID.String()}, update, &opt). - Decode(&updatedLoadedNodes) + // 2. Fetch exisiting Entity + existingNode, err := s.getByID(node.ID) if err != nil { - return customerrs.CouldNotUpdateError{Identifier: node.ID, Type: node, Err: err} + return err + } + + // 3. Check if Entity.Metadata.ResourceVersion == UpdatedEntity.Metadata.ResourceVersion + if node.Metadata.ResourceVersion != existingNode.Metadata.ResourceVersion { + // 3.1.1 End transaction + // 3.1.2 If no -> return error + + return fmt.Errorf( + "resource version %d of provided node %s is older or newer than %d in the store", + node.Metadata.ResourceVersion, + node.ID.String(), existingNode.Metadata.ResourceVersion, + ) + } + + // 3.2.1 If yes -> Update entity in callback + callback := func(sessCtx mongo.SessionContext) (interface{}, error) { + // Important: You must pass sessCtx as the Context parameter to the operations for them to be executed in the + // transaction. + update := bson.D{primitive.E{Key: "$set", Value: node}} + + upsert := false + after := options.After + opt := options.FindOneAndUpdateOptions{ + Upsert: &upsert, + ReturnDocument: &after, + } + + err = nodeCollection. + FindOneAndUpdate( + ctx, bson.M{"_id": node.ID.String()}, update, &opt). + Decode(&updatedLoadedNodes) + if err != nil { + return nil, customerrs.CouldNotUpdateError{Identifier: node.ID, Type: node, Err: err} + } + + // 3.2.2 End transaction + return "", nil + } + + _, err = session.WithTransaction(ctx, callback) + if err != nil { + return err } return nil diff --git a/controller/topology/ports/port.go b/controller/topology/ports/port.go index 2614f745c574a221f79974eaa95f11217a828187..5248c3b5a47ac63407d6e28727779ad966a105c9 100644 --- a/controller/topology/ports/port.go +++ b/controller/topology/ports/port.go @@ -1,6 +1,7 @@ package ports import ( + "code.fbi.h-da.de/danet/gosdn/controller/conflict" "code.fbi.h-da.de/danet/gosdn/controller/topology/ports/configuration" "github.com/google/uuid" ) @@ -8,6 +9,7 @@ import ( // Port is a representation of physical port on a network element. type Port struct { ID uuid.UUID `bson:"_id"` + Metadata conflict.Metadata `bson:"metadata"` Name string `bson:"name,omitempty"` Configuration configuration.IPConfig `bson:"configuration,omitempty"` } diff --git a/controller/topology/routing-tables/route.go b/controller/topology/routing-tables/route.go index ad7da495d82a6a2fafa7fb938fdb39c1ea68c8cd..746012f37eb752fef877fd1a46c7d3bf585fa068 100644 --- a/controller/topology/routing-tables/route.go +++ b/controller/topology/routing-tables/route.go @@ -1,14 +1,16 @@ package routingtables import ( + "code.fbi.h-da.de/danet/gosdn/controller/conflict" "github.com/google/uuid" ) // Route is a routing table entry on a network element. type Route struct { - ID uuid.UUID `bson:"_id"` - TargetIPRange string `bson:"target_ip_range"` - NextHopIP string `bson:"next_hop_ip"` - PortID uuid.UUID `bson:"port_id"` - Metric string `bson:"metric"` + ID uuid.UUID `bson:"_id"` + Metadata conflict.Metadata `bson:"metadata"` + TargetIPRange string `bson:"target_ip_range"` + NextHopIP string `bson:"next_hop_ip"` + PortID uuid.UUID `bson:"port_id"` + Metric string `bson:"metric"` }