[PATCH v8 12/12] tests/vm: Add workaround to consume console

Robert Foley posted 12 patches 5 years, 8 months ago
Maintainers: "Philippe Mathieu-Daudé" <philmd@redhat.com>, Fam Zheng <fam@euphon.net>, "Alex Bennée" <alex.bennee@linaro.org>
There is a newer version of this series
[PATCH v8 12/12] tests/vm: Add workaround to consume console
Posted by Robert Foley 5 years, 8 months ago
This adds support to basevm.py so that we always
drain the console chars.  This makes use of
support added in an earlier commit that allows
QEMUMachine to use the ConsoleSocket.

This is a workaround we found was needed since
there is a known issue where QEMU will hang waiting
for console characters to be consumed.

We also added the option of logging the console to a file.
LOG_CONSOLE=1 will now log the output to a file.

Signed-off-by: Robert Foley <robert.foley@linaro.org>
Reviewed-by: Peter Puhov <peter.puhov@linaro.org>
Acked-by: Alex Bennée <alex.bennee@linaro.org>
---
 tests/vm/Makefile.include |  4 ++++
 tests/vm/basevm.py        | 17 +++++++++++++++--
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include
index 8cccfaf95d..ad35c6e7a1 100644
--- a/tests/vm/Makefile.include
+++ b/tests/vm/Makefile.include
@@ -49,6 +49,7 @@ endif
 	@echo '    EXTRA_CONFIGURE_OPTS="..."'
 	@echo "    J=[0..9]*            	 - Override the -jN parameter for make commands"
 	@echo "    DEBUG=1              	 - Enable verbose output on host and interactive debugging"
+	@echo "    LOG_CONSOLE=1        	 - Log console to file in: ~/.cache/qemu-vm "
 	@echo "    V=1				 - Enable verbose ouput on host and guest commands"
 	@echo "    QEMU_LOCAL=1                 - Use QEMU binary local to this build."
 	@echo "    QEMU=/path/to/qemu		 - Change path to QEMU binary"
