Skip to content

Commit

Permalink
feat(inventory): enable syncing of sites for vlans
Browse files Browse the repository at this point in the history
  • Loading branch information
bl4ko committed Jan 16, 2025
1 parent 046efc0 commit 1f3b15d
Show file tree
Hide file tree
Showing 12 changed files with 131 additions and 91 deletions.
2 changes: 1 addition & 1 deletion internal/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const OrphanTagName = "netbox-ssot-orphan"
const OrphanTagColor = ColorGrey
const OrphanTagDescription = "Tag used by netbox-ssot to mark orphaned objects"

const DefaultVlanGroupName = "Default netbox-ssot vlan group"
const DefaultVlanGroupName = "DefaultVlanGroup"
const DefaultVlanGroupDescription = "Default netbox-ssot VlanGroup for all vlans that are not part of any other vlanGroup. This group is required for netbox-ssot vlan index to work."

const DefaultArpTagName = "arp-entry"
Expand Down
37 changes: 37 additions & 0 deletions internal/netbox/inventory/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package inventory

import (
"context"
"fmt"

"github.com/bl4ko/netbox-ssot/internal/constants"
"github.com/bl4ko/netbox-ssot/internal/netbox/objects"
"github.com/bl4ko/netbox-ssot/internal/utils"
)

// Inits default VlanGroup, which is required to group all Vlans that are not part of other
// vlangroups into it. Each vlan is indexed by their (vlanGroup, vid).
func (nbi *NetboxInventory) CreateDefaultVlanGroupForVlan(ctx context.Context, vlanSite *objects.Site) (*objects.VlanGroup, error) {
var vlanGroupName string
if vlanSite != nil {
vlanGroupName = fmt.Sprintf("%sDefaultVlanGroup", vlanSite.Name)
} else {
vlanGroupName = constants.DefaultVlanGroupName
}
vlanGroup, err := nbi.AddVlanGroup(ctx, &objects.VlanGroup{
NetboxObject: objects.NetboxObject{
Tags: []*objects.Tag{nbi.SsotTag},
Description: constants.DefaultVlanGroupDescription,
CustomFields: map[string]interface{}{
constants.CustomFieldSourceName: nbi.SsotTag.Name,
},
},
Name: vlanGroupName,
Slug: utils.Slugify(constants.DefaultVlanGroupName),
VidRanges: []objects.VidRange{{constants.DefaultVID, constants.MaxVID}},
})
if err != nil {
return nil, fmt.Errorf("add vlan group: %s", err)
}
return vlanGroup, nil

Check warning on line 36 in internal/netbox/inventory/helpers.go

View check run for this annotation

Codecov / codecov/patch

internal/netbox/inventory/helpers.go#L14-L36

Added lines #L14 - L36 were not covered by tests
}
29 changes: 6 additions & 23 deletions internal/netbox/inventory/init_items.go
Original file line number Diff line number Diff line change
Expand Up @@ -527,27 +527,6 @@ func (nbi *NetboxInventory) initInterfaces(ctx context.Context) error {
return nil
}

// Inits default VlanGroup, which is required to group all Vlans that are not part of other
// vlangroups into it. Each vlan is indexed by their (vlanGroup, vid).
func (nbi *NetboxInventory) initDefaultVlanGroup(ctx context.Context) error {
_, err := nbi.AddVlanGroup(ctx, &objects.VlanGroup{
NetboxObject: objects.NetboxObject{
Tags: []*objects.Tag{nbi.SsotTag},
Description: constants.DefaultVlanGroupDescription,
CustomFields: map[string]interface{}{
constants.CustomFieldSourceName: nbi.SsotTag.Name,
},
},
Name: constants.DefaultVlanGroupName,
Slug: utils.Slugify(constants.DefaultVlanGroupName),
VidRanges: []objects.VidRange{{constants.DefaultVID, constants.MaxVID}},
})
if err != nil {
return fmt.Errorf("init default vlan group: %s", err)
}
return nil
}

