- security: apparmor: Fix probing of apparmor availability on the

VM host when using modular daemons
  bsc#1235079

OBS-URL: https://build.opensuse.org/package/show/Virtualization/libvirt?expand=0&rev=1069
This commit is contained in:
2025-01-06 22:47:12 +00:00
committed by Git OBS Bridge
commit f835a8d769
17 changed files with 8926 additions and 0 deletions
+6486
View File
File diff suppressed because it is too large Load Diff
+1928
View File
File diff suppressed because it is too large Load Diff
+19
View File
@@ -0,0 +1,19 @@
<services>
<service name="tar_scm" mode="manual">
<param name="scm">git</param>
<param name="url">https://github.com/openSUSE/libvirt.git</param>
<param name="revision">factory</param>
<param name="extract">libvirt.spec</param>
<param name="extract">README.packaging.txt</param>
<param name="extract">libvirt-supportconfig</param>
<param name="versionformat">@PARENT_TAG@</param>
<param name="versionrewrite-pattern">[v]?([^-+a-z]+)(.*)</param>
<param name="versionrewrite-replacement">\1</param>
<param name="changesgenerate">disable</param>
</service>
<service name="set_version" mode="manual"/>
<service name="recompress" mode="manual">
<param name="file">*.tar</param>
<param name="compression">xz</param>
</service>
</services>
+23
View File
@@ -0,0 +1,23 @@
## Default LFS
*.7z filter=lfs diff=lfs merge=lfs -text
*.bsp filter=lfs diff=lfs merge=lfs -text
*.bz2 filter=lfs diff=lfs merge=lfs -text
*.gem filter=lfs diff=lfs merge=lfs -text
*.gz filter=lfs diff=lfs merge=lfs -text
*.jar filter=lfs diff=lfs merge=lfs -text
*.lz filter=lfs diff=lfs merge=lfs -text
*.lzma filter=lfs diff=lfs merge=lfs -text
*.obscpio filter=lfs diff=lfs merge=lfs -text
*.oxt filter=lfs diff=lfs merge=lfs -text
*.pdf filter=lfs diff=lfs merge=lfs -text
*.png filter=lfs diff=lfs merge=lfs -text
*.rpm filter=lfs diff=lfs merge=lfs -text
*.tbz filter=lfs diff=lfs merge=lfs -text
*.tbz2 filter=lfs diff=lfs merge=lfs -text
*.tgz filter=lfs diff=lfs merge=lfs -text
*.ttf filter=lfs diff=lfs merge=lfs -text
*.txz filter=lfs diff=lfs merge=lfs -text
*.whl filter=lfs diff=lfs merge=lfs -text
*.xz filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.zst filter=lfs diff=lfs merge=lfs -text
+1
View File
@@ -0,0 +1 @@
.osc
+12
View File
@@ -0,0 +1,12 @@
This package is maintained in git at
https://github.com/openSUSE/libvirt
Please submit a pull request for any changes. The spec file is also maintained
in git.
To build a package from git, edit the _service to reference the desired branch
and call
osc service localrun
The package can then be build as usual with your prefered osc build options.
+4
View File
@@ -0,0 +1,4 @@
libvirt-client
requires -libvirt-<targettype>
libvirt-devel
requires -libvirt-<targettype>
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+3
View File
@@ -0,0 +1,3 @@
addFilter("shlib-policy-name-error")
addFilter("missing-dependency-to-logrotate for logrotate script /etc/logrotate.d/libvirtd.(qemu|lxc|uml|libxl)")
addFilter("incoherent-logrotate-file")
+95
View File
@@ -0,0 +1,95 @@
#!/bin/bash
#############################################################
# Name: Supportconfig Plugin for libvirt
# Description: Gathers important troubleshooting information
# about libvirt
#############################################################
RCFILE="/usr/lib/supportconfig/resources/supportconfig.rc"
OF="output-libvirt.txt"
# conf files for all daemons reside in /etc/libvirt/. VM conf files
# and log files reside in hypervisor-specific locations.
DAEMON_CONF_FILES="$(find -L /etc/libvirt/*.conf -type f 2>/dev/null | sort)"
PERSISTENT_VM_CONF_FILES=""
ACTIVE_VM_CONF_FILES=""
DAEMON_LOG_FILES=""
if [ -s $RCFILE ]; then
if ! source $RCFILE; then
log_write $OF "ERROR: Initializing resource file: $RCFILE"
exit 1
fi
fi
rpm_installed() {
thisrpm="$1"
if rpm -q "$thisrpm" >/dev/null 2>&1; then
return 0
fi
return 1
}
if rpm_installed libvirt-daemon-driver-libxl; then
test -d /etc/libvirt/libxl && PERSISTENT_VM_CONF_FILES="$PERSISTENT_VM_CONF_FILES $(find -L /etc/libvirt/libxl/ -type f | sort)"
test -d /run/libvirt/libxl && ACTIVE_VM_CONF_FILES="$ACTIVE_VM_CONF_FILES $(find -L /run/libvirt/libxl/ -type f | sort)"
test -d /var/log/libvirt/libxl && DAEMON_LOG_FILES="$DAEMON_LOG_FILES $(find -L /var/log/libvirt/libxl/ -type f | sort)"
fi
if rpm_installed libvirt-daemon-driver-qemu; then
test -d /etc/libvirt/qemu && PERSISTENT_VM_CONF_FILES="$PERSISTENT_VM_CONF_FILES $(find -L /etc/libvirt/qemu/ -type f | sort)"
test -d /run/libvirt/qemu && ACTIVE_VM_CONF_FILES="$ACTIVE_VM_CONF_FILES $(find -L /run/libvirt/qemu/ -type f | sort)"
test -d /var/log/libvirt/qemu && DAEMON_LOG_FILES="$DAEMON_LOG_FILES $(find -L /var/log/libvirt/qemu/ -type f | sort)"
fi
if rpm_installed libvirt-daemon; then
DAEMON_LOG_FILES="$DAEMON_LOG_FILES $(find -L /var/log/libvirt/*.log -type f 2>/dev/null | sort)"
fi
if rpm_installed libvirt-client && virsh capabilities > /dev/null 2>&1; then
log_cmd $OF "virsh version"
log_cmd $OF "virsh capabilities"
log_cmd $OF "virsh domcapabilities"
log_cmd $OF "virsh nodeinfo"
log_cmd $OF "virsh nodedev-list"
# print all known domains on default URI
log_cmd $OF "virsh list --all"
# dump configuration info of active domains on default URI
for DOM in $(virsh list --name)
do
log_cmd $OF "virsh dumpxml $DOM"
log_cmd $OF "virsh vcpuinfo $DOM"
log_cmd $OF "virsh dominfo $DOM"
log_cmd $OF "virsh domjobinfo $DOM"
log_cmd $OF "virsh dommemstat $DOM"
log_cmd $OF "virsh snapshot-list $DOM"
done
# dump configuration info of inactive domains on default URI
for DOM in $(virsh list --name --inactive)
do
log_cmd $OF "virsh dumpxml $DOM"
log_cmd $OF "virsh snapshot-list $DOM"
done
# dump active networks, interfaces and storage pools
log_cmd $OF "virsh net-list"
log_cmd $OF "virsh iface-list"
log_cmd $OF "virsh pool-list"
fi
# dump libvirtd-related conf files
conf_files $OF "$DAEMON_CONF_FILES"
# dump persistent VM-related conf files
conf_files $OF "$PERSISTENT_VM_CONF_FILES"
# dump active VM-related conf files
conf_files $OF "$ACTIVE_VM_CONF_FILES"
# dump hook conf files
test -d /etc/libvirt/hooks && FILES="$(find -L /etc/libvirt/hooks/ -type f | sort)"
conf_files $OF "$FILES"
# dump all log files
log_files $OF 0 "$DAEMON_LOG_FILES"
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>libvirtd Migration Server</short>
<description>Enables TCP ports for libvirtd native migration</description>
<port protocol="tcp" port="49152-49215"/>
</service>
+331
View File
@@ -0,0 +1,331 @@
#!/usr/bin/python3
# libvirt hook script for QEMU/KVM domains. See the libvirt hooks
# documenation for more details
#
# https://www.libvirt.org/hooks.html
#
# Currently this hook looks for domains with <metadata> containing
# configuration for dmmd <disk> devices. All <metadata> sub-elements
# must have a matching <disk> under <devices>. Those without a matching
# <disk> will be ignored.
#
# The dmmd device syntax is similar to Xen's block-dmmd. E.g.
# md;/dev/md0(/etc/mdadm/mdadm.conf);lvm;/dev/vg/lv
#
# Device pairs (type;dev) are processed in order. The last device
# should match a <source dev=> attribute of a <disk>. The following
# configuration illustrates a domain with two dmmd devices
#
# <domain>
# ...
# <metadata>
# <hook:dmmd xmlns:hook='https://libvirt.org/schemas/domain/hooks/1.0'>
# <disk>md;/dev/md0(/etc/mdadm.conf);lvm;/dev/vg1/lv1</disk>
# <disk>md;/dev/md1(/etc/mdadm.conf);lvm;/dev/vg1/lv2</disk>
# </hook:dmmd>
# </metadata>
# <devices>
# ...
# <disk type='block' device='disk'>
# <driver name='qemu' type='raw'/>
# <source dev='/dev/vg1/lv1'/>
# <target dev='vdb' bus='virtio'/>
# </disk>
# <disk type='block' device='disk'>
# <driver name='qemu' type='raw'/>
# <source dev='/dev/vg1/lv2'/>
# <target dev='vdc' bus='virtio'/>
# </disk>
# </devices>
# </domain>
#
#
# md devices can optionally:
# specify a config file through:
# md;/dev/md100(/var/opt/config/mdadm.conf)
# use an array name (mdadm -N option):
# md;My-MD-name;lvm;/dev/vg1/lv1
import os
import sys
import time
import subprocess
from lxml import etree
from subprocess import check_output
from subprocess import CalledProcessError
COMMAND_TIMEOUT = 60
MDADM_BIN = "/sbin/mdadm"
PVSCAN_BIN = "/sbin/pvscan"
LVCHANGE_BIN = "/sbin/lvchange"
HOOK_NAMESPACE = "https://libvirt.org/schemas/domain/hooks/1.0"
HOOK_NS_TAG = "{%s}" % HOOK_NAMESPACE
DEBUG = False
def write_debug(msg):
if DEBUG:
with open("/var/log/libvirt/qemu/suse-qemu-hook-output.log", "a") as f:
f.write(msg + "\n")
def run_cmd(cmd):
cmd_output = ""
rc = 0
msg = ""
for m in cmd:
msg += m + " "
write_debug("run_cmd executing: " + msg)
try:
cmd_output = check_output(cmd, stderr=subprocess.STDOUT)
except CalledProcessError as err:
write_debug("run_cmd: caught CalledProcessError with output: " + err.output)
rc = err.returncode
if rc != 0:
write_debug("run_cmd failed: " + msg)
return [rc, cmd_output]
def prepare_md(dev):
conf = []
mdadmopts = []
devpath = ""
startcfg = dev.find("(")
# check if MD config specifies a conf file for mdadm
if startcfg != -1:
endcfg = dev.find(")")
conf = ["-c"]
conf.append(dev[startcfg + 1:endcfg])
dev = dev[:startcfg]
# check if MD config contains a device or array name
if not dev.startswith("/"):
mdadmopts = ["-s"]
mdadmopts.append("-N")
devpath = "/dev/md/" + dev
else:
devpath = dev
# check if MD device is already active
cmd = [MDADM_BIN, "-Q"]
cmd.append(devpath)
write_debug("prepare_md: calling mdadm -Q for device " + devpath)
ret, cmd_output = run_cmd(cmd)
if ret == 0:
write_debug("prepare_md: mdadm -Q succeeded for device " + devpath + ". Already activated")
return 0
cmd = [MDADM_BIN, "-A"]
cmd.extend(mdadmopts)
cmd.extend(conf)
cmd.append(devpath)
write_debug("prepare_md: calling mdadm -A for device " + devpath)
ret, cmd_output = run_cmd(cmd)
if ret != 0:
write_debug("prepare_md: mdadm -A failed for device " + devpath)
else:
write_debug("prepare_md: mdadm -A succeeded for device " + devpath)
return ret
def release_md(dev):
conf = []
devpath = ""
startcfg = dev.find("(")
if startcfg != -1:
endcfg = dev.find(")")
conf = ["-c"]
conf.append(dev[startcfg + 1:endcfg])
dev = dev[:startcfg]
# check if MD config contains a device or array name. For
# querying and deactivating a device name is required
if not dev.startswith("/"):
devpath = "/dev/md/" + dev
else:
devpath = dev
# check if device exists
cmd = [MDADM_BIN, "-Q"]
cmd.extend(conf)
cmd.append(devpath)
write_debug("release_md: calling mdadm -Q for device " + devpath)
ret, cmd_output = run_cmd(cmd)
if ret != 0:
write_debug("release_md: mdadm -Q failed for device " + devpath + ". Already deactivated")
return 0
cmd = [MDADM_BIN, "-S"]
cmd.extend(conf)
cmd.append(devpath)
write_debug("release_md: calling mdadm -S for device " + devpath)
ret, cmd_output = run_cmd(cmd)
if ret == 0:
write_debug("release_md: mdadm -S succeeded for device " + devpath)
else:
write_debug("release_md: mdadm -S failed for device " + devpath)
return ret
def prepare_lvm(dev):
cmd = [LVCHANGE_BIN]
cmd.append("-aey")
cmd.append(dev)
endtime = time.time() + COMMAND_TIMEOUT;
while time.time() < endtime:
# When using MD devices for LVM PV, it is best to rescan for PV and VG
run_cmd([PVSCAN_BIN])
ret, cmd_output = run_cmd(cmd)
if ret == 0 and os.path.exists(dev):
write_debug("prepare_lvm: lvchange -aey succeeded on device " + dev)
return 0
else:
write_debug("prepare_lvm: lvchange -aey failed on device " + dev)
time.sleep(0.1)
write_debug("prepare_lvm: lvchange -aey never succeeded for device " + dev)
return 1
def release_lvm(dev):
# Nothing to do if the device doesn't exist or is already deactivated
if not os.path.exists(dev):
write_debug("release_lvm: dev " + dev + " does not exist. Nothing to do!")
return 0
cmd = [LVCHANGE_BIN]
cmd.append("-aen")
cmd.append(dev)
endtime = time.time() + COMMAND_TIMEOUT;
while time.time() < endtime:
ret, cmd_output = run_cmd(cmd)
if ret == 0:
write_debug("release_lvm: lvchange -aen succeeded for device " + dev)
return 0
else:
write_debug("release_lvm: lvchange -aen failed for device " + dev + ". Trying again...")
time.sleep(0.1)
write_debug("release_lvm: lvchange -aen never succeeded for device " + dev)
return 1
def prepare_config(params):
write_debug("prepare_config: called with params " + params)
conf = params.split(";")
i = 0
while i < len(conf):
t = conf[i]
d = conf[i+1]
write_debug("prepare_config: got t = " + t + " and d = " + d)
if t == "md":
if prepare_md(d):
write_debug("prepare_config: failed to prepare MD device " + d)
return 1
if t == "lvm":
if prepare_lvm(d):
write_debug("prepare_config: failed to prepare LVM device " + d)
return 1
i += 2
return 0
def release_config(params):
write_debug("release_config: called with params " + params)
conf = params.split(";")
i = len(conf) - 1
ret = 0
# work backwards through the list when releasing, cleaning
# up LVM first, then MD
while i >= 0:
t = conf[i-1]
d = conf[i]
write_debug("release_config: got t = " + t + " and d = " + d)
if t == "md":
if release_md(d):
write_debug("release_config: failed to release MD device " + d)
ret = 1
if t == "lvm":
if release_lvm(d):
write_debug("release_config: failed to release LVM device " + d)
ret = 1
i -= 2
return ret
if len(sys.argv) < 3:
sys.exit(1)
exit_code = 0
disk_devs = []
phase = sys.argv[2]
vmxml = sys.stdin.read()
tree = etree.fromstring(vmxml.encode("utf-8", "ignore"))
devs = tree.xpath("/domain/devices/disk")
dmmd_configs = tree.xpath("/domain/metadata/hook:dmmd/disk", namespaces={'hook': HOOK_NAMESPACE})
if len(dmmd_configs) == 0:
write_debug("No dmmd configurations found in <metadata>")
sys.exit(0)
write_debug("got phase: " + phase)
# build a list of <disk type='block'> source device names to check against
# dmmd configurations
for d in devs:
val = d.get("type")
if val is None or val != "block":
continue
for child in d:
if child.tag == "source":
disk_devs.append(child.get("dev"))
# For each dmmd configuration in <metadata>, check there is a corresponding
# disk
for config in dmmd_configs:
# check that a disk exists for this config. <disk> devices may have
# been added or removed without a corresponding update to <metadata>
index = config.text.rfind(";")
if index == -1:
continue
disk = config.text[index + 1:]
# remove config file specfied with '(/path/to/conf)'
if disk.endswith(")"):
index = disk.rfind("(")
if index == -1:
continue
disk = disk[:index]
if disk not in disk_devs:
write_debug("Ignoring config '" + config.text + "' with no matching <disk> device")
continue
# TODO: check that migration can be handled by the 'prepare' phase on
# destination and 'release' phase on source
if phase == "prepare":
exit_code = prepare_config(config.text)
if phase == "release":
exit_code = release_config(config.text)
sys.exit(exit_code)