qemu-img Usage Analysis¶
Analysis of qemu-img usage patterns across oVirt, Proxmox, and OpenStack codebases, identifying operations, parameters, and abstraction layers that instar would need to support.
Overall Summary¶
| Platform | Components | Primary Operations |
|---|---|---|
| oVirt | VDSM, ovirt-engine, ovirt-imageio | info, create, convert, check, measure, commit, map, amend, bitmap |
| Proxmox | pve-storage, qemu-server, pve-qemu | convert, create, info, measure, resize, snapshot, dd, rebase, commit |
| OpenStack | Cinder, Nova, Glance, oslo.utils | info, convert, create, resize, rebase, commit (+ LUKS encryption) |
oVirt¶
Analysis of qemu-img usage patterns across the oVirt codebase.
Summary Statistics¶
| Component | Files | Operations |
|---|---|---|
| VDSM | 30+ | info, create, convert, check, measure, commit, map, amend, bitmap |
| ovirt-engine | 7 | convert, measure, info, check (planned) |
| ovirt-imageio | 9 | create, convert, rebase, info, measure, compare, bitmap, map |
| Other repos | 13 | create, convert, info, measure, compare |
VDSM - Primary qemu-img Wrapper¶
VDSM provides the most comprehensive abstraction layer for qemu-img operations.
Wrapper Module: lib/vdsm/storage/qemuimg.py¶
Binary Path Resolution:
Format Constants:
class FORMAT:
QCOW2 = "qcow2"
QCOW = "qcow"
QED = "qed"
RAW = "raw"
class PREALLOCATION:
OFF = "off"
METADATA = "metadata"
FALLOC = "falloc"
FULL = "full"
Operations¶
info¶
--U: Unsafe mode (skip image validation)
- --backing-chain: Show entire backing chain
- Security: Untrusted images run with resource limits (30s CPU, 1GiB memory)
create¶
qemu-img create -f FORMAT [-b BACKING] [-F BACKING_FORMAT] \
[-o preallocation=MODE] [-o compat=VERSION] [-u] <image> [size]
convert¶
qemu-img convert -f SRC_FMT -O DST_FMT [-p] [-t none] [-T none] \
[-c] [-W] [-n] [--target-is-zero] [-b BACKING] [--bitmaps] \
[--skip-broken-bitmaps] [-o OPTIONS] <src> <dst>
-p: Progress reporting
- -t/-T none: Disable caching
- -c: Enable compression
- -W: Unordered writes (block devices)
- -n: Don't create destination
- --target-is-zero: Skip zeroing (qemu-img 5.1+)
- --bitmaps: Copy dirty bitmaps
check¶
- Return code 3 (leaked clusters) is non-fatal - Instar extension:instar check --chain validates the entire backing
chain by discovering all backing images, loading them as separate
virtio-block devices, and checking format consistency, virtual size
validity, and QCOW2 header integrity for each backing image
measure¶
- Estimate space required for conversioncommit¶
- Merge snapshot chainsmap¶
- Get allocation mapamend¶
- Modify QCOW2 compatibility versionbitmap operations¶
qemu-img bitmap --add [-g GRANULARITY] [--enable] <image> <bitmap>
qemu-img bitmap --remove <image> <bitmap>
qemu-img bitmap --merge <src_bitmap> -b <src_image> -F <src_fmt> <dst_image> <dst_bitmap>
Error Handling Patterns¶
class InvalidOutput(cmdutils.Error):
msg = "Command {self.cmd} returned invalid output: {self.out}: {self.reason}"
Security for untrusted images:
ovirt-engine¶
OVA Extract (extract_ova.py)¶
- Runs as vdsm user via su -p -c
OVA Pack (pack_ova.py)¶
- Fixed output format: qcow2
- Progress reporting enabled
Image Measure (Ansible)¶
- Used for resource planningPlanned Operations¶
qemu-img checkfor QCOW2 validation (not yet implemented)
ovirt-imageio¶
Wrapper Module: ovirt_imageio/_internal/qemu_img.py¶
Simpler wrapper using direct subprocess calls:
def create(path, fmt, size=None, backing_file=None, backing_format=None, quiet=False)
def convert(src, dst, src_fmt, dst_fmt, progress=False, compressed=False)
def unsafe_rebase(path, backing, backing_fmt)
def info(path) -> dict
def measure(path, out_fmt) -> dict
def compare(a, b, format1=None, format2=None, strict=False)
def bitmap_add(path, bitmap)
Custom Exceptions¶
Dependencies¶
Other oVirt Components¶
ovirt-ansible-hosted-engine-setup¶
# Convert local VM disk to raw for shared storage
qemu-img convert -f qcow2 -O raw -t none -T none <src> <dst>
# Verify disk copy
qemu-img compare <src> <dst>
# Get appliance disk size
qemu-img info --output=json <path>
ovirt-node-ng-image¶
python-ovirt-engine-sdk4¶
# Get image info for upload validation
qemu-img info --output json <filename>
# Measure required space for format conversion
qemu-img measure -f <src_fmt> -O <dst_fmt> --output json <image>
ovirt-hosted-engine-setup¶
Key Patterns for Instar¶
Must Support¶
- Operations: info, create, convert, check, measure, commit, map, amend, bitmap
- Formats: raw, qcow2, qcow, qed (vmdk for import scenarios)
- Output: JSON format for info, measure, check, map
- Progress: Percentage-based progress for convert, commit
- Caching:
-t none -T nonefor direct I/O - Preallocation: off, metadata, falloc, full
- QCOW2 compat: 0.10 and 1.1 versions
- Bitmaps: Add, remove, merge, enable/disable
Security Considerations¶
- Resource limits: CPU time and memory limits for untrusted images
- Unsafe mode:
-Uflag for images that may be in use - User context: Operations often run as vdsm:kvm user
Error Handling¶
- Check return codes: 0=success, 1=errors, 2=corruption, 3=leaks
- JSON validation: Verify required fields in output
- Progress parsing: Handle
(XX.XX/100%)format
Performance Patterns¶
- Unordered writes:
-Wfor block devices - Target is zero:
--target-is-zerofor preallocated targets - No create:
-nwhen destination already exists - Cache modes: Direct I/O (
none) for production workloads
Proxmox¶
Analysis of qemu-img usage patterns across the Proxmox VE codebase.
Summary Statistics¶
| Component | Files | Operations |
|---|---|---|
| pve-storage | 6 | create, info, measure, resize, snapshot, commit, rebase |
| qemu-server | 5 | convert, dd, snapshot |
| pve-qemu | 12 patches | dd (extended), info, snapshot |
| proxmox-backup | 0 | Uses custom PBS block driver instead |
| Other (Ceph) | 10+ | create, convert, info, compare, bench, snapshot |
pve-qemu - qemu Patches¶
Proxmox extends qemu-img through patches rather than wrapper scripts.
Extended qemu-img dd Command¶
Location: debian/patches/pve/0009-PVE-Up-qemu-img-dd-add-osize-and-read-from-to-stdin-.patch
qemu-img dd [--image-opts] [-U] [-f FMT] [-O OUTPUT_FMT] [-n] [-l SNAPSHOT]
[bs=BLOCK_SIZE] [count=BLOCKS] [skip=BLOCKS] [osize=OUTPUT_SIZE]
[isize=INPUT_SIZE] if=INPUT of=OUTPUT
PVE-specific extensions:
- osize: Output size parameter for stdin/stdout piping
- isize: Input size for writing small images to larger targets
- -n: Skip target volume creation (for pre-created volumes)
- -l: Load snapshot during dd operation
- Stdin/stdout support for raw format streaming
Data structures:
struct DdInfo {
unsigned int flags;
int64_t count;
int64_t osize; // PVE extension
int64_t isize; // PVE extension
};
Snapshot Info Return Code¶
Location: debian/patches/pve/0008-PVE-Up-qemu-img-return-success-on-info-without-snaps.patch
Modified qemu-img info to return success (0) instead of failure (1)
when no snapshots exist.
pve-storage - Perl Wrapper Module¶
Wrapper Module: PVE/Storage/Common.pm¶
qemu_img_create:
sub qemu_img_create {
my ($fmt, $size, $path, $options) = @_;
my $cmd = ['/usr/bin/qemu-img', 'create'];
push @$cmd, '-o', "preallocation=$options->{preallocation}"
if defined($options->{preallocation});
push @$cmd, '-f', $fmt, $path, "${size}K";
run_command($cmd, errmsg => "unable to create image");
}
qemu_img_create_qcow2_backed:
sub qemu_img_create_qcow2_backed {
my ($path, $backing_path, $backing_format, $options) = @_;
my $cmd = [
'/usr/bin/qemu-img', 'create',
'-F', $backing_format,
'-b', $backing_path,
'-f', 'qcow2',
$path,
];
my $opts = ['extended_l2=on', 'cluster_size=128k'];
push @$opts, "preallocation=$options->{preallocation}"
if defined($options->{preallocation});
push @$cmd, '-o', join(',', @$opts) if @$opts > 0;
run_command($cmd, errmsg => "unable to create image");
}
Default QCOW2 options:
- extended_l2=on: Extended L2 table support
- cluster_size=128k: 128KB clusters (vs default 64KB)
qemu_img_info:
sub qemu_img_info {
my ($filename, $file_format, $timeout, $follow_backing_files) = @_;
my $cmd = ['/usr/bin/qemu-img', 'info', '--output=json', $filename];
push $cmd->@*, '-f', $file_format if $file_format;
push $cmd->@*, '--backing-chain' if $follow_backing_files;
return run_qemu_img_json($cmd, $timeout);
}
qemu_img_measure:
sub qemu_img_measure {
my ($size, $fmt, $timeout, $options) = @_;
my $cmd = ['/usr/bin/qemu-img', 'measure', '--output=json',
'--size', "${size}K", '-O', $fmt];
return run_qemu_img_json($cmd, $timeout);
}
qemu_img_resize:
sub qemu_img_resize {
my ($path, $format, $size, $preallocation, $timeout) = @_;
my $cmd = ['/usr/bin/qemu-img', 'resize'];
push $cmd->@*, "--preallocation=$preallocation" if $preallocation;
push $cmd->@*, '-f', $format, $path, $size;
$timeout = 10 if !$timeout;
run_command($cmd, timeout => $timeout);
}
Snapshot Operations: PVE/Storage/Plugin.pm¶
# Create snapshot
my $cmd = ['/usr/bin/qemu-img', 'snapshot', '-c', $snap, $path];
# Rollback to snapshot
my $cmd = ['/usr/bin/qemu-img', 'snapshot', '-a', $snap, $path];
# Delete snapshot
$cmd = ['/usr/bin/qemu-img', 'snapshot', '-d', $snap, $path];
# Commit changes to backing file
$cmd = ['/usr/bin/qemu-img', 'commit', $childpath];
# Rebase to new backing file
$cmd = ['/usr/bin/qemu-img', 'rebase', '-b', $rel_parent_path,
'-F', 'qcow2', '-f', 'qcow2', $childpath];
Supported Formats¶
Format restrictions: - Resize: raw, qcow2 only - Snapshots: qcow2, qed only
Security Validation for Untrusted Images¶
if ($untrusted) {
if (my $format_specific = $info->{'format-specific'}) {
if ($format_specific->{type} eq 'qcow2' &&
$format_specific->{data}->{"data-file"}) {
die "$filename: 'data-file' references are not allowed!\n";
} elsif ($format_specific->{type} eq 'vmdk') {
my $extents = $format_specific->{data}->{extents};
die "$filename: multiple extents are not allowed!\n"
if scalar($extents->@*) > 1;
}
}
}
qemu-server - VM Disk Operations¶
Image Conversion: PVE/QemuServer/QemuImage.pm¶
sub convert {
my ($src_volid, $dst_volid, $size, $opts) = @_;
my $cmd = [];
push @$cmd, '/usr/bin/qemu-img', 'convert', '-p', '-n';
push @$cmd, '-l', "snapshot.name=$snapname" if $snapname;
push @$cmd, '-t', 'none' if $dst_scfg->{type} eq 'zfspool';
push @$cmd, '-T', $cachemode if defined($cachemode);
push @$cmd, '-r', "${bwlimit}K" if defined($bwlimit);
# ...
}
Features:
- Progress reporting with -p and custom parser
- Bandwidth limiting with -r
- Snapshot support with -l snapshot.name=
- Cache modes: none for ZFS, unsafe otherwise
- Support for --target-image-opts
DD-based EFI Disk Copy: PVE/QemuServer.pm¶
my $cmd = ['qemu-img', 'dd', '-n', '-f', $src_format, '-O', $dst_format];
push $cmd->@*, '-l', $snapname if $method eq 'qemu';
push $cmd->@*, "bs=$bs", "osize=$size", "if=$src_path", "of=$dst_path";
- Block size: 1MB for better Ceph performance
- Used specifically for EFI disk cloning
Use Cases¶
- Disk cloning:
clone_disk()→QemuImage::convert() - Disk import:
ImportDisk::do_import()→QemuImage::convert() - EFI initialization:
OVMF.pm→QemuImage::convert() - Backup restore:
restore_vm_volumes()→QemuImage::convert()
proxmox-backup - Custom Block Driver¶
Proxmox Backup Server does not use qemu-img. Instead, it implements
a custom qemu block driver (pbs: protocol) for direct archive access.
PBS block driver URI format:
Reason: Enables streaming from backup archives without intermediate image files or format conversion.
Other Components (Ceph Integration)¶
Test Scripts¶
RBD Migration Tests: ceph/qa/workunits/rbd/cli_migration.sh
qemu-img convert -f raw -O qcow rbd:rbd/${image} ${TEMPDIR}/${image}.qcow
qemu-img create -f qcow2 ${TEMPDIR}/${image}.qcow2 1G
qemu-img bench -f qcow2 -w -c 65536 -d 16 --pattern 65 -s 4096 ${image}.qcow2
qemu-img snapshot -c "snap1" ${image}.qcow2
qemu-img compare ${TEMPDIR}/large.raw rbd:rbd/${dest_image}
Python Test Framework¶
Location: qemu/tests/qemu-iotests/iotests.py
qemu_img_args = os.environ.get('qemu_IMG', 'qemu-img').strip().split(' ')
def qemu_img(*args):
'''Run qemu-img and return the exit code'''
return subprocess.call(qemu_img_args + list(args))
def qemu_img_pipe(*args):
'''Run qemu-img and return its output'''
return subprocess.Popen(qemu_img_args + list(args),
stdout=subprocess.PIPE).communicate()[0]
def compare_images(img1, img2):
return qemu_img('compare', '-f', imgfmt, '-F', imgfmt, img1, img2) == 0
Key Patterns for Instar (Proxmox)¶
Must Support¶
- Operations: convert, create, info, measure, resize, snapshot, dd, rebase, commit
- Formats: raw, qcow2, qcow, qed, vmdk, cloop
- PVE dd extensions: osize, isize, stdin/stdout, -n, -l snapshot
- QCOW2 options: extended_l2, cluster_size=128k, preallocation
- Progress:
-pwith percentage parsing - Bandwidth limiting:
-roption
Storage Backend Integration¶
| Backend | Special Handling |
|---|---|
| ZFS | Cache mode: none |
| RBD/Ceph | 1MB block size for dd |
| iSCSI | Path conversion to qemu format |
| LVM | Supports qcow2 snapshots on LV |
Command-Line Options Summary¶
| Option | Purpose | Used By |
|---|---|---|
-p |
Progress reporting | convert |
-n |
Skip target creation | convert, dd |
-f |
Source format | all |
-O |
Output format | convert, dd |
-t/-T |
Cache mode | convert |
-r |
Bandwidth limit | convert |
-l |
Load snapshot | convert, dd |
-b/-F |
Backing file | create, rebase |
-o |
Format options | create |
--output=json |
JSON output | info, measure |
--backing-chain |
Follow backing | info |
bs=, osize=, isize= |
DD parameters | dd |
OpenStack¶
Analysis of qemu-img usage patterns across OpenStack components.
Summary Statistics¶
| Component | Files | Operations |
|---|---|---|
| Cinder | 15+ | convert, info, create, resize, rebase, commit |
| Nova | 10+ | info, convert, create, rebase |
| Glance | 5+ | info (format inspection) |
| oslo.utils | 2 | info parsing (QemuImgInfo class) |
| os-brick | 0 | Uses cryptsetup instead |
Cinder - Volume Image Utilities¶
Wrapper Module: cinder/image/image_utils.py¶
Resource Limits:
qemu_IMG_LIMITS = processutils.ProcessLimits(
cpu_time=CONF.image_conversion_cpu_limit, # default 60 seconds
address_space=CONF.image_conversion_address_space_limit * units.Gi) # default 1GB
Image Info with Security:
cmd = ['env', 'LC_ALL=C', 'qemu-img', 'info',
'-f', format_name, '--output=json']
if force_share:
cmd.append('--force-share')
cmd.append(path)
out, _err = utils.execute(*cmd, run_as_root=run_as_root,
prlimit=qemu_IMG_LIMITS)
Version Detection:
info = utils.execute('qemu-img', '--version', check_exit_code=False)[0]
pattern = r"qemu-img version ([0-9\.]*)"
Image Conversion:
cmd = ['qemu-img', 'convert', '-O', out_format]
# Cache modes
cmd.extend(['-t', 'none']) # Direct I/O
# or
cmd.extend(['-t', 'writeback']) # Buffered
# Sparse support
cmd.extend(['-S', '0'])
# Compression
if compress:
cmd.append('-c')
# VMDK subformat
if out_subformat:
cmd.extend(['-o', 'subformat=%s' % out_subformat])
LUKS Encryption Support:
cmd = ['qemu-img', 'convert']
obj1 = ['--object',
'secret,id=sec1,format=raw,file=%s' % src_passphrase_file]
obj2 = ['--object',
'secret,id=sec2,format=raw,file=%s' % passphrase_file]
cmd.extend(['-O', 'luks',
'-o', 'cipher-alg=%s,cipher-mode=%s,ivgen-alg=%s' % cipher_spec])
Format Mapping:
Volume Drivers: cinder/volume/drivers/remotefs.py¶
Snapshot Creation:
# Unencrypted snapshot
command = ['qemu-img', 'create', '-f', 'qcow2', '-o',
'backing_file=%s,backing_fmt=%s' %
(backing_path, backing_fmt),
new_snap_path,
"%dG" % snapshot.volume.size]
# Encrypted snapshot with LUKS
command = ['qemu-img', 'create', '-f', 'qcow2',
'-o', 'encrypt.format=luks,encrypt.key-secret=s1,'
'encrypt.cipher-alg=%(cipher_alg)s,'
'encrypt.cipher-mode=%(cipher_mode)s,'
'encrypt.ivgen-alg=%(ivgen_alg)s' % cipher_spec,
'-b', 'json:' + file_json,
'--object', 'secret,id=s0,file=' + tmp_key.name,
'--object', 'secret,id=s1,file=' + tmp_key.name,
new_snap_path]
Snapshot Commit:
cmd = ['qemu-img', 'commit']
if passphrase_file:
obj = ['--object',
'secret,id=s0,format=raw,file=%s' % passphrase_file]
image_opts = ['--image-opts']
src_opts = "file.filename=%(filename)s,encrypt.format=luks," \
"encrypt.key-secret=s0,backing.file.filename=%(backing)s," \
"backing.encrypt.key-secret=s0" % {...}
cmd += obj + image_opts + ['-d', src_opts]
else:
cmd += ['-d', path]
Snapshot Rebase:
command = ['qemu-img', 'rebase', '-u']
if passphrase_file:
objectdef = "secret,id=s0,file=%s" % passphrase_file
command += ['--object', objectdef, '-b', backing_file,
'-F', volume_format, '--image-opts', filename]
else:
command += ['-b', backing_file, image, '-F', volume_format]
RBD Driver: cinder/volume/drivers/rbd.py¶
LUKS Volume Creation:
create_cmd = (
'qemu-img', 'create', '-f', 'luks',
'-o', 'cipher-alg=%(cipher_alg)s,'
'cipher-mode=%(cipher_mode)s,'
'ivgen-alg=%(ivgen_alg)s' % cipher_spec,
'--object', 'secret,id=luks_sec,'
'format=raw,file=%(passfile)s' % {'passfile': tmp_key.name},
'-o', 'key-secret=luks_sec',
tmp_image.name,
'%sM' % (volume.size * 1024))
Configuration Options¶
image_conversion_dir # Temporary storage during conversion
image_conversion_cpu_limit # 60 seconds default
image_conversion_address_space_limit # 1 GB default
image_conversion_disable # Can disable conversion entirely
image_compress_on_upload # Enable compression for qcow2
vmdk_allowed_types = ['streamOptimized', 'monolithicSparse']
Nova - Compute Image Backend¶
Image Info Utility¶
def qemu_img_info(path, format=None, run_as_root=True):
cmd = ['env', 'LC_ALL=C', 'qemu-img', 'info', path,
'--force-share', '--output=json']
if format:
cmd.extend(['-f', format])
out, err = processutils.execute(*cmd, run_as_root=run_as_root,
prlimit=qemu_IMG_LIMITS)
return imageutils.QemuImgInfo(out, format='json')
Disk Operations¶
# Create COW overlay
cmd = ['qemu-img', 'create', '-f', 'qcow2',
'-o', 'backing_file=%s,backing_fmt=%s' % (backing_file, backing_fmt),
path]
# Resize disk
cmd = ['qemu-img', 'resize', path, size]
# Convert format
cmd = ['qemu-img', 'convert', '-O', out_format, src_path, dst_path]
oslo.utils - QemuImgInfo Parser¶
Class: oslo_utils/imageutils/qemu.py¶
class QemuImgInfo:
"""Parse qemu-img info output."""
def __init__(self, cmd_output=None, format='text'):
if format == 'json':
self._parse_json(cmd_output)
else:
self._parse_text(cmd_output)
@property
def image(self): pass
@property
def backing_file(self): pass
@property
def file_format(self): pass
@property
def virtual_size(self): pass
@property
def disk_size(self): pass
@property
def cluster_size(self): pass
@property
def encrypted(self): pass
@property
def snapshots(self): pass
Regex Patterns for Human Format:
BACKING_FILE_RE = re.compile(r"^(.*?)\s*\(actual\s+path\s*:\s+(.*?)\)\s*$")
TOP_LEVEL_RE = re.compile(r"^([\w\s]+):\s+(.*?)\s*$")
SIZE_RE = re.compile(r"\(\s*(\d+)\s+bytes\s*\)")
Glance - Format Inspector¶
Safe Image Format Detection¶
class FormatInspector:
"""Safely determine image format without full parsing."""
@staticmethod
def from_file(filename):
"""Detect format from file magic bytes."""
with open(filename, 'rb') as f:
header = f.read(512)
if header[:4] == b'QFI\xfb':
return 'qcow2'
elif header[:4] == b'KDMV':
return 'vmdk'
# ... etc
LUKS Detection as Container:
# LUKS volumes appear as 'raw' containers in qemu-img
# Must detect LUKS signature separately
if header[:6] == b'LUKS\xba\xbe':
return 'luks'
os-brick - NO qemu-img Usage¶
Os-brick uses cryptsetup for LUKS encryption, not qemu-img:
class LuksEncryptor(base.VolumeEncryptor):
def _format_luks_volume(self, passphrase, version):
cmd = ["cryptsetup", "--batch-mode", "luksFormat",
"--type", version, "--key-file=-"]
self._execute(*cmd, process_input=passphrase, run_as_root=True)
def _open_volume(self, passphrase):
self._execute('cryptsetup', 'luksOpen', '--key-file=-',
self.dev_path, self.dev_name, process_input=passphrase,
run_as_root=True)
Key Patterns for Instar (OpenStack)¶
Must Support¶
- Operations: info, convert, create, resize, rebase, commit
- Formats: raw, qcow2, vmdk (streamOptimized, monolithicSparse), vpc, luks
- Encryption: LUKS with cipher-alg, cipher-mode, ivgen-alg, secret objects
- Progress: Percentage parsing for long operations
- Resource limits: CPU time, address space limits (prlimit)
- Force share:
--force-sharefor live image queries
LUKS Encryption Parameters¶
| Parameter | Options |
|---|---|
| cipher-alg | aes-128, aes-256 |
| cipher-mode | xts, cbc-essiv |
| ivgen-alg | plain64, essiv |
| key-secret | Secret object reference |
Rootwrap Filters¶
Configuration Integration¶
- CPU limit: 60 seconds default (configurable)
- Memory limit: 1 GB default (configurable)
- Conversion can be disabled entirely
- Compression optional for qcow2 uploads
Combined Requirements for Instar¶
Operations Matrix¶
| Operation | oVirt | Proxmox | OpenStack | Priority |
|---|---|---|---|---|
| info | ✓ | ✓ | ✓ | High |
| create | ✓ | ✓ | ✓ | High |
| convert | ✓ | ✓ | ✓ | High |
| measure | ✓ | ✓ | - | High |
| check | ✓ | - | - | Medium |
| commit | ✓ | ✓ | ✓ | Medium |
| rebase | ✓ | ✓ | ✓ | Medium |
| snapshot | - | ✓ | - | Medium |
| resize | - | ✓ | ✓ | Medium |
| dd | - | ✓ (extended) | - | Medium |
| map | ✓ | - | - | Low |
| amend | ✓ | - | - | Low |
| bitmap | ✓ | - | - | Low |
| compare | ✓ | ✓ (tests) | - | Low |
| bench | - | ✓ (tests) | - | Low |
Security Requirements¶
- Resource limits: All platforms limit CPU/memory for untrusted images
- Format validation: Block data-file references, multiple extents
- User context: Run as specific user (vdsm:kvm, www-data, root via rootwrap)
- Timeout handling: Support operation timeouts
- LUKS encryption: OpenStack requires secret object handling
Output Formats¶
- JSON output required for: info, measure, check, map
- Progress output:
(XX.XX/100%)format parsing - Human-readable parsing: oslo.utils QemuImgInfo for legacy support