// Collects all vlans from Netbox API and stores them to local inventory.
func (nbi *NetboxInventory) initVlanGroups(ctx context.Context) error {
nbVlanGroups, err := service.GetAll[objects.VlanGroup](ctx, nbi.NetboxAPI, "")
Expand Down Expand Up @@ -582,8 +561,12 @@ func (nbi *NetboxInventory) initVlans(ctx context.Context) error {
vlan := &nbVlans[i]
if vlan.Group == nil {
// Update all existing vlans with default vlanGroup. This only happens
// when there are predefined vlans in netbox.
vlan.Group = nbi.vlanGroupsIndexByName[constants.DefaultVlanGroupName] // This should not fail, because InitDefaultVlanGroup executes before InitVlans
// when there are predefined vlans in netbox. This is required because
// vlans are indexed by vlan group.
vlan.Group, err = nbi.CreateDefaultVlanGroupForVlan(nbi.Ctx, vlan.Site)
if err != nil {
return fmt.Errorf("create default vlan group for vlan: %s", err)
}

Check warning on line 569 in internal/netbox/inventory/init_items.go

View check run for this annotation

Codecov / codecov/patch

internal/netbox/inventory/init_items.go#L564-L569

Added lines #L564 - L569 were not covered by tests
vlan, err = nbi.AddVlan(ctx, vlan)
if err != nil {
return err
Expand Down
42 changes: 0 additions & 42 deletions internal/netbox/inventory/init_items_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -404,27 +404,6 @@ func TestNetboxInventory_InitInterfaces(t *testing.T) {
}
}

func TestNetboxInventory_InitDefaultVlanGroup(t *testing.T) {
type args struct {
ctx context.Context
}
tests := []struct {
name string
nbi *NetboxInventory
args args
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := tt.nbi.initDefaultVlanGroup(tt.args.ctx); (err != nil) != tt.wantErr {
t.Errorf("NetboxInventory.InitDefaultVlanGroup() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

func TestNetboxInventory_InitVlanGroups(t *testing.T) {
type args struct {
ctx context.Context
Expand Down Expand Up @@ -992,27 +971,6 @@ func TestNetboxInventory_initInterfaces(t *testing.T) {
}
}

func TestNetboxInventory_initDefaultVlanGroup(t *testing.T) {
type args struct {
ctx context.Context
}
tests := []struct {
name string
nbi *NetboxInventory
args args
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := tt.nbi.initDefaultVlanGroup(tt.args.ctx); (err != nil) != tt.wantErr {
t.Errorf("NetboxInventory.initDefaultVlanGroup() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

func TestNetboxInventory_initVlanGroups(t *testing.T) {
type args struct {
ctx context.Context
Expand Down
1 change: 0 additions & 1 deletion internal/netbox/inventory/inventory.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,6 @@ func (nbi *NetboxInventory) Init() error {
nbi.initInterfaces,
nbi.initIPAddresses,
nbi.initVlanGroups,
nbi.initDefaultVlanGroup,
nbi.initPrefixes,
nbi.initVlans,
nbi.initDeviceRoles,
Expand Down
4 changes: 2 additions & 2 deletions internal/source/common/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,9 @@ func MatchClusterToSite(ctx context.Context, nbi *inventory.NetboxInventory, clu
// Function that matches vlanName to vlanGroupName using regexRelationsMap.
//
// In case there is no match or regexRelations is nil, it will return default VlanGroup.
func MatchVlanToGroup(ctx context.Context, nbi *inventory.NetboxInventory, vlanName string, vlanGroupRelations map[string]string, vlanGroupSiteRelations map[string]string) (*objects.VlanGroup, error) {
func MatchVlanToGroup(ctx context.Context, nbi *inventory.NetboxInventory, vlanName string, vlanSite *objects.Site, vlanGroupRelations map[string]string, vlanGroupSiteRelations map[string]string) (*objects.VlanGroup, error) {
if vlanGroupRelations == nil {
vlanGroup, _ := nbi.GetVlanGroup(constants.DefaultVlanGroupName)
vlanGroup, _ := nbi.CreateDefaultVlanGroupForVlan(ctx, vlanSite)

Check warning on line 74 in internal/source/common/utils.go

View check run for this annotation

Codecov / codecov/patch

internal/source/common/utils.go#L72-L74

Added lines #L72 - L74 were not covered by tests
return vlanGroup, nil
}
vlanGroupName, err := utils.MatchStringToValue(vlanName, vlanGroupRelations)

Check warning on line 77 in internal/source/common/utils.go

View check run for this annotation

Codecov / codecov/patch

internal/source/common/utils.go#L77

Added line #L77 was not covered by tests
Expand Down
13 changes: 11 additions & 2 deletions internal/source/dnac/dnac_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ func (ds *DnacSource) syncSites(nbi *inventory.NetboxInventory) error {
// Syncs dnac vlans to netbox inventory.
func (ds *DnacSource) syncVlans(nbi *inventory.NetboxInventory) error {
for vid, vlan := range ds.Vlans {
vlanGroup, err := common.MatchVlanToGroup(ds.Ctx, nbi, vlan.InterfaceName, ds.SourceConfig.VlanGroupRelations, ds.SourceConfig.VlanGroupSiteRelations)
vlanSite, err := common.MatchVlanToSite(ds.Ctx, nbi, vlan.InterfaceName, ds.SourceConfig.VlanSiteRelations)
if err != nil {
return fmt.Errorf("match vlan to site: %s", err)
}
vlanGroup, err := common.MatchVlanToGroup(ds.Ctx, nbi, vlan.InterfaceName, vlanSite, ds.SourceConfig.VlanGroupRelations, ds.SourceConfig.VlanGroupSiteRelations)

Check warning on line 59 in internal/source/dnac/dnac_sync.go

View check run for this annotation

Codecov / codecov/patch

internal/source/dnac/dnac_sync.go#L55-L59

Added lines #L55 - L59 were not covered by tests
if err != nil {
return fmt.Errorf("vlanGroup: %s", err)
}
Expand All @@ -71,6 +75,7 @@ func (ds *DnacSource) syncVlans(nbi *inventory.NetboxInventory) error {
Name: vlan.InterfaceName,
Group: vlanGroup,
Vid: vid,
Site: vlanSite,

Check warning on line 78 in internal/source/dnac/dnac_sync.go

View check run for this annotation

Codecov / codecov/patch

internal/source/dnac/dnac_sync.go#L78

Added line #L78 was not covered by tests
Tenant: vlanTenant,
})
if err != nil {
Expand Down Expand Up @@ -537,7 +542,11 @@ func (ds *DnacSource) syncWirelessLANs(nbi *inventory.NetboxInventory) error {
if err != nil {
return fmt.Errorf("add wirelessLANGroup %s: %s", wlanGroup, err)
}
vlanGroup, err := common.MatchVlanToGroup(ds.Ctx, nbi, wlanWirelessProfile.InterfaceName, ds.SourceConfig.VlanGroupRelations, ds.SourceConfig.VlanGroupSiteRelations)
vlanSite, err := common.MatchVlanToSite(ds.Ctx, nbi, wlanWirelessProfile.InterfaceName, ds.SourceConfig.VlanSiteRelations)
if err != nil {
return fmt.Errorf("match vlan to site: %s", err)
}
vlanGroup, err := common.MatchVlanToGroup(ds.Ctx, nbi, wlanWirelessProfile.InterfaceName, vlanSite, ds.SourceConfig.VlanGroupRelations, ds.SourceConfig.VlanGroupSiteRelations)

Check warning on line 549 in internal/source/dnac/dnac_sync.go

View check run for this annotation

Codecov / codecov/patch

internal/source/dnac/dnac_sync.go#L545-L549

Added lines #L545 - L549 were not covered by tests
if err != nil {
return err
}
Expand Down
9 changes: 8 additions & 1 deletion internal/source/fmc/fmc_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,13 @@ func (fmcs *FMCSource) syncVlanInterfaces(nbi *inventory.NetboxInventory, nbDevi
// Add vlan
ifaceTaggedVlans := []*objects.Vlan{}
if vlanIface.VID != 0 {
vlanGroup, err := common.MatchVlanToGroup(fmcs.Ctx, nbi, vlanIface.Name, fmcs.SourceConfig.VlanGroupRelations, fmcs.SourceConfig.VlanGroupSiteRelations)
// Match vlan to site
vlanSite, err := common.MatchVlanToSite(fmcs.Ctx, nbi, vlanIface.Name, fmcs.SourceConfig.VlanSiteRelations)
if err != nil {
return fmt.Errorf("match vlan to site: %s", err)
}

Check warning on line 123 in internal/source/fmc/fmc_sync.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_sync.go#L119-L123

Added lines #L119 - L123 were not covered by tests
// Match vlan to group
vlanGroup, err := common.MatchVlanToGroup(fmcs.Ctx, nbi, vlanIface.Name, vlanSite, fmcs.SourceConfig.VlanGroupRelations, fmcs.SourceConfig.VlanGroupSiteRelations)

Check warning on line 125 in internal/source/fmc/fmc_sync.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_sync.go#L125

Added line #L125 was not covered by tests
if err != nil {
return fmt.Errorf("match vlan to group: %s", err)
}
Expand All @@ -131,6 +137,7 @@ func (fmcs *FMCSource) syncVlanInterfaces(nbi *inventory.NetboxInventory, nbDevi
},
Status: &objects.VlanStatusActive,
Name: vlanIface.Name,
Site: vlanSite,

Check warning on line 140 in internal/source/fmc/fmc_sync.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fmc/fmc_sync.go#L140

Added line #L140 was not covered by tests
Vid: vlanIface.VID,
Tenant: vlanTenent,
Group: vlanGroup,
Expand Down
10 changes: 5 additions & 5 deletions internal/source/fortigate/fortigate_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,18 +167,18 @@ func (fs *FortigateSource) syncInterfaces(nbi *inventory.NetboxInventory) error
// Add Vlan for interface
vlanID := iface.VlanID
vlanName := fmt.Sprintf("Vlan%d", vlanID)
vlanGroup, err := common.MatchVlanToGroup(fs.Ctx, nbi, vlanName, fs.SourceConfig.VlanGroupRelations, fs.SourceConfig.VlanGroupSiteRelations)
vlanSite, err := common.MatchVlanToSite(fs.Ctx, nbi, vlanName, fs.SourceConfig.VlanSiteRelations)
if err != nil {
return fmt.Errorf("match vlan to site: %s", err)
}
vlanGroup, err := common.MatchVlanToGroup(fs.Ctx, nbi, vlanName, vlanSite, fs.SourceConfig.VlanGroupRelations, fs.SourceConfig.VlanGroupSiteRelations)

Check warning on line 174 in internal/source/fortigate/fortigate_sync.go

View check run for this annotation

Codecov / codecov/patch

internal/source/fortigate/fortigate_sync.go#L170-L174

Added lines #L170 - L174 were not covered by tests
if err != nil {
return fmt.Errorf("match vlan to group: %s", err)
}
vlanTenant, err := common.MatchVlanToTenant(fs.Ctx, nbi, vlanName, fs.SourceConfig.VlanTenantRelations)
if err != nil {
return fmt.Errorf("match vlan to tenant: %s", err)
}
vlanSite, err := common.MatchVlanToSite(fs.Ctx, nbi, vlanName, fs.SourceConfig.VlanSiteRelations)
if err != nil {
return fmt.Errorf("match vlan to site: %s", err)
}
NBVlan, err := nbi.AddVlan(fs.Ctx, &objects.Vlan{
NetboxObject: objects.NetboxObject{
Tags: fs.SourceTags,
Expand Down
21 changes: 18 additions & 3 deletions internal/source/ovirt/ovirt_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,13 @@ func (o *OVirtSource) syncNetworks(nbi *inventory.NetboxInventory) error {
description, _ := network.Description()
// TODO: handle other networks
if networkVlan, exists := network.Vlan(); exists {
// Get vlanSite from relation
vlanSite, err := common.MatchVlanToSite(o.Ctx, nbi, name, o.SourceConfig.VlanSiteRelations)
if err != nil {
return fmt.Errorf("match vlan to site: %s", err)
}

Check warning on line 31 in internal/source/ovirt/ovirt_sync.go

View check run for this annotation

Codecov / codecov/patch

internal/source/ovirt/ovirt_sync.go#L27-L31

Added lines #L27 - L31 were not covered by tests
// Get vlanGroup from relation
vlanGroup, err := common.MatchVlanToGroup(o.Ctx, nbi, name, o.SourceConfig.VlanGroupRelations, o.SourceConfig.VlanGroupSiteRelations)
vlanGroup, err := common.MatchVlanToGroup(o.Ctx, nbi, name, vlanSite, o.SourceConfig.VlanGroupRelations, o.SourceConfig.VlanGroupSiteRelations)

Check warning on line 33 in internal/source/ovirt/ovirt_sync.go

View check run for this annotation

Codecov / codecov/patch

internal/source/ovirt/ovirt_sync.go#L33

Added line #L33 was not covered by tests
if err != nil {
return err
}
Expand All @@ -43,6 +48,7 @@ func (o *OVirtSource) syncNetworks(nbi *inventory.NetboxInventory) error {
Name: name,
Group: vlanGroup,
Vid: int(networkVlanID),
Site: vlanSite,

Check warning on line 51 in internal/source/ovirt/ovirt_sync.go

View check run for this annotation

Codecov / codecov/patch

internal/source/ovirt/ovirt_sync.go#L51

Added line #L51 was not covered by tests
Status: &objects.VlanStatusActive,
Tenant: vlanTenant,
Comments: network.MustComment(),
Expand Down Expand Up @@ -624,8 +630,13 @@ func (o *OVirtSource) collectHostNicsData(nbHost *objects.Device, nbi *inventory
vlanID, exists := vlan.Id()
if exists {
vlanName := o.Networks.Vid2Name[int(vlanID)]
// Get vlanSite from relation
vlanSite, err := common.MatchVlanToSite(o.Ctx, nbi, vlanName, o.SourceConfig.VlanSiteRelations)
if err != nil {
return fmt.Errorf("match vlan to site: %s", err)
}

Check warning on line 637 in internal/source/ovirt/ovirt_sync.go

View check run for this annotation

Codecov / codecov/patch

internal/source/ovirt/ovirt_sync.go#L633-L637

Added lines #L633 - L637 were not covered by tests
// Get vlanGroup from relation
vlanGroup, err := common.MatchVlanToGroup(o.Ctx, nbi, vlanName, o.SourceConfig.VlanGroupRelations, o.SourceConfig.VlanGroupSiteRelations)
vlanGroup, err := common.MatchVlanToGroup(o.Ctx, nbi, vlanName, vlanSite, o.SourceConfig.VlanGroupRelations, o.SourceConfig.VlanGroupSiteRelations)

Check warning on line 639 in internal/source/ovirt/ovirt_sync.go

View check run for this annotation

Codecov / codecov/patch

internal/source/ovirt/ovirt_sync.go#L639

Added line #L639 was not covered by tests
if err != nil {
return err
}
Expand Down Expand Up @@ -1089,7 +1100,11 @@ func (o *OVirtSource) syncVMNics(nbi *inventory.NetboxInventory, ovirtVM *ovirts
if vnicNetworkVlan, ok := vnicNetwork.Vlan(); ok {
if vlanID, ok := vnicNetworkVlan.Id(); ok {
vlanName := o.Networks.Vid2Name[int(vlanID)]
vlanGroup, err := common.MatchVlanToGroup(o.Ctx, nbi, vlanName, o.SourceConfig.VlanGroupRelations, o.SourceConfig.VlanGroupSiteRelations)
vlanSite, err := common.MatchVlanToSite(o.Ctx, nbi, vlanName, o.SourceConfig.VlanSiteRelations)
if err != nil {
return fmt.Errorf("match vlan to site: %s", err)
}
vlanGroup, err := common.MatchVlanToGroup(o.Ctx, nbi, vlanName, vlanSite, o.SourceConfig.VlanGroupRelations, o.SourceConfig.VlanGroupSiteRelations)

Check warning on line 1107 in internal/source/ovirt/ovirt_sync.go

View check run for this annotation

Codecov / codecov/patch

internal/source/ovirt/ovirt_sync.go#L1103-L1107

Added lines #L1103 - L1107 were not covered by tests
if err != nil {
o.Logger.Warningf(o.Ctx, "match vlan to group: %s", err)
continue
Expand Down
7 changes: 6 additions & 1 deletion internal/source/paloalto/paloalto_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,11 @@ func (pas *PaloAltoSource) syncInterfaces(nbi *inventory.NetboxInventory) error
if subIface.Tag != 0 {
// Extract Vlan
vlanName := fmt.Sprintf("Vlan%d", subIface.Tag)
vlanGroup, err := common.MatchVlanToGroup(pas.Ctx, nbi, vlanName, pas.SourceConfig.VlanGroupRelations, pas.SourceConfig.VlanGroupSiteRelations)
vlanSite, err := common.MatchVlanToSite(pas.Ctx, nbi, vlanName, pas.SourceConfig.VlanSiteRelations)
if err != nil {
return fmt.Errorf("match vlan to site: %s", err)
}
vlanGroup, err := common.MatchVlanToGroup(pas.Ctx, nbi, vlanName, vlanSite, pas.SourceConfig.VlanGroupRelations, pas.SourceConfig.VlanGroupSiteRelations)

Check warning on line 176 in internal/source/paloalto/paloalto_sync.go

View check run for this annotation

Codecov / codecov/patch

internal/source/paloalto/paloalto_sync.go#L172-L176

Added lines #L172 - L176 were not covered by tests
if err != nil {
return fmt.Errorf("match vlan to group: %s", err)
}
Expand All @@ -185,6 +189,7 @@ func (pas *PaloAltoSource) syncInterfaces(nbi *inventory.NetboxInventory) error
Status: &objects.VlanStatusActive,
Name: fmt.Sprintf("Vlan%d", subIface.Tag),
Vid: subIface.Tag,
Site: vlanSite,

Check warning on line 192 in internal/source/paloalto/paloalto_sync.go

View check run for this annotation

Codecov / codecov/patch

internal/source/paloalto/paloalto_sync.go#L192

Added line #L192 was not covered by tests
Tenant: vlanTenant,
Group: vlanGroup,
}
Expand Down
Loading

0 comments on commit 1f3b15d

Please sign in to comment.