Skip to content
Snippets Groups Projects
target.go 4.11 KiB
Newer Older
  • Learn to ignore specific revisions
  • package gnmitarget
    
    import (
    	"crypto/tls"
    	"crypto/x509"
    	"net"
    	"os"
    	"reflect"
    
    	"code.fbi.h-da.de/danet/gnmi-target/handler"
    	server "code.fbi.h-da.de/danet/gnmi-target/internal/gnmiserver"
    
    	"google.golang.org/grpc"
    	"google.golang.org/grpc/credentials"
    	"google.golang.org/grpc/reflection"
    
    	not "code.fbi.h-da.de/danet/gnmi-target/internal/notifications"
    	pbGNMI "github.com/openconfig/gnmi/proto/gnmi"
    	"github.com/openconfig/ygot/ygot"
    	"github.com/openconfig/ygot/ytypes"
    	log "github.com/sirupsen/logrus"
    )
    
    type Logic interface {
    	Init() (ygot.ValidatedGoStruct, error)
    	Callback(newConfig, existingConfig ygot.ValidatedGoStruct) error
    }
    
    // GnmiTarget is a gnmi target that can be run on a operating system.
    type GnmiTarget struct {
    	model                     ygot.ValidatedGoStruct
    	modeldata                 []*pbGNMI.ModelData
    	schema                    *ytypes.Schema
    	unmarshalFn               func(data []byte, destStruct ygot.GoStruct, opts ...ytypes.UnmarshalOpt) error
    	ΛEnum                     map[string]map[int64]ygot.EnumDefinition
    	YangModelChangeDispatcher *not.Dispatcher
    	yangHandlers              []handler.PathHandler
    }
    
    func NewGnmiTarget(
    	schema *ytypes.Schema,
    	model ygot.ValidatedGoStruct,
    	modeldata []*pbGNMI.ModelData,
    	unmarshalFn func(data []byte, destStruct ygot.GoStruct, opts ...ytypes.UnmarshalOpt) error,
    	ΛEnum map[string]map[int64]ygot.EnumDefinition,
    	yangHandlers ...handler.PathHandler,
    ) *GnmiTarget {
    	return &GnmiTarget{
    		schema:                    schema,
    		model:                     model,
    		modeldata:                 modeldata,
    		unmarshalFn:               unmarshalFn,
    		ΛEnum:                     ΛEnum,
    
    		YangModelChangeDispatcher: not.NewDispatcher(),
    
    		yangHandlers:              yangHandlers,
    	}
    }
    
    func (gt *GnmiTarget) Start(bindAddress string, certFile string, keyFile string, caFile string, insecure bool) error {
    
    	//TODO: check if gt has been initialized correctly
    
    	gnmiModel := server.NewModel(gt.modeldata,
    		// NOTE: could be problematic
    		reflect.TypeOf(gt.model),
    		gt.schema.RootSchema(),
    		gt.unmarshalFn,
    		gt.ΛEnum)
    
    	// Check and display supported YANG models, abort if none.
    	log.Info("Supported YANG models:\n")
    	if len(gnmiModel.SupportedModels()) == 0 {
    		log.Fatal("None YANG models supported -- abort")
    	} else {
    		for _, m := range gnmiModel.SupportedModels() {
    			log.Info(m)
    		}
    	}
    
    	for _, handler := range gt.yangHandlers {
    		if err := handler.Init(gt.model); err != nil {
    			log.Fatalf("error in initializing GNMI target through handlers: %v", err)
    		}
    	}
    
    	gnmiServer, err := server.NewServer(gnmiModel, gt.model, gt.YangModelChangeDispatcher, gt.yangHandlers...)
    	if err != nil {
    		log.Fatalf("error in creating GNMI target: %v", err)
    	}
    
    	var grpcServer *grpc.Server
    
    	if insecure == false {
    		cert, err := tls.LoadX509KeyPair(certFile, keyFile)
    		if err != nil {
    			log.Fatalf("error in loading server certificate: %v", err)
    		}
    
    		ca, err := os.ReadFile(caFile)
    
    		pool := x509.NewCertPool()
    		if !pool.AppendCertsFromPEM(ca) {
    			log.Fatalf("error in appending ca certificate: %v", err)
    		}
    
    		tlsConfig := &tls.Config{
    			// activate mTLS
    			ClientAuth:   tls.RequireAndVerifyClientCert,
    			Certificates: []tls.Certificate{cert},
    			ClientCAs:    pool,
    		}
    
    		transportCredentials := credentials.NewTLS(tlsConfig)
    
    		// Create new GRPC Server without service registered
    		grpcServer = grpc.NewServer(grpc.Creds(transportCredentials))
    	} else {
    		log.Infof("\n\n*****WARNING*********WARNING*****\nStarting without secured gnmi server!\nAll gnmi transmissions are unencrypted\n*****WARNING*********WARNING*****\n\n")
    		// Create new GRPC Server without service registered
    		grpcServer = grpc.NewServer()
    	}
    
    	// Register GNMI Server
    	pbGNMI.RegisterGNMIServer(grpcServer, gnmiServer)
    	reflection.Register(grpcServer)
    
    	// Start Server
    	log.Infof("Starting gnmi-target server to listen on %s", bindAddress)
    	listener, err := net.Listen("tcp", bindAddress)
    	if err != nil {
    		log.Fatalf("Failed to list due to: %v", err)
    	}
    
    	log.Info("gnmi-target is ready to serve requests.")
    	err = grpcServer.Serve(listener)
    	if err != nil {
    		log.Fatalf("Failed to serve requests due to: %v", err)
    	}
    
    	return nil
    }