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

root and 1st level responses implemented. arbitrary values tricky

parent c0a422b9
Branches
Tags
2 merge requests!106Resolve "Job Failed #240443",!90Develop
......@@ -46,7 +46,7 @@ func main() {
device.Transport = transport
p := []string{"/interfaces"}
p := []string{"/interfaces/interface"}
errors := 0
for _, path := range p {
err := pnd.RequestAll(path)
......
......@@ -33,3 +33,11 @@ type ErrInvalidTypeAssertion struct {
func (e ErrInvalidTypeAssertion) Error() string {
return fmt.Sprintf("%v does not implement %v", e.v, e.t)
}
type ErrUnsupportedPath struct {
p interface{}
}
func (e ErrUnsupportedPath) Error() string {
return fmt.Sprintf("path %v is not supported", e.p)
}
\ No newline at end of file
......@@ -29,17 +29,17 @@ func NewGnmiTransport(config *gnmi.Config) (*Gnmi, error) {
return nil, err
}
return &Gnmi{
config: config,
client: c,
config: config,
client: c,
}, nil
}
type Gnmi struct {
SetNode func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
Unmarshal func([]byte, string, interface{}, ...ytypes.UnmarshalOpt) error
RespChan chan *gpb.SubscribeResponse
config *gnmi.Config
client gpb.GNMIClient
SetNode func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
Unmarshal func([]byte, []string, interface{}, ...ytypes.UnmarshalOpt) error
RespChan chan *gpb.SubscribeResponse
config *gnmi.Config
client gpb.GNMIClient
}
func (g *Gnmi) SetConfig(config *gnmi.Config) {
......@@ -101,7 +101,7 @@ func (g *Gnmi) ProcessResponse(resp interface{}, root interface{}, s *ytypes.Sch
val,ok := update.Val.Value.(*gpb.TypedValue_JsonIetfVal)
if ok {
opts := []ytypes.UnmarshalOpt{&ytypes.IgnoreExtraFields{}}
if err := g.Unmarshal(val.JsonIetfVal,fullPath.String(), root, opts...); err != nil {
if err := g.Unmarshal(val.JsonIetfVal, extraxtPathElements(fullPath), root, opts...); err != nil {
return err
}
return nil
......@@ -115,6 +115,14 @@ func (g *Gnmi) ProcessResponse(resp interface{}, root interface{}, s *ytypes.Sch
return nil
}
func extraxtPathElements(path *gpb.Path) []string {
elems := make([]string, len(path.Elem))
for i,e := range path.Elem {
elems[i] = strings.Title(e.Name)
}
return elems
}
// extractModelKey extracts the model's key from the full path. Highly model specific for now
// TODO: Remove hard coded model prefix
// TODO: Figure out why path.Elem() is empty but path.Elememt() is deprecated
......
......@@ -563,8 +563,8 @@ func Test_extractModelKey(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := extractModelKey(tt.args.path); got != tt.want {
t.Errorf("extractModelKey() = %v, want %v", got, tt.want)
if got := extraxtPathElements(tt.args.path); got != tt.want {
t.Errorf("extraxtPathElements() = %v, want %v", got, tt.want)
}
})
}
......
......@@ -6,6 +6,7 @@ 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"
......@@ -71,31 +72,64 @@ 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, interface{}, ...ytypes.UnmarshalOpt) error {
return func(bytes []byte, path string, goStruct interface{}, opt ...ytypes.UnmarshalOpt) error {
func (oc *OpenConfig) Unmarshal() func([]byte, []string, interface{}, ...ytypes.UnmarshalOpt) error {
return func(bytes []byte, fields []string, goStruct interface{}, opt ...ytypes.UnmarshalOpt) error {
switch l := len(fields); l {
case 0:
return openconfig.Unmarshal(bytes, goStruct.(*openconfig.Device), opt...)
case 1:
default:
return &ErrUnsupportedPath{fields}
}
var c ygot.GoStruct
var field string
// Load SBI definition
d := openconfig.Device{}
s := reflect.ValueOf(&d).Elem()
h := s.FieldByName("Interfaces")
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: Prettify (mk)
p2 := configStruct.Elem()
configStruct.Elem().Set(reflect.New(p2.Type().Elem()))
c := configStruct.Elem().Interface().(ygot.GoStruct)
if err := oc.schema.Unmarshal(bytes, c, opt...); err != nil {
return err
c, field = iter(&d, fields)
if err := openconfig.Unmarshal(bytes, c, opt...); err != nil {
log.Error(err)
}
reflect.ValueOf(goStruct.(*openconfig.Device)).Elem().FieldByName("Interfaces").Set(reflect.ValueOf(c))
reflect.ValueOf(goStruct.(*openconfig.Device)).Elem().FieldByName(field).Set(reflect.ValueOf(c))
return nil
}
}
func iter(a ygot.GoStruct, fields []string) (ygot.GoStruct, string) {
var b ygot.GoStruct
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)
}
if len(fields) > 1 {
c, _ = iter(b, fields[1:])
} else {
return b, f
}
reflect.ValueOf(b).Elem().FieldByName(f).Set(reflect.ValueOf(c))
return b, f
}
func (oc *OpenConfig) Id() uuid.UUID {
return oc.id
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment