Repository: osbuild/osbuild-composer
Pull request #1350 (2021-04-10 12:05:01)

distro/rhel84: build qcow2 images with compat=0.10
*"backport" from the rhel-8.4.0 branch*

By default, `qemu-img convert` creates qcow2 images usable in qemu 1.1 and
newer. RHEL 8 guest images are meant to be bootable on RHEL 6 though.
Unfortunately, RHEL 6 has qemu 0.12, therefore these images cannot be used
there.

To fix this, we need to use the new qcow2_compat option in qemu assembler
to override the default compat version and make qcow2 images that can be used
in qemu 0.10 and newer.

For this, we need osbuild 28 that is currently only available in RHEL 8.4,
therefore it's being pinned for now in Fedora, CentOS Stream and RHEL 8.3

Signed-off-by: Ondřej Budai <ondrej@budai.cz>


This pull request includes:

- [x] adequate testing for the new functionality or fixed issue
- [x] adequate documentation informing people about the change such as
  - [x] create a file in [news/unreleased](https://github.com/osbuild/osbuild-composer/tree/main/docs/news/unreleased) directory if this change should be mentioned in the release news
  - [ ] 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.

For user-visible changes, "adequate documentation" is an entry describing the
change for users in docs/news. Please refer to docs/news/README.md for details.

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`
-->


ondrejbudai: Ah, I need to pin osbuild also in RHEL 8.4 because it only has `27.2`. We might be fine with `Requires: osbuild >= 27.2` here but I think that depending on `osbuild 28` is just cleaner.
teg: We shouldn't be testing 8.4 on `main` anymore though, should we?
ondrejbudai: Let's leave it as follow-up?
ondrejbudai: I would also argue that main should still be able to build 8.4 so we need some coverage.
teg: Yeah, leave it as a follow-up. But I think the test should be: `main` should be able to build all the `rhel` verions on the `koji` API against the most recent `osbuild` major release on a RHEL8.3 host. Needs some work to make this elegant in shutzbot though.

Patch:
diff --git a/Schutzfile b/Schutzfile
index 0b9f37463..0b99196fb 100644
--- a/Schutzfile
+++ b/Schutzfile
@@ -1,5 +1,17 @@
 {
+  "fedora-32": {
+    "dependencies": {
+      "osbuild": {
+        "commit": "eb74ddf2ef8c203b5d354dfb97adee65babdc147"
+      }
+    }
+  },
   "fedora-33": {
+    "dependencies": {
+      "osbuild": {
+        "commit": "eb74ddf2ef8c203b5d354dfb97adee65babdc147"
+      }
+    },
     "dependants": {
       "koji-osbuild": {
         "commit": "4fdc457745e1147475ea3ac1e3b073e592d7b174"
@@ -9,7 +21,7 @@
   "rhel-8.3": {
     "dependencies": {
       "osbuild": {
-        "commit": "e4e527b5b7cdf8bb6e48a6ec3ace7d9d9b155bc0"
+        "commit": "eb74ddf2ef8c203b5d354dfb97adee65babdc147"
       }
     },
     "dependants": {
@@ -21,10 +33,17 @@
       }
     }
   },
+  "rhel-8.4": {
+    "dependencies": {
+      "osbuild": {
+        "commit": "eb74ddf2ef8c203b5d354dfb97adee65babdc147"
+      }
+    }
+  },
   "centos-8": {
     "dependencies": {
       "osbuild": {
-        "commit": "e4e527b5b7cdf8bb6e48a6ec3ace7d9d9b155bc0"
+        "commit": "eb74ddf2ef8c203b5d354dfb97adee65babdc147"
       }
     }
   }
diff --git a/docs/news/unreleased/rhel84-qcow2-compat.md b/docs/news/unreleased/rhel84-qcow2-compat.md
new file mode 100644
index 000000000..63db04770
--- /dev/null
+++ b/docs/news/unreleased/rhel84-qcow2-compat.md
@@ -0,0 +1,6 @@
+# RHEL 8.4: qcow2 images can now be used by older QEMUs
+
+Previously, the guest image for RHEL 8.4 was only usable by QEMU 1.1 and
+newer. However, this image should be usable on RHEL 6 that ships an older
+version of QEMU. This is now fixed and the guest image can be now used by
+QEMU 0.10 and newer.
diff --git a/internal/distro/rhel84/distro.go b/internal/distro/rhel84/distro.go
index e596f9d20..dac243d30 100644
--- a/internal/distro/rhel84/distro.go
+++ b/internal/distro/rhel84/distro.go
@@ -742,11 +742,12 @@ func defaultPartitionTable(imageOptions distro.ImageOptions, arch distro.Arch, r
 	panic("unknown arch: " + arch.Name())
 }
 
-func qemuAssembler(pt *disk.PartitionTable, format string, filename string, imageOptions distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
+func qemuAssembler(pt *disk.PartitionTable, format string, filename string, imageOptions distro.ImageOptions, arch distro.Arch, qcow2Compat string) *osbuild.Assembler {
 	options := pt.QEMUAssemblerOptions()
 
 	options.Format = format
 	options.Filename = filename
+	options.Qcow2Compat = qcow2Compat
 
 	if arch.Name() == "x86_64" {
 		options.Bootloader = &osbuild.QEMUBootloader{
@@ -1002,7 +1003,7 @@ func newDistro(isCentos bool) distro.Distro {
 		defaultSize:             6 * GigaByte,
 		partitionTableGenerator: defaultPartitionTable,
 		assembler: func(pt *disk.PartitionTable, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
-			return qemuAssembler(pt, "raw", "image.raw", options, arch)
+			return qemuAssembler(pt, "raw", "image.raw", options, arch, "")
 		},
 	}
 
@@ -1087,7 +1088,9 @@ func newDistro(isCentos bool) distro.Distro {
 		defaultSize:             10 * GigaByte,
 		partitionTableGenerator: defaultPartitionTable,
 		assembler: func(pt *disk.PartitionTable, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
-			return qemuAssembler(pt, "qcow2", "disk.qcow2", options, arch)
+			// guest images of RHEL 8 must be bootable with older QEMUs.
+			const qcow2Compat = "0.10"
+			return qemuAssembler(pt, "qcow2", "disk.qcow2", options, arch, qcow2Compat)
 		},
 	}
 
@@ -1115,7 +1118,7 @@ func newDistro(isCentos bool) distro.Distro {
 		defaultSize:             4 * GigaByte,
 		partitionTableGenerator: defaultPartitionTable,
 		assembler: func(pt *disk.PartitionTable, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
-			return qemuAssembler(pt, "qcow2", "disk.qcow2", options, arch)
+			return qemuAssembler(pt, "qcow2", "disk.qcow2", options, arch, "")
 		},
 	}
 
@@ -1174,7 +1177,7 @@ func newDistro(isCentos bool) distro.Distro {
 		defaultSize:             4 * GigaByte,
 		partitionTableGenerator: defaultPartitionTable,
 		assembler: func(pt *disk.PartitionTable, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
-			return qemuAssembler(pt, "vpc", "disk.vhd", options, arch)
+			return qemuAssembler(pt, "vpc", "disk.vhd", options, arch, "")
 		},
 	}
 
@@ -1203,7 +1206,7 @@ func newDistro(isCentos bool) distro.Distro {
 		defaultSize:             4 * GigaByte,
 		partitionTableGenerator: defaultPartitionTable,
 		assembler: func(pt *disk.PartitionTable, options distro.ImageOptions, arch distro.Arch) *osbuild.Assembler {
-			return qemuAssembler(pt, "vmdk", "disk.vmdk", options, arch)
+			return qemuAssembler(pt, "vmdk", "disk.vmdk", options, arch, "")
 		},
 	}
 
diff --git a/internal/osbuild1/qemu_assembler.go b/internal/osbuild1/qemu_assembler.go
index b0a200df9..4d6788212 100644
--- a/internal/osbuild1/qemu_assembler.go
+++ b/internal/osbuild1/qemu_assembler.go
@@ -7,13 +7,14 @@ package osbuild1
 // containing the indicated partitions. Finally, the image is converted into
 // the target format and stored with the given filename.
 type QEMUAssemblerOptions struct {
-	Bootloader *QEMUBootloader `json:"bootloader,omitempty"`
-	Format     string          `json:"format"`
-	Filename   string          `json:"filename"`
-	Size       uint64          `json:"size"`
-	PTUUID     string          `json:"ptuuid"`
-	PTType     string          `json:"pttype"`
-	Partitions []QEMUPartition `json:"partitions"`
+	Bootloader  *QEMUBootloader `json:"bootloader,omitempty"`
+	Format      string          `json:"format"`
+	Qcow2Compat string          `json:"qcow2_compat,omitempty"`
+	Filename    string          `json:"filename"`
+	Size        uint64          `json:"size"`
+	PTUUID      string          `json:"ptuuid"`
+	PTType      string          `json:"pttype"`
+	Partitions  []QEMUPartition `json:"partitions"`
 }
 
 type QEMUPartition struct {
diff --git a/osbuild-composer.spec b/osbuild-composer.spec
index 93794bbee..57e5a93f2 100644
--- a/osbuild-composer.spec
+++ b/osbuild-composer.spec
@@ -273,8 +273,8 @@ 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 >= 26
-Requires:   osbuild-ostree >= 26
+Requires:   osbuild >= 28
+Requires:   osbuild-ostree >= 28
 
 # remove in F34
 Obsoletes: golang-github-osbuild-composer-worker < %{version}-%{release}


Test patch:
diff --git a/test/data/manifests/centos_8-x86_64-qcow2-boot.json b/test/data/manifests/centos_8-x86_64-qcow2-boot.json
index ca1cb87f2..ca96cd8f5 100644
--- a/test/data/manifests/centos_8-x86_64-qcow2-boot.json
+++ b/test/data/manifests/centos_8-x86_64-qcow2-boot.json
@@ -4208,6 +4208,7 @@
             "type": "grub2"
           },
           "format": "qcow2",
+          "qcow2_compat": "0.10",
           "filename": "disk.qcow2",
           "size": 10737418240,
           "ptuuid": "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
@@ -11031,8 +11032,8 @@
       "wheel:x:10:"
     ],
     "image-format": {
-      "type": "qcow2",
-      "compat": "1.1"
+      "compat": "0.10",
+      "type": "qcow2"
     },
     "os-release": {
       "ANSI_COLOR": "0;31",
diff --git a/test/data/manifests/centos_8-x86_64-qcow2-customize.json b/test/data/manifests/centos_8-x86_64-qcow2-customize.json
index c2e690374..0578db7ba 100644
--- a/test/data/manifests/centos_8-x86_64-qcow2-customize.json
+++ b/test/data/manifests/centos_8-x86_64-qcow2-customize.json
@@ -4309,6 +4309,7 @@
             "type": "grub2"
           },
           "format": "qcow2",
+          "qcow2_compat": "0.10",
           "filename": "disk.qcow2",
           "size": 10737418240,
           "ptuuid": "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
@@ -11125,8 +11126,8 @@
     ],
     "hostname": "my-host",
     "image-format": {
-      "type": "qcow2",
-      "compat": "1.1"
+      "compat": "0.10",
+      "type": "qcow2"
     },
     "os-release": {
       "ANSI_COLOR": "0;31",
diff --git a/test/data/manifests/rhel_84-aarch64-qcow2-boot.json b/test/data/manifests/rhel_84-aarch64-qcow2-boot.json
index 3097db387..d30a6c605 100644
--- a/test/data/manifests/rhel_84-aarch64-qcow2-boot.json
+++ b/test/data/manifests/rhel_84-aarch64-qcow2-boot.json
@@ -3470,6 +3470,7 @@
         "name": "org.osbuild.qemu",
         "options": {
           "format": "qcow2",
+          "qcow2_compat": "0.10",
           "filename": "disk.qcow2",
           "size": 10737418240,
           "ptuuid": "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
@@ -9473,8 +9474,8 @@
       "wheel:x:10:"
     ],
     "image-format": {
-      "type": "qcow2",
-      "compat": "1.1"
+      "compat": "0.10",
+      "type": "qcow2"
     },
     "os-release": {
       "ANSI_COLOR": "0;31",
diff --git a/test/data/manifests/rhel_84-ppc64le-qcow2-boot.json b/test/data/manifests/rhel_84-ppc64le-qcow2-boot.json
index f346cad43..238fc9734 100644
--- a/test/data/manifests/rhel_84-ppc64le-qcow2-boot.json
+++ b/test/data/manifests/rhel_84-ppc64le-qcow2-boot.json
@@ -3753,6 +3753,7 @@
             "platform": "powerpc-ieee1275"
           },
           "format": "qcow2",
+          "qcow2_compat": "0.10",
           "filename": "disk.qcow2",
           "size": 10737418240,
           "ptuuid": "0x14fc63d2",
@@ -10200,8 +10201,8 @@
       "wheel:x:10:"
     ],
     "image-format": {
-      "type": "qcow2",
-      "compat": "1.1"
+      "compat": "0.10",
+      "type": "qcow2"
     },
     "os-release": {
       "ANSI_COLOR": "0;31",
diff --git a/test/data/manifests/rhel_84-s390x-qcow2-boot.json b/test/data/manifests/rhel_84-s390x-qcow2-boot.json
index fa1ac5f88..0644c353f 100644
--- a/test/data/manifests/rhel_84-s390x-qcow2-boot.json
+++ b/test/data/manifests/rhel_84-s390x-qcow2-boot.json
@@ -3694,6 +3694,7 @@
             "type": "zipl"
           },
           "format": "qcow2",
+          "qcow2_compat": "0.10",
           "filename": "disk.qcow2",
           "size": 10737418240,
           "ptuuid": "0x14fc63d2",
@@ -10132,8 +10133,8 @@
       "zkeyadm:x:996:"
     ],
     "image-format": {
-      "type": "qcow2",
-      "compat": "1.1"
+      "compat": "0.10",
+      "type": "qcow2"
     },
     "os-release": {
       "ANSI_COLOR": "0;31",
diff --git a/test/data/manifests/rhel_84-x86_64-qcow2-boot.json b/test/data/manifests/rhel_84-x86_64-qcow2-boot.json
index cd014c03e..df31342df 100644
--- a/test/data/manifests/rhel_84-x86_64-qcow2-boot.json
+++ b/test/data/manifests/rhel_84-x86_64-qcow2-boot.json
@@ -3520,6 +3520,7 @@
             "type": "grub2"
           },
           "format": "qcow2",
+          "qcow2_compat": "0.10",
           "filename": "disk.qcow2",
           "size": 10737418240,
           "ptuuid": "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
@@ -9611,8 +9612,8 @@
       "wheel:x:10:"
     ],
     "image-format": {
-      "type": "qcow2",
-      "compat": "1.1"
+      "compat": "0.10",
+      "type": "qcow2"
     },
     "os-release": {
       "ANSI_COLOR": "0;31",
diff --git a/test/data/manifests/rhel_84-x86_64-qcow2-customize.json b/test/data/manifests/rhel_84-x86_64-qcow2-customize.json
index ce1be9436..ec67d6b68 100644
--- a/test/data/manifests/rhel_84-x86_64-qcow2-customize.json
+++ b/test/data/manifests/rhel_84-x86_64-qcow2-customize.json
@@ -3622,6 +3622,7 @@
             "type": "grub2"
           },
           "format": "qcow2",
+          "qcow2_compat": "0.10",
           "filename": "disk.qcow2",
           "size": 10737418240,
           "ptuuid": "D209C89E-EA5E-4FBD-B161-B461CCE297E0",
@@ -9707,8 +9708,8 @@
     ],
     "hostname": "my-host",
     "image-format": {
-      "type": "qcow2",
-      "compat": "1.1"
+      "compat": "0.10",
+      "type": "qcow2"
     },
     "os-release": {
       "ANSI_COLOR": "0;31",