Skip to content

Commit

Permalink
- Add types as a seperate module
Browse files Browse the repository at this point in the history
- Working set and delete in xmlstore
  • Loading branch information
Jon Nightingale committed Oct 26, 2024
1 parent eedb79d commit 7d7a7ef
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 66 deletions.
40 changes: 29 additions & 11 deletions internal/xmlstore/xmlstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package xmlstore

import (
"encoding/xml"
"netconf-go/internal/types"
"strings"

"github.com/openconfig/goyang/pkg/yang"
Expand All @@ -12,7 +13,7 @@ type XMLStore struct {
}

type xmlElementInterface interface {
insert(yangMod *yang.Entry, path []string)
insert(yangMod *yang.Entry, path []string, requestType types.RequestType, delete bool)
}

type idRefElement struct {
Expand Down Expand Up @@ -42,11 +43,15 @@ type xmlElement struct {
XMLName xml.Name
Value string `xml:",chardata"`
Children []xmlElementInterface
delete bool
}

func (el xmlElement) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
start.Name.Local = el.XMLName.Local
start.Name.Space = el.XMLName.Space
if el.delete {
start.Attr = append(start.Attr, xml.Attr{Name: xml.Name{Local: "operation", Space: "urn:ietf:params:xml:ns:netconf:base:1.0"}, Value: "remove"})
}
if err := e.EncodeToken(start); err != nil {
return err
}
Expand All @@ -58,14 +63,14 @@ func (el xmlElement) MarshalXML(e *xml.Encoder, start xml.StartElement) error {

return e.EncodeToken(start.End())
}
func (el *xmlElement) insert(yangMod *yang.Entry, path []string) {
func (el *xmlElement) insert(yangMod *yang.Entry, path []string, requestType types.RequestType, delete bool) {
// ss := strings.Split(path, " ")
ss := path
if ss[0] == el.XMLName.Local {
// Found element, recurse
// println("Found ", ss[0])
for i := range el.Children {
el.Children[i].insert(nil, ss[1:])
el.Children[i].insert(nil, ss[1:], requestType, delete)
}
} else {
// Add new element, then insert into that
Expand All @@ -77,40 +82,53 @@ func (el *xmlElement) insert(yangMod *yang.Entry, path []string) {
el.Value = nv[1]
}
el.XMLName.Space = yangMod.Namespace().Name
el.Children = append(el.Children, &xmlElement{xml.Name{Space: "", Local: ss[1]}, "", []xmlElementInterface{}})
el.Children = append(el.Children, &xmlElement{xml.Name{Space: "", Local: ss[1]}, "", []xmlElementInterface{}, false})
if len(ss) == 2 {
return
}
el.Children[len(el.Children)-1].insert(nil, ss[2:])
el.Children[len(el.Children)-1].insert(nil, ss[2:], requestType, delete)
} else {
child := xmlElement{xml.Name{
Local: nv[0],
// Space: el.XMLName.Space
}, "", []xmlElementInterface{}}
}, "", []xmlElementInterface{}, false}
if len(nv) > 1 {
child.Value = nv[1]
}

el.Children = append(el.Children, &child)
if len(path) == 1 && requestType == types.EditConf && delete {
child.delete = true
}
// If its a set, the last path element is the value.
if len(path) == 1 && requestType == types.EditConf && !delete {
el.Value = path[0]
} else {
el.Children = append(el.Children, &child)
}
if len(ss) == 1 {
return
}
el.Children[len(el.Children)-1].insert(nil, ss[1:])
if len(nv) > 1 {
el.insert(nil, ss[1:], requestType, delete)
} else {
el.Children[len(el.Children)-1].insert(nil, ss[1:], requestType, delete)

}
}
}
}

func (store *XMLStore) Insert(yangMod *yang.Entry, line string) {
func (store *XMLStore) Insert(yangMod *yang.Entry, line string, requestType types.RequestType) {
// fmt.Printf("Inserting %v\n", line)
// Split on space
ss := strings.Split(line, " ")
isDelete := ss[0] == "delete"
// Drop first element from slice
ss = ss[1:]
// Insert into store
store.Root.XMLName.Local = ss[1]
store.Root.XMLName.Space = yangMod.Namespace().Name
if len(ss) > 2 {
store.Root.insert(yangMod, ss[2:])
store.Root.insert(yangMod, ss[2:], requestType, isDelete)
}
// fmt.Printf("%v\n", store)
// myxml, err := xml.MarshalIndent(store.Root, "", " ")
Expand Down
17 changes: 9 additions & 8 deletions netconf-cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"context"
"fmt"
"io"
"netconf-go/internal/types"
"os"
"path/filepath"
"sort"
Expand Down Expand Up @@ -279,7 +280,7 @@ func main() {
if mods[slice[1]] == nil {
mods[slice[1]] = getYangModule(s, slice[1])
}
netconfData, _ := sendNetconfRequest(s, requestLine, editConf)
netconfData, _ := sendNetconfRequest(s, requestLine, types.EditConf)
fmt.Printf("Request data: %v\n", netconfData)
case strings.HasPrefix(line, "get-conf"):
// TODO make common with get-oper/rpc below using fallthrough
Expand All @@ -296,7 +297,7 @@ func main() {
continue
}
}
netconfData, _ := sendNetconfRequest(s, requestLine, getConf)
netconfData, _ := sendNetconfRequest(s, requestLine, types.GetConf)
fmt.Printf("Request data: %v\n", netconfData)
case strings.HasPrefix(line, "get-oper"), strings.HasPrefix(line, "rpc"):
// TODO make common with set
Expand All @@ -320,23 +321,23 @@ func main() {
continue
}
}
var op requestType
var op types.RequestType
switch slice[0] {
case "get-oper":
op = getOper
op = types.GetOper
case "rpc":
op = rpcOp
op = types.RpcOp
case "get-conf":
op = getConf
op = types.GetConf
}
netconfData, _ := sendNetconfRequest(s, requestLine, op)
fmt.Printf("Request data: %v\n", netconfData)
case strings.HasPrefix(line, "validate"):
requestLine = line
sendNetconfRequest(s, requestLine, validate)
sendNetconfRequest(s, requestLine, types.Validate)
case strings.HasPrefix(line, "commit"):
requestLine = line
sendNetconfRequest(s, requestLine, commit)
sendNetconfRequest(s, requestLine, types.Commit)
default:
}
log.Debug("you said:", strconv.Quote(line))
Expand Down
72 changes: 31 additions & 41 deletions netconf_lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"fmt"

// "netconf-go/internal/completions"
"netconf-go/internal/types"
"netconf-go/internal/xmlstore"
"os"
"sort"
Expand All @@ -20,17 +21,6 @@ import (
log "github.com/sirupsen/logrus"
)

type requestType int

const (
validate requestType = iota
commit = 1
getConf = 2
getOper = 3
rpcOp = 5
editConf = 6
)

type cfgDatastore int

