44package telemetry
55
66import (
7+ "bufio"
78 "bytes"
89 "encoding/json"
10+ "encoding/xml"
911 "fmt"
12+ "io"
1013 "log"
14+ "net"
1115 "net/http"
1216 "os"
17+ "os/exec"
18+ "strings"
19+
20+ "github.com/Azure/azure-container-networking/common"
1321)
1422
1523// OS Details structure.
@@ -18,6 +26,7 @@ type OSInfo struct {
1826 OSVersion string
1927 KernelVersion string
2028 OSDistribution string
29+ ErrorMessage string
2130}
2231
2332// System Details structure.
@@ -28,6 +37,7 @@ type SystemInfo struct {
2837 DiskVMTotal uint64
2938 DiskVMFree uint64
3039 CPUCount int
40+ ErrorMessage string
3141}
3242
3343// Interface Details structure.
@@ -39,34 +49,37 @@ type InterfaceInfo struct {
3949 Name string
4050 SecondaryCATotalCount int
4151 SecondaryCAUsedCount int
52+ ErrorMessage string
4253}
4354
4455// CNI Bridge Details structure.
4556type BridgeInfo struct {
46- NetworkMode string
47- BridgeName string
57+ NetworkMode string
58+ BridgeName string
59+ ErrorMessage string
4860}
4961
5062// Orchestrator Details structure.
5163type OrchsestratorInfo struct {
5264 OrchestratorName string
5365 OrchestratorVersion string
66+ ErrorMessage string
5467}
5568
5669// Azure CNI Telemetry Report structure.
5770type Report struct {
5871 StartFlag bool
5972 Name string
6073 Version string
74+ ErrorMessage string
75+ Context string
76+ SubContext string
77+ VnetAddressSpace []string
6178 OrchestratorDetails * OrchsestratorInfo
6279 OSDetails * OSInfo
6380 SystemDetails * SystemInfo
6481 InterfaceDetails * InterfaceInfo
6582 BridgeDetails * BridgeInfo
66- VnetAddressSpace []string
67- ErrorMessage string
68- Context string
69- SubContext string
7083}
7184
7285// ReportManager structure.
@@ -77,31 +90,47 @@ type ReportManager struct {
7790 Report * Report
7891}
7992
80- // GetReport retrieves orchestrator, system, OS and Interface details and create a report structure.
81- func (reportMgr * ReportManager ) GetReport (name string , version string ) (* Report , error ) {
82- var err error
83- report := & Report {}
84-
85- report .Name = name
86- report .Version = version
87- report .OrchestratorDetails = GetOrchestratorDetails ()
93+ // Read file line by line and return array of lines.
94+ func ReadFileByLines (filename string ) ([]string , error ) {
95+ var (
96+ lineStrArr []string
97+ )
8898
89- report . SystemDetails , err = GetSystemDetails ( )
99+ f , err := os . Open ( filename )
90100 if err != nil {
91- return report , err
101+ return nil , fmt . Errorf ( "Error opening %s file error %v" , filename , err )
92102 }
93103
94- report .OSDetails , err = GetOSDetails ()
95- if err != nil {
96- return report , err
104+ r := bufio .NewReader (f )
105+
106+ for {
107+ lineStr , err := r .ReadString ('\n' )
108+ if err != nil {
109+ if err != io .EOF {
110+ return nil , fmt .Errorf ("Error reading %s file error %v" , filename , err )
111+ }
112+ break
113+ }
114+ lineStrArr = append (lineStrArr , lineStr )
97115 }
98116
99- report . InterfaceDetails , err = GetInterfaceDetails ( reportMgr . IpamQueryURL )
117+ err = f . Close ( )
100118 if err != nil {
101- return report , err
119+ return nil , fmt . Errorf ( "Error closing %s file error %v" , filename , err )
102120 }
103121
104- return report , nil
122+ return lineStrArr , nil
123+ }
124+
125+ // GetReport retrieves orchestrator, system, OS and Interface details and create a report structure.
126+ func (reportMgr * ReportManager ) GetReport (name string , version string ) {
127+ reportMgr .Report .Name = name
128+ reportMgr .Report .Version = version
129+
130+ reportMgr .Report .GetOrchestratorDetails ()
131+ reportMgr .Report .GetSystemDetails ()
132+ reportMgr .Report .GetOSDetails ()
133+ reportMgr .Report .GetInterfaceDetails (reportMgr .IpamQueryURL )
105134}
106135
107136// This function will send telemetry report to HostNetAgent.
@@ -112,9 +141,17 @@ func (reportMgr *ReportManager) SendReport() error {
112141 json .NewEncoder (& body ).Encode (reportMgr .Report )
113142
114143 log .Printf ("Going to send Telemetry report to hostnetagent %v" , reportMgr .HostNetAgentURL )
115- log .Printf ("Flag %v Name %v Version %v orchestname %s ErrorMessage %v SystemDetails %v OSDetails %v InterfaceDetails %v" ,
116- reportMgr .Report .StartFlag , reportMgr .Report .Name , reportMgr .Report .Version , reportMgr .Report .OrchestratorDetails , reportMgr .Report .ErrorMessage ,
117- reportMgr .Report .SystemDetails , reportMgr .Report .OSDetails , reportMgr .Report .InterfaceDetails )
144+
145+ log .Printf (`"Start Flag %v Name %v Version %v ErrorMessage %v vnet %v
146+ Context %v SubContext %v"` , reportMgr .Report .StartFlag , reportMgr .Report .Name ,
147+ reportMgr .Report .Version , reportMgr .Report .ErrorMessage , reportMgr .Report .VnetAddressSpace ,
148+ reportMgr .Report .Context , reportMgr .Report .SubContext )
149+
150+ log .Printf ("OrchestratorDetails %v" , reportMgr .Report .OrchestratorDetails )
151+ log .Printf ("OSDetails %v" , reportMgr .Report .OSDetails )
152+ log .Printf ("SystemDetails %v" , reportMgr .Report .SystemDetails )
153+ log .Printf ("InterfaceDetails %v" , reportMgr .Report .InterfaceDetails )
154+ log .Printf ("BridgeDetails %v" , reportMgr .Report .BridgeDetails )
118155
119156 res , err := httpc .Post (reportMgr .HostNetAgentURL , reportMgr .ReportType , & body )
120157 if err != nil {
@@ -166,3 +203,107 @@ func (report *Report) GetReportState() bool {
166203
167204 return true
168205}
206+
207+ // This function creates a report with interface details(ip, mac, name, secondaryca count).
208+ func (report * Report ) GetInterfaceDetails (queryUrl string ) {
209+
210+ var (
211+ macAddress string
212+ secondaryCACount int
213+ primaryCA string
214+ subnet string
215+ ifName string
216+ )
217+
218+ if queryUrl == "" {
219+ report .InterfaceDetails .ErrorMessage = "IpamQueryUrl is null"
220+ return
221+ }
222+
223+ interfaces , err := net .Interfaces ()
224+ if err != nil {
225+ report .InterfaceDetails = & InterfaceInfo {}
226+ report .InterfaceDetails .ErrorMessage = "Getting all interfaces failed due to " + err .Error ()
227+ return
228+ }
229+
230+ resp , err := http .Get (queryUrl )
231+ if err != nil {
232+ report .InterfaceDetails = & InterfaceInfo {}
233+ report .InterfaceDetails .ErrorMessage = "Http get failed in getting interface details " + err .Error ()
234+ return
235+ }
236+
237+ defer resp .Body .Close ()
238+
239+ // Decode XML document.
240+ var doc common.XmlDocument
241+ decoder := xml .NewDecoder (resp .Body )
242+ err = decoder .Decode (& doc )
243+ if err != nil {
244+ report .InterfaceDetails = & InterfaceInfo {}
245+ report .InterfaceDetails .ErrorMessage = "xml decode failed due to " + err .Error ()
246+ return
247+ }
248+
249+ // For each interface...
250+ for _ , i := range doc .Interface {
251+ i .MacAddress = strings .ToLower (i .MacAddress )
252+
253+ if i .IsPrimary {
254+ // Find the interface with the matching MacAddress.
255+ for _ , iface := range interfaces {
256+ macAddr := strings .Replace (iface .HardwareAddr .String (), ":" , "" , - 1 )
257+ macAddr = strings .ToLower (macAddr )
258+ if macAddr == i .MacAddress {
259+ ifName = iface .Name
260+ macAddress = iface .HardwareAddr .String ()
261+ }
262+ }
263+
264+ for _ , s := range i .IPSubnet {
265+ for _ , ip := range s .IPAddress {
266+ if ip .IsPrimary {
267+ primaryCA = ip .Address
268+ subnet = s .Prefix
269+ } else {
270+ secondaryCACount += 1
271+ }
272+ }
273+ }
274+
275+ break
276+ }
277+ }
278+
279+ report .InterfaceDetails = & InterfaceInfo {
280+ InterfaceType : "Primary" ,
281+ MAC : macAddress ,
282+ Subnet : subnet ,
283+ Name : ifName ,
284+ PrimaryCA : primaryCA ,
285+ SecondaryCATotalCount : secondaryCACount ,
286+ }
287+ }
288+
289+ // This function creates a report with orchestrator details(name, version).
290+ func (report * Report ) GetOrchestratorDetails () {
291+ out , err := exec .Command ("kubectl" , "--version" ).Output ()
292+ if err != nil {
293+ report .OrchestratorDetails = & OrchsestratorInfo {}
294+ report .OrchestratorDetails .ErrorMessage = "kubectl command failed due to " + err .Error ()
295+ return
296+ }
297+
298+ outStr := string (out )
299+ outStr = strings .TrimLeft (outStr , " " )
300+ report .OrchestratorDetails = & OrchsestratorInfo {}
301+
302+ resultArray := strings .Split (outStr , " " )
303+ if len (resultArray ) >= 2 {
304+ report .OrchestratorDetails .OrchestratorName = resultArray [0 ]
305+ report .OrchestratorDetails .OrchestratorVersion = resultArray [1 ]
306+ } else {
307+ report .OrchestratorDetails .ErrorMessage = "Length of array is less than 2"
308+ }
309+ }
0 commit comments