I mentioned in my targeted PXE booting post that I might migrate from maintaining copies of the kernel and initial ramdisks on the tftp server to asking iPXE to fetch them directly. This has been brought to the fore after I updated the mirror in my home lab environment and the installer no longer starts due to not being able to load its kernel modules. When I fetched the image from the mirror and compared its checksum to the one in my configuration management system I saw it had changed.
This is the error I see from the installer showing the problem:
Remotely fetching the image directly
In the original configuration, Salt fetches the image from the mirror (e.g. http://ftp.uk.debian.org/debian/dists/bullseye/main/installer-amd64/current/images/netboot/debian-installer/amd64/linux) and deploys it to the tftp server. iPXE is then configured to load the image from there. I am reconfiguring iPXE to fetch the image directly, initially from the local mirror in the lab network.
The original configuration lines (in this case for Debian’s bullseye (current stable at the time of writing) release were:
:bullseye-amd64 kernel ../bullseye-amd64/linux initrd=initrd.gz -- quiet initrd ../bullseye-amd64/initrd.gz boot
The edited ones (in the lab) :
:bullseye-amd64 kernel http://mirror/mirrors/debian/dists/bullseye/main/installer-amd64/current/images/netboot/debian-installer/amd64/linux initrd=initrd.gz -- quiet initrd http://mirror/mirrors/debian/dists/bullseye/main/installer-amd64/current/images/netboot/debian-installer/amd64/initrd.gz boot
This worked (shockingly, on the first attempt) and the installer was able to load correctly.
For CentOS I updated the entries like this - for the live network, fetching from the internet,
:centos-7-x86_64 kernel http://mirror/mirrors/centos-7-os/images/pxeboot/vmlinuz initrd=initrd.img -- ip=dhcp inst.repo=http://mirror/mirrors/centos-7-os/ rhgb quiet initrd http://mirror/mirrors/centos-7-os/images/pxeboot/initrd.img boot
Including images in mirrors
See my previous post on improving my mirror synchronisation script for the original version of these scripts that these changes apply to.
I initially had not included the installers in my Debian mirrors, fortunately adding them is a case of enabling the option
di-arch when calling
debmirror however this caused
debmirror to fail if the mirror does not have installers (e.g. updates and security mirrors). To work round this, I added an option to the role and made it an option when using the role.
defaults/main.yml I set the default value to be false (maintains old behaviour by default and more mirrors do not have installers to fetch than do):
and added the option in
installers: type: bool default: false description: Fetch the Debian installers (that match the architectures and suites requested)
Finally, modifying the
Run debmirror task in
tasks/main.yml to apply the option:
# Debian installers as well, if required. Bit of a hack - repeat # the --verbose if not wanted to put _something_ in the argument # list. - "--verbose" - "--verbose"
In the the
debian-mirrors role, which uses the debmirror role to mirror the specific mirrors I need, I set the new
installers option to
true on just the main mirror in
--- dependencies: - role: debmirror source: host: rsync.mirrorservice.org root: ftp.debian.org/debian target: '/debian' installers: true keyring_directory: '/keyrings/debian' suites: - buster - buster-updates - bullseye - bullseye-updates keys: - name: debian-10-buster url: https://ftp-master.debian.org/keys/archive-key-10.asc fingerprint: "80D1 5823 B7FD 1561 F9F7 BCDD DC30 D7C2 3CBB ABEE" - name: debian-11-buster url: https://ftp-master.debian.org/keys/archive-key-11.asc fingerprint: "1F89 983E 0081 FDE0 18F3 CC96 73A4 F27B 8DD4 7936" ...
This applies to CentOS and Rocky. Unlike
reposync has no option to download images automatically or specifically download extra files so they have to fetched separately. This does have the advantage that rather than selectively download via a variable (like I did with Debian) I test for the existence of the images folder and download them based on that.
tasks/main.yml, I included an image fetch task for each repository. I pulled out the files as a variable, although they are the same for CentOS 7 and Rocky 8 I fear they might change in the future:
- name: Fetch boot/installer images for each repository include_tasks: fetch_additional_files.yaml vars: source: "" destination: "/" extra_files: - images/pxeboot/vmlinuz - images/pxeboot/initrd.img - LiveOS/squashfs.img # CentOS 7 installer - images/install.img # Rocky 8 installer loop: '' loop_control: loop_var: repo # Avoid conflict with inner loop(s)
fetch_additional_files.yaml file contains:
--- - name: Test if source exists (might not for, e.g., updates mirrors) ansible.builtin.uri: url: "/" method: HEAD status_code: - 200 - 404 # Not found is an expected potential outcome register: test_file_uris loop: '' - name: Ensure target directories exists ansible.builtin.file: name: '/' state: directory loop: '' when: item.status == 200 - name: Fetch files ansible.builtin.get_url: dest: "//" # Ensure ends in `/` to indicate directory url: '' loop: '' when: item.status == 200 ...
DBAN was a little more interesting, because getting the image to PXE boot requires extracting it from the DBAN ISO image. In my old configuration, I pushed a manually extracted copy of the image stored in the configuration management code repository. I want to get away from this, it violates the principal of duplicating something that can get obtained from a more authoritative source and it puts a large (16MB) binary file into source control which is bad practice.
So, I added DBAN to my mirror with a new role. The role takes two arguments,
target (where to mirror to) and
version (which version of DBAN to fetch). First thing was to create
--- argument_specs: main: short_description: Mirror DBAN ISO and extract dban image (e.g. for PXE booting) options: target: type: str required: true description: Directory to mirror to version: type: str required: true description: Version of DBAN to fetch ...
Then the actual task in
--- - name: Make sure isoinfo is installed become: yes ansible.builtin.package: name: genisoimage state: present - name: Make target directory ansible.builtin.file: path: "" state: directory - name: Download iso ansible.builtin.get_url: dest: '/' url: https://sourceforge.net/projects/dban/files/dban/dban-/dban-_i586.iso/download - name: Extract DBan image ansible.builtin.shell: cmd: > isoinfo -i /dban-_i586.iso -x '/DBAN.BZI;1' > /dban.bzi - name: State the extracted file (check for silent failure of isoinfo) ansible.builtin.stat: path: '/dban.bzi' register: dban_extracted_image_stat - name: Check size ansible.builtin.assert: fail_msg: Extracted image does not exist or is zero sized that: - dban_extracted_image_stat.stat.exists - dban_extracted_image_stat.stat.size > 0 ...
To add DBAN to the mirror, I just added the role to the roles list in
- role: dban target: "/dban-2.3.0" version: 2.3.0 tags: ['dban']
It is worth noting that DBAN only works on BIOS booted systems, not EFI.
After committing, I also renamed all the
.yml files to
.yaml and committed that too - a convention I moved to a while a go and brings this code in line with my others.