Skip to content
Snippets Groups Projects
Select Git revision
  • 395ed59e90c2e536d556efd6dbff0e4f77f1dcd8
  • master default protected
  • renovate/google.golang.org-grpc-1.x
  • renovate/golang.org-x-net-0.x
  • renovate/google.golang.org-protobuf-1.x
  • renovate/github.com-spf13-viper-1.x
  • renovate/golang.org-x-sys-0.x
  • renovate/github.com-openconfig-ygot-0.x
  • renovate/github.com-spf13-cobra-1.x
  • renovate/golangci-golangci-lint-2.x
  • renovate/github.com-openconfig-goyang-1.x
  • ca-file-in-manual-fix
  • interface-enabled-test
  • dummy-target
  • unmarshal-set-request
  • setup-goreleaser
  • wg4-kms-setup
17 results

ubuntu.go

Blame
  • user avatar
    Malte Bauch authored
    395ed59e
    History
    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)
    //		}
    //	}
    //
    //}