Skip to content

Commit

Permalink
Store information about NodeGeneration in registry. (#1347)
Browse files Browse the repository at this point in the history
* Store information about NodeGeneration in registry.

So far generate.go contained two lists indenpendent from the nodes, that would describe nodes that (1) can be generated and (b) what the interface naming convention would be for the node kind. This will introduce seperate fields in the NodeRegistry for this information, such that the information for this sort of node generation can be defined as part of the node definition

* use utils func to create topo file on generate

* format

* typo

* added missing platforms

* rename Credentials->GetCredentials

* align node registration func

* use native interface names

* use getter

---------

Co-authored-by: Roman Dodin <dodin.roman@gmail.com>
  • Loading branch information
steiler and hellt authored Dec 5, 2024
1 parent 51c6366 commit ca7e450
Show file tree
Hide file tree
Showing 43 changed files with 379 additions and 219 deletions.
2 changes: 1 addition & 1 deletion clab/config/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func PrepareVars(c *clab.CLab) map[string]*NodeConfig {
vars[vkRole] = nodeCfg.Kind
}

creds := c.Reg.Kind(nodeCfg.Kind).Credentials().Slice()
creds := c.Reg.Kind(nodeCfg.Kind).GetCredentials().Slice()

res[name] = &NodeConfig{
TargetNode: nodeCfg,
Expand Down
4 changes: 2 additions & 2 deletions clab/inventory.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ func (c *CLab) generateAnsibleInventory(w io.Writer) error {
// assumption is that all nodes of the same kind have the same credentials
nodeRegEntry := c.Reg.Kind(n.Config().Kind)
if nodeRegEntry != nil {
kindProps.Username = nodeRegEntry.Credentials().GetUsername()
kindProps.Password = nodeRegEntry.Credentials().GetPassword()
kindProps.Username = nodeRegEntry.GetCredentials().GetUsername()
kindProps.Password = nodeRegEntry.GetCredentials().GetPassword()
}

// add network_os to the node
Expand Down
2 changes: 1 addition & 1 deletion clab/sshconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (c *CLab) addSSHConfig() error {
NodeRegistryEntry := c.Reg.Kind(n.Config().Kind)
nodeData := SSHConfigNodeTmpl{
Name: n.Config().LongName,
Username: NodeRegistryEntry.Credentials().GetUsername(),
Username: NodeRegistryEntry.GetCredentials().GetUsername(),
SSHConfig: n.GetSSHConfig(),
}

Expand Down
147 changes: 26 additions & 121 deletions cmd/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,121 +8,20 @@ import (
"errors"
"fmt"
"net"
"os"
"strconv"
"strings"

log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/srl-labs/containerlab/clab"
"github.com/srl-labs/containerlab/links"
"github.com/srl-labs/containerlab/nodes/ceos"
"github.com/srl-labs/containerlab/nodes/crpd"
"github.com/srl-labs/containerlab/nodes/rare"
"github.com/srl-labs/containerlab/nodes/sonic"
"github.com/srl-labs/containerlab/nodes/srl"
"github.com/srl-labs/containerlab/nodes/vr_sros"
"github.com/srl-labs/containerlab/nodes/vr_veos"
"github.com/srl-labs/containerlab/nodes/vr_vjunosevolved"
"github.com/srl-labs/containerlab/nodes/vr_vjunosswitch"
"github.com/srl-labs/containerlab/nodes/vr_vmx"
"github.com/srl-labs/containerlab/nodes/vr_vqfx"
"github.com/srl-labs/containerlab/nodes/vr_vsrx"
"github.com/srl-labs/containerlab/nodes/vr_xrv9k"
"github.com/srl-labs/containerlab/nodes/xrd"
"github.com/srl-labs/containerlab/nodes"
"github.com/srl-labs/containerlab/types"
"github.com/srl-labs/containerlab/utils"
"gopkg.in/yaml.v2"
)

func buildInterfaceFormatMap() map[string]string {
m := make(map[string]string)

// Add SR Linux kinds
for _, k := range srl.KindNames {
m[k] = "e1-%d"
}

// Add Arista cEOS kinds
for _, k := range ceos.KindNames {
m[k] = "eth%d"
}

// Add Arista vEOS kinds
for _, k := range vr_veos.KindNames {
m[k] = "Et1/%d"
}

// Add Nokia SR OS kinds
for _, k := range vr_sros.KindNames {
m[k] = "1/1/%d"
}

// Add Juniper cRPD
for _, k := range crpd.KindNames {
m[k] = "eth%d"
}

// Add Juniper VMX kinds
for _, k := range vr_vmx.KindNames {
m[k] = "ge-0/0/%d"
}

// Add Juniper vSRX kinds
for _, k := range vr_vsrx.KindNames {
m[k] = "ge-0/0/%d"
}

// Add Juniper vQFX kinds
for _, k := range vr_vqfx.KindNames {
m[k] = "ge-0/0/%d"
}

// Add Juniper vJunos-Switch/Router
for _, k := range vr_vjunosswitch.KindNames {
m[k] = "et-0/0/%d"
}

// Add Juniper vJunos-Evolved
for _, k := range vr_vjunosevolved.KindNames {
m[k] = "et-0/0/%d"
}

// Add Cisco XRv9k kinds
for _, k := range vr_xrv9k.KindNames {
m[k] = "Gi0/0/0/%d"
}

// Add Cisco XRd
for _, k := range xrd.KindNames {
m[k] = "eth%d"
}

// Add RARE FreeRtr
for _, k := range rare.KindNames {
m[k] = "eth%d"
}

// Add SONiC VS
for _, k := range sonic.KindNames {
m[k] = "eth%d"
}

m["linux"] = "eth%d"
m["bridge"] = "veth%d"

return m
}

var interfaceFormat = buildInterfaceFormatMap()

var supportedKinds = []string{
"srl", "ceos", "linux", "bridge", "sonic-vs", "crpd", "vr-sros", "vr-vmx", "vr-vsrx",
"vr-vqfx", "juniper_vjunosevolved", "juniper_vjunosrouter", "juniper_vjunosswitch", "vr-xrv9k", "vr-veos",
"xrd", "rare", "openbsd", "cisco_ftdv", "freebsd",
}

const (
defaultSRLType = srl.SRLinuxDefaultType
defaultNodePrefix = "node"
defaultGroupPrefix = "tier"
)
Expand All @@ -141,6 +40,7 @@ var (
groupPrefix string
file string
deploy bool
reg *nodes.NodeRegistry
)

type nodesDef struct {
Expand Down Expand Up @@ -183,7 +83,7 @@ var generateCmd = &cobra.Command{
}
log.Debugf("generated topo: %s", string(b))
if file != "" {
err = saveTopoFile(file, b)
err = utils.CreateFile(file, string(b))
if err != nil {
return err
}
Expand All @@ -192,7 +92,7 @@ var generateCmd = &cobra.Command{
reconfigure = true
if file == "" {
file = fmt.Sprintf("%s.clab.yml", name)
err = saveTopoFile(file, b)
err = utils.CreateFile(file, string(b))
if err != nil {
return err
}
Expand All @@ -208,6 +108,22 @@ var generateCmd = &cobra.Command{
}

func init() {
c := &clab.CLab{}
c.Reg = nodes.NewNodeRegistry()
c.RegisterNodes()

reg = c.Reg

generateNodesAttributes := reg.GetGenerateNodeAttributes()
supportedKinds := []string{}

// prepare list of generateable node kinds
for k, v := range generateNodesAttributes {
if v.IsGenerateable() {
supportedKinds = append(supportedKinds, k)
}
}

rootCmd.AddCommand(generateCmd)
generateCmd.Flags().StringVarP(&mgmtNetName, "network", "", "", "management network name")
generateCmd.Flags().IPNetVarP(&mgmtIPv4Subnet, "ipv4-subnet", "4", net.IPNet{}, "management network IPv4 subnet range")
Expand Down Expand Up @@ -271,6 +187,9 @@ func generateTopologyConfig(name, network, ipv4range, ipv6range string,
}
}
}

generateNodesAttributes := reg.GetGenerateNodeAttributes()

for i := 0; i < numStages-1; i++ {
interfaceOffset := uint(0)
if i > 0 {
Expand Down Expand Up @@ -299,9 +218,9 @@ func generateTopologyConfig(name, network, ipv4range, ipv6range string,
l := &links.LinkVEthRaw{
Endpoints: []*links.EndpointRaw{
links.NewEndpointRaw(node1, fmt.Sprintf(
interfaceFormat[nodes[i].kind], k+1+interfaceOffset), ""),
generateNodesAttributes[nodes[i].kind].GetInterfaceFormat(), k+1+interfaceOffset), ""),
links.NewEndpointRaw(node2, fmt.Sprintf(
interfaceFormat[nodes[i+1].kind], j+1), ""),
generateNodesAttributes[nodes[i+1].kind].GetInterfaceFormat(), j+1), ""),
},
}

Expand Down Expand Up @@ -401,17 +320,3 @@ func parseNodesFlag(kind string, nodes ...string) ([]nodesDef, error) {
}
return result, nil
}

func saveTopoFile(path string, data []byte) error {
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0666) // skipcq: GSC-G302
if err != nil {
return err
}

_, err = f.Write(data)
if err != nil {
return err
}

return f.Close()
}
2 changes: 1 addition & 1 deletion cmd/tools_veth.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ func parseVethEndpoint(s string) (parsedEndpoint, error) {

case 3:
if _, ok := utils.StringInSlice([]string{"ovs-bridge", "bridge"}, arr[0]); !ok {
return ep, fmt.Errorf("node type %s is not supported, supported nodes are %q", arr[0], supportedKinds)
return ep, fmt.Errorf("only bride and ovs-bridge can be used as a first block in the link definition. Got: %s", arr[0])
}

switch arr[0] {
Expand Down
12 changes: 9 additions & 3 deletions nodes/bridge/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,24 @@ import (
"github.com/vishvananda/netlink"
)

var kindnames = []string{"bridge"}
var kindNames = []string{"bridge"}

const (
iptCheckCmd = "-vL FORWARD -w 5"
iptAllowCmd = "-I FORWARD -i %s -j ACCEPT -w 5"

generateable = true
generateIfFormat = "eth%d"
)

// Register registers the node in the NodeRegistry.
func Register(r *nodes.NodeRegistry) {
r.Register(kindnames, func() nodes.Node {
generateNodeAttributes := nodes.NewGenerateNodeAttributes(generateable, generateIfFormat)
nrea := nodes.NewNodeRegistryEntryAttributes(nil, generateNodeAttributes)

r.Register(kindNames, func() nodes.Node {
return new(bridge)
}, nil)
}, nrea)
}

type bridge struct {
Expand Down
3 changes: 2 additions & 1 deletion nodes/c8000/c8000.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,10 @@ const (

// Register registers the node in the NodeRegistry.
func Register(r *nodes.NodeRegistry) {
nrea := nodes.NewNodeRegistryEntryAttributes(defaultCredentials, nil)
r.Register(kindnames, func() nodes.Node {
return new(c8000)
}, defaultCredentials)
}, nrea)
}

type c8000 struct {
Expand Down
7 changes: 6 additions & 1 deletion nodes/ceos/ceos.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (

const (
ifWaitScriptContainerPath = "/mnt/flash/if-wait.sh"
generateable = true
generateIfFormat = "eth%d"
)

var (
Expand All @@ -52,9 +54,12 @@ var (

// Register registers the node in the NodeRegistry.
func Register(r *nodes.NodeRegistry) {
generateNodeAttributes := nodes.NewGenerateNodeAttributes(generateable, generateIfFormat)
nrea := nodes.NewNodeRegistryEntryAttributes(defaultCredentials, generateNodeAttributes)

r.Register(KindNames, func() nodes.Node {
return new(ceos)
}, defaultCredentials)
}, nrea)
}

type ceos struct {
Expand Down
3 changes: 2 additions & 1 deletion nodes/checkpoint_cloudguard/checkpoint_cloudguard.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ var (

// Register registers the node in the NodeRegistry.
func Register(r *nodes.NodeRegistry) {
nrea := nodes.NewNodeRegistryEntryAttributes(defaultCredentials, nil)
r.Register(kindnames, func() nodes.Node {
return new(CheckpointCloudguard)
}, defaultCredentials)
}, nrea)
}

type CheckpointCloudguard struct {
Expand Down
13 changes: 10 additions & 3 deletions nodes/crpd/crpd.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,17 @@ import (
)

const (

// licDir is the directory where Junos 22+ expects to find the license file.
licDir = "/config/license"
licFile = "license.lic"

generateable = true
generateIfFormat = "eth%d"
)

var (
KindNames = []string{"crpd", "juniper_crpd"}
kindNames = []string{"crpd", "juniper_crpd"}
//go:embed crpd.cfg
defaultCfgTemplate string

Expand All @@ -41,9 +45,12 @@ var (

// Register registers the node in the NodeRegistry.
func Register(r *nodes.NodeRegistry) {
r.Register(KindNames, func() nodes.Node {
generateNodeAttributes := nodes.NewGenerateNodeAttributes(generateable, generateIfFormat)
nrea := nodes.NewNodeRegistryEntryAttributes(defaultCredentials, generateNodeAttributes)

r.Register(kindNames, func() nodes.Node {
return new(crpd)
}, defaultCredentials)
}, nrea)
}

type crpd struct {
Expand Down
11 changes: 8 additions & 3 deletions nodes/dell_sonic/dell_sonic.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ import (
)

var (
kindnames = []string{"dell_sonic"}
kindNames = []string{"dell_sonic"}
defaultCredentials = nodes.NewCredentials("admin", "admin")
generateable = true
generateIfFormat = "eth%d"
)

const (
Expand All @@ -29,9 +31,12 @@ const (

// Register registers the node in the NodeRegistry.
func Register(r *nodes.NodeRegistry) {
r.Register(kindnames, func() nodes.Node {
generateNodeAttributes := nodes.NewGenerateNodeAttributes(generateable, generateIfFormat)
nrea := nodes.NewNodeRegistryEntryAttributes(defaultCredentials, generateNodeAttributes)

r.Register(kindNames, func() nodes.Node {
return new(dell_sonic)
}, defaultCredentials)
}, nrea)
}

type dell_sonic struct {
Expand Down
Loading

0 comments on commit ca7e450

Please sign in to comment.