Skip to content
Snippets Groups Projects
Commit c53b5391 authored by Manuel Kieweg's avatar Manuel Kieweg
Browse files

process response can process partial paths now

parent 6577c6f6
Branches
Tags
1 merge request!173Process response overhaul
This commit is part of merge request !173. Comments created here will be created in the context of that merge request.
......@@ -4,8 +4,8 @@ go 1.16
require (
code.fbi.h-da.de/cocsn/api v0.2.2
code.fbi.h-da.de/cocsn/gosdn v0.0.3-0.20210622103523-1af2dd83f700
code.fbi.h-da.de/cocsn/gosdn/interfaces v0.0.0-20210622103523-1af2dd83f700
code.fbi.h-da.de/cocsn/gosdn v0.0.3-0.20210622104649-6577c6f645b1
code.fbi.h-da.de/cocsn/gosdn/interfaces v0.0.0-20210622104649-6577c6f645b1
code.fbi.h-da.de/cocsn/yang-models v0.0.7
github.com/google/uuid v1.2.0
github.com/openconfig/gnmi v0.0.0-20210527163611-d3a3e30199da
......
This diff is collapsed.
......@@ -4,7 +4,7 @@ go 1.16
require (
code.fbi.h-da.de/cocsn/api v0.2.2
code.fbi.h-da.de/cocsn/gosdn/interfaces v0.0.0-20210621161319-e9316e4c2a92
code.fbi.h-da.de/cocsn/gosdn/interfaces v0.0.0-20210622104649-6577c6f645b1
code.fbi.h-da.de/cocsn/yang-models v0.0.7
github.com/aristanetworks/goarista v0.0.0-20201120222254-94a892eb0c6a
github.com/docker/docker v20.10.6+incompatible
......
This diff is collapsed.
......@@ -22,11 +22,15 @@ func NewDevice(name string, opt *tpb.TransportOption, sbi southbound.SouthboundI
name = namesgenerator.GetRandomName(0)
}
root, err := ygot.DeepCopy(sbi.Schema().Root)
if err != nil {
return nil, err
}
if opt.Csbi {
return &CsbiDevice{
CommonDevice: CommonDevice{
UUID: uuid.New(),
GoStruct: sbi.Schema().Root,
GoStruct: root,
sbi: sbi,
transport: t,
name: name,
......@@ -36,7 +40,7 @@ func NewDevice(name string, opt *tpb.TransportOption, sbi southbound.SouthboundI
return &CommonDevice{
UUID: uuid.New(),
GoStruct: sbi.Schema().Root,
GoStruct: root,
sbi: sbi,
transport: t,
name: name,
......
......@@ -3,6 +3,7 @@ package nucleus
import (
"context"
"reflect"
"strings"
"code.fbi.h-da.de/cocsn/gosdn/interfaces/southbound"
......@@ -35,7 +36,7 @@ var opmap = map[ppb.ApiOperation]string{
type Gnmi struct {
SetNode func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
RespChan chan *gpb.SubscribeResponse
Unmarshal func([]byte, []string, interface{}, ...ytypes.UnmarshalOpt) error
Unmarshal func([]byte, []string, ygot.ValidatedGoStruct, ...ytypes.UnmarshalOpt) error
Options *tpb.TransportOption
client gpb.GNMIClient
config *gnmi.Config
......@@ -227,15 +228,37 @@ func (g *Gnmi) Type() string {
// ProcessResponse takes a gNMI response and serializes the contents to the root struct.
func (g *Gnmi) ProcessResponse(resp interface{}, root interface{}, s *ytypes.Schema) error {
models := s.SchemaTree
r := resp.(*gpb.GetResponse)
d, ok := root.(ygot.ValidatedGoStruct)
if !ok {
return &errors.ErrInvalidTypeAssertion{}
}
r, ok := resp.(*gpb.GetResponse)
if !ok {
return &errors.ErrInvalidTypeAssertion{}
}
rn := r.Notification
for _, msg := range rn {
for _, update := range msg.Update {
path := update.Path
val, ok := update.Val.Value.(*gpb.TypedValue_JsonVal)
if ok {
buf := strings.Builder{}
for _,e := range path.Elem {
key := strings.Title(e.Name)
buf.WriteString(key)
buf.WriteString("_")
}
filter := buf.String()
filter = strings.TrimSuffix(filter,"_")
keys := make([]string, 0)
for k := range models {
if strings.Contains(k, filter) {
keys = append(keys, k)
}
}
//TODO: Fetch field by name
opts := []ytypes.UnmarshalOpt{&ytypes.IgnoreExtraFields{}}
return g.Unmarshal(val.JsonVal, pathutils.ToStrings(path), root, opts...)
return g.Unmarshal(val.JsonVal, pathutils.ToStrings(path), d, opts...)
}
// TODO(mk): Evaluate hardcoded model key
schema := models["Device"]
......
......@@ -10,7 +10,6 @@ import (
"github.com/google/uuid"
gpb "github.com/openconfig/gnmi/proto/gnmi"
"github.com/openconfig/goyang/pkg/yang"
"github.com/openconfig/ygot/util"
"github.com/openconfig/ygot/ygot"
"github.com/openconfig/ygot/ytypes"
log "github.com/sirupsen/logrus"
......@@ -67,57 +66,57 @@ func (oc *OpenConfig) SetNode() func(schema *yang.Entry, root interface{}, path
// Unmarshal injects OpenConfig specific model representation to the transport.
// Needed for type assertion.
func (oc *OpenConfig) Unmarshal() func([]byte, []string, ygot.GoStruct, ...ytypes.UnmarshalOpt) error {
func (oc *OpenConfig) Unmarshal() func([]byte, []string, ygot.ValidatedGoStruct, ...ytypes.UnmarshalOpt) error {
return unmarshal
}
// unmarshal parses a root or 1st level gNMI response to a go struct
// Named return to return appropriate recover error
func unmarshal(bytes []byte, fields []string, goStruct ygot.GoStruct, opt ...ytypes.UnmarshalOpt) (err error) {
ygot.BuildEmptyTree(goStruct)
return openconfig.Unmarshal(bytes, goStruct.(*openconfig.Device), opt...)
func unmarshal(bytes []byte, fields []string, goStruct ygot.ValidatedGoStruct, opt ...ytypes.UnmarshalOpt) error {
defer func() {
if r := recover(); r != nil {
log.Error(r.(error))
}
}()
switch l := len(fields); l {
case 0:
return openconfig.Unmarshal(bytes, goStruct.(*openconfig.Device), opt...)
default:
}
var c ygot.ValidatedGoStruct
// Load SBI definition
d := openconfig.Device{}
ygot.BuildEmptyTree(&d)
c = getField(&d, fields)
if err := openconfig.Unmarshal(bytes, c, opt...); err != nil {
return err
}
if err := ygot.MergeStructInto(goStruct, &d); err != nil {
return err
}
return nil
}
// iter walks down the provided paths and initializes the ygot.GoStruct. It only works for
// the root level. Named returns to return appropriate recover error
// the root level.
// TODO(mk): Fix deeper layers
func iter(a ygot.GoStruct, fields []string) (b ygot.GoStruct, f string, err error) {
func getField(inStruct ygot.ValidatedGoStruct, fields []string) ygot.ValidatedGoStruct {
defer func() {
if r := recover(); r != nil {
err = r.(error)
log.Error(r.(error))
}
}()
var c ygot.GoStruct
var configStruct reflect.Value
f = fields[0]
s := reflect.ValueOf(a).Elem()
h := s.FieldByName(f)
configStruct = reflect.New(h.Type())
// Pointer of field needs to be initialized.
// Very convoluted russian doll trick
// https://stackoverflow.com/a/57469950/4378176
// https://golang.org/src/encoding/json/decode.go?s#L474
// TODO(mk): Prettify
p2 := configStruct.Elem()
// If we have KeyHelperGoStruct we need make and modify map instead of plain struct
if p2.Kind() == reflect.Map {
p2.Set(reflect.MakeMap(p2.Type()))
configStruct.Elem().Set(p2)
if err := util.InsertIntoMapStructField(a, f, "", p2); err != nil {
panic(err)
}
} else {
configStruct.Elem().Set(reflect.New(p2.Type().Elem()))
b = configStruct.Elem().Interface().(ygot.GoStruct)
}
f := fields[0]
s := reflect.ValueOf(inStruct)
h := reflect.Indirect(s).FieldByName(f).Interface()
outStruct := h.(ygot.ValidatedGoStruct)
if len(fields) > 1 {
c, _, _ = iter(b, fields[1:])
outStruct = getField(outStruct, fields[1:])
} else {
return
return outStruct
}
reflect.ValueOf(b).Elem().FieldByName(f).Set(reflect.ValueOf(c))
return
return outStruct
}
// ID returns the ID of the OpenConfig SBI
......@@ -145,7 +144,7 @@ func (csbi *Csbi) SetNode() func(schema *yang.Entry, root interface{}, path *gpb
// Unmarshal injects OpenConfig specific model representation to the transport.
// Needed for type assertion.
func (csbi *Csbi) Unmarshal() func([]byte, []string, ygot.GoStruct, ...ytypes.UnmarshalOpt) error {
func (csbi *Csbi) Unmarshal() func([]byte, []string, ygot.ValidatedGoStruct, ...ytypes.UnmarshalOpt) error {
return unmarshal
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment