Skip to content
Snippets Groups Projects
Commit e22181ad authored by Malte Bauch's avatar Malte Bauch
Browse files

Merge branch '67-overhaul-architecture' of ssh://code.fbi.h-da.de/cocsn/gosdn...

Merge branch '67-overhaul-architecture' of ssh://code.fbi.h-da.de/cocsn/gosdn into 67-overhaul-architecture
parents bbd295f7 2692f73d
No related branches found
No related tags found
3 merge requests!97Resolve "PND handling via CLI and database",!91"Overhaul Architecture",!90Develop
This commit is part of merge request !91. Comments created here will be created in the context of that merge request.
package main
import (
"code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi"
"code.fbi.h-da.de/cocsn/gosdn/nucleus"
schema "code.fbi.h-da.de/cocsn/yang-models/generated/arista"
"context"
"fmt"
"github.com/google/uuid"
gpb "github.com/openconfig/gnmi/proto/gnmi"
log "github.com/sirupsen/logrus"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
log.SetLevel(log.DebugLevel)
sbi := &nucleus.AristaOC{}
transport := &nucleus.Gnmi{
SetNode: sbi.SetNode(),
RespChan: make(chan *gpb.SubscribeResponse),
}
device := nucleus.Device{
Device: &schema.Device{},
SBI: sbi,
Config: nucleus.DeviceConfig{
Uuid: uuid.New(),
Address: "[fdfd::ce05]:6030",
Username: "admin",
Password: "arista",
},
Transport: transport,
}
pnd := nucleus.NewPND("openconfig", sbi)
if err := pnd.AddDevice(device); err != nil {
log.Fatal(err)
}
cfg := &gnmi.Config{
Addr: device.Config.Address,
Password: device.Config.Password,
Username: device.Config.Username,
}
ctx := gnmi.NewContext(context.Background(), cfg)
ctx = context.WithValue(ctx, "config", cfg)
paths := []string{"/interfaces/interface/name"}
opts := &gnmi.SubscribeOptions{
UpdatesOnly: false,
Prefix: "",
Mode: "stream",
StreamMode: "sample",
SampleInterval: uint64(10 * time.Second.Nanoseconds()),
SuppressRedundant: false,
HeartbeatInterval: uint64(time.Second.Nanoseconds()),
Paths: gnmi.SplitPaths(paths),
Origin: "",
Target: device.Config.Address,
}
done := make(chan os.Signal, 1)
signal.Notify(done, syscall.SIGILL, syscall.SIGTERM)
ctx = context.WithValue(ctx, "opts", opts)
go func() {
if err := transport.Subscribe(ctx); err != nil {
log.Fatal(err)
}
}()
fmt.Println("awaiting signal")
<-done
fmt.Println("exiting")
}
\ No newline at end of file
...@@ -3,25 +3,27 @@ package main ...@@ -3,25 +3,27 @@ package main
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" "code.fbi.h-da.de/cocsn/gosdn/nucleus"
"code.fbi.h-da.de/cocsn/yang-models/generated/openconfig" "code.fbi.h-da.de/cocsn/gosdn/nucleus/util"
schema "code.fbi.h-da.de/cocsn/yang-models/generated/arista"
"context" "context"
"fmt"
"github.com/google/uuid" "github.com/google/uuid"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
func main() { func main() {
log.SetLevel(log.DebugLevel) log.SetLevel(log.DebugLevel)
sbi := &nucleus.OpenConfig{} sbi := &nucleus.AristaOC{}
transport := &nucleus.Gnmi{SetNode: sbi.SetNode()}
device := nucleus.Device{ device := nucleus.Device{
Uuid: uuid.New(), Uuid: uuid.New(),
Device: &openconfig.Device{}, Device: &schema.Device{},
SBI: sbi, SBI: sbi,
Config: nucleus.DeviceConfig{ Config: nucleus.DeviceConfig{
Address: "[fdfd::ce05]:6030", Address: "[fdfd::ce05]:6030",
Username: "admin", Username: "admin",
Password: "arista", Password: "arista",
}, },
Transport: transport,
} }
pnd := nucleus.NewPND("openconfig", "test description", sbi) pnd := nucleus.NewPND("openconfig", "test description", sbi)
if err := pnd.AddDevice(device); err != nil { if err := pnd.AddDevice(device); err != nil {
...@@ -36,14 +38,25 @@ func main() { ...@@ -36,14 +38,25 @@ func main() {
ctx := gnmi.NewContext(context.Background(), cfg) ctx := gnmi.NewContext(context.Background(), cfg)
ctx = context.WithValue(ctx, "config", cfg) ctx = context.WithValue(ctx, "config", cfg)
paths := []string{"/interfaces/interface[name=*]/name"} paths := util.NewPaths()
req, err := gnmi.NewGetRequest(gnmi.SplitPaths(paths), "") paths.ParseSchema(sbi.Schema(), "device")
resp, err := nucleus.GetWithRequest(ctx, req) p := paths.StringBuilder()
if err != nil { errors := 0
log.Fatal(err) for _, path := range p {
} req, err := gnmi.NewGetRequest(gnmi.SplitPaths([]string{path}), "")
if err := device.Add(resp); err != nil { resp, err := nucleus.GetWithRequest(ctx, req)
panic(err) if err != nil {
log.Debug(err)
errors++
break
}
if err := device.Add(resp); err != nil {
log.Debug(err)
errors++
}
} }
fmt.Println(device.Config)
percentage := float64(errors) / float64(len(p)) * 100.0
log.Debugf("%v errors", errors)
log.Debugf("%v percent failed", percentage)
} }
package nucleus package nucleus
import ( import (
"code.fbi.h-da.de/cocsn/yang-models/generated/openconfig"
"github.com/google/uuid" "github.com/google/uuid"
pb "github.com/openconfig/gnmi/proto/gnmi"
"github.com/openconfig/ygot/ygot" "github.com/openconfig/ygot/ygot"
"github.com/openconfig/ygot/ytypes"
) )
type Device struct { type Device struct {
...@@ -20,23 +17,7 @@ type Device struct { ...@@ -20,23 +17,7 @@ type Device struct {
// use better naming in further develop // use better naming in further develop
// Also all that Interface Call specific logic belongs to SBI! // Also all that Interface Call specific logic belongs to SBI!
func (d Device) Add(resp interface{}) error { func (d Device) Add(resp interface{}) error {
s, err := d.SBI.Schema() return d.Transport.ProcessResponse(resp, d.Device, d.SBI.Schema())
if err != nil {
return err
}
models := s.SchemaTree
opts := []ytypes.SetNodeOpt{&ytypes.InitMissingElements{}, &ytypes.TolerateJSONInconsistencies{}}
r := resp.(*pb.GetResponse)
rn := r.Notification
for _, msg := range rn {
for _, val := range msg.Update {
schema := models["Device"]
if err := ytypes.SetNode(schema, d.Device.(*openconfig.Device), val.Path, val.Val, opts...); err != nil {
return err
}
}
}
return nil
} }
type DeviceConfig struct { type DeviceConfig struct {
......
...@@ -3,13 +3,17 @@ package nucleus ...@@ -3,13 +3,17 @@ package nucleus
import ( import (
"code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi" "code.fbi.h-da.de/cocsn/gosdn/forks/goarista/gnmi"
"context" "context"
"github.com/google/uuid"
"github.com/openconfig/gnmi/proto/gnmi_ext"
gpb "github.com/openconfig/gnmi/proto/gnmi" gpb "github.com/openconfig/gnmi/proto/gnmi"
"github.com/openconfig/gnmi/proto/gnmi_ext"
"github.com/openconfig/goyang/pkg/yang"
"github.com/openconfig/ygot/ytypes"
log "github.com/sirupsen/logrus"
) )
type Gnmi uuid.UUID type Gnmi struct {
SetNode func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
RespChan chan *gpb.SubscribeResponse
}
func (g *Gnmi) SetConfig(interface{}) error { func (g *Gnmi) SetConfig(interface{}) error {
return nil return nil
...@@ -19,6 +23,34 @@ func (g *Gnmi) GetConfig() interface{} { ...@@ -19,6 +23,34 @@ func (g *Gnmi) GetConfig() interface{} {
return nil return nil
} }
// interface satisfaction for now
// TODO: Convert to meaningfiul calls
func (g *Gnmi)Get(ctx context.Context, params ...string) (interface{}, error){return nil, nil}
func (g *Gnmi)Set(ctx context.Context, params ...string) (interface{}, error){return nil, nil}
func (g *Gnmi)Subscribe(ctx context.Context, params ...string) error{
return g.subscribe(ctx)
}
func (g *Gnmi)Type() string {
return "gnmi"
}
func (g *Gnmi)ProcessResponse(resp interface{},root interface{}, s *ytypes.Schema) error {
models := s.SchemaTree
opts := []ytypes.SetNodeOpt{&ytypes.InitMissingElements{}, &ytypes.TolerateJSONInconsistencies{}}
r := resp.(*gpb.GetResponse)
rn := r.Notification
for _, msg := range rn {
for _, val := range msg.Update {
schema := models["Device"]
if err := g.SetNode(schema, root, val.Path, val.Val, opts...); err != nil {
return err
}
}
}
return nil
}
// Capabilities calls GNMI capabilities // Capabilities calls GNMI capabilities
func (g *Gnmi) Capabilities(ctx context.Context) (interface{}, error) { func (g *Gnmi) Capabilities(ctx context.Context) (interface{}, error) {
client, err := gnmi.Dial(ctx.Value("config").(*gnmi.Config)) client, err := gnmi.Dial(ctx.Value("config").(*gnmi.Config))
...@@ -33,7 +65,7 @@ func (g *Gnmi) Capabilities(ctx context.Context) (interface{}, error) { ...@@ -33,7 +65,7 @@ func (g *Gnmi) Capabilities(ctx context.Context) (interface{}, error) {
} }
// Get calls GNMI get // Get calls GNMI get
func (g *Gnmi) Get(ctx context.Context, paths [][]string, origin string) (interface{}, error) { func (g *Gnmi) get(ctx context.Context, paths [][]string, origin string) (interface{}, error) {
req, err := gnmi.NewGetRequest(paths, origin) req, err := gnmi.NewGetRequest(paths, origin)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -56,7 +88,7 @@ func GetWithRequest(ctx context.Context, req *gpb.GetRequest) (interface{}, erro ...@@ -56,7 +88,7 @@ func GetWithRequest(ctx context.Context, req *gpb.GetRequest) (interface{}, erro
} }
// Set calls GNMI set // Set calls GNMI set
func (g *Gnmi) Set(ctx context.Context, setOps []*gnmi.Operation, func (g *Gnmi) set(ctx context.Context, setOps []*gnmi.Operation,
exts ...*gnmi_ext.Extension) error { exts ...*gnmi_ext.Extension) error {
client, err := gnmi.Dial(ctx.Value("config").(*gnmi.Config)) client, err := gnmi.Dial(ctx.Value("config").(*gnmi.Config))
if err != nil { if err != nil {
...@@ -66,13 +98,21 @@ func (g *Gnmi) Set(ctx context.Context, setOps []*gnmi.Operation, ...@@ -66,13 +98,21 @@ func (g *Gnmi) Set(ctx context.Context, setOps []*gnmi.Operation,
} }
// Subscribe calls GNMI subscribe // Subscribe calls GNMI subscribe
func (g *Gnmi) Subscribe(ctx context.Context, subscribeOptions *gnmi.SubscribeOptions, func (g *Gnmi) subscribe(ctx context.Context) error {
respChan chan<- *gpb.SubscribeResponse) error {
client, err := gnmi.Dial(ctx.Value("config").(*gnmi.Config)) client, err := gnmi.Dial(ctx.Value("config").(*gnmi.Config))
if err != nil { if err != nil {
return err return err
} }
return gnmi.SubscribeErr(ctx, client, subscribeOptions, respChan) opts := ctx.Value("opts").(*gnmi.SubscribeOptions)
go func() {
for {
resp := <- g.RespChan
if err := gnmi.LogSubscribeResponse(resp); err != nil {
log.Fatal(err)
}
}
}()
return gnmi.SubscribeErr(ctx, client, opts, g.RespChan)
} }
// Close calls GNMI close // Close calls GNMI close
......
package nucleus package nucleus
import ( import (
"code.fbi.h-da.de/cocsn/gosdn/nucleus/util" "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"
gpb "github.com/openconfig/gnmi/proto/gnmi"
"github.com/openconfig/goyang/pkg/yang"
"github.com/openconfig/ygot/ytypes" "github.com/openconfig/ygot/ytypes"
) )
...@@ -12,7 +15,8 @@ type SouthboundInterface interface { ...@@ -12,7 +15,8 @@ type SouthboundInterface interface {
// Deprecated // Deprecated
SbiIdentifier() string SbiIdentifier() string
Schema() (*ytypes.Schema, error) SetNode() func(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error
Schema() *ytypes.Schema
} }
type Tapi struct { type Tapi struct {
...@@ -27,21 +31,45 @@ func (oc *OpenConfig) SbiIdentifier() string { ...@@ -27,21 +31,45 @@ func (oc *OpenConfig) SbiIdentifier() string {
return "openconfig" return "openconfig"
} }
func (oc *OpenConfig) Schema() (*ytypes.Schema, error) { func (oc *OpenConfig) Schema() *ytypes.Schema {
return openconfig.Schema() schema, err := openconfig.Schema()
}
func (oc *OpenConfig) OpenconfigInterfaces(device Device) {
resp, err := oc.Transport.Get(nil, nil...)
if err != nil { if err != nil {
log.Fatal(err)
}
return schema
}
func (oc *OpenConfig) 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 {
if err := ytypes.SetNode(schema, root.(*openconfig.Device), path, val, opts...); err != nil {
return err
}
return nil
} }
device.Add(resp)
} }
func (oc *OpenConfig) GetFullDeviceInfo(device Device) error { type AristaOC struct {
paths := util.NewPaths() transport Transport
paths.ParseSchema(oc.schema, "device") schema *ytypes.Schema
}
return nil func (oc *AristaOC) SbiIdentifier() string {
return "arista"
}
func (oc *AristaOC) Schema() *ytypes.Schema {
schema, err := arista.Schema()
if err != nil {
log.Fatal(err)
}
return schema
}
func (oc *AristaOC) 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 {
if err := ytypes.SetNode(schema, root.(*arista.Device), path, val, opts...); err != nil {
return err
}
return nil
}
} }
...@@ -3,6 +3,7 @@ package nucleus ...@@ -3,6 +3,7 @@ package nucleus
import ( import (
"bytes" "bytes"
"context" "context"
"github.com/openconfig/ygot/ytypes"
"io" "io"
) )
...@@ -13,6 +14,8 @@ type Transport interface { ...@@ -13,6 +14,8 @@ type Transport interface {
Get(ctx context.Context, params ...string) (interface{}, error) Get(ctx context.Context, params ...string) (interface{}, error)
Set(ctx context.Context, params ...string) (interface{}, error) Set(ctx context.Context, params ...string) (interface{}, error)
Subscribe(ctx context.Context, params ...string) error Subscribe(ctx context.Context, params ...string) error
Type() string
ProcessResponse(resp interface{},root interface{}, models *ytypes.Schema) error
} }
// YANGConsumer is a auxillary type to redirect the response // YANGConsumer is a auxillary type to redirect the response
......
...@@ -93,7 +93,7 @@ func appendix(c chan string, stop chan bool,p chan []string) { ...@@ -93,7 +93,7 @@ func appendix(c chan string, stop chan bool,p chan []string) {
paths = append(paths, path) paths = append(paths, path)
log.Debug(path) log.Debug(path)
case sig = <-stop: case sig = <-stop:
log.Debug("Signal received: %v", sig) log.Debugf("Signal received: %v", sig)
} }
if sig {break} if sig {break}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment