Guide 7. Linking up virtual machines

What you're going to learn

In this guide you're going to learn:

  1. How to operate multiple virtual machines in a single test.
  2. Some additional nic subattributes.
  3. More information about virtual networks.

Preconditions

  1. Testo Framework is installed.
  2. Hyper-V is installed.
  3. Ubuntu server 16.04 image is downloaded and located here: C:\iso\ubuntu_server.iso. The location may be different, but in this case the ISO_DIR command-line param has to be adjusted accordingly.
  4. Testo guest additions iso image is downloaded and located in the same folder as Ubuntu Server 16.04 iso-image.
  5. The Host has the Internet access.
  6. (Recommended) Testo-lang syntax highlight for Sublime Text 3 is set up.
  7. (Recommended) Guide 6 is complete.

Introduction

In the third guide we learned about the virtual networks nat mode, which allows you to provide the Internet access to virtual machines. But, obviously, virtual networks could (and should) be used for linking up virtual machines with each other as well. That's what we're going to do in this guide. Additionally we'll discover a few little tricks to make our test scripts more convenient and easier to read.

At the end of this guide we're going to get the following test bench:

What to begin with?

From this moment on, there will be two virtual machines in our test cases, playing the roles of a server and a client. To make our test scripts more transparent and easier to read, we will need to do some job:

  1. Rename the virtual machine my_ubuntu into server;
  2. Rename the params hostname, login, password into server_hostname, server_login and default_password respectively and adjust all the references to these params;
  3. Rename the tests ubuntu_installation, ubuntu_prepare and ubuntu_install_guest_additions into server_install_ubuntu, server_prepare and server_install_guest_additions respectively;
  4. Delete the test ubuntu_guest_additions_demo.

You should get the following script:


network internet {
	mode: "nat"
}

machine server {
	cpus: 1
	ram: 512Mb
	disk main: {
		size: 5Gb
	}
	iso: "${ISO_DIR}\ubuntu_server.iso"

	nic nat: {
		attached_to: "internet"
	}
}

param server_hostname "server"
param server_login "server-login"
param default_password "1111"

test server_install_ubuntu {
	server {
		start
		# The actions can be separated with a newline
		# or a semicolon
		wait "Install Ubuntu Server"; press Enter;
		wait "Choose the language";	press Enter
		wait "Select your location"; press Enter
		wait "Detect keyboard layout?";	press Enter
		wait "Country of origin for the keyboard"; press Enter
		wait "Keyboard layout"; press Enter
		#wait "No network interfaces detected" timeout 5m; press Enter
		wait "Hostname:" timeout 5m; press Backspace*36; type "${server_hostname}"; press Enter
		wait "Full name for the new user"; type "${server_login}"; press Enter
		wait "Username for your account"; press Enter
		wait "Choose a password for the new user"; type "${default_password}"; press Enter
		wait "Re-enter password to verify"; type "${default_password}"; press Enter
		wait "Use weak password?"; press Left, Enter
		wait "Encrypt your home directory?"; press Enter

		wait "Is this time zone correct?" timeout 2m; press Enter
		wait "Partitioning method"; press Enter
		wait "Select disk to partition"; press Enter
		wait "Write the changes to disks and configure LVM?"; press Left, Enter
		wait "Amount of volume group to use for guided partitioning"; press Enter
		wait "Force UEFI installation?"; press Left, Enter
		wait "Write the changes to disks?"; press Left, Enter
		wait "HTTP proxy information" timeout 3m; press Enter
		wait "How do you want to manage upgrades" timeout 6m; press Enter
		wait "Choose software to install"; press Enter
		wait "Installation complete" timeout 30m;

		unplug dvd; press Enter
		wait "login:" timeout 2m; type "${server_login}"; press Enter
		wait "Password:"; type "${default_password}"; press Enter
		wait "Welcome to Ubuntu"
	}
}

test server_prepare: server_install_ubuntu {
	server {
		# Enter sudo mode
		type "sudo su"; press Enter
		wait "password for ${server_login}"; type "${default_password}"; press Enter
		wait "root@${server_hostname}"

		# Reset the eth0 NIC to prevent any issues with it after the rollback
		type "dhclient -r eth0 && dhclient eth0 && echo Result is $?"; press Enter

		# Check that apt is OK
		type "clear && apt update && echo Result is $?"; press Enter
		wait "Result is 0"

		# Install linux-azure package
		type "clear && apt install -y linux-azure && echo Result is $?"; press Enter
		wait "Result is 0" timeout 15m		

		# Reboot and login
		type "reboot"; press Enter

		wait "login:" timeout 2m; type "${server_login}"; press Enter
		wait "Password:"; type "${default_password}"; press Enter
		wait "Welcome to Ubuntu"

		# Enter sudo once more
		type "sudo su"; press Enter;
		wait "password for ${server_login}"; type "${default_password}"; press Enter
		wait "root@${server_hostname}"

		# Load the hv_sock module
		type "clear && modprobe hv_sock && echo Result is $?"; press Enter;
		wait "Result is 0"

		type "clear && lsmod | grep hv"; press Enter
		wait "hv_sock"
	}
}

param guest_additions_pkg "testo-guest-additions.deb"

test server_install_guest_additions: server_prepare {
	server {
		plug dvd "${ISO_DIR}\testo-guest-additions-hyperv.iso"

		type "mount /dev/cdrom /media"; press Enter
		wait "mounting read-only"
		type "clear && dpkg -i /media/${guest_additions_pkg} && echo Result is $?"; press Enter;
		wait "Result is 0"
		type "clear && umount /media && echo Result is $?"; press Enter;
		wait "Result is 0"
		sleep 2s
		unplug dvd
	}
}

Since we've renamed our virtual machine into server, Testo treats is as a brand new machine, therefore all the tests must run again, including the virtual machine creation.

But we need to keep in mind that the old virtual machine, my_ubuntu, wouldn't go anywhere automatically. Testo Framework "assumes" that this virtual machine may be of some use for you in the future, and thus shouldn't be removed. Still, we, as humans, understand that we won't need my_ubuntu anymore, so let's delete it:

C:\Users\Testo> testo clean
Testo is about to erase the following entities:
Virtual networks:
- internet
Virtual machines:
- my_ubuntu

Do you confirm erasing these entities? [y/N]: y
Deleted network internet
Deleted virtual machine my_ubuntu
C:\Users\Testo>

You can see that the virtual network internet was deleted as well.

Now, before doing anything else, it's good to make sure we didn't break anything with our changes.

C:\Users\Testo> testo run ping.testo --stop_on_fail --param ISO_DIR C:\iso
TESTS TO RUN:
server_install_ubuntu
server_prepare
server_install_guest_additions
[ 0%] Preparing the environment for test server_install_ubuntu
[ 0%] Restoring snapshot initial for virtual machine server
[ 0%] Running test server_install_ubuntu
[ 0%] Starting virtual machine server
[ 0%] Waiting "Install Ubuntu Server" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Choose the language" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Select your location" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Detect keyboard layout?" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Country of origin for the keyboard" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Keyboard layout" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Hostname:" for 5m with interval 1s in virtual machine server
[ 0%] Pressing key BACKSPACE 36 times in virtual machine server
[ 0%] Typing "server" with interval 30ms in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Full name for the new user" for 1m with interval 1s in virtual machine server
[ 0%] Typing "server-login" with interval 30ms in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Username for your account" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Choose a password for the new user" for 1m with interval 1s in virtual machine server
[ 0%] Typing "1111" with interval 30ms in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Re-enter password to verify" for 1m with interval 1s in virtual machine server
[ 0%] Typing "1111" with interval 30ms in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Use weak password?" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key LEFT in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Encrypt your home directory?" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Is this time zone correct?" for 2m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Partitioning method" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Select disk to partition" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Write the changes to disks and configure LVM?" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key LEFT in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Amount of volume group to use for guided partitioning" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Force UEFI installation?" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key LEFT in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Write the changes to disks?" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key LEFT in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "HTTP proxy information" for 3m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "How do you want to manage upgrades" for 6m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Choose software to install" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Installation complete" for 30m with interval 1s in virtual machine server
[ 0%] Unplugging dvd from virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "login:" for 2m with interval 1s in virtual machine server
[ 0%] Typing "server-login" with interval 30ms in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Password:" for 1m with interval 1s in virtual machine server
[ 0%] Typing "1111" with interval 30ms in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Welcome to Ubuntu" for 1m with interval 1s in virtual machine server
[ 0%] Taking snapshot server_install_ubuntu for virtual machine server
[ 33%] Test server_install_ubuntu PASSED in 0h:7m:6s
[ 33%] Preparing the environment for test server_prepare
[ 33%] Running test server_prepare
[ 33%] Typing "sudo su" with interval 30ms in virtual machine server
[ 33%] Pressing key ENTER in virtual machine server
[ 33%] Waiting "password for server-login" for 1m with interval 1s in virtual machine server
[ 33%] Typing "1111" with interval 30ms in virtual machine server
[ 33%] Pressing key ENTER in virtual machine server
[ 33%] Waiting "root@server" for 1m with interval 1s in virtual machine server
[ 33%] Typing "dhclient -r eth0 && dhclient eth0 && echo Result is $?" with interval 30ms in virtual machine server
[ 33%] Pressing key ENTER in virtual machine server
[ 33%] Typing "clear && apt update && echo Result is $?" with interval 30ms in virtual machine server
[ 33%] Pressing key ENTER in virtual machine server
[ 33%] Waiting "Result is 0" for 1m with interval 1s in virtual machine server
[ 33%] Typing "clear && apt install -y linux-azure && echo Result is $?" with interval 30ms in virtual machine server
[ 33%] Pressing key ENTER in virtual machine server
[ 33%] Waiting "Result is 0" for 15m with interval 1s in virtual machine server
[ 33%] Typing "reboot" with interval 30ms in virtual machine server
[ 33%] Pressing key ENTER in virtual machine server
[ 33%] Waiting "login:" for 2m with interval 1s in virtual machine server
[ 33%] Typing "server-login" with interval 30ms in virtual machine server
[ 33%] Pressing key ENTER in virtual machine server
[ 33%] Waiting "Password:" for 1m with interval 1s in virtual machine server
[ 33%] Typing "1111" with interval 30ms in virtual machine server
[ 33%] Pressing key ENTER in virtual machine server
[ 33%] Waiting "Welcome to Ubuntu" for 1m with interval 1s in virtual machine server
[ 33%] Typing "sudo su" with interval 30ms in virtual machine server
[ 33%] Pressing key ENTER in virtual machine server
[ 33%] Waiting "password for server-login" for 1m with interval 1s in virtual machine server
[ 33%] Typing "1111" with interval 30ms in virtual machine server
[ 33%] Pressing key ENTER in virtual machine server
[ 33%] Waiting "root@server" for 1m with interval 1s in virtual machine server
[ 33%] Typing "clear && modprobe hv_sock && echo Result is $?" with interval 30ms in virtual machine server
[ 33%] Pressing key ENTER in virtual machine server
[ 33%] Waiting "Result is 0" for 1m with interval 1s in virtual machine server
[ 33%] Typing "clear && lsmod | grep hv" with interval 30ms in virtual machine server
[ 33%] Pressing key ENTER in virtual machine server
[ 33%] Waiting "hv_sock" for 1m with interval 1s in virtual machine server
[ 33%] Taking snapshot server_prepare for virtual machine server
[ 67%] Test server_prepare PASSED in 0h:5m:45s
[ 67%] Preparing the environment for test server_install_guest_additions
[ 67%] Running test server_install_guest_additions
[ 67%] Plugging dvd C:/iso/testo-guest-additions-hyperv.iso into virtual machine server
[ 67%] Typing "mount /dev/cdrom /media" with interval 30ms in virtual machine server
[ 67%] Pressing key ENTER in virtual machine server
[ 67%] Waiting "mounting read-only" for 1m with interval 1s in virtual machine server
[ 67%] Typing "clear && dpkg -i /media/testo-guest-additions.deb && echo Result is $?" with interval 30ms in virtual machine server
[ 67%] Pressing key ENTER in virtual machine server
[ 67%] Waiting "Result is 0" for 1m with interval 1s in virtual machine server
[ 67%] Typing "clear && umount /media && echo Result is $?" with interval 30ms in virtual machine server
[ 67%] Pressing key ENTER in virtual machine server
[ 67%] Waiting "Result is 0" for 1m with interval 1s in virtual machine server
[ 67%] Sleeping in virtual machine server for 2s
[ 67%] Unplugging dvd from virtual machine server
[ 67%] Taking snapshot server_install_guest_additions for virtual machine server
[100%] Test server_install_guest_additions PASSED in 0h:0m:15s
PROCESSED TOTAL 3 TESTS IN 0h:13m:7s
UP-TO-DATE: 0
RUN SUCCESSFULLY: 3
FAILED: 0
C:\Users\Testo>

Declaring the second virtual machine

Now it's time to declare our second virtual machine. As you've probably guessed, it's going to be named client, and will be mostly a copy of the server machine.

machine client {
    cpus: 1
    ram: 512Mb
    disk main: {
        size: 5Gb
    }
    iso: "${ISO_DIR}\\ubuntu_server.iso"

    nic nat: {
        attached_to: "internet"
    }
}

But if we leave our virtual machines as they are now, they won't be connected in any way. To link them up we need to declare a new virtual network:

network LAN {
    mode: "internal"
}

Take a note that this network is declared as internal, which means that it's designated to isolated connection between machines.

All that's left to do is to add new NICs to the virtual machines, with attachment to the LAN network:

machine client {
    cpus: 1
    ram: 512Mb
    disk main: {
        size: 5Gb
    }
    iso: "${ISO_DIR}\\ubuntu_server.iso"

    nic nat: {
        attached_to: "internet"
    }

    nic server_side: {
        attached_to: "LAN"
        mac: "52:54:00:00:00:AA"
    }
}

machine server {
    cpus: 1
    ram: 512Mb
    disk main: {
        size: 5Gb
    }
    iso: "${ISO_DIR}\\ubuntu_server.iso"

    nic nat: {
        attached_to: "internet"
    }

    nic client_side: {
        attached_to: "LAN"
        mac: "52:54:00:00:00:BB"
    }
}

You can see that we added the mac subattribute to the "internal" NICs. Knowing the exact mac will play its role a little later, when we'll do renaming NICs inside the OS (so we can distinguish them easily).

Of course, the new client machine needs a couple of preparatory tests of its own: client_install_ubuntu, client_prepare and client_install_guest_additions. Don't forget to add a couple of new params:

param client_hostname "client"
param client_login "client-login"

test client_install_ubuntu {
    client {
        start
        # The actions can be separated with a newline
        # or a semicolon
        wait "Install Ubuntu Server"; press Enter;
        wait "Choose the language"; press Enter
        wait "Select your location"; press Enter
        wait "Detect keyboard layout?"; press Enter
        wait "Country of origin for the keyboard"; press Enter
        wait "Keyboard layout"; press Enter
        #wait "No network interfaces detected" timeout 5m; press Enter
        wait "Hostname:" timeout 5m; press Backspace*36; type "${client_hostname}"; press Enter
        wait "Full name for the new user"; type "${client_login}"; press Enter
        wait "Username for your account"; press Enter
        wait "Choose a password for the new user"; type "${default_password}"; press Enter
        wait "Re-enter password to verify"; type "${default_password}"; press Enter
        wait "Use weak password?"; press Left, Enter
        wait "Encrypt your home directory?"; press Enter

        wait "Is this time zone correct?" timeout 2m; press Enter
        wait "Partitioning method"; press Enter
        wait "Select disk to partition"; press Enter
        wait "Write the changes to disks and configure LVM?"; press Left, Enter
        wait "Amount of volume group to use for guided partitioning"; press Enter
        wait "Force UEFI installation?"; press Left, Enter
        wait "Write the changes to disks?"; press Left, Enter
        wait "HTTP proxy information" timeout 3m; press Enter
        wait "How do you want to manage upgrades" timeout 6m; press Enter
        wait "Choose software to install"; press Enter
        wait "Installation complete" timeout 30m;

        unplug dvd; press Enter
        wait "login:" timeout 2m; type "${client_login}"; press Enter
        wait "Password:"; type "${default_password}"; press Enter
        wait "Welcome to Ubuntu"
    }
}

test client_prepare: client_install_ubuntu {
    client {
        # Enter sudo mode
        type "sudo su"; press Enter
        wait "password for ${client_login}"; type "${default_password}"; press Enter
        wait "root@${client_hostname}"

        # Reset the eth0 NIC to prevent any issues with it after the rollback
        type "dhclient -r eth0 && dhclient eth0 && echo Result is $?"; press Enter

        # Check that apt is OK
        type "clear && apt update && echo Result is $?"; press Enter
        wait "Result is 0"

        # Install linux-azure package
        type "clear && apt install -y linux-azure && echo Result is $?"; press Enter
        wait "Result is 0" timeout 15m      

        # Reboot and login
        type "reboot"; press Enter

        wait "login:" timeout 2m; type "${client_login}"; press Enter
        wait "Password:"; type "${default_password}"; press Enter
        wait "Welcome to Ubuntu"

        # Enter sudo once more
        type "sudo su"; press Enter;
        wait "password for ${client_login}"; type "${default_password}"; press Enter
        wait "root@${client_hostname}"

        # Load the hv_sock module
        type "clear && modprobe hv_sock && echo Result is $?"; press Enter;
        wait "Result is 0"

        type "clear && lsmod | grep hv"; press Enter
        wait "hv_sock"
    }
}

