Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added centralized magic var replacer and support replacer for execs #2395

Merged
merged 1 commit into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 28 additions & 5 deletions clab/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ func (c *CLab) createNodeCfg(nodeName string, nodeDef *types.NodeDefinition, idx
if err != nil {
return nil, err
}
err = c.resolveBindPaths(binds, c.TopoPaths.NodeDir(nodeName))
err = c.resolveBindPaths(binds, nodeName)
if err != nil {
return nil, err
}
Expand All @@ -253,6 +253,8 @@ func (c *CLab) createNodeCfg(nodeName string, nodeDef *types.NodeDefinition, idx

nodeCfg.Config = c.Config.Topology.GetNodeConfigDispatcher(nodeCfg.ShortName)

c.processNodeExecs(nodeCfg)

return nodeCfg, nil
}

Expand All @@ -261,7 +263,7 @@ func (c *CLab) createNodeCfg(nodeName string, nodeDef *types.NodeDefinition, idx
// Returns an absolute path to the startup-config file.
func (c *CLab) processStartupConfig(nodeCfg *types.NodeConfig) error {
// replace __clabNodeName__ magic var in startup-config path with node short name
r := strings.NewReplacer(nodeNameVar, nodeCfg.ShortName)
r := c.magicVarReplacer(nodeCfg.ShortName)
p := r.Replace(c.Config.Topology.GetNodeStartupConfig(nodeCfg.ShortName))

// embedded config is a config that is defined as a multi-line string in the topology file
Expand Down Expand Up @@ -498,7 +500,7 @@ func (c *CLab) verifyContainersUniqueness(ctx context.Context) error {
// it allows host path to have `~` and relative path to an absolute path
// the list of binds will be changed in place.
// if the host path doesn't exist, the error will be returned.
func (c *CLab) resolveBindPaths(binds []string, nodeDir string) error {
func (c *CLab) resolveBindPaths(binds []string, nodeName string) error {
// checks are skipped when, for example, the destroy operation is run
if !c.checkBindsPaths {
return nil
Expand All @@ -513,8 +515,8 @@ func (c *CLab) resolveBindPaths(binds []string, nodeDir string) error {
// volume, in this case we don't need to resolve the path
continue
}
// replace special variable
r := strings.NewReplacer(clabDirVar, c.TopoPaths.TopologyLabDir(), nodeDirVar, nodeDir)
// replace special variables
r := c.magicVarReplacer(nodeName)
hp := r.Replace(elems[0])
hp = utils.ResolvePath(hp, c.TopoPaths.TopologyFileDir())

Expand Down Expand Up @@ -649,3 +651,24 @@ func addEnvVarsToNodeCfg(c *CLab, nodeCfg *types.NodeConfig) error {

return nil
}

// processNodeExecs replaces (in place) magic variables in node execs.
func (c *CLab) processNodeExecs(nodeCfg *types.NodeConfig) {
for i, e := range nodeCfg.Exec {
r := c.magicVarReplacer(nodeCfg.ShortName)
nodeCfg.Exec[i] = r.Replace(e)
}
}

// magicVarReplacer returns a string replacer that replaces all supported magic variables.
func (c *CLab) magicVarReplacer(nodeName string) *strings.Replacer {
if nodeName == "" {
return &strings.Replacer{}
}

return strings.NewReplacer(
clabDirVar, c.TopoPaths.TopologyLabDir(),
nodeDirVar, c.TopoPaths.NodeDir(nodeName),
nodeNameVar, nodeName,
)
}
35 changes: 34 additions & 1 deletion clab/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func TestBindsInit(t *testing.T) {
want: []string{
"node1.lic:/dst1",
"kind.lic:/dst2",
"${PWD}/test_data/clab-topo2/node1/somefile:/somefile",
"${PWD}/test_data/clab-topo2/node1/node1:/somefile",
},
},
"kind_and_node_binds": {
Expand Down Expand Up @@ -738,3 +738,36 @@ func TestStartupConfigInit(t *testing.T) {
})
}
}

func TestExecInit(t *testing.T) {
tests := map[string]struct {
got string
node string
want []string
}{
"node_exec": {
got: "test_data/topo14.yml",
node: "node1",
want: []string{
"echo \"Hello world\"",
"echo \"Hello node node1\"",
},
},
}

for name, tc := range tests {
t.Run(name, func(t *testing.T) {
opts := []ClabOption{
WithTopoPath(tc.got, ""),
}
c, err := NewContainerLab(opts...)
if err != nil {
t.Error(err)
}

if d := cmp.Diff(c.Nodes[tc.node].Config().Exec, tc.want); d != "" {
t.Errorf("execs do not match %s", d)
}
})
}
}
3 changes: 3 additions & 0 deletions clab/test_data/topo14.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ topology:
node1:
kind: nokia_srlinux
startup-config: ./configs/fabric/__clabNodeName__.cfg
exec:
- echo "Hello world"
- echo "Hello node __clabNodeName__"
2 changes: 1 addition & 1 deletion clab/test_data/topo2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ topology:
binds:
- node1.lic:/dst1
- kind.lic:/dst2
- __clabNodeDir__/somefile:/somefile
- __clabNodeDir__/__clabNodeName__:/somefile
node2:
kind: nokia_srlinux
type: ixr10
Loading