diff mbox

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

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

Commit Message

Thomas Huth March 14, 2017, 10:23 a.m. UTC
To be able to do simple migration tests with kvm-unit-tests, too,
add a helper script 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 script 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                      |  4 +++
 scripts/qemu-migration-helper.sh | 68 ++++++++++++++++++++++++++++++++++++++++
 scripts/runtime.bash             |  3 ++
 3 files changed, 75 insertions(+)
 create mode 100755 scripts/qemu-migration-helper.sh

Comments

Radim Krčmář March 15, 2017, 4:36 p.m. UTC | #1
2017-03-14 11:23+0100, Thomas Huth:
> To be able to do simple migration tests with kvm-unit-tests, too,
> add a helper script 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 script 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                      |  4 +++
>  scripts/qemu-migration-helper.sh | 68 ++++++++++++++++++++++++++++++++++++++++
>  scripts/runtime.bash             |  3 ++
>  3 files changed, 75 insertions(+)
>  create mode 100755 scripts/qemu-migration-helper.sh
> 
> diff --git a/powerpc/run b/powerpc/run
> index 6269abb..f1528ed 100755
> --- a/powerpc/run
> +++ b/powerpc/run
> @@ -41,6 +41,10 @@ if ! $qemu -machine '?' 2>&1 | grep 'pseries' > /dev/null; then
>  	exit 2
>  fi
>  
> +if [ "$MIGRATION" = "yes" ]; then
> +	qemu="scripts/qemu-migration-helper.sh $qemu"
> +fi

I think this script could be useful for other architectures as well ...
what about adding migration_cmd to scripts/arch-run.bash

  migration_cmd ()
  {
  	if [ "$MIGRATION" = "yes" ]; then
  		echo "scripts/qemu-migration-helper.sh"
  	fi
  }

and using only

  command="$(timeout_cmd) $(migration_cmd) $command"

in arch scripts?

> +
>  M='-machine pseries'
>  M+=",accel=$ACCEL"
>  command="$qemu -nodefaults $M -bios $FIRMWARE"
> diff --git a/scripts/qemu-migration-helper.sh b/scripts/qemu-migration-helper.sh
> new file mode 100755
> index 0000000..5842026
> --- /dev/null
> +++ b/scripts/qemu-migration-helper.sh

This doesn't seem to work with standalone tests, because they don't
bundle scripts/qemu-migration-helper.sh ...

Any reason why we couldn't turn it into a

  qemu-migration-helper () {
    ...
  }

wrapper (likely inside scripts/arch-run.bash), so it would get sourced
into the standalone test?

> @@ -0,0 +1,68 @@
> +#!/bin/bash
> +# This script runs two instances of QEMU and then migrates the guest from one
> +# instance to the other. The end of the migration is signalled to the guest by
> +# injecting an NMI.
> +
> +if ! command -v nc >/dev/null 2>&1; then
> +	echo "$0 needs nc (netcat)"
> +	exit 1
> +fi
> +
> +qemu=$1
> +shift
> +
> +if ! command -v "$qemu" >/dev/null 2>&1; then
> +	echo "The first parameter must be pointing to the QEMU executable"
> +	exit 1
> +fi
> +
> +migsock=`mktemp -u -t mig-helper-socket.XXXXXXXXXX`
> +stdout1=`mktemp -t mig-helper-stdout1.XXXXXXXXXX`
> +stdout2=`mktemp -t mig-helper-stdout2.XXXXXXXXXX`
> +qmpout1=`mktemp -t mig-helper-qmpout1.XXXXXXXXXX`
> +qmpout2=`mktemp -t mig-helper-qmpout2.XXXXXXXXXX`
> +qmp1=`mktemp -u -t mig-helper-qmp1.XXXXXXXXXX`
> +qmp2=`mktemp -u -t mig-helper-qmp2.XXXXXXXXXX`
> +
> +cleanup()
> +{
> +	rm -f ${stdout1} ${stdout2} ${migsock}
> +	rm -f ${qmpout1} ${qmpout2} ${qmp1} ${qmp2}
> +}
> +trap cleanup EXIT
> +
> +qmp_cmd()
> +{
> +	echo '{ "execute": "qmp_capabilities" }{ "execute":' "$2" '}' | nc -U $1
> +}
> +
> +$qemu $* -chardev socket,id=mon1,path=${qmp1},server,nowait \

I have a bad feeling about $*, please use "$@" instead.

The difference can be seen in:
  # f () { g $*; }
  # g () {echo $#; }
  # f 1 2; f "1 2"
  2
  2
  # f () { g "$@"; }
  # f 1 2; f "1 2"
  2
  1

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

qmpout* seems unused ... couldn't we just redirect to /dev/null?

> +
> +wait
> +
> +cat ${stdout1} ${stdout2}

The test might hang and we would never see its output ...
I think that stdout1 could be duplicated using a crazy technique similar
to what run_qemu() uses.  And do we need to capture stdout2 at all?

Thanks.
Thomas Huth March 20, 2017, 2:02 p.m. UTC | #2
On 15.03.2017 17:36, Radim Krčmář wrote:
> 2017-03-14 11:23+0100, Thomas Huth:
>> To be able to do simple migration tests with kvm-unit-tests, too,
>> add a helper script 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 script 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                      |  4 +++
>>  scripts/qemu-migration-helper.sh | 68 ++++++++++++++++++++++++++++++++++++++++
>>  scripts/runtime.bash             |  3 ++
>>  3 files changed, 75 insertions(+)
>>  create mode 100755 scripts/qemu-migration-helper.sh
>>
>> diff --git a/powerpc/run b/powerpc/run
>> index 6269abb..f1528ed 100755
>> --- a/powerpc/run
>> +++ b/powerpc/run
>> @@ -41,6 +41,10 @@ if ! $qemu -machine '?' 2>&1 | grep 'pseries' > /dev/null; then
>>  	exit 2
>>  fi
>>  
>> +if [ "$MIGRATION" = "yes" ]; then
>> +	qemu="scripts/qemu-migration-helper.sh $qemu"
>> +fi
> 
> I think this script could be useful for other architectures as well ...
> what about adding migration_cmd to scripts/arch-run.bash
> 
>   migration_cmd ()
>   {
>   	if [ "$MIGRATION" = "yes" ]; then
>   		echo "scripts/qemu-migration-helper.sh"
>   	fi
>   }
> 
> and using only
> 
>   command="$(timeout_cmd) $(migration_cmd) $command"
> 
> in arch scripts?

Yes, sounds like a good idea, I'll change my patch accordingly.

>> +
>>  M='-machine pseries'
>>  M+=",accel=$ACCEL"
>>  command="$qemu -nodefaults $M -bios $FIRMWARE"
>> diff --git a/scripts/qemu-migration-helper.sh b/scripts/qemu-migration-helper.sh
>> new file mode 100755
>> index 0000000..5842026
>> --- /dev/null
>> +++ b/scripts/qemu-migration-helper.sh
> 
> This doesn't seem to work with standalone tests, because they don't
> bundle scripts/qemu-migration-helper.sh ...
> 
> Any reason why we couldn't turn it into a
> 
>   qemu-migration-helper () {
>     ...
>   }
> 
> wrapper (likely inside scripts/arch-run.bash), so it would get sourced
> into the standalone test?

Oh, well, I've completely forgot about that standalone test feature ...
I'll have a look...

>> @@ -0,0 +1,68 @@
>> +#!/bin/bash
>> +# This script runs two instances of QEMU and then migrates the guest from one
>> +# instance to the other. The end of the migration is signalled to the guest by
>> +# injecting an NMI.
>> +
>> +if ! command -v nc >/dev/null 2>&1; then
>> +	echo "$0 needs nc (netcat)"
>> +	exit 1
>> +fi
>> +
>> +qemu=$1
>> +shift
>> +
>> +if ! command -v "$qemu" >/dev/null 2>&1; then
>> +	echo "The first parameter must be pointing to the QEMU executable"
>> +	exit 1
>> +fi
>> +
>> +migsock=`mktemp -u -t mig-helper-socket.XXXXXXXXXX`
>> +stdout1=`mktemp -t mig-helper-stdout1.XXXXXXXXXX`
>> +stdout2=`mktemp -t mig-helper-stdout2.XXXXXXXXXX`
>> +qmpout1=`mktemp -t mig-helper-qmpout1.XXXXXXXXXX`
>> +qmpout2=`mktemp -t mig-helper-qmpout2.XXXXXXXXXX`
>> +qmp1=`mktemp -u -t mig-helper-qmp1.XXXXXXXXXX`
>> +qmp2=`mktemp -u -t mig-helper-qmp2.XXXXXXXXXX`
>> +
>> +cleanup()
>> +{
>> +	rm -f ${stdout1} ${stdout2} ${migsock}
>> +	rm -f ${qmpout1} ${qmpout2} ${qmp1} ${qmp2}
>> +}
>> +trap cleanup EXIT
>> +
>> +qmp_cmd()
>> +{
>> +	echo '{ "execute": "qmp_capabilities" }{ "execute":' "$2" '}' | nc -U $1
>> +}
>> +
>> +$qemu $* -chardev socket,id=mon1,path=${qmp1},server,nowait \
> 
> I have a bad feeling about $*, please use "$@" instead.

Sure, will do.

>> +	 -mon chardev=mon1,mode=control > ${stdout1} &
>> +
>> +$qemu $* -chardev socket,id=mon2,path=${qmp2},server,nowait \
>> +	 -mon chardev=mon2,mode=control -incoming unix:${migsock} > ${stdout2} &
>> +
>> +# The test must prompt the user to migrate, so wait for the "migrate" keyword
>> +while ! grep -q -i "migrate" < ${stdout1} ; do
>> +	sleep 1
>> +done
>> +
>> +qmp_cmd ${qmp1} '"migrate", "arguments": { "uri": "unix:'${migsock}'" }' > ${qmpout1}
>> +
>> +# Wait for the migration to complete
>> +migstatus=`qmp_cmd ${qmp1} '"query-migrate"' | grep return`
>> +while ! grep -q '"completed"' <<<"$migstatus" ; do
>> +	sleep 1
>> +	migstatus=`qmp_cmd ${qmp1} '"query-migrate"' | grep return`
>> +	if grep -q '"failed"' <<<"$migstatus" ; then
>> +		echo "ERROR: Migration failed."
>> +		exit 1
>> +	fi
>> +done
>> +qmp_cmd ${qmp1} '"quit"'> ${qmpout1} 2>/dev/null
>> +
>> +qmp_cmd ${qmp2} '"inject-nmi"'> ${qmpout2}
> 
> qmpout* seems unused ... couldn't we just redirect to /dev/null?

It's useful for debugging (you just got to make sure that it does not
get deleted at the end)... but I could also set the variables to
/dev/null instead, so the output gets written there by default.

>> +
>> +wait
>> +
>> +cat ${stdout1} ${stdout2}
> 
> The test might hang and we would never see its output ...
> I think that stdout1 could be duplicated using a crazy technique similar
> to what run_qemu() uses.  And do we need to capture stdout2 at all?

At least on ppc, we need both outputs, since the return code of the test
is finally passed via the console output there. But I'll see whether I
can come up with something better here instead...

Thanks for the review!

 Thomas
diff mbox

Patch

diff --git a/powerpc/run b/powerpc/run
index 6269abb..f1528ed 100755
--- a/powerpc/run
+++ b/powerpc/run
@@ -41,6 +41,10 @@  if ! $qemu -machine '?' 2>&1 | grep 'pseries' > /dev/null; then
 	exit 2
 fi
 
