Skip to content

Commit

Permalink
saveconfig node method
Browse files Browse the repository at this point in the history
  • Loading branch information
hellt committed Jun 27, 2021
1 parent cdcc5d1 commit 106c5bc
Show file tree
Hide file tree
Showing 20 changed files with 132 additions and 106 deletions.
7 changes: 0 additions & 7 deletions clab/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,6 @@ var kinds = []string{
"host",
}

// DefaultCredentials holds default username and password per each kind
var DefaultCredentials = map[string][]string{
"vr-sros": {"admin", "admin"},
"vr-vmx": {"admin", "admin@123"},
"vr-xrv9k": {"clab", "clab@123"},
}

// Config defines lab configuration as it is provided in the YAML file
type Config struct {
Name string `json:"name,omitempty"`
Expand Down
108 changes: 9 additions & 99 deletions cmd/save.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,12 @@ package cmd
import (
"context"
"fmt"
"io/ioutil"
"strings"
"sync"

"github.com/scrapli/scrapligo/driver/base"
"github.com/scrapli/scrapligo/netconf"
"github.com/scrapli/scrapligo/transport"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/srl-labs/containerlab/clab"
"github.com/srl-labs/containerlab/types"
"github.com/srl-labs/containerlab/nodes"
)

var saveCommand = map[string][]string{
Expand Down Expand Up @@ -48,64 +43,21 @@ Refer to the https://containerlab.srlinux.dev/cmd/save/ documentation to see the
ctx, cancel := context.WithCancel(context.Background())
defer cancel()

labels := []*types.GenericFilter{{FilterType: "label", Match: c.Config.Name, Field: "containerlab", Operator: "="}}
containers, err := c.Runtime.ListContainers(ctx, labels)
if err != nil {
return fmt.Errorf("could not list containers: %v", err)
}
if len(containers) == 0 {
return fmt.Errorf("no containers found")
if err := c.ParseTopology(); err != nil {
return err
}

var wg sync.WaitGroup
wg.Add(len(containers))
for _, cont := range containers {
go func(cont types.GenericContainer) {
wg.Add(len(c.Nodes))
for _, node := range c.Nodes {
go func(node nodes.Node) {
defer wg.Done()
kind := cont.Labels["clab-node-kind"]

switch kind {
case "vr-sros",
"vr-vmx":
netconfSave(cont)
return
}

// skip saving if we have no command map
if _, ok := saveCommand[kind]; !ok {
return
}
stdout, stderr, err := c.Runtime.Exec(ctx, cont.ID, saveCommand[kind])
err := node.SaveConfig(ctx, c.Runtime)
if err != nil {
log.Errorf("%s: failed to execute cmd: %v", cont.Names, err)

}
if len(stderr) > 0 {
log.Infof("%s errors: %s", strings.TrimLeft(cont.Names[0], "/"), string(stderr))
}
switch {
// for srl kinds print the full stdout
case kind == "srl":
if len(stdout) > 0 {
confPath := cont.Labels["clab-node-dir"] + "/config/checkpoint/checkpoint-0.json"
log.Infof("saved SR Linux configuration from %s node to %s\noutput:\n%s", strings.TrimLeft(cont.Names[0], "/"), confPath, string(stdout))
}

case kind == "crpd":
// path by which to save a config
confPath := cont.Labels["clab-node-dir"] + "/config/conf-saved.conf"
err := ioutil.WriteFile(confPath, stdout, 0777)
if err != nil {
log.Errorf("failed to write config by %s path from %s container: %v", confPath, strings.TrimLeft(cont.Names[0], "/"), err)
}
log.Infof("saved cRPD configuration from %s node to %s", strings.TrimLeft(cont.Names[0], "/"), confPath)

case kind == "ceos":
// path by which a config was saved
confPath := cont.Labels["clab-node-dir"] + "/flash/conf-saved.conf"
log.Infof("saved cEOS configuration from %s node to %s", strings.TrimLeft(cont.Names[0], "/"), confPath)
log.Errorf("err: %v", err)
}
}(cont)
}(node)
}
wg.Wait()

Expand All @@ -116,45 +68,3 @@ Refer to the https://containerlab.srlinux.dev/cmd/save/ documentation to see the
func init() {
rootCmd.AddCommand(saveCmd)
}

// netconfSave saves the running config to the startup by means
// of invoking a netconf rpc <copy-config>
// this method is used on the network elements that can't perform a save of config via other means
func netconfSave(cont types.GenericContainer) {
kind := cont.Labels["clab-node-kind"]
host := strings.TrimLeft(cont.Names[0], "/")

driverOpts := []base.Option{
base.WithAuthStrictKey(false),
base.WithAuthUsername(clab.DefaultCredentials[kind][0]),
base.WithAuthPassword(clab.DefaultCredentials[kind][1]),
base.WithTransportType(transport.StandardTransportName),
}
if kind == "vr-sros" {
// vr-sros doesn't use echo on ssh channel, so we explicitly set it here
driverOpts = append(driverOpts, base.WithNetconfServerEcho(false))
}

d, err := netconf.NewNetconfDriver(
host,
driverOpts...,
)
if err != nil {
log.Errorf("Could not create netconf driver for %s: %+v\n", host, err)
}

err = d.Open()
if err != nil {
log.Errorf("failed to open netconf driver for %s: %+v\n", host, err)
return
}
defer d.Close()

_, err = d.CopyConfig("running", "startup")
if err != nil {
log.Errorf("%s: Could not send save config via Netconf: %+v", host, err)
return
}

log.Infof("saved configuration from %s node\n", host)
}
3 changes: 3 additions & 0 deletions nodes/bridge/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@ func (s *bridge) PostDeploy(ctx context.Context, r runtime.ContainerRuntime, ns
return nil
}
func (s *bridge) WithMgmtNet(*types.MgmtNet) {}
func (s *bridge) SaveConfig(ctx context.Context, r runtime.ContainerRuntime) error {
return nil
}
4 changes: 4 additions & 0 deletions nodes/ceos/ceos.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ func (s *ceos) PostDeploy(ctx context.Context, r runtime.ContainerRuntime, ns ma

func (s *ceos) WithMgmtNet(*types.MgmtNet) {}

func (s *ceos) SaveConfig(ctx context.Context, r runtime.ContainerRuntime) error {
return nil
}

//

func createCEOSFiles(node *types.NodeConfig) error {
Expand Down
4 changes: 4 additions & 0 deletions nodes/crpd/crpd.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ func (s *crpd) PostDeploy(ctx context.Context, r runtime.ContainerRuntime, ns ma

func (s *crpd) WithMgmtNet(*types.MgmtNet) {}

func (s *crpd) SaveConfig(ctx context.Context, r runtime.ContainerRuntime) error {
return nil
}

///

func createCRPDFiles(nodeCfg *types.NodeConfig) error {
Expand Down
3 changes: 3 additions & 0 deletions nodes/host/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,6 @@ func (s *host) PostDeploy(ctx context.Context, r runtime.ContainerRuntime, ns ma
}

func (s *host) WithMgmtNet(*types.MgmtNet) {}
func (s *host) SaveConfig(ctx context.Context, r runtime.ContainerRuntime) error {
return nil
}
4 changes: 4 additions & 0 deletions nodes/linux/linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,7 @@ func (l *linux) PostDeploy(ctx context.Context, r runtime.ContainerRuntime, ns m
}

func (l *linux) WithMgmtNet(*types.MgmtNet) {}

func (s *linux) SaveConfig(ctx context.Context, r runtime.ContainerRuntime) error {
return nil
}
4 changes: 4 additions & 0 deletions nodes/mysocketio/mysocketio.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,8 @@ func (s *mySocketIO) PostDeploy(ctx context.Context, r runtime.ContainerRuntime,

func (s *mySocketIO) WithMgmtNet(*types.MgmtNet) {}

func (s *mySocketIO) SaveConfig(ctx context.Context, r runtime.ContainerRuntime) error {
return nil
}

///
8 changes: 8 additions & 0 deletions nodes/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type Node interface {
Deploy(context.Context, runtime.ContainerRuntime) error
PostDeploy(context.Context, runtime.ContainerRuntime, map[string]Node) error
WithMgmtNet(*types.MgmtNet)
SaveConfig(context.Context, runtime.ContainerRuntime) error
}

var Nodes = map[string]Initializer{}
Expand Down Expand Up @@ -72,3 +73,10 @@ var DefaultConfigTemplates = map[string]string{
"crpd": "/etc/containerlab/templates/crpd/juniper.conf",
"vr-sros": "",
}

// DefaultCredentials holds default username and password per each kind
var DefaultCredentials = map[string][]string{
"vr-sros": {"admin", "admin"},
"vr-vmx": {"admin", "admin@123"},
"vr-xrv9k": {"clab", "clab@123"},
}
4 changes: 4 additions & 0 deletions nodes/ovs/ovs.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,7 @@ func (l *ovs) PostDeploy(ctx context.Context, r runtime.ContainerRuntime, ns map
}

func (l *ovs) WithMgmtNet(*types.MgmtNet) {}

func (s *ovs) SaveConfig(ctx context.Context, r runtime.ContainerRuntime) error {
return nil
}
4 changes: 4 additions & 0 deletions nodes/sonic/sonic.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,7 @@ func (s *sonic) PostDeploy(ctx context.Context, r runtime.ContainerRuntime, ns m
}

func (s *sonic) WithMgmtNet(*types.MgmtNet) {}

func (s *sonic) SaveConfig(ctx context.Context, r runtime.ContainerRuntime) error {
return nil
}
4 changes: 4 additions & 0 deletions nodes/srl/srl.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ func (s *srl) Destroy(ctx context.Context, r runtime.ContainerRuntime) error {

func (s *srl) WithMgmtNet(*types.MgmtNet) {}

func (s *srl) SaveConfig(ctx context.Context, r runtime.ContainerRuntime) error {
return nil
}

//

func createSRLFiles(nodeCfg *types.NodeConfig) error {
Expand Down
4 changes: 4 additions & 0 deletions nodes/vr_csr/vr-csr.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,7 @@ func (s *vrCsr) Destroy(ctx context.Context, r runtime.ContainerRuntime) error {
func (s *vrCsr) WithMgmtNet(mgmt *types.MgmtNet) {
s.mgmt = mgmt
}

func (s *vrCsr) SaveConfig(ctx context.Context, r runtime.ContainerRuntime) error {
return nil
}
4 changes: 4 additions & 0 deletions nodes/vr_ros/vr-ros.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,7 @@ func (s *vrRos) PostDeploy(ctx context.Context, r runtime.ContainerRuntime, ns m
}

func (s *vrRos) WithMgmtNet(mgmt *types.MgmtNet) { s.mgmt = mgmt }

func (s *vrRos) SaveConfig(ctx context.Context, r runtime.ContainerRuntime) error {
return nil
}
14 changes: 14 additions & 0 deletions nodes/vr_sros/vr-sros.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,20 @@ func (s *vrSROS) WithMgmtNet(mgmt *types.MgmtNet) {
s.mgmt = mgmt
}

func (s *vrSROS) SaveConfig(ctx context.Context, r runtime.ContainerRuntime) error {
err := utils.SaveCfgViaNetconf(s.cfg.LongName,
nodes.DefaultCredentials[s.cfg.Kind][0],
nodes.DefaultCredentials[s.cfg.Kind][0],
false)

if err != nil {
return err
}

log.Infof("saved %s running configuration to startup configuration file\n", s.cfg.ShortName)
return nil
}

//

func createVrSROSFiles(node *types.NodeConfig) error {
Expand Down
4 changes: 4 additions & 0 deletions nodes/vr_veos/vr-veos.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,7 @@ func (s *vrVEOS) PostDeploy(ctx context.Context, r runtime.ContainerRuntime, ns
}

func (s *vrVEOS) WithMgmtNet(mgmt *types.MgmtNet) { s.mgmt = mgmt }

func (s *vrVEOS) SaveConfig(ctx context.Context, r runtime.ContainerRuntime) error {
return nil
}
4 changes: 4 additions & 0 deletions nodes/vr_vmx/vr-vmx.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,7 @@ func (s *vrVMX) PostDeploy(ctx context.Context, r runtime.ContainerRuntime, ns m
}

func (s *vrVMX) WithMgmtNet(mgmt *types.MgmtNet) { s.mgmt = mgmt }

func (s *vrVMX) SaveConfig(ctx context.Context, r runtime.ContainerRuntime) error {
return nil
}
4 changes: 4 additions & 0 deletions nodes/vr_xrv/vr-xrv.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,7 @@ func (s *vrXRV) PostDeploy(ctx context.Context, r runtime.ContainerRuntime, ns m
}

func (s *vrXRV) WithMgmtNet(mgmt *types.MgmtNet) { s.mgmt = mgmt }

func (s *vrXRV) SaveConfig(ctx context.Context, r runtime.ContainerRuntime) error {
return nil
}
4 changes: 4 additions & 0 deletions nodes/vr_xrv9k/vr-xrv9k.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,7 @@ func (s *vrXRV9K) PostDeploy(ctx context.Context, r runtime.ContainerRuntime, ns
}

func (s *vrXRV9K) WithMgmtNet(mgmt *types.MgmtNet) { s.mgmt = mgmt }

func (s *vrXRV9K) SaveConfig(ctx context.Context, r runtime.ContainerRuntime) error {
return nil
}
43 changes: 43 additions & 0 deletions utils/netconf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2020 Nokia
// Licensed under the BSD 3-Clause License.
// SPDX-License-Identifier: BSD-3-Clause

package utils

import (
"fmt"

"github.com/scrapli/scrapligo/driver/base"
"github.com/scrapli/scrapligo/netconf"
"github.com/scrapli/scrapligo/transport"
)

// SaveCfgViaNetconf saves the running config to the startup by means
// of invoking a netconf rpc <copy-config>
// this method is used on the network elements that can't perform a save of config via other means
func SaveCfgViaNetconf(addr, username, password string, echo bool) error {
d, err := netconf.NewNetconfDriver(
addr,
base.WithAuthStrictKey(false),
base.WithAuthUsername(username),
base.WithAuthPassword(password),
base.WithTransportType(transport.StandardTransportName),
base.WithNetconfServerEcho(echo),
)
if err != nil {
return fmt.Errorf("Could not create netconf driver for %s: %+v\n", addr, err)
}

err = d.Open()
if err != nil {
return fmt.Errorf("failed to open netconf driver for %s: %+v\n", addr, err)
}
defer d.Close()

_, err = d.CopyConfig("running", "startup")
if err != nil {
return fmt.Errorf("%s: Could not send save config via Netconf: %+v", addr, err)
}

return nil
}

0 comments on commit 106c5bc

Please sign in to comment.