diff --git a/clab/config.go b/clab/config.go index c3804a6f0..484b03b01 100644 --- a/clab/config.go +++ b/clab/config.go @@ -524,13 +524,29 @@ func (c *CLab) resolveBindPaths(binds []string, nodedir string) error { return nil } -// SetClabIntfsEnvVar sets CLAB_INTFS env var for each node -// which holds the number of interfaces a node expects to have (without mgmt interfaces). +// SetClabIntfsEnvVar sets CLAB_INTFS and CLAB_INTFS_WITH_MGMT env vars for each node +// which holds the number of interfaces a node expects to have (with and without mgmt interfaces). func (c *CLab) SetClabIntfsEnvVar() { for _, n := range c.Nodes { // Injecting the env var with expected number of links + // also adding one interface for the implicit management interface (eth0) + clabIntfs := len(n.GetEndpoints()) + + // by default the eth0 interface is automatically added by the container runtime + // so we add 1 to the number of interfaces to account for the management interface + clabIntfsWithMgmt := clabIntfs + 1 + + // when network mode is set to none, the eth0 is explicitly added + // so we need to substract it from the number of interfaces + // in vrnetlab the provisioned interfaces are matched as eth* glob + // so all dataplane + management interfaces are counted + if n.Config().NetworkMode == "none" { + clabIntfsWithMgmt -= 1 + } + numIntfs := map[string]string{ - types.CLAB_ENV_INTFS: fmt.Sprintf("%d", len(n.GetEndpoints())), + types.CLAB_ENV_INTFS: fmt.Sprintf("%d", clabIntfs), + types.CLAB_ENV_INTFS_WITH_MGMT: fmt.Sprintf("%d", clabIntfsWithMgmt), } n.Config().Env = utils.MergeStringMaps(n.Config().Env, numIntfs) } diff --git a/nodes/ceos/ceos.go b/nodes/ceos/ceos.go index 7d946b7a2..7061a6351 100644 --- a/nodes/ceos/ceos.go +++ b/nodes/ceos/ceos.go @@ -288,10 +288,17 @@ func (n *ceos) ceosPostDeploy(_ context.Context) error { func (n *ceos) CheckInterfaceName() error { // allow eth and et interfaces // https://regex101.com/r/umQW5Z/2 - ifRe := regexp.MustCompile(`eth[1-9][\w\.]*$|et[1-9][\w\.]*$`) + pattern := `eth[1-9][\w\.]*$|et[1-9][\w\.]*$` + + if n.Config().NetworkMode == "none" { + pattern = `eth[0-9][\w\.]*$|et[0-9][\w\.]*$` + } + + ifRe := regexp.MustCompile(pattern) + for _, e := range n.Endpoints { if !ifRe.MatchString(e.GetIfaceName()) { - 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 consists of alpanumerical characters", n.Cfg.ShortName, e.GetIfaceName()) + return fmt.Errorf("arista cEOS node %q has an interface named %q which doesn't match the required pattern %s. Interfaces should be named as ethX or etX, where X consists of numerical characters", n.Cfg.ShortName, e.GetIfaceName(), pattern) } } diff --git a/nodes/checkpoint_cloudguard/checkpoint_cloudguard.go b/nodes/checkpoint_cloudguard/checkpoint_cloudguard.go index 89fe699af..5976b07f2 100644 --- a/nodes/checkpoint_cloudguard/checkpoint_cloudguard.go +++ b/nodes/checkpoint_cloudguard/checkpoint_cloudguard.go @@ -66,5 +66,5 @@ func (n *CheckpointCloudguard) PreDeploy(_ context.Context, params *nodes.PreDep // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. func (n *CheckpointCloudguard) CheckInterfaceName() error { - return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Config().NetworkMode, n.Endpoints) } diff --git a/nodes/ipinfusion_ocnos/ipinfusion_ocnos.go b/nodes/ipinfusion_ocnos/ipinfusion_ocnos.go index b02a30fa8..3ba59ca69 100644 --- a/nodes/ipinfusion_ocnos/ipinfusion_ocnos.go +++ b/nodes/ipinfusion_ocnos/ipinfusion_ocnos.go @@ -86,5 +86,5 @@ func (n *IPInfusionOcNOS) SaveConfig(_ context.Context) error { // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. func (n *IPInfusionOcNOS) CheckInterfaceName() error { - return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Config().NetworkMode, n.Endpoints) } diff --git a/nodes/node.go b/nodes/node.go index d6fc74e83..dc5e033d0 100644 --- a/nodes/node.go +++ b/nodes/node.go @@ -129,12 +129,20 @@ func WithRuntime(r runtime.ContainerRuntime) NodeOption { } // GenericVMInterfaceCheck checks interface names for generic VM-based nodes. -// These nodes could only have interfaces named ethX, where X is >0. -func GenericVMInterfaceCheck(nodeName string, eps []links.Endpoint) error { - ifRe := regexp.MustCompile(`eth[1-9][0-9]*$`) +// These nodes could only have interfaces named ethX, where X is >0 +// unless network mode is set to 'none' in which case any interface name is allowed. +func GenericVMInterfaceCheck(nodeName, netMode string, eps []links.Endpoint) error { + pattern := `eth[1-9][0-9]*$` + + if netMode == "none" { + pattern = `.*` + } + + ifRe := regexp.MustCompile(pattern) + for _, e := range eps { if !ifRe.MatchString(e.GetIfaceName()) { - return fmt.Errorf("%q interface name %q doesn't match the required pattern. It should be named as ethX, where X is >0", nodeName, e.GetIfaceName()) + return fmt.Errorf("%q interface name %q doesn't match the required pattern: %s", nodeName, e.GetIfaceName(), pattern) } } diff --git a/nodes/srl/version.go b/nodes/srl/version.go index b30f82be1..8a88abdb9 100644 --- a/nodes/srl/version.go +++ b/nodes/srl/version.go @@ -42,7 +42,7 @@ func (n *srl) RunningVersion(ctx context.Context) (*SrlVersion, error) { return n.parseVersionString(execResult.GetStdOutString()), nil } -func (n *srl) parseVersionString(s string) *SrlVersion { +func (*srl) parseVersionString(s string) *SrlVersion { re, _ := regexp.Compile(`v(\d{1,3})\.(\d{1,2})\.(\d{1,3})\-(\d{1,4})\-(\S+)`) v := re.FindStringSubmatch(s) diff --git a/nodes/vr_aoscx/vr-aoscx.go b/nodes/vr_aoscx/vr-aoscx.go index 80131b43c..55cf8a865 100644 --- a/nodes/vr_aoscx/vr-aoscx.go +++ b/nodes/vr_aoscx/vr-aoscx.go @@ -76,5 +76,5 @@ func (n *vrAosCX) PreDeploy(_ context.Context, params *nodes.PreDeployParams) er // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. func (n *vrAosCX) CheckInterfaceName() error { - return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Config().NetworkMode, n.Endpoints) } diff --git a/nodes/vr_csr/vr-csr.go b/nodes/vr_csr/vr-csr.go index f6a00db21..a5174fc23 100644 --- a/nodes/vr_csr/vr-csr.go +++ b/nodes/vr_csr/vr-csr.go @@ -98,5 +98,5 @@ func (n *vrCsr) SaveConfig(_ context.Context) error { // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. func (n *vrCsr) CheckInterfaceName() error { - return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Config().NetworkMode, n.Endpoints) } diff --git a/nodes/vr_ftdv/vr-ftdv.go b/nodes/vr_ftdv/vr-ftdv.go index 823782b41..79c04bd79 100644 --- a/nodes/vr_ftdv/vr-ftdv.go +++ b/nodes/vr_ftdv/vr-ftdv.go @@ -71,5 +71,5 @@ func (n *vrFtdv) PreDeploy(_ context.Context, params *nodes.PreDeployParams) err // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. func (n *vrFtdv) CheckInterfaceName() error { - return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Config().NetworkMode, n.Endpoints) } diff --git a/nodes/vr_ftosv/vr-ftosv.go b/nodes/vr_ftosv/vr-ftosv.go index 21f586aeb..8323f195d 100644 --- a/nodes/vr_ftosv/vr-ftosv.go +++ b/nodes/vr_ftosv/vr-ftosv.go @@ -80,5 +80,5 @@ func (n *vrFtosv) PreDeploy(_ context.Context, params *nodes.PreDeployParams) er // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. func (n *vrFtosv) CheckInterfaceName() error { - return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Config().NetworkMode, n.Endpoints) } diff --git a/nodes/vr_n9kv/vr-n9kv.go b/nodes/vr_n9kv/vr-n9kv.go index a229526d5..6ac7f7b2c 100644 --- a/nodes/vr_n9kv/vr-n9kv.go +++ b/nodes/vr_n9kv/vr-n9kv.go @@ -81,5 +81,5 @@ func (n *vrN9kv) PreDeploy(_ context.Context, params *nodes.PreDeployParams) err // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. func (n *vrN9kv) CheckInterfaceName() error { - return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Config().NetworkMode, n.Endpoints) } diff --git a/nodes/vr_openbsd/vr-openbsd.go b/nodes/vr_openbsd/vr-openbsd.go index f3861b791..fa338435a 100644 --- a/nodes/vr_openbsd/vr-openbsd.go +++ b/nodes/vr_openbsd/vr-openbsd.go @@ -100,5 +100,5 @@ func (n *vrOpenBSD) SaveConfig(ctx context.Context) error { // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. func (n *vrOpenBSD) CheckInterfaceName() error { - return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Config().NetworkMode, n.Endpoints) } diff --git a/nodes/vr_pan/vr-pan.go b/nodes/vr_pan/vr-pan.go index aab613a5c..a570c714d 100644 --- a/nodes/vr_pan/vr-pan.go +++ b/nodes/vr_pan/vr-pan.go @@ -82,5 +82,5 @@ func (n *vrPan) PreDeploy(_ context.Context, params *nodes.PreDeployParams) erro // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. func (n *vrPan) CheckInterfaceName() error { - return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Config().NetworkMode, n.Endpoints) } diff --git a/nodes/vr_ros/vr-ros.go b/nodes/vr_ros/vr-ros.go index 800c7794e..6d54665d9 100644 --- a/nodes/vr_ros/vr-ros.go +++ b/nodes/vr_ros/vr-ros.go @@ -78,5 +78,5 @@ func (n *vrRos) PreDeploy(_ context.Context, params *nodes.PreDeployParams) erro // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. func (n *vrRos) CheckInterfaceName() error { - return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Config().NetworkMode, n.Endpoints) } diff --git a/nodes/vr_sros/vr-sros.go b/nodes/vr_sros/vr-sros.go index 77e42727a..231c5c2c6 100644 --- a/nodes/vr_sros/vr-sros.go +++ b/nodes/vr_sros/vr-sros.go @@ -62,42 +62,42 @@ type vrSROS struct { sshPubKeys []ssh.PublicKey } -func (s *vrSROS) Init(cfg *types.NodeConfig, opts ...nodes.NodeOption) error { +func (n *vrSROS) Init(cfg *types.NodeConfig, opts ...nodes.NodeOption) error { // Init DefaultNode - s.DefaultNode = *nodes.NewDefaultNode(s) + n.DefaultNode = *nodes.NewDefaultNode(n) // set virtualization requirement - s.HostRequirements.VirtRequired = true - s.LicensePolicy = types.LicensePolicyWarn + n.HostRequirements.VirtRequired = true + n.LicensePolicy = types.LicensePolicyWarn // SR OS requires unbound pubkey authentication mode until this is // gets fixed in later SR OS relase. - s.SSHConfig.PubkeyAuthentication = types.PubkeyAuthValueUnbound + n.SSHConfig.PubkeyAuthentication = types.PubkeyAuthValueUnbound - s.Cfg = cfg + n.Cfg = cfg for _, o := range opts { - o(s) + o(n) } // vr-sros type sets the vrnetlab/sros variant (https://github.com/hellt/vrnetlab/sros) - if s.Cfg.NodeType == "" { - s.Cfg.NodeType = vrsrosDefaultType + if n.Cfg.NodeType == "" { + n.Cfg.NodeType = vrsrosDefaultType } // env vars are used to set launch.py arguments in vrnetlab container defEnv := map[string]string{ "CONNECTION_MODE": nodes.VrDefConnMode, - "DOCKER_NET_V4_ADDR": s.Mgmt.IPv4Subnet, - "DOCKER_NET_V6_ADDR": s.Mgmt.IPv6Subnet, + "DOCKER_NET_V4_ADDR": n.Mgmt.IPv4Subnet, + "DOCKER_NET_V6_ADDR": n.Mgmt.IPv6Subnet, } - s.Cfg.Env = utils.MergeStringMaps(defEnv, s.Cfg.Env) + n.Cfg.Env = utils.MergeStringMaps(defEnv, n.Cfg.Env) // mount tftpboot dir - s.Cfg.Binds = append(s.Cfg.Binds, fmt.Sprint(path.Join(s.Cfg.LabDir, "tftpboot"), ":/tftpboot")) - if s.Cfg.Env["CONNECTION_MODE"] == "macvtap" { + n.Cfg.Binds = append(n.Cfg.Binds, fmt.Sprint(path.Join(n.Cfg.LabDir, "tftpboot"), ":/tftpboot")) + if n.Cfg.Env["CONNECTION_MODE"] == "macvtap" { // mount dev dir to enable macvtap - s.Cfg.Binds = append(s.Cfg.Binds, "/dev:/dev") + n.Cfg.Binds = append(n.Cfg.Binds, "/dev:/dev") } - s.Cfg.Cmd = fmt.Sprintf("--trace --connection-mode %s --hostname %s --variant \"%s\"", s.Cfg.Env["CONNECTION_MODE"], - s.Cfg.ShortName, - s.Cfg.NodeType, + n.Cfg.Cmd = fmt.Sprintf("--trace --connection-mode %s --hostname %s --variant \"%s\"", n.Cfg.Env["CONNECTION_MODE"], + n.Cfg.ShortName, + n.Cfg.NodeType, ) return nil @@ -169,13 +169,20 @@ func (s *vrSROS) SaveConfig(_ context.Context) error { } // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. -func (s *vrSROS) CheckInterfaceName() error { +func (n *vrSROS) CheckInterfaceName() error { // vsim doesn't seem to support >20 interfaces, yet we allow to set max if number 32 just in case. // https://regex101.com/r/bx6kzM/1 - ifRe := regexp.MustCompile(`eth([1-9]|[12][0-9]|3[0-2])$`) - for _, e := range s.Endpoints { + pattern := `eth([1-9]|[12][0-9]|3[0-2])$` + + if n.Config().NetworkMode == "none" { + pattern = `eth([0-9]|[12][0-9]|3[0-2])$` + } + + ifRe := regexp.MustCompile(pattern) + + for _, e := range n.Endpoints { if !ifRe.MatchString(e.GetIfaceName()) { - return fmt.Errorf("nokia SR OS interface name %q doesn't match the required pattern. SR OS interfaces should be named as ethX, where X is from 1 to 32", e.GetIfaceName()) + return fmt.Errorf("nokia SR OS interface name %q doesn't match the required pattern %s. SR OS interfaces should be named as ethX, where X is <= 32", e.GetIfaceName(), pattern) } } diff --git a/nodes/vr_veos/vr-veos.go b/nodes/vr_veos/vr-veos.go index 86df216dc..95aac6005 100644 --- a/nodes/vr_veos/vr-veos.go +++ b/nodes/vr_veos/vr-veos.go @@ -100,5 +100,5 @@ func (n *vrVEOS) SaveConfig(_ context.Context) error { // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. func (n *vrVEOS) CheckInterfaceName() error { - return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Config().NetworkMode, n.Endpoints) } diff --git a/nodes/vr_vjunosevolved/vr-vjunosevolved.go b/nodes/vr_vjunosevolved/vr-vjunosevolved.go index f5612905f..3451342eb 100644 --- a/nodes/vr_vjunosevolved/vr-vjunosevolved.go +++ b/nodes/vr_vjunosevolved/vr-vjunosevolved.go @@ -98,5 +98,5 @@ func (n *vrVJUNOSEVOLVED) SaveConfig(_ context.Context) error { // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. func (n *vrVJUNOSEVOLVED) CheckInterfaceName() error { - return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Config().NetworkMode, n.Endpoints) } diff --git a/nodes/vr_vjunosswitch/vr-vjunosswitch.go b/nodes/vr_vjunosswitch/vr-vjunosswitch.go index 4c9435182..fa7d16037 100644 --- a/nodes/vr_vjunosswitch/vr-vjunosswitch.go +++ b/nodes/vr_vjunosswitch/vr-vjunosswitch.go @@ -98,5 +98,5 @@ func (n *vrVJUNOSSWITCH) SaveConfig(_ context.Context) error { // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. func (n *vrVJUNOSSWITCH) CheckInterfaceName() error { - return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Config().NetworkMode, n.Endpoints) } diff --git a/nodes/vr_vmx/vr-vmx.go b/nodes/vr_vmx/vr-vmx.go index 622b1a7cb..fceeff295 100644 --- a/nodes/vr_vmx/vr-vmx.go +++ b/nodes/vr_vmx/vr-vmx.go @@ -93,5 +93,5 @@ func (n *vrVMX) SaveConfig(_ context.Context) error { // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. func (n *vrVMX) CheckInterfaceName() error { - return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Config().NetworkMode, n.Endpoints) } diff --git a/nodes/vr_vqfx/vr-vqfx.go b/nodes/vr_vqfx/vr-vqfx.go index b02de9c1f..6c9d6243f 100644 --- a/nodes/vr_vqfx/vr-vqfx.go +++ b/nodes/vr_vqfx/vr-vqfx.go @@ -98,5 +98,5 @@ func (n *vrVQFX) SaveConfig(_ context.Context) error { // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. func (n *vrVQFX) CheckInterfaceName() error { - return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Config().NetworkMode, n.Endpoints) } diff --git a/nodes/vr_vsrx/vr-vsrx.go b/nodes/vr_vsrx/vr-vsrx.go index 8edd507c2..bf0b17874 100644 --- a/nodes/vr_vsrx/vr-vsrx.go +++ b/nodes/vr_vsrx/vr-vsrx.go @@ -98,5 +98,5 @@ func (n *vrVSRX) SaveConfig(_ context.Context) error { // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. func (n *vrVSRX) CheckInterfaceName() error { - return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Config().NetworkMode, n.Endpoints) } diff --git a/nodes/vr_xrv/vr-xrv.go b/nodes/vr_xrv/vr-xrv.go index 28acbce08..9dd31aef0 100644 --- a/nodes/vr_xrv/vr-xrv.go +++ b/nodes/vr_xrv/vr-xrv.go @@ -98,5 +98,5 @@ func (n *vrXRV) SaveConfig(_ context.Context) error { // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. func (n *vrXRV) CheckInterfaceName() error { - return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Config().NetworkMode, n.Endpoints) } diff --git a/nodes/vr_xrv9k/vr-xrv9k.go b/nodes/vr_xrv9k/vr-xrv9k.go index 3208bd72b..3ab2326f3 100644 --- a/nodes/vr_xrv9k/vr-xrv9k.go +++ b/nodes/vr_xrv9k/vr-xrv9k.go @@ -101,5 +101,5 @@ func (n *vrXRV9K) SaveConfig(_ context.Context) error { // CheckInterfaceName checks if a name of the interface referenced in the topology file correct. func (n *vrXRV9K) CheckInterfaceName() error { - return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Endpoints) + return nodes.GenericVMInterfaceCheck(n.Cfg.ShortName, n.Config().NetworkMode, n.Endpoints) } diff --git a/tests/01-smoke/01-basic-flow.robot b/tests/01-smoke/01-basic-flow.robot index 8a8317cce..569498a03 100644 --- a/tests/01-smoke/01-basic-flow.robot +++ b/tests/01-smoke/01-basic-flow.robot @@ -83,20 +83,20 @@ Exec command with json output and filtering Ensure CLAB_INTFS env var is set [Documentation] - ... This test ensures that the CLAB_INTFS environment variable is set in the container - ... and that it contains the correct number of interfaces. + ... This test ensures that the CLAB_INTFS and CLAB_INTFS_WITH_MGMT environment variables are set in the container + ... and that it contains the correct number of interfaces ${output} = Process.Run Process - ... sudo -E ${CLAB_BIN} --runtime ${runtime} exec -t ${CURDIR}/${lab-file} --label clab-node-name\=l1 --cmd 'ash -c "echo $CLAB_INTFS"' + ... sudo -E ${CLAB_BIN} --runtime ${runtime} exec -t ${CURDIR}/${lab-file} --label clab-node-name\=l1 --cmd 'ash -c "echo $CLAB_INTFS $CLAB_INTFS_WITH_MGMT"' ... shell=True Log ${output.stdout} Log ${output.stderr} Should Be Equal As Integers ${output.rc} 0 # l1 node has 3 interfaces defined in the lab topology - # log outputs to stderr, and thus we check for 3 interfaces there + # log outputs to stderr, and thus we check for 3 and 4 interfaces there # may be worth to change this to stdout in the future # we literally check if the string stdout:\n3 is present in the output, as this is how # the result is printed today. - Should Contain ${output.stderr} stdout:\\n3 + Should Contain ${output.stderr} stdout:\\n3 4 Inspect ${lab-name} lab ${rc} ${output} = Run And Return Rc And Output diff --git a/types/constants.go b/types/constants.go index 093032593..7b28ef20c 100644 --- a/types/constants.go +++ b/types/constants.go @@ -1,6 +1,14 @@ package types const ( - // env var containing the expected number of interfaces injected into every container. + // env var containing the expected number of interfaces injected into every container + // without added management interface. + // two different env vars are injected to support the smooth phasing out + // of the old images built with vrnetlab that still use CLAB_INTFS CLAB_ENV_INTFS = "CLAB_INTFS" + // env var containing the expected number of interfaces injected into every container + // with added management interface. + // this env var is used with newer vrnetlab images (>=0.15.0) that support + // network-mode:none feature and rely on this env var instead of CLAB_INTFS + CLAB_ENV_INTFS_WITH_MGMT = "CLAB_INTFS_WITH_MGMT" ) diff --git a/types/types.go b/types/types.go index b85ca841e..95e6141e0 100644 --- a/types/types.go +++ b/types/types.go @@ -143,7 +143,9 @@ type NodeConfig struct { // PortSet define the ports that should be exposed on a container PortSet nat.PortSet `json:"portset,omitempty"` // NetworkMode defines container networking mode. - // If set to `host` the host networking will be used for this node, else bridged network + // If set to `host` the host networking will be used for this node, + // if set to `none` then container runtime doesn't manage the eth0 interface at all + // else bridged network NetworkMode string `json:"networkmode,omitempty"` // MgmtNet is the name of the docker network this node is connected to with its first interface MgmtNet string `json:"mgmt-net,omitempty"` diff --git a/utils/if-wait.go b/utils/if-wait.go index 6a66e46c6..b975663eb 100644 --- a/utils/if-wait.go +++ b/utils/if-wait.go @@ -1,30 +1,9 @@ package utils +import _ "embed" + // IfWaitScript is used in ENTRYPOINT/CMD of the nodes that need to ensure that all // of the clab links/interfaces are available in the container before calling the main process. -var IfWaitScript string = `#!/bin/sh - -INTFS=$(echo $CLAB_INTFS) -SLEEP=0 - -int_calc () -{ - index=0 - for i in $(ls -1v /sys/class/net/ | grep -E '^et|^ens|^eno|^e[0-9]'); do - let index=index+1 - done - MYINT=$index -} - -int_calc - -echo "Waiting for all $INTFS interfaces to be connected" -while [ "$MYINT" -lt "$INTFS" ]; do - echo "Connected $MYINT interfaces out of $INTFS" - sleep 1 - int_calc -done - -echo "Sleeping $SLEEP seconds before boot" -sleep $SLEEP -` +// +//go:embed if-wait.sh +var IfWaitScript string diff --git a/utils/if-wait.sh b/utils/if-wait.sh new file mode 100755 index 000000000..c005c9bf2 --- /dev/null +++ b/utils/if-wait.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +SLEEP=0 + +int_calc() { + # Count the number of interfaces that are up matching the pattern + # the pattern is a regex that matches the interface + # et - matches et and eth + # e[0-9] - matches srlinux e1* interfaces + MYINT=$(ls -1 /sys/class/net/ | grep -E '^et|^ens|^eno|^e[0-9]' | wc -l) +} + +int_calc + +echo "Waiting for all $CLAB_INTFS_WITH_MGMT interfaces to be connected" +while [ "$MYINT" -lt "$CLAB_INTFS_WITH_MGMT" ]; do + echo "Connected $MYINT interfaces out of $CLAB_INTFS_WITH_MGMT" + sleep 1 + int_calc +done + +echo "Sleeping $SLEEP seconds before boot" +sleep $SLEEP