Repository: osbuild/osbuild-composer
Pull request #2909 (2022-08-23 10:47:02)

Add the `rhsm.facts` stage.
Work has been ongoing to store RHSM facts into built images. This PR is part of the `osbuild-composer` side of things but has some problems to solve and/or discuss.

In this initial pull request only the `ApiType` used to request the compose is stored in the `rhsm.facts` file eventually created by `osbuild`.


This pull request includes:

- [ ] adequate testing for the new functionality or fixed issue
- [ ] adequate documentation informing people about the change such as
  - [ ] submit a PR for the [guides](https://github.com/osbuild/guides) repository if this PR changed any behavior described there: https://www.osbuild.org/guides/

<!--
Thanks for proposing a change to osbuild-composer!

Please don't remove the above check list. These are things that each pull
request must have before it is merged. It helps maintainers to not forget
anything.

If the reason for ticking any of the boxes is ambiguous, please add a short
note explaining why.

In addition, if this pull request fixes a downstream issue, please refer to
test/README.md and add these additional items:

- [ ] 1st commit of any `rhbz#` related PR contains bug reproducer; CI reports FAIL or
- [ ] PR contains automated tests for new functionality and
- [ ] QE has approved reproducer/new tests and
- [ ] Subsequent commits provide bug fixes without modifying the reproducer; CI reports PASS and
- [ ] QE approves this PR; RHBZ status is set to `MODIFIED + Verified=Tested`

Information regarding our GitLab pipeline (Schutzbot):

CI will not be ran automatically if WIP label is applied or the PR is in DRAFT state, instead only
a link will be provided to the pipeline which can then be triggered manually if desired. To run the
CI automatically either switch the PR to ready or apply WIP+test label.

Outside contributors need manual approval from one of the osbuild-composer maintainers.

Schutzbot will only be triggered if all Tests jobs in GitHub workflow succeed.
-->


thozza: @supakeen you need to update the `Requires` in the SPEC file to osbuild v63, because there is currently v62, which does not include the `rhsm.facts` stage.
https://github.com/osbuild/osbuild-composer/blob/de6b8e8f5b783113a8d4cfd50fddc6c25c1568cd/osbuild-composer.spec#L308-L316
teg: Apart from the comment from @thozza , this looks great!
supakeen: Thank you @thozza, I've force pushed the dependency update.
Gundersanne: The osbuild commit in Schutzfile needs to be udpated to f3e2c8d5e9fcfdb8d73d2f111f7ed178c52310eb as well, otherwise it won't find v63
thozza: > The osbuild commit in the Schutzfile needs to be updated to f3e2c8d5e9fcfdb8d73d2f111f7ed178c52310eb as well, as that's where CI constructs osbuild's repo url from.

So the v63 was supposed to be already in the stable repos, but https://github.com/osbuild/osbuild-composer/pull/2902 was not merged yet so we came to the same conclusion with Simon... Ideally the override should not be needed at all.
Gundersanne: > > The osbuild commit in the Schutzfile needs to be updated to f3e2c8d5e9fcfdb8d73d2f111f7ed178c52310eb as well, as that's where CI constructs osbuild's repo url from.
> 
> So the v63 was supposed to be already in the stable repos, but #2902 was not merged yet so we came to the same conclusion with Simon... Ideally the override should not be needed at all.

Ahh makes sense. Thanks for the info.
supakeen: CI breaking on a depsolve job (invalid package set requested) and OSTree related things, force pushed the change for the second bit (moving the stage before prepping OSTree).

Patch:
diff --git a/Schutzfile b/Schutzfile
index c337e9e34..581061e34 100644
--- a/Schutzfile
+++ b/Schutzfile
@@ -2,7 +2,7 @@
   "fedora-35": {
     "dependencies": {
       "osbuild": {
-        "commit": "376cbffd136bc4ba86fc7c63697fa5b88fe3acef"
+        "commit": "ba218f781d4c7455cd995eea55be09e902370905"
       }
     },
     "repos": [
@@ -79,7 +79,7 @@
   "fedora-36": {
     "dependencies": {
       "osbuild": {
-        "commit": "376cbffd136bc4ba86fc7c63697fa5b88fe3acef"
+        "commit": "ba218f781d4c7455cd995eea55be09e902370905"
       }
     },
     "repos": [
@@ -156,21 +156,21 @@
   "rhel-8.4": {
     "dependencies": {
       "osbuild": {
-        "commit": "376cbffd136bc4ba86fc7c63697fa5b88fe3acef"
+        "commit": "ba218f781d4c7455cd995eea55be09e902370905"
       }
     }
   },
   "rhel-8.6": {
     "dependencies": {
       "osbuild": {
-        "commit": "376cbffd136bc4ba86fc7c63697fa5b88fe3acef"
+        "commit": "ba218f781d4c7455cd995eea55be09e902370905"
       }
     }
   },
   "rhel-8.7": {
     "dependencies": {
       "osbuild": {
-        "commit": "376cbffd136bc4ba86fc7c63697fa5b88fe3acef"
+        "commit": "ba218f781d4c7455cd995eea55be09e902370905"
       }
     },
     "repos": [
@@ -216,14 +216,14 @@
   "rhel-9.0": {
     "dependencies": {
       "osbuild": {
-        "commit": "376cbffd136bc4ba86fc7c63697fa5b88fe3acef"
+        "commit": "ba218f781d4c7455cd995eea55be09e902370905"
       }
     }
   },
   "rhel-9.1": {
     "dependencies": {
       "osbuild": {
-        "commit": "376cbffd136bc4ba86fc7c63697fa5b88fe3acef"
+        "commit": "ba218f781d4c7455cd995eea55be09e902370905"
       }
     },
     "repos": [
@@ -269,21 +269,21 @@
   "centos-8": {
     "dependencies": {
       "osbuild": {
-        "commit": "376cbffd136bc4ba86fc7c63697fa5b88fe3acef"
+        "commit": "ba218f781d4c7455cd995eea55be09e902370905"
       }
     }
   },
   "centos-9": {
     "dependencies": {
       "osbuild": {
-        "commit": "376cbffd136bc4ba86fc7c63697fa5b88fe3acef"
+        "commit": "ba218f781d4c7455cd995eea55be09e902370905"
       }
     }
   },
   "centos-stream-9": {
     "dependencies": {
       "osbuild": {
-        "commit": "376cbffd136bc4ba86fc7c63697fa5b88fe3acef"
+        "commit": "ba218f781d4c7455cd995eea55be09e902370905"
       }
     },
     "repos": [
@@ -329,7 +329,7 @@
   "centos-stream-8": {
     "dependencies": {
       "osbuild": {
-        "commit": "376cbffd136bc4ba86fc7c63697fa5b88fe3acef"
+        "commit": "ba218f781d4c7455cd995eea55be09e902370905"
       }
     },
     "repos": [
@@ -386,4 +386,4 @@
       }
     ]
   }
-}
\ No newline at end of file
+}
diff --git a/internal/cloudapi/v2/handler.go b/internal/cloudapi/v2/handler.go
index 9a9ecbcac..a4e32370b 100644
--- a/internal/cloudapi/v2/handler.go
+++ b/internal/cloudapi/v2/handler.go
@@ -269,6 +269,10 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
 		}
 
 		imageOptions := distro.ImageOptions{Size: imageType.Size(0)}
+		imageOptions.Facts = &distro.FactsImageOptions{
+			ApiType: "cloudapi-v2",
+		}
+
 		if request.Customizations != nil && request.Customizations.Subscription != nil {
 			imageOptions.Subscription = &distro.SubscriptionImageOptions{
 				Organization:  request.Customizations.Subscription.Organization,
diff --git a/internal/distro/distro.go b/internal/distro/distro.go
index d27973bfe..f11a1cfd5 100644
--- a/internal/distro/distro.go
+++ b/internal/distro/distro.go
@@ -129,6 +129,7 @@ type ImageOptions struct {
 	OSTree       ostree.RequestParams
 	Size         uint64
 	Subscription *SubscriptionImageOptions
+	Facts        *FactsImageOptions
 }
 
 // The SubscriptionImageOptions specify subscription-specific image options
@@ -142,6 +143,12 @@ type SubscriptionImageOptions struct {
 	Insights      bool
 }
 
+// The FactsImageOptions specify things to be stored into the Insights facts
+// storage. This mostly relates to how the build of the image was performed.
+type FactsImageOptions struct {
+	ApiType string
+}
+
 type BasePartitionTableMap map[string]disk.PartitionTable
 
 // A Manifest is an opaque JSON object, which is a valid input to osbuild
diff --git a/internal/distro/rhel8/pipelines.go b/internal/distro/rhel8/pipelines.go
index 33f4874b5..8cf0ea557 100644
--- a/internal/distro/rhel8/pipelines.go
+++ b/internal/distro/rhel8/pipelines.go
@@ -266,7 +266,7 @@ func edgeInstallerPipelines(t *imageType, customizations *blueprint.Customizatio
 	pipelines = append(pipelines, *anacondaTreePipeline(repos, installerPackages, kernelVer, archName, d.product, d.osVersion, "edge", ksUsers))
 	isolabel := fmt.Sprintf(d.isolabelTmpl, archName)
 	pipelines = append(pipelines, *bootISOTreePipeline(kernelVer, archName, d.vendor, d.product, d.osVersion, isolabel, kickstartOptions, payloadStages))
-	pipelines = append(pipelines, *bootISOPipeline(t.Filename(), d.isolabelTmpl, archName, false))
+	pipelines = append(pipelines, *bootISOPipeline(t.Filename(), d.isolabelTmpl, archName, t.Arch().Name() == "x86_64"))
 	return pipelines, nil
 }
 
@@ -690,6 +690,14 @@ func osPipeline(t *imageType,
 		p.AddStage(osbuild.NewSELinuxStage(selinuxStageOptions(false)))
 	}
 
+	if options.Facts != nil {
+		p.AddStage(osbuild.NewRHSMFactsStage(&osbuild.RHSMFactsStageOptions{
+			Facts: osbuild.RHSMFacts{
+				ApiType: options.Facts.ApiType,
+			},
+		}))
+	}
+
 	if t.rpmOstree {
 		p.AddStage(osbuild.NewOSTreePrepTreeStage(&osbuild.OSTreePrepTreeStageOptions{
 			EtcGroupMembers: []string{
diff --git a/internal/distro/rhel9/pipelines.go b/internal/distro/rhel9/pipelines.go
index 09c7fef3b..4105d211f 100644
--- a/internal/distro/rhel9/pipelines.go
+++ b/internal/distro/rhel9/pipelines.go
@@ -258,7 +258,7 @@ func edgeInstallerPipelines(t *imageType, customizations *blueprint.Customizatio
 	pipelines = append(pipelines, *anacondaTreePipeline(repos, installerPackages, kernelVer, archName, d.product, d.osVersion, "edge", ksUsers))
 	isolabel := fmt.Sprintf(d.isolabelTmpl, archName)
 	pipelines = append(pipelines, *bootISOTreePipeline(kernelVer, archName, d.vendor, d.product, d.osVersion, isolabel, kickstartOptions, payloadStages))
-	pipelines = append(pipelines, *bootISOPipeline(t.Filename(), d.isolabelTmpl, archName, false))
+	pipelines = append(pipelines, *bootISOPipeline(t.Filename(), d.isolabelTmpl, archName, t.Arch().Name() == "x86_64"))
 	return pipelines, nil
 }
 
@@ -688,6 +688,14 @@ func osPipeline(t *imageType,
 		p.AddStage(osbuild.NewSELinuxStage(selinuxStageOptions(false)))
 	}
 
+	if options.Facts != nil {
+		p.AddStage(osbuild.NewRHSMFactsStage(&osbuild.RHSMFactsStageOptions{
+			Facts: osbuild.RHSMFacts{
+				ApiType: options.Facts.ApiType,
+			},
+		}))
+	}
+
 	if t.rpmOstree {
 		p.AddStage(osbuild.NewOSTreePrepTreeStage(&osbuild.OSTreePrepTreeStageOptions{
 			EtcGroupMembers: []string{
diff --git a/internal/image/ostree_installer.go b/internal/image/ostree_installer.go
index 8cdbd9a3f..4d9f17b09 100644
--- a/internal/image/ostree_installer.go
+++ b/internal/image/ostree_installer.go
@@ -73,6 +73,7 @@ func (img *OSTreeInstaller) InstantiateManifest(m *manifest.Manifest,
 
 	isoPipeline := manifest.NewISO(m, buildPipeline, isoTreePipeline)
 	isoPipeline.Filename = img.Filename
+	isoPipeline.ISOLinux = true
 	artifact := isoPipeline.Export()
 
 	return artifact, nil
diff --git a/internal/osbuild/rhsm_facts_stage.go b/internal/osbuild/rhsm_facts_stage.go
new file mode 100644
index 000000000..e4984338e
--- /dev/null
+++ b/internal/osbuild/rhsm_facts_stage.go
@@ -0,0 +1,19 @@
+package osbuild
+
+type RHSMFactsStageOptions struct {
+	Facts RHSMFacts `json:"facts"`
+}
+
+type RHSMFacts struct {
+	ApiType string `json:"image-builder.osbuild-composer.api-type"`
+}
+
+func (RHSMFactsStageOptions) isStageOptions() {}
+
+// NewRHSMFactsStage creates a new RHSM stage
+func NewRHSMFactsStage(options *RHSMFactsStageOptions) *Stage {
+	return &Stage{
+		Type:    "org.osbuild.rhsm.facts",
+		Options: options,
+	}
+}
diff --git a/internal/weldr/api.go b/internal/weldr/api.go
index 8992221eb..d50706d6d 100644
--- a/internal/weldr/api.go
+++ b/internal/weldr/api.go
@@ -2351,6 +2351,9 @@ func (api *API) composeHandler(writer http.ResponseWriter, request *http.Request
 			URL:    cr.OSTree.URL,
 		},
 	}
+	options.Facts = &distro.FactsImageOptions{
+		ApiType: "weldr",
+	}
 
 	packageSets, err := api.depsolveBlueprintForImageType(*bp, options, imageType)
 	if err != nil {
diff --git a/osbuild-composer.spec b/osbuild-composer.spec
index e43fd6f44..924d7cdae 100644
--- a/osbuild-composer.spec
+++ b/osbuild-composer.spec
@@ -309,10 +309,10 @@ The core osbuild-composer binary. This is suitable both for spawning in containe
 Summary:    The worker for osbuild-composer
 Requires:   systemd
 Requires:   qemu-img
-Requires:   osbuild >= 62
-Requires:   osbuild-ostree >= 62
-Requires:   osbuild-lvm2 >= 62
-Requires:   osbuild-luks2 >= 62
+Requires:   osbuild >= 63
+Requires:   osbuild-ostree >= 63
+Requires:   osbuild-lvm2 >= 63
+Requires:   osbuild-luks2 >= 63
 Requires:   %{name}-dnf-json = %{version}-%{release}
 
 %description worker


Test patch:
diff --git a/internal/osbuild/rhsm_facts_stage_test.go b/internal/osbuild/rhsm_facts_stage_test.go
new file mode 100644
index 000000000..579b98683
--- /dev/null
+++ b/internal/osbuild/rhsm_facts_stage_test.go
@@ -0,0 +1,46 @@
+package osbuild
+
+import (
+	"encoding/json"
+	"fmt"
+	"reflect"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+)
+
+func TestNewRHSMFactsStage(t *testing.T) {
+	expectedStage := &Stage{
+		Type:    "org.osbuild.rhsm.facts",
+		Options: &RHSMFactsStageOptions{},
+	}
+	actualStage := NewRHSMFactsStage(&RHSMFactsStageOptions{})
+	assert.Equal(t, expectedStage, actualStage)
+}
+
+func TestRHSMFactsStageJson(t *testing.T) {
+	tests := []struct {
+		Options    RHSMFactsStageOptions
+		JsonString string
+	}{
+		{
+			Options: RHSMFactsStageOptions{
+				Facts: RHSMFacts{
+					ApiType: "test-api",
+				},
+			},
+			JsonString: fmt.Sprintf(`{"facts":{"image-builder.osbuild-composer.api-type":"%s"}}`, "test-api"),
+		},
+	}
+	for _, test := range tests {
+		marshaledJson, err := json.Marshal(test.Options)
+		require.NoError(t, err, "failed to marshal JSON")
+		require.Equal(t, test.JsonString, string(marshaledJson))
+
+		var jsonOptions RHSMFactsStageOptions
+		err = json.Unmarshal([]byte(test.JsonString), &jsonOptions)
+		require.NoError(t, err, "failed to parse JSON")
+		require.True(t, reflect.DeepEqual(test.Options, jsonOptions))
+	}
+}
diff --git a/test/cases/ostree-ng.sh b/test/cases/ostree-ng.sh
index 2ce6e6bf8..c5af75c58 100755
--- a/test/cases/ostree-ng.sh
+++ b/test/cases/ostree-ng.sh
@@ -75,6 +75,7 @@ EOF
 # Set up variables.
 TEST_UUID=$(uuidgen)
 IMAGE_KEY="osbuild-composer-ostree-test-${TEST_UUID}"
+BIOS_GUEST_ADDRESS=192.168.100.50
 UEFI_GUEST_ADDRESS=192.168.100.51
 PROD_REPO_URL=http://192.168.100.1/repo
 PROD_REPO=/var/www/html/repo
@@ -90,7 +91,7 @@ CONTAINER_TYPE=edge-container
 CONTAINER_FILENAME=container.tar
 INSTALLER_TYPE=edge-installer
 INSTALLER_FILENAME=installer.iso
-ANSIBLE_USER_FOR_UEFI="installeruser"
+ANSIBLE_USER_FOR_BIOS="installeruser"
 OSTREE_OSNAME=rhel
 
 # Set up temporary files.
@@ -515,9 +516,79 @@ sudo restorecon -Rv /var/lib/libvirt/images/
 
 # Create qcow2 file for virt install.
 greenprint "🖥 Create qcow2 file for virt install"
+LIBVIRT_BIOS_IMAGE_PATH=/var/lib/libvirt/images/${IMAGE_KEY}-bios.qcow2
 LIBVIRT_UEFI_IMAGE_PATH=/var/lib/libvirt/images/${IMAGE_KEY}-uefi.qcow2
+sudo qemu-img create -f qcow2 "${LIBVIRT_BIOS_IMAGE_PATH}" 20G
 sudo qemu-img create -f qcow2 "${LIBVIRT_UEFI_IMAGE_PATH}" 20G
 
+##################################################
+##
+## Install and test Edge image on BIOS VM
+##
+##################################################
+# Install ostree image via anaconda.
+greenprint "💿 Install ostree image via installer(ISO) on BIOS VM"
+sudo virt-install  --name="${IMAGE_KEY}-bios" \
+                   --disk path="${LIBVIRT_BIOS_IMAGE_PATH}",format=qcow2 \
+                   --ram 3072 \
+                   --vcpus 2 \
+                   --network network=integration,mac=34:49:22:B0:83:30 \
+                   --os-type linux \
+                   --os-variant ${OS_VARIANT} \
+                   --cdrom "/var/lib/libvirt/images/${ISO_FILENAME}" \
+                   --nographics \
+                   --noautoconsole \
+                   --wait=-1 \
+                   --noreboot
+
+# Start VM.
+greenprint "📟 Start BIOS VM"
+sudo virsh start "${IMAGE_KEY}-bios"
+
+# Check for ssh ready to go.
+greenprint "🛃 Checking for SSH is ready to go"
+for LOOP_COUNTER in $(seq 0 30); do
+    RESULTS="$(wait_for_ssh_up $BIOS_GUEST_ADDRESS)"
+    if [[ $RESULTS == 1 ]]; then
+        echo "SSH is ready now! 🥳"
+        break
+    fi
+    sleep 10
+done
+
+# Check image installation result
+check_result
+
+# Get ostree commit value.
+greenprint "🕹 Get ostree install commit value"
+INSTALL_HASH=$(curl "${PROD_REPO_URL}/refs/heads/${OSTREE_REF}")
+
+# Run Edge test on BIOS VM
+# Add instance IP address into /etc/ansible/hosts
+# Run BIOS VM test with installeruser added by edge-installer bp as ansible user
+sudo tee "${TEMPDIR}"/inventory > /dev/null << EOF
+[ostree_guest]
+${BIOS_GUEST_ADDRESS}
+[ostree_guest:vars]
+ansible_python_interpreter=/usr/bin/python3
+ansible_user=${ANSIBLE_USER_FOR_BIOS}
+ansible_private_key_file=${SSH_KEY}
+ansible_ssh_common_args="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
+EOF
+
+# Test IoT/Edge OS
+greenprint "📼 Run Edge tests on BIOS VM"
+sudo ansible-playbook -v -i "${TEMPDIR}"/inventory -e image_type="$OSTREE_OSNAME" -e ostree_commit="${INSTALL_HASH}" -e embeded_container="${EMBEDED_CONTAINER}" /usr/share/tests/osbuild-composer/ansible/check_ostree.yaml || RESULTS=0
+check_result
+
+# Clean up BIOS VM
+greenprint "🧹 Clean up BIOS VM"
+if [[ $(sudo virsh domstate "${IMAGE_KEY}-bios") == "running" ]]; then
+    sudo virsh destroy "${IMAGE_KEY}-bios"
+fi
+sudo virsh undefine "${IMAGE_KEY}-bios"
+sudo rm -f "$LIBVIRT_BIOS_IMAGE_PATH"
+
 ##################################################
 ##
 ## Install, upgrade and test Edge image on UEFI VM
@@ -567,7 +638,7 @@ ${UEFI_GUEST_ADDRESS}
 
 [ostree_guest:vars]
 ansible_python_interpreter=/usr/bin/python3
-ansible_user=${ANSIBLE_USER_FOR_UEFI}
+ansible_user=${ANSIBLE_USER_FOR_BIOS}
 ansible_private_key_file=${SSH_KEY}
 ansible_ssh_common_args="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
 EOF
@@ -710,7 +781,7 @@ ${UEFI_GUEST_ADDRESS}
 
 [ostree_guest:vars]
 ansible_python_interpreter=/usr/bin/python3
-ansible_user=${ANSIBLE_USER_FOR_UEFI}
+ansible_user=${ANSIBLE_USER_FOR_BIOS}
 ansible_private_key_file=${SSH_KEY}
 ansible_ssh_common_args="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null"
 EOF
diff --git a/test/data/manifests/centos_8-x86_64-edge_installer-boot.json b/test/data/manifests/centos_8-x86_64-edge_installer-boot.json
index 6d0ea66e1..4e057d4ad 100644
--- a/test/data/manifests/centos_8-x86_64-edge_installer-boot.json
+++ b/test/data/manifests/centos_8-x86_64-edge_installer-boot.json
@@ -9139,7 +9139,12 @@
               "filename": "installer.iso",
               "volid": "CentOS-Stream-8-x86_64-dvd",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/centos_8-x86_64-edge_installer_with_users-boot.json b/test/data/manifests/centos_8-x86_64-edge_installer_with_users-boot.json
index 1a6ebc008..7cc6c4a4b 100644
--- a/test/data/manifests/centos_8-x86_64-edge_installer_with_users-boot.json
+++ b/test/data/manifests/centos_8-x86_64-edge_installer_with_users-boot.json
@@ -9191,7 +9191,12 @@
               "filename": "installer.iso",
               "volid": "CentOS-Stream-8-x86_64-dvd",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/centos_9-x86_64-edge_installer-boot.json b/test/data/manifests/centos_9-x86_64-edge_installer-boot.json
index bfd1cbc79..fb14ee7fa 100644
--- a/test/data/manifests/centos_9-x86_64-edge_installer-boot.json
+++ b/test/data/manifests/centos_9-x86_64-edge_installer-boot.json
@@ -9392,7 +9392,12 @@
               "filename": "installer.iso",
               "volid": "CentOS-Stream-9-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/centos_9-x86_64-edge_installer_with_users-boot.json b/test/data/manifests/centos_9-x86_64-edge_installer_with_users-boot.json
index 1f6cdc63f..da0006c3b 100644
--- a/test/data/manifests/centos_9-x86_64-edge_installer_with_users-boot.json
+++ b/test/data/manifests/centos_9-x86_64-edge_installer_with_users-boot.json
@@ -9444,7 +9444,12 @@
               "filename": "installer.iso",
               "volid": "CentOS-Stream-9-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/fedora_35-aarch64-fedora_iot_installer-boot.json b/test/data/manifests/fedora_35-aarch64-fedora_iot_installer-boot.json
index 6b3d71e83..f32b5164b 100644
--- a/test/data/manifests/fedora_35-aarch64-fedora_iot_installer-boot.json
+++ b/test/data/manifests/fedora_35-aarch64-fedora_iot_installer-boot.json
@@ -10104,7 +10104,12 @@
               "filename": "installer.iso",
               "volid": "Fedora-35-BaseOS-aarch64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/fedora_35-aarch64-fedora_iot_installer_with_users-boot.json b/test/data/manifests/fedora_35-aarch64-fedora_iot_installer_with_users-boot.json
index 999cdace0..5da244fa0 100644
--- a/test/data/manifests/fedora_35-aarch64-fedora_iot_installer_with_users-boot.json
+++ b/test/data/manifests/fedora_35-aarch64-fedora_iot_installer_with_users-boot.json
@@ -10156,7 +10156,12 @@
               "filename": "installer.iso",
               "volid": "Fedora-35-BaseOS-aarch64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/fedora_35-x86_64-fedora_iot_installer-boot.json b/test/data/manifests/fedora_35-x86_64-fedora_iot_installer-boot.json
index aedae9c14..18e1a7d2e 100644
--- a/test/data/manifests/fedora_35-x86_64-fedora_iot_installer-boot.json
+++ b/test/data/manifests/fedora_35-x86_64-fedora_iot_installer-boot.json
@@ -10297,7 +10297,12 @@
               "filename": "installer.iso",
               "volid": "Fedora-35-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/fedora_35-x86_64-fedora_iot_installer_with_users-boot.json b/test/data/manifests/fedora_35-x86_64-fedora_iot_installer_with_users-boot.json
index b55dad0c0..afa6f623f 100644
--- a/test/data/manifests/fedora_35-x86_64-fedora_iot_installer_with_users-boot.json
+++ b/test/data/manifests/fedora_35-x86_64-fedora_iot_installer_with_users-boot.json
@@ -10349,7 +10349,12 @@
               "filename": "installer.iso",
               "volid": "Fedora-35-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/fedora_36-aarch64-fedora_iot_installer-boot.json b/test/data/manifests/fedora_36-aarch64-fedora_iot_installer-boot.json
index d703dd2cc..953abb403 100644
--- a/test/data/manifests/fedora_36-aarch64-fedora_iot_installer-boot.json
+++ b/test/data/manifests/fedora_36-aarch64-fedora_iot_installer-boot.json
@@ -10624,7 +10624,12 @@
               "filename": "installer.iso",
               "volid": "Fedora-36-BaseOS-aarch64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/fedora_36-aarch64-fedora_iot_installer_with_users-boot.json b/test/data/manifests/fedora_36-aarch64-fedora_iot_installer_with_users-boot.json
index 716599ef5..6eee329f9 100644
--- a/test/data/manifests/fedora_36-aarch64-fedora_iot_installer_with_users-boot.json
+++ b/test/data/manifests/fedora_36-aarch64-fedora_iot_installer_with_users-boot.json
@@ -10676,7 +10676,12 @@
               "filename": "installer.iso",
               "volid": "Fedora-36-BaseOS-aarch64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/fedora_36-x86_64-fedora_iot_installer-boot.json b/test/data/manifests/fedora_36-x86_64-fedora_iot_installer-boot.json
index 0562e1dfd..fbceadc85 100644
--- a/test/data/manifests/fedora_36-x86_64-fedora_iot_installer-boot.json
+++ b/test/data/manifests/fedora_36-x86_64-fedora_iot_installer-boot.json
@@ -10809,7 +10809,12 @@
               "filename": "installer.iso",
               "volid": "Fedora-36-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/fedora_36-x86_64-fedora_iot_installer_with_users-boot.json b/test/data/manifests/fedora_36-x86_64-fedora_iot_installer_with_users-boot.json
index 24be5fc74..42574f2bf 100644
--- a/test/data/manifests/fedora_36-x86_64-fedora_iot_installer_with_users-boot.json
+++ b/test/data/manifests/fedora_36-x86_64-fedora_iot_installer_with_users-boot.json
@@ -10861,7 +10861,12 @@
               "filename": "installer.iso",
               "volid": "Fedora-36-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/rhel_8-x86_64-edge_installer-boot.json b/test/data/manifests/rhel_8-x86_64-edge_installer-boot.json
index 04e4dd13a..2749cf686 100644
--- a/test/data/manifests/rhel_8-x86_64-edge_installer-boot.json
+++ b/test/data/manifests/rhel_8-x86_64-edge_installer-boot.json
@@ -3673,7 +3673,12 @@
               "filename": "installer.iso",
               "volid": "RHEL-8-6-0-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/rhel_8-x86_64-edge_installer_with_users-boot.json b/test/data/manifests/rhel_8-x86_64-edge_installer_with_users-boot.json
index 4a2b791eb..c9769e364 100644
--- a/test/data/manifests/rhel_8-x86_64-edge_installer_with_users-boot.json
+++ b/test/data/manifests/rhel_8-x86_64-edge_installer_with_users-boot.json
@@ -3725,7 +3725,12 @@
               "filename": "installer.iso",
               "volid": "RHEL-8-6-0-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/rhel_84-x86_64-edge_installer-boot.json b/test/data/manifests/rhel_84-x86_64-edge_installer-boot.json
index b8cb2bd8d..6de8f9a54 100644
--- a/test/data/manifests/rhel_84-x86_64-edge_installer-boot.json
+++ b/test/data/manifests/rhel_84-x86_64-edge_installer-boot.json
@@ -3715,7 +3715,12 @@
               "filename": "installer.iso",
               "volid": "RHEL-8-4-0-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/rhel_84-x86_64-edge_installer_with_users-boot.json b/test/data/manifests/rhel_84-x86_64-edge_installer_with_users-boot.json
index 665d0d6ae..d8ee1b80d 100644
--- a/test/data/manifests/rhel_84-x86_64-edge_installer_with_users-boot.json
+++ b/test/data/manifests/rhel_84-x86_64-edge_installer_with_users-boot.json
@@ -3767,7 +3767,12 @@
               "filename": "installer.iso",
               "volid": "RHEL-8-4-0-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/rhel_85-x86_64-edge_installer-boot.json b/test/data/manifests/rhel_85-x86_64-edge_installer-boot.json
index 25fe7fd40..02d98f521 100644
--- a/test/data/manifests/rhel_85-x86_64-edge_installer-boot.json
+++ b/test/data/manifests/rhel_85-x86_64-edge_installer-boot.json
@@ -3679,7 +3679,12 @@
               "filename": "installer.iso",
               "volid": "RHEL-8-5-0-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/rhel_85-x86_64-edge_installer_with_users-boot.json b/test/data/manifests/rhel_85-x86_64-edge_installer_with_users-boot.json
index 25fe7fd40..02d98f521 100644
--- a/test/data/manifests/rhel_85-x86_64-edge_installer_with_users-boot.json
+++ b/test/data/manifests/rhel_85-x86_64-edge_installer_with_users-boot.json
@@ -3679,7 +3679,12 @@
               "filename": "installer.iso",
               "volid": "RHEL-8-5-0-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/rhel_86-x86_64-edge_installer-boot.json b/test/data/manifests/rhel_86-x86_64-edge_installer-boot.json
index c0fd74c93..7881affb5 100644
--- a/test/data/manifests/rhel_86-x86_64-edge_installer-boot.json
+++ b/test/data/manifests/rhel_86-x86_64-edge_installer-boot.json
@@ -3673,7 +3673,12 @@
               "filename": "installer.iso",
               "volid": "RHEL-8-6-0-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/rhel_86-x86_64-edge_installer_with_users-boot.json b/test/data/manifests/rhel_86-x86_64-edge_installer_with_users-boot.json
index 05933d45d..115a643e1 100644
--- a/test/data/manifests/rhel_86-x86_64-edge_installer_with_users-boot.json
+++ b/test/data/manifests/rhel_86-x86_64-edge_installer_with_users-boot.json
@@ -3725,7 +3725,12 @@
               "filename": "installer.iso",
               "volid": "RHEL-8-6-0-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/rhel_87-x86_64-edge_installer-boot.json b/test/data/manifests/rhel_87-x86_64-edge_installer-boot.json
index 62f532ab6..aa2594637 100644
--- a/test/data/manifests/rhel_87-x86_64-edge_installer-boot.json
+++ b/test/data/manifests/rhel_87-x86_64-edge_installer-boot.json
@@ -3736,7 +3736,12 @@
               "filename": "installer.iso",
               "volid": "RHEL-8-7-0-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/rhel_87-x86_64-edge_installer_with_users-boot.json b/test/data/manifests/rhel_87-x86_64-edge_installer_with_users-boot.json
index bf383fb10..98c28d071 100644
--- a/test/data/manifests/rhel_87-x86_64-edge_installer_with_users-boot.json
+++ b/test/data/manifests/rhel_87-x86_64-edge_installer_with_users-boot.json
@@ -3788,7 +3788,12 @@
               "filename": "installer.iso",
               "volid": "RHEL-8-7-0-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/rhel_90-x86_64-edge_installer-boot.json b/test/data/manifests/rhel_90-x86_64-edge_installer-boot.json
index 3736b4a07..ec6b22821 100644
--- a/test/data/manifests/rhel_90-x86_64-edge_installer-boot.json
+++ b/test/data/manifests/rhel_90-x86_64-edge_installer-boot.json
@@ -3765,7 +3765,12 @@
               "filename": "installer.iso",
               "volid": "RHEL-9-0-0-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/rhel_90-x86_64-edge_installer_with_users-boot.json b/test/data/manifests/rhel_90-x86_64-edge_installer_with_users-boot.json
index 35cd043a2..ee29da1bb 100644
--- a/test/data/manifests/rhel_90-x86_64-edge_installer_with_users-boot.json
+++ b/test/data/manifests/rhel_90-x86_64-edge_installer_with_users-boot.json
@@ -3817,7 +3817,12 @@
               "filename": "installer.iso",
               "volid": "RHEL-9-0-0-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/rhel_91-x86_64-edge_installer-boot.json b/test/data/manifests/rhel_91-x86_64-edge_installer-boot.json
index 3e5df8793..efa31097d 100644
--- a/test/data/manifests/rhel_91-x86_64-edge_installer-boot.json
+++ b/test/data/manifests/rhel_91-x86_64-edge_installer-boot.json
@@ -9568,7 +9568,12 @@
               "filename": "installer.iso",
               "volid": "RHEL-9-1-0-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },
diff --git a/test/data/manifests/rhel_91-x86_64-edge_installer_with_users-boot.json b/test/data/manifests/rhel_91-x86_64-edge_installer_with_users-boot.json
index d758ab3a0..ad4fdb1bc 100644
--- a/test/data/manifests/rhel_91-x86_64-edge_installer_with_users-boot.json
+++ b/test/data/manifests/rhel_91-x86_64-edge_installer_with_users-boot.json
@@ -9620,7 +9620,12 @@
               "filename": "installer.iso",
               "volid": "RHEL-9-1-0-BaseOS-x86_64",
               "sysid": "LINUX",
+              "boot": {
+                "image": "isolinux/isolinux.bin",
+                "catalog": "isolinux/boot.cat"
+              },
               "efi": "images/efiboot.img",
+              "isohybridmbr": "/usr/share/syslinux/isohdpfx.bin",
               "isolevel": 3
             }
           },