Red Hat Enterprise Linux-9-Customizing Anaconda-En-Us
Red Hat Enterprise Linux-9-Customizing Anaconda-En-Us
Customizing Anaconda
Changing the installer appearance and creating custom add-ons on Red Hat
Enterprise Linux
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons
Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is
available at
http://creativecommons.org/licenses/by-sa/3.0/
. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must
provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert,
Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, the Red Hat logo, JBoss, OpenShift,
Fedora, the Infinity logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States
and other countries.
Linux ® is the registered trademark of Linus Torvalds in the United States and other countries.
XFS ® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States
and/or other countries.
MySQL ® is a registered trademark of MySQL AB in the United States, the European Union and
other countries.
Node.js ® is an official trademark of Joyent. Red Hat is not formally related to or endorsed by the
official Joyent Node.js open source or commercial project.
The OpenStack ® Word Mark and OpenStack logo are either registered trademarks/service marks
or trademarks/service marks of the OpenStack Foundation, in the United States and other
countries and are used with the OpenStack Foundation's permission. We are not affiliated with,
endorsed or sponsored by the OpenStack Foundation, or the OpenStack community.
Abstract
Anaconda is the installer used by Red Hat Enterprise Linux. You can customize Anaconda for
extending capabilities when you install RHEL in your environment.
Table of Contents
Table of Contents
. . . . . . . . . .OPEN
MAKING . . . . . . SOURCE
. . . . . . . . . .MORE
. . . . . . .INCLUSIVE
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3. . . . . . . . . . . . .
. . . . . . . . . . . . . FEEDBACK
PROVIDING . . . . . . . . . . . . ON
. . . .RED
. . . . .HAT
. . . . .DOCUMENTATION
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .4. . . . . . . . . . . . .
.CHAPTER
. . . . . . . . . . 1.. .INTRODUCTION
. . . . . . . . . . . . . . . . . TO
. . . .ANACONDA
. . . . . . . . . . . . .CUSTOMIZATION
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5. . . . . . . . . . . . .
1.1. INTRODUCTION TO ANACONDA CUSTOMIZATION 5
.CHAPTER
. . . . . . . . . . 2.
. . PERFORMING
. . . . . . . . . . . . . . . THE
. . . . . PRE-CUSTOMIZATION
. . . . . . . . . . . . . . . . . . . . . . . . TASKS
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6. . . . . . . . . . . . .
2.1. WORKING WITH ISO IMAGES 6
2.2. DOWNLOADING RH BOOT IMAGES 6
2.3. EXTRACTING RED HAT ENTERPRISE LINUX BOOT IMAGES 6
.CHAPTER
. . . . . . . . . . 3.
. . CUSTOMIZING
. . . . . . . . . . . . . . . . THE
. . . . .BOOT
. . . . . . .MENU
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8. . . . . . . . . . . . .
3.1. CUSTOMIZING THE BOOT MENU 8
3.2. SYSTEMS WITH BIOS FIRMWARE 8
3.3. SYSTEMS WITH UEFI FIRMWARE 11
.CHAPTER
. . . . . . . . . . 4.
. . .BRANDING
. . . . . . . . . . . .AND
. . . . .CHROMING
. . . . . . . . . . . . THE
. . . . . GRAPHICAL
. . . . . . . . . . . . . USER
. . . . . . INTERFACE
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
..............
4.1. CUSTOMIZING GRAPHICAL ELEMENTS 14
4.2. CUSTOMIZING THE PRODUCT NAME 15
4.3. CUSTOMIZING THE DEFAULT CONFIGURATION 16
4.3.1. Configuring the default configuration files 16
4.3.2. Configuring the product configuration files 21
4.3.3. Configuring the custom configuration files 23
.CHAPTER
. . . . . . . . . . 5.
. . DEVELOPING
. . . . . . . . . . . . . . . INSTALLER
. . . . . . . . . . . . .ADD-ONS
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .24
..............
5.1. INTRODUCTION TO ANACONDA AND ADD-ONS 24
5.2. ANACONDA ARCHITECTURE 24
5.3. ANACONDA USER INTERFACE 26
5.4. COMMUNICATION ACROSS ANACONDA THREADS 27
5.5. ANACONDA MODULES AND D-BUS LIBRARY 27
5.6. THE HELLO WORLD ADDON EXAMPLE 28
5.7. ANACONDA ADD-ON STRUCTURE 28
5.8. ANACONDA SERVICES AND CONFIGURATION FILES 29
5.9. GUI ADD-ON BASIC FEATURES 30
5.10. ADDING SUPPORT FOR THE ADD-ON GRAPHICAL USER INTERFACE (GUI) 30
5.11. ADD-ON GUI ADVANCED FEATURES 36
5.12. TUI ADD-ON BASIC FEATURES 37
5.13. DEFINING A SIMPLE TUI SPOKE 38
5.14. USING NORMALTUISPOKE TO DEFINE A TEXT INTERFACE SPOKE 41
5.15. DEPLOYING AND TESTING AN ANACONDA ADD-ON 43
.CHAPTER
. . . . . . . . . . 6.
. . .COMPLETING
. . . . . . . . . . . . . . .POST
. . . . . .CUSTOMIZATION
. . . . . . . . . . . . . . . . . . .TASKS
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .45
..............
6.1. CREATING A PRODUCT.IMG FILE 45
6.2. CREATING CUSTOM BOOT IMAGES 47
1
Red Hat Enterprise Linux 9.0 Customizing Anaconda
2
MAKING OPEN SOURCE MORE INCLUSIVE
3
Red Hat Enterprise Linux 9.0 Customizing Anaconda
4. Enter your suggestion for improvement in the Description field. Include links to the relevant
parts of the documentation.
4
CHAPTER 1. INTRODUCTION TO ANACONDA CUSTOMIZATION
Installer functionality - add-ons which can enhance the installer by adding new Kickstart
commands and new screens in the graphical and textual user interfaces
Also note that this document applies only to Red Hat Enterprise Linux 8 and Fedora 17 and later.
IMPORTANT
Procedures described in this book are written for Red Hat Enterprise Linux 9 or a similar
system. On other systems, the tools and applications used (such as genisoimage for
creating custom ISO images) may be different, and procedures may need to be adjusted.
5
Red Hat Enterprise Linux 9.0 Customizing Anaconda
NOTE
You must download either the Binary DVD or Boot ISO image and can use any
of the image variants (Server or ComputeNode).
You cannot customize the installer using the other available downloads, such as
the KVM Guest Image or Supplementary DVD; other available downloads, such as
the KVM Guest Image or Supplementary DVD.
For more information about the Binary DVD and Boot ISO downloads, see Red Hat Enterprise Linux 9
Performing an advanced RHEL 9 installation.
Procedure
1. Ensure that the directory /mnt/iso exists and nothing is currently mounted there.
3. Create a working directory where you want to place the contents of the ISO image.
$ mkdir /tmp/ISO
4. Copy all contents of the mounted image to your new working directory. Make sure to use the -p
option to preserve file and directory permissions and ownership.
6
CHAPTER 2. PERFORMING THE PRE-CUSTOMIZATION TASKS
# umount /mnt/iso
Additional resources
For detailed download instructions and description of the Binary DVD and Boot ISO downloads,
see the Red Hat Enterprise Linux 9 .
7
Red Hat Enterprise Linux 9.0 Customizing Anaconda
Prerequisites:
For information about downloading and extracting Boot images, see Extracting Red Hat Enterprise
Linux boot images
An installation media consists of ISOLINUX and GRUB2 boot loaders. The ISOLINUX boot loader is
used on systems with BIOS firmware, and the GRUB2 boot loader is used on systems with UEFI
firmware. Both the boot loaders are present on all Red Hat images for AMD64 and Intel 64 systems.
Customizing the boot menu options can especially be useful with Kickstart. Kickstart files must be
provided to the installer before the installation begins. Normally, this is done by manually editing one of
the existing boot options to add the inst.ks= boot option. You can add this option to one of the pre-
configured entries, if you edit boot loader configuration files on the media.
The isolinux/isolinux.cfg configuration file on the boot media contains directives for setting the color
scheme and the menu structure (entries and submenus).
In the configuration file, the default menu entry for Red Hat Enterprise Linux, Test this media & Install
Red Hat Enterprise Linux 9, is defined in the following block:
label check
menu label Test this ^media & install Red Hat Enterprise Linux 9.
menu default
kernel vmlinuz
append initrd=initrd.img inst.stage2=hd:LABEL=RHEL-9-BaseOS-x86_64 rd.live.check
quiet
Where:
menu label - determines how the entry will be named in the menu. The ^ character determines
its keyboard shortcut (the m key).
menu default - provides a default selection, even though it is not the first option in the list.
kernel - loads the installer kernel. In most cases it should not be changed.
append - contains additional kernel options. The initrd= and inst.stage2 options are
mandatory; you can add others.
For information about the options that are applicable to Anaconda refer to Red Hat
Enterprise Linux 9 Performing a standard RHEL 9 installation Guide.
9
Red Hat Enterprise Linux 9.0 Customizing Anaconda
One of the notable options is inst.ks=, which allows you to specify a location of a Kickstart file.
You can place a Kickstart file on the boot ISO image and use the inst.ks= option to specify its
location; for example, you can place a kickstart.ks file into the image’s root directory and use
inst.ks=hd:LABEL=RHEL-9-BaseOS-x86_64:/kickstart.ks.
You can also use dracut options which are listed on the dracut.cmdline(7) man page.
IMPORTANT
When using a disk label to refer to a certain drive (as seen in the
inst.stage2=hd:LABEL=RHEL-9-BaseOS-x86_64 option above), replace all
spaces with \x20.
Other important options which are not included in the menu entry definition are:
timeout - determines the time for which the boot menu is displayed before the default menu
entry is automatically used. The default value is 600, which means the menu is displayed for 60
seconds. Setting this value to 0 disables the timeout option.
NOTE
Setting the timeout to a low value such as 1 is useful when performing a headless
installation. This helps to avoid the default timeout to finish.
menu begin and menu end - determines a start and end of a submenu block, allowing you to
add additional options such as troubleshooting and grouping them in a submenu. A simple
submenu with two options (one to continue and one to go back to the main menu) looks similar
to the following:
label rescue
menu label ^Rescue a Red Hat Enterprise Linux system
kernel vmlinuz
append initrd=initrd.img inst.stage2=hd:LABEL=RHEL-9-BaseOS-x86_64 rescue quiet
menu separator
label returntomain
menu label Return to ^main menu
menu exit
menu end
The submenu entry definitions are similar to normal menu entries, but grouped between menu
begin and menu end statements. The menu exit line in the second option exits the submenu
and returns to the main menu.
menu background - the menu background can either be a solid color (see menu color below),
or an image in a PNG, JPEG or LSS16 format. When using an image, make sure that its
dimensions correspond to the resolution set using the set resolution statement. Default
dimensions are 640x480.
menu color - determines the color of a menu element. The full format is:
10
CHAPTER 3. CUSTOMIZING THE BOOT MENU
menu help textfile - creates a menu entry which, when selected, displays a help text file.
Additional resources
For a complete list of ISOLINUX configuration file options, see the Syslinux Wiki.
The EFI/BOOT/grub.cfg configuration file on the boot media contains a list of preconfigured menu
entries and other directives which controls the appearance and the Boot menu functionality.
In the configuration file, the default menu entry for Red Hat Enterprise Linux (Test this media & install
Red Hat Enterprise Linux 9) is defined in the following block:
menuentry 'Test this media & install Red Hat Enterprise Linux 9' --class fedora --class gnu-linux -
-class gnu --class os {
linuxefi /images/pxeboot/vmlinuz inst.stage2=hd:LABEL=RHEL-9-BaseOS-x86_64 rd.live.check
quiet
initrdefi /images/pxeboot/initrd.img
}
Where:
menuentry - Defines the title of the entry. It is specified in single or double quotes ( ' or "). You
can use the --class option to group menu entries into different classes, which can then be styled
differently using GRUB2 themes.
NOTE
As shown in the above example, you must enclose each menu entry definition in
curly braces ({}).
linuxefi - Defines the kernel that boots ( /images/pxeboot/vmlinuz in the above example) and
the other additional options, if any.
You can customize these options to change the behavior of the boot entry. For details about
the options that are applicable to Anaconda, refer to Red Hat Enterprise Linux 9 Performing an
advanced RHEL 9 installation.
One of the notable options is inst.ks=, which allows you to specify a location of a Kickstart file.
11
Red Hat Enterprise Linux 9.0 Customizing Anaconda
One of the notable options is inst.ks=, which allows you to specify a location of a Kickstart file.
You can place a Kickstart file on the boot ISO image and use the inst.ks= option to specify its
location; for example, you can place a kickstart.ks file into the image’s root directory and use
inst.ks=hd:LABEL=RHEL-9-BaseOS-x86_64:/kickstart.ks.
You can also use dracut options which are listed on the dracut.cmdline(7) man page.
IMPORTANT
When using a disk label to refer to a certain drive (as seen in the
inst.stage2=hd:LABEL=RHEL-9-BaseOS-x86_64 option above), replace all
spaces with \x20.
set timeout - determines how long is the boot menu displayed before the default menu entry is
automatically used. The default value is 60, which means the menu is displayed for 60 seconds.
Setting this value to -1 disables the timeout completely.
NOTE
submenu - A submenu block allows you to create a sub-menu and group some entries under it,
instead of displaying them in the main menu. The Troubleshooting submenu in the default
configuration contains entries for rescuing an existing system.
The title of the entry is in single or double quotes (' or ").
The submenu block contains one or more menuentry definitions as described above, and the
entire block is enclosed in curly braces ({}). For example:
set default - Determines the default entry. The entry numbers start from 0. If you want to make
the third entry the default one, use set default=2 and so on.
theme - determines the directory which contains GRUB2 theme files. You can use the themes
to customize visual aspects of the boot loader - background, fonts, and colors of specific
elements.
Additional resources
12
CHAPTER 3. CUSTOMIZING THE BOOT MENU
For additional information about customizing the boot menu, see the GNU GRUB Manual 2.00 .
For more general information about GRUB2, see the Red Hat Enterprise Linux 9 Managing,
monitoring and updating the kernel.
13
Red Hat Enterprise Linux 9.0 Customizing Anaconda
This section provides information about how to customize the graphical elements and the product name.
Prerequisites
For information about downloading and extracting boot images, see Extracting Red Hat Enterprise
Linux boot images
2. Create custom branding material (if you plan to customize the graphical elements)
NOTE
To create the custom branding material, first refer to the default graphical element files
type and dimensions. You can accordingly create the custom material. Details about
default graphical elements are available in the sample files that are provided in the
Customizing graphical elements section.
The customisable graphical elements of the installer are stored in the /usr/share/anaconda/pixmaps/
directory in the installer runtime file system. This directory contains the following customisable files:
pixmaps
├─ anaconda-password-show-off.svg
├─ anaconda-password-show-on.svg
├─ right-arrow-icon.png
├─ sidebar-bg.png
├─ sidebar-logo.png
└─ topbar-bg.png
14
CHAPTER 4. BRANDING AND CHROMING THE GRAPHICAL USER INTERFACE
/* theme colors/images */
.logo-sidebar {
background-image: url('/usr/share/anaconda/pixmaps/sidebar-bg.png');
background-color: @product_bg_color;
background-repeat: no-repeat;
}
.logo {
background-image: url('/usr/share/anaconda/pixmaps/sidebar-logo.png');
background-position: 50% 20px;
background-repeat: no-repeat;
background-color: transparent;
}
.product-logo {
background-image: none;
background-color: transparent;
}
AnacondaSpokeWindow #nav-box {
background-color: @product_bg_color;
background-image: url('/usr/share/anaconda/pixmaps/topbar-bg.png');
background-repeat: no-repeat;
color: white;
}
The most important part of the CSS file is the way in which it handles scaling based on resolution. The
PNG image backgrounds do not scale, they are always displayed in their true dimensions. Instead, the
backgrounds have a transparent background, and the stylesheet defines a matching background color
on the @define-color line. Therefore, the background images "fade" into the background color, which
means that the backgrounds work on all resolutions without a need for image scaling.
You could also change the background-repeat parameters to tile the background, or, if you are
confident that every system you will be installing on will have the same display resolution, you can use
background images which fill the entire bar.
Any of the files listed above can be customized. Once you do so, follow the instructions in Section 2.2,
“Creating a product.img File” to create your own product.img with custom graphics, and then Section
2.3, “Creating Custom Boot Images” to create a new bootable ISO image with your changes included.
15
Red Hat Enterprise Linux 9.0 Customizing Anaconda
To customize the product name, you must create a custom .buildstamp file. To do so, create a new file
.buildstamp.py with the following content:
[Main]
Product=My Distribution
Version=9
BugURL=https://bugzilla.redhat.com/
IsFinal=True
UUID=202007011344.x86_64
[Compose]
Lorax=28.14.49-1
Change My Distribution to the name which you want to display in the installer.
After you create the custom .buildstamp file, follow the steps in Creating a product.img file section to
create a new product.img file containing your customizations, and the Creating custom boot images
section to create a new bootable ISO file with your changes included.
[Anaconda]
# Run Anaconda in the debugging mode.
debug = False
16
CHAPTER 4. BRANDING AND CHROMING THE GRAPHICAL USER INTERFACE
Anaconda DBus modules that can fail to run. # The installation won't be aborted because of
them. # Supported patterns: MODULE.PREFIX., MODULE.NAME
optional_modules =
org.fedoraproject.Anaconda.Modules.Subscription
org.fedoraproject.Anaconda.Addons.*
[Installation System]
[Installation Target]
# Type of the installation target.
type = HARDWARE
[Network]
# Network device to be activated on boot if none was configured so.
# Valid values:
#
# NONE No device
# DEFAULT_ROUTE_DEVICE A default route device
# FIRST_WIRED_WITH_LINK The first wired device with link
#
default_on_boot = NONE
[Payload]
# Default package environment.
default_environment =
17
Red Hat Enterprise Linux 9.0 Customizing Anaconda
[Security]
# Enable SELinux usage in the installed system.
# Valid values:
#
# -1 The value is not set.
# 0 SELinux is disabled.
# 1 SELinux is enabled.
#
selinux = -1
[Bootloader]
# Type of the bootloader.
# Supported values:
#
# DEFAULT Choose the type by platform.
# EXTLINUX Use extlinux as the bootloader.
#
type = DEFAULT
18
CHAPTER 4. BRANDING AND CHROMING THE GRAPHICAL USER INTERFACE
[Storage]
# Enable dmraid usage during the installation.
dmraid = True
# Tell multipathd to use user friendly names when naming devices during the installation.
multipath_friendly_names = True
# Do you want to allow imperfect devices (for example, degraded mdraid array devices)?
allow_imperfect_devices = False
# Default partitioning.
# Specify a mount point and its attributes on each line.
#
# Valid attributes:
#
# size <SIZE> The size of the mount point.
# min <MIN_SIZE> The size will grow from MIN_SIZE to MAX_SIZE.
# max <MAX_SIZE> The max size is unlimited by default.
# free <SIZE> The required available space.
#
default_partitioning =
/ (min 1 GiB, max 70 GiB)
/home (min 500 MiB, free 50 GiB)
[Storage Constraints]
19
Red Hat Enterprise Linux 9.0 Customizing Anaconda
20
CHAPTER 4. BRANDING AND CHROMING THE GRAPHICAL USER INTERFACE
[User Interface]
# The path to a custom stylesheet.
custom_stylesheet =
[License]
# A path to EULA (if any)
#
# If the given distribution has an EULA & feels the need to
# tell the user about it fill in this variable by a path
# pointing to a file with the EULA on the installed system.
#
# This is currently used just to show the path to the file to
# the user at the end of the installation.
eula =
The installer loads configuration files of the base products before it loads the configuration file of the
specified product. For example, it will first load the configuration for Red Hat Enterprise Linux and then
the configuration for Red Hat Virtualization.
See an example of the product configuration file for Red Hat Enterprise Linux:
21
Red Hat Enterprise Linux 9.0 Customizing Anaconda
[Product]
product_name = Red Hat Enterprise Linux
[Installation System]
[Network]
default_on_boot = DEFAULT_ROUTE_DEVICE
[Payload]
ignored_packages =
ntfsprogs
btrfs-progs
dmraid
enable_closest_mirror = False
default_source = CDN
[Bootloader]
efi_dir = redhat
[Storage]
file_system_type = xfs
default_partitioning =
/ (min 1 GiB, max 70 GiB)
/home (min 500 MiB, free 50 GiB)
swap
[Storage Constraints]
swap_is_recommended = True
[User Interface]
help_directory = /usr/share/anaconda/help/rhel
[License]
eula = /usr/share/redhat-release/EULA
See an example of the product configuration file for Red Hat Virtualization:
[Product]
product_name = Red Hat Virtualization (RHVH)
[Base Product]
product_name = Red Hat Enterprise Linux
[Storage]
default_scheme = LVM_THINP
default_partitioning =
22
CHAPTER 4. BRANDING AND CHROMING THE GRAPHICAL USER INTERFACE
/ (min 6 GiB)
/home (size 1 GiB)
/tmp (size 1 GiB)
/var (size 15 GiB)
/var/crash (size 10 GiB)
/var/log (size 8 GiB)
/var/log/audit (size 2 GiB)
swap
[Storage Constraints]
root_device_types = LVM_THINP
must_not_be_on_root = /var
req_partition_sizes =
/var 10 GiB
/boot 1 GiB
To customize the installer configuration for your product, you must create a product configuration file.
Create a new file named my-distribution.conf, with content similar to the example above. Change
product_name in the [Product] section to the name of your product, for example My Distribution. The
product name should be the same as the name used in the .buildstamp file.
After you create the custom configuration file, follow the steps in Creating a product.img file section to
create a new product.img file containing your customizations, and the Creating custom boot images to
create a new bootable ISO file with your changes included.
After you create the custom configuration file, follow the steps in Creating a product.img file section to
create a new product.img file containing your customizations, and the Creating custom boot images to
create a new bootable ISO file with your changes included.
23
Red Hat Enterprise Linux 9.0 Customizing Anaconda
Using Anaconda enables you to install Fedora, Red Hat Enterprise Linux, and their derivatives, in the
following three ways:
This is the most common installation method. The interface allows users to install the system
interactively with little or no configuration required before starting the installation. This method covers
all common use cases, including setting up complicated partitioning layouts.
The graphical interface supports remote access over VNC, which allows you to use the GUI even on
systems with no graphics cards or attached monitor.
The TUI works similar to a monochrome line printer, which allows it to work on serial consoles that do not
support cursor movement, colors and other advanced features. The text mode is limited and allows you
to customize only the most common options, such as network settings, language options or installation
(package) source; advanced features such as manual partitioning are not available in this interface.
A Kickstart file is a plain text file with shell-like syntax that can contain data to drive the installation
process. A Kickstart file allows you to partially or completely automate the installation. A set of
commands which configures all required areas is necessary to completely automate the installation. If
one or more commands are missed, the installation requires interaction.
Apart from automation of the installer itself, Kickstart files can contain custom scripts that are run at
specific moments during the installation process.
24
CHAPTER 5. DEVELOPING INSTALLER ADD-ONS
pykickstart - parses and validates the Kickstart files. Also, provides data structure that stores
values that drive the installation.
dnf - the package manager that installs packages and resolves dependencies
pyanaconda - contains the user interface and modules for Anaconda, such as keyboard and
timezone selection, network configuration, and user creation. Also provides various utilities to
perform system-oriented functions
python-meh - contains an exception handler that gathers and stores additional system
information in case of a crash and passes this information to the libreport library, which itself is a
part of the ABRT Project
dasbus - enables communication between the D-Bus library with modules of anaconda and
with external components
python-simpleline - text UI framework library to manage user interaction in the Anaconda text
mode
gtk - the Gnome toolkit library for creating and managing GUI
Apart from the division into packages previously mentioned, Anaconda is internally divided into the user
interface and a set of modules that run as separate processes and communicate using the D-Bus library.
These modules are:
Payloads - handles data for installation in different formats, such as rpm, ostree, tar and other
installation formats. Payloads manage the sources of data for installation; sources can vary in
format such as CD-ROM, HDD, NFS, URLs, and other sources
Each module declares which parts of Kickstart it handles, and has methods to apply the configuration
from Kickstart to the installation environment and to the installed system.
The Python code portion of Anaconda (pyanaconda) starts as a “main” process that owns the user
interface. Any Kickstart data you provide are parsed using the pykickstart module and the Boss module
is started, it discovers all other modules, and starts them. Main process then sends Kickstart data to the
modules according to their declared capabilities. Modules process the data, apply the configuration to
25
Red Hat Enterprise Linux 9.0 Customizing Anaconda
the installation environment, and the UI validates if all required choices have been made. If not, you must
supply the data in an interactive installation mode. Once all required choices have been made, the
installation can start - the modules write data to the installed system.
Supports extensibility. You can add hubs without the need to reorder anything and can resolve
some complex ordering dependencies.
The following diagram shows the installer layout and the possible interactions between hubs and spokes
(screens):
In the diagram, screens 2-13 are called normal spokes, and screens 1 and 14 are standalone spokes.
Standalone spokes are the screens that can be used before or after the standalone spoke or hub. For
example, the Welcome screen at the beginning of the installation which prompts you to choose your
language for the rest of the installation.
NOTE
Each spoke has the following predefined properties that reflect the hub.
26
CHAPTER 5. DEVELOPING INSTALLER ADD-ONS
ready - states whether or not you can visit a spoke. For example, when the installer is
configuring a package source, the spoke is colored in gray, and you cannot access it until the
configuration is complete.
completed - marks whether or not the spoke is complete (all required values are set).
mandatory - determines whether you must visit the spoke before continuing the installation; for
example, you must visit the Installation Destination spoke, even if you want to use automatic
disk partitioning
status - provides a short summary of values configured within the spoke (displayed under the
spoke name in the hub)
To make the user interface clearer, spokes are grouped together into categories. For example, the
Localization category groups together spokes for keyboard layout selection, language support and
time zone settings.
Each spoke contains UI controls which display and allow you to modify values from one or more modules.
The same applies to spokes that add-ons provide.
The Gtk toolkit does not support element changes from multiple threads. The main event loop of Gtk
runs in the main thread of the Anaconda process. Therefore, all actions pertaining to the GUI must be
performed in the main thread. To do so, use GLib.idle_add, which is not always easy or desired. Several
helper functions and decorators that are defined in the pyanaconda.ui.gui.utils module may add to the
difficulty.
In a spoke and hub communication, a spoke announces when it is ready and is not blocked. The hubQ
message queue handles this function, and periodically checks the main event loop. When a spoke
becomes accessible, it sends a message to the queue announcing the change and that it should no
longer be blocked.
The same applies in a situation where a spoke needs to refresh its status or complete a flag. The
Configuration and Progress hub has a different queue called progressQ which serves as a medium to
transfer installation progress updates.
These mechanisms are also used for the text-based interface. In the text mode, there is no main loop,
but the keyboard input takes most of the time.
Calls to methods via D-Bus API are asynchronous, but with the dasbus library you can convert them to
synchronous method calls in Python. You can also write either of the following programs:
27
Red Hat Enterprise Linux 9.0 Customizing Anaconda
A program with synchronous calls that makes the caller wait until the call is complete.
For more information about threads and communication, see Communication across Anaconda threads .
Additionally, Anaconda uses Task objects running in modules. Tasks have a D-Bus API and methods that
are automatically executed in additional threads. To successfully run the tasks, use the sync_run_task
and async_run_task helper functions.
The suggested naming convention for add-ons is similar to Java packages or D-Bus service names.
To make the directory name a unique identifier for a Python package, prefix the add-on name with the
reversed domain name of your organization, using underscores (_) instead of dots. For example,
com_example_hello_world.
IMPORTANT
Make sure to create an __init__.py file in each directory. Directories missing this file are
considered as invalid Python packages.
Support for each interface (graphical interface and text interface) is available in a separate
subpackage and these subpackages are named gui for the graphical interface and tui for the
text-based interface.
The gui/ and tui/ directories contain Python modules with any name.
There is a service that performs the actual work of the addon. This service can be written in
Python or any other language.
The addon contains files that enable automatic startup of the service.
Following is a sample directory structure for an add-on which supports every interface (Kickstart, GUI
28
CHAPTER 5. DEVELOPING INSTALLER ADD-ONS
Following is a sample directory structure for an add-on which supports every interface (Kickstart, GUI
and TUI):
com_example_hello_world
├─ gui
│ ├─ init.py
│ └─ spokes
│ └─ init.py
└─ tui
├─ init.py
└─ spokes
└─ init.py
Each package must contain at least one module with an arbitrary name defining the classes that are
inherited from one or more classes defined in the API.
NOTE
For all add-ons, follow Python’s PEP 8 and PEP 257 guidelines for docstring conventions.
There is no consensus on the format of the actual content of docstrings in Anaconda; the
only requirement is that they are human-readable. If you plan to use auto-generated
documentation for your add-on, docstrings should follow the guidelines for the toolkit
you use to accomplish this.
You can include a category subpackage if an add-on needs to define a new category, but this is not
recommended.
29
Red Hat Enterprise Linux 9.0 Customizing Anaconda
[D-BUS Service]
# Start the org.fedoraproject.Anaconda.Addons.HelloWorld service.
# Runs org_fedora_hello_world/service/main.py
Name=org.fedoraproject.Anaconda.Addons.HelloWorld
Exec=/usr/libexec/anaconda/start-module org_fedora_hello_world.service
User=root
To implement a new class inherited from NormalSpoke, you must define the following class attributes
that the API requires:
builderObjects - lists all top-level objects from the spoke’s .glade file that should be exposed
to the spoke with their children objects (recursively). In case everything should be exposed to
the spoke, which is not recommended, the list should be empty.
mainWidgetName - contains the id of the main window widget (Add Link) as defined in the
.glade file.
category - contains the class of the category the spoke belongs to.
icon - contains the identifier of the icon that will be used for the spoke on the hub.
title - defines the title that will be used for the spoke on the hub.
30
CHAPTER 5. DEVELOPING INSTALLER ADD-ONS
4. Define the status and the ready, completed and mandatory Properties
Prerequisites
Your add-on includes support for Kickstart. See Anaconda add-on structure.
Install the anaconda-widgets and anaconda-widgets-devel packages, which contain Gtk widgets
specific for Anaconda, such as SpokeWindow.
Procedure
Create the following modules with all required definitions to add support for the Add-on
graphical user interface (GUI), according to the following examples.
:see: pyanaconda.ui.common.UIObject
:see: pyanaconda.ui.common.Spoke
:see: pyanaconda.ui.gui.GUIObject
:see: pyanaconda.ui.common.FirstbootSpokeMixIn
:see: pyanaconda.ui.gui.spokes.NormalSpoke
"""
# list all top-level objects from the .glade file that should be exposed
# to the spoke or leave empty to extract everything
builderObjects = ["helloWorldSpokeWindow", "buttonImage"]
31
Red Hat Enterprise Linux 9.0 Customizing Anaconda
uiFile = "hello_world.glade"
The __all__ attribute exports the spoke class, followed by the first lines of its definition including
definitions of attributes previously mentioned in GUI Add-on basic features. These attribute values are
referencing widgets defined in the com_example_hello_world/gui/spokes/hello.glade file. Two other
notable attributes are present:
category, which has its value imported from the HelloWorldCategory class from the
com_example_hello_world.gui.categories module. The HelloWorldCategory that the path
to add-ons is in sys.path so that values can be imported from the com_example_hello_world
package. The category attribute is part of the N_ function name, which marks the string for
translation; but returns the non-translated version of the string, as the translation happens in a
later stage.
title, which contains one underscore in its definition. The title attribute underscore marks the
beginning of the title itself and makes the spoke reachable by using the Alt+H keyboard
shortcut.
What usually follows the header of the class definition and the class attributes definitions is the
constructor that initializes an instance of the class. In case of the Anaconda graphical interface objects,
there are two methods initializing a new instance: the __init__ method and the initialize method.
The reason behind two such functions is that the GUI objects may be created in memory at one time
and fully initialized at a different time, as the spoke initialization could be time consuming. Therefore,
the __init__ method should only call the parent’s __init__ method and, for example, initialize non-GUI
attributes. On the other hand, the initialize method that is called when the installer’s graphical user
interface initializes should finish the full initialization of the spoke.
In the Hello World add-on example, define these two methods as follows. Note the number and
description of the arguments passed to the __init__ method.
32
CHAPTER 5. DEVELOPING INSTALLER ADD-ONS
"""
def initialize(self):
"""
The initialize method that is called after the instance is created.
The difference between init and this method is that this may take
a long time and thus could be called in a separate thread.
:see: pyanaconda.ui.common.UIObject.initialize
"""
NormalSpoke.initialize(self)
self._entry = self.builder.get_object("textLines")
self._reverse = self.builder.get_object("reverseCheckButton")
The data parameter passed to the __init__ method is the in-memory tree-like representation of the
Kickstart file where all data is stored. In one of the ancestors' __init__ methods it is stored in the
self.data attribute, which allows all other methods in the class to read and modify the structure.
NOTE
The storage object is no longer usable as of RHEL9. If your add-on needs to interact with
storage configuration, use the Storage DBus module.
Because the HelloWorldData class has already been defined in The Hello World addon example , there
already is a subtree in self.data for this add-on. Its root, an instance of the class, is available as
self.data.addons.com_example_hello_world.
Another action that an ancestor’s __init__ does is initializing an instance of the GtkBuilder with the
spoke’s .glade file and storing it as self.builder. The initialize method uses this to get the
GtkTextEntry used to show and modify the text from the kickstart file’s %addon section.
The __init__ and initialize methods are both important when the spoke is created. However, the main
role of the spoke is to be visited by a user who wants to change or review the spoke’s values shows and
sets. To enable this, three other methods are available:
refresh - called when the spoke is about to be visited; this method refreshes the state of the
spoke, mainly its UI elements, to ensure that the displayed data matches internal data structures
and, with that, to ensure that current values stored in the self.data structure are displayed.
apply - called when the spoke is left and used to store values from UI elements back into the
self.data structure.
execute - called when users leave the spoke and used to perform any runtime changes based
on the new state of the spoke.
These functions are implemented in the sample Hello World add-on in the following way:
def refresh(self):
"""
The refresh method that is called every time the spoke is displayed.
33
Red Hat Enterprise Linux 9.0 Customizing Anaconda
def apply(self):
"""
The apply method that is called when user leaves the spoke. It should
update the D-Bus service with values set in the GUI elements.
"""
buf = self._entry.get_buffer()
text = buf.get_text(buf.get_start_iter(),
buf.get_end_iter(),
True)
lines = text.splitlines(True)
self._hello_world_module.SetLines(lines)
self._hello_world_module.SetReverse(self._reverse.get_active())
def execute(self):
"""
The execute method that is called when the spoke is exited. It is
supposed to do all changes to the runtime environment according to
the values set in the GUI elements.
"""
# nothing to do here
pass
You can use several additional methods to control the spoke’s state:
ready - determines whether the spoke is ready to be visited; if the value is "False", the spoke is
not accessible, for example, the Package Selection spoke before a package source is
configured.
mandatory - determines if the spoke is mandatory or not, for example, the Installation
Destination spoke, which must always be visited, even if you want to use automatic partitioning.
All of these attributes need to be dynamically determined based on the current state of the installation
process.
Below is a sample implementation of these methods in the Hello World add-on, which requires a certain
value to be set in the text attribute of the HelloWorldData class:
@property
def ready(self):
34
CHAPTER 5. DEVELOPING INSTALLER ADD-ONS
"""
The ready property reports whether the spoke is ready, that is, can be visited
or not. The spoke is made (in)sensitive based on the returned value of the ready
property.
:rtype: bool
"""
@property
def mandatory(self):
"""
The mandatory property that tells whether the spoke is mandatory to be
completed to continue in the installation process.
:rtype: bool
"""
After these properties are defined, the spoke can control its accessibility and completeness, but it
cannot provide a summary of the values configured within - you must visit the spoke to see how it is
configured, which may not be desired. For this reason, an additional property called status exists. This
property contains a single line of text with a short summary of configured values, which can then be
displayed in the hub under the spoke title.
The status property is defined in the Hello World example add-on as follows:
@property
def status(self):
"""
The status property that is a brief string describing the state of the
spoke. It should describe whether all values are set and if possible
also the values themselves. The returned value will appear on the hub
below the spoke's title.
:rtype: str
"""
lines = self._hello_world_module.Lines
if not lines:
return _("No text added")
elif self._hello_world_module.Reverse:
return _("Text set with {} lines to reverse").format(len(lines))
else:
return _("Text set with {} lines").format(len(lines))
35
Red Hat Enterprise Linux 9.0 Customizing Anaconda
After defining all properties described in the examples, the add-on has full support for showing a
graphical user interface (GUI) as well as Kickstart.
NOTE
The example demonstrated here is very simple and does not contain any controls;
knowledge of Python Gtk programming is required to develop a functional, interactive
spoke in the GUI.
One notable restriction is that each spoke must have its own main window - an instance of the
SpokeWindow widget. This widget, along with other widgets specific to Anaconda, is found in the
anaconda-widgets package. You can find other files required for development of add-ons with GUI
support, such as Glade definitions, in the anaconda-widgets-devel package.
Once your graphical interface support module contains all necessary methods you can continue with the
following section to add support for the text-based user interface, or you can continue with Deploying
and testing an Anaconda add-on and test the add-on.
The sample Hello World add-on demonstrates usage of the englightbox content manager which
Anaconda also uses. This content manager can put a window into a lightbox to increase its visibility and
focus it to prevent users interacting with the underlying window. To demonstrate this function, the
sample add-on contains a button which opens a new dialog window; the dialog itself is a special
HelloWorldDialog inheriting from the GUIObject class, which is defined in pyanaconda.ui.gui.init.
The dialog class defines the run method that runs and destroys an internal Gtk dialog accessible through
the self.window attribute, which is populated using a mainWidgetName class attribute with the same
meaning. Therefore, the code defining the dialog is very simple, as demonstrated in the following
example:
The Defining an englightbox Dialog example code creates an instance of the dialog and then uses the
enlightbox context manager to run the dialog within a lightbox. The context manager has a reference to
the window of the spoke and only needs the dialog’s window to instantiate the lightbox for the dialog.
Another useful feature provided by Anaconda is the ability to define a spoke that will appear both
during the installation and after the first reboot. The Initial Setup utility is described in Adding support
for the Add-on graphical user interface (GUI). To make a spoke available in both Anaconda and Initial
Setup, it must inherit the special FirstbootSpokeMixIn class, also known as mixin, as the first inherited
class defined in the pyanaconda.ui.common module.
To make a spoke available in Anaconda and the reconfiguration mode of the Initial Setup, it must inherit
36
CHAPTER 5. DEVELOPING INSTALLER ADD-ONS
To make a spoke available in Anaconda and the reconfiguration mode of the Initial Setup, it must inherit
the special FirstbootSpokeMixIn class, also known as mixin, as the first inherited class defined in the
pyanaconda.ui.common module.
If you want to make a certain spoke available only in Initial Setup, this spoke should instead inherit the
FirstbootOnlySpokeMixIn class.
To make a spoke always available in both Anaconda and Initial Setup, the spoke should redefine the
should_run method, as demonstrated in the following example:
@classmethod
def should_run(cls, environment, data):
"""Run this spoke for Anaconda and Initial Setup"""
return True
The pyanaconda package provides many more advanced features, such as the @gtk_action_wait and
@gtk_action_nowait decorators, but they are out of scope of this guide. For more examples, refer to
the installer’s sources.
NOTE
To add support for the text interface into your add-on, create a new set of subpackages
under the tui directory as described in Anaconda add-on structure.
The text mode support in the installer is based on the simpleline library, which only allows very simple
user interaction. The text mode interface:
Does not support cursor movement - instead, it acts like a line printer.
Does not support any visual enhancements, such as using different colors or fonts, for example.
Internally, the simpleline toolkit has three main classes: App, UIScreen and Widget. Widgets are units
containing information to be printed on the screen. They are placed on UIScreens that are switched by a
single instance of the App class. On top of the basic elements, hubs, spoke`s and `dialogs all contain
various widgets in a way similar to the graphical interface.
The most important classes for an add-on are NormalTUISpoke and various other classes defined in the
pyanaconda.ui.tui.spokes package. All those classes are based on the TUIObject class, which itself is
an equivalent of the GUIObject class discussed in Add-on GUI advanced features. Each TUI spoke is a
Python class inheriting from the NormalTUISpoke class, overriding special arguments and methods
defined by the API. Because the text interface is simpler than the GUI, there are only two such
arguments:
title - determines the title of the spoke, similar as the title argument in the GUI.
37
Red Hat Enterprise Linux 9.0 Customizing Anaconda
category - determines the category of the spoke as a string; the category name is not displayed
anywhere, it is only used for grouping.
NOTE
The TUI handles categories differently than the GUI. It is recommended to assign a pre-
existing category to your new spoke. Creating a new category would require patching
Anaconda, and brings little benefit.
Each spoke is also expected to override several methods, namely init, initialize, refresh, refresh, apply,
execute, input, prompt, and properties (ready, completed, mandatory, and status).
Additional resources
Prerequisites
You have created a new set of subpackages under the tui directory as described in Anaconda
add-on structure.
Procedure
Create modules with all required definitions to add support for the add-on text user interface
(TUI), according to the following examples:
:see: simpleline.render.screen.UIScreen
"""
super().__init__(*args, **kwargs)
self.title = N_("Hello World")
self._hello_world_module = HELLO_WORLD.get_proxy()
self._container = None
self._reverse = False
self._lines = ""
def initialize(self):
"""
The initialize method that is called after the instance is created.
The difference between __init__ and this method is that this may take
a long time and thus could be called in a separated thread.
:see: pyanaconda.ui.common.UIObject.initialize
"""
38
CHAPTER 5. DEVELOPING INSTALLER ADD-ONS
# nothing to do here
super().initialize()
:see: simpleline.render.screen.UIScreen.setup
"""
super().setup(args)
self._reverse = self._hello_world_module.Reverse
self._lines = self._hello_world_module.Lines
return True
:see: pyanaconda.ui.common.UIObject.refresh
:see: simpleline.render.screen.UIScreen.refresh
"""
super().refresh(args)
self._container = ListColumnContainer(
columns=1
)
self._container.add(
CheckboxWidget(
title="Reverse",
completed=self._reverse
),
callback=self._change_reverse
)
self._container.add(
EntryWidget(
title="Hello world text",
value="".join(self._lines)
),
callback=self._change_lines
)
self.window.add_with_separator(self._container)
39
Red Hat Enterprise Linux 9.0 Customizing Anaconda
:see: simpleline.render.screen.UIScreen.input
"""
if self._container.process_user_input(key):
return InputState.PROCESSED_AND_REDRAW
if key.lower() == Prompt.CONTINUE:
self.apply()
self.execute()
return InputState.PROCESSED_AND_CLOSE
def apply(self):
"""
The apply method is not called automatically for TUI. It should be called
in input() if required. It should update the contents of internal data
structures with values set in the spoke.
"""
self._hello_world_module.SetReverse(self._reverse)
self._hello_world_module.SetLines(self._lines)
def execute(self):
"""
The execute method is not called automatically for TUI. It should be called
in input() if required. It is supposed to do all changes to the runtime
environment according to the values set in the spoke.
"""
# nothing to do here
pass
NOTE
It is not necessary to override the init method if it only calls the ancestor’s init, but the
comments in the example describe the arguments passed to constructors of spoke
classes in an understandable way.
40
CHAPTER 5. DEVELOPING INSTALLER ADD-ONS
The setup method sets up a default value for the internal attribute of the spoke on every entry,
which is then displayed by the refresh method, updated by the input method and used by the
apply method to update internal data structures.
The execute method has the same purpose as the equivalent method in the GUI; in this case,
the method has no effect.
The input method is specific to the text interface; there are no equivalents in Kickstart or GUI.
The input methods are responsible for user interaction.
The input method processes the entered string and takes action depending on its type and
value. The above example asks for any value and then stores it as an internal attribute (key). In
more complex add-ons, you typically need to perform some non-trivial actions, such as parse
letters as actions, convert numbers into integers, show additional screens or toggle boolean
values.
The return value of the input class must be either the InputState enum or the input string itself,
in case this input should be processed by a different screen. In contrast to the graphical mode,
the apply and execute methods are not called automatically when leaving the spoke; they must
be called explicitly from the input method. The same applies to closing (hiding) the spoke’s
screen: it must be called explicitly from the close method.
To show another screen, for example if you need additional information that was entered in a different
spoke, you can instantiate another TUIObject and use ScreenHandler.push_screen_modal() to show
it.
Due to restrictions of the text-based interface, TUI spokes tend to have a very similar structure, that
consists of a list of checkboxes or entries that should be checked or unchecked and populated by the
user.
Prerequisites
You have added a new set of subpackages under the TUI directory, as described in Anaconda
add-on structure.
Procedure
Create modules with all required definitions to add support for the Add-on text user interface
(TUI), according to the following examples.
class HelloWorldEditSpoke(NormalTUISpoke):
"""Example class demonstrating usage of editing in TUI"""
41
Red Hat Enterprise Linux 9.0 Customizing Anaconda
category = HelloWorldCategory
self._window.add_separator()
42
CHAPTER 5. DEVELOPING INSTALLER ADD-ONS
@property
def completed(self):
# completed if user entered something non-empty to the Conditioned input
return bool(self._conditional_input)
@property
def status(self):
return "Hidden input %s" % ("entered" if self._conditional_input
else "not entered")
def apply(self):
# nothing needed here, values are set in the self.args tree
pass
Prerequisites
Procedure
cd DIR
a. Add the updates.img file into the images directory of your unpacked ISO contents.
43
Red Hat Enterprise Linux 9.0 Customizing Anaconda
c. Set up a web server to provide the updates.img file to the Anaconda installer via HTTP.
d. Load updates.img file at boot time by adding the following specification to the boot
options.
For specific instructions on unpacking an existing boot image, creating a product.img file and
repackaging the image, see Extracting Red Hat Enterprise Linux boot images .
[1] The gui package may also contain a categories subpackage if the add-on needs to define a new category, but
this is not recommended.
44
CHAPTER 6. COMPLETING POST CUSTOMIZATION TASKS
This section provides information about how to create a product.img image file and to create a custom
boot image.
During a system boot, Anaconda loads the product.img file from the images/ directory on the boot
media. It then uses the files that are present in this directory to replace identically named files in the
installer’s file system. The files when replaced customizes the installer (for example, for replacing
default images with custom ones).
Note: The product.img image must contain a directory structure identical to the installer. For more
information about the installer directory structure, see the table below.
Procedure
1. Navigate to a working directory such as /tmp, and create a subdirectory named product/:
$ cd /tmp
45
Red Hat Enterprise Linux 9.0 Customizing Anaconda
$ mkdir product/
3. Create a directory structure identical to the location of the file you want to replace. For
example, if you want to test an add-on that is present in the /usr/share/anaconda/addons
directory on the installation system, create the same structure in your working directory:
$ mkdir -p product/usr/share/anaconda/addons
NOTE
To view the installer’s runtime file, boot the installation and switch to virtual
console 1 (Ctrl+Alt+F1) and then switch to the second tmux window (Ctrl+b+2).
A shell prompt that can be used to browse a file system opens.
4. Place your customized files (in this example, custom add-on for Anaconda) into the newly
created directory:
$ cp -r ~/path/to/custom/addon/ product/usr/share/anaconda/addons/
5. Repeat steps 3 and 4 (create a directory structure and place the custom files into it) for every
file you want to add to the installer.
6. Create a .buildstamp file in the root of the directory. The .buildstamp file describes the
system version, the product and several other parameters. The following is an example of a
.buildstamp file from Red Hat Enterprise Linux 8.4:
[Main]
Product=Red Hat Enterprise Linux
Version=8.4
BugURL=https://bugzilla.redhat.com/
IsFinal=True
UUID=202007011344.x86_64
[Compose]
Lorax=28.14.49-1
The IsFinal parameter specifies whether the image is for a release (GA) version of the product
(True), or a pre-release such as Alpha, Beta, or an internal milestone ( False).
$ cd product
This creates a product.img file one level above the product/ directory.
8. Move the product.img file to the images/ directory of the extracted ISO image.
The product.img file is now created and the customizations that you want to make are placed in the
respective directories.
NOTE
46
CHAPTER 6. COMPLETING POST CUSTOMIZATION TASKS
NOTE
Instead of adding the product.img file on the boot media, you can place this file into a
different location and use the inst.updates= boot option at the boot menu to load it. In
that case, the image file can have any name, and it can be placed in any location (USB
flash drive, hard disk, HTTP, FTP or NFS server), as long as this location is reachable from
the installation system.
Procedure
1. Make sure that all of your changes are included in the working directory. For example, if you are
testing an add-on, make sure to place the product.img in the images/ directory.
2. Make sure your current working directory is the top-level directory of the extracted ISO image,
for example, /tmp/ISO/iso/.
Make sure that the values for -V, -volset, and -A options match the image’s boot loader
configuration, if you are using the LABEL= directive for options that require a location to
load a file on the same disk. If your boot loader configuration (isolinux/isolinux.cfg for
BIOS and EFI/BOOT/grub.cfg for UEFI) uses the inst.stage2=LABEL=disk_label stanza
to load the second stage of the installer from the same disk, then the disk labels must
match.
IMPORTANT
In boot loader configuration files, replace all spaces in disk labels with \x20.
For example, if you create an ISO image with a RHEL 9.0 label, boot loader
configuration should use RHEL\x209.0.
Replace the value of the -o option (-o ../NEWISO.iso) with the file name of your new image.
The value in the example creates the NEWISO.iso file in the directory above the current
one.
For more information about this command, see the genisoimage(1) man page.
4. Implant an MD5 checksum into the image. Note that without an MD5 checksu, the image
verification check might fail (the rd.live.check option in the boot loader configuration) and the
installation can hang.
# implantisomd5 ../NEWISO.iso
47
Red Hat Enterprise Linux 9.0 Customizing Anaconda
In the above example, replace ../NEWISO.iso with the file name and the location of the ISO
image that you have created in the previous step.
You can now write the new ISO image to physical media or a network server to boot it on
physical hardware, or you can use it to start installing a virtual machine.
Additional resources
For instructions on preparing boot media or network server, see Performing an advanced RHEL
9 installation.
For instructions on creating virtual machines with ISO images, see Configuring and Managing
Virtualization.
48