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
No related branches found
No related tags found
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