Select Git revision
docker-compose.yml
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ubuntu.go 7.28 KiB
package ubuntu
import (
"net"
"os"
"os/exec"
"strings"
"syscall"
"time"
"code.fbi.h-da.de/danet/gnmi-target/modeldata/gnmitargetygot"
gnmiv "github.com/openconfig/gnmi/value"
"github.com/openconfig/ygot/ygot"
log "github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
)
type OsclientUbuntu struct {
gt *gnmitargetygot.Gnmitarget
}
func NewOsclientUbuntu() *OsclientUbuntu {
client := new(OsclientUbuntu)
return client
}
func (ou OsclientUbuntu) UpdateConfig(config *ygot.ValidatedGoStruct) error {
*config = ou.GetConfig()
return nil
}
func (ou *OsclientUbuntu) GetConfig() *gnmitargetygot.Gnmitarget {
ou.gt = &gnmitargetygot.Gnmitarget{}
// // Create Interfaces
// h, err := netlink.NewHandle()
// if err != nil {
// log.WithFields(log.Fields{}).Error(err)
// }
// // defer h.Delete()
// localIfaces, err := h.LinkList()
// if err != nil {
// log.WithFields(log.Fields{}).Error(err)
// }
// for _, localIface := range localIfaces {
// ou.createInterfaces(localIface, ou.gt)
// }
ou.getSystem(ou.gt)
return ou.gt
}
func (ou *OsclientUbuntu) GetCallbackFunc() func(ygot.ValidatedGoStruct) error {
return ou.callbackFunc
}
func (ou *OsclientUbuntu) callbackFunc(config ygot.ValidatedGoStruct) error {
diffs, err := ygot.Diff(ou.GetConfig(), config)
if err != nil {
return err
}
for _, diff := range diffs.GetUpdate() {
path, err := ygot.PathToString(diff.GetPath())
if err != nil {
return err
}
log.Info(path)
switch path {
case "/system/config/hostname":
value, err := gnmiv.ToScalar(diff.GetVal())
if err != nil {
return err
}
err = syscall.Sethostname([]byte(value.(string)))
if err != nil {
return err
}
default:
//INFO: currently this case is ignored
}
}
return nil
}
func (ou OsclientUbuntu) createInterfaces(localIface netlink.Link, gt *gnmitargetygot.Gnmitarget) {
//experiment with the ygot struct
//populate with data HERE
attributes := localIface.Attrs()
interfaces := gt.GetOrCreateInterfaces()
iface, err := interfaces.NewInterface(attributes.Name)
if err != nil {
log.Error("failed to create new interface")
log.WithFields(log.Fields{}).Error(err)
}
state := iface.GetOrCreateState()
config := iface.GetOrCreateConfig()
state.Ifindex = ygot.Uint32(uint32(attributes.Index))
iface.Name = ygot.String(attributes.Name)
//base ethernet interface type would be 6 (see iana-if-type.yang)
config.Type = gnmitargetygot.IETFInterfaces_InterfaceType_UNSET
config.Mtu = ygot.Uint16(uint16(attributes.MTU))
state.OperStatus = setOperState(attributes.OperState)
if attributes.Flags&net.FlagUp != 0 {
state.AdminStatus = gnmitargetygot.OpenconfigInterfaces_Interfaces_Interface_State_AdminStatus_UP
}
if attributes.Flags&net.FlagLoopback != 0 {
state.LoopbackMode = ygot.Bool(true)
}
ipv4Addresses, err := netlink.AddrList(localIface, netlink.FAMILY_V4)
if err != nil {
log.WithFields(log.Fields{}).Error(err)
}
ipv6Addresses, err := netlink.AddrList(localIface, netlink.FAMILY_V6)
if err != nil {
log.WithFields(log.Fields{}).Error(err)
}
for i, addr := range ipv4Addresses {
subiface := iface.GetOrCreateSubinterfaces().GetOrCreateSubinterface(uint32(i))
subiface.GetOrCreateConfig()
subiface.GetOrCreateState()
ipv4 := subiface.GetOrCreateIpv4()
ipv4Addr := ipv4.GetOrCreateAddresses().GetOrCreateAddress(addr.IP.String())
ipv4AddrConf := ipv4Addr.GetOrCreateConfig()
ipv4AddrConf.Ip = ygot.String(addr.IP.String())
prefix, _ := addr.IPNet.Mask.Size()
convPrefix := uint8(prefix)
ipv4AddrConf.PrefixLength = &convPrefix
}
for i, addr := range ipv6Addresses {
subiface := iface.GetOrCreateSubinterfaces().GetOrCreateSubinterface(uint32(i))
subiface.GetOrCreateConfig()
subiface.GetOrCreateState()
ipv6 := subiface.GetOrCreateIpv6()
ipv6Addr := ipv6.GetOrCreateAddresses().GetOrCreateAddress(addr.IP.String())
ipv6AddrConf := ipv6Addr.GetOrCreateConfig()
ipv6AddrConf.Ip = ygot.String(addr.IP.String())
prefix, _ := addr.IPNet.Mask.Size()
convPrefix := uint8(prefix)
ipv6AddrConf.PrefixLength = &convPrefix
}
//validate struct
if err := iface.Validate(); err != nil {
log.Error("failed to validate interface on gnmitarget")
log.WithFields(log.Fields{}).Error(err)
}
}
// setOperState helper function that allows to return the correct OperStatus
// type for openconfig interfaces based on a netlink LinkOperState
func setOperState(state netlink.LinkOperState) gnmitargetygot.E_OpenconfigInterfaces_Interfaces_Interface_State_OperStatus {
switch state {
case netlink.OperUp:
return gnmitargetygot.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_UP
case netlink.OperDown:
return gnmitargetygot.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_DOWN
case netlink.OperDormant:
return gnmitargetygot.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_DORMANT
case netlink.OperTesting:
return gnmitargetygot.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_TESTING
case netlink.OperNotPresent:
return gnmitargetygot.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_NOT_PRESENT
case netlink.OperLowerLayerDown:
return gnmitargetygot.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_LOWER_LAYER_DOWN
default:
return gnmitargetygot.OpenconfigInterfaces_Interfaces_Interface_State_OperStatus_UNKNOWN
}
}
func (ou *OsclientUbuntu) getSystem(gt *gnmitargetygot.Gnmitarget) {
system := gt.GetOrCreateSystem()
name, err := os.Hostname()
if err != nil {
panic(err)
}
state := system.GetOrCreateState()
config := system.GetOrCreateConfig()
clock := system.GetOrCreateClock()
// Create Config
config.Hostname = ygot.String(name)
state.CurrentDatetime = ygot.String(time.Now().Format(time.RFC3339))
o, _ := os.Stat("/proc/")
state.BootTime = ygot.Uint64(uint64(o.ModTime().UTC().UnixNano()))
// Create Clock
output, _ := exec.Command("realpath", "--relative-to=/usr/share/zoneinfo", "/etc/localtime").Output()
ss := strings.Split(string(output), " ")
zonename := ss[len(ss)-1]
clock.GetOrCreateConfig().TimezoneName = ygot.String(strings.TrimSuffix(string(zonename), "\n"))
//validate struct
if err := system.Validate(); err != nil {
log.Error("failed to validate interface on gnmitarget")
log.WithFields(log.Fields{}).Error(err)
}
}
//TODO: this will be removed in the near future
//func (ou OsclientUbuntu) TestUbuntu() {
// ou.gt = &gnmitargetygot.Gnmitarget{}
// //setup basic logging
// log.SetReportCaller(true)
// log.SetLevel(log.DebugLevel)
//
// //experiment with ubuntu interfaces
// localIfaces, err := net.Interfaces()
// log.Println(":", localIfaces)
// if err != nil {
// log.WithFields(log.Fields{}).Error(err)
// }
//
// for _, localIface := range localIfaces {
// if localIface.Name == "eth0" {
// ou.createInterfaces(&localIface, ou.gt)
// }
// fmt.Println(localIface.Name)
// }
//
// //create configuration for conversion of struct to GNMI Notification
// //TODO: find out if we need to set PathElemPrefix ?
// gnmiconf := ygot.GNMINotificationsConfig{UsePathElem: true}
//
// notifications, err := ygot.TogNMINotifications(ou.gt, time.Now().Unix(), gnmiconf)
// if err != nil {
// log.Println("error creating gnmi notifications")
// log.WithFields(log.Fields{}).Error(err)
// } else {
// for i, notification := range notifications {
// log.Println(" notification no. ", i, " : ", *notification)
// }
// }
//
//}