Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

init #1

Merged
merged 17 commits into from
Sep 11, 2024
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,6 @@
# Go workspace file
go.work
go.work.sum

configs/settings.json
/netbox-oxidized-sync
12 changes: 12 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
linters:
enable:
- ireturn
# - err113
- revive
# - gosec
- errcheck
- nilnil
- nilerr
- asasalint
- bodyclose
- fatcontext
16 changes: 16 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Launch Package",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}/cmd/netbox-oxidized-sync/",
"cwd": "${workspaceFolder}"
}
]
}
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,26 @@
# netbox-oxidized-sync
Sync Oxidized data to Netbox
Sync Oxidized data to Netbox.

The device has to exists within netbox with the same name.
This is because we need to get the tenant and the site from netbox. (oxidized does not have that info)

Currently supports FortiOS.
Within FortiOS, the following items are synced

| Type | Supported |
|---|---|
| Vlans | ✓ |
| Aggregate ports | ✓ |
| Virtual switches | ✓ |
| Redundant Ports | ✓ |
| Normal Ports | ✓ |
| Ip Adresses | ✗ |


## Use
Currently there is no published binary so you have to build it yourself.

Clone the repo and run `go build cmd/netbox-oxidized-sync/netbox-oxidized-sync.go`
Then you can run `./netbox-oxidized-sync` to run the binary.

To configure the application copy the `configs/example.settings.json` to `configs/settings.json` and modify where needed.
88 changes: 88 additions & 0 deletions cmd/netbox-oxidized-sync/netbox-oxidized-sync.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package main

import (
"log"
"slices"
"strconv"

"github.com/mattieserver/netbox-oxidized-sync/internal/confighelper"
"github.com/mattieserver/netbox-oxidized-sync/internal/configparser"
"github.com/mattieserver/netbox-oxidized-sync/internal/httphelper"
"github.com/mattieserver/netbox-oxidized-sync/internal/model"
"github.com/mattieserver/netbox-oxidized-sync/internal/netboxparser"
)

func worker(id int, jobs <-chan httphelper.OxidizedNode, results chan<- int, netboxdevices *[]model.NetboxDevice, oxidizedhttp *httphelper.OxidizedHTTPClient, netboxhttp *httphelper.NetboxHTTPClient) {
for j := range jobs {
log.Printf("Got oxided device: '%s' on worker %s",j.Name, strconv.Itoa(id), )

idx := slices.IndexFunc(*netboxdevices, func(c model.NetboxDevice) bool { return c.Name == j.Name })
if idx == -1 {
log.Printf("Device: '%s' not found in netbox", j.Name)
} else {
log.Printf("Device: '%s' found in netbox", j.Name)
config := oxidizedhttp.GetNodeConfig(j.FullName)

switch j.Model {
case "IOS":
log.Println("IOS not supported for now")
case "FortiOS":
log.Printf("Device: '%s' has fortiOS", j.Name)
fortigateInterfaces, _ := configparser.ParseFortiOSConfig(&config)
var netboxDevice = (*netboxdevices)[idx]
netboxInterfaceForDevice := netboxhttp.GetIntefacesForDevice(strconv.Itoa(netboxDevice.ID))
netboxVlansForSite, err := netboxhttp.GetVlansForSite(strconv.Itoa(netboxDevice.Site.ID))
if err != nil {
continue
}
interfacesToUpdate := netboxparser.ParseFortigateInterfaces(fortigateInterfaces, &netboxInterfaceForDevice, strconv.Itoa(netboxDevice.ID))
netboxhttp.UpdateOrCreateInferface(&interfacesToUpdate, &netboxVlansForSite, netboxDevice.Site.ID, netboxDevice.Tenant.ID)

default:
log.Printf("Model '%s' currently not supported", j.Model)
}
}

results <- id * 2
}
}

func loadOxidizedDevices(oxidizedhttp *httphelper.OxidizedHTTPClient, netboxhttp *httphelper.NetboxHTTPClient) {
log.Println("Starting to get all Oxidized Devices")
nodes := oxidizedhttp.GetAllNodes()
log.Println("Got all Oxidized Devices")

log.Println("Starting to get all Netbox Devices")
devices := netboxhttp.GetAllDevices()
log.Println("Got all Netbox Devices")

jobs := make(chan httphelper.OxidizedNode, len(nodes))
results := make(chan int, len(nodes))

for w := 1; w <= 3; w++ {
go worker(w, jobs, results, &devices, oxidizedhttp, netboxhttp)
}

for _, element := range nodes {
jobs <- element
}
close(jobs)

for a := 1; a <= len(nodes); a++ {
<-results
}

}

func main() {
log.Println("Starting Oxidized to Netbox sync")

conf := confighelper.ReadConfig()
log.Printf("Using Netbox: %s", conf.Netbox.BaseURL)
log.Printf("Using Oxidized: %s", conf.Oxidized.BaseURL)

netboxhttp := httphelper.NewNetbox(conf.Netbox.BaseURL, conf.Netbox.APIKey, conf.Netbox.Roles)
oxidizedhttp := httphelper.NewOxidized(conf.Oxidized.BaseURL, conf.Oxidized.Username, conf.Oxidized.Password)

loadOxidizedDevices(&oxidizedhttp, &netboxhttp)
}
12 changes: 12 additions & 0 deletions configs/example.settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"netbox": {
"base_url": "http://localhost:8000",
"api_key": "xxxx-xxxx-xxxx",
"roles": ""
},
"oxidized": {
"base_url": "http://localhost:8001",
"username": "XXXXX",
"password": "YYYY"
}
}
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module github.com/mattieserver/netbox-oxidized-sync

go 1.22.1
33 changes: 33 additions & 0 deletions internal/confighelper/confighelper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package confighelper

import (
"os"
"log"
"encoding/json"
)

type Config struct {
Netbox struct {
BaseURL string `json:"base_url"`
APIKey string `json:"api_key"`
Roles string `json:"roles"`
} `json:"netbox"`
Oxidized struct {
BaseURL string `json:"base_url"`
Username string `json:"username"`
Password string `json:"password"`
} `json:"oxidized"`
}

func ReadConfig() Config {
f, err := os.ReadFile("configs/settings.json")
if err != nil {
log.Println(err)
}

var data Config
json.Unmarshal([]byte(f), &data)

return data

}
Loading