@@ -18,6 +18,7 @@ package vm
1818
1919import (
2020 "context"
21+ "encoding/json"
2122 "fmt"
2223 "strings"
2324 "time"
@@ -183,12 +184,10 @@ var _ = Describe("VirtualMachineAdditionalNetworkInterfaces", Label(precheck.NoP
183184 )
184185
185186 const (
186- getLastInterfaceNameCmd = "ip -o link show | tail -1 | cut -d: -f2 | awk \" {print \\ $1} \" "
187+ expectedLastInterfaceName = "eno3 "
187188 )
188189
189190 It ("should preserve interface name after removing middle ClusterNetwork and rebooting" , func () {
190- var lastInterfaceNameBeforeRemoval string
191-
192191 By ("Create VM with Main network and two additional ClusterNetworks" , func () {
193192 ns := f .Namespace ().Name
194193
@@ -216,10 +215,7 @@ var _ = Describe("VirtualMachineAdditionalNetworkInterfaces", Label(precheck.NoP
216215
217216 By ("Get last interface name via SSH" , func () {
218217 util .UntilSSHReady (f , vm , framework .LongTimeout )
219- output , err := f .SSHCommand (vm .Name , vm .Namespace , getLastInterfaceNameCmd )
220- Expect (err ).NotTo (HaveOccurred ())
221- lastInterfaceNameBeforeRemoval = strings .TrimSpace (output )
222- Expect (lastInterfaceNameBeforeRemoval ).NotTo (BeEmpty (), "Failed to get last interface name" )
218+ checkLastInterfaceName (f , vm .Name , vm .Namespace , expectedLastInterfaceName )
223219 })
224220
225221 By ("Remove middle ClusterNetwork from VM spec" , func () {
@@ -253,13 +249,7 @@ var _ = Describe("VirtualMachineAdditionalNetworkInterfaces", Label(precheck.NoP
253249
254250 By ("Verify last interface name has not changed" , func () {
255251 util .UntilSSHReady (f , vm , framework .LongTimeout )
256- output , err := f .SSHCommand (vm .Name , vm .Namespace , getLastInterfaceNameCmd )
257- Expect (err ).NotTo (HaveOccurred ())
258- lastInterfaceNameAfterRemoval := strings .TrimSpace (output )
259- Expect (lastInterfaceNameAfterRemoval ).NotTo (BeEmpty (), "Failed to get last interface name" )
260-
261- Expect (lastInterfaceNameAfterRemoval ).To (Equal (lastInterfaceNameBeforeRemoval ),
262- fmt .Sprintf ("Interface name changed from %s to %s after removing middle ClusterNetwork" , lastInterfaceNameBeforeRemoval , lastInterfaceNameAfterRemoval ))
252+ checkLastInterfaceName (f , vm .Name , vm .Namespace , expectedLastInterfaceName )
263253 })
264254 })
265255 })
@@ -361,3 +351,33 @@ func checkResultSSHCommand(f *framework.Framework, vmName, vmNamespace, cmd, equ
361351 return strings .TrimSpace (res ), nil
362352 }).WithTimeout (Timeout ).WithPolling (Interval ).Should (Equal (equal ))
363353}
354+
355+ func checkLastInterfaceName (f * framework.Framework , vmName , vmNamespace , expected string ) {
356+ GinkgoHelper ()
357+ Eventually (func () (string , error ) {
358+ cmd := "ip -j link show"
359+ result , err := f .SSHCommand (vmName , vmNamespace , cmd , framework .WithSSHTimeout (5 * time .Second ))
360+ if err != nil {
361+ return "" , fmt .Errorf ("failed to execute command: %w: %s" , err , result )
362+ }
363+
364+ var links IPLinks
365+ err = json .Unmarshal ([]byte (result ), & links )
366+ if err != nil {
367+ return "" , fmt .Errorf ("failed to parse ip JSON output: %w" , err )
368+ }
369+ if len (links ) == 0 {
370+ return "" , fmt .Errorf ("no network interfaces found" )
371+ }
372+
373+ return links [len (links )- 1 ].IFName , nil
374+ }).WithTimeout (Timeout ).WithPolling (Interval ).Should (Equal (expected ))
375+ }
376+
377+ // IPLinks represents the JSON output of ip -j link show command.
378+ type IPLinks []IPLink
379+
380+ // IPLink represents a single network interface in the ip JSON output.
381+ type IPLink struct {
382+ IFName string `json:"ifname"`
383+ }
0 commit comments