Skip to content
Snippets Groups Projects
Commit c09f02c2 authored by istmxrein's avatar istmxrein
Browse files

refactor repo & add gnxi server

parent 128654e5
Branches
No related tags found
1 merge request!2First working version that retrieves the real state from the device
...@@ -31,7 +31,7 @@ POSSIBILITY OF SUCH DAMAGE. ...@@ -31,7 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
package cmd package cmd
import ( import (
gnmiServer "code.fbi.h-da.de/danet/gnmi-target/gnmi_server" gnmiServer "code.fbi.h-da.de/danet/gnmi-target/gnmi"
"fmt" "fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
......
/* Copyright 2017 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package gnmi
import (
"errors"
"fmt"
"reflect"
"sort"
"github.com/openconfig/goyang/pkg/yang"
"github.com/openconfig/ygot/ygot"
"github.com/openconfig/ygot/ytypes"
pb "github.com/openconfig/gnmi/proto/gnmi"
)
// JSONUnmarshaler is the signature of the Unmarshal() function in the GoStruct code generated by openconfig ygot library.
type JSONUnmarshaler func([]byte, ygot.GoStruct, ...ytypes.UnmarshalOpt) error
// GoStructEnumData is the data type to maintain GoStruct enum type.
type GoStructEnumData map[string]map[int64]ygot.EnumDefinition
// Model contains the model data and GoStruct information for the device to config.
type Model struct {
modelData []*pb.ModelData
structRootType reflect.Type
schemaTreeRoot *yang.Entry
jsonUnmarshaler JSONUnmarshaler
enumData GoStructEnumData
}
// NewModel returns an instance of Model struct.
func NewModel(m []*pb.ModelData, t reflect.Type, r *yang.Entry, f JSONUnmarshaler, e GoStructEnumData) *Model {
return &Model{
modelData: m,
structRootType: t,
schemaTreeRoot: r,
jsonUnmarshaler: f,
enumData: e,
}
}
func (m *Model) newRootValue() interface{} {
return reflect.New(m.structRootType.Elem()).Interface()
}
// NewConfigStruct creates a ValidatedGoStruct of this model from jsonConfig. If jsonConfig is nil, creates an empty GoStruct.
func (m *Model) NewConfigStruct(jsonConfig []byte) (ygot.ValidatedGoStruct, error) {
rootStruct, ok := m.newRootValue().(ygot.ValidatedGoStruct)
if !ok {
return nil, errors.New("root node is not a ygot.ValidatedGoStruct")
}
if jsonConfig != nil {
if err := m.jsonUnmarshaler(jsonConfig, rootStruct); err != nil {
return nil, err
}
if err := rootStruct.Validate(); err != nil {
return nil, err
}
}
return rootStruct, nil
}
// SupportedModels returns a list of supported models.
func (m *Model) SupportedModels() []string {
mDesc := make([]string, len(m.modelData))
for i, m := range m.modelData {
mDesc[i] = fmt.Sprintf("%s %s", m.Name, m.Version)
}
sort.Strings(mDesc)
return mDesc
}
\ No newline at end of file
This diff is collapsed.
package gnmi_server package gnmi
import ( import (
"github.com/openconfig/ygot/ygot"
"google.golang.org/grpc" "google.golang.org/grpc"
"google.golang.org/grpc/reflection" "google.golang.org/grpc/reflection"
"io/ioutil" "io/ioutil"
...@@ -10,57 +9,11 @@ import ( ...@@ -10,57 +9,11 @@ import (
"code.fbi.h-da.de/danet/gnmi-target/modeldata" "code.fbi.h-da.de/danet/gnmi-target/modeldata"
"code.fbi.h-da.de/danet/gnmi-target/modeldata/ygotstructs" "code.fbi.h-da.de/danet/gnmi-target/modeldata/ygotstructs"
"github.com/mlsgit/gnxi/gnmi"
"golang.org/x/net/context"
pbGNMI "github.com/openconfig/gnmi/proto/gnmi" pbGNMI "github.com/openconfig/gnmi/proto/gnmi"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
type gnmiServer struct {
*gnmi.Server
}
// Callback function called for gnmi set calls
func callback(newConfig ygot.ValidatedGoStruct) error {
log.Info("hitting callback.")
return nil
}
func newServer(model *gnmi.Model, config []byte) (*gnmiServer, error) {
srv, err := gnmi.NewServer(model, config, callback)
if err != nil {
return nil, err
}
return &gnmiServer{Server: srv}, nil
}
// TODO Add override to GNMI.Get here and follow suit to Manuel's implementation at
// https://code.fbi.h-da.de/danet/csbi/-/blob/main/resources/csbi.go
// and https://code.fbi.h-da.de/danet/gosdn/-/blob/develop/nucleus/gnmi_transport.go
// Get overrides the Get func of gnmi.Target to implement bridge
func (s *gnmiServer) Get(ctx context.Context, req *pbGNMI.GetRequest) (*pbGNMI.GetResponse, error) {
log.Infof("received a Get request")
// Obtain content of request
paths := req.GetPath()
// first cycle through GNMI paths
for pathComponent := range paths {
log.Infof("got request for path: %d", pathComponent)
currentPathElements := paths[pathComponent].GetElem()
//cycle through GNMI Element of this path and find out what to do!
for i := range currentPathElements {
log.Infof("GNMI Path Element is: %s", currentPathElements[i].GetName())
}
}
return s.Server.Get(ctx, req)
}
func StartGNMITarget(bindAddress string, configFile string) error { func StartGNMITarget(bindAddress string, configFile string) error {
...@@ -72,7 +25,7 @@ func StartGNMITarget(bindAddress string, configFile string) error { ...@@ -72,7 +25,7 @@ func StartGNMITarget(bindAddress string, configFile string) error {
} }
model := gnmi.NewModel(modeldata.ModelData, model := NewModel(modeldata.ModelData,
reflect.TypeOf((*ygotstructs.Device)(nil)), reflect.TypeOf((*ygotstructs.Device)(nil)),
ygotstructs.SchemaTree["Device"], ygotstructs.SchemaTree["Device"],
ygotstructs.Unmarshal, ygotstructs.Unmarshal,
...@@ -88,7 +41,7 @@ func StartGNMITarget(bindAddress string, configFile string) error { ...@@ -88,7 +41,7 @@ func StartGNMITarget(bindAddress string, configFile string) error {
} }
} }
gnmiServer, err := newServer(model, configData) gnmiServer, err := NewServer(model, configData, nil)
if err != nil { if err != nil {
log.Fatalf("error in creating GNMI target: %v", err) log.Fatalf("error in creating GNMI target: %v", err)
} }
......
package gnmi
import (
"fmt"
"strconv"
log "github.com/golang/glog"
"github.com/openconfig/goyang/pkg/yang"
pb "github.com/openconfig/gnmi/proto/gnmi"
)
// getChildNode gets a node's child with corresponding schema specified by path
// element. If not found and createIfNotExist is set as true, an empty node is
// created and returned.
func getChildNode(node map[string]interface{}, schema *yang.Entry, elem *pb.PathElem, createIfNotExist bool) (interface{}, *yang.Entry) {
var nextSchema *yang.Entry
var ok bool
if nextSchema, ok = schema.Dir[elem.Name]; !ok {
return nil, nil
}
var nextNode interface{}
if elem.GetKey() == nil {
if nextNode, ok = node[elem.Name]; !ok {
if createIfNotExist {
node[elem.Name] = make(map[string]interface{})
nextNode = node[elem.Name]
}
}
return nextNode, nextSchema
}
nextNode = getKeyedListEntry(node, elem, createIfNotExist)
return nextNode, nextSchema
}
// getKeyedListEntry finds the keyed list entry in node by the name and key of
// path elem. If entry is not found and createIfNotExist is true, an empty entry
// will be created (the list will be created if necessary).
func getKeyedListEntry(node map[string]interface{}, elem *pb.PathElem, createIfNotExist bool) map[string]interface{} {
curNode, ok := node[elem.Name]
if !ok {
if !createIfNotExist {
return nil
}
// Create a keyed list as node child and initialize an entry.
m := make(map[string]interface{})
for k, v := range elem.Key {
m[k] = v
if vAsNum, err := strconv.ParseFloat(v, 64); err == nil {
m[k] = vAsNum
}
}
node[elem.Name] = []interface{}{m}
return m
}
// Search entry in keyed list.
keyedList, ok := curNode.([]interface{})
if !ok {
return nil
}
for _, n := range keyedList {
m, ok := n.(map[string]interface{})
if !ok {
log.Errorf("wrong keyed list entry type: %T", n)
return nil
}
keyMatching := true
// must be exactly match
for k, v := range elem.Key {
attrVal, ok := m[k]
if !ok {
return nil
}
if v != fmt.Sprintf("%v", attrVal) {
keyMatching = false
break
}
}
if keyMatching {
return m
}
}
if !createIfNotExist {
return nil
}
// Create an entry in keyed list.
m := make(map[string]interface{})
for k, v := range elem.Key {
m[k] = v
if vAsNum, err := strconv.ParseFloat(v, 64); err == nil {
m[k] = vAsNum
}
}
node[elem.Name] = append(keyedList, m)
return m
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment