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

using reflection to identify top-level device field

parent 133467fa
No related branches found
No related tags found
2 merge requests!106Resolve "Job Failed #240443",!90Develop
Pipeline #66482 passed with warnings
...@@ -16,7 +16,7 @@ import ( ...@@ -16,7 +16,7 @@ import (
func main() { func main() {
log.SetLevel(log.DebugLevel) log.SetLevel(log.DebugLevel)
sbi := &nucleus.AristaOC{} sbi := &nucleus.Arista{}
device := nucleus.Device{ device := nucleus.Device{
GoStruct: sbi.Schema().Root, GoStruct: sbi.Schema().Root,
......
...@@ -2,6 +2,7 @@ package nucleus ...@@ -2,6 +2,7 @@ package nucleus
import ( import (
"code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi" "code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi"
"code.fbi.h-da.de/cocsn/gosdn/nucleus/util"
"context" "context"
gpb "github.com/openconfig/gnmi/proto/gnmi" gpb "github.com/openconfig/gnmi/proto/gnmi"
"testing" "testing"
...@@ -106,25 +107,34 @@ func TestGnmi_CapabilitiesIntegration(t *testing.T) { ...@@ -106,25 +107,34 @@ func TestGnmi_CapabilitiesIntegration(t *testing.T) {
if testing.Short() { if testing.Short() {
t.Skip("skipping integration test") t.Skip("skipping integration test")
} }
t.Run("Test GNMI Capabilities", func(t *testing.T){ respones := map[string]*gpb.CapabilityResponse{
cfg := &gnmi.Config{ "../test/cap-resp-arista-ceos": {},
Addr: address,
Username: "admin",
Password: "arista",
Encoding: gpb.Encoding_JSON_IETF,
} }
transport,err := NewGnmiTransport(cfg) for k,v := range respones {
if err != nil { if err := util.Read(k, v); err != nil {
t.Error(err) t.Errorf("error parsing %v: %v", k, err)
} }
resp, err := transport.Capabilities(context.Background())
if err != nil { t.Run("Test GNMI Capabilities", func(t *testing.T) {
t.Error(err) cfg := &gnmi.Config{
} Addr: address,
if resp == nil { Username: "admin",
t.Error("resp is nil") Password: "arista",
Encoding: gpb.Encoding_JSON_IETF,
}
transport, err := NewGnmiTransport(cfg)
if err != nil {
t.Error(err)
}
resp, err := transport.Capabilities(context.Background())
if err != nil {
t.Error(err)
}
if resp != v {
t.Error("resp is nil")
}
})
} }
})
} }
func TestPndImplementation_RequestAllIntegration(t *testing.T) { func TestPndImplementation_RequestAllIntegration(t *testing.T) {
......
...@@ -3,11 +3,13 @@ package nucleus ...@@ -3,11 +3,13 @@ package nucleus
import ( import (
"code.fbi.h-da.de/cocsn/yang-models/generated/arista" "code.fbi.h-da.de/cocsn/yang-models/generated/arista"
"code.fbi.h-da.de/cocsn/yang-models/generated/openconfig" "code.fbi.h-da.de/cocsn/yang-models/generated/openconfig"
log "github.com/golang/glog"
"github.com/google/uuid" "github.com/google/uuid"
gpb "github.com/openconfig/gnmi/proto/gnmi" gpb "github.com/openconfig/gnmi/proto/gnmi"
"github.com/openconfig/goyang/pkg/yang" "github.com/openconfig/goyang/pkg/yang"
"github.com/openconfig/ygot/ygot"
"github.com/openconfig/ygot/ytypes" "github.com/openconfig/ygot/ytypes"
log "github.com/sirupsen/logrus"
"reflect"
) )
// SouthboundInterface provides an // SouthboundInterface provides an
...@@ -47,6 +49,7 @@ func (oc *OpenConfig) SbiIdentifier() string { ...@@ -47,6 +49,7 @@ func (oc *OpenConfig) SbiIdentifier() string {
func (oc *OpenConfig) Schema() *ytypes.Schema { func (oc *OpenConfig) Schema() *ytypes.Schema {
schema, err := openconfig.Schema() schema, err := openconfig.Schema()
oc.schema = schema
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
...@@ -65,6 +68,34 @@ func (oc *OpenConfig) SetNode() func(schema *yang.Entry, root interface{}, path ...@@ -65,6 +68,34 @@ 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 {
// 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
}
reflect.ValueOf(goStruct.(*openconfig.Device)).Elem().FieldByName("Interfaces").Set(reflect.ValueOf(c))
return nil
}
}
func (oc *OpenConfig) Id() uuid.UUID { func (oc *OpenConfig) Id() uuid.UUID {
return oc.id return oc.id
} }
...@@ -72,7 +103,7 @@ func (oc *OpenConfig) Id() uuid.UUID { ...@@ -72,7 +103,7 @@ func (oc *OpenConfig) Id() uuid.UUID {
// deprecated // deprecated
// Use for prototyping only. // Use for prototyping only.
// Use OpenConfig instead // Use OpenConfig instead
type AristaOC struct { type Arista struct {
// deprecated // deprecated
transport Transport transport Transport
...@@ -80,26 +111,27 @@ type AristaOC struct { ...@@ -80,26 +111,27 @@ type AristaOC struct {
id uuid.UUID id uuid.UUID
} }
func (oc *AristaOC) Id() uuid.UUID { func (oc *Arista) Id() uuid.UUID {
return oc.id return oc.id
} }
func (oc *AristaOC) SbiIdentifier() string { func (oc *Arista) SbiIdentifier() string {
return "arista" return "arista"
} }
func (oc *AristaOC) Schema() *ytypes.Schema { func (oc *Arista) Schema() *ytypes.Schema {
schema, err := arista.Schema() schema, err := arista.Schema()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }
oc.schema = schema
return schema return schema
} }
// SetNode injects AristaOC specific model // SetNode injects Arista specific model
// representation to the transport. // representation to the transport.
// Needed for type assertion. // Needed for type assertion.
func (oc *AristaOC) SetNode() func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error { func (oc *Arista) SetNode() func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error {
return func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error { return func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error {
if err := ytypes.SetNode(schema, root.(*arista.Device), path, val, opts...); err != nil { if err := ytypes.SetNode(schema, root.(*arista.Device), path, val, opts...); err != nil {
return err return err
...@@ -107,3 +139,17 @@ func (oc *AristaOC) SetNode() func(schema *yang.Entry, root interface{}, path *g ...@@ -107,3 +139,17 @@ func (oc *AristaOC) SetNode() func(schema *yang.Entry, root interface{}, path *g
return nil return nil
} }
} }
// Unmarshal injects Arista specific model
// representation to the transport.
// Needed for type assertion.
func (oc *Arista) Unmarshal() func([]byte, interface{}, ...ytypes.UnmarshalOpt) error {
return func(bytes []byte, goStruct interface{}, opt ...ytypes.UnmarshalOpt) error {
ifaces := &arista.OpenconfigInterfaces_Interfaces{}
if err := oc.schema.Unmarshal(bytes, ifaces, opt...); err != nil {
return err
}
goStruct.(*arista.Device).Interfaces = ifaces
return nil
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment