Skip to content

Commit 18c2288

Browse files
authored
Merge pull request #91 from iptecharch/nc-commit-datastore-knob
add the possibility to commit directly to running for netconf targets
2 parents e0c6037 + a0f584f commit 18c2288

File tree

6 files changed

+166
-84
lines changed

6 files changed

+166
-84
lines changed

collocated.yaml

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,15 +109,23 @@ schema-store:
109109
- ./lab/common/yang/sros_23.3/YANG/nokia-combined
110110
directories:
111111
- ./lab/common/yang/sros_23.3/YANG/ietf
112-
- ./lab/common/yang/sros_23.3/YANG/nokia-sros-yang-extensions.yang
112+
- ./lab/common/yang/sros_23.3/YANG
113113
- name: sros
114114
vendor: Nokia
115115
version: 23.7
116116
files:
117117
- ./lab/common/yang/sros_23.7/YANG/nokia-combined
118118
directories:
119119
- ./lab/common/yang/sros_23.7/YANG/ietf
120-
- ./lab/common/yang/sros_23.7/YANG/nokia-sros-yang-extensions.yang
120+
- ./lab/common/yang/sros_23.7/YANG
121+
- name: sros
122+
vendor: Nokia
123+
version: 23.10
124+
files:
125+
- ./lab/common/yang/sros_23.10/YANG/nokia-combined
126+
directories:
127+
- ./lab/common/yang/sros_23.10/YANG/ietf
128+
- ./lab/common/yang/sros_23.10/YANG
121129
- name: srl
122130
vendor: Nokia
123131
version: 22.11.2
@@ -135,7 +143,7 @@ schema-store:
135143
directories:
136144
- ./lab/common/yang/srl-23.10.1/ietf
137145
- ./lab/common/yang/srl-23.10.1/openconfig/extensions
138-
- ./lab/common/yang/srl-23.10.1/openconfig/openconfig-extensions.yang
146+
- ./lab/common/yang/srl-23.10.1/openconfig
139147
excludes:
140148
- .*tools.*
141149
- name: srl

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ require (
1111
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
1212
github.com/iptecharch/cache v0.0.30
1313
github.com/iptecharch/schema-server v0.0.14
14-
github.com/iptecharch/sdc-protos v0.0.20
14+
github.com/iptecharch/sdc-protos v0.0.21
1515
github.com/iptecharch/yang-parser v0.0.3
1616
github.com/jellydator/ttlcache/v3 v3.1.1
1717
github.com/kylelemons/godebug v1.1.0

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,8 @@ github.com/iptecharch/cache v0.0.30 h1:/W1DsYWvtIbgmF8T180QUXR7LF6cbt1dnpZfvmYbK
137137
github.com/iptecharch/cache v0.0.30/go.mod h1:ofOIjTApxhy15tKgjzOedhrKQnF0dsAO48gkE/jyYXQ=
138138
github.com/iptecharch/schema-server v0.0.14 h1:kZQvP/A3YsJTv5YhQCmKgcb1/iZu57q+tuF4CaT3scc=
139139
github.com/iptecharch/schema-server v0.0.14/go.mod h1:RmCUIZQCCE+x53YR4hP3wIajWCQ0IG3TIvxrrNSIq4w=
140-
github.com/iptecharch/sdc-protos v0.0.20 h1:vy6kXpRuZoaN2mGKR2nB8IXNeL5C0fd8ecVYwSf+KC4=
141-
github.com/iptecharch/sdc-protos v0.0.20/go.mod h1:l1i2wnD7455b1zRQjcJGEOC+Q0H7RMu2UViIowBCPyM=
140+
github.com/iptecharch/sdc-protos v0.0.21 h1:wmQk3J3SoO6qIbpaMYQi8Y2XfWp+tUabyGPf7E0bzv8=
141+
github.com/iptecharch/sdc-protos v0.0.21/go.mod h1:l1i2wnD7455b1zRQjcJGEOC+Q0H7RMu2UViIowBCPyM=
142142
github.com/iptecharch/yang-parser v0.0.3 h1:sfmGIWdhEeql8RXUF/nD0/Z4Td9Pbhk76jVC/VXSSNI=
143143
github.com/iptecharch/yang-parser v0.0.3/go.mod h1:mOB/+f1fOgqD00+RoxHgOxl+Cnq0kEd0tZwBrcrMaUI=
144144
github.com/jellydator/ttlcache/v3 v3.1.1 h1:RCgYJqo3jgvhl+fEWvjNW8thxGWsgxi+TPhRir1Y9y8=

pkg/config/datastore.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ const (
1111
sbiNOOP = "noop"
1212
sbiNETCONF = "netconf"
1313
sbiGNMI = "gnmi"
14+
15+
ncCommitDatastoreRunning = "running"
16+
ncCommitDatastoreCandidate = "candidate"
1417
)
1518

1619
type DatastoreConfig struct {
@@ -37,6 +40,8 @@ type SBI struct {
3740
OperationWithNamespace bool `yaml:"operation-with-namespace,omitempty" json:"operation-with-namespace,omitempty"`
3841
// use 'remove' operation instead of 'delete'
3942
UseOperationRemove bool `yaml:"use-operation-remove,omitempty" json:"use-operation-remove,omitempty"`
43+
// for netconf targets: defines whether to commit to running or use a candidate.
44+
CommitDatastore string `yaml:"commit-datastore,omitempty" json:"commit-datastore,omitempty"`
4045
// ConnectRetry
4146
ConnectRetry time.Duration `yaml:"connect-retry,omitempty" json:"connect-retry,omitempty"`
4247
// Timeout
@@ -107,6 +112,17 @@ func (s *SBI) validateSetDefaults() error {
107112
return err
108113
}
109114

115+
if s.Type == sbiNETCONF {
116+
switch s.CommitDatastore {
117+
case "":
118+
s.CommitDatastore = ncCommitDatastoreCandidate
119+
case ncCommitDatastoreRunning:
120+
case ncCommitDatastoreCandidate:
121+
default:
122+
return fmt.Errorf("unknown commit-datastore: %s. Must be one of %s, %s",
123+
s.CommitDatastore, ncCommitDatastoreCandidate, ncCommitDatastoreRunning)
124+
}
125+
}
110126
if s.ConnectRetry < time.Second {
111127
s.ConnectRetry = time.Second
112128
}

pkg/datastore/target/nc.go

Lines changed: 126 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -121,85 +121,14 @@ func (t *ncTarget) Set(ctx context.Context, req *sdcpb.SetDataRequest) (*sdcpb.S
121121
if !t.connected {
122122
return nil, fmt.Errorf("not connected")
123123
}
124-
xcbCfg := &netconf.XMLConfigBuilderOpts{
125-
HonorNamespace: t.sbiConfig.IncludeNS,
126-
OperationWithNamespace: t.sbiConfig.OperationWithNamespace,
127-
UseOperationRemove: t.sbiConfig.UseOperationRemove,
128-
}
129-
xmlCBDelete := netconf.NewXMLConfigBuilder(t.schemaClient, t.schema, xcbCfg)
130-
131-
// iterate over the delete array
132-
for _, p := range req.GetDelete() {
133-
xmlCBDelete.Delete(ctx, p)
134-
}
135-
136-
// iterate over the replace array
137-
// ATTENTION: This is not implemented intentionally, since it is expected,
138-
// that the datastore will only come up with deletes and updates.
139-
// actual replaces will be resolved to deletes and updates by the datastore
140-
// also replaces would only really make sense with jsonIETF encoding, where
141-
// an entire branch is replaces, on single values this is covered via an
142-
// update.
143-
//
144-
// for _, r := range req.Replace {
145-
// }
146-
//
147-
148-
xmlCBAdd := netconf.NewXMLConfigBuilder(t.schemaClient, t.schema, xcbCfg)
149-
150-
// iterate over the update array
151-
for _, u := range req.Update {
152-
xmlCBAdd.AddValue(ctx, u.Path, u.Value)
124+
switch t.sbiConfig.CommitDatastore {
125+
case "running":
126+
return t.setRunning(ctx, req)
127+
case "candidate":
128+
return t.setCandidate(ctx, req)
153129
}
154-
155-
// first apply the deletes before the adds
156-
for _, xml := range []*netconf.XMLConfigBuilder{xmlCBDelete, xmlCBAdd} {
157-
// finally retrieve the xml config as string
158-
xdoc, err := xml.GetDoc()
159-
if err != nil {
160-
return nil, err
161-
}
162-
163-
// if there was no data in the xml document, continue
164-
if len(xdoc) == 0 {
165-
continue
166-
}
167-
168-
log.Debugf("datastore %s XML:\n%s\n", t.name, xdoc)
169-
170-
// edit the config
171-
_, err = t.driver.EditConfig("candidate", xdoc)
172-
if err != nil {
173-
log.Errorf("datastore %s failed edit-config: %v", t.name, err)
174-
if strings.Contains(err.Error(), "EOF") {
175-
t.Close()
176-
t.connected = false
177-
go t.reconnect()
178-
return nil, err
179-
}
180-
err2 := t.driver.Discard()
181-
if err != nil {
182-
// log failed discard
183-
log.Errorf("failed with %v while discarding pending changes after error %v", err2, err)
184-
}
185-
return nil, err
186-
}
187-
188-
}
189-
log.Infof("datastore %s: committing changes on target", t.name)
190-
// commit the config
191-
err := t.driver.Commit()
192-
if err != nil {
193-
if strings.Contains(err.Error(), "EOF") {
194-
t.Close()
195-
t.connected = false
196-
go t.reconnect()
197-
}
198-
return nil, err
199-
}
200-
return &sdcpb.SetDataResponse{
201-
Timestamp: time.Now().UnixNano(),
202-
}, nil
130+
// should not get here if the config validation happened.
131+
return nil, fmt.Errorf("unknown commit-datastore: %s", t.sbiConfig.CommitDatastore)
203132
}
204133

205134
func (t *ncTarget) Status() string {
@@ -326,3 +255,122 @@ func (t *ncTarget) reconnect() {
326255
return
327256
}
328257
}
258+
259+
func (t *ncTarget) setRunning(ctx context.Context, req *sdcpb.SetDataRequest) (*sdcpb.SetDataResponse, error) {
260+
xcbCfg := &netconf.XMLConfigBuilderOpts{
261+
HonorNamespace: t.sbiConfig.IncludeNS,
262+
OperationWithNamespace: t.sbiConfig.OperationWithNamespace,
263+
UseOperationRemove: t.sbiConfig.UseOperationRemove,
264+
}
265+
266+
xmlBuilder := netconf.NewXMLConfigBuilder(t.schemaClient, t.schema, xcbCfg)
267+
268+
// iterate over the update array
269+
for _, u := range req.GetUpdate() {
270+
xmlBuilder.AddValue(ctx, u.Path, u.Value)
271+
}
272+
// iterate over the delete array
273+
for _, p := range req.GetDelete() {
274+
xmlBuilder.Delete(ctx, p)
275+
}
276+
277+
xdoc, err := xmlBuilder.GetDoc()
278+
if err != nil {
279+
return nil, err
280+
}
281+
282+
// if there was no data in the xml document, return
283+
if len(xdoc) == 0 {
284+
return &sdcpb.SetDataResponse{
285+
Timestamp: time.Now().UnixNano(),
286+
}, nil
287+
}
288+
289+
log.Debugf("datastore %s XML:\n%s\n", t.name, xdoc)
290+
291+
// edit the config
292+
_, err = t.driver.EditConfig("running", xdoc)
293+
if err != nil {
294+
log.Errorf("datastore %s failed edit-config: %v", t.name, err)
295+
if strings.Contains(err.Error(), "EOF") {
296+
t.Close()
297+
t.connected = false
298+
go t.reconnect()
299+
return nil, err
300+
}
301+
return nil, err
302+
}
303+
return &sdcpb.SetDataResponse{
304+
Timestamp: time.Now().UnixNano(),
305+
}, nil
306+
}
307+
308+
func (t *ncTarget) setCandidate(ctx context.Context, req *sdcpb.SetDataRequest) (*sdcpb.SetDataResponse, error) {
309+
xcbCfg := &netconf.XMLConfigBuilderOpts{
310+
HonorNamespace: t.sbiConfig.IncludeNS,
311+
OperationWithNamespace: t.sbiConfig.OperationWithNamespace,
312+
UseOperationRemove: t.sbiConfig.UseOperationRemove,
313+
}
314+
xmlCBDelete := netconf.NewXMLConfigBuilder(t.schemaClient, t.schema, xcbCfg)
315+
316+
// iterate over the delete array
317+
for _, p := range req.GetDelete() {
318+
xmlCBDelete.Delete(ctx, p)
319+
}
320+
321+
xmlCBAdd := netconf.NewXMLConfigBuilder(t.schemaClient, t.schema, xcbCfg)
322+
323+
// iterate over the update array
324+
for _, u := range req.Update {
325+
xmlCBAdd.AddValue(ctx, u.Path, u.Value)
326+
}
327+
328+
// first apply the deletes before the adds
329+
for _, xml := range []*netconf.XMLConfigBuilder{xmlCBDelete, xmlCBAdd} {
330+
// finally retrieve the xml config as string
331+
xdoc, err := xml.GetDoc()
332+
if err != nil {
333+
return nil, err
334+
}
335+
336+
// if there was no data in the xml document, continue
337+
if len(xdoc) == 0 {
338+
continue
339+
}
340+
341+
log.Debugf("datastore %s XML:\n%s\n", t.name, xdoc)
342+
343+
// edit the config
344+
_, err = t.driver.EditConfig("candidate", xdoc)
345+
if err != nil {
346+
log.Errorf("datastore %s failed edit-config: %v", t.name, err)
347+
if strings.Contains(err.Error(), "EOF") {
348+
t.Close()
349+
t.connected = false
350+
go t.reconnect()
351+
return nil, err
352+
}
353+
err2 := t.driver.Discard()
354+
if err != nil {
355+
// log failed discard
356+
log.Errorf("failed with %v while discarding pending changes after error %v", err2, err)
357+
}
358+
return nil, err
359+
}
360+
361+
}
362+
log.Infof("datastore %s: committing changes on target", t.name)
363+
// commit the config
364+
err := t.driver.Commit()
365+
if err != nil {
366+
if strings.Contains(err.Error(), "EOF") {
367+
t.Close()
368+
t.connected = false
369+
go t.reconnect()
370+
}
371+
return nil, err
372+
}
373+
return &sdcpb.SetDataResponse{
374+
Timestamp: time.Now().UnixNano(),
375+
}, nil
376+
}

pkg/server/datastore.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package server
22

33
import (
44
"context"
5+
"fmt"
56
"time"
67

78
sdcpb "github.com/iptecharch/sdc-protos/sdcpb"
@@ -80,12 +81,21 @@ func (s *Server) CreateDataStore(ctx context.Context, req *sdcpb.CreateDataStore
8081
if _, ok := s.datastores[name]; ok {
8182
return nil, status.Errorf(codes.InvalidArgument, "datastore %s already exists", name)
8283
}
84+
commitDatastore := "candidate"
85+
switch req.GetTarget().GetCommitCandidate() {
86+
case sdcpb.CommitCandidate_COMMIT_CANDIDATE:
87+
case sdcpb.CommitCandidate_COMMIT_RUNNING:
88+
commitDatastore = "running"
89+
default:
90+
return nil, fmt.Errorf("unknown commitDatastore: %v", req.GetTarget().GetCommitCandidate())
91+
}
8392
sbi := &config.SBI{
8493
Type: req.GetTarget().GetType(),
8594
Address: req.GetTarget().GetAddress(),
8695
IncludeNS: req.GetTarget().GetIncludeNs(),
8796
OperationWithNamespace: req.GetTarget().GetOperationWithNs(),
8897
UseOperationRemove: req.GetTarget().GetUseOperationRemove(),
98+
CommitDatastore: commitDatastore,
8999
}
90100
if req.GetTarget().GetTls() != nil {
91101
sbi.TLS = &config.TLS{

0 commit comments

Comments
 (0)