Skip to content

Commit

Permalink
Merge pull request #1191 from srl-labs/iface-signatures-for-all
Browse files Browse the repository at this point in the history
add interface signatures for all nodes
  • Loading branch information
hellt authored Jan 14, 2023
2 parents 03a7bce + 121b149 commit ba3475c
Show file tree
Hide file tree
Showing 26 changed files with 283 additions and 43 deletions.
1 change: 0 additions & 1 deletion cmd/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,6 @@ func deployFn(_ *cobra.Command, _ []string) error {
// execute commands specified for nodes with `exec` node parameter
execCollection := exec.NewExecCollection()
for _, n := range c.Nodes {

for _, e := range n.Config().Exec {
exec, err := exec.NewExecCmdFromString(e)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions cmd/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ var interfaceFormat = map[string]string{
"vr-veos": "eth%d",
"xrd": "eth%d",
}

var supportedKinds = []string{
"srl", "ceos", "linux", "bridge", "sonic-vs", "crpd", "vr-sros",
"vr-vmx", "vr-vqfx", "vr-xrv9k", "vr-veos", "xrd",
Expand Down
3 changes: 2 additions & 1 deletion docs/manual/kinds/ceos.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Arista cEOS node launched with containerlab can be managed via the following int

ceos container uses the following mapping for its linux interfaces:

* `eth0` - management interface connected to the containerlab management network
* `eth0`[^5] - management interface connected to the containerlab management network
* `eth1` - first data interface

When containerlab launches ceos node, it will set IPv4/6 addresses as assigned by docker to the `eth0` interface and ceos node will boot with that addresses configured. Data interfaces `eth1+` need to be configured with IP addressing manually.
Expand Down Expand Up @@ -400,3 +400,4 @@ sudo ip6tables -P INPUT ACCEPT
[^2]: feel free to omit the IP addressing for Management interface, as it will be configured by containerlab when ceos node boots.
[^3]: if startup config needs to be enforced, either deploy a lab with `--reconfigure` flag, or use [`enforce-startup-config`](../nodes.md#enforce-startup-config) setting.
[^4]: for example, Ubuntu 21.04 comes with cgroup v2 [by default](https://askubuntu.com/a/1369957).
[^5]: interface name can also be `et` instead of `eth`.
2 changes: 1 addition & 1 deletion nodes/bridge/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ func (*bridge) UpdateConfigWithRuntimeInfo(_ context.Context) error { return nil
// GetContainers is a noop for bridges.
func (*bridge) GetContainers(_ context.Context) ([]runtime.GenericContainer, error) { return nil, nil }

// RunExec is not implemented for bridge kind
// RunExec is not implemented for bridge kind.
func (b *bridge) RunExec(_ context.Context, _ *cExec.ExecCmd) (cExec.ExecResultHolder, error) {
log.Warnf("Exec operation is not implemented for kind %q", b.Config().Kind)

Expand Down
15 changes: 15 additions & 0 deletions nodes/ceos/ceos.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"os"
"path"
"path/filepath"
"regexp"
"strings"

log "github.com/sirupsen/logrus"
Expand Down Expand Up @@ -271,3 +272,17 @@ func (n *ceos) ceosPostDeploy(_ context.Context) error {

return err
}

// CheckInterfaceName checks if a name of the interface referenced in the topology file correct.
func (n *ceos) CheckInterfaceName() error {
// allow eth and et interfaces
// https://regex101.com/r/umQW5Z/1
ifRe := regexp.MustCompile(`eth[1-9]+$|et[1-9]+$`)
for _, e := range n.Config().Endpoints {
if !ifRe.MatchString(e.EndpointName) {
return fmt.Errorf("arista cEOS node %q has an interface named %q which doesn't match the required pattern. Interfaces should be named as ethX or etX, where X is >1", n.Cfg.ShortName, e.EndpointName)
}
}

return nil
}
21 changes: 19 additions & 2 deletions nodes/checkpoint_cloudguard/checkpoint_cloudguard.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,17 @@ package checkpoint_cloudguard
import (
"context"
"fmt"
"regexp"

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

var kindnames = []string{"checkpoint_cloudguard"}
var defaultCredentials = nodes.NewCredentials("admin", "admin")
var (
kindnames = []string{"checkpoint_cloudguard"}
defaultCredentials = nodes.NewCredentials("admin", "admin")
)

// Register registers the node in the NodeRegistry.
func Register(r *nodes.NodeRegistry) {
Expand Down Expand Up @@ -57,3 +60,17 @@ func (n *CheckpointCloudguard) PreDeploy(_ context.Context, _, _, _ string) erro
utils.CreateDirectory(n.Cfg.LabDir, 0777)
return nil
}

// CheckInterfaceName checks if a name of the interface referenced in the topology file correct.
func (n *CheckpointCloudguard) CheckInterfaceName() error {
// allow eth and et interfaces
// https://regex101.com/r/C3Fhr0/1
ifRe := regexp.MustCompile(`eth[1-9]+$`)
for _, e := range n.Config().Endpoints {
if !ifRe.MatchString(e.EndpointName) {
return fmt.Errorf("%q interface name %q doesn't match the required pattern. It should be named as ethX, where X is >1", n.Cfg.ShortName, e.EndpointName)
}
}

return nil
}
15 changes: 15 additions & 0 deletions nodes/crpd/crpd.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"fmt"
"os"
"path/filepath"
"regexp"

log "github.com/sirupsen/logrus"
"github.com/srl-labs/containerlab/clab/exec"
Expand Down Expand Up @@ -159,3 +160,17 @@ func createCRPDFiles(node nodes.Node) error {
}
return nil
}

// CheckInterfaceName checks if a name of the interface referenced in the topology file correct.
func (n *crpd) CheckInterfaceName() error {
// allow eth and et interfaces
// https://regex101.com/r/C3Fhr0/1
ifRe := regexp.MustCompile(`eth[1-9]+$`)
for _, e := range n.Config().Endpoints {
if !ifRe.MatchString(e.EndpointName) {
return fmt.Errorf("%q interface name %q doesn't match the required pattern. It should be named as ethX, where X is >1", n.Cfg.ShortName, e.EndpointName)
}
}

return nil
}
2 changes: 2 additions & 0 deletions nodes/default_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ func (d *DefaultNode) SaveConfig(_ context.Context) error {
return nil
}

// CheckDeploymentConditions wraps individual functions that check if a node
// satisfies deployment requirements.
func (d *DefaultNode) CheckDeploymentConditions(ctx context.Context) error {
err := d.OverwriteNode.VerifyHostRequirements()
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion nodes/host/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func (*host) GetContainers(_ context.Context) ([]runtime.GenericContainer, error
}, nil
}

// RunExec is not implemented for host kind
// RunExec is not implemented for host kind.
func (n *host) RunExec(_ context.Context, _ *cExec.ExecCmd) (cExec.ExecResultHolder, error) {
log.Warnf("Exec operation is not implemented for kind %q", n.Config().Kind)

Expand Down
21 changes: 19 additions & 2 deletions nodes/ipinfusion_ocnos/ipinfusion_ocnos.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package ipinfusion_ocnos
import (
"context"
"fmt"
"regexp"

log "github.com/sirupsen/logrus"
"github.com/srl-labs/containerlab/netconf"
Expand All @@ -15,8 +16,10 @@ import (
"github.com/srl-labs/containerlab/utils"
)

var kindnames = []string{"ipinfusion_ocnos"}
var defaultCredentials = nodes.NewCredentials("admin", "admin")
var (
kindnames = []string{"ipinfusion_ocnos"}
defaultCredentials = nodes.NewCredentials("admin", "admin")
)

const (
scrapliPlatformName = "ipinfusion_ocnos"
Expand Down Expand Up @@ -77,3 +80,17 @@ func (s *IPInfusionOcNOS) SaveConfig(_ context.Context) error {
log.Infof("saved %s running configuration to startup configuration file\n", s.Cfg.ShortName)
return nil
}

// CheckInterfaceName checks if a name of the interface referenced in the topology file correct.
func (n *IPInfusionOcNOS) CheckInterfaceName() error {
// allow eth and et interfaces
// https://regex101.com/r/C3Fhr0/1
ifRe := regexp.MustCompile(`eth[1-9]+$`)
for _, e := range n.Config().Endpoints {
if !ifRe.MatchString(e.EndpointName) {
return fmt.Errorf("%q interface name %q doesn't match the required pattern. It should be named as ethX, where X is >1", n.Cfg.ShortName, e.EndpointName)
}
}

return nil
}
2 changes: 1 addition & 1 deletion nodes/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ type Node interface {
PostDeploy(context.Context, map[string]Node) error
WithMgmtNet(*types.MgmtNet) // WithMgmtNet provides the management network for the node
WithRuntime(runtime.ContainerRuntime) // WithRuntime provides the runtime for the node
// CheckInterfaceName checks if a name of the interface referenced in the topology file correct
// CheckInterfaceName checks if a name of the interface referenced in the topology file is correct for this node
CheckInterfaceName() error
// VerifyStartupConfig checks for existence of the referenced file and maybe performs additional config checks
VerifyStartupConfig(topoDir string) error
Expand Down
15 changes: 7 additions & 8 deletions nodes/node_registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package nodes

import (
"fmt"

"sort"
"strings"
)
Expand All @@ -14,20 +13,20 @@ type NodeRegistry struct {
nodeIndex map[string]*nodeRegistryEntry
}

// NewNodeRegistry constructs a new Registry
// NewNodeRegistry constructs a new Registry.
func NewNodeRegistry() *NodeRegistry {
return &NodeRegistry{
nodeIndex: map[string]*nodeRegistryEntry{},
}
}

// Register registers the node' init function for all provided names
// Register registers the node' init function for all provided names.
func (r *NodeRegistry) Register(names []string, initf Initializer, credentials *Credentials) error {
newEntry := newRegistryEntry(names, initf, credentials)
return r.addEntry(newEntry)
}

// addEntry adds the node entry to the registry
// addEntry adds the node entry to the registry.
func (r *NodeRegistry) addEntry(entry *nodeRegistryEntry) error {
for _, name := range entry.nodeKindNames {
if _, exists := r.nodeIndex[name]; exists {
Expand All @@ -40,7 +39,7 @@ func (r *NodeRegistry) addEntry(entry *nodeRegistryEntry) error {
return nil
}

// NewNodeOfKind return a new Node of the given Node Kind
// NewNodeOfKind return a new Node of the given Node Kind.
func (r *NodeRegistry) NewNodeOfKind(nodeKindName string) (Node, error) {
nodeKindEntry, ok := r.nodeIndex[nodeKindName]
if !ok {
Expand All @@ -52,7 +51,7 @@ func (r *NodeRegistry) NewNodeOfKind(nodeKindName string) (Node, error) {
return nodeKindEntry.initFunction(), nil
}

// GetRegisteredNodeKindNames returns a sorted slice of all the registered node kind names in the registry
// GetRegisteredNodeKindNames returns a sorted slice of all the registered node kind names in the registry.
func (r *NodeRegistry) GetRegisteredNodeKindNames() []string {
var result []string
for k := range r.nodeIndex {
Expand All @@ -78,13 +77,13 @@ func newRegistryEntry(nodeKindNames []string, initFunction Initializer, credenti
}
}

// Credentials defines NOS SSH credentials
// Credentials defines NOS SSH credentials.
type Credentials struct {
username string
password string
}

// NewCredentials constructor for the Credentials struct
// NewCredentials constructor for the Credentials struct.
func NewCredentials(username, password string) *Credentials {
return &Credentials{
username: username,
Expand Down
2 changes: 1 addition & 1 deletion nodes/ovs/ovs.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (*ovs) UpdateConfigWithRuntimeInfo(_ context.Context) error { return nil }
// GetContainers is a noop for bridges.
func (*ovs) GetContainers(_ context.Context) ([]runtime.GenericContainer, error) { return nil, nil }

// RunExec is not implemented for ovs kind
// RunExec is not implemented for ovs kind.
func (n *ovs) RunExec(_ context.Context, _ *cExec.ExecCmd) (cExec.ExecResultHolder, error) {
log.Warnf("Exec operation is not implemented for kind %q", n.Config().Kind)

Expand Down
21 changes: 19 additions & 2 deletions nodes/vr_csr/vr-csr.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"context"
"fmt"
"path"
"regexp"

log "github.com/sirupsen/logrus"
"github.com/srl-labs/containerlab/netconf"
Expand All @@ -16,8 +17,10 @@ import (
"github.com/srl-labs/containerlab/utils"
)

var kindnames = []string{"vr-csr", "vr-cisco_csr1000v"}
var defaultCredentials = nodes.NewCredentials("admin", "admin")
var (
kindnames = []string{"vr-csr", "vr-cisco_csr1000v"}
defaultCredentials = nodes.NewCredentials("admin", "admin")
)

const (
scrapliPlatformName = "cisco_iosxe"
Expand Down Expand Up @@ -89,3 +92,17 @@ func (s *vrCsr) SaveConfig(_ context.Context) error {
log.Infof("saved %s running configuration to startup configuration file\n", s.Cfg.ShortName)
return nil
}

// CheckInterfaceName checks if a name of the interface referenced in the topology file correct.
func (n *vrCsr) CheckInterfaceName() error {
// allow eth and et interfaces
// https://regex101.com/r/C3Fhr0/1
ifRe := regexp.MustCompile(`eth[1-9]+$`)
for _, e := range n.Config().Endpoints {
if !ifRe.MatchString(e.EndpointName) {
return fmt.Errorf("%q interface name %q doesn't match the required pattern. It should be named as ethX, where X is >1", n.Cfg.ShortName, e.EndpointName)
}
}

return nil
}
21 changes: 19 additions & 2 deletions nodes/vr_ftosv/vr-ftosv.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ import (
"context"
"fmt"
"path"
"regexp"

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

var kindnames = []string{"vr-ftosv", "vr-dell_ftosv"}
var defaultCredentials = nodes.NewCredentials("admin", "admin")
var (
kindnames = []string{"vr-ftosv", "vr-dell_ftosv"}
defaultCredentials = nodes.NewCredentials("admin", "admin")
)

const (
configDirName = "config"
Expand Down Expand Up @@ -71,3 +74,17 @@ func (s *vrFtosv) PreDeploy(_ context.Context, _, _, _ string) error {
utils.CreateDirectory(s.Cfg.LabDir, 0777)
return nodes.LoadStartupConfigFileVr(s, configDirName, startupCfgFName)
}

// CheckInterfaceName checks if a name of the interface referenced in the topology file correct.
func (n *vrFtosv) CheckInterfaceName() error {
// allow eth and et interfaces
// https://regex101.com/r/C3Fhr0/1
ifRe := regexp.MustCompile(`eth[1-9]+$`)
for _, e := range n.Config().Endpoints {
if !ifRe.MatchString(e.EndpointName) {
return fmt.Errorf("%q interface name %q doesn't match the required pattern. It should be named as ethX, where X is >1", n.Cfg.ShortName, e.EndpointName)
}
}

return nil
}
21 changes: 19 additions & 2 deletions nodes/vr_n9kv/vr-n9kv.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@ import (
"context"
"fmt"
"path"
"regexp"

"github.com/srl-labs/containerlab/nodes"

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

var kindnames = []string{"vr-n9kv", "vr-cisco_n9kv"}
var defaultCredentials = nodes.NewCredentials("admin", "admin")
var (
kindnames = []string{"vr-n9kv", "vr-cisco_n9kv"}
defaultCredentials = nodes.NewCredentials("admin", "admin")
)

const (
configDirName = "config"
Expand Down Expand Up @@ -72,3 +75,17 @@ func (s *vrN9kv) PreDeploy(_ context.Context, _, _, _ string) error {
utils.CreateDirectory(s.Cfg.LabDir, 0777)
return nodes.LoadStartupConfigFileVr(s, configDirName, startupCfgFName)
}

// CheckInterfaceName checks if a name of the interface referenced in the topology file correct.
func (n *vrN9kv) CheckInterfaceName() error {
// allow eth and et interfaces
// https://regex101.com/r/C3Fhr0/1
ifRe := regexp.MustCompile(`eth[1-9]+$`)
for _, e := range n.Config().Endpoints {
if !ifRe.MatchString(e.EndpointName) {
return fmt.Errorf("%q interface name %q doesn't match the required pattern. It should be named as ethX, where X is >1", n.Cfg.ShortName, e.EndpointName)
}
}

return nil
}
Loading

0 comments on commit ba3475c

Please sign in to comment.