diff --git a/api/go/gosdn/pnd/pnd.pb.go b/api/go/gosdn/pnd/pnd.pb.go index 8b52d80fe24ce2736647ae104ff754eaa8be9562..b7680a2d65f6d0cde9984ae9e920c01d6f3f2abe 100644 --- a/api/go/gosdn/pnd/pnd.pb.go +++ b/api/go/gosdn/pnd/pnd.pb.go @@ -286,6 +286,110 @@ func (Status) EnumDescriptor() ([]byte, []int) { return file_gosdn_pnd_pnd_proto_rawDescGZIP(), []int{4} } +type SubscriptionMode int32 + +const ( + SubscriptionMode_SUBSCRIPTION_MODE_UNSPECIFIED SubscriptionMode = 0 + SubscriptionMode_SUBSCRIPTION_MODE_ONCE SubscriptionMode = 1 + SubscriptionMode_SUBSCRIPTION_MODE_STREAM SubscriptionMode = 2 + SubscriptionMode_SUBSCRIPTION_MODE_POLL SubscriptionMode = 3 +) + +// Enum value maps for SubscriptionMode. +var ( + SubscriptionMode_name = map[int32]string{ + 0: "SUBSCRIPTION_MODE_UNSPECIFIED", + 1: "SUBSCRIPTION_MODE_ONCE", + 2: "SUBSCRIPTION_MODE_STREAM", + 3: "SUBSCRIPTION_MODE_POLL", + } + SubscriptionMode_value = map[string]int32{ + "SUBSCRIPTION_MODE_UNSPECIFIED": 0, + "SUBSCRIPTION_MODE_ONCE": 1, + "SUBSCRIPTION_MODE_STREAM": 2, + "SUBSCRIPTION_MODE_POLL": 3, + } +) + +func (x SubscriptionMode) Enum() *SubscriptionMode { + p := new(SubscriptionMode) + *p = x + return p +} + +func (x SubscriptionMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SubscriptionMode) Descriptor() protoreflect.EnumDescriptor { + return file_gosdn_pnd_pnd_proto_enumTypes[5].Descriptor() +} + +func (SubscriptionMode) Type() protoreflect.EnumType { + return &file_gosdn_pnd_pnd_proto_enumTypes[5] +} + +func (x SubscriptionMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SubscriptionMode.Descriptor instead. +func (SubscriptionMode) EnumDescriptor() ([]byte, []int) { + return file_gosdn_pnd_pnd_proto_rawDescGZIP(), []int{5} +} + +type StreamMode int32 + +const ( + StreamMode_STREAM_MODE_UNSPECIFIED StreamMode = 0 + StreamMode_STREAM_MODE_TARGET_DEFINED StreamMode = 1 // The target selects the relevant mode for each element. + StreamMode_STREAM_MODE_ON_CHANGE StreamMode = 2 // The target sends an update on element value change. + StreamMode_STREAM_MODE_SAMPLE StreamMode = 3 // The target samples values according to the interval. +) + +// Enum value maps for StreamMode. +var ( + StreamMode_name = map[int32]string{ + 0: "STREAM_MODE_UNSPECIFIED", + 1: "STREAM_MODE_TARGET_DEFINED", + 2: "STREAM_MODE_ON_CHANGE", + 3: "STREAM_MODE_SAMPLE", + } + StreamMode_value = map[string]int32{ + "STREAM_MODE_UNSPECIFIED": 0, + "STREAM_MODE_TARGET_DEFINED": 1, + "STREAM_MODE_ON_CHANGE": 2, + "STREAM_MODE_SAMPLE": 3, + } +) + +func (x StreamMode) Enum() *StreamMode { + p := new(StreamMode) + *p = x + return p +} + +func (x StreamMode) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (StreamMode) Descriptor() protoreflect.EnumDescriptor { + return file_gosdn_pnd_pnd_proto_enumTypes[6].Descriptor() +} + +func (StreamMode) Type() protoreflect.EnumType { + return &file_gosdn_pnd_pnd_proto_enumTypes[6] +} + +func (x StreamMode) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use StreamMode.Descriptor instead. +func (StreamMode) EnumDescriptor() ([]byte, []int) { + return file_gosdn_pnd_pnd_proto_rawDescGZIP(), []int{6} +} + type GetOndListRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2356,6 +2460,260 @@ func (x *DeleteOndResponse) GetStatus() Status { return Status_STATUS_UNSPECIFIED } +type SubscribePathRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Timestamp in nanoseconds since Epoch. + Did string `protobuf:"bytes,2,opt,name=did,proto3" json:"did,omitempty"` + Pid string `protobuf:"bytes,3,opt,name=pid,proto3" json:"pid,omitempty"` + Sublist *SubscriptionList `protobuf:"bytes,4,opt,name=sublist,proto3" json:"sublist,omitempty"` +} + +func (x *SubscribePathRequest) Reset() { + *x = SubscribePathRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_pnd_pnd_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SubscribePathRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubscribePathRequest) ProtoMessage() {} + +func (x *SubscribePathRequest) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_pnd_pnd_proto_msgTypes[33] + 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 SubscribePathRequest.ProtoReflect.Descriptor instead. +func (*SubscribePathRequest) Descriptor() ([]byte, []int) { + return file_gosdn_pnd_pnd_proto_rawDescGZIP(), []int{33} +} + +func (x *SubscribePathRequest) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *SubscribePathRequest) GetDid() string { + if x != nil { + return x.Did + } + return "" +} + +func (x *SubscribePathRequest) GetPid() string { + if x != nil { + return x.Pid + } + return "" +} + +func (x *SubscribePathRequest) GetSublist() *SubscriptionList { + if x != nil { + return x.Sublist + } + return nil +} + +// The mode determines how the target should trigger updates to be sent. +// Reference: gNMI Specification Section 3.5.1.2 +type SubscriptionList struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Subscription []*Subscription `protobuf:"bytes,1,rep,name=subscription,proto3" json:"subscription,omitempty"` + Mode SubscriptionMode `protobuf:"varint,2,opt,name=mode,proto3,enum=gosdn.pnd.SubscriptionMode" json:"mode,omitempty"` +} + +func (x *SubscriptionList) Reset() { + *x = SubscriptionList{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_pnd_pnd_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SubscriptionList) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubscriptionList) ProtoMessage() {} + +func (x *SubscriptionList) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_pnd_pnd_proto_msgTypes[34] + 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 SubscriptionList.ProtoReflect.Descriptor instead. +func (*SubscriptionList) Descriptor() ([]byte, []int) { + return file_gosdn_pnd_pnd_proto_rawDescGZIP(), []int{34} +} + +func (x *SubscriptionList) GetSubscription() []*Subscription { + if x != nil { + return x.Subscription + } + return nil +} + +func (x *SubscriptionList) GetMode() SubscriptionMode { + if x != nil { + return x.Mode + } + return SubscriptionMode_SUBSCRIPTION_MODE_UNSPECIFIED +} + +type Subscription struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Path string `protobuf:"bytes,1,opt,name=path,proto3" json:"path,omitempty"` + StreamMode StreamMode `protobuf:"varint,2,opt,name=stream_mode,json=streamMode,proto3,enum=gosdn.pnd.StreamMode" json:"stream_mode,omitempty"` + SampleInterval uint64 `protobuf:"varint,3,opt,name=sample_interval,json=sampleInterval,proto3" json:"sample_interval,omitempty"` // ns between samples in SAMPLE mode. +} + +func (x *Subscription) Reset() { + *x = Subscription{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_pnd_pnd_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Subscription) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Subscription) ProtoMessage() {} + +func (x *Subscription) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_pnd_pnd_proto_msgTypes[35] + 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 Subscription.ProtoReflect.Descriptor instead. +func (*Subscription) Descriptor() ([]byte, []int) { + return file_gosdn_pnd_pnd_proto_rawDescGZIP(), []int{35} +} + +func (x *Subscription) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +func (x *Subscription) GetStreamMode() StreamMode { + if x != nil { + return x.StreamMode + } + return StreamMode_STREAM_MODE_UNSPECIFIED +} + +func (x *Subscription) GetSampleInterval() uint64 { + if x != nil { + return x.SampleInterval + } + return 0 +} + +type SubscribePathResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` // Timestamp in nanoseconds since Epoch. + Status Status `protobuf:"varint,2,opt,name=status,proto3,enum=gosdn.pnd.Status" json:"status,omitempty"` + Device []*gnmi.Notification `protobuf:"bytes,3,rep,name=device,proto3" json:"device,omitempty"` +} + +func (x *SubscribePathResponse) Reset() { + *x = SubscribePathResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_pnd_pnd_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SubscribePathResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SubscribePathResponse) ProtoMessage() {} + +func (x *SubscribePathResponse) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_pnd_pnd_proto_msgTypes[36] + 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 SubscribePathResponse.ProtoReflect.Descriptor instead. +func (*SubscribePathResponse) Descriptor() ([]byte, []int) { + return file_gosdn_pnd_pnd_proto_rawDescGZIP(), []int{36} +} + +func (x *SubscribePathResponse) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *SubscribePathResponse) GetStatus() Status { + if x != nil { + return x.Status + } + return Status_STATUS_UNSPECIFIED +} + +func (x *SubscribePathResponse) GetDevice() []*gnmi.Notification { + if x != nil { + return x.Device + } + return nil +} + var File_gosdn_pnd_pnd_proto protoreflect.FileDescriptor var file_gosdn_pnd_pnd_proto_rawDesc = []byte{ @@ -2623,142 +2981,199 @@ var file_gosdn_pnd_pnd_proto_rawDesc = []byte{ 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x29, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x2a, 0x9c, 0x01, 0x0a, 0x0b, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, 0x18, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54, - 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, - 0x00, 0x12, 0x18, 0x0a, 0x14, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, - 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x43, - 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, - 0x49, 0x54, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x48, 0x41, 0x4e, 0x47, - 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, - 0x44, 0x10, 0x03, 0x12, 0x1d, 0x0a, 0x19, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54, - 0x41, 0x54, 0x45, 0x5f, 0x49, 0x4e, 0x43, 0x4f, 0x4e, 0x53, 0x49, 0x53, 0x54, 0x45, 0x4e, 0x54, - 0x10, 0x04, 0x2a, 0x7c, 0x0a, 0x0c, 0x41, 0x70, 0x69, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x19, 0x41, 0x50, 0x49, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, + 0x74, 0x75, 0x73, 0x22, 0x8f, 0x01, 0x0a, 0x14, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, + 0x65, 0x50, 0x61, 0x74, 0x68, 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, 0x10, 0x0a, 0x03, 0x64, 0x69, + 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x64, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, + 0x70, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x69, 0x64, 0x12, 0x35, + 0x0a, 0x07, 0x73, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x07, 0x73, 0x75, + 0x62, 0x6c, 0x69, 0x73, 0x74, 0x22, 0x80, 0x01, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x73, 0x75, 0x62, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2f, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, + 0x64, 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, + 0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x83, 0x01, 0x0a, 0x0c, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, + 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x36, 0x0a, + 0x0b, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5f, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x0a, 0x73, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5f, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, + 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x22, 0x8c, + 0x01, 0x0a, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x50, 0x61, 0x74, 0x68, + 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, 0x29, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x11, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, + 0x6e, 0x64, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x2a, 0x0a, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x6e, 0x6d, 0x69, 0x2e, 0x4e, 0x6f, 0x74, 0x69, 0x66, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x2a, 0x9c, 0x01, + 0x0a, 0x0b, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1c, 0x0a, + 0x18, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, + 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x43, + 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x50, 0x45, 0x4e, 0x44, + 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, + 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x54, 0x45, 0x44, 0x10, + 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, + 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x45, 0x44, 0x10, 0x03, 0x12, 0x1d, 0x0a, + 0x19, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x49, 0x4e, + 0x43, 0x4f, 0x4e, 0x53, 0x49, 0x53, 0x54, 0x45, 0x4e, 0x54, 0x10, 0x04, 0x2a, 0x7c, 0x0a, 0x0c, + 0x41, 0x70, 0x69, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x19, + 0x41, 0x50, 0x49, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, + 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x41, + 0x50, 0x49, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x50, 0x44, + 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x41, 0x50, 0x49, 0x5f, 0x4f, 0x50, 0x45, + 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x10, 0x02, + 0x12, 0x18, 0x0a, 0x14, 0x41, 0x50, 0x49, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, + 0x4e, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x03, 0x2a, 0x6d, 0x0a, 0x07, 0x53, 0x62, + 0x69, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x42, 0x49, 0x5f, 0x54, 0x59, 0x50, + 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x17, 0x0a, 0x13, 0x53, 0x42, 0x49, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4f, 0x50, 0x45, 0x4e, + 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x42, 0x49, 0x5f, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x49, 0x4e, 0x45, 0x52, 0x49, 0x53, + 0x45, 0x44, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x42, 0x49, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x50, 0x4c, 0x55, 0x47, 0x49, 0x4e, 0x10, 0x03, 0x2a, 0x69, 0x0a, 0x09, 0x4f, 0x70, 0x65, + 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x15, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, - 0x00, 0x12, 0x18, 0x0a, 0x14, 0x41, 0x50, 0x49, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, - 0x4f, 0x4e, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x41, - 0x50, 0x49, 0x5f, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x52, 0x45, 0x50, - 0x4c, 0x41, 0x43, 0x45, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, 0x41, 0x50, 0x49, 0x5f, 0x4f, 0x50, - 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x03, - 0x2a, 0x6d, 0x0a, 0x07, 0x53, 0x62, 0x69, 0x54, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x53, - 0x42, 0x49, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, - 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x53, 0x42, 0x49, 0x5f, 0x54, 0x59, 0x50, - 0x45, 0x5f, 0x4f, 0x50, 0x45, 0x4e, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x1a, - 0x0a, 0x16, 0x53, 0x42, 0x49, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, - 0x49, 0x4e, 0x45, 0x52, 0x49, 0x53, 0x45, 0x44, 0x10, 0x02, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x42, - 0x49, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x50, 0x4c, 0x55, 0x47, 0x49, 0x4e, 0x10, 0x03, 0x2a, - 0x69, 0x0a, 0x09, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x15, - 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, - 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x4f, 0x50, 0x45, 0x52, 0x41, - 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x14, 0x0a, - 0x10, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, - 0x54, 0x10, 0x02, 0x12, 0x15, 0x0a, 0x11, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, - 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x52, 0x4d, 0x10, 0x03, 0x2a, 0x41, 0x0a, 0x06, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, - 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, - 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4f, 0x4b, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x53, - 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x32, 0xfc, 0x09, - 0x0a, 0x0a, 0x50, 0x6e, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x63, 0x0a, 0x0a, - 0x47, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x73, - 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, - 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, - 0x10, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64, - 0x73, 0x12, 0x5c, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x12, 0x18, 0x2e, 0x67, 0x6f, + 0x00, 0x12, 0x14, 0x0a, 0x10, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, + 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x4f, 0x50, 0x45, 0x52, 0x41, + 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x4d, 0x4d, 0x49, 0x54, 0x10, 0x02, 0x12, 0x15, 0x0a, + 0x11, 0x4f, 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, + 0x52, 0x4d, 0x10, 0x03, 0x2a, 0x41, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, + 0x0a, 0x12, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, + 0x5f, 0x4f, 0x4b, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, + 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x2a, 0x8b, 0x01, 0x0a, 0x10, 0x53, 0x75, 0x62, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x21, 0x0a, 0x1d, + 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x4f, 0x44, + 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x1a, 0x0a, 0x16, 0x53, 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, + 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x4f, 0x4e, 0x43, 0x45, 0x10, 0x01, 0x12, 0x1c, 0x0a, 0x18, 0x53, + 0x55, 0x42, 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x4f, 0x44, 0x45, + 0x5f, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x10, 0x02, 0x12, 0x1a, 0x0a, 0x16, 0x53, 0x55, 0x42, + 0x53, 0x43, 0x52, 0x49, 0x50, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x50, + 0x4f, 0x4c, 0x4c, 0x10, 0x03, 0x2a, 0x7c, 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4d, + 0x6f, 0x64, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x5f, 0x4d, 0x4f, + 0x44, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x1e, 0x0a, 0x1a, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, + 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x5f, 0x44, 0x45, 0x46, 0x49, 0x4e, 0x45, 0x44, 0x10, 0x01, + 0x12, 0x19, 0x0a, 0x15, 0x53, 0x54, 0x52, 0x45, 0x41, 0x4d, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, + 0x4f, 0x4e, 0x5f, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x10, 0x02, 0x12, 0x16, 0x0a, 0x12, 0x53, + 0x54, 0x52, 0x45, 0x41, 0x4d, 0x5f, 0x4d, 0x4f, 0x44, 0x45, 0x5f, 0x53, 0x41, 0x4d, 0x50, 0x4c, + 0x45, 0x10, 0x03, 0x32, 0xd4, 0x0a, 0x0a, 0x0a, 0x50, 0x6e, 0x64, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x12, 0x63, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, + 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, + 0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, + 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x6e, + 0x64, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, + 0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x5c, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x4f, 0x6e, + 0x64, 0x12, 0x18, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, + 0x74, 0x4f, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, - 0x64, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, - 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x2f, 0x7b, 0x64, 0x69, 0x64, 0x7d, 0x12, - 0x66, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1c, 0x2e, - 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x4f, 0x6e, 0x64, - 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f, - 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, - 0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x63, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x53, 0x62, - 0x69, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, - 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, - 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x70, 0x6e, 0x64, - 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x73, 0x62, 0x69, 0x73, 0x12, 0x5d, 0x0a, 0x06, - 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x12, 0x18, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, - 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x19, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, - 0x53, 0x62, 0x69, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, - 0x2f, 0x73, 0x62, 0x69, 0x73, 0x2f, 0x7b, 0x73, 0x69, 0x64, 0x7d, 0x12, 0x66, 0x0a, 0x0a, 0x53, - 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x73, 0x64, - 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, - 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, - 0x2a, 0x22, 0x10, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x73, - 0x62, 0x69, 0x73, 0x12, 0x6f, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, - 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, - 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, - 0x64, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, - 0x13, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x73, 0x12, 0x6a, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, - 0x65, 0x12, 0x1b, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, - 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, - 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, - 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, - 0x7d, 0x2f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x2f, 0x7b, 0x63, 0x75, 0x69, 0x64, 0x7d, - 0x12, 0x72, 0x0a, 0x0d, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73, - 0x74, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, - 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, - 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, - 0x13, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x73, 0x12, 0x6d, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, - 0x19, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x50, - 0x61, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x67, 0x6f, 0x73, - 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x12, 0x23, - 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x73, - 0x2f, 0x7b, 0x64, 0x69, 0x64, 0x7d, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x2f, 0x7b, 0x70, 0x61, - 0x74, 0x68, 0x7d, 0x12, 0x6f, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x4c, 0x69, - 0x73, 0x74, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, - 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1e, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, - 0x74, 0x50, 0x61, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x3a, 0x01, 0x2a, 0x22, 0x16, 0x2f, 0x70, - 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x73, 0x2f, 0x70, - 0x61, 0x74, 0x68, 0x73, 0x12, 0x66, 0x0a, 0x09, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, - 0x64, 0x12, 0x1b, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, - 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, - 0x65, 0x4f, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x18, 0x2a, 0x16, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, - 0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x64, 0x69, 0x64, 0x7d, 0x42, 0xae, 0x02, 0x5a, - 0x2d, 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, 0x70, 0x6e, 0x64, 0x92, 0x41, - 0xfb, 0x01, 0x12, 0xf8, 0x01, 0x0a, 0x10, 0x67, 0x6f, 0x53, 0x44, 0x4e, 0x20, 0x4e, 0x6f, 0x72, - 0x74, 0x68, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x4d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, - 0x6c, 0x20, 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x6f, 0x20, 0x63, - 0x6f, 0x64, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x6f, 0x53, 0x44, - 0x4e, 0x20, 0x6e, 0x6f, 0x72, 0x74, 0x68, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x49, 0x6e, 0x74, - 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x22, 0x3e, 0x0a, 0x18, 0x67, 0x6f, 0x53, 0x44, 0x4e, 0x20, - 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x12, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x63, 0x6f, 0x64, 0x65, - 0x2e, 0x66, 0x62, 0x69, 0x2e, 0x68, 0x2d, 0x64, 0x61, 0x2e, 0x64, 0x65, 0x2f, 0x64, 0x61, 0x6e, - 0x65, 0x74, 0x2f, 0x61, 0x70, 0x69, 0x2a, 0x50, 0x0a, 0x14, 0x42, 0x53, 0x44, 0x20, 0x33, 0x2d, - 0x43, 0x6c, 0x61, 0x75, 0x73, 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x38, - 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x66, 0x62, 0x69, - 0x2e, 0x68, 0x2d, 0x64, 0x61, 0x2e, 0x64, 0x65, 0x2f, 0x64, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x61, - 0x70, 0x69, 0x2f, 0x2d, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, - 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x03, 0x30, 0x2e, 0x31, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x15, + 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x2f, + 0x7b, 0x64, 0x69, 0x64, 0x7d, 0x12, 0x66, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x4c, + 0x69, 0x73, 0x74, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, + 0x53, 0x65, 0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, + 0x74, 0x4f, 0x6e, 0x64, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x1b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x70, 0x6e, + 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x63, 0x0a, + 0x0a, 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1c, 0x2e, 0x67, 0x6f, + 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, + 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x67, 0x6f, 0x73, 0x64, + 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, + 0x12, 0x10, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x73, 0x62, + 0x69, 0x73, 0x12, 0x5d, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x12, 0x18, 0x2e, 0x67, + 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, + 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x62, 0x69, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x70, 0x6e, 0x64, 0x73, + 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x73, 0x62, 0x69, 0x73, 0x2f, 0x7b, 0x73, 0x69, 0x64, + 0x7d, 0x12, 0x66, 0x0a, 0x0a, 0x53, 0x65, 0x74, 0x53, 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74, 0x12, + 0x1c, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x53, + 0x62, 0x69, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, + 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x53, 0x62, 0x69, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x15, 0x3a, 0x01, 0x2a, 0x22, 0x10, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, + 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x73, 0x62, 0x69, 0x73, 0x12, 0x6f, 0x0a, 0x0d, 0x47, 0x65, 0x74, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x73, + 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x6f, + 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1b, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x15, 0x12, 0x13, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, + 0x64, 0x7d, 0x2f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x6a, 0x0a, 0x09, 0x47, 0x65, + 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x1b, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, + 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, + 0x2e, 0x47, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, 0x70, 0x6e, 0x64, + 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x2f, + 0x7b, 0x63, 0x75, 0x69, 0x64, 0x7d, 0x12, 0x72, 0x0a, 0x0d, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, + 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, 0x73, + 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, + 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4c, 0x69, + 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, 0x13, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, + 0x64, 0x7d, 0x2f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x6d, 0x0a, 0x07, 0x47, 0x65, + 0x74, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, + 0x64, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1a, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x47, 0x65, 0x74, + 0x50, 0x61, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x25, 0x12, 0x23, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, + 0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x64, 0x69, 0x64, 0x7d, 0x2f, 0x70, 0x61, 0x74, + 0x68, 0x73, 0x2f, 0x7b, 0x70, 0x61, 0x74, 0x68, 0x7d, 0x12, 0x6f, 0x0a, 0x0b, 0x53, 0x65, 0x74, + 0x50, 0x61, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, + 0x2e, 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, + 0x70, 0x6e, 0x64, 0x2e, 0x53, 0x65, 0x74, 0x50, 0x61, 0x74, 0x68, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x3a, + 0x01, 0x2a, 0x22, 0x16, 0x2f, 0x70, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, + 0x6f, 0x6e, 0x64, 0x73, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x73, 0x12, 0x66, 0x0a, 0x09, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x64, 0x12, 0x1b, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, + 0x70, 0x6e, 0x64, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, + 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x6e, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x2a, 0x16, 0x2f, 0x70, 0x6e, 0x64, + 0x73, 0x2f, 0x7b, 0x70, 0x69, 0x64, 0x7d, 0x2f, 0x6f, 0x6e, 0x64, 0x73, 0x2f, 0x7b, 0x64, 0x69, + 0x64, 0x7d, 0x12, 0x56, 0x0a, 0x0d, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x50, + 0x61, 0x74, 0x68, 0x12, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, 0x2e, + 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x50, 0x61, 0x74, 0x68, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x70, 0x6e, 0x64, + 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x50, 0x61, 0x74, 0x68, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x30, 0x01, 0x42, 0xae, 0x02, 0x5a, 0x2d, 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, 0x70, 0x6e, 0x64, 0x92, 0x41, 0xfb, 0x01, + 0x12, 0xf8, 0x01, 0x0a, 0x10, 0x67, 0x6f, 0x53, 0x44, 0x4e, 0x20, 0x4e, 0x6f, 0x72, 0x74, 0x68, + 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x12, 0x4d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x20, + 0x42, 0x75, 0x66, 0x66, 0x65, 0x72, 0x20, 0x73, 0x70, 0x65, 0x63, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x47, 0x6f, 0x20, 0x63, 0x6f, 0x64, + 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x67, 0x6f, 0x53, 0x44, 0x4e, 0x20, + 0x6e, 0x6f, 0x72, 0x74, 0x68, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x66, 0x61, 0x63, 0x65, 0x22, 0x3e, 0x0a, 0x18, 0x67, 0x6f, 0x53, 0x44, 0x4e, 0x20, 0x4e, 0x6f, + 0x72, 0x74, 0x68, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, + 0x12, 0x22, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x66, + 0x62, 0x69, 0x2e, 0x68, 0x2d, 0x64, 0x61, 0x2e, 0x64, 0x65, 0x2f, 0x64, 0x61, 0x6e, 0x65, 0x74, + 0x2f, 0x61, 0x70, 0x69, 0x2a, 0x50, 0x0a, 0x14, 0x42, 0x53, 0x44, 0x20, 0x33, 0x2d, 0x43, 0x6c, + 0x61, 0x75, 0x73, 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x38, 0x68, 0x74, + 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x66, 0x62, 0x69, 0x2e, 0x68, + 0x2d, 0x64, 0x61, 0x2e, 0x64, 0x65, 0x2f, 0x64, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x61, 0x70, 0x69, + 0x2f, 0x2d, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x2f, 0x4c, + 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x03, 0x30, 0x2e, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, } var ( @@ -2773,119 +3188,133 @@ func file_gosdn_pnd_pnd_proto_rawDescGZIP() []byte { return file_gosdn_pnd_pnd_proto_rawDescData } -var file_gosdn_pnd_pnd_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_gosdn_pnd_pnd_proto_msgTypes = make([]protoimpl.MessageInfo, 33) +var file_gosdn_pnd_pnd_proto_enumTypes = make([]protoimpl.EnumInfo, 7) +var file_gosdn_pnd_pnd_proto_msgTypes = make([]protoimpl.MessageInfo, 37) var file_gosdn_pnd_pnd_proto_goTypes = []interface{}{ (ChangeState)(0), // 0: gosdn.pnd.ChangeState (ApiOperation)(0), // 1: gosdn.pnd.ApiOperation (SbiType)(0), // 2: gosdn.pnd.SbiType (Operation)(0), // 3: gosdn.pnd.Operation (Status)(0), // 4: gosdn.pnd.Status - (*GetOndListRequest)(nil), // 5: gosdn.pnd.GetOndListRequest - (*GetOndRequest)(nil), // 6: gosdn.pnd.GetOndRequest - (*GetSbiListRequest)(nil), // 7: gosdn.pnd.GetSbiListRequest - (*GetSbiRequest)(nil), // 8: gosdn.pnd.GetSbiRequest - (*GetChangeListRequest)(nil), // 9: gosdn.pnd.GetChangeListRequest - (*GetChangeRequest)(nil), // 10: gosdn.pnd.GetChangeRequest - (*GetPathRequest)(nil), // 11: gosdn.pnd.GetPathRequest - (*GetOndResponse)(nil), // 12: gosdn.pnd.GetOndResponse - (*GetOndListResponse)(nil), // 13: gosdn.pnd.GetOndListResponse - (*GetSbiResponse)(nil), // 14: gosdn.pnd.GetSbiResponse - (*GetSbiListResponse)(nil), // 15: gosdn.pnd.GetSbiListResponse - (*GetPathResponse)(nil), // 16: gosdn.pnd.GetPathResponse - (*GetChangeResponse)(nil), // 17: gosdn.pnd.GetChangeResponse - (*GetChangeListResponse)(nil), // 18: gosdn.pnd.GetChangeListResponse - (*PrincipalNetworkDomain)(nil), // 19: gosdn.pnd.PrincipalNetworkDomain - (*OrchestratedNetworkingDevice)(nil), // 20: gosdn.pnd.OrchestratedNetworkingDevice - (*Change)(nil), // 21: gosdn.pnd.Change - (*SetOndListRequest)(nil), // 22: gosdn.pnd.SetOndListRequest - (*SetSbiListRequest)(nil), // 23: gosdn.pnd.SetSbiListRequest - (*SetChangeListRequest)(nil), // 24: gosdn.pnd.SetChangeListRequest - (*SetPathListRequest)(nil), // 25: gosdn.pnd.SetPathListRequest - (*ChangeRequest)(nil), // 26: gosdn.pnd.ChangeRequest - (*SetOnd)(nil), // 27: gosdn.pnd.SetOnd - (*SetSbi)(nil), // 28: gosdn.pnd.SetSbi - (*SetChange)(nil), // 29: gosdn.pnd.SetChange - (*SetResponse)(nil), // 30: gosdn.pnd.SetResponse - (*SetOndListResponse)(nil), // 31: gosdn.pnd.SetOndListResponse - (*SetChangeListResponse)(nil), // 32: gosdn.pnd.SetChangeListResponse - (*SetChangeResponse)(nil), // 33: gosdn.pnd.SetChangeResponse - (*SetSbiListResponse)(nil), // 34: gosdn.pnd.SetSbiListResponse - (*SetPathListResponse)(nil), // 35: gosdn.pnd.SetPathListResponse - (*DeleteOndRequest)(nil), // 36: gosdn.pnd.DeleteOndRequest - (*DeleteOndResponse)(nil), // 37: gosdn.pnd.DeleteOndResponse - (*southbound.SouthboundInterface)(nil), // 38: gosdn.southbound.SouthboundInterface - (*gnmi.Notification)(nil), // 39: gnmi.Notification - (*transport.TransportOption)(nil), // 40: gosdn.transport.TransportOption + (SubscriptionMode)(0), // 5: gosdn.pnd.SubscriptionMode + (StreamMode)(0), // 6: gosdn.pnd.StreamMode + (*GetOndListRequest)(nil), // 7: gosdn.pnd.GetOndListRequest + (*GetOndRequest)(nil), // 8: gosdn.pnd.GetOndRequest + (*GetSbiListRequest)(nil), // 9: gosdn.pnd.GetSbiListRequest + (*GetSbiRequest)(nil), // 10: gosdn.pnd.GetSbiRequest + (*GetChangeListRequest)(nil), // 11: gosdn.pnd.GetChangeListRequest + (*GetChangeRequest)(nil), // 12: gosdn.pnd.GetChangeRequest + (*GetPathRequest)(nil), // 13: gosdn.pnd.GetPathRequest + (*GetOndResponse)(nil), // 14: gosdn.pnd.GetOndResponse + (*GetOndListResponse)(nil), // 15: gosdn.pnd.GetOndListResponse + (*GetSbiResponse)(nil), // 16: gosdn.pnd.GetSbiResponse + (*GetSbiListResponse)(nil), // 17: gosdn.pnd.GetSbiListResponse + (*GetPathResponse)(nil), // 18: gosdn.pnd.GetPathResponse + (*GetChangeResponse)(nil), // 19: gosdn.pnd.GetChangeResponse + (*GetChangeListResponse)(nil), // 20: gosdn.pnd.GetChangeListResponse + (*PrincipalNetworkDomain)(nil), // 21: gosdn.pnd.PrincipalNetworkDomain + (*OrchestratedNetworkingDevice)(nil), // 22: gosdn.pnd.OrchestratedNetworkingDevice + (*Change)(nil), // 23: gosdn.pnd.Change + (*SetOndListRequest)(nil), // 24: gosdn.pnd.SetOndListRequest + (*SetSbiListRequest)(nil), // 25: gosdn.pnd.SetSbiListRequest + (*SetChangeListRequest)(nil), // 26: gosdn.pnd.SetChangeListRequest + (*SetPathListRequest)(nil), // 27: gosdn.pnd.SetPathListRequest + (*ChangeRequest)(nil), // 28: gosdn.pnd.ChangeRequest + (*SetOnd)(nil), // 29: gosdn.pnd.SetOnd + (*SetSbi)(nil), // 30: gosdn.pnd.SetSbi + (*SetChange)(nil), // 31: gosdn.pnd.SetChange + (*SetResponse)(nil), // 32: gosdn.pnd.SetResponse + (*SetOndListResponse)(nil), // 33: gosdn.pnd.SetOndListResponse + (*SetChangeListResponse)(nil), // 34: gosdn.pnd.SetChangeListResponse + (*SetChangeResponse)(nil), // 35: gosdn.pnd.SetChangeResponse + (*SetSbiListResponse)(nil), // 36: gosdn.pnd.SetSbiListResponse + (*SetPathListResponse)(nil), // 37: gosdn.pnd.SetPathListResponse + (*DeleteOndRequest)(nil), // 38: gosdn.pnd.DeleteOndRequest + (*DeleteOndResponse)(nil), // 39: gosdn.pnd.DeleteOndResponse + (*SubscribePathRequest)(nil), // 40: gosdn.pnd.SubscribePathRequest + (*SubscriptionList)(nil), // 41: gosdn.pnd.SubscriptionList + (*Subscription)(nil), // 42: gosdn.pnd.Subscription + (*SubscribePathResponse)(nil), // 43: gosdn.pnd.SubscribePathResponse + (*southbound.SouthboundInterface)(nil), // 44: gosdn.southbound.SouthboundInterface + (*gnmi.Notification)(nil), // 45: gnmi.Notification + (*transport.TransportOption)(nil), // 46: gosdn.transport.TransportOption } var file_gosdn_pnd_pnd_proto_depIdxs = []int32{ - 19, // 0: gosdn.pnd.GetOndResponse.pnd:type_name -> gosdn.pnd.PrincipalNetworkDomain - 20, // 1: gosdn.pnd.GetOndResponse.ond:type_name -> gosdn.pnd.OrchestratedNetworkingDevice - 19, // 2: gosdn.pnd.GetOndListResponse.pnd:type_name -> gosdn.pnd.PrincipalNetworkDomain - 20, // 3: gosdn.pnd.GetOndListResponse.ond:type_name -> gosdn.pnd.OrchestratedNetworkingDevice - 19, // 4: gosdn.pnd.GetSbiResponse.pnd:type_name -> gosdn.pnd.PrincipalNetworkDomain - 38, // 5: gosdn.pnd.GetSbiResponse.sbi:type_name -> gosdn.southbound.SouthboundInterface - 19, // 6: gosdn.pnd.GetSbiListResponse.pnd:type_name -> gosdn.pnd.PrincipalNetworkDomain - 38, // 7: gosdn.pnd.GetSbiListResponse.sbi:type_name -> gosdn.southbound.SouthboundInterface - 19, // 8: gosdn.pnd.GetPathResponse.pnd:type_name -> gosdn.pnd.PrincipalNetworkDomain - 39, // 9: gosdn.pnd.GetPathResponse.device:type_name -> gnmi.Notification - 19, // 10: gosdn.pnd.GetChangeResponse.pnd:type_name -> gosdn.pnd.PrincipalNetworkDomain - 21, // 11: gosdn.pnd.GetChangeResponse.change:type_name -> gosdn.pnd.Change - 19, // 12: gosdn.pnd.GetChangeListResponse.pnd:type_name -> gosdn.pnd.PrincipalNetworkDomain - 21, // 13: gosdn.pnd.GetChangeListResponse.change:type_name -> gosdn.pnd.Change - 39, // 14: gosdn.pnd.OrchestratedNetworkingDevice.device:type_name -> gnmi.Notification - 38, // 15: gosdn.pnd.OrchestratedNetworkingDevice.sbi:type_name -> gosdn.southbound.SouthboundInterface + 21, // 0: gosdn.pnd.GetOndResponse.pnd:type_name -> gosdn.pnd.PrincipalNetworkDomain + 22, // 1: gosdn.pnd.GetOndResponse.ond:type_name -> gosdn.pnd.OrchestratedNetworkingDevice + 21, // 2: gosdn.pnd.GetOndListResponse.pnd:type_name -> gosdn.pnd.PrincipalNetworkDomain + 22, // 3: gosdn.pnd.GetOndListResponse.ond:type_name -> gosdn.pnd.OrchestratedNetworkingDevice + 21, // 4: gosdn.pnd.GetSbiResponse.pnd:type_name -> gosdn.pnd.PrincipalNetworkDomain + 44, // 5: gosdn.pnd.GetSbiResponse.sbi:type_name -> gosdn.southbound.SouthboundInterface + 21, // 6: gosdn.pnd.GetSbiListResponse.pnd:type_name -> gosdn.pnd.PrincipalNetworkDomain + 44, // 7: gosdn.pnd.GetSbiListResponse.sbi:type_name -> gosdn.southbound.SouthboundInterface + 21, // 8: gosdn.pnd.GetPathResponse.pnd:type_name -> gosdn.pnd.PrincipalNetworkDomain + 45, // 9: gosdn.pnd.GetPathResponse.device:type_name -> gnmi.Notification + 21, // 10: gosdn.pnd.GetChangeResponse.pnd:type_name -> gosdn.pnd.PrincipalNetworkDomain + 23, // 11: gosdn.pnd.GetChangeResponse.change:type_name -> gosdn.pnd.Change + 21, // 12: gosdn.pnd.GetChangeListResponse.pnd:type_name -> gosdn.pnd.PrincipalNetworkDomain + 23, // 13: gosdn.pnd.GetChangeListResponse.change:type_name -> gosdn.pnd.Change + 45, // 14: gosdn.pnd.OrchestratedNetworkingDevice.device:type_name -> gnmi.Notification + 44, // 15: gosdn.pnd.OrchestratedNetworkingDevice.sbi:type_name -> gosdn.southbound.SouthboundInterface 0, // 16: gosdn.pnd.Change.state:type_name -> gosdn.pnd.ChangeState - 39, // 17: gosdn.pnd.Change.diff:type_name -> gnmi.Notification - 27, // 18: gosdn.pnd.SetOndListRequest.ond:type_name -> gosdn.pnd.SetOnd - 28, // 19: gosdn.pnd.SetSbiListRequest.sbi:type_name -> gosdn.pnd.SetSbi - 29, // 20: gosdn.pnd.SetChangeListRequest.change:type_name -> gosdn.pnd.SetChange - 26, // 21: gosdn.pnd.SetPathListRequest.change_request:type_name -> gosdn.pnd.ChangeRequest + 45, // 17: gosdn.pnd.Change.diff:type_name -> gnmi.Notification + 29, // 18: gosdn.pnd.SetOndListRequest.ond:type_name -> gosdn.pnd.SetOnd + 30, // 19: gosdn.pnd.SetSbiListRequest.sbi:type_name -> gosdn.pnd.SetSbi + 31, // 20: gosdn.pnd.SetChangeListRequest.change:type_name -> gosdn.pnd.SetChange + 28, // 21: gosdn.pnd.SetPathListRequest.change_request:type_name -> gosdn.pnd.ChangeRequest 1, // 22: gosdn.pnd.ChangeRequest.api_op:type_name -> gosdn.pnd.ApiOperation - 38, // 23: gosdn.pnd.SetOnd.sbi:type_name -> gosdn.southbound.SouthboundInterface - 40, // 24: gosdn.pnd.SetOnd.transport_option:type_name -> gosdn.transport.TransportOption + 44, // 23: gosdn.pnd.SetOnd.sbi:type_name -> gosdn.southbound.SouthboundInterface + 46, // 24: gosdn.pnd.SetOnd.transport_option:type_name -> gosdn.transport.TransportOption 2, // 25: gosdn.pnd.SetSbi.sbi_type:type_name -> gosdn.pnd.SbiType 3, // 26: gosdn.pnd.SetChange.op:type_name -> gosdn.pnd.Operation 4, // 27: gosdn.pnd.SetResponse.status:type_name -> gosdn.pnd.Status 4, // 28: gosdn.pnd.SetOndListResponse.status:type_name -> gosdn.pnd.Status - 30, // 29: gosdn.pnd.SetOndListResponse.responses:type_name -> gosdn.pnd.SetResponse + 32, // 29: gosdn.pnd.SetOndListResponse.responses:type_name -> gosdn.pnd.SetResponse 4, // 30: gosdn.pnd.SetChangeListResponse.status:type_name -> gosdn.pnd.Status - 30, // 31: gosdn.pnd.SetChangeListResponse.responses:type_name -> gosdn.pnd.SetResponse + 32, // 31: gosdn.pnd.SetChangeListResponse.responses:type_name -> gosdn.pnd.SetResponse 4, // 32: gosdn.pnd.SetChangeResponse.status:type_name -> gosdn.pnd.Status 4, // 33: gosdn.pnd.SetSbiListResponse.status:type_name -> gosdn.pnd.Status - 30, // 34: gosdn.pnd.SetSbiListResponse.responses:type_name -> gosdn.pnd.SetResponse + 32, // 34: gosdn.pnd.SetSbiListResponse.responses:type_name -> gosdn.pnd.SetResponse 4, // 35: gosdn.pnd.SetPathListResponse.status:type_name -> gosdn.pnd.Status - 30, // 36: gosdn.pnd.SetPathListResponse.responses:type_name -> gosdn.pnd.SetResponse + 32, // 36: gosdn.pnd.SetPathListResponse.responses:type_name -> gosdn.pnd.SetResponse 4, // 37: gosdn.pnd.DeleteOndResponse.status:type_name -> gosdn.pnd.Status - 5, // 38: gosdn.pnd.PndService.GetOndList:input_type -> gosdn.pnd.GetOndListRequest - 6, // 39: gosdn.pnd.PndService.GetOnd:input_type -> gosdn.pnd.GetOndRequest - 22, // 40: gosdn.pnd.PndService.SetOndList:input_type -> gosdn.pnd.SetOndListRequest - 7, // 41: gosdn.pnd.PndService.GetSbiList:input_type -> gosdn.pnd.GetSbiListRequest - 8, // 42: gosdn.pnd.PndService.GetSbi:input_type -> gosdn.pnd.GetSbiRequest - 23, // 43: gosdn.pnd.PndService.SetSbiList:input_type -> gosdn.pnd.SetSbiListRequest - 9, // 44: gosdn.pnd.PndService.GetChangeList:input_type -> gosdn.pnd.GetChangeListRequest - 10, // 45: gosdn.pnd.PndService.GetChange:input_type -> gosdn.pnd.GetChangeRequest - 24, // 46: gosdn.pnd.PndService.SetChangeList:input_type -> gosdn.pnd.SetChangeListRequest - 11, // 47: gosdn.pnd.PndService.GetPath:input_type -> gosdn.pnd.GetPathRequest - 25, // 48: gosdn.pnd.PndService.SetPathList:input_type -> gosdn.pnd.SetPathListRequest - 36, // 49: gosdn.pnd.PndService.DeleteOnd:input_type -> gosdn.pnd.DeleteOndRequest - 13, // 50: gosdn.pnd.PndService.GetOndList:output_type -> gosdn.pnd.GetOndListResponse - 12, // 51: gosdn.pnd.PndService.GetOnd:output_type -> gosdn.pnd.GetOndResponse - 31, // 52: gosdn.pnd.PndService.SetOndList:output_type -> gosdn.pnd.SetOndListResponse - 15, // 53: gosdn.pnd.PndService.GetSbiList:output_type -> gosdn.pnd.GetSbiListResponse - 14, // 54: gosdn.pnd.PndService.GetSbi:output_type -> gosdn.pnd.GetSbiResponse - 34, // 55: gosdn.pnd.PndService.SetSbiList:output_type -> gosdn.pnd.SetSbiListResponse - 18, // 56: gosdn.pnd.PndService.GetChangeList:output_type -> gosdn.pnd.GetChangeListResponse - 17, // 57: gosdn.pnd.PndService.GetChange:output_type -> gosdn.pnd.GetChangeResponse - 32, // 58: gosdn.pnd.PndService.SetChangeList:output_type -> gosdn.pnd.SetChangeListResponse - 16, // 59: gosdn.pnd.PndService.GetPath:output_type -> gosdn.pnd.GetPathResponse - 35, // 60: gosdn.pnd.PndService.SetPathList:output_type -> gosdn.pnd.SetPathListResponse - 37, // 61: gosdn.pnd.PndService.DeleteOnd:output_type -> gosdn.pnd.DeleteOndResponse - 50, // [50:62] is the sub-list for method output_type - 38, // [38:50] is the sub-list for method input_type - 38, // [38:38] is the sub-list for extension type_name - 38, // [38:38] is the sub-list for extension extendee - 0, // [0:38] is the sub-list for field type_name + 41, // 38: gosdn.pnd.SubscribePathRequest.sublist:type_name -> gosdn.pnd.SubscriptionList + 42, // 39: gosdn.pnd.SubscriptionList.subscription:type_name -> gosdn.pnd.Subscription + 5, // 40: gosdn.pnd.SubscriptionList.mode:type_name -> gosdn.pnd.SubscriptionMode + 6, // 41: gosdn.pnd.Subscription.stream_mode:type_name -> gosdn.pnd.StreamMode + 4, // 42: gosdn.pnd.SubscribePathResponse.status:type_name -> gosdn.pnd.Status + 45, // 43: gosdn.pnd.SubscribePathResponse.device:type_name -> gnmi.Notification + 7, // 44: gosdn.pnd.PndService.GetOndList:input_type -> gosdn.pnd.GetOndListRequest + 8, // 45: gosdn.pnd.PndService.GetOnd:input_type -> gosdn.pnd.GetOndRequest + 24, // 46: gosdn.pnd.PndService.SetOndList:input_type -> gosdn.pnd.SetOndListRequest + 9, // 47: gosdn.pnd.PndService.GetSbiList:input_type -> gosdn.pnd.GetSbiListRequest + 10, // 48: gosdn.pnd.PndService.GetSbi:input_type -> gosdn.pnd.GetSbiRequest + 25, // 49: gosdn.pnd.PndService.SetSbiList:input_type -> gosdn.pnd.SetSbiListRequest + 11, // 50: gosdn.pnd.PndService.GetChangeList:input_type -> gosdn.pnd.GetChangeListRequest + 12, // 51: gosdn.pnd.PndService.GetChange:input_type -> gosdn.pnd.GetChangeRequest + 26, // 52: gosdn.pnd.PndService.SetChangeList:input_type -> gosdn.pnd.SetChangeListRequest + 13, // 53: gosdn.pnd.PndService.GetPath:input_type -> gosdn.pnd.GetPathRequest + 27, // 54: gosdn.pnd.PndService.SetPathList:input_type -> gosdn.pnd.SetPathListRequest + 38, // 55: gosdn.pnd.PndService.DeleteOnd:input_type -> gosdn.pnd.DeleteOndRequest + 40, // 56: gosdn.pnd.PndService.SubscribePath:input_type -> gosdn.pnd.SubscribePathRequest + 15, // 57: gosdn.pnd.PndService.GetOndList:output_type -> gosdn.pnd.GetOndListResponse + 14, // 58: gosdn.pnd.PndService.GetOnd:output_type -> gosdn.pnd.GetOndResponse + 33, // 59: gosdn.pnd.PndService.SetOndList:output_type -> gosdn.pnd.SetOndListResponse + 17, // 60: gosdn.pnd.PndService.GetSbiList:output_type -> gosdn.pnd.GetSbiListResponse + 16, // 61: gosdn.pnd.PndService.GetSbi:output_type -> gosdn.pnd.GetSbiResponse + 36, // 62: gosdn.pnd.PndService.SetSbiList:output_type -> gosdn.pnd.SetSbiListResponse + 20, // 63: gosdn.pnd.PndService.GetChangeList:output_type -> gosdn.pnd.GetChangeListResponse + 19, // 64: gosdn.pnd.PndService.GetChange:output_type -> gosdn.pnd.GetChangeResponse + 34, // 65: gosdn.pnd.PndService.SetChangeList:output_type -> gosdn.pnd.SetChangeListResponse + 18, // 66: gosdn.pnd.PndService.GetPath:output_type -> gosdn.pnd.GetPathResponse + 37, // 67: gosdn.pnd.PndService.SetPathList:output_type -> gosdn.pnd.SetPathListResponse + 39, // 68: gosdn.pnd.PndService.DeleteOnd:output_type -> gosdn.pnd.DeleteOndResponse + 43, // 69: gosdn.pnd.PndService.SubscribePath:output_type -> gosdn.pnd.SubscribePathResponse + 57, // [57:70] is the sub-list for method output_type + 44, // [44:57] is the sub-list for method input_type + 44, // [44:44] is the sub-list for extension type_name + 44, // [44:44] is the sub-list for extension extendee + 0, // [0:44] is the sub-list for field type_name } func init() { file_gosdn_pnd_pnd_proto_init() } @@ -3290,14 +3719,62 @@ func file_gosdn_pnd_pnd_proto_init() { return nil } } + file_gosdn_pnd_pnd_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SubscribePathRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_pnd_pnd_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SubscriptionList); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_pnd_pnd_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Subscription); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_pnd_pnd_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SubscribePathResponse); 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_pnd_pnd_proto_rawDesc, - NumEnums: 5, - NumMessages: 33, + NumEnums: 7, + NumMessages: 37, NumExtensions: 0, NumServices: 1, }, diff --git a/api/go/gosdn/pnd/pnd_grpc.pb.go b/api/go/gosdn/pnd/pnd_grpc.pb.go index bc681280de05002ce2a8bcacb94bd30e6e03cc44..8f51b481ff262c48401f6c8a6d43472292914a51 100644 --- a/api/go/gosdn/pnd/pnd_grpc.pb.go +++ b/api/go/gosdn/pnd/pnd_grpc.pb.go @@ -51,6 +51,10 @@ type PndServiceClient interface { // Allows to delete a specific Orchestrated Networking Device which is managed by a // specific Principal Network Domain. DeleteOnd(ctx context.Context, in *DeleteOndRequest, opts ...grpc.CallOption) (*DeleteOndResponse, error) + // Allows to subscribe to multiple paths of an Orchestrated Networking Device which is + // managed by a specific Principal Network Domain and streams data depending on the subscribe + // method. + SubscribePath(ctx context.Context, in *SubscribePathRequest, opts ...grpc.CallOption) (PndService_SubscribePathClient, error) } type pndServiceClient struct { @@ -169,6 +173,38 @@ func (c *pndServiceClient) DeleteOnd(ctx context.Context, in *DeleteOndRequest, return out, nil } +func (c *pndServiceClient) SubscribePath(ctx context.Context, in *SubscribePathRequest, opts ...grpc.CallOption) (PndService_SubscribePathClient, error) { + stream, err := c.cc.NewStream(ctx, &PndService_ServiceDesc.Streams[0], "/gosdn.pnd.PndService/SubscribePath", opts...) + if err != nil { + return nil, err + } + x := &pndServiceSubscribePathClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type PndService_SubscribePathClient interface { + Recv() (*SubscribePathResponse, error) + grpc.ClientStream +} + +type pndServiceSubscribePathClient struct { + grpc.ClientStream +} + +func (x *pndServiceSubscribePathClient) Recv() (*SubscribePathResponse, error) { + m := new(SubscribePathResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + // PndServiceServer is the server API for PndService service. // All implementations must embed UnimplementedPndServiceServer // for forward compatibility @@ -206,6 +242,10 @@ type PndServiceServer interface { // Allows to delete a specific Orchestrated Networking Device which is managed by a // specific Principal Network Domain. DeleteOnd(context.Context, *DeleteOndRequest) (*DeleteOndResponse, error) + // Allows to subscribe to multiple paths of an Orchestrated Networking Device which is + // managed by a specific Principal Network Domain and streams data depending on the subscribe + // method. + SubscribePath(*SubscribePathRequest, PndService_SubscribePathServer) error mustEmbedUnimplementedPndServiceServer() } @@ -249,6 +289,9 @@ func (UnimplementedPndServiceServer) SetPathList(context.Context, *SetPathListRe func (UnimplementedPndServiceServer) DeleteOnd(context.Context, *DeleteOndRequest) (*DeleteOndResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method DeleteOnd not implemented") } +func (UnimplementedPndServiceServer) SubscribePath(*SubscribePathRequest, PndService_SubscribePathServer) error { + return status.Errorf(codes.Unimplemented, "method SubscribePath not implemented") +} func (UnimplementedPndServiceServer) mustEmbedUnimplementedPndServiceServer() {} // UnsafePndServiceServer may be embedded to opt out of forward compatibility for this service. @@ -478,6 +521,27 @@ func _PndService_DeleteOnd_Handler(srv interface{}, ctx context.Context, dec fun return interceptor(ctx, in, info, handler) } +func _PndService_SubscribePath_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(SubscribePathRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(PndServiceServer).SubscribePath(m, &pndServiceSubscribePathServer{stream}) +} + +type PndService_SubscribePathServer interface { + Send(*SubscribePathResponse) error + grpc.ServerStream +} + +type pndServiceSubscribePathServer struct { + grpc.ServerStream +} + +func (x *pndServiceSubscribePathServer) Send(m *SubscribePathResponse) error { + return x.ServerStream.SendMsg(m) +} + // PndService_ServiceDesc is the grpc.ServiceDesc for PndService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -534,6 +598,12 @@ var PndService_ServiceDesc = grpc.ServiceDesc{ Handler: _PndService_DeleteOnd_Handler, }, }, - Streams: []grpc.StreamDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "SubscribePath", + Handler: _PndService_SubscribePath_Handler, + ServerStreams: true, + }, + }, Metadata: "gosdn/pnd/pnd.proto", } diff --git a/api/openapiv2/gosdn_northbound.swagger.json b/api/openapiv2/gosdn_northbound.swagger.json index af22a6a6698f1af5938dafe014840b2d62e12995..69bed00d7edfeade732080856ea454d749ea902b 100644 --- a/api/openapiv2/gosdn_northbound.swagger.json +++ b/api/openapiv2/gosdn_northbound.swagger.json @@ -2892,6 +2892,46 @@ ], "default": "STATUS_UNSPECIFIED" }, + "gosdnpndSubscription": { + "type": "object", + "properties": { + "path": { + "type": "string" + }, + "streamMode": { + "$ref": "#/definitions/pndStreamMode" + }, + "sampleInterval": { + "type": "string", + "format": "uint64" + } + } + }, + "gosdnpndSubscriptionList": { + "type": "object", + "properties": { + "subscription": { + "type": "array", + "items": { + "$ref": "#/definitions/gosdnpndSubscription" + } + }, + "mode": { + "$ref": "#/definitions/gosdnpndSubscriptionMode" + } + }, + "title": "The mode determines how the target should trigger updates to be sent.\nReference: gNMI Specification Section 3.5.1.2" + }, + "gosdnpndSubscriptionMode": { + "type": "string", + "enum": [ + "SUBSCRIPTION_MODE_UNSPECIFIED", + "SUBSCRIPTION_MODE_ONCE", + "SUBSCRIPTION_MODE_STREAM", + "SUBSCRIPTION_MODE_POLL" + ], + "default": "SUBSCRIPTION_MODE_UNSPECIFIED" + }, "gosdnrbacRole": { "type": "object", "properties": { @@ -3310,6 +3350,34 @@ } } }, + "pndStreamMode": { + "type": "string", + "enum": [ + "STREAM_MODE_UNSPECIFIED", + "STREAM_MODE_TARGET_DEFINED", + "STREAM_MODE_ON_CHANGE", + "STREAM_MODE_SAMPLE" + ], + "default": "STREAM_MODE_UNSPECIFIED" + }, + "pndSubscribePathResponse": { + "type": "object", + "properties": { + "timestamp": { + "type": "string", + "format": "int64" + }, + "status": { + "$ref": "#/definitions/gosdnpndStatus" + }, + "device": { + "type": "array", + "items": { + "$ref": "#/definitions/gnmiNotification" + } + } + } + }, "protobufAny": { "type": "object", "properties": { diff --git a/api/proto/gosdn/pnd/pnd.proto b/api/proto/gosdn/pnd/pnd.proto index d68ef4940e68f6987808b4482fe8137136a9393f..6b3a8940f6a424395987a5f9b31a54535a712ff8 100644 --- a/api/proto/gosdn/pnd/pnd.proto +++ b/api/proto/gosdn/pnd/pnd.proto @@ -114,6 +114,10 @@ service PndService { delete: "/pnds/{pid}/onds/{did}" }; } + // Allows to subscribe to multiple paths of an Orchestrated Networking Device which is + // managed by a specific Principal Network Domain and streams data depending on the subscribe + // method. + rpc SubscribePath(SubscribePathRequest) returns (stream SubscribePathResponse) {}; } message GetOndListRequest { @@ -360,3 +364,44 @@ enum Status { STATUS_OK = 1; STATUS_ERROR = 2; } + +message SubscribePathRequest { + int64 timestamp = 1; // Timestamp in nanoseconds since Epoch. + string did = 2; + string pid = 3; + SubscriptionList sublist = 4; +} + +// The mode determines how the target should trigger updates to be sent. +// Reference: gNMI Specification Section 3.5.1.2 +message SubscriptionList { + repeated Subscription subscription = 1; + SubscriptionMode mode = 2; +} + +enum SubscriptionMode { + SUBSCRIPTION_MODE_UNSPECIFIED = 0; + SUBSCRIPTION_MODE_ONCE = 1; + SUBSCRIPTION_MODE_STREAM = 2; + SUBSCRIPTION_MODE_POLL = 3; +} + +message Subscription { + string path = 1; + StreamMode stream_mode = 2; + uint64 sample_interval = 3; // ns between samples in SAMPLE mode. +} + +enum StreamMode { + STREAM_MODE_UNSPECIFIED = 0; + STREAM_MODE_TARGET_DEFINED = 1; // The target selects the relevant mode for each element. + STREAM_MODE_ON_CHANGE = 2; // The target sends an update on element value change. + STREAM_MODE_SAMPLE = 3; // The target samples values according to the interval. +} + + +message SubscribePathResponse { + int64 timestamp = 1; // Timestamp in nanoseconds since Epoch. + Status status = 2; + repeated gnmi.Notification device = 3; +} diff --git a/cli/adapter/PndAdapter.go b/cli/adapter/PndAdapter.go index a02ac56ea36adfc4f457dd03484b76fbf1d8e8fa..9d39456be20e8676541b5e15943bc32508f702f9 100644 --- a/cli/adapter/PndAdapter.go +++ b/cli/adapter/PndAdapter.go @@ -127,6 +127,16 @@ func (p *PndAdapter) Request(ctx context.Context, did uuid.UUID, path string) (* return resp, nil } +// SubscribeONDPath sends an API call to the controller requesting to subscribe +// to a specific path of a specifc device +func (p *PndAdapter) SubscribeONDPath(ctx context.Context, did uuid.UUID, slist *ppb.SubscriptionList) (ppb.PndService_SubscribePathClient, error) { + resp, err := api.SubscribePath(ctx, p.endpoint, p.id.String(), did.String(), slist) + if err != nil { + return nil, err + } + return resp, nil +} + // RequestAll sends an API call to the controller requesting the specified path // for all registered devices. Not yet implemented. func (p *PndAdapter) RequestAll(ctx context.Context, path string) ([]proto.Message, error) { diff --git a/cli/cmd/deviceSubscribe.go b/cli/cmd/deviceSubscribe.go new file mode 100644 index 0000000000000000000000000000000000000000..e3718790bf9d233ca9389048ae629148b785d4ac --- /dev/null +++ b/cli/cmd/deviceSubscribe.go @@ -0,0 +1,103 @@ +/* +Copyright © 2021 da/net research group <danet.fbi.h-da.de> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +package cmd + +import ( + "io" + + "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd" + "github.com/google/uuid" + "github.com/pterm/pterm" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" +) + +// deviceGetCmd represents the get command +var deviceSubscribeCmd = &cobra.Command{ + Use: "subscribe [uuid] [path]", + Args: cobra.ExactArgs(2), + Short: "Subscribes to paths of a provided device with fixed subscribe options", + Long: `Requests a subscription on paths from a specified orchestrated network device on the controller. +The device UUID and requested paths must be specified as a positional arguments.`, + + RunE: func(cmd *cobra.Command, args []string) error { + did, err := uuid.Parse(args[0]) + if err != nil { + pterm.Error.Println(err) + return err + } + + subClient, err := pndAdapter.SubscribeONDPath( + createContextWithAuthorization(), + did, + &pnd.SubscriptionList{ + Subscription: []*pnd.Subscription{ + { + Path: args[1], + StreamMode: pnd.StreamMode_STREAM_MODE_SAMPLE, + SampleInterval: 1000000000, + }, + }, + Mode: pnd.SubscriptionMode_SUBSCRIPTION_MODE_STREAM, + }, + ) + if err != nil { + pterm.Error.Println(err) + return err + } + + for i := 0; i < 5; i++ { + subscribeResponse, err := subClient.Recv() + if err != nil { + if err != nil { + if err == io.EOF { + break + } + log.Error(err) + + closeErr := subClient.CloseSend() + if closeErr != nil { + log.Error(err) + } + } + } + + pterm.Println(subscribeResponse.String()) + } + + return nil + }, +} + +func init() { + deviceCmd.AddCommand(deviceSubscribeCmd) +} diff --git a/controller/api/device.go b/controller/api/device.go index 22f51cf7d71e4330fa9c4e061f19b74083dbdd44..35f211724d87cef0111344c9bc116196643b869e 100644 --- a/controller/api/device.go +++ b/controller/api/device.go @@ -152,6 +152,24 @@ func GetPath(ctx context.Context, addr, pid, did, path string) (*ppb.GetPathResp return pndClient.GetPath(ctx, req) } +// SubscribePath subscribes to paths on a device +func SubscribePath(ctx context.Context, addr, pid, did string, slist *ppb.SubscriptionList) (ppb.PndService_SubscribePathClient, error) { + log.Println("subscribePath called") + pndClient, err := nbi.PndClient(addr, dialOptions...) + if err != nil { + return nil, err + } + + req := &ppb.SubscribePathRequest{ + Timestamp: time.Now().UnixNano(), + Did: did, + Pid: pid, + Sublist: slist, + } + + return pndClient.SubscribePath(ctx, req) +} + // DeleteDevice deletes a device func DeleteDevice(ctx context.Context, addr, pid, did string) (*ppb.DeleteOndResponse, error) { pndClient, err := nbi.PndClient(addr, dialOptions...) diff --git a/controller/controller.go b/controller/controller.go index 923ded438b508ecbede74717f0df556b82f5ad55..7b48477b18b757da291167d04e19711e7ba9b9af 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -59,6 +59,7 @@ type Core struct { grpcServer *grpc.Server nbi *nbi.NorthboundInterface eventService eventInterfaces.Service + deviceWatcher *nucleus.DeviceWatcher stopChan chan os.Signal csbiClient cpb.CsbiServiceClient @@ -105,6 +106,10 @@ func initialize() error { return err } + c.deviceWatcher = nucleus.NewDeviceWatcher(c.pndStore) + // TODO: udpate with actual paths to subscribe to using template/config + c.deviceWatcher.SubToDevices([][]string{{"system", "config", "hostname"}}, nil) + err = ensureDefaultRoleExists() if err != nil { return err @@ -242,6 +247,7 @@ func ensureDefaultRoleExists() error { "/gosdn.pnd.PndService/SetPathList", "/gosdn.pnd.PndService/SetSbiList", "/gosdn.pnd.PndService/DeleteOnd", + "/gosdn.pnd.PndService/SubscribePath", "/gosdn.southbound.SbiService/GetSchema", })) if err != nil { diff --git a/controller/eventService/Service.go b/controller/eventService/Service.go index 5c13102d4926f0246cf2c250fe009fa72de3ca9b..c4d00cc9cf3ab4376c8906cb29e18d18227df018 100644 --- a/controller/eventService/Service.go +++ b/controller/eventService/Service.go @@ -10,6 +10,7 @@ import ( interfaces "code.fbi.h-da.de/danet/gosdn/controller/interfaces/event" amqp "github.com/rabbitmq/amqp091-go" + log "github.com/sirupsen/logrus" ) // EventService is used to setup a connection to a broker and publish events to topics. @@ -78,5 +79,7 @@ func (e *EventService) PublishEvent(topic string, event event.Event) error { // CloseConnection closes an exisiting connection. func (e *EventService) CloseConnection() { - e.connection.Close() + if err := e.connection.Close(); err != nil { + log.Error(err) + } } diff --git a/controller/interfaces/networkdomain/pnd.go b/controller/interfaces/networkdomain/pnd.go index ed2c7f1079605f0327e84b530deee5a37e443349..750cd46ff1f4b0684c84fe91486618e35daad3a9 100644 --- a/controller/interfaces/networkdomain/pnd.go +++ b/controller/interfaces/networkdomain/pnd.go @@ -35,4 +35,6 @@ type NetworkDomain interface { GetChange(uuid.UUID) (change.Change, error) Commit(uuid.UUID) error Confirm(uuid.UUID) error + SubscribePath(uuid.UUID, *ppb.SubscriptionList) error + UpdateDeviceAfterSubscribeResponse(device.Device) error } diff --git a/controller/interfaces/transport/transport.go b/controller/interfaces/transport/transport.go index 8e32f357fff138ccc8c8248625951779efa41e5a..2822639fad82fee21a03ecde9e50ed147062694c 100644 --- a/controller/interfaces/transport/transport.go +++ b/controller/interfaces/transport/transport.go @@ -16,6 +16,24 @@ type Transport interface { Set(ctx context.Context, payload change.Payload, path string, schema *ytypes.Schema) error CustomSet(ctx context.Context, req *gpb.SetRequest) (*gpb.SetResponse, error) Subscribe(ctx context.Context, params ...string) error + ControlPlaneSubscribe(ctx context.Context, subscribeCallbackFunc HandleSubscribeResponse, + subscriptionInfo *SubscriptionInformation) error Type() string ProcessResponse(resp interface{}, root interface{}, models *ytypes.Schema) error + ProcessControlPlaneSubscribeResponse(resp *gpb.SubscribeResponse_Update, root any, schema *ytypes.Schema) error +} + +type ( + // HandleSubscribeResponse is the callback function to handle subcription responses + HandleSubscribeResponse func(*gpb.SubscribeResponse, *SubscriptionInformation) +) + +// SubscriptionInformation contains additional information used for internal subscriptions +// for distinguishing from which device the information is from, to stop subscriptions and +// error handling +type SubscriptionInformation struct { + PndID string + DeviceID string + DeviceName string + StopContext context.Context } diff --git a/controller/mocks/HandleSubscribeResponse.go b/controller/mocks/HandleSubscribeResponse.go new file mode 100644 index 0000000000000000000000000000000000000000..07d3feeda850107c25b8b08f6eef12d20d3c7a02 --- /dev/null +++ b/controller/mocks/HandleSubscribeResponse.go @@ -0,0 +1,35 @@ +// Code generated by mockery v2.14.0. DO NOT EDIT. + +package mocks + +import ( + gnmi "github.com/openconfig/gnmi/proto/gnmi" + mock "github.com/stretchr/testify/mock" + + transport "code.fbi.h-da.de/danet/gosdn/controller/interfaces/transport" +) + +// HandleSubscribeResponse is an autogenerated mock type for the HandleSubscribeResponse type +type HandleSubscribeResponse struct { + mock.Mock +} + +// Execute provides a mock function with given fields: _a0, _a1 +func (_m *HandleSubscribeResponse) Execute(_a0 *gnmi.SubscribeResponse, _a1 *transport.SubscriptionInformation) { + _m.Called(_a0, _a1) +} + +type mockConstructorTestingTNewHandleSubscribeResponse interface { + mock.TestingT + Cleanup(func()) +} + +// NewHandleSubscribeResponse creates a new instance of HandleSubscribeResponse. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewHandleSubscribeResponse(t mockConstructorTestingTNewHandleSubscribeResponse) *HandleSubscribeResponse { + mock := &HandleSubscribeResponse{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/controller/mocks/NetworkDomain.go b/controller/mocks/NetworkDomain.go index 2455cbb107a8c16361a9d004ddd51b845062d193..c4c289f1abcaed9dfbbc263fbc46a095394f445e 100644 --- a/controller/mocks/NetworkDomain.go +++ b/controller/mocks/NetworkDomain.go @@ -403,6 +403,20 @@ func (_m *NetworkDomain) RequestAll(_a0 string) error { return r0 } +// SubscribePath provides a mock function with given fields: _a0, _a1 +func (_m *NetworkDomain) SubscribePath(_a0 uuid.UUID, _a1 *pnd.SubscriptionList) error { + ret := _m.Called(_a0, _a1) + + var r0 error + if rf, ok := ret.Get(0).(func(uuid.UUID, *pnd.SubscriptionList) error); ok { + r0 = rf(_a0, _a1) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // UpdateDevice provides a mock function with given fields: _a0, _a1 func (_m *NetworkDomain) UpdateDevice(_a0 device.Device, _a1 string) error { ret := _m.Called(_a0, _a1) @@ -417,6 +431,20 @@ func (_m *NetworkDomain) UpdateDevice(_a0 device.Device, _a1 string) error { return r0 } +// UpdateDeviceAfterSubscribeResponse provides a mock function with given fields: _a0 +func (_m *NetworkDomain) UpdateDeviceAfterSubscribeResponse(_a0 device.Device) error { + ret := _m.Called(_a0) + + var r0 error + if rf, ok := ret.Get(0).(func(device.Device) error); ok { + r0 = rf(_a0) + } else { + r0 = ret.Error(0) + } + + return r0 +} + type mockConstructorTestingTNewNetworkDomain interface { mock.TestingT Cleanup(func()) diff --git a/controller/mocks/Store.go b/controller/mocks/Store.go index 6ce0fd98513a962eeea46f362bd24474bcdc99db..f8f71cd7da2b2719058248e965e8a591a1d3f764 100644 --- a/controller/mocks/Store.go +++ b/controller/mocks/Store.go @@ -3,8 +3,8 @@ package mocks import ( - store "code.fbi.h-da.de/danet/gosdn/controller/interfaces/store" - uuid "github.com/google/uuid" + southbound "code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound" + store "code.fbi.h-da.de/danet/gosdn/controller/store" mock "github.com/stretchr/testify/mock" ) @@ -13,13 +13,13 @@ type Store struct { mock.Mock } -// Add provides a mock function with given fields: item -func (_m *Store) Add(item store.Storable) error { - ret := _m.Called(item) +// Add provides a mock function with given fields: _a0 +func (_m *Store) Add(_a0 southbound.SouthboundInterface) error { + ret := _m.Called(_a0) var r0 error - if rf, ok := ret.Get(0).(func(store.Storable) error); ok { - r0 = rf(item) + if rf, ok := ret.Get(0).(func(southbound.SouthboundInterface) error); ok { + r0 = rf(_a0) } else { r0 = ret.Error(0) } @@ -27,13 +27,13 @@ func (_m *Store) Add(item store.Storable) error { return r0 } -// Delete provides a mock function with given fields: id -func (_m *Store) Delete(id uuid.UUID) error { - ret := _m.Called(id) +// Delete provides a mock function with given fields: _a0 +func (_m *Store) Delete(_a0 southbound.SouthboundInterface) error { + ret := _m.Called(_a0) var r0 error - if rf, ok := ret.Get(0).(func(uuid.UUID) error); ok { - r0 = rf(id) + if rf, ok := ret.Get(0).(func(southbound.SouthboundInterface) error); ok { + r0 = rf(_a0) } else { r0 = ret.Error(0) } @@ -41,36 +41,20 @@ func (_m *Store) Delete(id uuid.UUID) error { return r0 } -// Exists provides a mock function with given fields: id -func (_m *Store) Exists(id uuid.UUID) bool { - ret := _m.Called(id) +// Get provides a mock function with given fields: _a0 +func (_m *Store) Get(_a0 store.Query) (southbound.LoadedSbi, error) { + ret := _m.Called(_a0) - var r0 bool - if rf, ok := ret.Get(0).(func(uuid.UUID) bool); ok { - r0 = rf(id) + var r0 southbound.LoadedSbi + if rf, ok := ret.Get(0).(func(store.Query) southbound.LoadedSbi); ok { + r0 = rf(_a0) } else { - r0 = ret.Get(0).(bool) - } - - return r0 -} - -// Get provides a mock function with given fields: id -func (_m *Store) Get(id uuid.UUID) (store.Storable, error) { - ret := _m.Called(id) - - var r0 store.Storable - if rf, ok := ret.Get(0).(func(uuid.UUID) store.Storable); ok { - r0 = rf(id) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(store.Storable) - } + r0 = ret.Get(0).(southbound.LoadedSbi) } var r1 error - if rf, ok := ret.Get(1).(func(uuid.UUID) error); ok { - r1 = rf(id) + if rf, ok := ret.Get(1).(func(store.Query) error); ok { + r1 = rf(_a0) } else { r1 = ret.Error(1) } @@ -78,20 +62,27 @@ func (_m *Store) Get(id uuid.UUID) (store.Storable, error) { return r0, r1 } -// UUIDs provides a mock function with given fields: -func (_m *Store) UUIDs() []uuid.UUID { +// GetAll provides a mock function with given fields: +func (_m *Store) GetAll() ([]southbound.LoadedSbi, error) { ret := _m.Called() - var r0 []uuid.UUID - if rf, ok := ret.Get(0).(func() []uuid.UUID); ok { + var r0 []southbound.LoadedSbi + if rf, ok := ret.Get(0).(func() []southbound.LoadedSbi); ok { r0 = rf() } else { if ret.Get(0) != nil { - r0 = ret.Get(0).([]uuid.UUID) + r0 = ret.Get(0).([]southbound.LoadedSbi) } } - return r0 + var r1 error + if rf, ok := ret.Get(1).(func() error); ok { + r1 = rf() + } else { + r1 = ret.Error(1) + } + + return r0, r1 } type mockConstructorTestingTNewStore interface { diff --git a/controller/mocks/Transport.go b/controller/mocks/Transport.go index 6062bf4c5a646c79782bfb0d0a16feca25ebfa3e..d6961a3fb977757487dd33ffcdbcfe71c9c420d5 100644 --- a/controller/mocks/Transport.go +++ b/controller/mocks/Transport.go @@ -11,6 +11,8 @@ import ( mock "github.com/stretchr/testify/mock" + transport "code.fbi.h-da.de/danet/gosdn/controller/interfaces/transport" + ytypes "github.com/openconfig/ygot/ytypes" ) @@ -19,6 +21,20 @@ type Transport struct { mock.Mock } +// ControlPlaneSubscribe provides a mock function with given fields: ctx, subscribeCallbackFunc, subscriptionInfo +func (_m *Transport) ControlPlaneSubscribe(ctx context.Context, subscribeCallbackFunc transport.HandleSubscribeResponse, subscriptionInfo *transport.SubscriptionInformation) error { + ret := _m.Called(ctx, subscribeCallbackFunc, subscriptionInfo) + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, transport.HandleSubscribeResponse, *transport.SubscriptionInformation) error); ok { + r0 = rf(ctx, subscribeCallbackFunc, subscriptionInfo) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // CustomSet provides a mock function with given fields: ctx, req func (_m *Transport) CustomSet(ctx context.Context, req *gnmi.SetRequest) (*gnmi.SetResponse, error) { ret := _m.Called(ctx, req) @@ -72,6 +88,20 @@ func (_m *Transport) Get(ctx context.Context, params ...string) (interface{}, er return r0, r1 } +// ProcessControlPlaneSubscribeResponse provides a mock function with given fields: resp, root, schema +func (_m *Transport) ProcessControlPlaneSubscribeResponse(resp *gnmi.SubscribeResponse_Update, root interface{}, schema *ytypes.Schema) error { + ret := _m.Called(resp, root, schema) + + var r0 error + if rf, ok := ret.Get(0).(func(*gnmi.SubscribeResponse_Update, interface{}, *ytypes.Schema) error); ok { + r0 = rf(resp, root, schema) + } else { + r0 = ret.Error(0) + } + + return r0 +} + // ProcessResponse provides a mock function with given fields: resp, root, models func (_m *Transport) ProcessResponse(resp interface{}, root interface{}, models *ytypes.Schema) error { ret := _m.Called(resp, root, models) diff --git a/controller/northbound/server/pnd.go b/controller/northbound/server/pnd.go index 5124730e44bda354d81c0433a395783a5221b462..7b88166d9bf5379bdb4fc03f60b2dc7ffcce7200 100644 --- a/controller/northbound/server/pnd.go +++ b/controller/northbound/server/pnd.go @@ -652,3 +652,27 @@ func (p PndServer) DeleteOnd(ctx context.Context, request *ppb.DeleteOndRequest) Status: ppb.Status_STATUS_OK, }, nil } + +// SubscribePath subscribes to specifc paths of an ond +func (p PndServer) SubscribePath(request *ppb.SubscribePathRequest, stream ppb.PndService_SubscribePathServer) error { + pid, err := uuid.Parse(request.Pid) + if err != nil { + return err + } + + pnd, err := p.pndStore.Get(store.Query{ID: pid}) + if err != nil { + return err + } + + did, err := uuid.Parse(request.Did) + if err != nil { + return err + } + + if err := pnd.SubscribePath(did, request.Sublist); err != nil { + return err + } + + return nil +} diff --git a/controller/nucleus/deviceWatcher.go b/controller/nucleus/deviceWatcher.go new file mode 100644 index 0000000000000000000000000000000000000000..de7f135afb62ca2fab0f69d823985acd3e246b38 --- /dev/null +++ b/controller/nucleus/deviceWatcher.go @@ -0,0 +1,168 @@ +package nucleus + +import ( + "context" + "fmt" + + "code.fbi.h-da.de/danet/gosdn/controller/interfaces/device" + "code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkdomain" + "code.fbi.h-da.de/danet/gosdn/controller/interfaces/transport" + "code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors" + "code.fbi.h-da.de/danet/gosdn/controller/nucleus/types" + "code.fbi.h-da.de/danet/gosdn/controller/store" + "code.fbi.h-da.de/danet/gosdn/forks/goarista/gnmi" + "github.com/google/uuid" + gpb "github.com/openconfig/gnmi/proto/gnmi" + log "github.com/sirupsen/logrus" +) + +const ( + subscribeSampleInterval uint64 = 1000000000 // 1 second in nanoseconds + // TODO: These gNMI options are adjusted to arista gNMI fork. Change when switching to native gNMI. + gNMISubscribeMode string = "stream" + gNMIStreamMode string = "on_change" +) + +// DeviceWatcher is a component that subscribes to devices via gNMI from within the controller and handles +// responses by triggering the internal event process. +type DeviceWatcher struct { + pndStore networkdomain.PndStore + deviceSubcriptions map[uuid.UUID]*deviceSubscriptionHelper +} + +// deviceSubscriptionHelper is used to store information to stop a running subscribe go routine. +type deviceSubscriptionHelper struct { + stopSubscribeCtx context.Context + stopFunc context.CancelFunc +} + +// NewDeviceWatcher takes a pndStore to subscribe to device paths. +func NewDeviceWatcher(pndStore networkdomain.PndStore) *DeviceWatcher { + return &DeviceWatcher{ + pndStore: pndStore, + deviceSubcriptions: make(map[uuid.UUID]*deviceSubscriptionHelper), + } +} + +// SubToDevices subscribes to every available device in each network domain according to provided SubscribeOptions. +// Paths should be provided in the following format [][]string{{"system", "config", "hostname"}} +// SubscribeOptions can be nil. Use nil for a fixed, pre-defined set of gNMI subscription options (streaming in sample mode each second). +func (d *DeviceWatcher) SubToDevices(paths [][]string, opts *gnmi.SubscribeOptions) { + if opts == nil { + opts = &gnmi.SubscribeOptions{ + Mode: gNMISubscribeMode, + StreamMode: gNMIStreamMode, + Paths: paths, + SampleInterval: subscribeSampleInterval, + } + } + + pnds, err := d.pndStore.GetAll() + if err != nil { + log.Error(err) + } + + for _, pnd := range pnds { + d.subscribeToPndDevices(pnd.ID().String(), pnd, opts) + } +} + +func (d *DeviceWatcher) subscribeToPndDevices(pndID string, pnd networkdomain.NetworkDomain, opts *gnmi.SubscribeOptions) { + for _, device := range pnd.Devices() { + subID := uuid.New() + + stopContext, cancel := context.WithCancel(context.Background()) + d.addToDeviceSubscriptions(subID, &deviceSubscriptionHelper{ + stopSubscribeCtx: stopContext, + stopFunc: cancel, + }) + go d.callSubscribe(stopContext, pndID, device, opts) + } +} + +func (d *DeviceWatcher) callSubscribe(stopContext context.Context, pndID string, device device.Device, opts *gnmi.SubscribeOptions) { + gNMIOptionsCtx := context.Background() + gNMIOptionsCtx = context.WithValue(gNMIOptionsCtx, types.CtxKeyOpts, opts) + + // SubscriptionInformation contains pnd ID, device ID and name to be used in the internal subscribe to check + // from which device a response was sent + if err := device.Transport().ControlPlaneSubscribe(gNMIOptionsCtx, d.handleSubscribeResponse, &transport.SubscriptionInformation{ + PndID: pndID, + DeviceID: device.ID().String(), + DeviceName: device.Name(), + StopContext: stopContext, + }); err != nil { + log.Error(err) + } +} + +func (d *DeviceWatcher) addToDeviceSubscriptions(subID uuid.UUID, devSub *deviceSubscriptionHelper) { + //TODO: improve handling of subscriptions, like be able to expose to apps so specific subscriptions instead of only all can be stopped in the future + d.deviceSubcriptions[subID] = devSub +} + +// StopAndRemoveAllDeviceSubscriptions stops and removes all the available running subscriptions. +func (d *DeviceWatcher) StopAndRemoveAllDeviceSubscriptions() { + for key := range d.deviceSubcriptions { + d.StopAndRemoveDeviceSubscription(key) + } +} + +// StopAndRemoveDeviceSubscription passes a subscription uuid to stop the running subscription go routing and removes the entry from the map +// of device subscriptions. +func (d *DeviceWatcher) StopAndRemoveDeviceSubscription(subID uuid.UUID) { + d.deviceSubcriptions[subID].stopFunc() + delete(d.deviceSubcriptions, subID) +} + +// handleSubscribeResponse takes the subscribe response and additional information about the device to distinguish +// from which device a subscribe response was sent including improved error handling +func (d *DeviceWatcher) handleSubscribeResponse(resp *gpb.SubscribeResponse, subscriptionInfo *transport.SubscriptionInformation) { + switch resp := resp.Response.(type) { + case *gpb.SubscribeResponse_Error: + log.Error(&errors.ErrSubscribeResponse{ + PndID: subscriptionInfo.PndID, + DeviceID: subscriptionInfo.DeviceID, + DeviceName: subscriptionInfo.DeviceName, + Err: fmt.Sprintf("SubscribeResponse_Error"), + }) + case *gpb.SubscribeResponse_SyncResponse: + if !resp.SyncResponse { + log.Error(&errors.ErrSubscribeSyncResponse{ + PndID: subscriptionInfo.PndID, + DeviceID: subscriptionInfo.DeviceID, + DeviceName: subscriptionInfo.DeviceName, + }) + } + case *gpb.SubscribeResponse_Update: + d.handleSubscribeResponseUpdate(resp, subscriptionInfo) + default: + log.Infof("Invalid SubscribeResponse, %v", resp) + } +} + +func (d *DeviceWatcher) handleSubscribeResponseUpdate(resp *gpb.SubscribeResponse_Update, subscriptionInfo *transport.SubscriptionInformation) { + pndID, err := uuid.Parse(subscriptionInfo.PndID) + if err != nil { + log.Error(err) + } + + pnd, err := d.pndStore.Get(store.Query{ID: pndID}) + if err != nil { + log.Error(err) + } + + device, err := pnd.GetDevice(subscriptionInfo.DeviceID) + if err != nil { + log.Error(err) + } + + err = device.Transport().ProcessControlPlaneSubscribeResponse(resp, device.GetModel(), device.SBI().Schema()) + if err != nil { + log.Error(err) + } else { + if err := pnd.UpdateDeviceAfterSubscribeResponse(device); err != nil { + log.Error(err) + } + } +} diff --git a/controller/nucleus/errors/errors.go b/controller/nucleus/errors/errors.go index d155b6950024a187d6b97a467c3f282acc627de0..254cb165389ff596a289d04981c8fefc799aa2f9 100644 --- a/controller/nucleus/errors/errors.go +++ b/controller/nucleus/errors/errors.go @@ -251,3 +251,28 @@ type ErrAMQPMessageFail struct { func (e ErrAMQPMessageFail) Error() string { return fmt.Sprintf("Action: %s, Internal error: %v", e.Action, e.Err) } + +// ErrSubscribeResponse implements the Error interface and is called if there is an issue during a ongoing +// gNMI Subscription. +type ErrSubscribeResponse struct { + PndID string + DeviceID string + DeviceName string + Err string +} + +func (e ErrSubscribeResponse) Error() string { + return fmt.Sprintf("Subscribe failed, PndID: %s, DeviceID: %s, DeviceName: %s, Internal error: %s", e.PndID, e.DeviceID, e.DeviceName, e.Err) +} + +// ErrSubscribeSyncResponse implements the Error interface and is called if there is an issue syncing a +// gNMI Subscription. +type ErrSubscribeSyncResponse struct { + PndID string + DeviceID string + DeviceName string +} + +func (e ErrSubscribeSyncResponse) Error() string { + return fmt.Sprintf("Sync failed, PndID: %s, DeviceID: %s, DeviceName: %s", e.PndID, e.DeviceID, e.DeviceName) +} diff --git a/controller/nucleus/gnmi_transport.go b/controller/nucleus/gnmi_transport.go index 5e5b94a990ad974fe36ce74dd9d1768bc004359e..029c33fa15681c318156187127cce98dd6b134a6 100644 --- a/controller/nucleus/gnmi_transport.go +++ b/controller/nucleus/gnmi_transport.go @@ -5,6 +5,7 @@ import ( "fmt" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/change" + tpInterface "code.fbi.h-da.de/danet/gosdn/controller/interfaces/transport" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound" @@ -202,6 +203,16 @@ func (g *Gnmi) Subscribe(ctx context.Context, params ...string) error { return g.subscribe(ctx) } +// ControlPlaneSubscribe is used to subscribe to devices from within the controller. gNMI SubscribeOptions need to be provided in the context, +// the callback function handles the responses received from the subscription. +func (g *Gnmi) ControlPlaneSubscribe(ctx context.Context, subscribeCallbackFunc tpInterface.HandleSubscribeResponse, subscriptionInfo *tpInterface.SubscriptionInformation) error { + if g.client == nil { + return &errors.ErrNilClient{} + } + + return g.controlPlaneSubscribe(ctx, subscribeCallbackFunc, subscriptionInfo) +} + // Type returns the gNMI transport type func (g *Gnmi) Type() string { return "gnmi" @@ -226,36 +237,103 @@ func (g *Gnmi) ProcessResponse(resp interface{}, root interface{}, s *ytypes.Sch } } rn := r.Notification - errs := make([]error, 0) for _, msg := range rn { - for _, update := range msg.Update { - path := update.Path - switch val := update.Val.Value.(type) { - case *gpb.TypedValue_JsonVal: - opts := []ytypes.UnmarshalOpt{&ytypes.IgnoreExtraFields{}} - if err := g.Unmarshal(val.JsonVal, path, d, opts...); err != nil { - errs = append(errs, err) - } - case *gpb.TypedValue_JsonIetfVal: - opts := []ytypes.UnmarshalOpt{&ytypes.IgnoreExtraFields{}} - if err := g.Unmarshal(val.JsonIetfVal, path, d, opts...); err != nil { - errs = append(errs, err) - } - default: - schema := s.RootSchema() - opts := []ytypes.SetNodeOpt{&ytypes.InitMissingElements{}, &ytypes.TolerateJSONInconsistencies{}} - if err := g.SetNode(schema, root, update.Path, update.Val, opts...); err != nil { - errs = append(errs, err) - } + if err := g.processResponseUpdates(msg.Update, d, root.(ygot.ValidatedGoStruct), s); err != nil { + return err + } + } + + return nil +} + +// ProcessControlPlaneSubscribeResponse processes the gNMI notification within the subscribe response, updating the provided device model. +func (g *Gnmi) ProcessControlPlaneSubscribeResponse(resp *gpb.SubscribeResponse_Update, root any, schema *ytypes.Schema) error { + dModel, ok := root.(ygot.ValidatedGoStruct) + if !ok { + return &errors.ErrInvalidTypeAssertion{ + Value: root, + Type: (*ygot.ValidatedGoStruct)(nil), + } + } + + notification := resp.Update + + if len(notification.Update) > 0 { + if err := g.processResponseUpdates(notification.Update, dModel, root.(ygot.ValidatedGoStruct), schema); err != nil { + return err + } + } + + if len(notification.Delete) > 0 { + if err := g.processResponseDeletes(notification.Delete, dModel, schema); err != nil { + return err + } + } + + return nil +} + +func (g *Gnmi) processResponseUpdates(updates []*gpb.Update, deviceModel ygot.ValidatedGoStruct, root ygot.ValidatedGoStruct, s *ytypes.Schema) error { + errs := make([]error, 0) + + for _, update := range updates { + path := update.Path + switch val := update.Val.Value.(type) { + case *gpb.TypedValue_JsonVal: + opts := []ytypes.UnmarshalOpt{&ytypes.IgnoreExtraFields{}} + if err := g.Unmarshal(val.JsonVal, path, deviceModel, opts...); err != nil { + errs = append(errs, err) + } + case *gpb.TypedValue_JsonIetfVal: + opts := []ytypes.UnmarshalOpt{&ytypes.IgnoreExtraFields{}} + if err := g.Unmarshal(val.JsonIetfVal, path, deviceModel, opts...); err != nil { + errs = append(errs, err) + } + default: + schema := s.RootSchema() + opts := []ytypes.SetNodeOpt{&ytypes.InitMissingElements{}, &ytypes.TolerateJSONInconsistencies{}} + if err := g.SetNode(schema, root, update.Path, update.Val, opts...); err != nil { + errs = append(errs, err) } } } + + if len(errs) != 0 { + return handleProcessResponseErrors(errs) + } + + return nil +} + +func handleProcessResponseErrors(errs []error) error { for _, e := range errs { log.Error(e) } - if len(errs) != 0 { - return fmt.Errorf("encountered %v errors during response processing\n%v", len(errs), errs) + + return fmt.Errorf("encountered %v errors during response processing\n%v", len(errs), errs) +} + +func (g *Gnmi) processResponseDeletes(deletes []*gpb.Path, deviceModel ygot.ValidatedGoStruct, rootSchema *ytypes.Schema) error { + if err := ytypes.DeleteNode(rootSchema.RootSchema(), deviceModel, deletes[0]); err != nil { + return err + } + modelAsString, _ := ygot.EmitJSON(deviceModel, &ygot.EmitJSONConfig{ + Format: ygot.RFC7951, + Indent: "", + SkipValidation: true, + RFC7951Config: &ygot.RFC7951JSONConfig{ + AppendModuleName: true, + }}) + + rootPath, err := ygot.StringToStructuredPath("/") + if err != nil { + return err } + + if err := g.Unmarshal([]byte(modelAsString), rootPath, deviceModel); err != nil { + return err + } + return nil } @@ -301,7 +379,7 @@ func (g *Gnmi) getWithRequest(ctx context.Context, req *gpb.GetRequest) (interfa return resp, nil } -// Subscribe calls GNMI subscribe +// subscribe calls GNMI subscribe. func (g *Gnmi) subscribe(ctx context.Context) error { ctx = gnmi.NewContext(ctx, g.config) opts, ok := ctx.Value(types.CtxKeyOpts).(*gnmi.SubscribeOptions) @@ -330,6 +408,46 @@ func (g *Gnmi) subscribe(ctx context.Context) error { return gnmi.SubscribeErr(ctx, g.client, opts, g.RespChan) } +// controlPlaneSubscribe calls gNMI subscribe with a callback for responses and additional device information including +// an option to stop the subscription. +func (g *Gnmi) controlPlaneSubscribe(ctx context.Context, subcribeCallbackFunc func(*gpb.SubscribeResponse, + *tpInterface.SubscriptionInformation), subscriptionInfo *tpInterface.SubscriptionInformation) error { + ctx = gnmi.NewContext(ctx, g.config) + opts, ok := ctx.Value(types.CtxKeyOpts).(*gnmi.SubscribeOptions) + if !ok { + return &errors.ErrInvalidTypeAssertion{ + Value: ctx.Value(types.CtxKeyOpts), + Type: &gnmi.SubscribeOptions{}, + } + } + + go func() { + log.WithFields(log.Fields{ + "address": opts.Target, + "paths": opts.Paths, + "mode": opts.Mode, + "interval": opts.SampleInterval, + }).Info("subscribed to gNMI target") + for { + resp := <-g.RespChan + if resp != nil { + // callback to trigger internal event handling process + go subcribeCallbackFunc(resp, subscriptionInfo) + } + + select { + case <-subscriptionInfo.StopContext.Done(): + if err := subscriptionInfo.StopContext.Err(); err != nil { + log.Error(err) + } + return + default: + } + } + }() + return gnmi.SubscribeErr(ctx, g.client, opts, g.RespChan) +} + // Close calls GNMI close func (g *Gnmi) Close() error { return nil diff --git a/controller/nucleus/principalNetworkDomain.go b/controller/nucleus/principalNetworkDomain.go index 46e6aa1be776f51f308b778ca43cdc1302167966..566d6623b37017bf8f63f2c903c6ec715a09279c 100644 --- a/controller/nucleus/principalNetworkDomain.go +++ b/controller/nucleus/principalNetworkDomain.go @@ -34,6 +34,7 @@ import ( "code.fbi.h-da.de/danet/gosdn/controller/store" + "code.fbi.h-da.de/danet/gosdn/forks/goarista/gnmi" "github.com/google/uuid" gpb "github.com/openconfig/gnmi/proto/gnmi" "github.com/openconfig/ygot/ygot" @@ -277,15 +278,7 @@ func (pnd *pndImplementation) GetDevice(identifier string) (device.Device, error return nil, err } - // TODO: We should investigate why we copy the device here. - copiedDevice := &CommonDevice{ - name: d.Name(), - UUID: d.ID(), - Model: d.GetModel(), - sbi: d.SBI(), - } - - return copiedDevice, nil + return d, nil } // RemoveDevice removes a device from the PND @@ -562,6 +555,73 @@ func (pnd *pndImplementation) ChangeOND(duid uuid.UUID, operation ppb.ApiOperati return ch.cuid, nil } +func (pnd *pndImplementation) SubscribePath(uuid uuid.UUID, subList *ppb.SubscriptionList) error { + d, err := pnd.deviceService.Get(store.Query{ + ID: uuid, + }) + if err != nil { + return err + } + + mode, err := mapModeToAristaFork(subList.GetMode()) + if err != nil { + return err + } + + for _, sub := range subList.Subscription { + streamMode, err := mapStreamModeToAristaFork(sub.GetStreamMode()) + if err != nil { + return err + } + + opts := &gnmi.SubscribeOptions{ + Mode: mode, + StreamMode: streamMode, + Paths: [][]string{splitStringPath(sub.GetPath())}, + SampleInterval: sub.SampleInterval, + } + + ctx := context.Background() + ctx = context.WithValue(ctx, types.CtxKeyOpts, opts) + + if err = d.Transport().Subscribe(ctx); err != nil { + return err + } + } + + return nil +} + +func splitStringPath(s string) []string { + return strings.Split(s, "/") +} + +func mapStreamModeToAristaFork(mode ppb.StreamMode) (string, error) { + switch mode { + case ppb.StreamMode_STREAM_MODE_TARGET_DEFINED: + return "target_defined", nil + case ppb.StreamMode_STREAM_MODE_ON_CHANGE: + return "on_change", nil + case ppb.StreamMode_STREAM_MODE_SAMPLE: + return "sample", nil + default: + return "", fmt.Errorf("StreamMode of type: %T is not supported", mode) + } +} + +func mapModeToAristaFork(mode ppb.SubscriptionMode) (string, error) { + switch mode { + case ppb.SubscriptionMode_SUBSCRIPTION_MODE_STREAM: + return "stream", nil + case ppb.SubscriptionMode_SUBSCRIPTION_MODE_ONCE: + return "once", nil + case ppb.SubscriptionMode_SUBSCRIPTION_MODE_POLL: + return "poll", nil + default: + return "", fmt.Errorf("SubscriptionMode of type: %T is not supported", mode) + } +} + //nolint // handleRollbackError will be implemented in the near future func handleRollbackError(id uuid.UUID, err error) { @@ -864,3 +924,12 @@ func (pnd *pndImplementation) MarshalBSON() ([]byte, error) { Description: pnd.Description, }) } + +// UpdateONDAfterSubscribeResponse takes a device and forwards it to the device service to handle the update. +func (pnd *pndImplementation) UpdateDeviceAfterSubscribeResponse(device device.Device) error { + if err := pnd.deviceService.Update(device); err != nil { + return err + } + + return nil +} diff --git a/controller/nucleus/principalNetworkDomain_test.go b/controller/nucleus/principalNetworkDomain_test.go index 73043dd766cdda55397112f4ec22039d1efa86de..f62903bd4a5871bf837be80783ed9f148f39c9cc 100644 --- a/controller/nucleus/principalNetworkDomain_test.go +++ b/controller/nucleus/principalNetworkDomain_test.go @@ -7,11 +7,13 @@ import ( "testing" "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/csbi" + cpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/csbi" ppb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd" spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound" tpb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/transport" eventservice "code.fbi.h-da.de/danet/gosdn/controller/eventService" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/device" + eventInterfaces "code.fbi.h-da.de/danet/gosdn/controller/interfaces/event" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkdomain" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound" "code.fbi.h-da.de/danet/gosdn/controller/mocks" @@ -1206,3 +1208,63 @@ func Test_pndImplementation_saveGoStructsToFile(t *testing.T) { }) } } + +func Test_pndImplementation_SubscribePath(t *testing.T) { + type fields struct { + Name string + Description string + southboundService southbound.Service + deviceService device.Service + changes *store.ChangeStore + ID uuid.UUID + csbiClient cpb.CsbiServiceClient + callback func(uuid.UUID, chan device.Details) + eventService eventInterfaces.Service + } + type args struct { + uuid uuid.UUID + subList *ppb.SubscriptionList + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + //TODO: Implement proper test here! + // { + // name: "default", + // args: args{ + // uuid: did, + // subList: &ppb.SubscriptionList{ + // Subscription: []*ppb.Subscription{ + // { + // Path: "", + // StreamMode: ppb.StreamMode_STREAM_MODE_SAMPLE, + // SampleInterval: 1000000000, // 1 second + // }, + // }, + // Mode: ppb.SubscriptionMode_SUBSCRIPTION_MODE_STREAM, + // }, + // }, + // }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + pnd := &pndImplementation{ + Name: tt.fields.Name, + Description: tt.fields.Description, + southboundService: tt.fields.southboundService, + deviceService: tt.fields.deviceService, + changes: tt.fields.changes, + Id: tt.fields.ID, + csbiClient: tt.fields.csbiClient, + callback: tt.fields.callback, + eventService: tt.fields.eventService, + } + if err := pnd.SubscribePath(tt.args.uuid, tt.args.subList); (err != nil) != tt.wantErr { + t.Errorf("pndImplementation.SubscribePath() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +}