topology-map/main.go
2024-09-17 18:39:53 +02:00

212 lines
4.6 KiB
Go

package main
import (
"encoding/json"
"fmt"
"html/template"
"io"
"net/http"
"strconv"
)
const apiKey = "4e75b8927940adc29e2e1eac042bf92bcddd57fe"
const netboxBaseURL = "https://netbox.internal.faercol.me/api/"
type Device struct {
ID int `json:"id"`
Name string `json:"name"`
}
type Object struct {
Device Device `json:"device"`
}
type CableTermination struct {
Object Object `json:"object"`
}
type Cable struct {
ID int `json:"id"`
ATerminations []CableTermination `json:"a_terminations"`
BTerminations []CableTermination `json:"b_terminations"`
}
type VM struct {
ID int `json:"id"`
Name string `json:"name"`
Device Device `json:"device"`
}
type vmsResponse struct {
Results []VM `json:"results"`
}
type deviceResponse struct {
Results []Device `json:"results"`
}
type cableResponse struct {
Results []Cable `json:"results"`
}
type ElementData struct {
ID string `json:"id"`
Source string `json:"source,omitempty"`
Target string `json:"target,omitempty"`
Parent string `json:"parent,omitempty"`
}
type Element struct {
Data ElementData `json:"data"`
Classes []string `json:"classes"`
}
func GetDevices() ([]Device, error) {
query, err := http.NewRequest("GET", netboxBaseURL+"dcim/devices", nil)
if err != nil {
return nil, err
}
query.Header.Set("Authorization", "Token "+apiKey)
resp, err := http.DefaultClient.Do(query)
if err != nil {
return nil, err
}
var res deviceResponse
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if err := json.Unmarshal(respBody, &res); err != nil {
return nil, err
}
return res.Results, nil
}
func GetCables() ([]Cable, error) {
query, err := http.NewRequest("GET", netboxBaseURL+"dcim/cables", nil)
if err != nil {
return nil, err
}
query.Header.Set("Authorization", "Token "+apiKey)
resp, err := http.DefaultClient.Do(query)
if err != nil {
return nil, err
}
var res cableResponse
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if err := json.Unmarshal(respBody, &res); err != nil {
return nil, err
}
return res.Results, nil
}
func GetVMs() ([]VM, error) {
query, err := http.NewRequest("GET", netboxBaseURL+"virtualization/virtual-machines", nil)
if err != nil {
return nil, err
}
query.Header.Set("Authorization", "Token "+apiKey)
resp, err := http.DefaultClient.Do(query)
if err != nil {
return nil, err
}
var res vmsResponse
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if err := json.Unmarshal(respBody, &res); err != nil {
return nil, err
}
return res.Results, nil
}
func main() {
srv := http.NewServeMux()
srv.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) {
fmt.Println("Serving static file")
fs := http.FileServer(http.Dir("./static"))
http.StripPrefix("/static", fs).ServeHTTP(w, r)
})
srv.HandleFunc("/api/data", func(w http.ResponseWriter, r *http.Request) {
fmt.Println("Serving API route")
devices, err := GetDevices()
if err != nil {
fmt.Printf("Failed to get devices: %s\n", err)
w.WriteHeader(500)
return
}
cables, err := GetCables()
if err != nil {
fmt.Printf("Failed to get cables: %s\n", err)
w.WriteHeader(500)
return
}
vms, err := GetVMs()
if err != nil {
fmt.Printf("Failed to get VMs: %s\n", err)
w.WriteHeader(500)
return
}
resp := []Element{}
for _, d := range devices {
resp = append(resp, Element{Data: ElementData{ID: d.Name}})
}
for _, c := range cables {
resp = append(resp, Element{Data: ElementData{ID: "link-" + strconv.FormatInt(int64(c.ID), 10), Source: c.ATerminations[0].Object.Device.Name, Target: c.BTerminations[0].Object.Device.Name}})
}
for _, v := range vms {
resp = append(resp, Element{Data: ElementData{ID: v.Name}}, Element{Data: ElementData{ID: "vm-" + strconv.FormatInt(int64(v.ID), 10), Source: v.Name, Target: v.Device.Name}, Classes: []string{"edge", "virtual-edge"}})
}
respBody, err := json.Marshal(resp)
if err != nil {
fmt.Printf("Failed to serialize data: %s\n", err)
w.WriteHeader(500)
return
}
w.Write(respBody)
})
srv.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Println("Serving main root")
tpl, err := template.New("index.html").ParseFiles("templates/index.html")
if err != nil {
fmt.Printf("Failed to read template: %s\n", err)
w.WriteHeader(500)
return
}
if err := tpl.Execute(w, nil); err != nil {
fmt.Printf("Failed to execute template: %s\n", err)
w.WriteHeader(500)
return
}
})
if err := http.ListenAndServe("127.0.0.1:5000", srv); err != nil {
panic(err)
}
}