212 lines
4.6 KiB
Go
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)
|
|
}
|
|
}
|