Skip to content

Commit

Permalink
Merge branch 'master' of github.com:srl-labs/containerlab
Browse files Browse the repository at this point in the history
  • Loading branch information
hellt committed Aug 2, 2021
2 parents 2ea5674 + 0b5686a commit 39c5061
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 17 deletions.
34 changes: 25 additions & 9 deletions clab/config/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ var TemplateNames []string
// path to additional templates
var TemplatePaths []string

// debug count
var DebugCount int

type NodeConfig struct {
TargetNode *types.NodeConfig
// All the variables used to render the template
Expand Down Expand Up @@ -89,7 +92,7 @@ func RenderAll(nodes map[string]nodes.Node, links map[int]*types.Link) (map[stri
var buf strings.Builder
err := tmpl.ExecuteTemplate(&buf, tmplN, vars)
if err != nil {
res[nodeName].Print(0, true)
res[nodeName].Print(true, true)
return nil, err
}

Expand All @@ -103,37 +106,50 @@ func RenderAll(nodes map[string]nodes.Node, links map[int]*types.Link) (map[stri

// Implement stringer for NodeConfig
func (c *NodeConfig) String() string {

s := fmt.Sprintf("%s: %v", c.TargetNode.ShortName, c.Info)
return s
}

// Print the config
func (c *NodeConfig) Print(printLines int, forceDebug ...bool) {
func (c *NodeConfig) Print(vars, rendered bool) {
var s strings.Builder

s.WriteString(c.TargetNode.ShortName)

if log.IsLevelEnabled(log.DebugLevel) || len(forceDebug) > 0 {
if vars {
s.WriteString(" vars = ")
var saved_nodes Dict
restore := false
if DebugCount < 3 {
saved_nodes, restore = c.Vars[vkNodes].(Dict)
if restore {
var n strings.Builder
n.WriteRune('{')
for k := range saved_nodes {
fmt.Fprintf(&n, "%s: {...}, ", k)
}
n.WriteRune('}')
c.Vars[vkNodes] = n.String()
}
}
vars, err := yaml.Marshal(c.Vars)
if err != nil {
log.Warnf("error printing vars for node %s: %s", c.TargetNode.ShortName, err)
s.WriteString(err.Error())
}
if restore {
c.Vars[vkNodes] = saved_nodes
}
if len(vars) > 0 {
s.Write(vars)
}
}

if printLines > 0 {
if rendered {
for idx, conf := range c.Data {
fmt.Fprintf(&s, "\n Template %s for %s = [[", c.Info[idx], c.TargetNode.ShortName)

cl := strings.SplitN(conf, "\n", printLines+1)
if len(cl) > printLines {
cl[printLines] = "..."
}
cl := strings.Split(conf, "\n")
for _, l := range cl {
s.WriteString("\n ")
s.WriteString(l)
Expand Down
26 changes: 20 additions & 6 deletions cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import (
"github.com/srl-labs/containerlab/nodes"
)

// Only print config locally, don't send to the node
var printLines int
// Dryrun and print config
var check string

// configCmd represents the config command
var configCmd = &cobra.Command{
Expand All @@ -25,6 +25,7 @@ var configCmd = &cobra.Command{
var err error

transport.DebugCount = debugCount
config.DebugCount = debugCount

c, err := clab.NewContainerLab(
clab.WithTimeout(timeout),
Expand All @@ -40,9 +41,21 @@ var configCmd = &cobra.Command{
return err
}

if printLines > 0 {
if check != "" {

pv := check == "all" || check == "vars"
pt := check == "all" || check == "template"

if !(pv || pt) {
if c, ok := allConfig[check]; ok {
c.Print(true, true)
return nil
}
log.Warnf("Invalid command line option for check. Options: 'template'(default), 'vars', 'all' or a valid node name")
pt = true
}
for _, c := range allConfig {
c.Print(printLines)
c.Print(pv, pt)
}
return nil
}
Expand Down Expand Up @@ -101,7 +114,8 @@ var configCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(configCmd)
configCmd.Flags().StringSliceVarP(&config.TemplatePaths, "template-path", "p", []string{}, "comma separated list of paths to search for templates")
configCmd.MarkFlagDirname("template-path")
_ = configCmd.MarkFlagDirname("template-path")
configCmd.Flags().StringSliceVarP(&config.TemplateNames, "template-list", "l", []string{}, "comma separated list of template names to render")
configCmd.Flags().IntVarP(&printLines, "check", "c", 0, "render templates in dry-run mode & print N lines of rendered config")
configCmd.Flags().StringVarP(&check, "check", "c", "", "render templates in dry-run mode & print either 'template', 'vars', 'all' or a specific node")
configCmd.Flags().Lookup("check").NoOptDefVal = "template"
}
43 changes: 43 additions & 0 deletions docs/manual/kinds/vr-nxos.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Cisco NXOS

[Cisco NXOS](https://www.cisco.com/c/en/us/products/ios-nx-os-software/nx-os/index.html) virtual appliance is identified with `vr-nxos` kind in the [topology file](../topo-def-file.md). It is built using [hellt/vrnetlab](../vrnetlab.md) project and essentially is a Qemu VM packaged in a docker container format.

!!!note
This is a Titanium based system, which is an older version of NX-OS.

vr-nxos nodes launched with containerlab come up pre-provisioned with SSH service enabled.

## Managing vr-nxos nodes
Cisco NXOS node launched with containerlab can be managed via the following interfaces:

=== "bash"
to connect to a `bash` shell of a running vr-nxos container:
```bash
docker exec -it <container-name/id> bash
```
=== "CLI via SSH"
to connect to the NX-OS CLI
```bash
ssh clab@<container-name/id>
```


!!!info
Default user credentials: `admin:admin`

## Interfaces mapping
vr-nxos container can have up to 90 interfaces and uses the following mapping rules:

* `eth0` - management interface connected to the containerlab management network
* `eth1` - first data interface, mapped to first data port of NX-OS line card
* `eth2+` - second and subsequent data interface

When containerlab launches vr-nxos node, it will assign IPv4/6 address to the `eth0` interface. These addresses can be used to reach management plane of the router.

Data interfaces `eth1+` needs to be configured with IP addressing manually using CLI/management protocols.


## Features and options
### Node configuration
vr-nxos nodes come up with a basic configuration where only the control plane and line cards are provisioned, as well as the `clab` user.

2 changes: 0 additions & 2 deletions docs/manual/kinds/vr-xrv9k.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,3 @@ The following labs feature vr-xrv9k node:

- [SR Linux and Cisco XRv9k](../../lab-examples/vr-xrv9k.md)

## Known issues and limitations
* LACP and BPDU packets are not propagated to/from vrnetlab based routers launched with containerlab.
1 change: 1 addition & 0 deletions nodes/all/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
_ "github.com/srl-labs/containerlab/nodes/sonic"
_ "github.com/srl-labs/containerlab/nodes/srl"
_ "github.com/srl-labs/containerlab/nodes/vr_csr"
_ "github.com/srl-labs/containerlab/nodes/vr_nxos"
_ "github.com/srl-labs/containerlab/nodes/vr_pan"
_ "github.com/srl-labs/containerlab/nodes/vr_ros"
_ "github.com/srl-labs/containerlab/nodes/vr_sros"
Expand Down
1 change: 1 addition & 0 deletions nodes/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ const (
NodeKindVrVMX = "vr-vmx"
NodeKindVrXRV = "vr-xrv"
NodeKindVrXRV9K = "vr-xrv9k"
NodeKindVrNXOS = "vr-nxos"
)

// a map of node kinds overriding the default global runtime
Expand Down
86 changes: 86 additions & 0 deletions nodes/vr_nxos/vr-nxos.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright 2021 Nokia
// Licensed under the BSD 3-Clause License.
// SPDX-License-Identifier: BSD-3-Clause

package vr_nxos

import (
"context"
"fmt"

"github.com/srl-labs/containerlab/nodes"
"github.com/srl-labs/containerlab/runtime"
"github.com/srl-labs/containerlab/types"
"github.com/srl-labs/containerlab/utils"
)

func init() {
nodes.Register(nodes.NodeKindVrNXOS, func() nodes.Node {
return new(vrNXOS)
})
}

type vrNXOS struct {
cfg *types.NodeConfig
mgmt *types.MgmtNet
runtime runtime.ContainerRuntime
}

func (s *vrNXOS) Init(cfg *types.NodeConfig, opts ...nodes.NodeOption) error {
s.cfg = cfg
for _, o := range opts {
o(s)
}
// env vars are used to set launch.py arguments in vrnetlab container
defEnv := map[string]string{
"USERNAME": "admin",
"PASSWORD": "admin",
"CONNECTION_MODE": nodes.VrDefConnMode,
"VCPU": "2",
"RAM": "4096",
"DOCKER_NET_V4_ADDR": s.mgmt.IPv4Subnet,
"DOCKER_NET_V6_ADDR": s.mgmt.IPv6Subnet,
}
s.cfg.Env = utils.MergeStringMaps(defEnv, s.cfg.Env)

s.cfg.Cmd = fmt.Sprintf("--username %s --password %s --hostname %s --connection-mode %s --trace",
s.cfg.Env["USERNAME"], s.cfg.Env["PASSWORD"], s.cfg.ShortName, s.cfg.Env["CONNECTION_MODE"])

return nil
}

func (s *vrNXOS) Config() *types.NodeConfig { return s.cfg }

func (s *vrNXOS) PreDeploy(configName, labCADir, labCARoot string) error {
utils.CreateDirectory(s.cfg.LabDir, 0777)
return nil
}

func (s *vrNXOS) Deploy(ctx context.Context) error {
_, err := s.runtime.CreateContainer(ctx, s.cfg)
return err
}

func (s *vrNXOS) GetImages() map[string]string {
return map[string]string{
nodes.ImageKey: s.cfg.Image,
}
}

func (s *vrNXOS) PostDeploy(ctx context.Context, ns map[string]nodes.Node) error {
return nil
}

func (s *vrNXOS) WithMgmtNet(mgmt *types.MgmtNet) { s.mgmt = mgmt }
func (s *vrNXOS) WithRuntime(r runtime.ContainerRuntime) {
s.runtime = r
}
func (s *vrNXOS) GetRuntime() runtime.ContainerRuntime { return s.runtime }

func (s *vrNXOS) Delete(ctx context.Context) error {
return s.runtime.DeleteContainer(ctx, s.Config().LongName)
}

func (s *vrNXOS) SaveConfig(ctx context.Context) error {
return nil
}
1 change: 1 addition & 0 deletions schemas/clab.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"vr-vmx",
"vr-xrv",
"vr-xrv9k",
"vr-nxos",
"vr-veos",
"vr-csr",
"vr-pan",
Expand Down

0 comments on commit 39c5061

Please sign in to comment.