diff mbox

[kvm-unit-tests,v3,1/2] Add the possibility to do simple migration tests

Message ID 1490029932-19862-2-git-send-email-thuth@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Thomas Huth March 20, 2017, 5:12 p.m. UTC
To be able to do simple migration tests with kvm-unit-tests, too,
add a helper function that does all the necessary work: Start two
instances of QEMU (source and destination) with QMP sockets for
sending commands to them, then trigger the migration from one
instance to the other and finally signal the end of the migration
to the guest by injecting an NMI.
This helper function is now used automatically for powerpc tests
if the test is put into the "migration" group in the unittests.cfg
file.

Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 powerpc/run           |  2 +-
 scripts/arch-run.bash | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++
 scripts/runtime.bash  |  3 +++
 3 files changed, 65 insertions(+), 1 deletion(-)

Comments

Andrew Jones March 21, 2017, 12:39 p.m. UTC | #1
On Mon, Mar 20, 2017 at 06:12:11PM +0100, Thomas Huth wrote:
> To be able to do simple migration tests with kvm-unit-tests, too,
> add a helper function that does all the necessary work: Start two
> instances of QEMU (source and destination) with QMP sockets for
> sending commands to them, then trigger the migration from one
> instance to the other and finally signal the end of the migration
> to the guest by injecting an NMI.
> This helper function is now used automatically for powerpc tests
> if the test is put into the "migration" group in the unittests.cfg
> file.
> 
> Signed-off-by: Thomas Huth <thuth@redhat.com>
> ---
>  powerpc/run           |  2 +-
>  scripts/arch-run.bash | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  scripts/runtime.bash  |  3 +++
>  3 files changed, 65 insertions(+), 1 deletion(-)
> 
> diff --git a/powerpc/run b/powerpc/run
> index 6269abb..d92608e 100755
> --- a/powerpc/run
> +++ b/powerpc/run
> @@ -46,7 +46,7 @@ M+=",accel=$ACCEL"
>  command="$qemu -nodefaults $M -bios $FIRMWARE"
>  [ -f "$ENV" ] && command+=" -initrd $ENV"
>  command+=" -display none -serial stdio -kernel"
> -command="$(timeout_cmd) $command"
> +command="$(migration_cmd) $(timeout_cmd) $command"
>  echo $command "$@"
>  
>  # powerpc tests currently exit with rtas-poweroff, which exits with 0.
> diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash
> index 1610f3b..453ae1c 100644
> --- a/scripts/arch-run.bash
> +++ b/scripts/arch-run.bash
> @@ -70,3 +70,64 @@ timeout_cmd ()
>  		echo "timeout -k 1s --foreground $TIMEOUT"
>  	fi
>  }
> +
> +qmp ()
> +{

Let's put the nc probe here, and instead of saying $0 needs nc, we can
say which specific function with $FUNCNAME, i.e.

 command -v nc >/dev/null 2>&1 || (echo "$FUNCNAME needs nc (netcat)"; exit 1)

We could also cache the results of the probe, if we don't want to do it on
every invocation of qmp()

> +	echo '{ "execute": "qmp_capabilities" }{ "execute":' "$2" '}' | nc -U $1
> +}
> +
> +run_migration ()
> +{
> +	if ! command -v nc >/dev/null 2>&1; then
> +		echo "$0 needs nc (netcat)"
> +		exit 1
> +	fi

With the above change we can remove this.

> +
> +	qemu=$1
> +	shift
> +
> +	migsock=`mktemp -u -t mig-helper-socket.XXXXXXXXXX`
> +	migout1=`mktemp -t mig-helper-stdout1.XXXXXXXXXX`
> +	qmp1=`mktemp -u -t mig-helper-qmp1.XXXXXXXXXX`
> +	qmp2=`mktemp -u -t mig-helper-qmp2.XXXXXXXXXX`
> +	qmpout1=/dev/null
> +	qmpout2=/dev/null
> +
> +	trap 'rm -f ${migout1} ${migsock} ${qmp1} ${qmp2}' EXIT
> +
> +	$qemu "$@" -chardev socket,id=mon1,path=${qmp1},server,nowait \
> +		 -mon chardev=mon1,mode=control | tee ${migout1} &
> +
> +	$qemu "$@" -chardev socket,id=mon2,path=${qmp2},server,nowait \
> +		 -mon chardev=mon2,mode=control -incoming unix:${migsock} &
> +
> +	# The test must prompt the user to migrate, so wait for the "migrate" keyword
> +	while ! grep -q -i "migrate" < ${migout1} ; do
> +		sleep 1
> +	done
> +
> +	qmp ${qmp1} '"migrate", "arguments": { "uri": "unix:'${migsock}'" }' > ${qmpout1}
> +
> +	# Wait for the migration to complete
> +	migstatus=`qmp ${qmp1} '"query-migrate"' | grep return`
> +	while ! grep -q '"completed"' <<<"$migstatus" ; do
> +		sleep 1
> +		migstatus=`qmp ${qmp1} '"query-migrate"' | grep return`
> +		if grep -q '"failed"' <<<"$migstatus" ; then
> +			echo "ERROR: Migration failed."
> +			exit 1
> +		fi
> +	done
> +	qmp ${qmp1} '"quit"'> ${qmpout1} 2>/dev/null
> +
> +	qmp ${qmp2} '"inject-nmi"'> ${qmpout2}

This script mostly works for ARM, except this part. The ARM processor
types we currently care about in kvm-unit-tests are ARMv7 and ARMv8.
While ARMv7 processors may support non-maskable FIQs, ARMv8 processors
can not. So, I don't believe it will ever make sense to implement
inject-nmi for ARMv8 processors, and thus when we want this to work with
ARM unit tests we'll need a different way to inform the unit test that
migration has completed.

That said, I'm OK with the patch going in now, as it works for both
ppc and x86.

Thanks,
drew

> +
> +	wait
> +}
> +
> +migration_cmd ()
> +{
> +	if [ "$MIGRATION" = "yes" ]; then
> +		echo "run_migration"
> +	fi
> +}
> diff --git a/scripts/runtime.bash b/scripts/runtime.bash
> index 98f1835..e630279 100644
> --- a/scripts/runtime.bash
> +++ b/scripts/runtime.bash
> @@ -99,6 +99,9 @@ function run()
>      }
>  
>      cmdline=$(get_cmdline $kernel)
> +    if grep -qw "migration" <<<$groups ; then
> +        cmdline="MIGRATION=yes $cmdline"
> +    fi
>      if [ "$verbose" = "yes" ]; then
>          echo $cmdline
>      fi
> -- 
> 1.8.3.1
>
Thomas Huth March 22, 2017, 3:15 a.m. UTC | #2
On 21.03.2017 13:39, Andrew Jones wrote:
> On Mon, Mar 20, 2017 at 06:12:11PM +0100, Thomas Huth wrote:
>> To be able to do simple migration tests with kvm-unit-tests, too,
>> add a helper function that does all the necessary work: Start two
>> instances of QEMU (source and destination) with QMP sockets for
>> sending commands to them, then trigger the migration from one
>> instance to the other and finally signal the end of the migration
>> to the guest by injecting an NMI.
>> This helper function is now used automatically for powerpc tests
>> if the test is put into the "migration" group in the unittests.cfg
>> file.
>>
>> Signed-off-by: Thomas Huth <thuth@redhat.com>
>> ---
>>  powerpc/run           |  2 +-
>>  scripts/arch-run.bash | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++
>>  scripts/runtime.bash  |  3 +++
>>  3 files changed, 65 insertions(+), 1 deletion(-)
>>
>> diff --git a/powerpc/run b/powerpc/run
>> index 6269abb..d92608e 100755
>> --- a/powerpc/run
>> +++ b/powerpc/run
>> @@ -46,7 +46,7 @@ M+=",accel=$ACCEL"
>>  command="$qemu -nodefaults $M -bios $FIRMWARE"
>>  [ -f "$ENV" ] && command+=" -initrd $ENV"
>>  command+=" -display none -serial stdio -kernel"
>> -command="$(timeout_cmd) $command"
>> +command="$(migration_cmd) $(timeout_cmd) $command"
>>  echo $command "$@"
>>  
>>  # powerpc tests currently exit with rtas-poweroff, which exits with 0.
>> diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash
>> index 1610f3b..453ae1c 100644
>> --- a/scripts/arch-run.bash
>> +++ b/scripts/arch-run.bash
>> @@ -70,3 +70,64 @@ timeout_cmd ()
>>  		echo "timeout -k 1s --foreground $TIMEOUT"
>>  	fi
>>  }
>> +
>> +qmp ()
>> +{
> 
> Let's put the nc probe here, and instead of saying $0 needs nc, we can
> say which specific function with $FUNCNAME, i.e.
> 
>  command -v nc >/dev/null 2>&1 || (echo "$FUNCNAME needs nc (netcat)"; exit 1)
> 
> We could also cache the results of the probe, if we don't want to do it on
> every invocation of qmp()

I tried to move the check to the qmp() function, as you suggested, but
that does not work as expected: The script then does not terminate
anymore! Seems like the shell is waiting for the started QEMU processes
to finish first, so I'd have to add some ugly error handling magic in
that case to kill the background QEMU processes if nc is not available.
I think it is easier if I keep the check at the beginning of
run_migration() instead.

>> +	echo '{ "execute": "qmp_capabilities" }{ "execute":' "$2" '}' | nc -U $1
>> +}
>> +
>> +run_migration ()
>> +{
>> +	if ! command -v nc >/dev/null 2>&1; then
>> +		echo "$0 needs nc (netcat)"
>> +		exit 1

I noticed that I should rather exit with "2" instead of "1" here ...
otherwise run_tests.sh does not report a FAIL here. I'll send a new
version with the fix...

>> +	fi

 Thomas
diff mbox

Patch

diff --git a/powerpc/run b/powerpc/run
index 6269abb..d92608e 100755
--- a/powerpc/run
+++ b/powerpc/run
@@ -46,7 +46,7 @@  M+=",accel=$ACCEL"
 command="$qemu -nodefaults $M -bios $FIRMWARE"
 [ -f "$ENV" ] && command+=" -initrd $ENV"
 command+=" -display none -serial stdio -kernel"
-command="$(timeout_cmd) $command"
+command="$(migration_cmd) $(timeout_cmd) $command"
 echo $command "$@"
 
 # powerpc tests currently exit with rtas-poweroff, which exits with 0.
diff --git a/scripts/arch-run.bash b/scripts/arch-run.bash
index 1610f3b..453ae1c 100644
--- a/scripts/arch-run.bash
+++ b/scripts/arch-run.bash
@@ -70,3 +70,64 @@  timeout_cmd ()
 		echo "timeout -k 1s --foreground $TIMEOUT"
 	fi
 }