@@ -75,6 +76,7 @@ $(IMAGES_DIR)/%.img:	$(SRC_PATH)/tests/vm/% \
 		$(if $(GENISOIMAGE),--genisoimage $(GENISOIMAGE)) \
 		$(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \
 		$(if $(EFI_AARCH64),--efi-aarch64 $(EFI_AARCH64)) \
+		$(if $(LOG_CONSOLE),--log-console) \
 		--image "$@" \
 		--force \
 		--build-image $@, \
@@ -91,6 +93,7 @@ vm-build-%: $(IMAGES_DIR)/%.img
 		$(if $(V),--verbose) \
 		$(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \
 		$(if $(EFI_AARCH64),--efi-aarch64 $(EFI_AARCH64)) \
+		$(if $(LOG_CONSOLE),--log-console) \
 		--image "$<" \
 		$(if $(BUILD_TARGET),--build-target $(BUILD_TARGET)) \
 		--snapshot \
@@ -114,6 +117,7 @@ vm-boot-ssh-%: $(IMAGES_DIR)/%.img
 		$(if $(V)$(DEBUG), --debug) \
 		$(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \
 		$(if $(EFI_AARCH64),--efi-aarch64 $(EFI_AARCH64)) \
+		$(if $(LOG_CONSOLE),--log-console) \
 		--image "$<" \
 		--interactive \
 		false, \
diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py
index b9d828423b..64dbe64326 100644
--- a/tests/vm/basevm.py
+++ b/tests/vm/basevm.py
@@ -117,6 +117,11 @@ class BaseVM(object):
              "w").write(self._config['ssh_pub_key'])
 
         self.debug = args.debug
+        self._console_log_path = None
+        if args.log_console:
+                self._console_log_path = \
+                         os.path.join(os.path.expanduser("~/.cache/qemu-vm"),
+                                      "{}.install.log".format(self.name))
         self._stderr = sys.stderr
         self._devnull = open(os.devnull, "w")
         if self.debug:
@@ -271,7 +276,9 @@ class BaseVM(object):
         args += self._data_args + extra_args + self._config['extra_args']
         logging.debug("QEMU args: %s", " ".join(args))
         qemu_path = get_qemu_path(self.arch, self._build_path)
-        guest = QEMUMachine(binary=qemu_path, args=args)
+        guest = QEMUMachine(binary=qemu_path, args=args,
+                            console_log=self._console_log_path,
+                            drain_console=True)
         guest.set_machine(self._config['machine'])
         guest.set_console()
         try:
@@ -285,6 +292,8 @@ class BaseVM(object):
             raise
         atexit.register(self.shutdown)
         self._guest = guest
+        # Init console so we can start consuming the chars.
+        self.console_init()
         usernet_info = guest.qmp("human-monitor-command",
                                  command_line="info usernet")
         self.ssh_port = None
@@ -296,7 +305,9 @@ class BaseVM(object):
             raise Exception("Cannot find ssh port from 'info usernet':\n%s" % \
                             usernet_info)
 
-    def console_init(self, timeout = 120):
+    def console_init(self, timeout = None):
+        if timeout == None:
+            timeout = self.socket_timeout
         vm = self._guest
         vm.console_socket.settimeout(timeout)
         self.console_raw_path = os.path.join(vm._temp_dir,
@@ -578,6 +589,8 @@ def parse_args(vmcls):
     parser.add_option("--efi-aarch64",
                       default="/usr/share/qemu-efi-aarch64/QEMU_EFI.fd",
                       help="Path to efi image for aarch64 VMs.")
+    parser.add_option("--log-console", action="store_true",
+                      help="Log console to file.")
     parser.disable_interspersed_args()
     return parser.parse_args()
 
-- 
2.17.1


Re: [PATCH v8 12/12] tests/vm: Add workaround to consume console
Posted by Philippe Mathieu-Daudé 5 years, 8 months ago
On 5/29/20 10:34 PM, Robert Foley wrote:
> This adds support to basevm.py so that we always
> drain the console chars.  This makes use of
> support added in an earlier commit that allows
> QEMUMachine to use the ConsoleSocket.
> 
> This is a workaround we found was needed since
> there is a known issue where QEMU will hang waiting
> for console characters to be consumed.
> 
> We also added the option of logging the console to a file.
> LOG_CONSOLE=1 will now log the output to a file.
> 
> Signed-off-by: Robert Foley <robert.foley@linaro.org>
> Reviewed-by: Peter Puhov <peter.puhov@linaro.org>
> Acked-by: Alex Bennée <alex.bennee@linaro.org>
> ---
>  tests/vm/Makefile.include |  4 ++++
>  tests/vm/basevm.py        | 17 +++++++++++++++--
>  2 files changed, 19 insertions(+), 2 deletions(-)
> 
> diff --git a/tests/vm/Makefile.include b/tests/vm/Makefile.include
> index 8cccfaf95d..ad35c6e7a1 100644
> --- a/tests/vm/Makefile.include
> +++ b/tests/vm/Makefile.include
> @@ -49,6 +49,7 @@ endif
>  	@echo '    EXTRA_CONFIGURE_OPTS="..."'
>  	@echo "    J=[0..9]*            	 - Override the -jN parameter for make commands"
>  	@echo "    DEBUG=1              	 - Enable verbose output on host and interactive debugging"
> +	@echo "    LOG_CONSOLE=1        	 - Log console to file in: ~/.cache/qemu-vm "
>  	@echo "    V=1				 - Enable verbose ouput on host and guest commands"
>  	@echo "    QEMU_LOCAL=1                 - Use QEMU binary local to this build."
>  	@echo "    QEMU=/path/to/qemu		 - Change path to QEMU binary"
> @@ -75,6 +76,7 @@ $(IMAGES_DIR)/%.img:	$(SRC_PATH)/tests/vm/% \
>  		$(if $(GENISOIMAGE),--genisoimage $(GENISOIMAGE)) \
>  		$(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \
>  		$(if $(EFI_AARCH64),--efi-aarch64 $(EFI_AARCH64)) \
> +		$(if $(LOG_CONSOLE),--log-console) \
>  		--image "$@" \
>  		--force \
>  		--build-image $@, \
> @@ -91,6 +93,7 @@ vm-build-%: $(IMAGES_DIR)/%.img
>  		$(if $(V),--verbose) \
>  		$(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \
>  		$(if $(EFI_AARCH64),--efi-aarch64 $(EFI_AARCH64)) \
> +		$(if $(LOG_CONSOLE),--log-console) \
>  		--image "$<" \
>  		$(if $(BUILD_TARGET),--build-target $(BUILD_TARGET)) \
>  		--snapshot \
> @@ -114,6 +117,7 @@ vm-boot-ssh-%: $(IMAGES_DIR)/%.img
>  		$(if $(V)$(DEBUG), --debug) \
>  		$(if $(QEMU_LOCAL),--build-path $(BUILD_DIR)) \
>  		$(if $(EFI_AARCH64),--efi-aarch64 $(EFI_AARCH64)) \
> +		$(if $(LOG_CONSOLE),--log-console) \
>  		--image "$<" \
>  		--interactive \
>  		false, \
> diff --git a/tests/vm/basevm.py b/tests/vm/basevm.py
> index b9d828423b..64dbe64326 100644
> --- a/tests/vm/basevm.py
> +++ b/tests/vm/basevm.py
> @@ -117,6 +117,11 @@ class BaseVM(object):
>               "w").write(self._config['ssh_pub_key'])
>  
>          self.debug = args.debug
> +        self._console_log_path = None
> +        if args.log_console:
> +                self._console_log_path = \
> +                         os.path.join(os.path.expanduser("~/.cache/qemu-vm"),
> +                                      "{}.install.log".format(self.name))
>          self._stderr = sys.stderr
>          self._devnull = open(os.devnull, "w")
>          if self.debug:
> @@ -271,7 +276,9 @@ class BaseVM(object):
>          args += self._data_args + extra_args + self._config['extra_args']
>          logging.debug("QEMU args: %s", " ".join(args))
>          qemu_path = get_qemu_path(self.arch, self._build_path)
> -        guest = QEMUMachine(binary=qemu_path, args=args)
> +        guest = QEMUMachine(binary=qemu_path, args=args,
> +                            console_log=self._console_log_path,
> +                            drain_console=True)

Are you sure you need to set drain_console here? Isn't it implied by
self._console_log_path?

>          guest.set_machine(self._config['machine'])
>          guest.set_console()
>          try:
> @@ -285,6 +292,8 @@ class BaseVM(object):
>              raise
>          atexit.register(self.shutdown)
>          self._guest = guest
> +        # Init console so we can start consuming the chars.
> +        self.console_init()
>          usernet_info = guest.qmp("human-monitor-command",
>                                   command_line="info usernet")
>          self.ssh_port = None
> @@ -296,7 +305,9 @@ class BaseVM(object):
>              raise Exception("Cannot find ssh port from 'info usernet':\n%s" % \
>                              usernet_info)
>  
> -    def console_init(self, timeout = 120):
> +    def console_init(self, timeout = None):
> +        if timeout == None:
> +            timeout = self.socket_timeout
>          vm = self._guest
>          vm.console_socket.settimeout(timeout)
>          self.console_raw_path = os.path.join(vm._temp_dir,
> @@ -578,6 +589,8 @@ def parse_args(vmcls):
>      parser.add_option("--efi-aarch64",
>                        default="/usr/share/qemu-efi-aarch64/QEMU_EFI.fd",
>                        help="Path to efi image for aarch64 VMs.")
> +    parser.add_option("--log-console", action="store_true",
> +                      help="Log console to file.")
>      parser.disable_interspersed_args()
>      return parser.parse_args()
>  
> 


Re: [PATCH v8 12/12] tests/vm: Add workaround to consume console
Posted by Robert Foley 5 years, 8 months ago
On Sun, 31 May 2020 at 07:27, Philippe Mathieu-Daudé <philmd@redhat.com> wrote:
>
> On 5/29/20 10:34 PM, Robert Foley wrote:
<snip>
> > @@ -271,7 +276,9 @@ class BaseVM(object):
> >          args += self._data_args + extra_args + self._config['extra_args']
> >          logging.debug("QEMU args: %s", " ".join(args))
> >          qemu_path = get_qemu_path(self.arch, self._build_path)
> > -        guest = QEMUMachine(binary=qemu_path, args=args)
> > +        guest = QEMUMachine(binary=qemu_path, args=args,
> > +                            console_log=self._console_log_path,
> > +                            drain_console=True)
>
> Are you sure you need to set drain_console here? Isn't it implied by
> self._console_log_path?

Good point.  Yes, drain_console is implied by self._console_log_path.
Will fix it.

Thanks & Regards,
-Rob
>
> >          guest.set_machine(self._config['machine'])
> >          guest.set_console()
> >          try:
> > @@ -285,6 +292,8 @@ class BaseVM(object):
> >              raise
> >          atexit.register(self.shutdown)
> >          self._guest = guest
> > +        # Init console so we can start consuming the chars.
> > +        self.console_init()
> >          usernet_info = guest.qmp("human-monitor-command",
> >                                   command_line="info usernet")
> >          self.ssh_port = None
> > @@ -296,7 +305,9 @@ class BaseVM(object):
> >              raise Exception("Cannot find ssh port from 'info usernet':\n%s" % \
> >                              usernet_info)
> >
> > -    def console_init(self, timeout = 120):
> > +    def console_init(self, timeout = None):
> > +        if timeout == None:
> > +            timeout = self.socket_timeout
> >          vm = self._guest
> >          vm.console_socket.settimeout(timeout)
> >          self.console_raw_path = os.path.join(vm._temp_dir,
> > @@ -578,6 +589,8 @@ def parse_args(vmcls):
> >      parser.add_option("--efi-aarch64",
> >                        default="/usr/share/qemu-efi-aarch64/QEMU_EFI.fd",
> >                        help="Path to efi image for aarch64 VMs.")
> > +    parser.add_option("--log-console", action="store_true",
> > +                      help="Log console to file.")
> >      parser.disable_interspersed_args()
> >      return parser.parse_args()
> >
> >
>