20-gRPC配置
本章節下載: 20-gRPC配置 (462.70 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-3中,設備支持以下兩種gRPC對接模式:
· Dial-in模式:設備作為gRPC服務器,采集器作為gRPC客戶端。由采集器主動向設備發起gRPC連接並訂閱需要采集的數據信息。
· Dial-out模式:設備作為gRPC客戶端,采集器作為gRPC服務器。設備主動和采集器建立gRPC連接,將設備上配置的訂閱數據推送給采集器。
圖1-3 基於gRPC的Telemetry技術
與gRPC相關的協議規範有:
· RFC 7540 - Hypertext Transfer Protocol version 2 (HTTP/2)
如果執行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 | depth depth ]
多次執行本命令可配置多個采樣路徑和推送條件。同一采樣路徑最多支持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對接軟件需要另外開發,請參見“gRPC對接軟件二次開發舉例”。
如圖1-4所示,設備作為gRPC服務器與采集器相連。采集器為gRPC客戶端。
通過在設備上配置gRPC Dial-in模式,使gRPC客戶端可以訂閱設備上的LLDP事件。
圖1-4 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-5所示,設備作為gRPC客戶端與采集器相連。采集器為gRPC服務器,接收數據的端口號為50050。
通過在設備上配置gRPC Dial-out模式,使設備向采集器推送接口模塊的事件數據。
圖1-5 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-6所示,設備作為gRPC客戶端與采集器相連。采集器為gRPC服務器,接收數據的端口號為50050。
通過在設備上配置gRPC Dial-out模式,使設備以10秒的周期向采集器推送接口模塊的設備能力信息。
圖1-6 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保留在沒有任何通知或提示的情況下對資料內容進行修改的權利!