Skip to content

Commit

Permalink
hooks: Add log-firmware
Browse files Browse the repository at this point in the history
This is a combination of the interface of log-console and the
functionality of qemucmdline, hard-coded to log the firmware output to a
log file. qemucmdline can't be used directly for HostedEngine, because
we want a separate log file per VM, and qemucmdline does not have
internally functionality to allow doing that, relying instead on the
engine to supply correct params somehow. For HostedEngine, we can't rely
on the engine, as it does not exist at this point.

Change-Id: I5e2324009daed5136ab7884226cce0feee2e0c96
Signed-off-by: Yedidyah Bar David <[email protected]>
  • Loading branch information
didib authored and mz-pdm committed Jul 21, 2022
1 parent 62544a7 commit 69188fa
Show file tree
Hide file tree
Showing 7 changed files with 186 additions and 0 deletions.
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -402,6 +402,7 @@ AC_OUTPUT([
vdsm_hooks/httpsisoboot/Makefile
vdsm_hooks/localdisk/Makefile
vdsm_hooks/log_console/Makefile
vdsm_hooks/log_firmware/Makefile
vdsm_hooks/macbind/Makefile
vdsm_hooks/nestedvt/Makefile
vdsm_hooks/openstacknet/Makefile
Expand Down
1 change: 1 addition & 0 deletions execcmd-allowlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ vdsm_hooks/fcoe/fcoe_before_network_setup.py
vdsm_hooks/localdisk/after_disk_prepare
vdsm_hooks/localdisk/localdisk-helper
vdsm_hooks/log_console/before_vm_start.py
vdsm_hooks/log_firmware/before_vm_start.py
vdsm_hooks/openstacknet/after_get_caps.py
vdsm_hooks/openstacknet/openstacknet_utils.py
vdsm_hooks/scratchpad/before_vm_start.py
11 changes: 11 additions & 0 deletions vdsm.spec.in
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,14 @@ Requires: %{name}
%description hook-log-console
This hook allows logging a VM serial console to a file.

%package hook-log-firmware
Summary: Log VM's firmware to a file
BuildArch: noarch
Requires: %{name}

%description hook-log-firmware
This hook allows logging a VM firmware to a file.

%package hook-macbind
Summary: Bind a vNIC to a Bridge
BuildArch: noarch
Expand Down Expand Up @@ -1061,6 +1069,9 @@ exit 0
%files hook-log-console
%{_libexecdir}/%{vdsm_name}/hooks/before_vm_start/50_log_console

%files hook-log-firmware
%{_libexecdir}/%{vdsm_name}/hooks/before_vm_start/50_log_firmware

%files hook-vmfex-dev
%{_libexecdir}/%{vdsm_name}/hooks/before_device_create/50_vmfex
%{_libexecdir}/%{vdsm_name}/hooks/before_device_migrate_destination/50_vmfex
Expand Down
1 change: 1 addition & 0 deletions vdsm_hooks/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ SUBDIRS = \
fcoe \
localdisk \
log_console \
log_firmware \
openstacknet \
qemucmdline \
vhostmd \
Expand Down
31 changes: 31 additions & 0 deletions vdsm_hooks/log_firmware/Makefile.am
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#
# Copyright 2022 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# Refer to the README and COPYING files for full details of the license
#

EXTRA_DIST = \
before_vm_start.py

install-data-local:
$(MKDIR_P) $(DESTDIR)$(vdsmhooksdir)/before_vm_start
$(INSTALL_SCRIPT) $(srcdir)/before_vm_start.py \
$(DESTDIR)$(vdsmhooksdir)/before_vm_start/50_log_firmware

uninstall-local:
$(RM) $(DESTDIR)$(vdsmhooksdir)/before_vm_start/50_log_firmware

51 changes: 51 additions & 0 deletions vdsm_hooks/log_firmware/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
log_firmware vdsm hook
=================================
This hook appends a VM's firmware debug logging to a log file on the host.

Installation:
* Use engine-config to set the appropriate custom properties as such:

Custom property for a VM:
sudo engine-config -s "UserDefinedVMProperties=log_firmware=^(on|off)$"

* Prepare the log directory on the host:
sudo mkdir -p /var/log/qemu-firmware
sudo chown qemu /var/log/qemu-firmware
sudo chcon -t qemu_var_run_t /var/log/qemu-firmware
sudo chmod 700 /var/log/qemu-firmware

Usage:

The hook can be enabled using one of two ways:

1. Set the VM property 'log_firmware' to 'on', for specific VMs, as needed, via
the engine. Set it to 'off', to explicitly disable the hook.

2. Set the environment variable 'log_firmware_vm_regexp', in
/etc/sysconfig/vdsm, to a regular expression matching the VM names for which
you want to enable the hook. Matching is done using Python's re.match().

If log_firmware is set to 'off', for some VM, the hook will be disabled,
regardless of the value of log_firmware_vm_regexp or whether the name matches.

If 'log_firmware' is not 'on', for some VM, and 'log_firmware_vm_regexp' does
not match, the hook will be disabled. So by default, with both variables
being empty/unset, the hook is disabled.

In principle, a future version might enable it by default, based on feedback
from users.

Using log_firmware_vm_regexp is useful, in particular, for enabling the hook
for a HostedEngine VM, for which using 'log_firmware' is less practical, as
the engine might be down exactly when you want to use it (to help diagnose
why it's down...).

The logs are written to the directory set with the environment variable
log_firmware_dir, or to /var/log/qemu-firmware if it's not set.
If you do set it, you should prepare the directory as detailed above.
The logs' filenames, inside this directory, are {vm_name}-firmware.log,
where {vm_name} is replaced with the VM's name.

TODO: I'd like to be able to be able to write log files to
/var/log/libvirt/qemu, like other logs, but that's not easy.
See also: https://gerrit.ovirt.org/c/lago-ost/+/114150
90 changes: 90 additions & 0 deletions vdsm_hooks/log_firmware/before_vm_start.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/usr/bin/python3
#
# Copyright 2022 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
#
# Refer to the README and COPYING files for full details of the license
#

import os
import re
import traceback

from vdsm.hook import hooking


def main():
log_firmware = os.environ.get('log_firmware')
hooking.log(f'log_firmware: "{log_firmware}"')
if log_firmware == 'off':
return

log_firmware_vm_regexp = os.environ.get('log_firmware_vm_regexp')
hooking.log(f'log_firmware_vm_regexp: "{log_firmware_vm_regexp}"')

domxml = hooking.read_domxml()
vm_name = domxml.getElementsByTagName('name')[0].firstChild.data
hooking.log(f'vm_name: {vm_name}')

if (
log_firmware != 'on'
and (
not log_firmware_vm_regexp
or not re.match(log_firmware_vm_regexp, vm_name)
)
):
return

domain = domxml.getElementsByTagName('domain')[0]

domain.setAttribute(
'xmlns:qemu',
'http://libvirt.org/schemas/domain/qemu/1.0'
)

qemucl = domxml.createElement('qemu:commandline')

log_dir = os.environ.get(
'log_firmware_dir',
'/var/log/qemu-firmware'
)
for arg in (
'-chardev',
f'file,id=firmware,path={log_dir}/{vm_name}-firmware.log',
'-device',
'isa-debugcon,iobase=0x402,chardev=firmware',
):
argelement = domxml.createElement('qemu:arg')
argelement.setAttribute('value', arg)
qemucl.appendChild(argelement)

domain.appendChild(qemucl)
hooking.log(f'qemucl: [{qemucl.toprettyxml()}]')

hooking.log(f'domxml: [{domxml.toprettyxml()}]')
hooking.write_domxml(domxml)


if __name__ == '__main__':
try:
main()
except:
hooking.exit_hook(
'log_firmware: %s' % (
traceback.format_exc()
),
return_code=1
)

0 comments on commit 69188fa

Please sign in to comment.