-
Malte Bauch authoredMalte Bauch authored
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
network-element.go 3.70 KiB
package main
import (
"context"
"encoding/json"
"fmt"
"time"
"code.fbi.h-da.de/danet/gosdn/api/go/gosdn/device"
"code.fbi.h-da.de/danet/gosdn/application-framework/models"
"code.fbi.h-da.de/danet/gosdn/models/generated/arista"
"github.com/google/uuid"
"github.com/openconfig/ygot/ygot"
"github.com/openconfig/ygot/ytypes"
)
var statusMap map[string]map[string]*InterfaceStatus
// NetworkElement is a NetworkElement.
type NetworkElement struct {
// UUID represents the Devices UUID
UUID uuid.UUID
// Name is the device's human readable Name
Name string
// Device embeds a ygot.GoStruct containing the device details
Model arista.Device
}
// NewNetworkElement creates a new NetworkElement.
func NewNetworkElement(id uuid.UUID, name string, deviceModel string) *NetworkElement {
d := &NetworkElement{
UUID: id,
Model: arista.Device{},
Name: name,
}
// Create 'root' path to be able to load the whole model from the store.
path, err := ygot.StringToPath("/", ygot.StructuredPath)
if err != nil {
panic(err)
}
opts := []ytypes.UnmarshalOpt{
&ytypes.IgnoreExtraFields{},
}
// Use unmarshall from the devices SBI to unmarshall ygot json in go struct.
err = models.Unmarshal([]byte(deviceModel), path, &d.Model, opts...)
if err != nil {
panic(err)
}
return d
}
type InterfaceStatus struct {
NetworkElementName string
Name string
Status string
}
func checkIfOperationStateHasChanged(deviceServer device.DeviceServiceClient, networkElementID uuid.UUID) ([]InterfaceStatus, error) {
ctx := context.Background()
request := &device.GetDeviceRequest{
Timestamp: time.Now().UnixNano(),
DeviceID: networkElementID.String(),
}
resp, err := deviceServer.Get(ctx, request)
if err != nil {
return nil, err
}
networkElement := NewNetworkElement(uuid.MustParse(resp.Device.Id), resp.Device.Name, resp.Device.Model)
storedInterfaces, ok := statusMap[networkElement.Name]
if !ok {
addDeviceToStatusMap(networkElement.Name, *&networkElement.Model.Interfaces.Interface)
return nil, nil
}
return walkThroughInterfaces(*&networkElement.Model.Interfaces.Interface, storedInterfaces)
}
func addDeviceToStatusMap(networkElementName string, interfaces map[string]*arista.OpenconfigInterfaces_Interfaces_Interface) {
statusList := make(map[string]*InterfaceStatus)
for _, receivedInterface := range interfaces {
statusList[*receivedInterface.Name] = &InterfaceStatus{
NetworkElementName: networkElementName,
Name: *receivedInterface.Name,
Status: receivedInterface.State.OperStatus.String(),
}
}
statusMap[networkElementName] = statusList
}
func walkThroughInterfaces(interfaces map[string]*arista.OpenconfigInterfaces_Interfaces_Interface, storedInterfaces map[string]*InterfaceStatus) ([]InterfaceStatus, error) {
statusList := make([]InterfaceStatus, 0)
for _, receivedInterface := range interfaces {
storedInterface, ok := storedInterfaces[*receivedInterface.Name]
if !ok {
return statusList, fmt.Errorf("could not find %s in stored interfaces", *receivedInterface.Name)
}
if storedInterface.Status != receivedInterface.State.OperStatus.String() {
statusList = append(statusList, InterfaceStatus{
NetworkElementName: storedInterface.NetworkElementName,
Name: *receivedInterface.Name,
Status: receivedInterface.State.OperStatus.String(),
})
storedInterface.Status = receivedInterface.State.OperStatus.String()
statusMapCopy := statusMap
go func() {
b, err := json.Marshal(statusMapCopy)
if err != nil {
fmt.Println("error: ", err)
return
}
for clientChannel := range clientChannels {
clientChannel <- []byte(b)
}
}()
}
}
return statusList, nil
}