Repository: srl-labs/containerlab
Pull request #2500 (2025-03-03 01:22:31)

Bump github.com/klauspost/compress from 1.17.11 to 1.18.0
Bumps [github.com/klauspost/compress](https://github.com/klauspost/compress) from 1.17.11 to 1.18.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/klauspost/compress/releases">github.com/klauspost/compress's releases</a>.</em></p>
<blockquote>
<h2>v1.18.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Deprecate Go 1.21 and add 1.24 by <a href="https://github.com/klauspost"><code>@​klauspost</code></a> in <a href="https://redirect.github.com/klauspost/compress/pull/1055">klauspost/compress#1055</a></li>
<li>Add unsafe little endian loaders by <a href="https://github.com/klauspost"><code>@​klauspost</code></a> in <a href="https://redirect.github.com/klauspost/compress/pull/1036">klauspost/compress#1036</a></li>
<li>fix: check <code>r.err != nil</code> but return a nil value error <code>err</code> by <a href="https://github.com/alingse"><code>@​alingse</code></a> in <a href="https://redirect.github.com/klauspost/compress/pull/1028">klauspost/compress#1028</a></li>
<li>refactor: use built-in <code>min</code> function by <a href="https://github.com/Juneezee"><code>@​Juneezee</code></a> in <a href="https://redirect.github.com/klauspost/compress/pull/1038">klauspost/compress#1038</a></li>
<li>zstd: use <code>slices.Max</code> for max value in slice by <a href="https://github.com/Juneezee"><code>@​Juneezee</code></a> in <a href="https://redirect.github.com/klauspost/compress/pull/1041">klauspost/compress#1041</a></li>
<li>flate: Simplify L4-6 loading by <a href="https://github.com/klauspost"><code>@​klauspost</code></a> in <a href="https://redirect.github.com/klauspost/compress/pull/1043">klauspost/compress#1043</a></li>
<li>flate: Simplify matchlen (remove asm) by <a href="https://github.com/klauspost"><code>@​klauspost</code></a> in <a href="https://redirect.github.com/klauspost/compress/pull/1045">klauspost/compress#1045</a></li>
<li>s2: Add block decode fuzzer by <a href="https://github.com/klauspost"><code>@​klauspost</code></a> in <a href="https://redirect.github.com/klauspost/compress/pull/1044">klauspost/compress#1044</a></li>
<li>s2: Improve small block compression speed w/o asm by <a href="https://github.com/klauspost"><code>@​klauspost</code></a> in <a href="https://redirect.github.com/klauspost/compress/pull/1048">klauspost/compress#1048</a></li>
<li>flate: Fix matchlen L5+L6 by <a href="https://github.com/klauspost"><code>@​klauspost</code></a> in <a href="https://redirect.github.com/klauspost/compress/pull/1049">klauspost/compress#1049</a></li>
<li>flate: Cleanup &amp; reduce casts by <a href="https://github.com/klauspost"><code>@​klauspost</code></a> in <a href="https://redirect.github.com/klauspost/compress/pull/1050">klauspost/compress#1050</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/tcpdumppy"><code>@​tcpdumppy</code></a> made their first contribution in <a href="https://redirect.github.com/klauspost/compress/pull/1021">klauspost/compress#1021</a></li>
<li><a href="https://github.com/sam9291"><code>@​sam9291</code></a> made their first contribution in <a href="https://redirect.github.com/klauspost/compress/pull/1022">klauspost/compress#1022</a></li>
<li><a href="https://github.com/dezza"><code>@​dezza</code></a> made their first contribution in <a href="https://redirect.github.com/klauspost/compress/pull/1023">klauspost/compress#1023</a></li>
<li><a href="https://github.com/alingse"><code>@​alingse</code></a> made their first contribution in <a href="https://redirect.github.com/klauspost/compress/pull/1028">klauspost/compress#1028</a></li>
<li><a href="https://github.com/hyunsooda"><code>@​hyunsooda</code></a> made their first contribution in <a href="https://redirect.github.com/klauspost/compress/pull/1031">klauspost/compress#1031</a></li>
<li><a href="https://github.com/Juneezee"><code>@​Juneezee</code></a> made their first contribution in <a href="https://redirect.github.com/klauspost/compress/pull/1038">klauspost/compress#1038</a></li>
<li><a href="https://github.com/Bbulatov"><code>@​Bbulatov</code></a> made their first contribution in <a href="https://redirect.github.com/klauspost/compress/pull/1052">klauspost/compress#1052</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a href="https://github.com/klauspost/compress/compare/v1.17.11...v1.18.0">https://github.com/klauspost/compress/compare/v1.17.11...v1.18.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/klauspost/compress/commit/8e79dc4b98d4c5a09c62a2546b79c14edf7c3e38"><code>8e79dc4</code></a> Deprecate Go 1.21 and add 1.24 (<a href="https://redirect.github.com/klauspost/compress/issues/1055">#1055</a>)</li>
<li><a href="https://github.com/klauspost/compress/commit/df8e99c8d015080686afb9b70a88791dd16a97a6"><code>df8e99c</code></a> build(deps): bump the github-actions group with 2 updates (<a href="https://redirect.github.com/klauspost/compress/issues/1053">#1053</a>)</li>
<li><a href="https://github.com/klauspost/compress/commit/7787431d606fe7748391cb5009cee0cf966d1cd9"><code>7787431</code></a> zstd: fix unused debug code (<a href="https://redirect.github.com/klauspost/compress/issues/1052">#1052</a>)</li>
<li><a href="https://github.com/klauspost/compress/commit/0bf3ecbea777ec39f7919b47e464a046254e29a8"><code>0bf3ecb</code></a> flate: Cleanup &amp; reduce casts (<a href="https://redirect.github.com/klauspost/compress/issues/1050">#1050</a>)</li>
<li><a href="https://github.com/klauspost/compress/commit/e0f89a9638ea2c7d21d9de0044efde931959eabe"><code>e0f89a9</code></a> flate: Fix matchlen L5+L6 (<a href="https://redirect.github.com/klauspost/compress/issues/1049">#1049</a>)</li>
<li><a href="https://github.com/klauspost/compress/commit/c8a8470492769c69e56a348e5142734cab19664e"><code>c8a8470</code></a> s2: Improve small block compression speed w/o asm (<a href="https://redirect.github.com/klauspost/compress/issues/1048">#1048</a>)</li>
<li><a href="https://github.com/klauspost/compress/commit/b05b993abb0da411a09cff9387877a4026c38906"><code>b05b993</code></a> s2: Add block decode fuzzer (<a href="https://redirect.github.com/klauspost/compress/issues/1044">#1044</a>)</li>
<li><a href="https://github.com/klauspost/compress/commit/aafbabd27ac86586bf3d7458e4efe99476716623"><code>aafbabd</code></a> flate: Simplify matchlen (remove asm) (<a href="https://redirect.github.com/klauspost/compress/issues/1045">#1045</a>)</li>
<li><a href="https://github.com/klauspost/compress/commit/dbaa9c1172b66d27d918b0e82a014d97f5dea2e5"><code>dbaa9c1</code></a> flate: Simplify l4-6 loading (<a href="https://redirect.github.com/klauspost/compress/issues/1043">#1043</a>)</li>
<li><a href="https://github.com/klauspost/compress/commit/4fa2036c90af5117d4c79f9fa9872bdb16de613c"><code>4fa2036</code></a> Add unsafe little endian loaders (<a href="https://redirect.github.com/klauspost/compress/issues/1036">#1036</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/klauspost/compress/compare/v1.17.11...v1.18.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/klauspost/compress&package-manager=go_modules&previous-version=1.17.11&new-version=1.18.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>


Patch:
diff --git a/clab/exec/exec.go b/clab/exec/exec.go
index 52699524..7b578842 100644
--- a/clab/exec/exec.go
+++ b/clab/exec/exec.go
@@ -262,8 +262,8 @@ func (ec *ExecCollection) Log() {
 			default:
 				log.Info(
 					"Executed command",
-					"command", er.GetCmdString(),
 					"node", k,
+					"command", er.GetCmdString(),
 					"stdout", er.GetStdOutString(),
 				)
 			}
diff --git a/cmd/version/upgrade.go b/cmd/version/upgrade.go
index 867ba35b..ce09ff02 100644
--- a/cmd/version/upgrade.go
+++ b/cmd/version/upgrade.go
@@ -33,7 +33,7 @@ var upgradeCmd = &cobra.Command{
 			return fmt.Errorf("failed to download upgrade script: %w", err)
 		}
 
-		c := exec.Command("sudo", "bash", f.Name())
+		c := exec.Command("sudo", "-E", "bash", f.Name())
 		// pass the environment variables to the upgrade script
 		// so that GITHUB_TOKEN is available
 		c.Env = os.Environ()
@@ -51,8 +51,15 @@ var upgradeCmd = &cobra.Command{
 
 // downloadFile will download a file from a URL and write its content to a file.
 func downloadFile(url string, file *os.File) error {
+	// Create an HTTP client with specific transport
+	client := &http.Client{
+		Transport: &http.Transport{
+			Proxy: http.ProxyFromEnvironment,
+		},
+	}
+
 	// Get the data
-	resp, err := http.Get(url)
+	resp, err := client.Get(url)
 	if err != nil {
 		return err
 	}
diff --git a/docs/lab-examples/ixiacone-srl.md b/docs/lab-examples/ixiacone-srl.md
index 2a689432..19fd1ce4 100644
--- a/docs/lab-examples/ixiacone-srl.md
+++ b/docs/lab-examples/ixiacone-srl.md
@@ -5,7 +5,7 @@
 | **Resource requirements**[^1] | :fontawesome-solid-microchip: 2 <br/>:fontawesome-solid-memory: 2 GB                   |
 | **Topology file**             | [ixiacone-srl.clab.yaml][topofile]                                                     |
 | **Name**                      | ixiac01                                                                                |
-| **Version information**[^2]   | `containerlab:0.46.2`, `ixia-c-one:1.20.0-6`, `srlinux:23.10.1`, `docker-ce:20.10.2`   |
+| **Version information**[^2]   | `containerlab:0.46.2`, `ixia-c-one:1.24.0-4`, `srlinux:23.10.1`, `docker-ce:20.10.2`   |
 
 ## Description
 
diff --git a/go.mod b/go.mod
index 64af8c7b..3c510668 100644
--- a/go.mod
+++ b/go.mod
@@ -101,7 +101,7 @@ require (
 	github.com/moby/sys/userns v0.1.0 // indirect
 	github.com/morikuni/aec v1.0.0 // indirect
 	github.com/muesli/reflow v0.3.0 // indirect
-	github.com/muesli/termenv v0.15.3-0.20241212154518-8c990cd6cf4b // indirect
+	github.com/muesli/termenv v0.16.0 // indirect
 	github.com/oklog/ulid v1.3.1 // indirect
 	github.com/pelletier/go-toml v1.9.5 // indirect
 	github.com/pjbgf/sha1cd v0.3.2 // indirect
@@ -183,7 +183,7 @@ require (
 	github.com/josharian/native v1.1.0 // indirect
 	github.com/json-iterator/go v1.1.12 // indirect
 	github.com/kevinburke/ssh_config v1.2.0 // indirect
-	github.com/klauspost/compress v1.17.11
+	github.com/klauspost/compress v1.18.0
 	github.com/klauspost/pgzip v1.2.6 // indirect
 	github.com/manifoldco/promptui v0.9.0 // indirect
 	github.com/mattn/go-isatty v0.0.20 // indirect
diff --git a/go.sum b/go.sum
index b3719a11..c4908442 100644
--- a/go.sum
+++ b/go.sum
@@ -643,8 +643,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
 github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
 github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
-github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
-github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
+github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
+github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
 github.com/klauspost/cpuid v0.0.0-20180405133222-e7e905edc00e/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
 github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
 github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
@@ -781,8 +781,8 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P
 github.com/mozilla/tls-observatory v0.0.0-20190404164649-a3c1b6cfecfd/go.mod h1:SrKMQvPiws7F7iqYp8/TX+IhxCYhzr6N/1yb8cwHsGk=
 github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
 github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
-github.com/muesli/termenv v0.15.3-0.20241212154518-8c990cd6cf4b h1:gmVbquSG+bANneniKyO7R2DkOlCat7XDaSfXxHKKQBY=
-github.com/muesli/termenv v0.15.3-0.20241212154518-8c990cd6cf4b/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ=
+github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
+github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
 github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
diff --git a/lab-examples/ixiac01/go.mod b/lab-examples/ixiac01/go.mod
index 319dc61b..6972155c 100644
--- a/lab-examples/ixiac01/go.mod
+++ b/lab-examples/ixiac01/go.mod
@@ -4,7 +4,7 @@ go 1.22.7
 
 toolchain go1.23.0
 
-require github.com/open-traffic-generator/snappi/gosnappi v1.20.0
+require github.com/open-traffic-generator/snappi/gosnappi v1.24.0
 
 require (
 	github.com/Masterminds/semver/v3 v3.3.1 // indirect
@@ -16,6 +16,6 @@ require (
 	golang.org/x/text v0.21.0 // indirect
 	google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a // indirect
 	google.golang.org/grpc v1.70.0 // indirect
-	google.golang.org/protobuf v1.36.4 // indirect
+	google.golang.org/protobuf v1.36.5 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 )
diff --git a/lab-examples/ixiac01/go.sum b/lab-examples/ixiac01/go.sum
index 7cb0e771..d532639e 100644
--- a/lab-examples/ixiac01/go.sum
+++ b/lab-examples/ixiac01/go.sum
@@ -21,8 +21,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
 github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/open-traffic-generator/snappi/gosnappi v1.20.0 h1:3uSvj1jgPYSkLNvLDRdGH481Kut6ZVfCdVwEJ3JyMXU=
-github.com/open-traffic-generator/snappi/gosnappi v1.20.0/go.mod h1:HJVHZycvinhqYIUB0bLoyX90vQJf3kR3APOiVqJySrU=
+github.com/open-traffic-generator/snappi/gosnappi v1.24.0 h1:SEov6nqY/0/vQAXNC1pxiP4VzueDo7ueAr/fp/TxawI=
+github.com/open-traffic-generator/snappi/gosnappi v1.24.0/go.mod h1:U515+6Dic9HapkCLRAefk1jrdubK0XoObqNiUwYm35M=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
@@ -49,8 +49,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a h1:
 google.golang.org/genproto/googleapis/rpc v0.0.0-20241202173237-19429a94021a/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
 google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
 google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
-google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNIM=
-google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
+google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
+google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
diff --git a/lab-examples/ixiac01/ixiac01.clab.yml b/lab-examples/ixiac01/ixiac01.clab.yml
index f12c3fa6..8353105d 100644
--- a/lab-examples/ixiac01/ixiac01.clab.yml
+++ b/lab-examples/ixiac01/ixiac01.clab.yml
@@ -3,7 +3,7 @@ topology:
   nodes:
     ixia-c:
       kind: keysight_ixia-c-one
-      image: ghcr.io/open-traffic-generator/ixia-c-one:1.20.0-6
+      image: ghcr.io/open-traffic-generator/ixia-c-one:1.24.0-4
     srl:
       kind: nokia_srlinux
       image: ghcr.io/nokia/srlinux:23.10.1
diff --git a/links/link_veth.go b/links/link_veth.go
index 8aa684cf..792f2522 100644
--- a/links/link_veth.go
+++ b/links/link_veth.go
@@ -195,7 +195,7 @@ func (l *LinkVEth) deployBEnd(ctx context.Context, idx int) error {
 	l.DeploymentState = LinkDeploymentStateFullDeployed
 
 	if len(l.Endpoints) == 2 {
-		log.Infof("Created link: %s <--> %s", l.Endpoints[0], l.Endpoints[1])
+		log.Infof("Created link: %s ▪┄┄▪ %s", l.Endpoints[0], l.Endpoints[1])
 	}
 
 	return nil
diff --git a/nodes/srl/srl.go b/nodes/srl/srl.go
index 4749bf7b..232cad5a 100644
--- a/nodes/srl/srl.go
+++ b/nodes/srl/srl.go
@@ -194,8 +194,13 @@ func (n *srl) Init(cfg *types.NodeConfig, opts ...nodes.NodeOption) error {
 	n.Cfg.Binds = append(n.Cfg.Binds, fmt.Sprint(cfgPath, ":/etc/opt/srlinux/:rw"))
 
 	// mount srlinux topology
-	topoPath := filepath.Join(n.Cfg.LabDir, "topology.yml")
-	n.Cfg.Binds = append(n.Cfg.Binds, fmt.Sprint(topoPath, ":/tmp/topology.yml:ro"))
+	srcTopoPath := filepath.Join(n.Cfg.LabDir, "topology.yml")
+	dstTopoPath := "/tmp/topology.yml"
+	// if a user provided a topology file, it means that they want to use a custom srl topology file
+	// in that case we do not need to mount the one for the provided type
+	if !utils.DestinationBindMountExists(n.Cfg.Binds, dstTopoPath) {
+		n.Cfg.Binds = append(n.Cfg.Binds, fmt.Sprint(srcTopoPath, ":", dstTopoPath, ":ro"))
+	}
 
 	n.InterfaceRegexp = InterfaceRegexp
 	n.InterfaceHelp = InterfaceHelp
@@ -203,14 +208,14 @@ func (n *srl) Init(cfg *types.NodeConfig, opts ...nodes.NodeOption) error {
 	return nil
 }
 
-func (s *srl) PreDeploy(_ context.Context, params *nodes.PreDeployParams) error {
-	utils.CreateDirectory(s.Cfg.LabDir, 0777)
+func (n *srl) PreDeploy(_ context.Context, params *nodes.PreDeployParams) error {
+	utils.CreateDirectory(n.Cfg.LabDir, 0777)
 
 	// Create appmgr subdir for agent specs and copy files, if needed
-	if s.Cfg.Extras != nil && len(s.Cfg.Extras.SRLAgents) != 0 {
-		agents := s.Cfg.Extras.SRLAgents
+	if n.Cfg.Extras != nil && len(n.Cfg.Extras.SRLAgents) != 0 {
+		agents := n.Cfg.Extras.SRLAgents
 
-		appmgr := filepath.Join(s.Cfg.LabDir, "config", "appmgr")
+		appmgr := filepath.Join(n.Cfg.LabDir, "config", "appmgr")
 		utils.CreateDirectory(appmgr, 0777)
 
 		// process extras -> agents configurations
@@ -233,42 +238,42 @@ func (s *srl) PreDeploy(_ context.Context, params *nodes.PreDeployParams) error
 	}
 
 	// store provided pubkeys
-	s.sshPubKeys = params.SSHPubKeys
+	n.sshPubKeys = params.SSHPubKeys
 
 	// store the certificate-related parameters
 	// for cert generation to happen in Post-Deploy phase with mgmt IPs as SANs
-	s.cert = params.Cert
-	s.topologyName = params.TopologyName
+	n.cert = params.Cert
+	n.topologyName = params.TopologyName
 
-	return s.createSRLFiles()
+	return n.createSRLFiles()
 }
 
-func (s *srl) PostDeploy(ctx context.Context, params *nodes.PostDeployParams) error {
+func (n *srl) PostDeploy(ctx context.Context, params *nodes.PostDeployParams) error {
 	log.Info("Running postdeploy actions",
-		"kind", s.Cfg.Kind,
-		"node", s.Cfg.ShortName)
+		"kind", n.Cfg.Kind,
+		"node", n.Cfg.ShortName)
 
 	// generate the certificate
-	certificate, err := s.LoadOrGenerateCertificate(s.cert, s.topologyName)
+	certificate, err := n.LoadOrGenerateCertificate(n.cert, n.topologyName)
 	if err != nil {
 		return err
 	}
 
 	// set the certificate data
-	s.Config().TLSCert = string(certificate.Cert)
-	s.Config().TLSKey = string(certificate.Key)
+	n.Config().TLSCert = string(certificate.Cert)
+	n.Config().TLSKey = string(certificate.Key)
 
 	// Populate /etc/hosts for service discovery on mgmt interface
-	if err := s.populateHosts(ctx, params.Nodes); err != nil {
-		log.Warnf("Unable to populate hosts for node %q: %v", s.Cfg.ShortName, err)
+	if err := n.populateHosts(ctx, params.Nodes); err != nil {
+		log.Warnf("Unable to populate hosts for node %q: %v", n.Cfg.ShortName, err)
 	}
 
 	// start waiting for initial commit and mgmt server ready
-	if err := s.Ready(ctx); err != nil {
+	if err := n.Ready(ctx); err != nil {
 		return err
 	}
 
-	s.swVersion, err = s.RunningVersion(ctx)
+	n.swVersion, err = n.RunningVersion(ctx)
 	if err != nil {
 		return err
 	}
@@ -276,58 +281,58 @@ func (s *srl) PostDeploy(ctx context.Context, params *nodes.PostDeployParams) er
 	// return if config file is found in the lab directory.
 	// This can be either if the startup-config has been mounted by that path
 	// or the config has been previously generated and saved
-	if utils.FileExists(filepath.Join(s.Cfg.LabDir, "config", "config.json")) {
+	if utils.FileExists(filepath.Join(n.Cfg.LabDir, "config", "config.json")) {
 		return nil
 	}
 
-	if err := s.addDefaultConfig(ctx); err != nil {
+	if err := n.addDefaultConfig(ctx); err != nil {
 		return err
 	}
 
-	if err := s.addOverlayCLIConfig(ctx); err != nil {
+	if err := n.addOverlayCLIConfig(ctx); err != nil {
 		return err
 	}
 
 	// once default and overlay config is added, we can commit the config
-	if err := s.commitConfig(ctx); err != nil {
+	if err := n.commitConfig(ctx); err != nil {
 		return err
 	}
 
-	return s.generateCheckpoint(ctx)
+	return n.generateCheckpoint(ctx)
 }
 
-func (s *srl) SaveConfig(ctx context.Context) error {
+func (n *srl) SaveConfig(ctx context.Context) error {
 	cmd, _ := exec.NewExecCmdFromString(saveCmd)
-	execResult, err := s.RunExec(ctx, cmd)
+	execResult, err := n.RunExec(ctx, cmd)
 	if err != nil {
-		return fmt.Errorf("%s: failed to execute cmd: %v", s.Cfg.ShortName, err)
+		return fmt.Errorf("%s: failed to execute cmd: %v", n.Cfg.ShortName, err)
 	}
 
 	if len(execResult.GetStdErrString()) > 0 {
-		return fmt.Errorf("%s errors: %s", s.Cfg.ShortName, execResult.GetStdErrString())
+		return fmt.Errorf("%s errors: %s", n.Cfg.ShortName, execResult.GetStdErrString())
 	}
 
-	log.Infof("saved SR Linux configuration from %s node. Output:\n%s", s.Cfg.ShortName, execResult.GetStdOutString())
+	log.Infof("saved SR Linux configuration from %s node. Output:\n%s", n.Cfg.ShortName, execResult.GetStdOutString())
 
 	return nil
 }
 
 // Ready returns when the node boot sequence reached the stage when it is ready to accept config commands
 // returns an error if not ready by the expiry of the timer readyTimeout.
-func (s *srl) Ready(ctx context.Context) error {
+func (n *srl) Ready(ctx context.Context) error {
 	ctx, cancel := context.WithTimeout(ctx, readyTimeout)
 	defer cancel()
 	var err error
 
-	log.Debugf("Waiting for SR Linux node %q to boot...", s.Cfg.ShortName)
+	log.Debugf("Waiting for SR Linux node %q to boot...", n.Cfg.ShortName)
 	for {
 		select {
 		case <-ctx.Done():
-			return fmt.Errorf("timed out waiting for SR Linux node %s to boot: %v", s.Cfg.ShortName, err)
+			return fmt.Errorf("timed out waiting for SR Linux node %s to boot: %v", n.Cfg.ShortName, err)
 		default:
 			// two commands are checked, first if the mgmt_server is running
 			cmd, _ := exec.NewExecCmdFromString(mgmtServerRdyCmd)
-			execResult, err := s.RunExec(ctx, cmd)
+			execResult, err := n.RunExec(ctx, cmd)
 			if err != nil || (execResult != nil && execResult.GetReturnCode() != 0) {
 				logMsg := "mgmt_server status check failed"
 
@@ -359,7 +364,7 @@ func (s *srl) Ready(ctx context.Context) error {
 			// once mgmt server is running, we need to check if it is ready to accept configuration commands
 			// this is done with checking readyForConfigCmd
 			cmd, _ = exec.NewExecCmdFromString(readyForConfigCmd)
-			execResult, err = s.RunExec(ctx, cmd)
+			execResult, err = n.RunExec(ctx, cmd)
 			if err != nil {
 				log.Debugf("error during readyForConfigCmd execution: %s", err)
 				time.Sleep(retryTimer)
@@ -378,7 +383,7 @@ func (s *srl) Ready(ctx context.Context) error {
 				continue
 			}
 
-			log.Debugf("Node %s is ready to accept configs", s.Cfg.ShortName)
+			log.Debugf("Node %s is ready to accept configs", n.Cfg.ShortName)
 
 			return nil
 		}
@@ -400,24 +405,24 @@ func (*srl) checkKernelVersion() error {
 	return nil
 }
 
-func (s *srl) CheckDeploymentConditions(ctx context.Context) error {
+func (n *srl) CheckDeploymentConditions(ctx context.Context) error {
 	// perform the srl specific kernel version check
-	err := s.checkKernelVersion()
+	err := n.checkKernelVersion()
 	if err != nil {
 		return err
 	}
 
-	return s.DefaultNode.CheckDeploymentConditions(ctx)
+	return n.DefaultNode.CheckDeploymentConditions(ctx)
 }
 
-func (s *srl) createSRLFiles() error {
-	log.Debugf("Creating directory structure for SRL container: %s", s.Cfg.ShortName)
+func (n *srl) createSRLFiles() error {
+	log.Debugf("Creating directory structure for SRL container: %s", n.Cfg.ShortName)
 	var src string
 
-	if s.Cfg.License != "" {
+	if n.Cfg.License != "" {
 		// copy license file to node specific directory in lab
-		src = s.Cfg.License
-		licPath := filepath.Join(s.Cfg.LabDir, "license.key")
+		src = n.Cfg.License
+		licPath := filepath.Join(n.Cfg.LabDir, "license.key")
 		if err := utils.CopyFile(src, licPath, 0644); err != nil {
 			return fmt.Errorf("CopyFile src %s -> dst %s failed %v", src, licPath, err)
 		}
@@ -425,16 +430,16 @@ func (s *srl) createSRLFiles() error {
 	}
 
 	// generate SRL topology file, including base MAC
-	err := generateSRLTopologyFile(s.Cfg)
+	err := generateSRLTopologyFile(n.Cfg)
 	if err != nil {
 		return err
 	}
 
-	utils.CreateDirectory(path.Join(s.Cfg.LabDir, "config"), 0777)
+	utils.CreateDirectory(path.Join(n.Cfg.LabDir, "config"), 0777)
 
 	// create repository files (for yum/apt) that
 	// are mounted to srl container during the init phase
-	err = s.createRepoFiles()
+	err = n.createRepoFiles()
 	if err != nil {
 		return err
 	}
@@ -443,11 +448,11 @@ func (s *srl) createSRLFiles() error {
 	// if the node has a `startup-config:` statement, the file specified in that section
 	// will be used as a template in GenerateConfig()
 	var cfgTemplate string
-	cfgPath := filepath.Join(s.Cfg.LabDir, "config", "config.json")
-	if s.Cfg.StartupConfig != "" {
-		log.Debug("Reading startup-config", "file", s.Cfg.StartupConfig)
+	cfgPath := filepath.Join(n.Cfg.LabDir, "config", "config.json")
+	if n.Cfg.StartupConfig != "" {
+		log.Debug("Reading startup-config", "file", n.Cfg.StartupConfig)
 
-		c, err := os.ReadFile(s.Cfg.StartupConfig)
+		c, err := os.ReadFile(n.Cfg.StartupConfig)
 		if err != nil {
 			return err
 		}
@@ -459,14 +464,14 @@ func (s *srl) createSRLFiles() error {
 		isJSON := len(x) > 0 && x[0] == '{'
 		if !isJSON {
 			log.Debugf("startup-config passed to %s is in the CLI format. Will apply it in post-deploy stage",
-				s.Cfg.ShortName)
+				n.Cfg.ShortName)
 
-			cBuf, err := utils.SubstituteEnvsAndTemplate(bytes.NewReader(c), s.Cfg)
+			cBuf, err := utils.SubstituteEnvsAndTemplate(bytes.NewReader(c), n.Cfg)
 			if err != nil {
 				return err
 			}
 
-			s.startupCliCfg = cBuf.Bytes()
+			n.startupCliCfg = cBuf.Bytes()
 
 			// no need to generate and mount startup-config passed in a CLI format
 			// as we will apply it over the top of a default config in the post deploy stage
@@ -476,14 +481,14 @@ func (s *srl) createSRLFiles() error {
 	}
 
 	if cfgTemplate == "" {
-		log.Debugf("configuration template for node %s is empty, skipping startup config file generation", s.Cfg.ShortName)
+		log.Debugf("configuration template for node %s is empty, skipping startup config file generation", n.Cfg.ShortName)
 
 		return nil
 	}
 
-	err = s.GenerateConfig(cfgPath, cfgTemplate)
+	err = n.GenerateConfig(cfgPath, cfgTemplate)
 	if err != nil {
-		log.Errorf("node=%s, failed to generate config: %v", s.Cfg.ShortName, err)
+		log.Errorf("node=%s, failed to generate config: %v", n.Cfg.ShortName, err)
 	}
 
 	return err
@@ -659,22 +664,22 @@ func (n *srl) addDefaultConfig(ctx context.Context) error {
 }
 
 // addOverlayCLIConfig adds CLI formatted config that is read out of a file provided via startup-config directive.
-func (s *srl) addOverlayCLIConfig(ctx context.Context) error {
-	if len(s.startupCliCfg) == 0 {
-		log.Debugf("node %q: startup-config empty, committing existing candidate", s.Config().ShortName)
+func (n *srl) addOverlayCLIConfig(ctx context.Context) error {
+	if len(n.startupCliCfg) == 0 {
+		log.Debugf("node %q: startup-config empty, committing existing candidate", n.Config().ShortName)
 
 		return nil
 	}
 
-	cfgStr := string(s.startupCliCfg)
+	cfgStr := string(n.startupCliCfg)
 
-	log.Debugf("Node %q additional config from startup-config file %s:\n%s", s.Cfg.ShortName, s.Cfg.StartupConfig, cfgStr)
+	log.Debugf("Node %q additional config from startup-config file %s:\n%s", n.Cfg.ShortName, n.Cfg.StartupConfig, cfgStr)
 
 	cmd := exec.NewExecCmdFromSlice([]string{
 		"bash", "-c",
 		fmt.Sprintf("echo '%s' > %s", cfgStr, overlayCfgPath),
 	})
-	_, err := s.RunExec(ctx, cmd)
+	_, err := n.RunExec(ctx, cmd)
 	if err != nil {
 		return err
 	}
@@ -683,7 +688,7 @@ func (s *srl) addOverlayCLIConfig(ctx context.Context) error {
 		"bash", "-c",
 		fmt.Sprintf("su -s /bin/bash admin -c '/opt/srlinux/bin/sr_cli -ed < %s'", overlayCfgPath),
 	})
-	execResult, err := s.RunExec(ctx, cmd)
+	execResult, err := n.RunExec(ctx, cmd)
 	if err != nil {
 		return err
 	}
@@ -692,20 +697,20 @@ func (s *srl) addOverlayCLIConfig(ctx context.Context) error {
 		return fmt.Errorf("%w:%s", nodes.ErrCommandExecError, execResult.GetStdErrString())
 	}
 
-	log.Debugf("node %s. stdout: %s, stderr: %s", s.Cfg.ShortName, execResult.GetStdOutString(), execResult.GetStdErrString())
+	log.Debugf("node %s. stdout: %s, stderr: %s", n.Cfg.ShortName, execResult.GetStdOutString(), execResult.GetStdErrString())
 
 	return nil
 }
 
 // commitConfig commits and saves default+overlay config to the startup-config file.
-func (s *srl) commitConfig(ctx context.Context) error {
-	log.Debugf("Node %q: commiting configuration", s.Cfg.ShortName)
+func (n *srl) commitConfig(ctx context.Context) error {
+	log.Debugf("Node %q: commiting configuration", n.Cfg.ShortName)
 
 	cmd, err := exec.NewExecCmdFromString(`bash -c "/opt/srlinux/bin/sr_cli -ed commit save"`)
 	if err != nil {
 		return err
 	}
-	execResult, err := s.RunExec(ctx, cmd)
+	execResult, err := n.RunExec(ctx, cmd)
 	if err != nil {
 		return err
 	}
@@ -714,18 +719,18 @@ func (s *srl) commitConfig(ctx context.Context) error {
 		return fmt.Errorf("%w:%s", nodes.ErrCommandExecError, execResult.GetStdErrString())
 	}
 
-	log.Debugf("node %s. stdout: %s, stderr: %s", s.Cfg.ShortName, execResult.GetStdOutString(), execResult.GetStdErrString())
+	log.Debugf("node %s. stdout: %s, stderr: %s", n.Cfg.ShortName, execResult.GetStdOutString(), execResult.GetStdErrString())
 
 	return nil
 }
 
-func (s *srl) generateCheckpoint(ctx context.Context) error {
+func (n *srl) generateCheckpoint(ctx context.Context) error {
 	cmd, err := exec.NewExecCmdFromString(`bash -c '/opt/srlinux/bin/sr_cli /tools system configuration generate-checkpoint name clab-initial comment \"set by containerlab\"'`)
 	if err != nil {
 		return err
 	}
 
-	execResult, err := s.RunExec(ctx, cmd)
+	execResult, err := n.RunExec(ctx, cmd)
 	if err != nil {
 		return err
 	}
@@ -734,7 +739,7 @@ func (s *srl) generateCheckpoint(ctx context.Context) error {
 		return fmt.Errorf("%w:%s", nodes.ErrCommandExecError, execResult.GetStdErrString())
 	}
 
-	log.Debugf("node %s. stdout: %s, stderr: %s", s.Cfg.ShortName, execResult.GetStdOutString(), execResult.GetStdErrString())
+	log.Debugf("node %s. stdout: %s, stderr: %s", n.Cfg.ShortName, execResult.GetStdOutString(), execResult.GetStdErrString())
 
 	return nil
 }
@@ -742,10 +747,10 @@ func (s *srl) generateCheckpoint(ctx context.Context) error {
 // populateHosts adds container hostnames for other nodes of a lab to SR Linux /etc/hosts file
 // to mitigate the fact that srlinux uses non default netns for management and thus
 // can't leverage docker DNS service.
-func (s *srl) populateHosts(ctx context.Context, nodes map[string]nodes.Node) error {
-	hosts, err := s.Runtime.GetHostsPath(ctx, s.Cfg.LongName)
+func (n *srl) populateHosts(ctx context.Context, nodes map[string]nodes.Node) error {
+	hosts, err := n.Runtime.GetHostsPath(ctx, n.Cfg.LongName)
 	if err != nil {
-		log.Warnf("Unable to locate /etc/hosts file for srl node %v: %v", s.Cfg.ShortName, err)
+		log.Warnf("Unable to locate /etc/hosts file for srl node %v: %v", n.Cfg.ShortName, err)
 		return err
 	}
 	var entriesv4, entriesv6 bytes.Buffer
@@ -770,7 +775,7 @@ func (s *srl) populateHosts(ctx context.Context, nodes map[string]nodes.Node) er
 
 	file, err := os.OpenFile(hosts, os.O_APPEND|os.O_WRONLY, 0666) // skipcq: GSC-G302
 	if err != nil {
-		log.Warnf("Unable to open /etc/hosts file for srl node %v: %v", s.Cfg.ShortName, err)
+		log.Warnf("Unable to open /etc/hosts file for srl node %v: %v", n.Cfg.ShortName, err)
 		return err
 	}
 
@@ -786,8 +791,8 @@ func (s *srl) populateHosts(ctx context.Context, nodes map[string]nodes.Node) er
 	return file.Close()
 }
 
-func (s *srl) GetMappedInterfaceName(ifName string) (string, error) {
-	captureGroups, err := utils.GetRegexpCaptureGroups(s.InterfaceRegexp, ifName)
+func (n *srl) GetMappedInterfaceName(ifName string) (string, error) {
+	captureGroups, err := utils.GetRegexpCaptureGroups(n.InterfaceRegexp, ifName)
 	if err != nil {
 		return "", err
 	}
@@ -824,23 +829,23 @@ func (s *srl) GetMappedInterfaceName(ifName string) (string, error) {
 }
 
 // CheckInterfaceName checks if a name of the interface referenced in the topology file correct.
-func (s *srl) CheckInterfaceName() error {
+func (n *srl) CheckInterfaceName() error {
 	// allow ethernetX-X-X, eX-X-X and mgmt0 interface names
 	ifRe := regexp.MustCompile(`(:?e|ethernet)\d+-\d+(-\d+)?|mgmt0`)
-	nm := strings.ToLower(s.Cfg.NetworkMode)
+	nm := strings.ToLower(n.Cfg.NetworkMode)
 
-	err := s.CheckInterfaceOverlap()
+	err := n.CheckInterfaceOverlap()
 	if err != nil {
 		return err
 	}
 
-	for _, e := range s.Endpoints {
+	for _, e := range n.Endpoints {
 		if !ifRe.MatchString(e.GetIfaceName()) {
-			return fmt.Errorf("nokia sr linux interface name %q doesn't match the required pattern: %s", e.GetIfaceName(), s.InterfaceHelp)
+			return fmt.Errorf("nokia sr linux interface name %q doesn't match the required pattern: %s", e.GetIfaceName(), n.InterfaceHelp)
 		}
 
 		if e.GetIfaceName() == "mgmt0" && nm != "none" {
-			return fmt.Errorf("mgmt0 interface name is not allowed for %s node when network mode is not set to none", s.Cfg.ShortName)
+			return fmt.Errorf("mgmt0 interface name is not allowed for %s node when network mode is not set to none", n.Cfg.ShortName)
 		}
 	}
 
@@ -849,7 +854,7 @@ func (s *srl) CheckInterfaceName() error {
 
 // createRepoFiles creates apt/ym repository files
 // to enable srl nodes to install ndk apps.
-func (s *srl) createRepoFiles() error {
+func (n *srl) createRepoFiles() error {
 	yumRepo := `[srlinux]
 name=SR Linux NDK apps
 baseurl=https://srlinux.fury.site/yum/
@@ -858,21 +863,21 @@ gpgcheck=0`
 
 	aptRepo := `deb [trusted=yes] https://srlinux.fury.site/apt/ /`
 
-	yumPath := s.Cfg.LabDir + "/yum.repo"
+	yumPath := n.Cfg.LabDir + "/yum.repo"
 	err := utils.CreateFile(yumPath, yumRepo)
 	if err != nil {
 		return err
 	}
 
-	aptPath := s.Cfg.LabDir + "/apt.list"
+	aptPath := n.Cfg.LabDir + "/apt.list"
 	err = utils.CreateFile(aptPath, aptRepo)
 	if err != nil {
 		return err
 	}
 
 	// mount srlinux repository files
-	s.Cfg.Binds = append(
-		s.Cfg.Binds,
+	n.Cfg.Binds = append(
+		n.Cfg.Binds,
 		yumPath+":/etc/yum.repos.d/srlinux.repo:ro",
 		aptPath+":/etc/apt/sources.list.d/srlinux.list:ro")
 
diff --git a/utils/containers.go b/utils/containers.go
index fcd25071..e88cbe4f 100644
--- a/utils/containers.go
+++ b/utils/containers.go
@@ -60,3 +60,19 @@ func ContainerNSToPID(cID string) (int, error) {
 	}
 	return pid, nil
 }
+
+// DestinationBindMountExists checks if a bind mount destination exists in a list of bind mounts.
+// The bind options are not matched, only the destination is matched.
+// The binds are expected to be in the format of "source:destination[:options]".
+func DestinationBindMountExists(binds []string, dest string) bool {
+	for _, b := range binds {
+		parts := strings.Split(b, ":")
+		if len(parts) >= 2 {
+			// The destination is the second part
+			if parts[1] == dest {
+				return true
+			}
+		}
+	}
+	return false
+}


Test patch:
diff --git a/tests/01-smoke/01-basic-flow.robot b/tests/01-smoke/01-basic-flow.robot
index 15e224c9..17009a8c 100644
--- a/tests/01-smoke/01-basic-flow.robot
+++ b/tests/01-smoke/01-basic-flow.robot
@@ -18,15 +18,15 @@ ${n2-ipv4}                  172.20.20.100/24
 ${n2-ipv6}                  3fff:172:20:20::100/64
 ${table-delimit}            │
 ${l1-uname-exec-output}     SEPARATOR=\n
-...                         Executed command command="uname -n" node=clab-2-linux-nodes-l1
+...                         Executed command node=clab-2-linux-nodes-l1 command="uname -n"
 ...                         ${SPACE}${SPACE}stdout=
 ...                         ${SPACE}${SPACE}│ l1
 ${l2-uname-exec-output}     SEPARATOR=\n
-...                         Executed command command="uname -n" node=clab-2-linux-nodes-l2
+...                         Executed command node=clab-2-linux-nodes-l2 command="uname -n"
 ...                         ${SPACE}${SPACE}stdout=
 ...                         ${SPACE}${SPACE}│ l2
 ${l3-uname-exec-output}     SEPARATOR=\n
-...                         Executed command command="uname -n" node=clab-2-linux-nodes-l3
+...                         Executed command node=clab-2-linux-nodes-l3 command="uname -n"
 ...                         ${SPACE}${SPACE}stdout=
 ...                         ${SPACE}${SPACE}│ l3
 
diff --git a/tests/01-smoke/18-stages.robot b/tests/01-smoke/18-stages.robot
index e2323f1a..5bc9a6a6 100644
--- a/tests/01-smoke/18-stages.robot
+++ b/tests/01-smoke/18-stages.robot
@@ -15,11 +15,11 @@ ${lab-file}                     stages.clab.yml
 ${lab-name}                     stages
 ${runtime}                      docker
 ${n4-exec-output}               SEPARATOR=\n
-...                             Executed command command="uname -n" node=node4
+...                             Executed command node=node4 command="uname -n"
 ...                             ${SPACE}${SPACE}stdout=
 ...                             ${SPACE}${SPACE}│ node4
 ${n4-exec-healthy-output}       SEPARATOR=\n
-...                             Executed command command="echo hey I am exiting healthy stage" node=node4
+...                             Executed command node=node4 command="echo hey I am exiting healthy stage"
 ...                             ${SPACE}${SPACE}stdout=
 ...                             ${SPACE}${SPACE}│ hey I am exiting healthy stage
 
@@ -81,7 +81,7 @@ Ensure node4 executed on-exit commands for its healthy stage
 Ensure node3 executed on-exit commands for its create stage and this output doesn't contain any non eth0/lo interfaces
     ${extracted_text} =    Extract Text Between Markers
     ...    ${deploylog.stderr}
-    ...    INFO Executed command command="ls /sys/class/net/" node=node3
+    ...    INFO Executed command node=node3 command="ls /sys/class/net/"
 
     Log    extracted node3 output is${\n}${extracted_text}    console=${True}
 
@@ -98,7 +98,7 @@ Ensure node3 executed on-exit commands for its create stage and this output does
 Ensure node1 executed on-enter commands for its create-links stage and this output doesn't contain any non eth0/lo interfaces
     ${extracted_text} =    Extract Text Between Markers
     ...    ${deploylog.stderr}
-    ...    INFO Executed command command="ls /sys/class/net/" node=node1
+    ...    INFO Executed command node=node1 command="ls /sys/class/net/"
 
     Log    ${extracted_text}    console=${True}
 
diff --git a/utils/containers_test.go b/utils/containers_test.go
index 1a175ccc..f4e02587 100644
--- a/utils/containers_test.go
+++ b/utils/containers_test.go
@@ -47,3 +47,55 @@ func TestGetCanonicalImageName(t *testing.T) {
 		})
 	}
 }
+func TestDestinationBindMountExists(t *testing.T) {
+	tests := map[string]struct {
+		binds []string
+		dest  string
+		want  bool
+	}{
+		"empty binds slice": {
+			binds: []string{},
+			dest:  "/target",
+			want:  false,
+		},
+		"single bind with matching destination": {
+			binds: []string{"/source:/target"},
+			dest:  "/target",
+			want:  true,
+		},
+		"multiple binds with one matching destination": {
+			binds: []string{"/source1:/target1", "/source2:/target"},
+			dest:  "/target",
+			want:  true,
+		},
+		"no matching destination": {
+			binds: []string{"/source1:/target1", "/source2:/target2"},
+			dest:  "/target3",
+			want:  false,
+		},
+		"bind with additional options": {
+			binds: []string{"/source:/target:ro,z"},
+			dest:  "/target",
+			want:  true,
+		},
+		"malformed bind without separator": {
+			binds: []string{"malformedstring"},
+			dest:  "/target",
+			want:  false,
+		},
+		"bind with empty parts": {
+			binds: []string{":/target:", "/source:"},
+			dest:  "/target",
+			want:  true,
+		},
+	}
+
+	for name, tc := range tests {
+		t.Run(name, func(t *testing.T) {
+			got := DestinationBindMountExists(tc.binds, tc.dest)
+			if !cmp.Equal(got, tc.want) {
+				t.Fatalf("wanted %v, got %v", tc.want, got)
+			}
+		})
+	}
+}