const (
Expand Down Expand Up @@ -59,7 +49,7 @@ type netconfRequest struct {
ncEntry *yang.Entry
NetConfPath []netconfPathElement
Value string
reqType requestType
reqType types.RequestType
store *xmlstore.XMLStore
}

Expand Down Expand Up @@ -331,7 +321,7 @@ func listYang(path string) ([]string, int) {
return names, returnType
}

func newNetconfRequest(netconfEntry *yang.Entry, Path []string, value string, requestType requestType, delete bool) *netconfRequest {
func newNetconfRequest(netconfEntry *yang.Entry, Path []string, value string, requestType types.RequestType, delete bool) *netconfRequest {
ncArray := make([]netconfPathElement, len(Path))
for i, p := range Path {
if strings.Contains(p, "=") {
Expand All @@ -355,7 +345,7 @@ func newNetconfRequest(netconfEntry *yang.Entry, Path []string, value string, re
}
}

func emitNestedXML(enc *xml.Encoder, paths []netconfPathElement, value string, reqType requestType) {
func emitNestedXML(enc *xml.Encoder, paths []netconfPathElement, value string, reqType types.RequestType) {
var start3 xml.StartElement
if paths[0].delete {
start3 = xml.StartElement{
Expand Down Expand Up @@ -396,13 +386,13 @@ func emitNestedXML(enc *xml.Encoder, paths []netconfPathElement, value string, r
func (nc *netconfRequest) MarshalXML(enc *xml.Encoder, start xml.StartElement) error {

switch nc.reqType {
case commit:
case types.Commit:
enc.EncodeToken(xml.StartElement{Name: xml.Name{Local: "commit"}})
case validate:
case types.Validate:
enc.EncodeToken(xml.StartElement{Name: xml.Name{Local: "validate"}})
enc.EncodeToken(xml.StartElement{Name: xml.Name{Local: "source"}})
enc.EncodeToken(xml.StartElement{Name: xml.Name{Local: "candidate"}})
case editConf:
case types.EditConf:
enc.EncodeToken(xml.StartElement{Name: xml.Name{Local: "edit-config"}})
emitNestedXML(enc, []netconfPathElement{
{name: "target", value: nil},
Expand All @@ -411,7 +401,7 @@ func (nc *netconfRequest) MarshalXML(enc *xml.Encoder, start xml.StartElement) e
nc.reqType)
enc.EncodeToken(xml.StartElement{Name: xml.Name{Local: "config", Space: "urn:ietf:params:xml:ns:netconf:base:1.0"}})

case getConf:
case types.GetConf:
enc.EncodeToken(xml.StartElement{Name: xml.Name{Local: "get-config"}})
emitNestedXML(enc, []netconfPathElement{
{name: "source", value: nil},
Expand All @@ -422,39 +412,39 @@ func (nc *netconfRequest) MarshalXML(enc *xml.Encoder, start xml.StartElement) e
if nc.ncEntry != nil {
enc.EncodeToken(xml.StartElement{Name: xml.Name{Local: "filter"}})
}
case getOper:
case types.GetOper:
enc.EncodeToken(xml.StartElement{Name: xml.Name{Local: "get"}})
enc.EncodeToken(xml.StartElement{Name: xml.Name{Local: "filter"}, Attr: []xml.Attr{{Name: xml.Name{Local: "type"}, Value: "subtree"}}})
case rpcOp:
case types.RpcOp:
// enc.EncodeToken(xml.StartElement{Name: xml.Name{Local: "rpc"}})
}

var err error
if nc.ncEntry != nil {
start2 := xml.StartElement{Name: xml.Name{Local: nc.NetConfPath[0].name, Space: nc.ncEntry.Namespace().Name}}
// start2 := xml.StartElement{Name: xml.Name{Local: nc.NetConfPath[0].name, Space: nc.ncEntry.Namespace().Name}}
//fmt.Println(start2)
err = enc.EncodeToken(start2)
// err = enc.EncodeToken(start2)
if err != nil {
fmt.Println(err)
}

if len(nc.NetConfPath) > 1 {
emitNestedXML(enc, nc.NetConfPath[1:], nc.Value, nc.reqType)
}
// @@@ To reinstate old, also uncomment 'start2 above and below
// emitNestedXML(enc, nc.NetConfPath[1:], nc.Value, nc.reqType)
enc.Encode(nc.store.Root)

err = enc.EncodeToken(start2.End())
// err = enc.EncodeToken(start2.End())
if err != nil {
fmt.Println(err)
}
}
switch nc.reqType {
case commit:
case types.Commit:
enc.EncodeToken(xml.EndElement{Name: xml.Name{Local: "commit"}})
case validate:
case types.Validate:
enc.EncodeToken(xml.EndElement{Name: xml.Name{Local: "validate"}})
enc.EncodeToken(xml.EndElement{Name: xml.Name{Local: "source"}})
enc.EncodeToken(xml.EndElement{Name: xml.Name{Local: "candidate"}})
case editConf:
case types.EditConf:
err = enc.EncodeToken(xml.EndElement{Name: xml.Name{Local: "config", Space: "urn:ietf:params:xml:ns:netconf:base:1.0"}})
if err != nil {
fmt.Println(err)
Expand All @@ -463,15 +453,15 @@ func (nc *netconfRequest) MarshalXML(enc *xml.Encoder, start xml.StartElement) e
if err != nil {
fmt.Println(err)
}
case getConf:
case types.GetConf:
if nc.ncEntry != nil {
enc.EncodeToken(xml.EndElement{Name: xml.Name{Local: "filter"}})
}
enc.EncodeToken(xml.EndElement{Name: xml.Name{Local: "get-config"}})
case getOper:
case types.GetOper:
enc.EncodeToken(xml.EndElement{Name: xml.Name{Local: "filter"}})
enc.EncodeToken(xml.EndElement{Name: xml.Name{Local: "get"}})
case rpcOp:
case types.RpcOp:
// enc.EncodeToken(xml.EndElement{Name: xml.Name{Local: "rpc"}})
}

Expand Down Expand Up @@ -581,7 +571,7 @@ func getYangModule(s *netconf.Session, yangMod string) *yang.Module {

return mod
}
func sendNetconfRequest(s *netconf.Session, requestLine string, requestType requestType) (string, string) {
func sendNetconfRequest(s *netconf.Session, requestLine string, requestType types.RequestType) (string, string) {
var store xmlstore.XMLStore

defer timeTrack(time.Now(), "Request")
Expand All @@ -595,20 +585,20 @@ func sendNetconfRequest(s *netconf.Session, requestLine string, requestType requ
// Create a request structure with module, path array, and string value.
var ncRequest *netconfRequest
switch requestType {
case commit:
case types.Commit:
fallthrough
case validate:
case types.Validate:
ncRequest = newNetconfRequest(nil, nil, "", requestType, false)
case editConf:
case types.EditConf:
if slice[0] == "delete" {
ncRequest = newNetconfRequest(yang.ToEntry(mods[slice[1]]), slice[2:], "", requestType, true)
} else {
ncRequest = newNetconfRequest(yang.ToEntry(mods[slice[1]]), slice[2:len(slice)-1], slice[len(slice)-1], requestType, false)
}
case getOper, getConf, rpcOp:
case types.GetOper, types.GetConf, types.RpcOp:
if len(slice) >= 3 {
ncRequest = newNetconfRequest(yang.ToEntry(mods[slice[1]]), slice[2:], "", requestType, false)
} else if requestType == getConf {
} else if requestType == types.GetConf {
// getConf supports getting the whole config.
ncRequest = newNetconfRequest(nil, []string{}, "", requestType, false)
}
Expand All @@ -620,7 +610,7 @@ func sendNetconfRequest(s *netconf.Session, requestLine string, requestType requ

// Add to xmlstore
if len(slice) > 1 {
store.Insert(yang_module, requestLine)
store.Insert(yang_module, requestLine, requestType)
}
ncRequest.store = &store

Expand All @@ -641,10 +631,10 @@ func sendNetconfRequest(s *netconf.Session, requestLine string, requestType requ
var theString string
var reply *netconf.Reply = nil

if requestType == commit {
if requestType == types.Commit {
error = s.Commit(context.Background())
log.Debugf("Request reply: %v, error: %v\n", reply, error)
} else if requestType == validate {
} else if requestType == types.Validate {
error = s.Validate(context.Background(), netconf.Candidate)
log.Debugf("Request reply: %v, error: %v\n", reply, error)
// } else if requestType == getConf || requestType == getOper {
Expand Down
Loading

0 comments on commit 7d7a7ef

Please sign in to comment.