From fe7c5860cd0be697b57dab02699018470f5f0487 Mon Sep 17 00:00:00 2001 From: toweber <> Date: Tue, 17 Dec 2024 15:54:00 +0100 Subject: [PATCH 1/8] adding no_proxy env variable by default to each clab node --- clab/config.go | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/clab/config.go b/clab/config.go index 04e62160f..e6abc8e10 100644 --- a/clab/config.go +++ b/clab/config.go @@ -220,6 +220,53 @@ func (c *CLab) createNodeCfg(nodeName string, nodeDef *types.NodeDefinition, idx // Merge EnvVarFiles content and the existing env variable nodeCfg.Env = utils.MergeStringMaps(envFileContent, nodeCfg.Env) + // Default set of no_proxy entries + noProxyDefaults := []string{"localhost", "127.0.0.1", "::1", "*.local"} + + // check if either of the no_proxy variables exists + noProxyLower, existsLower := nodeCfg.Env["no_proxy"] + noProxyUpper, existsUpper := nodeCfg.Env["NO_PROXY"] + noProxy := "" + if existsLower { + noProxy = noProxyLower + for _, defaultValue := range noProxyDefaults { + if !strings.Contains(noProxy, defaultValue) { + noProxy=noProxy + "," + defaultValue + } + } + } else if existsUpper { + noProxy = noProxyUpper + for _, defaultValue := range noProxyDefaults { + if !strings.Contains(noProxy, defaultValue) { + noProxy=noProxy + "," + defaultValue + } + } + } else { + noProxy = strings.Join(noProxyDefaults, ",") + } + + // add all clab nodes to the no_proxy variable, if they have a static IP assigned, add this as well + var noProxyList []string + for key := range c.Config.Topology.Nodes { + noProxyList = append(noProxyList, key) + ipv4address := c.Config.Topology.Nodes[key].GetMgmtIPv4() + if ipv4address != "" { + noProxyList = append(noProxyList, ipv4address) + } + ipv6address := c.Config.Topology.Nodes[key].GetMgmtIPv6() + if ipv6address != "" { + noProxyList = append(noProxyList, ipv6address) + } + } + + // sort for better readability + sort.Strings(noProxyList) + + noProxy = noProxy + "," + strings.Join(noProxyList, ",") + + nodeCfg.Env["no_proxy"] = noProxy + nodeCfg.Env["NO_PROXY"] = noProxy + log.Debugf("node config: %+v", nodeCfg) // process startup-config From 2f9bab293a8405bdea2692d9325eed4c69e778cb Mon Sep 17 00:00:00 2001 From: toweber <> Date: Tue, 17 Dec 2024 15:31:08 +0100 Subject: [PATCH 2/8] formatting --- clab/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clab/config.go b/clab/config.go index e6abc8e10..331cfd0a0 100644 --- a/clab/config.go +++ b/clab/config.go @@ -264,7 +264,7 @@ func (c *CLab) createNodeCfg(nodeName string, nodeDef *types.NodeDefinition, idx noProxy = noProxy + "," + strings.Join(noProxyList, ",") - nodeCfg.Env["no_proxy"] = noProxy + nodeCfg.Env["no_proxy"] = noProxy nodeCfg.Env["NO_PROXY"] = noProxy log.Debugf("node config: %+v", nodeCfg) From 5d7a8701ae0c13c26685272cda85654b528f3522 Mon Sep 17 00:00:00 2001 From: toweber <> Date: Thu, 19 Dec 2024 15:09:11 +0100 Subject: [PATCH 3/8] Add mgmt subnet range to no_proxy var --- clab/config.go | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/clab/config.go b/clab/config.go index 331cfd0a0..799d252c4 100644 --- a/clab/config.go +++ b/clab/config.go @@ -227,14 +227,14 @@ func (c *CLab) createNodeCfg(nodeName string, nodeDef *types.NodeDefinition, idx noProxyLower, existsLower := nodeCfg.Env["no_proxy"] noProxyUpper, existsUpper := nodeCfg.Env["NO_PROXY"] noProxy := "" - if existsLower { + if existsLower { noProxy = noProxyLower - for _, defaultValue := range noProxyDefaults { + for _, defaultValue := range noProxyDefaults { if !strings.Contains(noProxy, defaultValue) { noProxy=noProxy + "," + defaultValue } } - } else if existsUpper { + } else if existsUpper { noProxy = noProxyUpper for _, defaultValue := range noProxyDefaults { if !strings.Contains(noProxy, defaultValue) { @@ -247,9 +247,9 @@ func (c *CLab) createNodeCfg(nodeName string, nodeDef *types.NodeDefinition, idx // add all clab nodes to the no_proxy variable, if they have a static IP assigned, add this as well var noProxyList []string - for key := range c.Config.Topology.Nodes { - noProxyList = append(noProxyList, key) - ipv4address := c.Config.Topology.Nodes[key].GetMgmtIPv4() + for key := range c.Config.Topology.Nodes { + noProxyList = append(noProxyList, key) + ipv4address := c.Config.Topology.Nodes[key].GetMgmtIPv4() if ipv4address != "" { noProxyList = append(noProxyList, ipv4address) } @@ -257,7 +257,11 @@ func (c *CLab) createNodeCfg(nodeName string, nodeDef *types.NodeDefinition, idx if ipv6address != "" { noProxyList = append(noProxyList, ipv6address) } - } + } + + // add mgmt subnet range for the sake of completeness - some OS support it, others don't + noProxyList = append(noProxyList, c.Config.Mgmt.IPv4Subnet) + noProxyList = append(noProxyList, c.Config.Mgmt.IPv6Subnet) // sort for better readability sort.Strings(noProxyList) From e8f98e8b8f868c783709290501fb9cafc2c3d7eb Mon Sep 17 00:00:00 2001 From: toweber <> Date: Thu, 19 Dec 2024 15:31:11 +0100 Subject: [PATCH 4/8] Add mgmt subnet to no_proxy if not empty --- clab/config.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/clab/config.go b/clab/config.go index 799d252c4..6a883c841 100644 --- a/clab/config.go +++ b/clab/config.go @@ -260,8 +260,12 @@ func (c *CLab) createNodeCfg(nodeName string, nodeDef *types.NodeDefinition, idx } // add mgmt subnet range for the sake of completeness - some OS support it, others don't - noProxyList = append(noProxyList, c.Config.Mgmt.IPv4Subnet) - noProxyList = append(noProxyList, c.Config.Mgmt.IPv6Subnet) + if c.Config.Mgmt.IPv4Subnet != "" { + noProxyList = append(noProxyList, c.Config.Mgmt.IPv4Subnet) + } + if c.Config.Mgmt.IPv6Subnet != "" { + noProxyList = append(noProxyList, c.Config.Mgmt.IPv6Subnet) + } // sort for better readability sort.Strings(noProxyList) From c5f3249a5f1a4d711962c0d23172c7daac998b6b Mon Sep 17 00:00:00 2001 From: Roman Dodin Date: Thu, 19 Dec 2024 16:15:01 +0100 Subject: [PATCH 5/8] make format --- clab/config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clab/config.go b/clab/config.go index 6a883c841..15d23f435 100644 --- a/clab/config.go +++ b/clab/config.go @@ -231,14 +231,14 @@ func (c *CLab) createNodeCfg(nodeName string, nodeDef *types.NodeDefinition, idx noProxy = noProxyLower for _, defaultValue := range noProxyDefaults { if !strings.Contains(noProxy, defaultValue) { - noProxy=noProxy + "," + defaultValue + noProxy = noProxy + "," + defaultValue } } } else if existsUpper { noProxy = noProxyUpper for _, defaultValue := range noProxyDefaults { if !strings.Contains(noProxy, defaultValue) { - noProxy=noProxy + "," + defaultValue + noProxy = noProxy + "," + defaultValue } } } else { From ad13123bdb8a8540950fab43de3baaecd91e2034 Mon Sep 17 00:00:00 2001 From: Roman Dodin Date: Fri, 20 Dec 2024 21:26:07 +0100 Subject: [PATCH 6/8] move to a func and add a test --- clab/config.go | 131 ++++++++++++++++------------- tests/01-smoke/01-basic-flow.robot | 13 +++ 2 files changed, 84 insertions(+), 60 deletions(-) diff --git a/clab/config.go b/clab/config.go index 15d23f435..6116b320c 100644 --- a/clab/config.go +++ b/clab/config.go @@ -211,69 +211,11 @@ func (c *CLab) createNodeCfg(nodeName string, nodeDef *types.NodeDefinition, idx return nil, err } - // Load content of the EnvVarFiles - envFileContent, err := utils.LoadEnvVarFiles(c.TopoPaths.TopologyFileDir(), - c.Config.Topology.GetNodeEnvFiles(nodeName)) + // load environment variables + err = addEnvVarsToNodeCfg(c, nodeCfg) if err != nil { return nil, err } - // Merge EnvVarFiles content and the existing env variable - nodeCfg.Env = utils.MergeStringMaps(envFileContent, nodeCfg.Env) - - // Default set of no_proxy entries - noProxyDefaults := []string{"localhost", "127.0.0.1", "::1", "*.local"} - - // check if either of the no_proxy variables exists - noProxyLower, existsLower := nodeCfg.Env["no_proxy"] - noProxyUpper, existsUpper := nodeCfg.Env["NO_PROXY"] - noProxy := "" - if existsLower { - noProxy = noProxyLower - for _, defaultValue := range noProxyDefaults { - if !strings.Contains(noProxy, defaultValue) { - noProxy = noProxy + "," + defaultValue - } - } - } else if existsUpper { - noProxy = noProxyUpper - for _, defaultValue := range noProxyDefaults { - if !strings.Contains(noProxy, defaultValue) { - noProxy = noProxy + "," + defaultValue - } - } - } else { - noProxy = strings.Join(noProxyDefaults, ",") - } - - // add all clab nodes to the no_proxy variable, if they have a static IP assigned, add this as well - var noProxyList []string - for key := range c.Config.Topology.Nodes { - noProxyList = append(noProxyList, key) - ipv4address := c.Config.Topology.Nodes[key].GetMgmtIPv4() - if ipv4address != "" { - noProxyList = append(noProxyList, ipv4address) - } - ipv6address := c.Config.Topology.Nodes[key].GetMgmtIPv6() - if ipv6address != "" { - noProxyList = append(noProxyList, ipv6address) - } - } - - // add mgmt subnet range for the sake of completeness - some OS support it, others don't - if c.Config.Mgmt.IPv4Subnet != "" { - noProxyList = append(noProxyList, c.Config.Mgmt.IPv4Subnet) - } - if c.Config.Mgmt.IPv6Subnet != "" { - noProxyList = append(noProxyList, c.Config.Mgmt.IPv6Subnet) - } - - // sort for better readability - sort.Strings(noProxyList) - - noProxy = noProxy + "," + strings.Join(noProxyList, ",") - - nodeCfg.Env["no_proxy"] = noProxy - nodeCfg.Env["NO_PROXY"] = noProxy log.Debugf("node config: %+v", nodeCfg) @@ -636,3 +578,72 @@ func labelsToEnvVars(n *types.NodeConfig) { n.Env["CLAB_LABEL_"+utils.ToEnvKey(k)] = v } } + +// addEnvVarsToNodeCfg adds env vars that come from different sources to node config struct +func addEnvVarsToNodeCfg(c *CLab, nodeCfg *types.NodeConfig) error { + // Load content of the EnvVarFiles + envFileContent, err := utils.LoadEnvVarFiles(c.TopoPaths.TopologyFileDir(), + c.Config.Topology.GetNodeEnvFiles(nodeCfg.ShortName)) + if err != nil { + return err + } + // Merge EnvVarFiles content and the existing env variable + nodeCfg.Env = utils.MergeStringMaps(envFileContent, nodeCfg.Env) + + // Default set of no_proxy entries + noProxyDefaults := []string{"localhost", "127.0.0.1", "::1", "*.local"} + + // check if either of the no_proxy variables exists + noProxyLower, existsLower := nodeCfg.Env["no_proxy"] + noProxyUpper, existsUpper := nodeCfg.Env["NO_PROXY"] + noProxy := "" + if existsLower { + noProxy = noProxyLower + for _, defaultValue := range noProxyDefaults { + if !strings.Contains(noProxy, defaultValue) { + noProxy = noProxy + "," + defaultValue + } + } + } else if existsUpper { + noProxy = noProxyUpper + for _, defaultValue := range noProxyDefaults { + if !strings.Contains(noProxy, defaultValue) { + noProxy = noProxy + "," + defaultValue + } + } + } else { + noProxy = strings.Join(noProxyDefaults, ",") + } + + // add all clab nodes to the no_proxy variable, if they have a static IP assigned, add this as well + var noProxyList []string + for key := range c.Config.Topology.Nodes { + noProxyList = append(noProxyList, key) + ipv4address := c.Config.Topology.Nodes[key].GetMgmtIPv4() + if ipv4address != "" { + noProxyList = append(noProxyList, ipv4address) + } + ipv6address := c.Config.Topology.Nodes[key].GetMgmtIPv6() + if ipv6address != "" { + noProxyList = append(noProxyList, ipv6address) + } + } + + // add mgmt subnet range for the sake of completeness - some OS support it, others don't + if c.Config.Mgmt.IPv4Subnet != "" { + noProxyList = append(noProxyList, c.Config.Mgmt.IPv4Subnet) + } + if c.Config.Mgmt.IPv6Subnet != "" { + noProxyList = append(noProxyList, c.Config.Mgmt.IPv6Subnet) + } + + // sort for better readability + sort.Strings(noProxyList) + + noProxy = noProxy + "," + strings.Join(noProxyList, ",") + + nodeCfg.Env["no_proxy"] = noProxy + nodeCfg.Env["NO_PROXY"] = noProxy + + return nil +} diff --git a/tests/01-smoke/01-basic-flow.robot b/tests/01-smoke/01-basic-flow.robot index eeccc2254..a52ca0508 100644 --- a/tests/01-smoke/01-basic-flow.robot +++ b/tests/01-smoke/01-basic-flow.robot @@ -98,6 +98,19 @@ Ensure CLAB_INTFS env var is set # the result is printed today. Should Contain ${output.stderr} stdout:\\n3 +Ensure default no_proxy env var is set + [Documentation] + ... This test ensures that the NO_PROXY env var is populated by clab automatically + ... with the relevant addresses and names + ${output} = Process.Run Process + ... sudo -E ${CLAB_BIN} --runtime ${runtime} exec -t ${CURDIR}/${lab-file} --label clab-node-name\=l1 --cmd 'ash -c "echo $NO_PROXY"' + ... shell=True + Log ${output.stdout} + Log ${output.stderr} + Should Be Equal As Integers ${output.rc} 0 + + Should Contain ${output.stderr} localhost,127.0.0.1,::1,*.local,172.20.20.100,172.20.20.99,3fff:172:20:20::100,3fff:172:20:20::99,l1,l2,l3 + Inspect ${lab-name} lab using its name ${rc} ${output} = Run And Return Rc And Output ... sudo -E ${CLAB_BIN} --runtime ${runtime} inspect --name ${lab-name} From fac4d4f8922a42d289596b899ed7b16c43dc7f1f Mon Sep 17 00:00:00 2001 From: Roman Dodin Date: Fri, 20 Dec 2024 21:44:32 +0100 Subject: [PATCH 7/8] fix contain condition --- tests/01-smoke/01-basic-flow.robot | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/01-smoke/01-basic-flow.robot b/tests/01-smoke/01-basic-flow.robot index a52ca0508..61ac8c263 100644 --- a/tests/01-smoke/01-basic-flow.robot +++ b/tests/01-smoke/01-basic-flow.robot @@ -18,6 +18,7 @@ ${n2-ipv4} 172.20.20.100/24 ${n2-ipv6} 3fff:172:20:20::100/64 ${table-delimit} │ + *** Test Cases *** Verify number of Hosts entries before deploy ${rc} ${output} = Run And Return Rc And Output @@ -109,7 +110,9 @@ Ensure default no_proxy env var is set Log ${output.stderr} Should Be Equal As Integers ${output.rc} 0 - Should Contain ${output.stderr} localhost,127.0.0.1,::1,*.local,172.20.20.100,172.20.20.99,3fff:172:20:20::100,3fff:172:20:20::99,l1,l2,l3 + Should Contain + ... ${output.stderr} + ... localhost,127.0.0.1,::1,*.local,172.20.20.0/24,172.20.20.100,172.20.20.99,3fff:172:20:20::/64,3fff:172:20:20::100,3fff:172:20:20::99,l1,l2,l3 Inspect ${lab-name} lab using its name ${rc} ${output} = Run And Return Rc And Output @@ -203,7 +206,7 @@ Ensure "inspect all" outputs IP addresses ... sudo -E ${CLAB_BIN} --runtime ${runtime} inspect --all Log ${output} Should Be Equal As Integers ${rc} 0 - + # get a 4th line from the bottom of the inspect cmd. # this relates to the l2 node ipv4 ${line} = String.Get Line ${output} -6 From e2c6551a1f4e08bcf06697c3783a381fc9257aa2 Mon Sep 17 00:00:00 2001 From: Roman Dodin Date: Fri, 20 Dec 2024 21:54:48 +0100 Subject: [PATCH 8/8] doc entry --- docs/manual/nodes.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/manual/nodes.md b/docs/manual/nodes.md index d1923c6fc..d85f425bc 100644 --- a/docs/manual/nodes.md +++ b/docs/manual/nodes.md @@ -345,6 +345,18 @@ topology: You can also specify a magic ENV VAR - `__IMPORT_ENVS: true` - which will import all environment variables defined in your shell to the relevant topology level. +/// admonition | `NO_PROXY` variable + type: subtle-note +If you use an http(s) proxy on your host, you typically set the `NO_PROXY` environment variable in your containers to ensure that when containers talk to one another, they don't send traffic through the proxy, as that would lead to broken communication. And setting those env vars is tedious. + +Containerlab automates this process by automatically setting `NO_PROXY`/`no_proxy` environment variables in the containerlab nodes with the values of: + +1. localhost,127.0.0.1,::1,*.local +2. management network range for v4 and v6 (e.g. `172.20.20.0/24`) +3. IPv4/IPv6 management addresses of the nodes of the lab +4. node names as stated in your topology file +/// + ### env-files To add environment variables defined in a file use the `env-files` property that can be defined at `defaults`, `kind` and `node` levels.