Improve visuals and code structure
This commit is contained in:
parent
25adf0f374
commit
a5084c57f0
8 changed files with 485 additions and 184 deletions
115
internal/cache/datacache.go
vendored
Normal file
115
internal/cache/datacache.go
vendored
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
package cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"git.faercol.me/faercol/topology-map/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewDataCache() *DataCache {
|
||||||
|
return &DataCache{
|
||||||
|
lock: sync.Mutex{},
|
||||||
|
devices: make(map[int]*models.Device),
|
||||||
|
interfaces: make(map[int]*models.Interface),
|
||||||
|
cables: make(map[int]*models.Cable),
|
||||||
|
vms: make(map[int]*models.VM),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type DataCache struct {
|
||||||
|
lock sync.Mutex
|
||||||
|
devices map[int]*models.Device
|
||||||
|
interfaces map[int]*models.Interface
|
||||||
|
cables map[int]*models.Cable
|
||||||
|
vms map[int]*models.VM
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataCache) AddDevice(device models.Device) {
|
||||||
|
d.lock.Lock()
|
||||||
|
defer d.lock.Unlock()
|
||||||
|
d.devices[device.ID] = &device
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataCache) GetDevices() []*models.Device {
|
||||||
|
d.lock.Lock()
|
||||||
|
defer d.lock.Unlock()
|
||||||
|
|
||||||
|
var res []*models.Device
|
||||||
|
for _, dev := range d.devices {
|
||||||
|
res = append(res, dev)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataCache) AddInterface(iface models.Interface) {
|
||||||
|
d.lock.Lock()
|
||||||
|
defer d.lock.Unlock()
|
||||||
|
d.interfaces[iface.ID] = &iface
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataCache) GetInterfaces() []*models.Interface {
|
||||||
|
d.lock.Lock()
|
||||||
|
defer d.lock.Unlock()
|
||||||
|
|
||||||
|
var res []*models.Interface
|
||||||
|
for _, iface := range d.interfaces {
|
||||||
|
res = append(res, iface)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataCache) AddCable(cable models.Cable) {
|
||||||
|
d.lock.Lock()
|
||||||
|
defer d.lock.Unlock()
|
||||||
|
d.cables[cable.ID] = &cable
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataCache) GetCables() []*models.Cable {
|
||||||
|
d.lock.Lock()
|
||||||
|
defer d.lock.Unlock()
|
||||||
|
|
||||||
|
var res []*models.Cable
|
||||||
|
for _, cable := range d.cables {
|
||||||
|
res = append(res, cable)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataCache) AddVM(vm models.VM) {
|
||||||
|
d.lock.Lock()
|
||||||
|
defer d.lock.Unlock()
|
||||||
|
d.vms[vm.ID] = &vm
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataCache) GetVMs() []*models.VM {
|
||||||
|
d.lock.Lock()
|
||||||
|
defer d.lock.Unlock()
|
||||||
|
|
||||||
|
var res []*models.VM
|
||||||
|
for _, vm := range d.vms {
|
||||||
|
res = append(res, vm)
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *DataCache) ReconcileData() {
|
||||||
|
d.lock.Lock()
|
||||||
|
defer d.lock.Unlock()
|
||||||
|
|
||||||
|
for id, cable := range d.cables {
|
||||||
|
ifaceA, ok := d.interfaces[cable.ATerminations[0].ObjectID]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cable.ATerminations[0].Object.Interface = *ifaceA
|
||||||
|
|
||||||
|
ifaceB, ok := d.interfaces[cable.BTerminations[0].ObjectID]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cable.BTerminations[0].Object.Interface = *ifaceB
|
||||||
|
|
||||||
|
d.cables[id] = cable
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
14
internal/models/cytoscape.go
Normal file
14
internal/models/cytoscape.go
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
type ElementData struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
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,omitempty"`
|
||||||
|
}
|
145
internal/models/netbox.go
Normal file
145
internal/models/netbox.go
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
package models
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
const (
|
||||||
|
Iface2dot5G = "2.5gbase-t"
|
||||||
|
Iface1G = "1000base-t"
|
||||||
|
Iface100M = "100base-tx"
|
||||||
|
)
|
||||||
|
|
||||||
|
var speedAssociation map[string]int = map[string]int{
|
||||||
|
"2.5gbase-t": 2500,
|
||||||
|
"1000base-t": 1000,
|
||||||
|
"100base-tx": 100,
|
||||||
|
}
|
||||||
|
|
||||||
|
type DeviceRole struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Slug string `json:"slug"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Device struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Role DeviceRole `json:"role"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d Device) UniqueID() string {
|
||||||
|
return "device-" + strconv.FormatInt(int64(d.ID), 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d Device) Element() Element {
|
||||||
|
return Element{
|
||||||
|
Data: ElementData{
|
||||||
|
ID: d.UniqueID(),
|
||||||
|
Label: d.Name,
|
||||||
|
},
|
||||||
|
Classes: nil,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type InterfaceType struct {
|
||||||
|
Value string `json:"value"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Interface struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Device Device `json:"device"`
|
||||||
|
MacAddress string `json:"mac_address"`
|
||||||
|
Type InterfaceType `json:"type"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i Interface) MaxSpeed() int {
|
||||||
|
speed, ok := speedAssociation[i.Type.Value]
|
||||||
|
if !ok {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return speed
|
||||||
|
}
|
||||||
|
|
||||||
|
type Object struct {
|
||||||
|
Device Device `json:"device"`
|
||||||
|
Interface Interface
|
||||||
|
}
|
||||||
|
|
||||||
|
type CableTermination struct {
|
||||||
|
ObjectID int `json:"object_id"`
|
||||||
|
Object Object `json:"object"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Cable struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
ATerminations []CableTermination `json:"a_terminations"`
|
||||||
|
BTerminations []CableTermination `json:"b_terminations"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cable) UniqueID() string {
|
||||||
|
return "link-" + strconv.FormatInt(int64(c.ID), 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cable) MaxSpeed() int {
|
||||||
|
speedA := c.ATerminations[0].Object.Interface.MaxSpeed()
|
||||||
|
speedB := c.BTerminations[0].Object.Interface.MaxSpeed()
|
||||||
|
|
||||||
|
if speedA > speedB {
|
||||||
|
return speedB
|
||||||
|
}
|
||||||
|
return speedA
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Cable) Element() Element {
|
||||||
|
|
||||||
|
var linkClass string
|
||||||
|
switch c.MaxSpeed() {
|
||||||
|
case 2500:
|
||||||
|
linkClass = "link-fast"
|
||||||
|
case 1000:
|
||||||
|
linkClass = "link-normal"
|
||||||
|
case 100:
|
||||||
|
linkClass = "link-slow"
|
||||||
|
default:
|
||||||
|
linkClass = "link-speed-unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
return Element{
|
||||||
|
Data: ElementData{
|
||||||
|
ID: c.UniqueID(),
|
||||||
|
Source: c.ATerminations[0].Object.Device.UniqueID(),
|
||||||
|
Target: c.BTerminations[0].Object.Device.UniqueID(),
|
||||||
|
},
|
||||||
|
Classes: []string{"link", linkClass},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type VM struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Device Device `json:"device"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v VM) UniqueID() string {
|
||||||
|
return "vm-" + strconv.FormatInt(int64(v.ID), 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v VM) Elements() []Element {
|
||||||
|
return []Element{
|
||||||
|
{
|
||||||
|
Data: ElementData{
|
||||||
|
ID: v.UniqueID(),
|
||||||
|
Label: v.Name,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Data: ElementData{
|
||||||
|
ID: "vm-cable" + strconv.FormatInt(int64(v.ID), 10),
|
||||||
|
Source: v.UniqueID(),
|
||||||
|
Target: v.Device.UniqueID(),
|
||||||
|
},
|
||||||
|
Classes: []string{"link", "link-virtual"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
124
internal/netbox/netbox.go
Normal file
124
internal/netbox/netbox.go
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
package netbox
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"git.faercol.me/faercol/topology-map/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
devicesRoute = "dcim/devices"
|
||||||
|
cablesRoute = "dcim/cables"
|
||||||
|
vmsRoute = "virtualization/virtual-machines"
|
||||||
|
interfaceRoute = "dcim/interfaces"
|
||||||
|
)
|
||||||
|
|
||||||
|
type vmsResponse struct {
|
||||||
|
Results []models.VM `json:"results"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type deviceResponse struct {
|
||||||
|
Results []models.Device `json:"results"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type cableResponse struct {
|
||||||
|
Results []models.Cable `json:"results"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type interfaceResponse struct {
|
||||||
|
Results []models.Interface `json:"results"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NetboxClient struct {
|
||||||
|
httpClt *http.Client
|
||||||
|
netboxBaseURL string
|
||||||
|
netboxToken string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *NetboxClient) queryAPI(route string) ([]byte, error) {
|
||||||
|
query, err := http.NewRequest("GET", c.netboxBaseURL+route, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
query.Header.Set("Authorization", "Token "+c.netboxToken)
|
||||||
|
|
||||||
|
resp, err := c.httpClt.Do(query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
respBody, err := io.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return respBody, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *NetboxClient) GetDevices() ([]models.Device, error) {
|
||||||
|
var res deviceResponse
|
||||||
|
|
||||||
|
respBody, err := c.queryAPI(devicesRoute)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(respBody, &res); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.Results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *NetboxClient) GetInterfaces() ([]models.Interface, error) {
|
||||||
|
var res interfaceResponse
|
||||||
|
|
||||||
|
respBody, err := c.queryAPI(interfaceRoute)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(respBody, &res); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return res.Results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *NetboxClient) GetCables() ([]models.Cable, error) {
|
||||||
|
var res cableResponse
|
||||||
|
|
||||||
|
respBody, err := c.queryAPI(cablesRoute)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(respBody, &res); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.Results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *NetboxClient) GetVMs() ([]models.VM, error) {
|
||||||
|
var res vmsResponse
|
||||||
|
|
||||||
|
respBody, err := c.queryAPI(vmsRoute)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(respBody, &res); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.Results, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(baseURL, token string) *NetboxClient {
|
||||||
|
return &NetboxClient{
|
||||||
|
httpClt: http.DefaultClient,
|
||||||
|
netboxBaseURL: baseURL,
|
||||||
|
netboxToken: token,
|
||||||
|
}
|
||||||
|
}
|
215
main.go
215
main.go
|
@ -4,142 +4,62 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"io"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
|
||||||
|
"git.faercol.me/faercol/topology-map/internal/cache"
|
||||||
|
"git.faercol.me/faercol/topology-map/internal/models"
|
||||||
|
"git.faercol.me/faercol/topology-map/internal/netbox"
|
||||||
)
|
)
|
||||||
|
|
||||||
const apiKey = "4e75b8927940adc29e2e1eac042bf92bcddd57fe"
|
const apiKey = "4e75b8927940adc29e2e1eac042bf92bcddd57fe"
|
||||||
const netboxBaseURL = "https://netbox.internal.faercol.me/api/"
|
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() {
|
func main() {
|
||||||
|
|
||||||
|
fmt.Println("Initializing data")
|
||||||
|
dataCache := cache.NewDataCache()
|
||||||
|
netboxClt := netbox.NewClient(netboxBaseURL, apiKey)
|
||||||
|
|
||||||
|
fmt.Println("Getting devices")
|
||||||
|
devices, err := netboxClt.GetDevices()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
for _, d := range devices {
|
||||||
|
dataCache.AddDevice(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Getting VMs")
|
||||||
|
vms, err := netboxClt.GetVMs()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
for _, v := range vms {
|
||||||
|
dataCache.AddVM(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Getting cables")
|
||||||
|
cables, err := netboxClt.GetCables()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
for _, c := range cables {
|
||||||
|
dataCache.AddCable(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Getting interfaces")
|
||||||
|
interfaces, err := netboxClt.GetInterfaces()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
for _, i := range interfaces {
|
||||||
|
dataCache.AddInterface(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Reconciling data")
|
||||||
|
dataCache.ReconcileData()
|
||||||
|
fmt.Println("Done")
|
||||||
|
|
||||||
srv := http.NewServeMux()
|
srv := http.NewServeMux()
|
||||||
|
|
||||||
srv.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) {
|
srv.HandleFunc("/static/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -149,36 +69,16 @@ func main() {
|
||||||
})
|
})
|
||||||
srv.HandleFunc("/api/data", func(w http.ResponseWriter, r *http.Request) {
|
srv.HandleFunc("/api/data", func(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Println("Serving API route")
|
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()
|
resp := []models.Element{}
|
||||||
if err != nil {
|
for _, d := range dataCache.GetDevices() {
|
||||||
fmt.Printf("Failed to get cables: %s\n", err)
|
resp = append(resp, d.Element())
|
||||||
w.WriteHeader(500)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
for _, c := range dataCache.GetCables() {
|
||||||
vms, err := GetVMs()
|
resp = append(resp, c.Element())
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Failed to get VMs: %s\n", err)
|
|
||||||
w.WriteHeader(500)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
for _, v := range dataCache.GetVMs() {
|
||||||
resp := []Element{}
|
resp = append(resp, v.Elements()...)
|
||||||
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)
|
respBody, err := json.Marshal(resp)
|
||||||
|
@ -188,6 +88,7 @@ func main() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w.Header().Add("Content-Type", "application/json")
|
||||||
w.Write(respBody)
|
w.Write(respBody)
|
||||||
})
|
})
|
||||||
srv.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
srv.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -206,7 +107,7 @@ func main() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if err := http.ListenAndServe("127.0.0.1:5000", srv); err != nil {
|
if err := http.ListenAndServe("0.0.0.0:5000", srv); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,28 +21,17 @@ function setupGraph() {
|
||||||
.then(function (elements) {
|
.then(function (elements) {
|
||||||
|
|
||||||
var cy = window.cy = cytoscape({
|
var cy = window.cy = cytoscape({
|
||||||
|
container: document.getElementById('map-container'),
|
||||||
container: document.getElementById('map-container'), // container to render in
|
|
||||||
|
|
||||||
elements: elements,
|
elements: elements,
|
||||||
// elements: [ // list of graph elements to start with
|
|
||||||
// { // node a
|
|
||||||
// data: { id: 'a' }
|
|
||||||
// },
|
|
||||||
// { // node b
|
|
||||||
// data: { id: 'b' }
|
|
||||||
// },
|
|
||||||
// { // edge ab
|
|
||||||
// data: { id: 'ab', source: 'a', target: 'b' }
|
|
||||||
// }
|
|
||||||
// ],
|
|
||||||
|
|
||||||
style: [ // the stylesheet for the graph
|
style: [ // the stylesheet for the graph
|
||||||
{
|
{
|
||||||
selector: 'node',
|
selector: 'node',
|
||||||
style: {
|
style: {
|
||||||
'background-color': '#666',
|
'background-color': '#E1F5FE',
|
||||||
'label': 'data(id)'
|
'border-color': '#03A9F4',
|
||||||
|
'border-width': 0.5,
|
||||||
|
'label': 'data(label)'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -50,23 +39,37 @@ function setupGraph() {
|
||||||
selector: 'edge',
|
selector: 'edge',
|
||||||
style: {
|
style: {
|
||||||
'width': 1,
|
'width': 1,
|
||||||
'line-color': '#1E88E5',
|
'line-color': '#42A5F5',
|
||||||
'target-arrow-color': '#1E88E5',
|
'target-arrow-color': '#1E88E5',
|
||||||
'target-arrow-shape': 'none',
|
'target-arrow-shape': 'none',
|
||||||
'curve-style': 'bezier'
|
'curve-style': 'bezier'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
selector: ".virtual-edge",
|
selector: ".link-virtual",
|
||||||
style: {
|
style: {
|
||||||
"line-color": "#BDBDBD",
|
"line-color": "#BDBDBD",
|
||||||
"line-style": "dashed",
|
"line-style": "dashed",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
{
|
||||||
|
selector: ".link-fast",
|
||||||
|
style: {
|
||||||
|
"width": 1.5,
|
||||||
|
"line-color": "#1565C0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
selector: ".link-slow",
|
||||||
|
style: {
|
||||||
|
"line-color": "#FFC107",
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
layout: {
|
layout: {
|
||||||
name: 'cola',
|
name: 'cose',
|
||||||
|
nodeDimensionsIncludeLabels: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#map-container {
|
#map-container {
|
||||||
width: 80%;
|
width: 95%;
|
||||||
height: 600px;
|
height: 1200px;
|
||||||
|
margin: auto;
|
||||||
display: block;
|
display: block;
|
||||||
}
|
background-color: #F5F5F5;
|
||||||
|
border-color: #BDBDBD;
|
||||||
.edge {
|
|
||||||
color: pink;
|
|
||||||
}
|
}
|
BIN
topology-map
BIN
topology-map
Binary file not shown.
Loading…
Reference in a new issue