Skip to content

Commit 6aee22c

Browse files
authored
Merge pull request #9 from BarbarossaTM/featurePrep/versioNetBoxConector
Move common functions in netbox/utils sub-module
2 parents 169f11b + 22c898a commit 6aee22c

File tree

4 files changed

+323
-196
lines changed

4 files changed

+323
-196
lines changed

pkg/connector/netbox/netbox.go

+13-144
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@ package netbox
99

1010
import (
1111
"fmt"
12-
"regexp"
13-
"strconv"
1412
"strings"
1513
"sync"
1614
"sync/atomic"
1715
"time"
1816

1917
dbModel "github.com/cloudflare/octopus/pkg/connector/netbox/model"
18+
nbUtils "github.com/cloudflare/octopus/pkg/connector/netbox/utils"
2019
"github.com/cloudflare/octopus/pkg/model"
2120
"github.com/cloudflare/octopus/proto/octopus"
2221

@@ -29,10 +28,6 @@ const (
2928
updateInterval = time.Minute * 2
3029
)
3130

32-
var (
33-
ifNameTagsRegexp = regexp.MustCompile(`^(?P<intf_name>.+?)\.((?P<outer_tag>\d+)\.)?(?P<inner_tag>\d+)$`)
34-
)
35-
3631
type NetboxConnector struct {
3732
connectorMu sync.RWMutex
3833
client NetboxClientI
@@ -192,7 +187,7 @@ func (n *NetboxConnector) addDevices(t *model.Topology) error {
192187
topoDev.Role = d.DeviceRole.Slug
193188
topoDev.DeviceType = d.DeviceType.Slug
194189

195-
md, err := metaDataFromTags(d.Tags)
190+
md, err := nbUtils.GetMetaDataFromTags(d.Tags)
196191
if err != nil {
197192
return fmt.Errorf("unable to get meta data: %v", err)
198193
}
@@ -218,7 +213,7 @@ func (n *NetboxConnector) addInterfaces(t *model.Topology) error {
218213
t.DevicesByInterfaceID[nbIfa.ID] = d
219214
t.Interfaces[nbIfa.ID] = ifa
220215

221-
md, err := metaDataFromTags(nbIfa.Tags)
216+
md, err := nbUtils.GetMetaDataFromTags(nbIfa.Tags)
222217
if err != nil {
223218
return fmt.Errorf("unable to get meta data: %v", err)
224219
}
@@ -255,15 +250,15 @@ func (n *NetboxConnector) addInterfaceUnits(t *model.Topology) error {
255250
return fmt.Errorf("can not find interface %s:%s", nbIfa.Device.Name, nbIfa.Parent.Name)
256251
}
257252

258-
vlanTag, err := parseUnitStr(unitStr)
253+
vlanTag, err := nbUtils.ParseUnitStr(unitStr)
259254
if err != nil {
260-
return fmt.Errorf("Unable to convert unit %q (id=%d) (interface %q) to int for %s:%s. Ignoring logical interface.", unitStr, nbIfa.ID, nbIfa.Name, nbIfa.Device.Name, nbIfa.Parent.Name)
255+
return fmt.Errorf("unable to convert unit %q (id=%d) (interface %q) to int for %s:%s. Ignoring logical interface", unitStr, nbIfa.ID, nbIfa.Name, nbIfa.Device.Name, nbIfa.Parent.Name)
261256
}
262257

263258
u := ifa.AddUnitIfNotExists(vlanTag)
264259
t.DevicesByInterfaceID[nbIfa.ID] = d
265260

266-
md, err := metaDataFromTags(nbIfa.Tags)
261+
md, err := nbUtils.GetMetaDataFromTags(nbIfa.Tags)
267262
if err != nil {
268263
return fmt.Errorf("unable to get meta data: %v", err)
269264
}
@@ -274,34 +269,6 @@ func (n *NetboxConnector) addInterfaceUnits(t *model.Topology) error {
274269
return nil
275270
}
276271

277-
func parseUnitStr(unitStr string) (model.VLANTag, error) {
278-
if strings.Contains(unitStr, ".") {
279-
parts := strings.Split(unitStr, ".")
280-
if len(parts) != 2 {
281-
return model.VLANTag{}, fmt.Errorf("invalid unit string %q", unitStr)
282-
}
283-
284-
outerTag, err := strconv.Atoi(parts[0])
285-
if err != nil {
286-
return model.VLANTag{}, fmt.Errorf("unable to convert %q to int: %v", parts[0], err)
287-
}
288-
289-
innerTag, err := strconv.Atoi(parts[1])
290-
if err != nil {
291-
return model.VLANTag{}, fmt.Errorf("unable to convert %q to int: %v", parts[1], err)
292-
}
293-
294-
return model.NewVLANTag(uint16(outerTag), uint16(innerTag)), nil
295-
}
296-
297-
ctag, err := strconv.Atoi(unitStr)
298-
if err != nil {
299-
return model.VLANTag{}, fmt.Errorf("unable to convert %q to int: %v", unitStr, err)
300-
}
301-
302-
return model.NewVLANTag(0, uint16(ctag)), nil
303-
}
304-
305272
func (n *NetboxConnector) addIPAddresses(t *model.Topology) error {
306273
for _, nbIP := range n.ipAddresses {
307274
if nbIP.AssignedObjectID == 0 || nbIP.AssignedObjectTypeID != n.client.GetDcimInterfaceTypeID() {
@@ -323,18 +290,18 @@ func (n *NetboxConnector) addIPAddresses(t *model.Topology) error {
323290
return fmt.Errorf("interface with id %d not found", ifaID)
324291
}
325292

326-
_, vt, err := getInterfaceAndVLANTag(dcimIfa.Name)
293+
_, vt, err := nbUtils.GetInterfaceAndVLANTag(dcimIfa.Name)
327294
if err != nil {
328295
return fmt.Errorf("unable to extract interface name and unit from %q: %v", dcimIfa.Name, err)
329296
}
330297

331-
pfx, err := bnet.PrefixFromString(sanitizeIPAddress(nbIP.Address))
298+
pfx, err := bnet.PrefixFromString(nbUtils.SanitizeIPAddress(nbIP.Address))
332299
if err != nil {
333300
return fmt.Errorf("failed to parse IP %q: %v", nbIP.Address, err)
334301
}
335302

336303
ip := model.NewIP(*pfx)
337-
getCustomFieldData(ip.MetaData, nbIP.CustomFieldData)
304+
nbUtils.GetCustomFieldData(ip.MetaData, nbIP.CustomFieldData)
338305

339306
u := ifa.AddUnitIfNotExists(vt)
340307
if pfx.Addr().IsIPv4() {
@@ -347,26 +314,14 @@ func (n *NetboxConnector) addIPAddresses(t *model.Topology) error {
347314
return nil
348315
}
349316

350-
func sanitizeIPAddress(addr string) string {
351-
if strings.Contains(addr, "/") {
352-
return addr
353-
}
354-
355-
if strings.Contains(addr, ".") {
356-
return addr + "/32"
357-
}
358-
359-
return addr + "/128"
360-
}
361-
362317
func (n *NetboxConnector) addPrefixes(t *model.Topology) error {
363318
for _, p := range n.prefixes {
364319
pfx, err := bnet.PrefixFromString(p.Prefix)
365320
if err != nil {
366321
return fmt.Errorf("failed to parse Prefix %q: %v", p.Prefix, err)
367322
}
368323

369-
md, err := metaDataFromTags(p.Tags)
324+
md, err := nbUtils.GetMetaDataFromTags(p.Tags)
370325
if err != nil {
371326
return fmt.Errorf("failed to get Tags for Prefix %q: %v", p.Prefix, err)
372327
}
@@ -380,36 +335,6 @@ func (n *NetboxConnector) addPrefixes(t *model.Topology) error {
380335
return nil
381336
}
382337

383-
func metaDataFromTags(tags []string) (*model.MetaData, error) {
384-
ret := model.NewMetaData()
385-
for _, tag := range tags {
386-
parts := strings.Split(tag, "=")
387-
388-
// Semantic Tag
389-
if len(parts) == 2 {
390-
if _, exists := ret.SemanticTags[parts[0]]; exists {
391-
return nil, fmt.Errorf("Key %q exists already: %q vs. %q", parts[0], ret.SemanticTags[parts[0]], parts[1])
392-
}
393-
394-
ret.SemanticTags[parts[0]] = parts[1]
395-
396-
} else {
397-
// Regular Tag
398-
ret.Tags = append(ret.Tags, tag)
399-
}
400-
}
401-
402-
return ret, nil
403-
}
404-
405-
func getCustomFieldData(md *model.MetaData, customFieldData string) {
406-
if customFieldData == "" || customFieldData == "{}" {
407-
return
408-
}
409-
410-
md.CustomFieldData = customFieldData
411-
}
412-
413338
func (n *NetboxConnector) getCableEnd(terminationType int32, terminationID int64, t *model.Topology) (*model.CableEnd, error) {
414339
ce := model.CableEnd{}
415340

@@ -483,7 +408,7 @@ func (n *NetboxConnector) getCableEnd(terminationType int32, terminationID int64
483408

484409
default:
485410
// consoleport, consoleserverport, powerport, or poweroutlet
486-
return nil, fmt.Errorf("Don't know what to do with cable termination ID %d (type %d)", terminationID, terminationType)
411+
return nil, fmt.Errorf("don't know what to do with cable termination ID %d (type %d)", terminationID, terminationType)
487412
}
488413

489414
return &ce, nil
@@ -528,7 +453,7 @@ func (n *NetboxConnector) addRearPorts(t *model.Topology) error {
528453
for _, rp := range n.rearPorts {
529454
nbDev := n.devices[rp.DeviceID]
530455
if nbDev == nil {
531-
return fmt.Errorf("Device %d not found", rp.DeviceID)
456+
return fmt.Errorf("device %d not found", rp.DeviceID)
532457
}
533458

534459
d := t.GetDevice(nbDev.Name)
@@ -549,7 +474,7 @@ func (n *NetboxConnector) addFrontPorts(t *model.Topology) error {
549474
for _, fp := range n.frontPorts {
550475
nbDev := n.devices[fp.DeviceID]
551476
if nbDev == nil {
552-
return fmt.Errorf("Device %d not found", fp.DeviceID)
477+
return fmt.Errorf("device %d not found", fp.DeviceID)
553478
}
554479

555480
d := t.GetDevice(nbDev.Name)
@@ -573,62 +498,6 @@ func (n *NetboxConnector) addFrontPorts(t *model.Topology) error {
573498
return nil
574499
}
575500

576-
func getInterfaceAndVLANTag(name string) (ifName string, vt model.VLANTag, err error) {
577-
if isLogicalInterface(name) {
578-
return extractInterfaceAndUnit(name)
579-
}
580-
581-
return name, model.VLANTag{}, nil
582-
}
583-
584-
func isLogicalInterface(name string) bool {
585-
return strings.Contains(name, ".")
586-
}
587-
588-
func extractInterfaceAndUnit(name string) (string, model.VLANTag, error) {
589-
extractedVars := reSubMatchMap(ifNameTagsRegexp, name)
590-
if _, exists := extractedVars["intf_name"]; !exists {
591-
return "", model.VLANTag{}, fmt.Errorf("unable to extract interface name from %q", name)
592-
}
593-
594-
if _, exists := extractedVars["inner_tag"]; !exists {
595-
return "", model.VLANTag{}, fmt.Errorf("unable to extract inner tag from %q", name)
596-
}
597-
598-
innerTag, err := strconv.Atoi(extractedVars["inner_tag"])
599-
if err != nil {
600-
return "", model.VLANTag{}, fmt.Errorf("unable to convert inner tag from string %q to int (%q)", extractedVars["inner_tag"], name)
601-
}
602-
603-
vt := model.VLANTag{
604-
InnerTag: uint16(innerTag),
605-
}
606-
607-
outerTagStr := extractedVars["outer_tag"]
608-
if outerTagStr != "" {
609-
outerTag, err := strconv.Atoi(outerTagStr)
610-
if err != nil {
611-
return "", model.VLANTag{}, fmt.Errorf("unable to convert outer tag from string %q to int (%q)", outerTagStr, name)
612-
}
613-
614-
vt.OuterTag = uint16(outerTag)
615-
}
616-
617-
return extractedVars["intf_name"], vt, nil
618-
}
619-
620-
func reSubMatchMap(r *regexp.Regexp, str string) map[string]string {
621-
match := r.FindStringSubmatch(str)
622-
subMatchMap := make(map[string]string)
623-
for i, name := range r.SubexpNames() {
624-
if i != 0 && name != "" && i <= len(match) {
625-
subMatchMap[name] = match[i]
626-
}
627-
}
628-
629-
return subMatchMap
630-
}
631-
632501
func (n *NetboxConnector) StartRefreshRoutine() {
633502
go n.refreshRoutine()
634503
}

pkg/connector/netbox/netbox_test.go

-52
Original file line numberDiff line numberDiff line change
@@ -1019,55 +1019,3 @@ func TestEnrichment(t *testing.T) {
10191019
assert.Equal(t, test.expected, test.t.ToProto(), test.name)
10201020
}
10211021
}
1022-
1023-
func TestExtractInterfaceAndUnit(t *testing.T) {
1024-
tests := []struct {
1025-
name string
1026-
input string
1027-
expectedName string
1028-
expectedVLANTag model.VLANTag
1029-
wantFail bool
1030-
}{
1031-
{
1032-
name: "dot1q",
1033-
input: "vlan.900",
1034-
expectedName: "vlan",
1035-
expectedVLANTag: model.NewVLANTag(0, 900),
1036-
},
1037-
{
1038-
name: "Q-in-Q",
1039-
input: "xe-0/0/0.100.200",
1040-
expectedName: "xe-0/0/0",
1041-
expectedVLANTag: model.NewVLANTag(100, 200),
1042-
},
1043-
{
1044-
name: "broken",
1045-
input: "xe-0/0/0",
1046-
expectedName: "xe-0/0/0",
1047-
expectedVLANTag: model.NewVLANTag(100, 200),
1048-
wantFail: true,
1049-
},
1050-
}
1051-
1052-
for _, test := range tests {
1053-
t.Run(test.name, func(t *testing.T) {
1054-
ifName, vt, err := extractInterfaceAndUnit(test.input)
1055-
if err != nil {
1056-
if test.wantFail {
1057-
return
1058-
}
1059-
1060-
t.Errorf("unexpected failure of test %q: %v", test.name, err)
1061-
return
1062-
}
1063-
1064-
if test.wantFail {
1065-
t.Errorf("unexpected success of test %q", test.name)
1066-
return
1067-
}
1068-
1069-
assert.Equal(t, test.expectedName, ifName, test.name)
1070-
assert.Equal(t, test.expectedVLANTag, vt, test.name)
1071-
})
1072-
}
1073-
}

0 commit comments

Comments
 (0)