From 1cdaef7c36f7ed6e03d5a4754c560d1432b3585e Mon Sep 17 00:00:00 2001 From: Malte Bauch <malte.bauch@stud.h-da.de> Date: Mon, 17 Jan 2022 18:11:33 +0100 Subject: [PATCH] first steps moving towards plugin creation within the gosdn controller first basic steps towards a plugin implementation which is handled by the gosdn itself. the csbi orchestrator still generates code and launches cSBIs but the plugin itself is build within the goSDN controller. simplifies the headache of plugin generation for multiple platforms. --- grpc.go | 6 +- templates.go | 161 +++++++++++++++------------------------------------ write.go | 34 +---------- 3 files changed, 50 insertions(+), 151 deletions(-) diff --git a/grpc.go b/grpc.go index d914cfde..13021616 100644 --- a/grpc.go +++ b/grpc.go @@ -104,11 +104,7 @@ func (s server) CreatePlugin(req *pb.CreateRequest, stream pb.Csbi_CreatePluginS if err != nil { return handleRPCError(labels, err) } - err = buildPlugin(d.ID.String()) - if err != nil { - return handleRPCError(labels, err) - } - file, err := os.Open(filepath.Join(d.ID.String(), "plugin.so")) + file, err := os.Open(filepath.Join(d.ID.String(), "gostructs.go")) if err != nil { return handleRPCError(labels, err) } diff --git a/templates.go b/templates.go index ad71ef19..ec0811d3 100644 --- a/templates.go +++ b/templates.go @@ -1,10 +1,6 @@ package csbi -import ( - "html/template" - - "github.com/openconfig/ygot/ygen" -) +import "github.com/openconfig/ygot/ygen" var pluginStruct = ygen.GoStructCodeSnippet{ StructName: "Csbi", @@ -13,55 +9,30 @@ var pluginStruct = ygen.GoStructCodeSnippet{ id uuid.UUID }`, Methods: ` -func (sbi *Csbi) SbiIdentifier() string { - return "plugin sbi" +// SbiIdentifier returns the identifier as a +func (csbi *Csbi) SbiIdentifier() string { + return "csbi" } -func (sbi *Csbi) SetNode(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error { - log.WithFields(log.Fields{ - "schema": schema.Name, - "path": path, - "val": val, - "opts": opts, - }).Trace("entering SetNode()") +// SetNode injects schema specific model representation to the transport. +// Needed for type assertion. +func (csbi *Csbi) SetNode(schema *yang.Entry, root interface{}, path *gpb.Path, val interface{}, opts ...ytypes.SetNodeOpt) error { return ytypes.SetNode(schema, root.(*Device), path, val, opts...) } -func (sbi *Csbi) Schema() *ytypes.Schema { - schema, err := Schema() - sbi.schema = schema - if err != nil { - log.Fatal(err) - } - return schema -} - -func (sbi *Csbi) ID() uuid.UUID { - return sbi.id -} - -func (sbi *Csbi) Type() spb.Type { - return spb.Type_CONTAINERISED -} - -func (sbi *Csbi) Unmarshal(bytes []byte, fields []string, goStruct ygot.ValidatedGoStruct, opt ...ytypes.UnmarshalOpt) error { - log.WithFields(log.Fields{}).Trace("entering Unmarshal()") - return unmarshal(sbi.Schema(), bytes, fields, goStruct, opt...) +// Unmarshal injects schema specific model representation to the transport. +// Needed for type assertion. +func (csbi *Csbi) Unmarshal(bytes []byte, path *gpb.Path, goStruct ygot.ValidatedGoStruct, opt ...ytypes.UnmarshalOpt) error { + return unmarshal(csbi.Schema(), bytes, path, goStruct, opt...) } -// unmarshal parses gNMI response to a go struct. -func unmarshal(schema *ytypes.Schema, bytes []byte, fields []string, goStruct ygot.ValidatedGoStruct, opt ...ytypes.UnmarshalOpt) error { +//unmarshal parses a gNMI response to a go struct. +func unmarshal(schema *ytypes.Schema, bytes []byte, path *gpb.Path, goStruct ygot.ValidatedGoStruct, opt ...ytypes.UnmarshalOpt) error { defer func() { if r := recover(); r != nil { log.Error(r.(error)) } }() - log.WithFields(log.Fields{ - "schema": schema.RootSchema().Name, - "fields": fields, - "bytes": len(bytes), - "opts": opt, - }).Trace("entering unmarshal()") // Load SBI definition root, err := ygot.DeepCopy(schema.Root) @@ -70,94 +41,58 @@ func unmarshal(schema *ytypes.Schema, bytes []byte, fields []string, goStruct yg } validatedDeepCopy, ok := root.(ygot.ValidatedGoStruct) if !ok { - return fmt.Errorf("no validated go struct") + return &errors.ErrInvalidTypeAssertion{} } - ygot.BuildEmptyTree(validatedDeepCopy) - log.Trace("built empty tree") - - var fieldStruct ygot.ValidatedGoStruct - if len(fields) != 0 { - log.Trace("fetching fields") - fieldStruct, err = getField(validatedDeepCopy, fields) - if err != nil { - return err - } - } else { - log.Trace("using root struct") - fieldStruct = validatedDeepCopy + + // returns the node we want to fill with the data contained in 'bytes', + // using the specified 'path'. + createdNode, _, err := ytypes.GetOrCreateNode(schema.RootSchema(), validatedDeepCopy, path) + if err != nil { + return err + } + validatedCreatedNode, ok := createdNode.(ygot.ValidatedGoStruct) + if !ok { + return &errors.ErrInvalidTypeAssertion{} } - if err := Unmarshal(bytes, fieldStruct, opt...); err != nil { + if err := Unmarshal(bytes, validatedCreatedNode, opt...); err != nil { return err } - ygot.PruneEmptyBranches(validatedDeepCopy) - log.Trace("pruned empty branches") - log.Trace("merging structs...") - return ygot.MergeStructInto(goStruct, validatedDeepCopy) + + opts := []ygot.MergeOpt{&ygot.MergeOverwriteExistingFields{}} + return ygot.MergeStructInto(goStruct, validatedDeepCopy, opts...) } -// getField traverses the GoStruct and returns the field that represents the -// tail of the path -func getField(inStruct ygot.ValidatedGoStruct, fields []string) (ygot.ValidatedGoStruct, error) { - defer func() { - if r := recover(); r != nil { - log.Error(r.(error)) - } - }() - log.WithFields(log.Fields{ - "fields": fields, - }).Trace("getting field") - f := fields[0] - log.Tracef("field name: %v", f) - s := reflect.ValueOf(inStruct) - h := reflect.Indirect(s).FieldByName(f).Interface() - outStruct, ok := h.(ygot.ValidatedGoStruct) - if !ok { - t := reflect.TypeOf(h) - if !(util.IsTypeStruct(t) || util.IsTypeStructPtr(t)) { - return nil, fmt.Errorf("cannot process entry of type %v, request longer or shorter path", t) - } - return nil, fmt.Errorf("expected ValidatedGoStruct got %v", t) - } - if len(fields) > 1 { - log.Trace("fetching fields") - return getField(outStruct, fields[1:]) +// Schema is holding the default OpenConfig schema for minimal compatibility +// to gosdn interfaces +func (csbi *Csbi) Schema() *ytypes.Schema { + schema, err := Schema() + csbi.schema = schema + if err != nil { + log.Fatal(err) } - return outStruct, nil + return schema +} + +// ID returns the Southbound's UUID +func (csbi *Csbi) ID() uuid.UUID { + return csbi.id +} + +// Type returns the Southbound's type +func (csbi *Csbi) Type() spb.Type { + return spb.Type_CONTAINERISED }`, } const pluginImportAmendmend = ` + "code.fbi.h-da.de/danet/gosdn/nucleus/errors" spb "code.fbi.h-da.de/danet/api/go/gosdn/southbound" "github.com/google/uuid" - "github.com/openconfig/ygot/util" + log "github.com/sirupsen/logrus" ) var PluginSymbol Csbi ` - -var templater *template.Template - -const pluginGoModTemplate = `module << .ModuleName >> - -go << .GoVersion >> - -require (<<range $element := .Dependencies>> - <<$element.Name>> v<<$element.Version>> -<<end>>) -` - -// Module represents a Go module entry in go.mod. Name and version needed. -type Module struct { - Name string `json:"name"` - Version string `json:"version"` -} - -// GoMod represents a go.mod file used for templates. -type GoMod struct { - ModuleName string `json:"name"` - GoVersion string `json:"go_version"` - Dependencies []Module `json:"dependencies"` -} diff --git a/write.go b/write.go index 2b37cfe0..d3233ae7 100644 --- a/write.go +++ b/write.go @@ -3,9 +3,7 @@ package csbi import ( "bytes" "context" - "encoding/json" "fmt" - "html/template" "io/fs" "net" "os" @@ -93,11 +91,7 @@ func writeCsbi(ctx context.Context, code *ygen.GeneratedGoCode, path string) err } func writePlugin(code *ygen.GeneratedGoCode, path string) error { - err := writeCode(path, code) - if err != nil { - return err - } - return writeGoMod(path) + return writeCode(path, code) } func copyFile(path, filename string) error { @@ -153,29 +147,3 @@ func writeCode(path string, code *ygen.GeneratedGoCode) error { } return nil } -func writeGoMod(path string) error { - // Read dependencies from JSON file - deps, err := os.ReadFile(filepath.Join("resources", "plugin_deps.json")) - if err != nil { - return err - } - module := GoMod{} - if err := json.Unmarshal(deps, &module); err != nil { - return err - } - - // Create go.mod in destination directory and write template - file := filepath.Join(path, "go.mod") - goMod, err := os.OpenFile(file, os.O_CREATE|os.O_WRONLY, 0755) - if err != nil { - return err - } - defer goMod.Sync() - - templater := template.New("goMod").Delims("<<", ">>") - _, err = templater.Parse(pluginGoModTemplate) - if err != nil { - return err - } - return templater.Execute(goMod, module) -} -- GitLab