+if [ "$MIGRATION" = "yes" ]; then
+	qemu="scripts/qemu-migration-helper.sh $qemu"
+fi
+
 M='-machine pseries'
 M+=",accel=$ACCEL"
 command="$qemu -nodefaults $M -bios $FIRMWARE"
diff --git a/scripts/qemu-migration-helper.sh b/scripts/qemu-migration-helper.sh
new file mode 100755
index 0000000..5842026
--- /dev/null
+++ b/scripts/qemu-migration-helper.sh
@@ -0,0 +1,68 @@ 
+#!/bin/bash
+# This script runs two instances of QEMU and then migrates the guest from one
+# instance to the other. The end of the migration is signalled to the guest by
+# injecting an NMI.
+
+if ! command -v nc >/dev/null 2>&1; then
+	echo "$0 needs nc (netcat)"
+	exit 1
+fi
+
+qemu=$1
+shift
+
+if ! command -v "$qemu" >/dev/null 2>&1; then
+	echo "The first parameter must be pointing to the QEMU executable"
+	exit 1
+fi
+
+migsock=`mktemp -u -t mig-helper-socket.XXXXXXXXXX`
+stdout1=`mktemp -t mig-helper-stdout1.XXXXXXXXXX`
+stdout2=`mktemp -t mig-helper-stdout2.XXXXXXXXXX`
+qmpout1=`mktemp -t mig-helper-qmpout1.XXXXXXXXXX`
+qmpout2=`mktemp -t mig-helper-qmpout2.XXXXXXXXXX`
+qmp1=`mktemp -u -t mig-helper-qmp1.XXXXXXXXXX`
+qmp2=`mktemp -u -t mig-helper-qmp2.XXXXXXXXXX`
+
+cleanup()
+{
+	rm -f ${stdout1} ${stdout2} ${migsock}
+	rm -f ${qmpout1} ${qmpout2} ${qmp1} ${qmp2}
+}
+trap cleanup EXIT
+
+qmp_cmd()
+{
+	echo '{ "execute": "qmp_capabilities" }{ "execute":' "$2" '}' | nc -U $1
+}
+
+$qemu $* -chardev socket,id=mon1,path=${qmp1},server,nowait \
+	 -mon chardev=mon1,mode=control > ${stdout1} &
+
+$qemu $* -chardev socket,id=mon2,path=${qmp2},server,nowait \
+	 -mon chardev=mon2,mode=control -incoming unix:${migsock} > ${stdout2} &
+
+# The test must prompt the user to migrate, so wait for the "migrate" keyword
+while ! grep -q -i "migrate" < ${stdout1} ; do
+	sleep 1
+done
+
+qmp_cmd ${qmp1} '"migrate", "arguments": { "uri": "unix:'${migsock}'" }' > ${qmpout1}
+
+# Wait for the migration to complete
+migstatus=`qmp_cmd ${qmp1} '"query-migrate"' | grep return`
+while ! grep -q '"completed"' <<<"$migstatus" ; do
+	sleep 1
+	migstatus=`qmp_cmd ${qmp1} '"query-migrate"' | grep return`
+	if grep -q '"failed"' <<<"$migstatus" ; then
+		echo "ERROR: Migration failed."
+		exit 1
+	fi
+done
+qmp_cmd ${qmp1} '"quit"'> ${qmpout1} 2>/dev/null
+
+qmp_cmd ${qmp2} '"inject-nmi"'> ${qmpout2}
+
+wait
+
+cat ${stdout1} ${stdout2}
diff --git a/scripts/runtime.bash b/scripts/runtime.bash
index 9c1bc3b..f58eb4e 100644
--- a/scripts/runtime.bash
+++ b/scripts/runtime.bash
@@ -98,6 +98,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