diff --git a/Dockerfile b/Dockerfile index a1ac8eb7..b30b280e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,7 +22,7 @@ FROM opensuse/leap:15.5 # Dependency uses by line # 1. ISO image building -# 2. RAW image modification on x86_64 +# 2. RAW image modification on x86_64 and aarch64 # 3. Podman EIB library # 4. RPM resolution logic # 5. Embedded artefact registry @@ -31,13 +31,21 @@ RUN zypper addrepo https://download.opensuse.org/repositories/isv:SUSE:Edge:Edge zypper --gpg-auto-import-keys refresh && \ zypper install -y \ xorriso squashfs \ - libguestfs kernel-default e2fsprogs parted gptfdisk btrfsprogs guestfs-tools lvm2 \ + libguestfs kernel-default e2fsprogs parted gptfdisk btrfsprogs guestfs-tools lvm2 qemu-uefi-aarch64 \ podman \ createrepo_c \ helm hauler \ nm-configurator && \ zypper clean -a +# Make adjustments for running guestfish and image modifications on aarch64 +# guestfish looks for very specific locations on the filesystem for UEFI firmware +# and also expects the boot kernel to be a portable executable (PE), not ELF. +RUN mkdir -p /usr/share/edk2/aarch64 && \ + cp /usr/share/qemu/aavmf-aarch64-code.bin /usr/share/edk2/aarch64/QEMU_EFI-pflash.raw && \ + cp /usr/share/qemu/aavmf-aarch64-vars.bin /usr/share/edk2/aarch64/vars-template-pflash.raw && \ + mv /boot/vmlinux* /boot/backup-vmlinux + COPY --from=0 /src/eib /bin/eib COPY config/artifacts.yaml artifacts.yaml diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index bdc3ecda..dcb80c9a 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -8,6 +8,7 @@ * Kubernetes manifests are now applied in a systemd service * Artifact sources origin and metadata are now extracted from a configuration file (`config/artifacts.yaml`) * Dropped `-chart` suffix from installed Helm chart names +* Added ability to build aarch64 images on an aarch64 host machine ## API diff --git a/pkg/build/raw.go b/pkg/build/raw.go index 7fc48320..dbdd925b 100644 --- a/pkg/build/raw.go +++ b/pkg/build/raw.go @@ -106,6 +106,7 @@ func (b *Builder) writeModifyScript(imageFilename string, includeCombustion, ren ConfigureCombustion bool RenameFilesystem bool DiskSize string + Arch string }{ ImagePath: imageFilename, CombustionDir: b.context.CombustionDir, @@ -114,6 +115,7 @@ func (b *Builder) writeModifyScript(imageFilename string, includeCombustion, ren ConfigureCombustion: includeCombustion, RenameFilesystem: renameFilesystem, DiskSize: string(b.context.ImageDefinition.OperatingSystem.RawConfiguration.DiskSize), + Arch: string(b.context.ImageDefinition.Image.Arch), } data, err := template.Parse(modifyScriptName, modifyRawImageTemplate, &values) diff --git a/pkg/build/raw_test.go b/pkg/build/raw_test.go index a40648be..e54b29e6 100644 --- a/pkg/build/raw_test.go +++ b/pkg/build/raw_test.go @@ -78,7 +78,7 @@ func TestWriteModifyScript(t *testing.T) { "btrfs filesystem label / INSTALL", "sed -i '/ignition.platform/ s/$/ alpha beta /' /tmp/grub.cfg", "truncate -s 64G", - "virt-resize --expand /dev/sda3", + "virt-resize --expand $ROOT_PART", }, expectedMissing: []string{}, }, diff --git a/pkg/build/templates/modify-raw-image.sh.tpl b/pkg/build/templates/modify-raw-image.sh.tpl index a5fb7c1a..29cf4289 100644 --- a/pkg/build/templates/modify-raw-image.sh.tpl +++ b/pkg/build/templates/modify-raw-image.sh.tpl @@ -13,6 +13,17 @@ set -euo pipefail # # Guestfish Command Documentation: https://libguestfs.org/guestfish.1.html +# In x86_64, the default root partition is the third partition +ROOT_PART=/dev/sda3 + +# Make the necessary adaptations for aarch64 +if [[ {{ .Arch }} == "aarch64" ]]; then + if ! test -f /dev/kvm; then + export LIBGUESTFS_BACKEND_SETTINGS=force_tcg + fi + ROOT_PART=/dev/sda2 +fi + # Test the block size of the base image and adapt to suit either 512/4096 byte images BLOCKSIZE=512 if ! guestfish -i --blocksize=$BLOCKSIZE -a {{.ImagePath}} echo "[INFO] 512 byte sector check successful."; then @@ -26,7 +37,7 @@ fi {{ if ne .DiskSize "" -}} truncate -r {{.ImagePath}} {{.ImagePath}}.expanded truncate -s {{.DiskSize}} {{.ImagePath}}.expanded -virt-resize --expand /dev/sda3 {{.ImagePath}} {{.ImagePath}}.expanded +virt-resize --expand $ROOT_PART {{.ImagePath}} {{.ImagePath}}.expanded cp {{.ImagePath}}.expanded {{.ImagePath}} rm -f {{.ImagePath}}.expanded {{ end }} diff --git a/pkg/eib/eib.go b/pkg/eib/eib.go index 71d4e69b..a1092936 100644 --- a/pkg/eib/eib.go +++ b/pkg/eib/eib.go @@ -139,9 +139,9 @@ func buildCombustion(ctx *image.Context, rootDir string) (*combustion.Combustion imgPath := filepath.Join(ctx.ImageConfigDir, "base-images", ctx.ImageDefinition.Image.BaseImage) imgType := ctx.ImageDefinition.Image.ImageType - baseBuilder := resolver.NewTarballBuilder(ctx.BuildDir, imgPath, imgType, p) + baseBuilder := resolver.NewTarballBuilder(ctx.BuildDir, imgPath, imgType, string(ctx.ImageDefinition.Image.Arch), p) - combustionHandler.RPMResolver = resolver.New(ctx.BuildDir, p, baseBuilder, "") + combustionHandler.RPMResolver = resolver.New(ctx.BuildDir, p, baseBuilder, "", string(ctx.ImageDefinition.Image.Arch)) combustionHandler.RPMRepoCreator = rpm.NewRepoCreator(ctx.BuildDir) } diff --git a/pkg/rpm/resolver/base.go b/pkg/rpm/resolver/base.go index 5145aa08..11d8e954 100644 --- a/pkg/rpm/resolver/base.go +++ b/pkg/rpm/resolver/base.go @@ -34,15 +34,18 @@ type TarballImageBuilder struct { imgPath string // type of the image that will be used as base (either ISO or RAW) imgType string + // architecture of the image that will be built + arch string // imgImporter used to import the tarball archive as a container image imgImporter ImageImporter } -func NewTarballBuilder(workDir, imgPath, imgType string, importer ImageImporter) *TarballImageBuilder { +func NewTarballBuilder(workDir, imgPath, imgType, arch string, importer ImageImporter) *TarballImageBuilder { return &TarballImageBuilder{ dir: workDir, imgPath: imgPath, imgType: imgType, + arch: arch, imgImporter: importer, } } @@ -94,11 +97,13 @@ func (t *TarballImageBuilder) writeTarballImageScript() error { ImgPath string ArchiveName string ImgType string + Arch string }{ WorkDir: t.getTarballImgDir(), ImgPath: t.getBaseISOCopyPath(), ArchiveName: tarballName, ImgType: t.imgType, + Arch: t.arch, } data, err := template.Parse(prepareTarballScriptName, prepareTraballTemplate, &values) diff --git a/pkg/rpm/resolver/resolver.go b/pkg/rpm/resolver/resolver.go index d1b6c405..2aa68004 100644 --- a/pkg/rpm/resolver/resolver.go +++ b/pkg/rpm/resolver/resolver.go @@ -56,14 +56,17 @@ type Resolver struct { // path to the mounts.conf filepath that overrides the default mounts.conf configuration; // if left empty the default override path will be used. For more info - https://github.com/containers/common/blob/v0.57/docs/containers-mounts.conf.5.md overrideMountsPath string + // architecture of the packages the resolver should pull + arch string } -func New(workDir string, podman Podman, baseImageBuilder BaseResolverImageBuilder, overrideMountsPath string) *Resolver { +func New(workDir string, podman Podman, baseImageBuilder BaseResolverImageBuilder, overrideMountsPath, arch string) *Resolver { return &Resolver{ dir: workDir, podman: podman, baseResolverImageBuilder: baseImageBuilder, overrideMountsPath: overrideMountsPath, + arch: arch, } } @@ -185,11 +188,13 @@ func (r *Resolver) writeRPMResolutionScript(localRPMConfig *image.LocalRPMConfig LocalRPMList string LocalGPGList string NoGPGCheck bool + Arch string }{ RegCode: packages.RegCode, AddRepo: packages.AdditionalRepos, CacheDir: r.generateResolverImgRPMRepoPath(), NoGPGCheck: packages.NoGPGCheck, + Arch: r.arch, } if len(packages.PKGList) > 0 { diff --git a/pkg/rpm/resolver/templates/prepare-tarball.sh.tpl b/pkg/rpm/resolver/templates/prepare-tarball.sh.tpl index acf97d5c..67344a87 100644 --- a/pkg/rpm/resolver/templates/prepare-tarball.sh.tpl +++ b/pkg/rpm/resolver/templates/prepare-tarball.sh.tpl @@ -10,6 +10,11 @@ set -euo pipefail WORK_DIR={{.WorkDir}} IMG_PATH={{.ImgPath}} +# Make the necessarry adaptations for aarch64 +if [[ {{ .Arch }} == "aarch64" ]]; then + export LIBGUESTFS_BACKEND_SETTINGS=force_tcg +fi + {{ if eq .ImgType "iso" -}} xorriso -osirrox on -indev $IMG_PATH extract / $WORK_DIR/iso-root/ diff --git a/pkg/rpm/resolver/templates/rpm-resolution.sh.tpl b/pkg/rpm/resolver/templates/rpm-resolution.sh.tpl index 99bcb210..125e9b08 100644 --- a/pkg/rpm/resolver/templates/rpm-resolution.sh.tpl +++ b/pkg/rpm/resolver/templates/rpm-resolution.sh.tpl @@ -9,10 +9,11 @@ set -euo pipefail # LocalRPMList - list of local RPMs for which dependency resolution has to be done # LocalGPGList - list of local GPG keys that will be imported in the resolver image # NoGPGCheck - when set to true skips the GPG validation for all third-party repositories and local RPMs +# Arch - sets the architecture of the rpm packages to pull {{ if ne .RegCode "" }} suseconnect -r {{ .RegCode }} -SLE_SP=$(cat /etc/rpm/macros.sle | awk '/sle/ {print $2};' | cut -c4) && suseconnect -p PackageHub/15.$SLE_SP/x86_64 +SLE_SP=$(cat /etc/rpm/macros.sle | awk '/sle/ {print $2};' | cut -c4) && suseconnect -p PackageHub/15.$SLE_SP/{{ .Arch }} zypper ref trap "suseconnect -d" EXIT {{ end -}} @@ -51,4 +52,4 @@ zypper \ --allow-vendor-change \ -n {{.PKGList}} {{.LocalRPMList}} -touch {{.CacheDir}}/zypper-success \ No newline at end of file +touch {{.CacheDir}}/zypper-success