diff options
| author | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-02-12 18:30:30 +0000 |
|---|---|---|
| committer | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-02-26 01:05:01 +0000 |
| commit | ac150976f5c892d3c4c919dcc2e0b15bc3761e02 (patch) | |
| tree | e14bf509c268cd9edf762a22ea3f0b0f837bd6e3 /classes/xen-guest-bundle.bbclass | |
| parent | f7022507859f519f87cbca5dcff437e9dc676ff0 (diff) | |
| download | meta-virtualization-ac150976f5c892d3c4c919dcc2e0b15bc3761e02.tar.gz | |
xen-guest-bundle: add bbclass for packaging Xen guest bundles
New bbclass that creates installable packages bundling Xen guest
images (rootfs + kernel + config). When installed via IMAGE_INSTALL
into a Dom0 image that inherits xen-guest-cross-install, guests are
automatically deployed by merge_installed_xen_bundles().
Features:
- Parse-time dependency generation from XEN_GUEST_BUNDLES
- Per-guest varflags for memory, vcpus, vif, extra, disk, name
- Custom config file support via XEN_GUEST_CONFIG_FILE varflag
- Explicit rootfs/kernel path overrides for external guests
- Manifest-based packaging for cross-install integration
Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com>
Diffstat (limited to 'classes/xen-guest-bundle.bbclass')
| -rw-r--r-- | classes/xen-guest-bundle.bbclass | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/classes/xen-guest-bundle.bbclass b/classes/xen-guest-bundle.bbclass new file mode 100644 index 00000000..0e061bfb --- /dev/null +++ b/classes/xen-guest-bundle.bbclass | |||
| @@ -0,0 +1,405 @@ | |||
| 1 | # SPDX-FileCopyrightText: Copyright (C) 2025 Bruce Ashfield | ||
| 2 | # | ||
| 3 | # SPDX-License-Identifier: MIT | ||
| 4 | # | ||
| 5 | # xen-guest-bundle.bbclass | ||
| 6 | # =========================================================================== | ||
| 7 | # Xen guest bundling class for creating installable guest packages | ||
| 8 | # =========================================================================== | ||
| 9 | # | ||
| 10 | # This class creates packages that bundle Xen guest images (rootfs + kernel + | ||
| 11 | # config). When these packages are installed via IMAGE_INSTALL into a Dom0 | ||
| 12 | # image that inherits xen-guest-cross-install, the guests are automatically | ||
| 13 | # merged into the target image by merge_installed_xen_bundles(). | ||
| 14 | # | ||
| 15 | # =========================================================================== | ||
| 16 | # Component Relationships | ||
| 17 | # =========================================================================== | ||
| 18 | # | ||
| 19 | # To bundle a guest like "xen-guest-image-minimal:autostart", two recipe | ||
| 20 | # types work together: | ||
| 21 | # | ||
| 22 | # 1. Guest Image Recipe (creates the guest rootfs) | ||
| 23 | # recipes-extended/images/xen-guest-image-minimal.bb | ||
| 24 | # +-- inherit core-image | ||
| 25 | # +-- Produces: ${DEPLOY_DIR_IMAGE}/xen-guest-image-minimal-${MACHINE}.ext4 | ||
| 26 | # | ||
| 27 | # 2. Bundle Recipe (packages guest images for deployment) | ||
| 28 | # recipes-extended/xen-guest-bundles/my-bundle_1.0.bb | ||
| 29 | # +-- inherit xen-guest-bundle | ||
| 30 | # +-- XEN_GUEST_BUNDLES = "xen-guest-image-minimal:autostart" | ||
| 31 | # +-- Creates installable package with rootfs, kernel, and config | ||
| 32 | # | ||
| 33 | # Flow diagram: | ||
| 34 | # | ||
| 35 | # xen-guest-image-minimal.bb | ||
| 36 | # (guest image recipe) | ||
| 37 | # | | ||
| 38 | # | do_image_complete | ||
| 39 | # v | ||
| 40 | # ${DEPLOY_DIR_IMAGE}/xen-guest-image-minimal-${MACHINE}.ext4 | ||
| 41 | # | | ||
| 42 | # | XEN_GUEST_BUNDLES="xen-guest-image-minimal" | ||
| 43 | # v | ||
| 44 | # my-bundle_1.0.bb --------> my-bundle package | ||
| 45 | # (inherits xen-guest-bundle) | | ||
| 46 | # | IMAGE_INSTALL="my-bundle" | ||
| 47 | # v | ||
| 48 | # xen-image-minimal | ||
| 49 | # (Dom0 host image) | ||
| 50 | # | ||
| 51 | # =========================================================================== | ||
| 52 | # When to Use This Class vs BUNDLED_XEN_GUESTS | ||
| 53 | # =========================================================================== | ||
| 54 | # | ||
| 55 | # There are two ways to bundle Xen guests into a host image: | ||
| 56 | # | ||
| 57 | # 1. BUNDLED_XEN_GUESTS variable (simpler, no extra recipe needed) | ||
| 58 | # Set in local.conf or image recipe: | ||
| 59 | # BUNDLED_XEN_GUESTS = "xen-guest-image-minimal:autostart" | ||
| 60 | # | ||
| 61 | # 2. xen-guest-bundle packages (this class) | ||
| 62 | # Create a bundle recipe, install via IMAGE_INSTALL | ||
| 63 | # | ||
| 64 | # Decision guide: | ||
| 65 | # | ||
| 66 | # Use Case | BUNDLED_XEN_GUESTS | Bundle Recipe | ||
| 67 | # --------------------------------------------|--------------------|-------------- | ||
| 68 | # Simple: guests in one host image | recommended | overkill | ||
| 69 | # Reuse guests across multiple host images | repetitive | recommended | ||
| 70 | # Package versioning and dependencies | not supported | supported | ||
| 71 | # Distribute pre-built guest sets | not supported | supported | ||
| 72 | # | ||
| 73 | # For most single-image use cases, BUNDLED_XEN_GUESTS is simpler. | ||
| 74 | # | ||
| 75 | # =========================================================================== | ||
| 76 | # Usage | ||
| 77 | # =========================================================================== | ||
| 78 | # | ||
| 79 | # inherit xen-guest-bundle | ||
| 80 | # | ||
| 81 | # XEN_GUEST_BUNDLES = "\ | ||
| 82 | # xen-guest-image-minimal:autostart \ | ||
| 83 | # my-other-guest \ | ||
| 84 | # " | ||
| 85 | # | ||
| 86 | # Variable format: recipe-name[:autostart][:external] | ||
| 87 | # - recipe-name: Yocto image recipe name that produces the guest rootfs | ||
| 88 | # - autostart: Optional. Creates symlink in /etc/xen/auto/ for xendomains | ||
| 89 | # - external: Optional. Skip dependency generation (3rd-party guest) | ||
| 90 | # | ||
| 91 | # Per-guest configuration via varflags (same interface as cross-install): | ||
| 92 | # XEN_GUEST_MEMORY[guest-name] = "1024" | ||
| 93 | # XEN_GUEST_VCPUS[guest-name] = "2" | ||
| 94 | # XEN_GUEST_VIF[guest-name] = "bridge=xenbr0" | ||
| 95 | # XEN_GUEST_EXTRA[guest-name] = "root=/dev/xvda ro console=hvc0 ip=dhcp" | ||
| 96 | # XEN_GUEST_DISK_DEVICE[guest-name] = "xvda" | ||
| 97 | # XEN_GUEST_NAME[guest-name] = "my-custom-name" | ||
| 98 | # | ||
| 99 | # Custom config file (replaces auto-generation entirely): | ||
| 100 | # SRC_URI += "file://custom.cfg" | ||
| 101 | # XEN_GUEST_CONFIG_FILE[guest-name] = "${UNPACKDIR}/custom.cfg" | ||
| 102 | # | ||
| 103 | # Explicit rootfs/kernel paths (for external/3rd-party guests): | ||
| 104 | # XEN_GUEST_ROOTFS[my-vendor-guest] = "vendor-rootfs.ext4" | ||
| 105 | # XEN_GUEST_KERNEL[my-vendor-guest] = "vendor-kernel" | ||
| 106 | # | ||
| 107 | # =========================================================================== | ||
| 108 | # Integration with xen-guest-cross-install.bbclass | ||
| 109 | # =========================================================================== | ||
| 110 | # | ||
| 111 | # This class creates packages that are processed by xen-guest-cross-install: | ||
| 112 | # 1. Installs guest files to ${datadir}/xen-guest-bundles/${PN}/ | ||
| 113 | # 2. merge_installed_xen_bundles() copies them to final locations at image time | ||
| 114 | # 3. Bundle files are removed from the final image after merge | ||
| 115 | # | ||
| 116 | # See also: xen-guest-cross-install.bbclass | ||
| 117 | |||
| 118 | XEN_GUEST_BUNDLES ?= "" | ||
| 119 | XEN_GUEST_IMAGE_FSTYPE ?= "ext4" | ||
| 120 | XEN_GUEST_MEMORY_DEFAULT ?= "512" | ||
| 121 | XEN_GUEST_VCPUS_DEFAULT ?= "1" | ||
| 122 | XEN_GUEST_VIF_DEFAULT ?= "bridge=xenbr0" | ||
| 123 | XEN_GUEST_EXTRA_DEFAULT ?= "root=/dev/xvda ro ip=dhcp" | ||
| 124 | XEN_GUEST_DISK_DEVICE_DEFAULT ?= "xvda" | ||
| 125 | |||
| 126 | # =========================================================================== | ||
| 127 | # Parse-time dependency generation | ||
| 128 | # =========================================================================== | ||
| 129 | |||
| 130 | python __anonymous() { | ||
| 131 | bundles = (d.getVar('XEN_GUEST_BUNDLES') or "").split() | ||
| 132 | if not bundles: | ||
| 133 | return | ||
| 134 | |||
| 135 | processed = [] | ||
| 136 | deps = "" | ||
| 137 | |||
| 138 | for entry in bundles: | ||
| 139 | parts = entry.split(':') | ||
| 140 | guest_name = parts[0] | ||
| 141 | |||
| 142 | is_external = 'external' in parts | ||
| 143 | is_autostart = 'autostart' in parts | ||
| 144 | |||
| 145 | # Generate dependency on guest recipe (unless external) | ||
| 146 | if not is_external: | ||
| 147 | deps += " %s:do_image_complete" % guest_name | ||
| 148 | |||
| 149 | # Store processed entry: guest_name:autostart_flag | ||
| 150 | autostart_flag = "autostart" if is_autostart else "" | ||
| 151 | processed.append("%s:%s" % (guest_name, autostart_flag)) | ||
| 152 | |||
| 153 | if deps: | ||
| 154 | d.appendVarFlag('do_compile', 'depends', deps) | ||
| 155 | |||
| 156 | d.setVar('_PROCESSED_XEN_BUNDLES', ' '.join(processed)) | ||
| 157 | |||
| 158 | # Build config file map from varflags | ||
| 159 | # Format: guest1=/path/to/file1;guest2=/path/to/file2 | ||
| 160 | config_mappings = [] | ||
| 161 | for entry in bundles: | ||
| 162 | guest_name = entry.split(':')[0] | ||
| 163 | custom_file = d.getVarFlag('XEN_GUEST_CONFIG_FILE', guest_name) | ||
| 164 | if custom_file: | ||
| 165 | config_mappings.append("%s=%s" % (guest_name, custom_file)) | ||
| 166 | d.setVar('_XEN_GUEST_CONFIG_FILE_MAP', ';'.join(config_mappings)) | ||
| 167 | |||
| 168 | # Build params map from varflags | ||
| 169 | # Format: guest1=memory|vcpus|vif|extra|disk_device|name|rootfs|kernel;guest2=... | ||
| 170 | mem_default = d.getVar('XEN_GUEST_MEMORY_DEFAULT') | ||
| 171 | vcpus_default = d.getVar('XEN_GUEST_VCPUS_DEFAULT') | ||
| 172 | vif_default = d.getVar('XEN_GUEST_VIF_DEFAULT') | ||
| 173 | extra_default = d.getVar('XEN_GUEST_EXTRA_DEFAULT') | ||
| 174 | disk_default = d.getVar('XEN_GUEST_DISK_DEVICE_DEFAULT') | ||
| 175 | |||
| 176 | param_mappings = [] | ||
| 177 | for entry in bundles: | ||
| 178 | guest_name = entry.split(':')[0] | ||
| 179 | |||
| 180 | memory = d.getVarFlag('XEN_GUEST_MEMORY', guest_name) or mem_default | ||
| 181 | vcpus = d.getVarFlag('XEN_GUEST_VCPUS', guest_name) or vcpus_default | ||
| 182 | vif = d.getVarFlag('XEN_GUEST_VIF', guest_name) or vif_default | ||
| 183 | extra = d.getVarFlag('XEN_GUEST_EXTRA', guest_name) or extra_default | ||
| 184 | disk_device = d.getVarFlag('XEN_GUEST_DISK_DEVICE', guest_name) or disk_default | ||
| 185 | name = d.getVarFlag('XEN_GUEST_NAME', guest_name) or guest_name | ||
| 186 | rootfs = d.getVarFlag('XEN_GUEST_ROOTFS', guest_name) or "" | ||
| 187 | kernel = d.getVarFlag('XEN_GUEST_KERNEL', guest_name) or "" | ||
| 188 | |||
| 189 | params = "|".join([memory, vcpus, vif, extra, disk_device, name, rootfs, kernel]) | ||
| 190 | param_mappings.append("%s=%s" % (guest_name, params)) | ||
| 191 | |||
| 192 | d.setVar('_XEN_GUEST_PARAMS_MAP', ';'.join(param_mappings)) | ||
| 193 | } | ||
| 194 | |||
| 195 | S = "${UNPACKDIR}/sources" | ||
| 196 | B = "${WORKDIR}/build" | ||
| 197 | |||
| 198 | do_patch[noexec] = "1" | ||
| 199 | do_configure[noexec] = "1" | ||
| 200 | |||
| 201 | # =========================================================================== | ||
| 202 | # do_compile: resolve guests and generate configs | ||
| 203 | # =========================================================================== | ||
| 204 | |||
| 205 | do_compile() { | ||
| 206 | set -e | ||
| 207 | |||
| 208 | mkdir -p "${S}" | ||
| 209 | rm -rf "${B}/images" "${B}/configs" | ||
| 210 | mkdir -p "${B}/images" | ||
| 211 | mkdir -p "${B}/configs" | ||
| 212 | |||
| 213 | # Clear manifest | ||
| 214 | : > "${B}/manifest" | ||
| 215 | |||
| 216 | if [ -z "${_PROCESSED_XEN_BUNDLES}" ]; then | ||
| 217 | bbnote "No Xen guest bundles to process" | ||
| 218 | return 0 | ||
| 219 | fi | ||
| 220 | |||
| 221 | bbnote "Processing Xen guest bundles: ${_PROCESSED_XEN_BUNDLES}" | ||
| 222 | |||
| 223 | for bundle in ${_PROCESSED_XEN_BUNDLES}; do | ||
| 224 | guest_name=$(echo "$bundle" | cut -d: -f1) | ||
| 225 | autostart_flag=$(echo "$bundle" | cut -d: -f2) | ||
| 226 | |||
| 227 | bbnote "Processing guest: $guest_name (autostart=$autostart_flag)" | ||
| 228 | |||
| 229 | # Resolve rootfs | ||
| 230 | rootfs_path=$(resolve_bundle_rootfs "$guest_name") | ||
| 231 | if [ -z "$rootfs_path" ]; then | ||
| 232 | bbfatal "Cannot resolve rootfs for guest '$guest_name'" | ||
| 233 | fi | ||
| 234 | rootfs_basename=$(basename "$rootfs_path") | ||
| 235 | |||
| 236 | # Resolve kernel | ||
| 237 | kernel_path=$(resolve_bundle_kernel "$guest_name") | ||
| 238 | if [ -z "$kernel_path" ]; then | ||
| 239 | bbfatal "Cannot resolve kernel for guest '$guest_name'" | ||
| 240 | fi | ||
| 241 | kernel_basename=$(basename "$kernel_path") | ||
| 242 | |||
| 243 | # Copy to build dir (readlink -f resolves versioned symlinks) | ||
| 244 | cp "$(readlink -f "$rootfs_path")" "${B}/images/${rootfs_basename}" | ||
| 245 | cp "$(readlink -f "$kernel_path")" "${B}/images/${kernel_basename}" | ||
| 246 | |||
| 247 | # Generate or install config | ||
| 248 | config_map="${_XEN_GUEST_CONFIG_FILE_MAP}" | ||
| 249 | custom_config=$(echo "$config_map" | tr ';' '\n' | grep "^${guest_name}=" | cut -d= -f2-) | ||
| 250 | |||
| 251 | if [ -n "$custom_config" ] && [ -f "$custom_config" ]; then | ||
| 252 | bbnote "Installing custom config: $custom_config" | ||
| 253 | sed -E \ | ||
| 254 | -e "s#^(disk = \[)[^,]+#\1'file:/var/lib/xen/images/$rootfs_basename#" \ | ||
| 255 | -e "s#^(kernel = )\"[^\"]+\"#\1\"/var/lib/xen/images/$kernel_basename\"#" \ | ||
| 256 | "$custom_config" > "${B}/configs/${guest_name}.cfg" | ||
| 257 | else | ||
| 258 | bbnote "Generating config for $guest_name" | ||
| 259 | generate_bundle_config "$guest_name" "$rootfs_basename" "$kernel_basename" \ | ||
| 260 | "${B}/configs/${guest_name}.cfg" | ||
| 261 | fi | ||
| 262 | |||
| 263 | # Write manifest entry: guest_name:rootfs_file:kernel_file:autostart_flag | ||
| 264 | echo "${guest_name}:${rootfs_basename}:${kernel_basename}:${autostart_flag}" >> "${B}/manifest" | ||
| 265 | |||
| 266 | bbnote "Guest '$guest_name' compiled successfully" | ||
| 267 | done | ||
| 268 | } | ||
| 269 | |||
| 270 | # Resolve guest rootfs path from DEPLOY_DIR_IMAGE | ||
| 271 | resolve_bundle_rootfs() { | ||
| 272 | local guest="$1" | ||
| 273 | local params_map="${_XEN_GUEST_PARAMS_MAP}" | ||
| 274 | |||
| 275 | # Check for explicit rootfs override (field 6) | ||
| 276 | local guest_params=$(echo "$params_map" | tr ';' '\n' | grep "^${guest}=" | cut -d= -f2-) | ||
| 277 | local override="" | ||
| 278 | if [ -n "$guest_params" ]; then | ||
| 279 | override=$(echo "$guest_params" | cut -d'|' -f7) | ||
| 280 | fi | ||
| 281 | |||
| 282 | if [ -n "$override" ]; then | ||
| 283 | local path="${DEPLOY_DIR_IMAGE}/$override" | ||
| 284 | if [ -e "$path" ]; then | ||
| 285 | echo "$path" | ||
| 286 | return 0 | ||
| 287 | fi | ||
| 288 | bbwarn "XEN_GUEST_ROOTFS override '$override' not found at $path" | ||
| 289 | return 1 | ||
| 290 | fi | ||
| 291 | |||
| 292 | # Standard Yocto naming: <recipe>-<MACHINE>.<fstype> | ||
| 293 | local path="${DEPLOY_DIR_IMAGE}/${guest}-${MACHINE}.${XEN_GUEST_IMAGE_FSTYPE}" | ||
| 294 | if [ -e "$path" ]; then | ||
| 295 | echo "$path" | ||
| 296 | return 0 | ||
| 297 | fi | ||
| 298 | |||
| 299 | # Fallback: <recipe>-<MACHINE>.rootfs.<fstype> | ||
| 300 | path="${DEPLOY_DIR_IMAGE}/${guest}-${MACHINE}.rootfs.${XEN_GUEST_IMAGE_FSTYPE}" | ||
| 301 | if [ -e "$path" ]; then | ||
| 302 | echo "$path" | ||
| 303 | return 0 | ||
| 304 | fi | ||
| 305 | |||
| 306 | bbwarn "Guest rootfs not found for '$guest'. Searched:" | ||
| 307 | bbwarn " ${DEPLOY_DIR_IMAGE}/${guest}-${MACHINE}.${XEN_GUEST_IMAGE_FSTYPE}" | ||
| 308 | bbwarn " ${DEPLOY_DIR_IMAGE}/${guest}-${MACHINE}.rootfs.${XEN_GUEST_IMAGE_FSTYPE}" | ||
| 309 | return 1 | ||
| 310 | } | ||
| 311 | |||
| 312 | # Resolve guest kernel path from DEPLOY_DIR_IMAGE | ||
| 313 | resolve_bundle_kernel() { | ||
| 314 | local guest="$1" | ||
| 315 | local params_map="${_XEN_GUEST_PARAMS_MAP}" | ||
| 316 | |||
| 317 | # Check for explicit kernel override (field 7) | ||
| 318 | local guest_params=$(echo "$params_map" | tr ';' '\n' | grep "^${guest}=" | cut -d= -f2-) | ||
| 319 | local override="" | ||
| 320 | if [ -n "$guest_params" ]; then | ||
| 321 | override=$(echo "$guest_params" | cut -d'|' -f8) | ||
| 322 | fi | ||
| 323 | |||
| 324 | if [ -n "$override" ]; then | ||
| 325 | local path="${DEPLOY_DIR_IMAGE}/$override" | ||
| 326 | if [ -e "$path" ]; then | ||
| 327 | echo "$path" | ||
| 328 | return 0 | ||
| 329 | fi | ||
| 330 | bbwarn "XEN_GUEST_KERNEL override '$override' not found at $path" | ||
| 331 | return 1 | ||
| 332 | fi | ||
| 333 | |||
| 334 | # Default: shared kernel (same MACHINE) | ||
| 335 | local path="${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGETYPE}" | ||
| 336 | if [ -e "$path" ]; then | ||
| 337 | echo "$path" | ||
| 338 | return 0 | ||
| 339 | fi | ||
| 340 | |||
| 341 | bbwarn "Guest kernel not found at ${DEPLOY_DIR_IMAGE}/${KERNEL_IMAGETYPE}" | ||
| 342 | return 1 | ||
| 343 | } | ||
| 344 | |||
| 345 | # Generate a Xen guest configuration file with final target paths | ||
| 346 | generate_bundle_config() { | ||
| 347 | local guest="$1" | ||
| 348 | local rootfs_basename="$2" | ||
| 349 | local kernel_basename="$3" | ||
| 350 | local outfile="$4" | ||
| 351 | local params_map="${_XEN_GUEST_PARAMS_MAP}" | ||
| 352 | |||
| 353 | # Extract params | ||
| 354 | local guest_params=$(echo "$params_map" | tr ';' '\n' | grep "^${guest}=" | cut -d= -f2-) | ||
| 355 | |||
| 356 | local memory=$(echo "$guest_params" | cut -d'|' -f1) | ||
| 357 | local vcpus=$(echo "$guest_params" | cut -d'|' -f2) | ||
| 358 | local vif=$(echo "$guest_params" | cut -d'|' -f3) | ||
| 359 | local extra=$(echo "$guest_params" | cut -d'|' -f4) | ||
| 360 | local disk_device=$(echo "$guest_params" | cut -d'|' -f5) | ||
| 361 | local name=$(echo "$guest_params" | cut -d'|' -f6) | ||
| 362 | |||
| 363 | cat > "$outfile" << EOF | ||
| 364 | name = "$name" | ||
| 365 | memory = $memory | ||
| 366 | vcpus = $vcpus | ||
| 367 | disk = ['file:/var/lib/xen/images/$rootfs_basename,$disk_device,rw'] | ||
| 368 | vif = ['$vif'] | ||
| 369 | kernel = "/var/lib/xen/images/$kernel_basename" | ||
| 370 | extra = "$extra" | ||
| 371 | EOF | ||
| 372 | } | ||
| 373 | |||
| 374 | # =========================================================================== | ||
| 375 | # do_install: package for merge_installed_xen_bundles | ||
| 376 | # =========================================================================== | ||
| 377 | |||
| 378 | do_install() { | ||
| 379 | if [ ! -f "${B}/manifest" ] || [ ! -s "${B}/manifest" ]; then | ||
| 380 | bbnote "No guests to install" | ||
| 381 | return 0 | ||
| 382 | fi | ||
| 383 | |||
| 384 | install -d ${D}${datadir}/xen-guest-bundles/${PN}/images | ||
| 385 | install -d ${D}${datadir}/xen-guest-bundles/${PN}/configs | ||
| 386 | |||
| 387 | # Install guest images | ||
| 388 | if [ -d "${B}/images" ] && [ -n "$(ls -A ${B}/images 2>/dev/null)" ]; then | ||
| 389 | cp ${B}/images/* ${D}${datadir}/xen-guest-bundles/${PN}/images/ | ||
| 390 | fi | ||
| 391 | |||
| 392 | # Install guest configs | ||
| 393 | if [ -d "${B}/configs" ] && [ -n "$(ls -A ${B}/configs 2>/dev/null)" ]; then | ||
| 394 | cp ${B}/configs/* ${D}${datadir}/xen-guest-bundles/${PN}/configs/ | ||
| 395 | fi | ||
| 396 | |||
| 397 | # Install manifest | ||
| 398 | install -m 0644 ${B}/manifest ${D}${datadir}/xen-guest-bundles/${PN}/manifest | ||
| 399 | } | ||
| 400 | |||
| 401 | FILES:${PN} = "${datadir}/xen-guest-bundles" | ||
| 402 | |||
| 403 | # Guest rootfs images are binary filesystem images that contain build paths | ||
| 404 | # internally (normal for ext4/etc images) and can be large | ||
| 405 | INSANE_SKIP:${PN} += "installed-vs-shipped buildpaths" | ||