test client_install_guest_additions: client_prepare {
    client {
        plug dvd "${ISO_DIR}\\testo-guest-additions-hyperv.iso"

        type "mount /dev/cdrom /media"; press Enter
        wait "mounting read-only"
        type "clear && dpkg -i /media/${guest_additions_pkg} && echo Result is $?"; press Enter;
        wait "Result is 0"
        type "clear && umount /media && echo Result is $?"; press Enter;
        wait "Result is 0"
        sleep 2s
        unplug dvd
    }
}

We can see a lot of duplicate code, but we shouldn't fret about that. Later we'll learn about macros, which allow to group up frequently-used actions into named blocks, and our sript will get much shorter.

Now let's run our script.

C:\Users\Testo> testo run ping.testo --stop_on_fail --param ISO_DIR C:\iso
Because of the cache loss, Testo is scheduled to run the following tests:
- server_install_ubuntu
- server_prepare
- server_install_guest_additions
Do you confirm running them? [y/N]: y
TESTS TO RUN:
server_install_ubuntu
server_prepare
server_install_guest_additions
client_install_ubuntu
client_prepare
client_install_guest_additions
[ 0%] Preparing the environment for test server_install_ubuntu
[ 0%] Creating virtual machine server
[ 0%] Taking snapshot initial for virtual machine server
[ 0%] Running test server_install_ubuntu
[ 0%] Starting virtual machine server
[ 0%] Waiting "Install Ubuntu Server" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Choose the language" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Select your location" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Detect keyboard layout?" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Country of origin for the keyboard" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Keyboard layout" for 1m with interval 1s in virtual machine server
[ 0%] Pressing key ENTER in virtual machine server
[ 0%] Waiting "Hostname:" for 5m with interval 1s in virtual machine server
C:/Users/Testo/ping.testo:63:3: Error while performing action wait "Hostname:" timeout 5m on virtual machine server
- Timeout

C:/Users/Testo/ng.testo:29:1: note: the virtual machine server was declared here

[ 17%] Test server_install_ubuntu FAILED in 0h:5m:14s
C:\Users\Testo>

Look at that: Ubunstu installation broke up. Again. Why? Because now we have multiple NICs plugged into the virtual machine, so we get a new screen we haven't been expecting in the test script:

Primary NIC

The primary interface is listed at the top, so we just need to press Enter. Let's adjust our test script a little.

wait "Keyboard layout"; press Enter
#wait "No network interfaces detected" timeout 5m; press Enter
wait "Primary network interface"; press Enter
wait "Hostname:" timeout 5m; press Backspace*36; type "${server_hostname}"; press Enter

Run the script again, and now all the tests should pass successfully.

Renaming NICs inside the OS

By default, the NICs are given pretty uninformative names inside the OS (ens3, ens4 and so on). Of course it would be much more convenient if we had them named accordingly to their names in the virtual machine declaration: client_side, server side and so on. We can actually achieve that with renaming NICs inside the OS based on the MAC, which we already know.

Renaming can be done with (for example), the following bash-script (download link is available at the end of the guide).

#!/bin/bash

set -e

mac=$1

oldname=`ifconfig -a | grep ${mac,,} | awk '{print $1}'`
newname=$2

echo SUBSYSTEM==\"net\", ACTION==\"add\", ATTR{address}==\"$mac\", NAME=\"$newname\", DRIVERS==\"?*\" >> /lib/udev/rules.d/70-test-tools.rules

