Skip to content

Commit 104d6dc

Browse files
tamilmani1989sharmasushant
authored andcommitted
VSTS#1728451 Added telemetry support for CNI
1 parent 6f24a3f commit 104d6dc

File tree

6 files changed

+845
-4
lines changed

6 files changed

+845
-4
lines changed

cni/network/network.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/Azure/azure-container-networking/log"
1212
"github.com/Azure/azure-container-networking/network"
1313
"github.com/Azure/azure-container-networking/platform"
14+
"github.com/Azure/azure-container-networking/telemetry"
1415

1516
cniSkel "github.com/containernetworking/cni/pkg/skel"
1617
cniTypesCurr "github.com/containernetworking/cni/pkg/types/current"
@@ -24,7 +25,8 @@ const (
2425
// NetPlugin represents the CNI network plugin.
2526
type netPlugin struct {
2627
*cni.Plugin
27-
nm network.NetworkManager
28+
nm network.NetworkManager
29+
reportManager *telemetry.ReportManager
2830
}
2931

3032
// NewPlugin creates a new netPlugin object.
@@ -49,6 +51,10 @@ func NewPlugin(config *common.PluginConfig) (*netPlugin, error) {
4951
}, nil
5052
}
5153

54+
func (plugin *netPlugin) SetReportManager(reportManager *telemetry.ReportManager) {
55+
plugin.reportManager = reportManager
56+
}
57+
5258
// Starts the plugin.
5359
func (plugin *netPlugin) Start(config *common.PluginConfig) error {
5460
// Initialize base plugin.

cni/network/plugin/main.go

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,20 @@
44
package main
55

66
import (
7-
"fmt"
87
"os"
98

109
"github.com/Azure/azure-container-networking/cni"
1110
"github.com/Azure/azure-container-networking/cni/network"
1211
"github.com/Azure/azure-container-networking/common"
12+
"github.com/Azure/azure-container-networking/log"
13+
"github.com/Azure/azure-container-networking/telemetry"
14+
)
15+
16+
const (
17+
hostNetAgentURL = "http://169.254.169.254/machine/plugins?comp=netagent&type=cnireport"
18+
ipamQueryURL = "http://169.254.169.254/machine/plugins?comp=nmagent&type=getinterfaceinfov1"
19+
pluginName = "CNI"
20+
reportType = "application/json"
1321
)
1422

1523
// Version is populated by make during build.
@@ -18,21 +26,72 @@ var version string
1826
// Main is the entry point for CNI network plugin.
1927
func main() {
2028
var config common.PluginConfig
29+
var err error
2130
config.Version = version
2231

32+
reportManager := &telemetry.ReportManager{HostNetAgentURL: hostNetAgentURL, IpamQueryURL: ipamQueryURL, ReportType: reportType}
33+
34+
reportManager.Report, err = reportManager.GetReport(pluginName, config.Version)
35+
if err != nil {
36+
log.Printf("GetReport failed due to %v", err)
37+
reportManager.Report.ErrorMessage = err.Error()
38+
}
39+
40+
report := reportManager.Report
41+
42+
if !report.GetReportState() {
43+
log.Printf("GetReport state file didn't exist. Setting flag to true")
44+
}
45+
46+
report.Context = "AzureCNI"
47+
48+
err = reportManager.SendReport()
49+
if err != nil {
50+
log.Printf("SendReport failed due to %v", err)
51+
} else {
52+
if err = report.SetReportState(); err != nil {
53+
log.Printf("SetReportState failed due to %v", err)
54+
55+
report.ErrorMessage = err.Error()
56+
if reportManager.SendReport() != nil {
57+
log.Printf("SendReport failed due to %v", err)
58+
}
59+
}
60+
}
61+
2362
netPlugin, err := network.NewPlugin(&config)
2463
if err != nil {
25-
fmt.Printf("Failed to create network plugin, err:%v.\n", err)
64+
log.Printf("Failed to create network plugin, err:%v.\n", err)
65+
66+
report.ErrorMessage = err.Error()
67+
if err = reportManager.SendReport(); err != nil {
68+
log.Printf("SendReport failed due to %v", err)
69+
}
70+
2671
os.Exit(1)
2772
}
2873

74+
netPlugin.SetReportManager(reportManager)
75+
2976
err = netPlugin.Start(&config)
3077
if err != nil {
31-
fmt.Printf("Failed to start network plugin, err:%v.\n", err)
78+
log.Printf("Failed to start network plugin, err:%v.\n", err)
79+
80+
report.ErrorMessage = err.Error()
81+
if err = reportManager.SendReport(); err != nil {
82+
log.Printf("SendReport failed due to %v", err)
83+
}
84+
3285
os.Exit(1)
3386
}
3487

3588
err = netPlugin.Execute(cni.PluginApi(netPlugin))
89+
if err != nil {
90+
report.ErrorMessage = err.Error()
91+
if err = reportManager.SendReport(); err != nil {
92+
log.Printf("SendReport failed due to %v", err)
93+
}
94+
}
3695

3796
netPlugin.Stop()
3897

telemetry/telemetry.go

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
// Copyright 2017 Microsoft. All rights reserved.
2+
// MIT License
3+
4+
package telemetry
5+
6+
import (
7+
"bytes"
8+
"encoding/json"
9+
"encoding/xml"
10+
"fmt"
11+
"log"
12+
"net/http"
13+
"os"
14+
)
15+
16+
type xmlDocument struct {
17+
XMLName xml.Name `xml:"Interfaces"`
18+
Interface []struct {
19+
XMLName xml.Name `xml:"Interface"`
20+
MacAddress string `xml:"MacAddress,attr"`
21+
IsPrimary bool `xml:"IsPrimary,attr"`
22+
23+
IPSubnet []struct {
24+
XMLName xml.Name `xml:"IPSubnet"`
25+
Prefix string `xml:"Prefix,attr"`
26+
27+
IPAddress []struct {
28+
XMLName xml.Name `xml:"IPAddress"`
29+
Address string `xml:"Address,attr"`
30+
IsPrimary bool `xml:"IsPrimary,attr"`
31+
}
32+
}
33+
}
34+
}
35+
36+
// OS Details structure.
37+
type OSInfo struct {
38+
OSType string
39+
OSVersion string
40+
KernelVersion string
41+
OSDistribution string
42+
}
43+
44+
// System Details structure.
45+
type SystemInfo struct {
46+
MemVMTotal uint64
47+
MemVMFree uint64
48+
MemUsedByProcess uint64
49+
DiskVMTotal uint64
50+
DiskVMFree uint64
51+
CPUCount int
52+
}
53+
54+
// Interface Details structure.
55+
type InterfaceInfo struct {
56+
InterfaceType string
57+
Subnet string
58+
PrimaryCA string
59+
MAC string
60+
Name string
61+
SecondaryCATotalCount int
62+
SecondaryCAUsedCount int
63+
}
64+
65+
// CNI Bridge Details structure.
66+
type BridgeInfo struct {
67+
NetworkMode string
68+
BridgeName string
69+
}
70+
71+
type OrchsestratorInfo struct {
72+
OrchestratorName string
73+
OrchestratorVersion string
74+
}
75+
76+
// Azure CNI Telemetry Report structure.
77+
type Report struct {
78+
StartFlag bool
79+
Name string
80+
Version string
81+
OrchestratorDetails *OrchsestratorInfo
82+
OSDetails *OSInfo
83+
SystemDetails *SystemInfo
84+
InterfaceDetails *InterfaceInfo
85+
BridgeDetails *BridgeInfo
86+
VnetAddressSpace []string
87+
ErrorMessage string
88+
Context string
89+
SubContext string
90+
}
91+
92+
// ReportManager structure.
93+
type ReportManager struct {
94+
HostNetAgentURL string
95+
IpamQueryURL string
96+
ReportType string
97+
Report *Report
98+
}
99+
100+
// GetReport retrieves orchestrator, system, OS and Interface details and create a report structure.
101+
func (reportMgr *ReportManager) GetReport(name string, version string) (*Report, error) {
102+
var err error
103+
report := &Report{}
104+
105+
report.Name = name
106+
report.Version = version
107+
report.OrchestratorDetails = GetOrchestratorDetails()
108+
109+
report.SystemDetails, err = GetSystemDetails()
110+
if err != nil {
111+
return report, err
112+
}
113+
114+
report.OSDetails, err = GetOSDetails()
115+
if err != nil {
116+
return report, err
117+
}
118+
119+
report.InterfaceDetails, err = GetInterfaceDetails(reportMgr.IpamQueryURL)
120+
if err != nil {
121+
return report, err
122+
}
123+
124+
return report, nil
125+
}
126+
127+
// This function will send telemetry report to HostNetAgent.
128+
func (reportMgr *ReportManager) SendReport() error {
129+
var body bytes.Buffer
130+
131+
httpc := &http.Client{}
132+
json.NewEncoder(&body).Encode(reportMgr.Report)
133+
134+
log.Printf("Going to send Telemetry report to hostnetagent %v", reportMgr.HostNetAgentURL)
135+
log.Printf("Flag %v Name %v Version %v orchestname %s ErrorMessage %v SystemDetails %v OSDetails %v InterfaceDetails %v",
136+
reportMgr.Report.StartFlag, reportMgr.Report.Name, reportMgr.Report.Version, reportMgr.Report.OrchestratorDetails, reportMgr.Report.ErrorMessage,
137+
reportMgr.Report.SystemDetails, reportMgr.Report.OSDetails, reportMgr.Report.InterfaceDetails)
138+
139+
res, err := httpc.Post(reportMgr.HostNetAgentURL, reportMgr.ReportType, &body)
140+
if err != nil {
141+
return fmt.Errorf("[Azure CNI] HTTP Post returned error %v", err)
142+
}
143+
144+
if res.StatusCode != 200 {
145+
return fmt.Errorf("[Azure CNI] HTTP Post returned statuscode %d", res.StatusCode)
146+
}
147+
148+
log.Printf("Send telemetry success %d\n", res.StatusCode)
149+
return nil
150+
}
151+
152+
// This function will save the state in file if telemetry report sent successfully.
153+
func (report *Report) SetReportState() error {
154+
f, err := os.OpenFile(TelemetryFile, os.O_RDWR|os.O_CREATE, 0666)
155+
if err != nil {
156+
return fmt.Errorf("Error opening telemetry file %v", err)
157+
}
158+
159+
defer f.Close()
160+
161+
reportBytes, err := json.Marshal(report)
162+
if err != nil {
163+
log.Printf("report write failed due to %v", err)
164+
_, err = f.WriteString("report write failed")
165+
} else {
166+
_, err = f.Write(reportBytes)
167+
}
168+
169+
if err != nil {
170+
log.Printf("Error while writing to file %v", err)
171+
return fmt.Errorf("Error while writing to file %v", err)
172+
}
173+
174+
report.StartFlag = false
175+
log.Printf("SetReportState succeeded")
176+
return nil
177+
}
178+
179+
// This function will check if report is sent atleast once by checking telemetry file.
180+
func (report *Report) GetReportState() bool {
181+
if _, err := os.Stat(TelemetryFile); os.IsNotExist(err) {
182+
log.Printf("File not exist %v", TelemetryFile)
183+
report.StartFlag = true
184+
return false
185+
}
186+
187+
return true
188+
}

0 commit comments

Comments
 (0)