Subpackages¶
Subpackages are experimental approach to deliver in a single point (RPM) dropin files and additional requirements.
The qm project is designed to provide a flexible and modular environment for managing Quality Management (QM) software in containerized environments. One of the key features of the qm package is its support for sub-package(s), such as the qm-dropin sub-packages. These sub-packages are not enabled by default and are optional. However, allow users to easily extend or customize their QM environment by adding specific configurations, tools, or scripts to the containerized QM ecosystem by simple installing or uninstalling a RPM package into the system.
The key features of QM Sub-Packages are
- Modularity
- No configuration change, no typo or distribution rebuild/update.
- Just dnf install/remove from the traditional rpm schema.
- Customizability
- Users can easily add specific configurations to enhance or modify the behavior of their QM containers.
- Maintainability
- Sub-packages ensure that the base qm package remains untouched, allowing easy updates without breaking custom configurations.
- Simplicity
- Like qm-dropin provide a clear directory structure and templates to guide users in customizing their QM environment.
Note
The following sections describe the currently available QM subpackages.
Building QM sub-packages¶
Choose one of the following sub-packages and build using make.
git clone git@github.com:containers/qm.git && cd qm
Example of subpackages: kvm, qm-oci-hooks, ros2, text2speech, windowmanager
make TARGETS=input subpackages
ls rpmbuild/RPMS/noarch/
qm-0.6.7-1.fc40.noarch.rpm qm_mount_bind_input-0.6.7-1.fc40.noarch.rpm
Installing QM sub-packages¶
$ sudo dnf install ./rpmbuild/RPMS/noarch/qm_mount_bind_input-0.6.7-1.fc40.noarch.rpm
<SNIP>
Complete!
If QM is already running, restart or reload your QM container environment to apply the new configurations.
sudo systemctl daemon-reload
sudo podman restart qm
Removing QM sub-packages¶
sudo rpm -e qm_mount_bind_input
Creating your own drop-in QM sub-package¶
We recommend using the existing drop-in files as a guide and adapting them to your specific needs. However, here are the step-by-step instructions:
1) Add a drop-in file to: etc/containers/systemd/qm.container.d/qm_dropin_<subpackage>.conf>
2) Add your package as a sub-package to: rpm/<subpackage_directory>/<subpackage>.spec
3) Add the makefile for the sub-package and any files required by the sub-package to: subsystems/<subpackage_directory>
4) Test the sub-package build by running: make clean && make TARGETS=<subpackage> subpackages
5) Install your sub-package using: dnf install -y rpmbuild/RPMS/noarch/<subpackage>*.noarch.rpm
6) Restart podman container using: sudo podman restart qm
7) Additionally, test it with and without enabling the sub-package using (by default it should be disabled but there are cases where it will be enabled by default if QM community decide):
Example changing the spec and triggering the build via make (feel free to automate via sed, awk etc):
# Use make file to run specific subpackage
make TARGETS=windowmanager subpackages
QM sub-package Video¶
The video sub-package exposes /dev/video0 (or many video devices required) to the container. This feature is useful for demonstrating how to share a camera from the host system into a container using Podman drop-in. To showcase this functionality, we provide the following demo:
Building the video sub-package, installing, and restarting QM¶
make TARGETS=video subpackages
sudo dnf install ./rpmbuild/RPMS/noarch/qm-mount-bind-video-0.6.7-1.fc40.noarch.rpm
sudo systemctl daemon-reload
sudo podman restart qm
This simulates a rear camera when the user shifts into reverse gear.
In this simulation, we created a systemd service that, every time it is started, captures a snapshot from the webcam, simulating the action of a rear camera. (Feel free to start and restart the service multiple times!)
host> sudo podman exec -it qm bash
bash-5.2# systemctl daemon-reload
bash-5.2# systemctl start rear-camera
# ls -la /var/tmp/screenshot.jpg
-rw-r--r--. 1 root root 516687 Oct 13 04:05 /var/tmp/screenshot.jpg
bash-5.2#
Copy the screenshot to the host and view it¶
host> sudo podman cp qm:/var/tmp/screenshot.jpg .
Great job! Now imagine all the possibilities this opens up!
QM sub-package Sound¶
Step 1: Install the QM Mount Bind Sound Package¶
To set up sound cards in a QM environment using Podman, follow the steps below:
Run the following commands to install the qm_mount_bind_sound package and restart QM (if previously in use):
# Build and install the RPM for QM sound
git clone https://github.com/containers/qm.git && cd qm
make TARGETS=sound subpackages
sudo dnf install -y rpmbuild/RPMS/noarch/qm_mount_bind_sound-0.6.7-1.fc40.noarch.rpm
# Restart QM container (if already running)
sudo systemctl daemon-reload
sudo podman restart qm
Step 2: Identify Sound Cards¶
After installing the drop-in and restarting QM, you need to identify which sound card in the Linux system will be used in QM. If you’re familiar with your sound card setup feel free to skip this step.
To list the sound cards available on your system (in our case, we will pick the number 1):
cat /proc/asound/cards
Example Output:
0 [NVidia ]: HDA-Intel - HDA NVidia
HDA NVidia at 0x9e000000 irq 17
1 [sofhdadsp ]: sof-hda-dsp - sof-hda-dsp
LENOVO-20Y5000QUS-ThinkPadX1ExtremeGen4i
2 [USB ]: USB-Audio - USB Audio Device
Generic USB Audio at usb-0000:00:14.0-5, full speed
Detecting Channels and Sample Rates¶
To list the supported number of channels and samples use pactl command:
pactl list sinks | grep -i 48000 | uniq
Sample Specification: s24-32le 2ch 48000Hz
Verify Sample Rate Support¶
To show the supported sample rates for a specific sound card codec, you can also inspect the codec details:
cat /proc/asound/card1/codec#0 | grep -i rates
This will output the supported sample rates for the codec associated with card1.
Differentiating Between Cards¶
Accessing Card 1 (sof-hda-dsp)
cat /proc/asound/cards | grep -A 1 '^ 1 '
Accessing Card 2 (USB Audio Device)
cat /proc/asound/cards | grep -A 1 '^ 2 '
Step 3: Testing audio inside QM¶
Inside QM, run the following command:
podman exec -it qm bash
bash-# podman ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
76dacaa9a89e quay.io/qm-images/audio:latest sleep infinity 7 hours ago Up 7 hours systemd-audio
bash-# podman exec -it systemd-audio bash
Execute the audio test within the nested container, and the sound will be output through the physical speakers of your computer—or, in this case, the car's multimedia soundbox.
bash-# speaker-test -D hw:1,0 -c 2 -r 48000
Params:
hw:1,0: sound card 1, device 0
-c 2: two channels (stereo)
-r 48000: sample rate of 48 kHz
QM sub-package OCI Hooks¶
The QM sub-package OCI Hooks provides dynamic device access management for containers through OCI runtime hooks. This subpackage includes essential hooks that enable secure and flexible device sharing between the host system and containers with robust error handling and comprehensive testing.
Components¶
The qm-oci-hooks subpackage includes:
- qm-device-manager: Dynamic device mounting hook that provides access to various hardware devices based on container annotations
- wayland-client-devices: Hook for GPU hardware acceleration access for Wayland client applications running as nested containers
Supported Device Types¶
QM Device Manager¶
The qm-device-manager hook supports the following device types through container annotations:
| Device Type | Annotation | Devices Provided |
|---|---|---|
| Audio | org.containers.qm.device.audio=true |
/dev/snd/* (audio devices) |
| Video | org.containers.qm.device.video=true |
/dev/video*, /dev/media* (cameras, video devices) |
| Input | org.containers.qm.device.input=true |
/dev/input/* (keyboards, mice, touchpads) |
| TTYs | org.containers.qm.device.ttys=true |
/dev/tty0-7 (virtual terminals) |
| TTY USB | org.containers.qm.device.ttyUSB=true |
/dev/ttyUSB* (USB TTY devices) |
| DVB | org.containers.qm.device.dvb=true |
/dev/dvb/* (digital TV devices) |
| Radio | org.containers.qm.device.radio=true |
/dev/radio* (radio devices) |
| Multi-seat Support | org.containers.qm.wayland.seat=seat0 |
Input devices, render devices, and display devices associated with the specified systemd-logind seat |
Wayland Client Devices¶
The wayland-client-devices hook supports:
| Functionality | Annotation | Devices Provided |
|---|---|---|
| GPU Acceleration | org.containers.qm.wayland-client.gpu=true |
GPU render devices (/dev/dri/render*) for hardware acceleration |
Features¶
- Dynamic Device Discovery: Automatically discovers and mounts available devices at container startup
- Annotation-Based Security: Devices are only mounted when explicitly requested via annotations
- Multi-seat Support: Enables proper device access in systemd-logind multi-seat environments
- Comprehensive Mock Device Support: Full testing infrastructure with mock devices for all device types
- GPU Acceleration: Provides hardware acceleration for Wayland client applications
- Comprehensive Logging: All hooks provide detailed logging for monitoring and debugging:
- Device Manager:
/var/log/qm-device-manager.log - Wayland Client:
/var/log/qm-wayland-client-devices.log - Runtime Flexibility: No system restart required when adding device access to new containers
- Lightweight Implementation: Shell script-based hooks with minimal dependencies
Building and Installing¶
git clone https://github.com/containers/qm.git && cd qm
make TARGETS=qm-oci-hooks subpackages
sudo dnf install rpmbuild/RPMS/noarch/qm-oci-hooks-*.noarch.rpm
Usage Examples¶
Example 1: Serial communication with USB TTY devices¶
# Create a container with access to all USB TTY devices
cat > /etc/containers/systemd/serial-app.container << EOF
[Unit]
Description=Serial Communication Application
[Container]
Image=my-serial-app:latest
Annotation=org.containers.qm.device.ttyUSB=true
[Install]
WantedBy=default.target
EOF
Example 2: Multi-seat Wayland compositor with session devices¶
# Create a dropin for QM container to enable multi-seat support
mkdir -p /etc/containers/systemd/qm.container.d/
cat > /etc/containers/systemd/qm.container.d/wayland-seat.conf << EOF
[Container]
Annotation=org.containers.qm.wayland.seat=seat0
EOF
# Create a Wayland compositor container that runs inside QM
cat > /etc/qm/containers/systemd/wayland-compositor.container << EOF
[Unit]
Description=Wayland Compositor with Multi-seat Support
[Container]
Image=wayland-compositor:latest
Annotation=org.containers.qm.wayland.seat=seat0
[Install]
WantedBy=default.target
EOF
Example 3: Wayland client application with GPU acceleration¶
# Create a Wayland client container with GPU hardware acceleration
cat > /etc/qm/containers/systemd/gpu-app.container << EOF
[Unit]
Description=GPU-accelerated Application
[Container]
Image=my-gpu-app:latest
Annotation=org.containers.qm.wayland-client.gpu=true
[Install]
WantedBy=default.target
EOF
Verification¶
To verify the hooks are installed and working:
# Check all OCI hook installations
ls -la /usr/share/containers/oci/hooks.d/
# Check hook executables
ls -la /usr/libexec/oci/hooks.d/
# Verify hook JSON configurations are valid
find /usr/share/containers/oci/hooks.d/ -name "*.json" -exec jq . {} \;
# View hook logs (all hooks provide comprehensive logging)
tail -f /var/log/qm-device-manager.log
tail -f /var/log/qm-wayland-client-devices.log
# Test device access with qm-device-manager
podman exec -it my-audio-app ls -la /dev/snd/
# Test GPU access with wayland-client-devices (if applicable)
podman exec -it gpu-app ls -la /dev/dri/
# Run hook tests (if source available)
cd oci-hooks && tox -e all
Testing and Development¶
The OCI hooks include a comprehensive test suite for development and validation:
# Run all tests
cd oci-hooks && tox -e all
# Run specific test categories
tox -e unit # Unit tests only
tox -e integration # Integration tests only
tox -e performance # Performance tests only
# Run linting and formatting
tox -e lint # Code linting
tox -e format # Code formatting
# Test with mock devices (useful for CI environments)
FORCE_MOCK_DEVICES=true tox -e unit -- -k "mock_devices"
OCI Hooks Specification and Documentation¶
The QM OCI hooks are implemented according to the Open Container Initiative (OCI) Runtime Specification.
OCI Hook Configuration Format¶
OCI hooks are configured using JSON files that define when and how the hooks should be executed. Each hook configuration follows the structure defined in the OCI config schema.
Key components of hook configuration:
- version: OCI specification version (e.g.,
"1.0.0") - hook: Object defining the hook executable and arguments
- when: Object defining trigger conditions for the hook
- stages: Array of lifecycle stages when the hook should run
Hook Lifecycle Stages¶
According to the OCI POSIX Platform Hooks specification, hooks can be executed at three stages:
- prestart: Hooks called after the container process is spawned, but before the user-supplied command is executed
- poststart: Hooks called after the user-supplied command is executed
- poststop: Hooks called after the container process is terminated
QM hooks execution stages:
qm-device-manager: Runs during prestart to mount devices before the container startswayland-client-devices: Runs during prestart to provide GPU access before the container starts
Hook Input/Output Specification¶
OCI hooks receive container state information via stdin and communicate results via stdout/stderr and exit codes:
Input (stdin): JSON object containing container state according to OCI spec:
{
"ociVersion": "1.0.0",
"id": "container-id",
"status": "creating",
"pid": 1234,
"bundle": "/path/to/bundle",
"annotations": {
"org.containers.qm.device.audio": "true"
}
}
Output:
- Exit code 0: Success
- Exit code non-zero: Failure (container creation aborted)
- stderr: Error messages and diagnostics
- stdout: Hook output (typically empty for QM hooks)
Annotation Pattern Matching¶
QM hooks use regular expressions in their when.annotations configuration to match container annotations:
org\\.containers\\.qm\\.device\\.(audio|video|input|ttys|ttyUSB|dvb|radio): Matches device-specific annotationsorg\\.containers\\.qm\\.wayland\\.seat: Matches Wayland seat annotations with any valueorg\\.containers\\.qm\\.wayland-client\\.gpu: Matches GPU acceleration requests
Hook Installation Locations¶
QM hooks are installed in standard OCI locations:
- Hook executables:
/usr/libexec/oci/hooks.d/ - Hook configurations:
/usr/share/containers/oci/hooks.d/ - Hook libraries:
/usr/libexec/oci/lib/
QM sub-package ROS2¶
The QM sub-package ROS2 (a.k.a “The Robot Operating System” or middleware for robots) is widely used by open-source projects, enterprises, companies, edge env and government agencies, including NASA, to advance robotics and autonomous systems. Enabled by Quadlet in QM, ROS2 on top of QM provides a secure environment where robots can operate and communicate safely, benefiting from QM’s “Freedom from Interference” frequently tested layer. This ensures robots can function without external interference, enhancing their reliability and security.
The types of robots compatible with this environment are extensive, ranging from medical devices and aerial drones to aqua drones and space rockets. ROS2 within QM supports high availability, meaning these robotic systems can maintain continuous operations, crucial for mission-critical and industrial applications. This versatility makes it ideal for environments that demand robust communication and operational safety, from healthcare and aerospace to underwater exploration and autonomous land vehicles.
How to test this env?
git clone https://github.com/containers/qm.git && cd qm
make TARGETS=ros2_rolling subpackages
sudo dnf install rpmbuild/RPMS/noarch/qm_ros2_rolling-0.6.7-1.fc40.noarch.rpm -y
sudo systemctl daemon-reload
sudo podman restart qm # if you have qm already running
Testing using talker and listener examples
$host> sudo podman exec -it qm bash
QM> . /opt/ros/jazzy/setup.bash # always replace jazz with the image ROS distro
QM> ros2 run demo_nodes_cpp talker &
QM> ros2 run demo_nodes_cpp listener
QM sub-package KVM¶
The QM sub-package KVM includes drop-in configuration that enables the integration of Kernel-based Virtual Machine (KVM) management into the QM (Quality Management) container environment. This configuration allows users to pull containerized kvm from qm-images-repo and run it inside QM
There is also kvm.container which is installed as a service.
Below example step by step:
Step 1: clone QM repo, create rpm.
git clone https://github.com/containers/qm.git && cd qm
make TARGETS=kvm subpackages
Step 2: copy rpm to running machine
scp -oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null -P 2222 rpmbuild/RPMS/noarch/qm-kvm-0.7.4-1.fc41.noarch.rpm root@127.0.0.1:/root/
Step 3: ssh machine install and verify
sudo dnf install ./qm-kvm-0.7.4-1.fc41.noarch.rpm
sudo systemctl restart qm # if you have qm already running
Step 4: verify, configuration exist
ls -ltr /etc/containers/systemd/qm.container.d/
total 12
-rw-r--r--. 1 root root 34 Jan 1 1970 publish-port.conf
-rw-r--r--. 1 root root 139 Jul 21 2023 qm_dropin_mount_bind_kvm.conf
ls -ltr /etc/qm/containers/systemd/
total 12
-rw-r--r--. 1 root root 91 Jan 1 1970 nginx.container
-rw-r--r--. 1 root root 188 Jul 21 2023 kvm.container
[root@localhost ~]# podman exec qm systemctl is-active kvm
active
[root@localhost ~]# podman exec -it qm sh
sh-5.1# ssh fedora@localhost -p 2226
[fedora@ibm-p8-kvm-03-guest-02 ~]$ grep ^NAME /etc/os-release
NAME="Fedora Linux"
AutoSD install¶
Some notes related to installing qm on ostree AutoSD image
- Check /var/qm size is larger then 1.5G
- Installing in ostree images with dnf command, requires running rpm-ostree usroverlay
In case using aib schema to build your image, verify adding the following to build command
--define 'extra_rpms=["audit","dnf","python3-gobject"] qm_varpart_relative_size=0.5'