Skip to content

Commit fd2081d

Browse files
authored
Adding in lat and long for meraki (#621)
1 parent 60f93bb commit fd2081d

File tree

1 file changed

+119
-2
lines changed

1 file changed

+119
-2
lines changed

pkg/inputs/snmp/x/meraki/meraki.go

+119-2
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ type MerakiClient struct {
3333
auth runtime.ClientAuthInfoWriter
3434
orgs []orgDesc
3535
timeout time.Duration
36+
cache *clientCache
3637
}
3738

3839
type orgDesc struct {
@@ -50,8 +51,9 @@ type networkDesc struct {
5051
}
5152

5253
const (
53-
ControllerKey = "meraki_controller_name"
54-
MerakiApiKey = "KENTIK_MERAKI_API_KEY"
54+
ControllerKey = "meraki_controller_name"
55+
MerakiApiKey = "KENTIK_MERAKI_API_KEY"
56+
DeviceCacheDuration = time.Duration(24) * time.Hour
5557
)
5658

5759
func NewMerakiClient(jchfChan chan []*kt.JCHF, gconf *kt.SnmpGlobalConfig, conf *kt.SnmpDeviceConfig, metrics *kt.SnmpDeviceMetric, log logger.ContextL) (*MerakiClient, error) {
@@ -64,6 +66,7 @@ func NewMerakiClient(jchfChan chan []*kt.JCHF, gconf *kt.SnmpGlobalConfig, conf
6466
orgs: []orgDesc{},
6567
auth: httptransport.APIKeyAuth("X-Cisco-Meraki-API-Key", "header", kt.LookupEnvString(MerakiApiKey, conf.Ext.MerakiConfig.ApiKey)),
6668
timeout: 30 * time.Second,
69+
cache: newClientCache(log),
6770
}
6871

6972
host := conf.Ext.MerakiConfig.Host
@@ -1212,6 +1215,7 @@ type deviceStatusWrapper struct {
12121215
org orgDesc
12131216
NetworkName string `json:"networkName"`
12141217
device *organizations.GetOrganizationDevicesStatusesOKBodyItems0
1218+
info *organizations.GetOrganizationDevicesOKBodyItems0
12151219
}
12161220

12171221
func (c *MerakiClient) getDeviceStatus(dur time.Duration) ([]*kt.JCHF, error) {
@@ -1278,9 +1282,118 @@ func (c *MerakiClient) getDeviceStatus(dur time.Duration) ([]*kt.JCHF, error) {
12781282
return nil, nil
12791283
}
12801284

1285+
// Next, get device info to add more info about these devices.
1286+
err := c.getDeviceInfo(devices)
1287+
if err != nil {
1288+
return nil, err
1289+
}
1290+
12811291
return c.parseDeviceStatus(devices)
12821292
}
12831293

1294+
type clientCache struct {
1295+
log logger.ContextL
1296+
deviceInfoTime time.Time
1297+
deviceInfo []*organizations.GetOrganizationDevicesOKBodyItems0
1298+
}
1299+
1300+
func newClientCache(log logger.ContextL) *clientCache {
1301+
return &clientCache{
1302+
log: log,
1303+
}
1304+
}
1305+
1306+
func (c *clientCache) getDeviceInfo() ([]*organizations.GetOrganizationDevicesOKBodyItems0, bool) {
1307+
if c.deviceInfoTime.Add(DeviceCacheDuration).Before(time.Now()) { // No information, cache invalid or old.
1308+
return nil, false
1309+
}
1310+
1311+
return c.deviceInfo, true
1312+
}
1313+
1314+
func (c *clientCache) setDeviceInfo(infos []*organizations.GetOrganizationDevicesOKBodyItems0) {
1315+
c.deviceInfo = infos
1316+
c.deviceInfoTime = time.Now()
1317+
}
1318+
1319+
func (c *MerakiClient) getDeviceInfo(devices []*deviceStatusWrapper) error {
1320+
// Build up a map of product types to filter on.
1321+
productTypes := map[string]bool{}
1322+
for _, pt := range c.conf.Ext.MerakiConfig.ProductTypes {
1323+
productTypes[pt] = true
1324+
}
1325+
1326+
var getDeviceInfo func(nextToken string, org orgDesc, devices *[]*deviceStatusWrapper, cache *[]*organizations.GetOrganizationDevicesOKBodyItems0) error
1327+
getDeviceInfo = func(nextToken string, org orgDesc, devices *[]*deviceStatusWrapper, cache *[]*organizations.GetOrganizationDevicesOKBodyItems0) error {
1328+
params := organizations.NewGetOrganizationDevicesParamsWithTimeout(c.timeout)
1329+
params.SetOrganizationID(org.ID)
1330+
if nextToken != "" {
1331+
params.SetStartingAfter(&nextToken)
1332+
}
1333+
1334+
prod, err := c.client.Organizations.GetOrganizationDevices(params, c.auth)
1335+
if err != nil {
1336+
return err
1337+
}
1338+
1339+
// Store these for some tail recursion.
1340+
raw := prod.GetPayload()
1341+
1342+
for _, device := range raw {
1343+
// Filter for networks here.
1344+
if _, ok := org.networks[device.NetworkID]; !ok {
1345+
continue
1346+
}
1347+
// Also filter on product types.
1348+
if len(productTypes) > 0 && !productTypes[device.ProductType] {
1349+
continue
1350+
}
1351+
1352+
ld := device
1353+
*cache = append(*cache, ld)
1354+
for _, wrap := range *devices {
1355+
if wrap.device.Serial == device.Serial {
1356+
wrap.info = ld
1357+
}
1358+
}
1359+
}
1360+
1361+
// Recursion!
1362+
nextLink := getNextLink(prod.Link)
1363+
if nextLink != "" {
1364+
return getDeviceInfo(nextLink, org, devices, cache)
1365+
} else {
1366+
return nil
1367+
}
1368+
}
1369+
1370+
// First check the cache.
1371+
if cc, ok := c.cache.getDeviceInfo(); ok {
1372+
// We have a valid cache, don't use rest of call.
1373+
for _, device := range cc {
1374+
for _, wrap := range devices {
1375+
if wrap.device.Serial == device.Serial {
1376+
ld := device
1377+
wrap.info = ld
1378+
}
1379+
}
1380+
}
1381+
return nil
1382+
}
1383+
1384+
// Need to build up cache case here.
1385+
cache := []*organizations.GetOrganizationDevicesOKBodyItems0{}
1386+
for _, org := range c.orgs {
1387+
err := getDeviceInfo("", org, &devices, &cache)
1388+
if err != nil {
1389+
return err
1390+
}
1391+
}
1392+
c.cache.setDeviceInfo(cache)
1393+
1394+
return nil
1395+
}
1396+
12841397
func (c *MerakiClient) parseDeviceStatus(devices []*deviceStatusWrapper) ([]*kt.JCHF, error) {
12851398
res := make([]*kt.JCHF, 0)
12861399

@@ -1301,6 +1414,10 @@ func (c *MerakiClient) parseDeviceStatus(devices []*deviceStatusWrapper) ([]*kt.
13011414
"mac": wrap.device.Mac,
13021415
"model": wrap.device.Model,
13031416
"product_type": wrap.device.ProductType,
1417+
"lat": fmt.Sprintf("%f", wrap.info.Lat),
1418+
"lng": fmt.Sprintf("%f", wrap.info.Lng),
1419+
"address": wrap.info.Address,
1420+
"notes": wrap.info.Notes,
13041421
}
13051422

13061423
dst.CustomInt = map[string]int32{}

0 commit comments

Comments
 (0)