+
+qmp ()
+{
+	echo '{ "execute": "qmp_capabilities" }{ "execute":' "$2" '}' | nc -U $1
+}
+
+run_migration ()
+{
+	if ! command -v nc >/dev/null 2>&1; then
+		echo "$0 needs nc (netcat)"
+		exit 1
+	fi
+
+	qemu=$1
+	shift
+
+	migsock=`mktemp -u -t mig-helper-socket.XXXXXXXXXX`
+	migout1=`mktemp -t mig-helper-stdout1.XXXXXXXXXX`
+	qmp1=`mktemp -u -t mig-helper-qmp1.XXXXXXXXXX`
+	qmp2=`mktemp -u -t mig-helper-qmp2.XXXXXXXXXX`
+	qmpout1=/dev/null
+	qmpout2=/dev/null
+
+	trap 'rm -f ${migout1} ${migsock} ${qmp1} ${qmp2}' EXIT
+
+	$qemu "$@" -chardev socket,id=mon1,path=${qmp1},server,nowait \
+		 -mon chardev=mon1,mode=control | tee ${migout1} &
+
+	$qemu "$@" -chardev socket,id=mon2,path=${qmp2},server,nowait \
+		 -mon chardev=mon2,mode=control -incoming unix:${migsock} &
+
+	# The test must prompt the user to migrate, so wait for the "migrate" keyword
+	while ! grep -q -i "migrate" < ${migout1} ; do
+		sleep 1
+	done
+
+	qmp ${qmp1} '"migrate", "arguments": { "uri": "unix:'${migsock}'" }' > ${qmpout1}
+
+	# Wait for the migration to complete
+	migstatus=`qmp ${qmp1} '"query-migrate"' | grep return`
+	while ! grep -q '"completed"' <<<"$migstatus" ; do
+		sleep 1
+		migstatus=`qmp ${qmp1} '"query-migrate"' | grep return`
+		if grep -q '"failed"' <<<"$migstatus" ; then
+			echo "ERROR: Migration failed."
+			exit 1
+		fi
+	done
+	qmp ${qmp1} '"quit"'> ${qmpout1} 2>/dev/null
+
+	qmp ${qmp2} '"inject-nmi"'> ${qmpout2}
+
+	wait
+}
+
+migration_cmd ()
+{
+	if [ "$MIGRATION" = "yes" ]; then
+		echo "run_migration"
+	fi
+}
diff --git a/scripts/runtime.bash b/scripts/runtime.bash
index 98f1835..e630279 100644
--- a/scripts/runtime.bash
+++ b/scripts/runtime.bash
@@ -99,6 +99,9 @@  function run()
     }
 
     cmdline=$(get_cmdline $kernel)
+    if grep -qw "migration" <<<$groups ; then
+        cmdline="MIGRATION=yes $cmdline"
+    fi
     if [ "$verbose" = "yes" ]; then
         echo $cmdline
     fi