01-gRPC配置
本章节下载: 01-gRPC配置 (448.26 KB)
gRPC(Google Remote Procedure Call,Google远程过程调用)是Google发布的基于HTTP 2.0协议承载的高性能开源软件框架,提供了支持多种编程语言的、对网络设备进行配置和管理的方法。通信双方可以基于该软件框架进行二次开发。
gRPC协议栈分层如表1-1所示。
表1-1 gRPC协议栈分层模型
分层 |
说明 |
内容层 |
业务模块的数据 通信双方需要了解彼此的数据模型,才能正确交互信息 |
Protocol Buffers编码层 |
gRPC通过Protocol Buffers编码格式承载数据 |
gRPC层 |
远程过程调用,定义了远程过程调用的协议交互格式 |
HTTP 2.0层 |
gRPC承载在HTTP 2.0协议上 |
TCP层 |
TCP连接提供面向连接的、可靠的数据链路 |
如图1-1所示,gRPC网络采用客户端/服务器模型,使用HTTP 2.0协议传输报文。
图1-1 gRPC网络架构
gRPC网络的工作机制如下:
(1) 服务器通过监听指定服务端口来等待客户端的连接请求。
(2) 用户通过执行客户端程序登录到服务器。
(3) 客户端调用.proto文件提供的gRPC方法发送请求消息。
(4) 服务器回复应答消息。
H3C设备支持作为gRPC服务器或者gRPC客户端。
.proto文件使用protocol buffers语言编写。protocol buffers是Google开发的数据描述语言,用于自定义数据结构并生成基于各种语言的代码,在序列化和结构化数据方面比XML语言更简单、解析更快。
Telemetry是一项监控设备性能和故障的远程数据采集技术。H3C的Telemetry技术采用gRPC协议将数据从设备推送给网管的采集器。如图1-2所示,网络设备和网管系统建立gRPC连接后,网管可以订阅设备上指定业务模块的数据信息。
图1-2 基于gRPC的Telemetry技术
图1-2中,设备支持以下两种gRPC对接模式:
· Dial-in模式:设备作为gRPC服务器,采集器作为gRPC客户端。由采集器主动向设备发起gRPC连接并订阅需要采集的数据信息。
· Dial-out模式:设备作为gRPC客户端,采集器作为gRPC服务器。设备主动和采集器建立gRPC连接,将设备上配置的订阅数据推送给采集器。
与gRPC相关的协议规范有:
· RFC 7540 - Hypertext Transfer Protocol version 2 (HTTP/2)
本特性的支持情况与设备的型号有关,请以设备的实际情况为准。
型号 |
说明 |
MSR610 |
不支持 |
MSR 810、MSR 810-W、MSR 810-W-DB、MSR 810-LM、MSR 810-W-LM、MSR 810-10-PoE、MSR 810-LM-HK、MSR 810-W-LM-HK、MSR810-LM-CNDE-SJK、MSR810-CNDE-SJK、MSR810-EI、MSR810-LM-EA、MSR810-LM-EI |
支持 |
MSR 810-LMS、MSR 810-LUS |
不支持 |
MSR810-SI、MSR810-LM-SI |
不支持 |
MSR810-LMS-EA、MSR810-LME |
不支持 |
MSR1004S-5G、MSR1004S-5G-CN |
支持 |
MSR1104S-W、MSR1104S-W-CAT6、MSR1104S-5G-CN、MSR1104S-W-5G-CN |
支持 |
MSR 2600-6-X1、MSR2600-15-X1、MSR2600-15-X1-T |
支持 |
MSR2600-10-X1 |
支持 |
MSR 2630 |
支持 |
MSR 3600-28、MSR 3600-51 |
支持 |
MSR 3600-28-SI、MSR 3600-51-SI |
不支持 |
MSR 3600-28-X1、MSR 3600-28-X1-DP、MSR 3600-51-X1、MSR 3600-51-X1-DP |
支持 |
MSR3600-28-G-DP、MSR3600-51-G-DP |
支持 |
MSR 3610-I-DP、MSR 3610-IE-DP、MSR3610-IE-ES、MSR3610-IE-EAD、MSR-EAD-AK770、MSR3610-I-IG、MSR3610-IE-IG |
支持 |
MSR-iMC |
支持 |
MSR 3610-X1、MSR 3610-X1-DP、MSR 3610-X1-DC、MSR 3610-X1-DP-DC、MSR3620-X1、MSR3640-X1 |
支持 |
MSR 3610、MSR 3620、MSR 3620-DP、MSR 3640、MSR 3660 |
支持 |
MSR 3610-G、MSR 3620-G |
支持 |
MSR3640-G |
支持 |
MSR3640-X1-HI |
支持 |
型号 |
说明 |
MSR810-W-WiNet、MSR810-LM-WiNet |
支持 |
MSR830-4LM-WiNet |
不支持 |
MSR830-5BEI-WiNet、MSR830-6EI-WiNet、MSR830-10BEI-WiNet |
支持 |
MSR830-6BHI-WiNet、MSR830-10BHI-WiNet |
支持 |
MSR2600-6-WiNet |
支持 |
MSR2600-10-X1-WiNet |
支持 |
MSR2630-WiNet |
支持 |
MSR3600-28-WiNet |
支持 |
MSR3610-X1-WiNet |
支持 |
MSR3620-X1-WiNet |
支持 |
MSR3610-WiNet、MSR3620-10-WiNet、MSR3620-DP-WiNet、MSR3620-WiNet、MSR3660-WiNet |
支持 |
型号 |
说明 |
MSR860-6EI-XS |
支持 |
MSR860-6HI-XS |
支持 |
MSR2630-XS |
支持 |
MSR3600-28-XS |
支持 |
MSR3610-XS |
支持 |
MSR3620-XS |
支持 |
MSR3610-I-XS |
支持 |
MSR3610-IE-XS |
支持 |
MSR3620-X1-XS |
支持 |
MSR3640-XS |
支持 |
MSR3660-XS |
支持 |
型号 |
说明 |
MSR810-LM-GL |
支持 |
MSR810-W-LM-GL |
支持 |
MSR830-6EI-GL |
支持 |
MSR830-10EI-GL |
支持 |
MSR830-6HI-GL |
支持 |
MSR830-10HI-GL |
支持 |
MSR1004S-5G-GL |
支持 |
MSR2600-6-X1-GL |
支持 |
MSR3600-28-SI-GL |
不支持 |
仅非FIPS模式支持配置gRPC特性。有关FIPS的介绍,请参见“安全配置指导”中的“FIPS”。
如果执行undo grpc enable命令关闭gRPC功能,所有gRPC相关配置都会被删除。
gRPC Dial-in模式配置任务如下:
(1) (可选)配置与采集器进行SSL通信时使用的PKI域
(2) 配置gRPC服务
(3) 配置gRPC用户
(4) (可选)开启gRPC Dial-in模式的日志功能
与采集器进行SSL通信时需要通过本功能指定PKI域。创建PKI域的具体方法请参见“安全配置指导”中的“PKI”。
(1) 进入系统视图。
system-view
(2) 指定与采集器进行SSL通信时使用的PKI域。
grpc pki domain domain-name
(1) 进入系统视图。
system-view
(2) 开启gRPC功能。
grpc enable
缺省情况下,gRPC功能处于关闭状态。
grpc port port-number
缺省情况下,gRPC服务的端口号为50051。
修改端口号后,gRPC服务将重启,正在访问的客户端将被断开,客户端需要重新发送连接请求才能继续访问。
(4) (可选)配置gRPC会话超时时间。
grpc idle-timeout minutes
缺省情况下,gRPC会话超时时间为5分钟。
设备上需要为gRPC客户端创建本地用户,gRPC客户端才能与设备建立gRPC会话。
(1) 进入系统视图。
system-view
(2) 添加设备管理类本地用户。
local-user user-name [ class manage ]
(3) 设置本地用户的密码。
password [ { hash | simple } password ]
缺省情况下,不存在本地用户密码,即本地用户认证时无需输入密码,只要用户名有效且其他属性验证通过即可认证成功。
(4) 配置本地用户的授权用户角色为network-admin。
authorization-attribute user-role user-role
缺省情况下,本地用户的授权用户角色为network-operator。
(5) 配置本地用户可以使用的服务类型为HTTPS服务。
service-type https
缺省情况下,未配置用户的服务类型。
有关local-user、password、authorization-attribute和service-type命令的详细介绍,请参见“安全命令参考”中的“AAA”。
为了管理员定位gRPC问题的需要,可以开启gRPC日志功能,以便记录设备对gRPC报文的处理信息。
设备生成的gRPC日志信息会交给信息中心模块处理,信息中心模块的配置将决定日志信息的发送规则和发送方向。关于信息中心的详细描述请参见“网络管理和监控配置指导”中的“信息中心”。
如果gRPC操作频繁,设备会输出大量gRPC日志,这可能会影响设备性能,建议仅开启需关注的gRPC操作的日志功能。
(1) 进入系统视图。
system-view
(2) 开启gRPC Dial-in模式的RPC类操作日志功能。
grpc log dial-in rpc { all | { cli | get }* }
缺省情况下,gRPC Dial-in模式的RPC类操作日志功能处于关闭状态。
gRPC Dial-out模式配置任务如下:
(1) (可选)配置与采集器进行SSL通信时使用的PKI域
(2) 开启gRPC功能
(3) 配置传感器
(4) 配置采集器
(5) 配置订阅
(6) (可选)开启gRPC Dial-out模式的日志功能
与采集器进行SSL通信时需要通过本功能指定PKI域。创建PKI域的具体方法请参见“安全配置指导”中的“PKI”。
(1) 进入系统视图。
system-view
(2) 指定与采集器进行SSL通信时使用的PKI域。
grpc pki domain domain-name
(1) 进入系统视图。
system-view
(2) 开启gRPC功能。
grpc enable
缺省情况下,gRPC功能处于关闭状态。
设备通过传感器完成数据的采集。
采样路径用于指定需要采样的数据源,具体包括以下2种类型:
· 事件触发:传感器组的数据采样没有固定周期,仅由事件触发。关于事件触发类型的采样路径,请参见对应模块的《NETCONF XML API Event Reference》手册。
· 周期采样:传感器组以固定的时间间隔来进行数据采样。关于周期采样类型的采样路径,请参见对应模块的除《NETCONF XML API Event Reference》之外的其他NETCONF XML API手册。
(1) 进入系统视图。
system-view
(2) 进入Telemetry视图。
telemetry
(3) 创建传感器组,并进入传感器组视图。
sensor-group group-name
(4) 配置采样路径。
sensor path path [ condition node node operator operator value value ]
多次执行本命令可配置多个采样路径和推送条件。同一采样路径最多支持5个推送条件,只有这些条件都满足时才推送数据。
采集器用于接收网络设备推送的采样数据。设备上需要建立目标组并在目标组中配置正确的采集器地址信息,才能和采集器通信。
建议系统中创建的目标组数量不超过5个,否则会影响系统性能。
如果采集器位于VPN中,请先配置VPN实例,再配置采集器。关于VPN实例的配置,请参见“MPLS配置指导”中的“MPLS L3VPN”。
(1) 进入系统视图。
system-view
(2) 进入Telemetry视图。
telemetry
(3) 创建目标组,并进入目标组视图。
destination-group group-name
(4) 配置采集器的地址和相关参数。
(IPv4网络)
ipv4-address ipv4-address [ port port-number ] [ vpn-instance vpn-instance-name ]
(IPv6网络)
ipv6-address ipv6-address [ port port-number ] [ vpn-instance vpn-instance-name ]
采集器的IPv6地址不能指定为IPv6链路本地地址。有关IPv6链路本地地址的介绍,请参见“三层技术-IP业务配置指导”中的“IPv6基础”。
多次执行本命令可配置多个采集器。配置本命令时,只要任意一个参数不同,就算不同的采集器。
完成传感器组和目标组的配置后,需要创建订阅并将二者关联,设备才能和目标组中的采集器建立gRPC连接,从而将订阅报文发送给采集器。
(1) 进入系统视图。
system-view
(2) 进入Telemetry视图。
telemetry
(3) 创建订阅,并进入订阅视图。
subscription subscription-name
(4) (可选)配置设备发送的订阅报文的DSCP优先级。
dscp dscp-value
缺省情况下,设备发送的订阅报文的DSCP优先级为0。
DSCP优先级的取值越大,报文的优先级越高。
(5) (可选)配置设备发送订阅报文的源地址。
source-address { ipv4-address | interface interface-type interface-number | ipv6 ipv6-address }
缺省情况下,设备使用路由出接口的主IP地址作为发送订阅报文的源IP地址。
当设备发送订阅报文的源地址发生变化时,设备将会重新连接gRPC服务器。
(6) 配置关联传感器组。
sensor-group group-name [ sample-interval [ msec ] interval ]
当传感器组中的采样路径为事件触发类型时,请不要配置sample-interval参数,否则该采样路径不生效;当采样路径为周期采样类型时,必须配置sample-interval参数才会采样和推送数据。
(7) 配置关联目标组。
destination-group group-name
为了管理员定位gRPC问题的需要,可以开启gRPC日志功能,以便记录设备对gRPC报文的处理信息。
设备生成的gRPC日志信息会交给信息中心模块处理,信息中心模块的配置将决定日志信息的发送规则和发送方向。关于信息中心的详细描述请参见“网络管理和监控配置指导”中的“信息中心”。
(1) 进入系统视图。
system-view
(2) 开启gRPC Dial-out模式的日志功能。
grpc log dial-out { all | { event | sample }* }
缺省情况下,gRPC Dial-out模式的日志功能处于关闭状态。
在完成上述配置后,在任意视图下执行display命令可以显示配置后gRPC的运行情况,通过查看显示信息验证配置的效果。
表1-2 gRPC显示和维护
操作 |
命令 |
显示gRPC的相关信息 |
display grpc |
本章节主要描述设备上的命令行配置。采集器上的gRPC对接软件需要另外开发,请参见“2.3 gRPC对接软件二次开发举例”。
如图1-3所示,设备作为gRPC服务器与采集器相连。采集器为gRPC客户端。
通过在设备上配置gRPC Dial-in模式,使gRPC客户端可以订阅设备上的LLDP事件。
图1-3 gRPC Dial-in模式配置组网图
在开始下面的配置之前,假设gRPC服务器与gRPC客户端的IP地址都已配置完毕,并且它们之间路由可达。
(1) 配置Device(gRPC服务器)
# 开启gRPC功能。
<Device> system-view
[Device] grpc enable
# 创建本地用户test,配置该用户的密码,授权用户角色为network-admin,可以使用的服务类型为HTTPS服务。
[Device] local-user test
[Device-luser-manage-test] password simple 123456TESTplat&!
[Device-luser-manage-test] authorization-attribute user-role network-admin
[Device-luser-manage-test] service-type https
[Device-luser-manage-test] quit
(2) 配置gRPC客户端
a. 在gRPC客户端安装gRPC环境,具体安装方式请参考相关文档。
b. 获取H3C提供的.proto文件(该文件中已写入订阅LLDP事件的配置),并通过protocol buffers编译器生成特定语言(例如Java、Python、C/C++、Go)的执行代码。
c. 编写客户端程序,调用上一步生成的代码。
d. 执行客户端程序,登录到gRPC服务器。
当设备发生LLDP事件时,gRPC客户端成功收到设备上的订阅信息。
订阅事件触发类型(一般带有“event”字符)的采样路径的传感器组时,请不要在sensor-group (subscription view)命令中指定周期采样参数sample-interval。
如图1-4所示,设备作为gRPC客户端与采集器相连。采集器为gRPC服务器,接收数据的端口号为50050。
通过在设备上配置gRPC Dial-out模式,使设备向采集器推送接口模块的事件数据。
图1-4 gRPC Dial-out模式配置组网图
在开始下面的配置之前,假设设备与采集器的IP地址都已配置完毕,并且它们之间路由可达。
# 开启gRPC功能。
<Device> system-view
[Device] grpc enable
# 创建传感器组Test,并添加采样路径为ifmgr/interfaceevent。
[Device] telemetry
[Device-telemetry] sensor-group Test
[Device-telemetry-sensor-group-Test] sensor path ifmgr/interfaceevent
[Device-telemetry-sensor-group-Test] quit
# 创建目标组collector1,并配置IP地址为192.168.2.1、端口号为50050的采集器。
[Device-telemetry] destination-group collector1
[Device-telemetry-destination-group-collector1] ipv4-address 192.168.2.1 port 50050
[Device-telemetry-destination-group-collector1] quit
# 创建订阅B,配置关联传感器组为Test,关联目标组为collector1。
[Device-telemetry] subscription B
[Device-telemetry-subscription-B] sensor-group Test
[Device-telemetry-subscription-B] destination-group collector1
[Device-telemetry-subscription-B] quit
当设备的接口模块上报事件后,采集器收到设备推送的事件数据。
如图1-5所示,设备作为gRPC客户端与采集器相连。采集器为gRPC服务器,接收数据的端口号为50050。
通过在设备上配置gRPC Dial-out模式,使设备以10秒的周期向采集器推送接口模块的设备能力信息。
图1-5 gRPC Dial-out模式配置组网图
在开始下面的配置之前,假设设备与采集器的IP地址都已配置完毕,并且它们之间路由可达。
# 开启gRPC功能。
<Device> system-view
[Device] grpc enable
# 创建传感器组test,并添加采样路径为ifmgr/devicecapabilities。
[Device] telemetry
[Device-telemetry] sensor-group test
[Device-telemetry-sensor-group-test] sensor path ifmgr/devicecapabilities
[Device-telemetry-sensor-group-test] quit
# 创建目标组collector1,并配置IP地址为192.168.2.1、端口号为50050的采集器。
[Device-telemetry] destination-group collector1
[Device-telemetry-destination-group-collector1] ipv4-address 192.168.2.1 port 50050
[Device-telemetry-destination-group-collector1] quit
# 创建订阅A,配置关联传感器组为test,数据采样和推送周期为10秒,关联目标组为collector1。
[Device-telemetry] subscription A
[Device-telemetry-subscription-A] sensor-group test sample-interval 10
[Device-telemetry-subscription-A] destination-group collector1
[Device-telemetry-subscription-A] quit
采集器每10秒收到一次设备推送的数据信息。
Protocol Buffers编码提供了一种灵活、高效、自动序列化结构数据的机制。Protocol Buffers与XML、JSON编码类似,不同之处在于Protocol Buffers是一种二进制编码,性能更高。
表2-1对比了Protocol Buffers和对应的JSON编码格式。
表2-1 Protocol Buffers和对应的JSON编码格式示例
Protocol Buffers编码 |
对应的JSON编码 |
{ 1:“H3C” 2:“H3C” 3:“H3C device_test” 4:“Syslog/LogBuffer” 5:"notification": { "Syslog": { "LogBuffer": { "BufferSize": 512, "BufferSizeLimit": 1024, "DroppedLogsCount": 0, "LogsCount": 100, "LogsCountPerSeverity": { "Alert": 0, "Critical": 1, "Debug": 0, "Emergency": 0, "Error": 3, "Informational": 80, "Notice": 15, "Warning": 1 }, "OverwrittenLogsCount": 0, "State": "enable" } }, "Timestamp": "1527206160022" } } |
{ "producerName": "H3C", "deviceName": "H3C", "deviceModel": "H3C device_test", "sensorPath": "Syslog/LogBuffer", "jsonData": { "notification": { "Syslog": { "LogBuffer": { "BufferSize": 512, "BufferSizeLimit": 1024, "DroppedLogsCount": 0, "LogsCount": 100, "LogsCountPerSeverity": { "Alert": 0, "Critical": 1, "Debug": 0, "Emergency": 0, "Error": 3, "Informational": 80, "Notice": 15, "Warning": 1 }, "OverwrittenLogsCount": 0, "State": "enable" } }, "Timestamp": "1527206160022" } } } |
Protocol Buffers编码通过proto文件描述数据结构,用户可以利用Protoc等工具软件根据proto文件自动生成其他编程语言(例如Java、C++)代码,然后基于这些生成的代码进行二次开发,以实现gRPC设备对接。
H3C为Dial-in模式和Dial-out模式分别提供了proto文件。
grpc_service.proto文件定义了Dial-in模式下的公共RPC方法(例如Login、Logout),其内容和含义如下:
syntax = "proto2";
package grpc_service;
message GetJsonReply { //Get方法应答结果
required string result = 1;
}
message SubscribeReply { //订阅结果
required string result = 1;
}
message ConfigReply { //配置结果
required string result = 1;
}
message ReportEvent { //订阅事件结果定义
required string token_id = 1; //登录token_id
required string stream_name = 2; //订阅的事件流名称
required string event_name = 3; //订阅的事件名
required string json_text = 4; //订阅结果json字符串
}
message GetReportRequest{ //获取事件订阅结果请求
required string token_id = 1; //登录成功后的token_id
}
message LoginRequest { //登录请求参数定义
required string user_name = 1; //登录请求用户名
required string password = 2; //登录请求密码
}
message LoginReply { //登录请求应答定义
required string token_id = 1; //登录成功后返回的token_id
}
message LogoutRequest { //退出登录请求参数定义
required string token_id = 1; //token_id
}
message LogoutReply { //退出登录返回结果定义
required string result = 1; //退出登录结果
}
message SubscribeRequest { //定义事件流名称
required string stream_name = 1;
}
service GrpcService { //定义gRPC方法
rpc Login (LoginRequest) returns (LoginReply) {} //登录方法
rpc Logout (LogoutRequest) returns (LogoutReply) {} //退出登录方法
rpc SubscribeByStreamName (SubscribeRequest) returns (SubscribeReply) {} //订阅事件流
rpc GetEventReport (GetReportRequest) returns (stream ReportEvent) {} //获取事件结果
}
Dial-in模式支持Device、Ifmgr、IPFW、LLDP、Syslog等业务模块proto文件。
以Device.proto文件为例,该文件定义了Device模块数据的RPC方法,其内容和含义如下:
syntax = "proto2";
import "grpc_service.proto";
package device;
message DeviceBase { //获取设备基本信息结构定义
optional string HostName = 1; //设备的名称
optional string HostOid = 2; //sysoid
optional uint32 MaxChassisNum = 3; //最大框数
optional uint32 MaxSlotNum = 4; //最大slot数
optional string HostDescription = 5; //设备描述信息
}
message DevicePhysicalEntities { //设备物理实体信息
message Entity {
optional uint32 PhysicalIndex = 1; //实体索引
optional string VendorType = 2; //vendor类型
optional uint32 EntityClass = 3;//实体类型
optional string SoftwareRev = 4; //软件版本
optional string SerialNumber = 5; //序列号
optional string Model = 6; //模式
}
repeated Entity entity = 1;
}
service DeviceService { //定义的RPC方法
rpc GetJsonDeviceBase(DeviceBase) returns (grpc_service.GetJsonReply) {} //获取设备基本信息
rpc GetJsonDevicePhysicalEntities(DevicePhysicalEntities) returns (grpc_service.GetJsonReply) {} //获取设备实体信息
}
grpc_dialout.proto文件定义了Dial-out模式下的公共RPC方法,其内容和含义如下:
syntax = "proto2";
package grpc_dialout;
message DeviceInfo{ //推送的设备信息
required string producerName = 1; //厂商名
required string deviceName = 2; //设备的名称
required string deviceModel = 3; //设备型号
optional string deviceIpAddr = 4; //设备IP地址
optional string eventType = 5; //采样路径类型
optional string deviceSerialNumber = 6; //设备序列号
}
message DialoutMsg{ //推送的消息格式描述
required DeviceInfo deviceMsg = 1; //DeviceInfo所描述的设备信息
required string sensorPath = 2; //采样路径,对应netconf表的xpath路径
required string jsonData = 3; //采样结果数据(JSON格式字符串)
}
message DialoutResponse{ //采集器(gRPC服务器)返回信息,预留(暂不处理返回值,可填充任意值)
required string response = 1;
}
service GRPCDialout { //推送方法
rpc Dialout(stream DialoutMsg) returns (DialoutResponse);
}
请联系H3C技术支持。
本举例开发的软件用于实现采集器获取设备数据。开发环境为Linux,编程语言以C++为例。
(1) 获取H3C提供的proto文件:
¡ 对于Dial-in模式,需要grpc_service.proto文件和具体业务模块对应的proto文件。
¡ 对于Dial-out模式,需要grpc_dialout.proto文件。
(2) 获取处理proto文件的工具软件protoc。
下载地址:https://github.com/google/protobuf/releases
(3) 获取对应开发语言的protobuf插件,例如C++插件protobuf-cpp。
下载地址:https://github.com/google/protobuf/releases
生成proto文件对应的C++代码。
将需要的proto文件收集到当前目录下,例如grpc_service.proto和BufferMonitor.proto。
$protoc --plugin=./grpc_cpp_plugin --grpc_out=. --cpp_out=. *.proto
将grpc_dialout.proto文件收集到当前目录下。
$ protoc --plugin=./grpc_cpp_plugin --grpc_out=. --cpp_out=. *.proto
对于Dial-in模式,主要是实现gRPC客户端代码(采集器上使用)。
由于生成的proto代码已经封装好了对应的服务类(这里以GrpcService和BufferMonitorService为例),只要在编写的客户端代码中调用其RPC方法,客户端就能够向设备(gRPC服务器)发起对应的RPC请求。
客户端代码主要包括以下3部分:
· 进行登录操作,获取token_id。
· 为要发起的RPC方法准备参数,用proto生成的服务类发起RPC调用并解析返回结果。
· 退出登录。
编码步骤如下:
(1) 编写一个GrpcServiceTest类。
在这个类中使用由grpc_service.proto生成的GrpcService::Stub类,通过grpc_service.proto自动生成的Login和Logout方法分别完成登录和退出。
class GrpcServiceTest
{
public:
/* 构造函数 */
GrpcServiceTest(std::shared_ptr<Channel> channel): GrpcServiceStub(GrpcService::NewStub(channel)) {}
/* 成员函数 */
int Login(const std::string& username, const std::string& password);
void Logout();
void listen();
/* 成员变量 */
std::string token;
private:
std::unique_ptr<GrpcService::Stub> GrpcServiceStub; //使用grpc_service.proto生成的GrpcService::Stub类
};
(2) 实现自定义的Login方法。
通过用户输入的用户名,密码调用GrpcService::Stub类的Login方法完成登录。
int GrpcServiceTest::Login(const std::string& username, const std::string& password)
{
LoginRequest request; //设置用户名密码
request.set_user_name(username);
request.set_password(password);
LoginReply reply;
ClientContext context;
//调用登录方法
Status status = GrpcServiceStub->Login(&context, request, &reply);
if (status.ok())
{
std::cout << "login ok!" << std::endl;
std::cout <<"token id is :" << reply.token_id() << std::endl;
token = reply.token_id(); //登录成功,获取到token.
return 0;
}
else{
std::cout << status.error_code() << ": " << status.error_message()
<< ". Login failed!" << std::endl;
return -1;
}
}
(3) 发起对设备的RPC方法请求。
这里以订阅接口丢包事件举例:
rpc SubscribePortQueDropEvent(PortQueDropEvent) returns (grpc_service.SubscribeReply) {}
(4) 编写一个BufMon_GrpcClient类来封装发起的RPC方法。
使用BufferMonitor.proto自动生成的BufferMonitorService::Stub类完成RPC方法的调用。
class BufMon_GrpcClient
{
public:
BufMon_GrpcClient(std::shared_ptr<Channel> channel): mStub(BufferMonitorService::NewStub(channel))
{
}
std::string BufMon_Sub_AllEvent(std::string token);
std::string BufMon_Sub_BoardEvent(std::string token);
std::string BufMon_Sub_PortOverrunEvent(std::string token);
std::string BufMon_Sub_PortDropEvent(std::string token);
/* get 表项 */
std::string BufMon_Sub_GetStatistics(std::string token);
std::string BufMon_Sub_GetGlobalCfg(std::string token);
std::string BufMon_Sub_GetBoardCfg(std::string token);
std::string BufMon_Sub_GetNodeQueCfg(std::string token);
std::string BufMon_Sub_GetPortQueCfg(std::string token);
private:
std::unique_ptr<BufferMonitorService::Stub> mStub; //使用BufferMonitor.proto自动生成的类
};
(5) 实现自定义的std::string BufMon_Sub_PortDropEvent(std::string token)方法完成接口丢包事件订阅。
std::string BufMon_GrpcClient::BufMon_Sub_PortDropEvent(std::string token)
{
std::cout << "-------BufMon_Sub_PortDropEvent-------- " << std::endl;
PortQueDropEvent stNodeEvent;
PortQueDropEvent_PortQueDrop* pstParam = stNodeEvent.add_portquedrop();
UINT uiIfIndex = 0;
UINT uiQueIdx = 0;
UINT uiAlarmType = 0;
std::cout<<"Please input interface queue info : ifIndex queIdx alarmtype " << std::endl;
cout<<"alarmtype : 1 for ingress; 2 for egress; 3 for port headroom"<<endl;
std::cin>>uiIfIndex>>uiQueIdx>>uiAlarmType; //设置订阅参数,接口索引等。
pstParam->set_ifindex(uiIfIndex);
pstParam->set_queindex(uiQueIdx);
pstParam->set_alarmtype(uiAlarmType);
ClientContext context;
/* token need add to context */ //设置登录成功后返回的token_id
std::string key = "token_id";
std::string value = token;
context.AddMetadata(key, value);
SubscribeReply reply;
Status status = mStub->SubscribePortQueDropEvent(&context,stNodeEvent,&reply); //调用RPC方法
return reply.result();
}
(6) 循环等待事件上报。
在之前的GrpcServiceTest类中实现此方法,代码如下:
void GrpcServiceTest::listen()
{
GetReportRequest reportRequest;
ClientContext context;
ReportEvent reportedEvent;
/* add token to request */
reportRequest.set_token_id(token);
std::unique_ptr< ClientReader< ReportEvent>> reader(GrpcServiceStub->GetEventReport(&context, reportRequest)); //通过grpc_service.proto自动生成的类的GetEventReport来获取事件信息
std::string streamName;
std::string eventName;
std::string jsonText;
std::string token;
JsonFormatTool jsonTool;
std::cout << "Listen to server for Event" << std::endl;
while(reader->Read(&reportedEvent) ) //读取收到的上报事件
{
streamName = reportedEvent.stream_name();
eventName = reportedEvent.event_name();
jsonText = reportedEvent.json_text();
token = reportedEvent.token_id();
std::cout << "/**********************EVENT COME************************/" << std::endl;
std::cout << "TOKEN: " << token << std::endl;
std::cout << "StreamName: "<< streamName << std::endl;
std::cout << "EventName: " << eventName << std::endl;
std::cout << "JsonText without format: " << std::endl << jsonText << std::endl;
std::cout << std::endl;
std::cout << "JsonText Formated: " << jsonTool.formatJson(jsonText) << std::endl;
std::cout << std::endl;
}
Status status = reader->Finish();
std::cout << "Status Message:" << status.error_message() << "ERROR code :" << status.error_code();
}
(7) 这样就完成了Dial-in模式的登录和RPC请求调用,最后调用Logout退出即可。
对于Dial-out模式,主要是实现服务端代码,使采集器(gRPC服务器)接收从设备上获取到的数据并进行解析。
服务端代码主要包括以下2部分:
· 继承自动生成的GRPCDialout::Service类,重载自动生成的RPC服务Dialout,并完成解析,获得相应字段内容。
· 将RPC服务注册到指定监听端口上。
编码步骤如下:
(1) 继承并重载RPC服务Dialout。
新建一个类DialoutTest并继承GRPCDialout::Service。
class DialoutTest final : public GRPCDialout::Service { //重载自动生成的抽象类
Status Dialout(ServerContext* context, ServerReader< DialoutMsg>* reader, DialoutResponse* response) override; //实现Dialout RPC方法
};
(2) 将DialoutTest服务注册为gRPC服务,并指定监听端口。
using grpc::Server;
using grpc::ServerBuilder;
std::string server_address("0.0.0.0:60057"); //指定要监听的地址和端口
DialoutTest dialout_test; //定义(1)中声明的对象
ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());//添加监听
builder.RegisterService(&dialout_test); //注册服务
std::unique_ptr<Server> server(builder.BuildAndStart()); //启动服务
server->Wait();
(3) 实现Dialout方法,实现数据解析。
Status DialoutTest::Dialout(ServerContext* context, ServerReader< DialoutMsg>* reader, DialoutResponse* response)
{
DialoutMsg msg;
while( reader->Read(&msg))
{
const DeviceInfo &device_msg = msg.devicemsg();
std::cout<< "Producer-Name: " << device_msg.producername() << std::endl;
std::cout<< "Device-Name: " << device_msg.devicename() << std::endl;
std::cout<< "Device-Model: " << device_msg.devicemodel() << std::endl;
std::cout<<"Sensor-Path: " << msg.sensorpath()<<std::endl;
std::cout<<"Json-Data: " << msg.jsondata()<<std::endl;
std::cout<<std::endl;
}
response->set_response("test");
return Status::OK;
}
(4) 通过Read方法获取到proto文件生成的DialoutMsg对象后,可以调用对应的方法获取相应的字段值。
不同款型规格的资料略有差异, 详细信息请向具体销售和400咨询。H3C保留在没有任何通知或提示的情况下对资料内容进行修改的权利!