rm -f /etc/network/interfaces
echo source /etc/network/interfaces.d/* >> /etc/network/interfaces
echo auto lo >> /etc/network/interfaces
echo iface lo inet loopback >> /etc/network/interfaces

ip link set $oldname down
ip link set $oldname name $newname
ip link set $newname up

echo "Renaming success"

Save this script in the rename_net.sh file in the same folder where the ping.testo file is located.

And write a test to use this script inside the server:

test server_setup_nic: server_install_guest_additions {
    server {
        copyto ".\\rename_net.sh" "/opt/rename_net.sh"
        exec bash """
            chmod +x /opt/rename_net.sh
            /opt/rename_net.sh 52:54:00:00:00:bb client_side
            ip ad
        """
    }
}
C:\Users\Testo> testo run ping.testo --stop_on_fail --param ISO_DIR C:\iso --test_spec server_setup_nic
UP-TO-DATE TESTS:
server_install_ubuntu
server_prepare
server_install_guest_additions
TESTS TO RUN:
server_setup_nic
[ 75%] Preparing the environment for test server_setup_nic
[ 75%] Restoring snapshot server_install_guest_additions for virtual machine server
[ 75%] Running test server_setup_nic
[ 75%] Copying C:/Users/Testo/rename_net.sh to virtual machine server to destination /opt/rename_net.sh with timeout 10m
[ 75%] Executing bash command in virtual machine server with timeout 10m
+ chmod +x /opt/rename_net.sh
+ /opt/rename_net.sh 52:54:00:00:00:bb client_side
Renaming success
+ ip ad
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc mq state DOWN group default qlen 1000

link/ether 00:15:5d:01:25:15 brd ff:ff:ff:ff:ff:ff
inet 172.17.172.120/28 brd 172.17.172.127 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::215:5dff:fe01:2515/64 scope link
valid_lft forever preferred_lft
forever
3: client_side: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc mq state DOWN group default qlen 1000
link/ether 52:54:00:00:00:bb brd ff:ff:ff:ff:ff:ff
[ 75%] Taking snapshot server_setup_nic for virtual machine server
[100%] Test server_setup_nic PASSED in 0h:0m:4s
PROCESSED TOTAL 4 TESTS IN 0h:0m:4s
UP-TO-DATE: 3
RUN SUCCESSFULLY: 1
FAILED: 0
C:\Users\Testo>

In the ip command output we can see that the remaining NIC is named clear and neat: client_side.

Now we need to setup the IP-address for the NIC:

test server_setup_nic: server_install_guest_additions {
    server {
        copyto ".\\rename_net.sh" "/opt/rename_net.sh"
        exec bash """
            chmod +x /opt/rename_net.sh
            /opt/rename_net.sh 52:54:00:00:00:bb client_side
            ip a a 192.168.1.1/24 dev client_side
            ip l s client_side up
            ip ad
        """
    }
}

And repeat all these steps with the client virtual machine.

C:\Users\Testo> testo run ping.testo --stop_on_fail --param ISO_DIR C:\iso
Because of the cache loss, Testo is scheduled to run the following tests:
- server_setup_nic
Do you confirm running them? [y/N]: y
UP-TO-DATE TESTS:
server_install_ubuntu
server_prepare
server_install_guest_additions
client_install_ubuntu
client_prepare
client_install_guest_additions
TESTS TO RUN:
server_setup_nic
client_setup_nic
[ 75%] Preparing the environment for test server_setup_nic
[ 75%] Restoring snapshot server_install_guest_additions for virtual machine server
[ 75%] Running test server_setup_nic
[ 75%] Copying C:/Users/Testo/rename_net.sh to virtual machine server to destination /opt/rename_net.sh with timeout 10m
[ 75%] Executing bash command in virtual machine server with timeout 10m
+ chmod +x /opt/rename_net.sh
+ /opt/rename_net.sh 52:54:00:00:00:bb client_side
Renaming success
+ ip a a 192.168.1.1/24 dev client_side
+ ip l s client_side up
+ ip ad
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen
1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <NO-CARRIER,BROADCAST,MU
LTICAST,UP> mtu 1500 qdisc mq state DOWN group default qlen 1000
link/ether 00:15:5d:01:25:15 brd ff:ff:ff:ff:ff:ff
inet 172.17.172.120/28 brd 172.17.172.127 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::215:5dff:
fe01:2515/64 scope link
valid_lft forever preferred_lft forever
3: client_side: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc mq state DOWN group default qlen 1000
link/ether 52:54:00:00:00:bb brd ff:ff:ff:ff:ff:ff
inet 192.168.1.1/24
scope global client_side
valid_lft forever preferred_lft forever
[ 75%] Taking snapshot server_setup_nic for virtual machine server
[ 88%] Test server_setup_nic PASSED in 0h:0m:5s
[ 88%] Preparing the environment for test client_setup_nic
[ 88%] Restoring snapshot client_install_guest_additions for virtual machine client
[ 88%] Running test client_setup_nic
[ 88%] Copying C:/Users/Testo/rename_net.sh to virtual machine client to destination /opt/rename_net.sh with timeout 10m
[ 88%] Executing bash command in virtual machine client with timeout 10m
+ chmod +x /opt/rename_net.sh
+ /opt/rename_net.sh 52:54:00:00:00:aa server_side
Renaming success
+ ip a a 192.168.1.2/24 dev server_side
+ ip l s server_side up
+ ip ad
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen
1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0: <NO-CARRIER,BROADCAST,MU
LTICAST,UP> mtu 1500 qdisc mq state DOWN group default qlen 1000
link/ether 00:15:5d:01:25:16 brd ff:ff:ff:ff:ff:ff
inet 172.17.172.116/28 brd 172.17.172.127 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::215:5dff:
fe01:2516/64 scope link
valid_lft forever preferred_lft forever
3: server_side: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc mq state DOWN group default qlen 1000
link/ether 52:54:00:00:00:aa brd ff:ff:ff:ff:ff:ff
inet 192.168.1.2/24
scope global server_side
valid_lft forever preferred_lft forever
[ 88%] Taking snapshot client_setup_nic for virtual machine client
[100%] Test client_setup_nic PASSED in 0h:0m:5s
PROCESSED TOTAL 8 TESTS IN 0h:0m:10s
UP-TO-DATE: 6
RUN SUCCESSFULLY: 2
FAILED: 0
C:\Users\Testo>

Pinging!

Finally, all things are set up and we can check that client and server can ping each other.

Create one last test test_ping which, unlike the previous tests, has two parent-tests: client_prepare and server_prepare. We need both these tests to complete successfully to begin the ping testing.

test test_ping: client_setup_nic, server_setup_nic {
    client exec bash "ping 192.168.1.2 -c5"
    server exec bash "ping 192.168.1.1 -c5"
}

Final script run

C:\Users\Testo> testo run ping.testo --stop_on_fail --param ISO_DIR C:\iso --test_spec test_ping
UP-TO-DATE TESTS:
server_install_ubuntu
server_prepare
server_install_guest_additions
server_setup_nic
client_install_ubuntu
client_prepare
client_install_guest_additions
client_setup_nic
TESTS TO RUN:
test_ping
[ 89%] Preparing the environment for test test_ping
[ 89%] Restoring snapshot server_setup_nic for virtual machine server
[ 89%] Restoring snapshot client_setup_nic for virtual machine client
[ 89%] Running test test_ping
[ 89%] Executing bash command in virtual machine client with timeout 10m
+ ping 192.168.1.2 -c5
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.023 ms
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=0.032 ms
64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=0.027 ms
64
bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=0.029 ms
64 bytes from 192.168.1.2: icmp_seq=5 ttl=64 time=0.025 ms

--- 192.168.1.2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4093ms
rtt min/avg/max/mdev = 0.023/0.027/0.032/
0.004 ms
[ 89%] Executing bash command in virtual machine server with timeout 10m
+ ping 192.168.1.1 -c5
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.015 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.028 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.024 ms
64
bytes from 192.168.1.1: icmp_seq=4 ttl=64 time=0.031 ms
64 bytes from 192.168.1.1: icmp_seq=5 ttl=64 time=0.030 ms

--- 192.168.1.1 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4085ms
rtt min/avg/max/mdev = 0.015/0.025/0.031/
0.008 ms
[ 89%] Taking snapshot test_ping for virtual machine server
[ 89%] Taking snapshot test_ping for virtual machine client
[100%] Test test_ping PASSED in 0h:0m:17s
PROCESSED TOTAL 9 TESTS IN 0h:0m:17s
UP-TO-DATE: 8
RUN SUCCESSFULLY: 1
FAILED: 0
C:\Users\Testo>

We can see that the ping command runs great, which means that we managed to setup a test bench with two linked up virtual machines!

Conclusions

Virtual networks can be used not only to gain the Internet access, but to link up virtual machines with each other as well.

Testo Framework allows you to develop preparatory tests with the Internet access and then unplug the NIC leading to the Internet if the Internet is not needed anymore. This way you can reduce the redundant Internet connections, that can possibly mess up the test cases.

You can simplify the NICs distibguishing inside the test scripts by assigning fixed MAC-addresses to the NICs and then renaming them inside the OS to your linking.

Tests hierarchy looks like this at the moment:

You can find the complete test scripts and NIC-renaming bash script here.