* [PATCH v2 1/2] image: remove unrequested intermediate image types
@ 2026-11-04 7:25 'Clara Kowalsky' via isar-users
2026-11-04 7:26 ` [PATCH v2 2/2] imagetypes_vm: add support for standalone vmdk images 'Clara Kowalsky' via isar-users
0 siblings, 1 reply; 2+ messages in thread
From: 'Clara Kowalsky' via isar-users @ 2026-11-04 7:25 UTC (permalink / raw)
To: isar-users; +Cc: Clara Kowalsky
Images built only as dependencies currently remain in the deploy
directory even when they are not listed in IMAGE_FSTYPES.
Fix this by keeping only explicitly requested image outputs and removing
dependency-only images and conversion intermediates. Users who need a
dependency image retained should include it in IMAGE_FSTYPES.
Since dependencies are now also removed, run cleanup after all image
tasks finish rather than at the end of each producing task. This keeps
dependency images available until their consumers have completed.
Expanded file paths are recorded, so cleanup also handles type-specific
filenames and deploy directories.
Unittests are added to test dependency cleanup and retention of
requested outputs.
Signed-off-by: Clara Kowalsky <clara.kowalsky@siemens.com>
---
meta/classes-recipe/image.bbclass | 24 ++---
.../unittests/test_image_type_cleanup.py | 92 +++++++++++++++++++
2 files changed, 104 insertions(+), 12 deletions(-)
create mode 100644 testsuite/unittests/test_image_type_cleanup.py
diff --git a/meta/classes-recipe/image.bbclass b/meta/classes-recipe/image.bbclass
index ce19ae1c..229a37fe 100644
--- a/meta/classes-recipe/image.bbclass
+++ b/meta/classes-recipe/image.bbclass
@@ -187,6 +187,8 @@ SUDO_CHROOT = "imager_run -d ${PP_ROOTFS} -u root --"
# hook up IMAGE_CMD_*
python() {
image_types = (d.getVar('IMAGE_FSTYPES') or '').split()
+ requested_types = set(image_types)
+ intermediate_files = set()
conversions = set(d.getVar('IMAGE_CONVERSIONS').split())
chroot_mode = d.getVar('ISAR_CHROOT_MODE')
@@ -285,8 +287,10 @@ python() {
# add conversions
conversion_depends = set()
- rm_images = set()
def create_conversions(t):
+ localdata.setVar('type', t)
+ if t not in requested_types:
+ intermediate_files.add(localdata.getVar('IMAGE_FILE_HOST'))
for c in sorted(conversions):
if t.endswith('.' + c):
t = t[:-len(c) - 1]
@@ -301,20 +305,9 @@ python() {
for dep in (localdata.getVar('CONVERSION_DEPS:' + c) or '').split():
conversion_install.add(dep)
local_conversion_install.add(dep)
- # remove temporary image files
- if t not in image_types:
- rm_images.add(localdata.expand('${IMAGE_FILE_HOST}'))
-
for t in basetypes[bt]:
create_conversions(t)
- if bt not in image_types:
- localdata.setVar('type', t)
- rm_images.add(localdata.expand('${IMAGE_FILE_HOST}'))
-
- for image in rm_images:
- cmds.append('\trm ' + image)
-
# image type dependencies
after = 'do_image_tools'
for dep in typedeps[bt]:
@@ -340,6 +333,7 @@ python() {
d.appendVar('INSTALL_image_%s' % bt_clean, ' ' + ' '.join(sorted(local_imager_install | local_conversion_install)))
d.appendVarFlag(task, 'vardeps', ' INSTALL_image_%s' % bt_clean)
+ d.setVar('IMAGE_INTERMEDIATE_FILES', ' '.join(sorted(intermediate_files)))
d.appendVar('IMAGER_INSTALL', ' ' + ' '.join(sorted(imager_install | conversion_install)))
d.appendVar('IMAGER_BOM', ' ' + ' '.join(sorted(imager_bom)))
d.appendVar('IMAGER_BUILD_DEPS', ' ' + ' '.join(sorted(imager_build_deps)))
@@ -429,6 +423,12 @@ python do_image() {
"""Virtual task"""
pass
}
+python cleanup_image_intermediates() {
+ for image in (d.getVar('IMAGE_INTERMEDIATE_FILES') or '').split():
+ bb.utils.remove(image)
+}
+do_image[postfuncs] += "cleanup_image_intermediates"
+do_image[vardeps] += "IMAGE_INTERMEDIATE_FILES"
addtask image before do_build after do_image_tools
python do_deploy() {
diff --git a/testsuite/unittests/test_image_type_cleanup.py b/testsuite/unittests/test_image_type_cleanup.py
new file mode 100644
index 00000000..1e2ad5b9
--- /dev/null
+++ b/testsuite/unittests/test_image_type_cleanup.py
@@ -0,0 +1,92 @@
+# This software is a part of Isar.
+# Copyright (C) Siemens AG, 2026
+#
+# SPDX-License-Identifier: MIT
+
+import sys
+import tempfile
+import unittest
+from pathlib import Path
+
+root = Path(__file__).resolve().parents[2]
+sys.path.extend([
+ str(root / 'bitbake/lib'),
+ str(root / 'meta/lib'),
+])
+
+import bb.data
+from bb.build import exec_func
+from bb.parse import handle
+
+
+data = bb.data.init()
+data.setVar('BBPATH', f'{root}/meta:{root}/bitbake')
+data.setVar('__bbclasstype', 'recipe')
+data.setVar('IMGCLASSES', '')
+parsed = handle(str(root / 'meta/classes-recipe/image.bbclass'), data)
+data.setVar('IMAGE_TYPEDEP:ova', 'vmdk')
+data.setVar('IMAGE_TYPEDEP:vmdk', 'wic')
+data.setVar('IMAGE_CMD:vmdk', ':')
+namespace = {'bb': bb}
+exec(parsed['get_base_type'], namespace)
+image_tasks = next(
+ function for function in parsed.getVar('__BBANONFUNCS', False)
+ if 'def collect_image_type(' in parsed.getVar(function, False)
+)
+exec(parsed[image_tasks], namespace)
+
+
+class TestImageTypeCleanup(unittest.TestCase):
+ def generate_image_tasks(self, image_types, deploy_dir='/deploy'):
+ d = bb.data.createCopy(data)
+ d.setVar('IMAGE_FSTYPES', image_types)
+ d.setVar('DEPLOY_DIR_IMAGE', str(deploy_dir))
+ d.setVar('IMAGE_FULLNAME', 'image')
+ namespace[image_tasks](d)
+ return d
+
+ def assert_intermediates(self, image_types, expected):
+ d = self.generate_image_tasks(image_types)
+ self.assertEqual(
+ set(d.getVar('IMAGE_INTERMEDIATE_FILES').split()),
+ {'/deploy/image.' + image_type for image_type in expected},
+ )
+
+ def test_only_unrequested_types_are_intermediates(self):
+ self.assert_intermediates('ova.zst', {'ova', 'vmdk', 'wic'})
+ self.assert_intermediates('vmdk ova.zst', {'ova', 'wic'})
+ self.assert_intermediates('ova ova.zst vmdk wic', set())
+
+ def test_unrequested_conversion_stages_are_cleaned(self):
+ self.assert_intermediates('tar.gz.xz', {'tar', 'tar.gz'})
+ self.assert_intermediates('tar.gz tar.gz.xz', {'tar'})
+
+ def test_cleanup_uses_image_type_filename_overrides(self):
+ d = bb.data.createCopy(data)
+ d.setVar('IMAGE_FSTYPES', 'tar.gz')
+ d.setVar('IMAGE_FULLNAME:tar', 'custom-image')
+ d.setVar('DEPLOY_DIR_IMAGE:tar', '/custom-deploy')
+ namespace[image_tasks](d)
+ self.assertEqual(
+ d.getVar('IMAGE_INTERMEDIATE_FILES'),
+ '/custom-deploy/custom-image.tar',
+ )
+
+ def test_cleanup_removes_only_intermediate_files(self):
+ with tempfile.TemporaryDirectory() as deploy_dir:
+ deploy_dir = Path(deploy_dir)
+ for image_type in ('ova', 'wic', 'vmdk', 'ova.zst'):
+ (deploy_dir / ('image.' + image_type)).touch()
+
+ d = self.generate_image_tasks('vmdk ova.zst', deploy_dir)
+ d.setVar('T', str(deploy_dir / 'temp'))
+ exec_func('cleanup_image_intermediates', d)
+
+ self.assertEqual(
+ {path.name for path in deploy_dir.glob('image.*')},
+ {'image.vmdk', 'image.ova.zst'},
+ )
+
+
+if __name__ == '__main__':
+ unittest.main()
--
2.56.0
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20261104072600.3229817-1-clara.kowalsky%40siemens.com.
^ permalink raw reply [flat|nested] 2+ messages in thread* [PATCH v2 2/2] imagetypes_vm: add support for standalone vmdk images
2026-11-04 7:25 [PATCH v2 1/2] image: remove unrequested intermediate image types 'Clara Kowalsky' via isar-users
@ 2026-11-04 7:26 ` 'Clara Kowalsky' via isar-users
0 siblings, 0 replies; 2+ messages in thread
From: 'Clara Kowalsky' via isar-users @ 2026-11-04 7:26 UTC (permalink / raw)
To: isar-users; +Cc: Clara Kowalsky
This adds vmdk as an image type, so virtual machine disks can be
generated without OVA packaging. OVA depends on the vmdk image and
reuses its output. The generic image cleanup removes the intermediate
vmdk unless it is explicitly requested in IMAGE_FSTYPES.
Signed-off-by: Clara Kowalsky <clara.kowalsky@siemens.com>
---
doc/user_manual.md | 1 +
meta/classes-recipe/imagetypes_vm.bbclass | 18 ++++++++++++++----
2 files changed, 15 insertions(+), 4 deletions(-)
diff --git a/doc/user_manual.md b/doc/user_manual.md
index 09ac080b..199eb931 100644
--- a/doc/user_manual.md
+++ b/doc/user_manual.md
@@ -540,6 +540,7 @@ Currently, the following image types are provided:
- `wic` - full disk image with user-specified partitions created and populated using the wic tool
- `ubi` - image for use on mtd nand partitions employing UBI
- `ubifs` - raw UBI filesystem image, normally used together with UBI partitions
+ - `vmdk` - virtual machine disk image
- `ova` - Open Virtual Appliance: image for use on VirtualBox or VMware
- `wsl` - tar file for Windows Subsystem for Linux
- `squashfs` - raw squashfs filesystem image
diff --git a/meta/classes-recipe/imagetypes_vm.bbclass b/meta/classes-recipe/imagetypes_vm.bbclass
index fd4e97ed..32a72bf4 100644
--- a/meta/classes-recipe/imagetypes_vm.bbclass
+++ b/meta/classes-recipe/imagetypes_vm.bbclass
@@ -8,9 +8,13 @@ FILESEXTRAPATHS:prepend = "${LAYERDIR_core}/recipes-core/images:"
OVF_TEMPLATE_FILE ?= "virtualbox/vm-img-virtualbox.ovf.tmpl"
IMAGE_SRC_URI:ova = "file://${OVF_TEMPLATE_FILE}"
-IMAGE_TYPEDEP:ova = "wic"
+IMAGE_TYPEDEP:ova = "${@'vmdk' if d.getVar('VIRTUAL_MACHINE_IMAGE_TYPE') == 'vmdk' else 'wic'}"
IMAGER_INSTALL:ova += "qemu-utils gawk uuid-runtime"
+IMAGE_TYPEDEP:vmdk = "wic"
+IMAGER_INSTALL:vmdk += "qemu-utils"
+IMAGE_CMD:vmdk = "${convert_wic}"
+
# virtual machine disk settings
SOURCE_IMAGE_FILE ?= "${IMAGE_FULLNAME}.wic"
@@ -19,9 +23,16 @@ SOURCE_IMAGE_FILE ?= "${IMAGE_FULLNAME}.wic"
VMDK_SUBFORMAT ?= "monolithicSparse"
VIRTUAL_MACHINE_IMAGE_TYPE ?= "vmdk"
-VIRTUAL_MACHINE_IMAGE_FILE = "${IMAGE_FULLNAME}-disk001.${VIRTUAL_MACHINE_IMAGE_TYPE}"
+VIRTUAL_MACHINE_IMAGE_FILE = "${@get_ova_disk_file(d)}"
+VIRTUAL_MACHINE_IMAGE_TYPE:vmdk = "vmdk"
VIRTUAL_MACHINE_DISK = "${PP_DEPLOY}/${VIRTUAL_MACHINE_IMAGE_FILE}"
+def get_ova_disk_file(d):
+ if d.getVar("VIRTUAL_MACHINE_IMAGE_TYPE") == "vmdk":
+ return "%s.vmdk" % d.getVar("IMAGE_FULLNAME")
+ return "%s-disk001.%s" % (
+ d.getVar("IMAGE_FULLNAME"), d.getVar("VIRTUAL_MACHINE_IMAGE_TYPE"))
+
def set_convert_options(d):
format = d.getVar("VIRTUAL_MACHINE_IMAGE_TYPE")
if format == "vmdk":
@@ -66,7 +77,7 @@ OVA_VARS = "OVA_NAME OVA_MEMORY OVA_NUMBER_OF_CPU OVA_VRAM \
IMAGE_TEMPLATE_FILES:ova = "${OVF_TEMPLATE_FILE}"
IMAGE_TEMPLATE_VARS:ova = "${OVA_VARS}"
-do_image_ova[prefuncs] += "convert_wic"
+do_image_ova[prefuncs] += "${@'convert_wic' if d.getVar('VIRTUAL_MACHINE_IMAGE_TYPE') != 'vmdk' else ''}"
IMAGE_CMD:ova() {
if [ ! ${VIRTUAL_MACHINE_IMAGE_TYPE} = "vmdk" ]; then
exit 0
@@ -96,7 +107,6 @@ IMAGE_CMD:ova() {
tar -uvf ${PP_DEPLOY}/${IMAGE_FULLNAME}.ova -C ${PP_DEPLOY} ${VIRTUAL_MACHINE_IMAGE_FILE}
rm -f '${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.mf'
rm -f '${DEPLOY_DIR_IMAGE}/${IMAGE_FULLNAME}.ovf'
- rm -f '${DEPLOY_DIR_IMAGE}/${VIRTUAL_MACHINE_IMAGE_FILE}'
EOIMAGER
}
IMAGE_CMD:ova[depends] = "${PN}:do_transform_template"
--
2.56.0
--
You received this message because you are subscribed to the Google Groups "isar-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to isar-users+unsubscribe@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/isar-users/20261104072600.3229817-2-clara.kowalsky%40siemens.com.
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-11-04 7:26 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-04 7:25 [PATCH v2 1/2] image: remove unrequested intermediate image types 'Clara Kowalsky' via isar-users
2026-11-04 7:26 ` [PATCH v2 2/2] imagetypes_vm: add support for standalone vmdk images 'Clara Kowalsky' via isar-users
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox