diff --git a/README.md b/README.md index b56ebab..5c95d87 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ Read more about how [custom images](https://maas.io/docs/how-to-customise-images | RHEL 7 | EOL | >= 2.3 | | RHEL 8 | Stable | >= 2.7 | | RHEL 9 | Beta | >= 3.3 | +| RHEL 10 | Beta | >= 3.3 | | Rocky 8 | Beta | >= 3.3 | | Rocky 9 | Beta | >= 3.3 | | SLES 12 | Beta | >= 3.4 | diff --git a/rhel10/Makefile b/rhel10/Makefile new file mode 100644 index 0000000..840c548 --- /dev/null +++ b/rhel10/Makefile @@ -0,0 +1,56 @@ +#!/usr/bin/make -f + +include ../scripts/check.mk + +PACKER ?= packer +PACKER_LOG ?= 0 +ISO ?= rhel-baseos-10.0-x86_64-dvd.iso +TIMEOUT ?= 1h +ARCH ?= x86_64 + +ifeq ($(wildcard /usr/share/OVMF/OVMF_CODE.fd),) + OVMF_SFX ?= _4M +else + OVMF_SFX ?= +endif + +export PACKER_LOG + +# Fallback +ifeq ($(strip $(ARCH)),amd64) + ARCH = x86_64 +endif + +.PHONY: all clean + +all: rhel10.tar.gz + +$(eval $(call check_packages_deps)) + +lint: + packer validate . + packer fmt -check -diff . + +format: + packer fmt . + +OVMF_VARS.fd: /usr/share/OVMF/OVMF_VARS${OVMF_SFX}.fd + cp -v $< ${ARCH}_VARS.fd + +SIZE_VARS.fd: +ifeq ($(strip $(ARCH)),aarch64) + truncate -s 64m ${ARCH}_VARS.fd +else + truncate -s 2m ${ARCH}_VARS.fd +endif + +rhel10.tar.gz: check-deps clean OVMF_VARS.fd SIZE_VARS.fd + ${PACKER} init rhel10.pkr.hcl && ${PACKER} build \ + -var architecture=${ARCH} \ + -var ovmf_suffix=${OVMF_SFX} \ + -var "rhel10_iso_path=${ISO}" \ + -var timeout=${TIMEOUT} \ + rhel10.pkr.hcl + +clean: + ${RM} -rf *.fd output-rhel10 rhel10.tar.gz diff --git a/rhel10/README.md b/rhel10/README.md new file mode 100644 index 0000000..a6bde7e --- /dev/null +++ b/rhel10/README.md @@ -0,0 +1,110 @@ +# RHEL 10 Packer Template for MAAS + +## Introduction + +The Packer template in this directory creates a RHEL 10 AMD64/ARM64 image for use with MAAS. + +## Prerequisites (to create the image) + +* A machine running Ubuntu 22.04+ with the ability to run KVM virtual machines. +* qemu-utils, libnbd-bin, nbdkit and fuse2fs +* [Packer](https://www.packer.io/intro/getting-started/install.html), v1.8.0 or newer +* The [RHEL 10 DVD ISO](https://developers.redhat.com/products/rhel/download) + +## Requirements (to deploy the image) + +* [MAAS](https://maas.io) 3.3+ +* [Curtin](https://launchpad.net/curtin) 22.1+ + +## Customizing the Image + +The deployment image may be customized by modifying http/rhel10.ks. See the [CentOS kickstart documentation](https://docs.centos.org/en-US/centos/install-guide/Kickstart2/) for more information. + +## Building the image using a proxy + +The Packer template pulls all packages from the DVD except for Canonical's +cloud-init repository. To use a proxy during the installation define the +`KS_PROXY` variable in the environment, as bellow: + +```shell +export KS_PROXY=$HTTP_PROXY +``` + +## Building an image + +You can easily build the image using the Makefile: + +```shell +make ISO=/PATH/TO/rhel-baseos-10.0-x86_64-dvd.iso +``` + +Alternatively you can manually run packer. Your current working directory must +be in packer-maas/rhel10, where this file is located. Once in packer-maas/rhel10 +you can generate an image with: + +```shell +packer init +PACKER_LOG=1 packer build -var 'rhel10_iso_path=/PATH/TO/rhel-baseos-10.0-x86_64-dvd.iso' . +``` + +Note: rhel10.pkr.hcl is configured to run Packer in headless mode. Only Packer +output will be seen. If you wish to see the installation output connect to the +VNC port given in the Packer output or change the value of headless to false in +rhel10.pkr.hcl. + +Installation is non-interactive. + +### Makefile Parameters + +#### ARCH + +Defaults to x86_64 to build AMD64 compatible images. In order to build ARM64 images, use ARCH=aarch64 + +### ISO + +The path to the installation ISO image for RHEL. + +#### TIMEOUT + +The timeout to apply when building the image. The default value is set to 1h. + +## Uploading an image to MAAS + +```shell +maas $PROFILE boot-resources create \ + name='rhel/rhel10' title='RHEL 10 Custom' \ + architecture='amd64/generic' filetype='tgz' \ + content@=rhel10.tar.gz +``` + +For ARM64, use: + +```shell +maas $PROFILE boot-resources create \ + name='rhel/rhel' title='RHEL 10 Custom' \ + architecture='arm64/generic' filetype='tgz' \ + content@=rhel10.tar.gz +``` + +Please note that, currently due to lack of support in curtin, deploying ARM64 images needs a preseed file. This is due to [LP# 2090874](https://bugs.launchpad.net/curtin/+bug/2090874) and currently is in the process of getting fixed. + +``` +#cloud-config +debconf_selections: + maas: | + {{for line in str(curtin_preseed).splitlines()}} + {{line}} + {{endfor}} + +extract_commands: + grub_install: curtin in-target -- cp -v /boot/efi/EFI/redhat/shimaa64.efi /boot/efi/EFI/redhat/shimx64.efi + +late_commands: + maas: [wget, '--no-proxy', '{{node_disable_pxe_url}}', '--post-data', '{{node_disable_pxe_data}}', '-O', '/dev/null'] +``` + +This file needs to be saved on Region Controllers under /var/snap/maas/current/preseeds/curtin_userdata_rhel_arm64_generic_rhel10 or /etc/maas/preseeds/curtin_userdata_rhel_arm64_generic_rhel10. The last portion of this file must match the image name uploaded in MAAS. + +## Default Username + +The default username is ```cloud-user``` diff --git a/rhel10/http/rhel10.ks.pkrtpl.hcl b/rhel10/http/rhel10.ks.pkrtpl.hcl new file mode 100644 index 0000000..be6c3f0 --- /dev/null +++ b/rhel10/http/rhel10.ks.pkrtpl.hcl @@ -0,0 +1,74 @@ +#cdrom +harddrive --partition=vdb --dir=/ +poweroff +eula --agreed +firewall --enabled --service=ssh +firstboot --disable +lang en_US.UTF-8 +keyboard us +network --device eth0 --bootproto=dhcp +firewall --enabled --service=ssh +selinux --enforcing +timezone UTC --utc +rootpw --plaintext password + +repo --name="AppStream" ${KS_APPSTREAM_REPOS} ${KS_PROXY} + +ignoredisk --only-use=vda +bootloader --disabled +zerombr +clearpart --all --initlabel +part / --size=1 --grow --asprimary --fstype=ext4 + +%post --erroronfail +# workaround anaconda requirements and clear root password +passwd -d root +passwd -l root + +# Clean up install config not applicable to deployed environments. +for f in resolv.conf fstab; do + rm -f /etc/$f + touch /etc/$f + chown root:root /etc/$f + chmod 644 /etc/$f +done + +rm -f /etc/sysconfig/network-scripts/ifcfg-[^lo]* + +# Kickstart copies install boot options. Serial is turned on for logging with +# Packer which disables console output. Disable it so console output is shown +# during deployments +sed -i 's/^GRUB_TERMINAL=.*/GRUB_TERMINAL_OUTPUT="console"/g' /etc/default/grub +sed -i '/GRUB_SERIAL_COMMAND="serial"/d' /etc/default/grub +sed -ri 's/(GRUB_CMDLINE_LINUX=".*)\s+console=ttyS0(.*")/\1\2/' /etc/default/grub +sed -i 's/GRUB_ENABLE_BLSCFG=.*/GRUB_ENABLE_BLSCFG=false/g' /etc/default/grub + +dnf clean all +%end + +%packages --ignoremissing +@core +bash-completion +cloud-init +# cloud-init only requires python3-oauthlib with MAAS. As such upstream +# removed this dependency. +python3-oauthlib +rsync +tar +# grub2-efi-x64 ships grub signed for UEFI secure boot. If grub2-efi-x64-modules +# is installed grub will be generated on deployment and unsigned which breaks +# UEFI secure boot. +grub2-pc +grub2-efi-* +shim-* +grub2-efi-*-modules +efibootmgr +dosfstools +lvm2 +mdadm +device-mapper-multipath +iscsi-initiator-utils +-plymouth +# Remove Intel wireless firmware +-i*-firmware +%end diff --git a/rhel10/rhel10.pkr.hcl b/rhel10/rhel10.pkr.hcl new file mode 100644 index 0000000..2f68961 --- /dev/null +++ b/rhel10/rhel10.pkr.hcl @@ -0,0 +1,129 @@ +packer { + required_version = ">= 1.7.0" + required_plugins { + qemu = { + version = "~> 1.0" + source = "github.com/hashicorp/qemu" + } + } +} + +variable "filename" { + type = string + default = "rhel10.tar.gz" + description = "The filename of the tarball to produce" +} + +variable "rhel10_iso_path" { + type = string + default = "${env("RHEL10_ISO_PATH")}" +} + +# Use --baseurl to specify the exact url for AppStream repo +variable "ks_appstream_repos" { + type = string + default = "--baseurl='file:///run/install/repo/AppStream'" +} + +variable ks_proxy { + type = string + default = "${env("KS_PROXY")}" +} + +variable "timeout" { + type = string + default = "1h" + description = "Timeout for building the image" +} + +variable "architecture" { + type = string + default = "amd64" + description = "The architecture to build the image for (amd64 or arm64)" +} + +variable "ovmf_suffix" { + type = string + default = "" + description = "Suffix for OVMF CODE and VARS files. Newer systems such as Noble use _4M." +} + +locals { + qemu_arch = { + "x86_64" = "x86_64" + "aarch64" = "aarch64" + } + uefi_imp = { + "x86_64" = "OVMF" + "aarch64" = "AAVMF" + } + uefi_sfx = { + "x86_64" = "${var.ovmf_suffix}" + "aarch64" = "" + } + qemu_machine = { + "x86_64" = "accel=kvm" + "aarch64" = "virt" + } + qemu_cpu = { + "x86_64" = "host" + "aarch64" = "max" + } + ks_proxy = var.ks_proxy != "" ? "--proxy=${var.ks_proxy}" : "" +} + + +source "qemu" "rhel10" { + boot_command = ["", "e", "", " console=ttyS0 inst.cmdline inst.text inst.ks=http://{{.HTTPIP}}:{{.HTTPPort}}/rhel10.ks "] + boot_wait = "5s" + communicator = "none" + disk_size = "4G" + headless = true + iso_checksum = "none" + iso_url = var.rhel10_iso_path + memory = 2048 + cores = 4 + qemu_binary = "qemu-system-${lookup(local.qemu_arch, var.architecture, "")}" + qemuargs = [ + ["-serial", "stdio"], + ["-boot", "strict=off"], + ["-device", "qemu-xhci"], + ["-device", "usb-kbd"], + ["-device", "virtio-net-pci,netdev=net0"], + ["-netdev", "user,id=net0"], + ["-device", "virtio-blk-pci,drive=drive0,bootindex=0"], + ["-device", "virtio-blk-pci,drive=cdrom0,bootindex=1"], + ["-machine", "${lookup(local.qemu_machine, var.architecture, "")}"], + ["-cpu", "${lookup(local.qemu_cpu, var.architecture, "")}"], + ["-device", "virtio-gpu-pci"], + ["-global", "driver=cfi.pflash01,property=secure,value=off"], + ["-drive", "if=pflash,format=raw,unit=0,id=ovmf_code,readonly=on,file=/usr/share/${lookup(local.uefi_imp, var.architecture, "")}/${lookup(local.uefi_imp, var.architecture, "")}_CODE${lookup(local.uefi_sfx, var.architecture, "")}.fd"], + ["-drive", "if=pflash,format=raw,unit=1,id=ovmf_vars,file=${var.architecture}_VARS.fd"], + ["-drive", "file=output-rhel10/packer-rhel10,if=none,id=drive0,cache=writeback,discard=ignore,format=qcow2"], + ["-drive", "file=${var.rhel10_iso_path},if=none,id=cdrom0,media=cdrom"] + ] + shutdown_timeout = var.timeout + http_content = { + "/rhel10.ks" = templatefile("${path.root}/http/rhel10.ks.pkrtpl.hcl", + { + KS_PROXY = local.ks_proxy, + KS_APPSTREAM_REPOS = var.ks_appstream_repos, + } + ) + } +} + +build { + sources = ["source.qemu.rhel10"] + + post-processor "shell-local" { + inline = [ + "SOURCE=${source.name}", + "OUTPUT=${var.filename}", + "source ../scripts/fuse-nbd", + "source ../scripts/fuse-tar-root", + "rm -rf output-${source.name}", + ] + inline_shebang = "/bin/bash -e" + } +}