Monday 27 October 2014

Fun with RHEL 6 kickstart continued

I had to recently go back and look at creating a custom RHEL 6 DVD. Although I had done this in the past, it appeared that the work in my previous post was incomplete. There were many things that I had not realised needed to be correct to allow a RHEL 6 DVD to work. These changes seem to have crept in from RHEL6.1 to RHEL6.5. These were:-

  • The build environment for the RHEL6 DVD
  • The DVD .treeinfo file
  • The different repodata directories on the disk
  • The change of location for the repodata directory
  • The subtle change of format of the files in the repodata directory

RHEL6 build environment

The first problem that I noticed with the build that was using my RHEL5 build environment was that the format of the .xml files created by the createrepo tool were different and did not use the default SHA265 checksums. The only answer was to build a RHEL6 server and add the necessary files to allow the DVD to be created. The installation was on a VM and used the basic RHEL graphical install.

The following packages were added to the install to complete the build environment.

createrepo-0.9.9-22.el6.noarch.rpm
python-deltarpm-3.5-0.5.20090913git.el6.x86_64.rpm
deltarpm-3.5-0.5.20090913git.el6.x86_64.rpm

These were installed using the normal yum command.

yum install -y --nogpgcheck ./deltarpm-3.5-0.5.20090913git.el6.x86_64.rpm
yum install -y --nogpgcheck ./python-deltarpm-3.5-0.5.20090913git.el6.x86_64.rpm

yum install -y --nogpgcheck ./createrepo-0.9.9-22.el6.noarch.rpm


The DVD .treeinfo file

To my surprise this file is now important to the DVD and kickstart. Here is a sample based on my custom RHEL6 DVD.

[general]
family = Red Hat Enterprise Linux
timestamp = 1384196515.415715
variant = Server
totaldiscs = 1
version = 6.5
discnum = 1
packagedir = Packages 
variants = Server
arch = x86_64

[images-x86_64]
initrd = images/pxeboot/initrd.img
kernel = images/pxeboot/vmlinuz

[images-xen]
initrd = images/pxeboot/initrd.img
kernel = images/pxeboot/vmlinuz

[variant-Server]
addons =
repository = repodata

[checksums]
images/pxeboot/initrd.img = sha256:ee05f49df116b74342467fd403c4cddb740c21e29b82ccac33e763ce5a0cc02a
images/efiboot.img = sha256:6facd92cf4b7c572d1e7e7a82aa96e78dca2c074a89cf381d105719d4e5b39be
images/pxeboot/vmlinuz = sha256:92670cf84a593faaafc71b25bc30efc56b742b484c76f254cc9910e9712b98a8
images/install.img = sha256:86a8e1b59eeefd2db84c9ce3b5f29d9a24d3eb6cf7edef366eb80e0b06abd3a1
images/efidisk.img = sha256:b201662c37170f0a290f8484b939d4d474fd60d6ba94b48866c8979154a95bf1
images/product.img = sha256:a18500d76e6faf0df6df8487b05a15116fb13c3ce455be1b9d68a6026eb295bd

[stage2]
mainimage = images/install.img 

From what I can gather this file will point to the base repodata directory which the distribution will use to detail the packages / groups to install. The problem that I found was that there was no definitive explanation to this file format. The following is based on the information at the following URL Fedup .treeinfo.

Some details about the file format:

[general] section: general info about this distro tree.

  • 'timestamp', 'arch', and 'version' are required.
  • 'timestamp' is the build time, in seconds since the Epoch. It may be a floating point number.
  • 'timestamp' should match the timestamp in other .treeinfo files for other arches/variants built as part of the same "compose". (e.g. Fedora 17 x86_64 and Fedora 17 i386 have the same timestamp.)
  • 'version' is a string, not an integer - "17-Beta" is valid.
  • 'family' is the OS/distro family name, 'variant' is name of the distro variant, like "Server" or "Client" or "Workstation".
  • 'packagedir' usually points to the directory containing packages, but in Fedora this is ignored in favor of reading repodata/repomd.xml.
  • 'discnum' and 'totaldiscs' can be used when writing a tree to multiple CD/DVD images.

[stage2] section: installer runtime images.
- 'mainimage' will refer to the main installer runtime image, if one exists.
In Fedora 17 and later the installer uses this to automatically find
its runtime if you boot with 'inst.repo=url://to/os/tree'.

[images-*] sections: list the boot images (kernel, initramfs, boot.iso, etc.)

  • There should be an [images-$arch] section for the arch in [general]. There may be more sections for other major arches the tree supports.
  • [images-xen], by convention, contains the images that should be used when installing into a virtualized guest.
  • Standard keys are 'kernel', 'initrd', and 'boot.iso'.


[checksums] section: checksums of various files in the tree

  • Everything listed in all the [images-*] sections should have a checksum.
  • Each line is of the form: relative/path = hash_algorithm:hex_digest

The different repodata directories on the disk

This was strange to understand because the DVD appeared to have multiple repodata directories. If you look at the top level of an official RHEL6 DVD it has the following directories:-

dr-xr-xr-x   3 root  root    2048 30 Jan  2013 EFI
dr-xr-xr-x   3 root  root    2048 30 Jan  2013 HighAvailability
dr-xr-xr-x   3 root  root    2048 30 Jan  2013 LoadBalancer
dr-xr-xr-x   2 root  root  671744 30 Jan  2013 Packages
dr-xr-xr-x   3 root  root    2048 30 Jan  2013 ResilientStorage
dr-xr-xr-x   3 root  root    2048 30 Jan  2013 ScalableFileSystem
dr-xr-xr-x   3 root  root    2048 30 Jan  2013 Server
dr-xr-xr-x   3 root  root    2048 30 Jan  2013 images
dr-xr-xr-x   2 root  root    2048 30 Jan  2013 isolinux
dr-xr-xr-x   2 root  root    4096 30 Jan  2013 repodata

  • The directory EFI/ contains EFI boot loader.
  • The directory HighAvailability/ contains a repodata directory defining the packages for a high availability system.
  • The directory LoadBalancer/ contains a repodata directory defining the packages for a load balancer system.
  • The directory Packages/ contains the .rpm packages.
  • The directory ResilientStorage/ contains a repodata directory defining the packages for a resilient storage server system.
  • The directory ScalableFileSystem/ contains a repodata directory defining the packages for a server with a scalable file system.
  • The directory Server/ contains a repodata directory defining the packages for a server system.
  • The directory images/ contains the image files used during the Red Hat Enterprise Linux 6 installation process.
  • The directory isolinux/ contains the boot menu configuration files.
  • The directory repodata/ contains the default data to define the packages / groups that are to be installed. 
Note: If you don't plan on using the HighAvailability, LoadBalancer, ResilientStorage, ScalableFileSystem, or Server configurations, these directories and their contents can be removed.

Repodata

The files in the repodata/ directory are built using the createrepo command. The easiest way to do this is to have a master comps-rhel6-Server.xml file. When I set up the build environment I created a directory /isobuild/ and put the master comps-rhel6-Server.xml file under that top level directory. I then created the following /isobuild/custom/ directory for the custom iso contents.

mkdir /isobuild
mkdir -p /isobuild/custom
mkdir /tmp/cdrom
mount /dev/cdrom /tmp/cdrom
cp -R /tmp/cdrom/* /isobuild/custom/
cp -R /tmp/cdrom/.[a-zA-Z]* /tmp/cdrom/

Before clearing out some of the unwanted directories I copied the Server/repodata/*comps-rhel6-Server.xml.gz file to /isobuild/ and called it comps-rhel6-Server.xml.

cd /isobuild
cp custom/Server/repodata/*-comps-rhel6-Server.xml.gz ./comps-rhel6-Server.xml.gz

This then gave me an initial file that I could start editing to remove / add packages to. The files in the DVD repodata directory were created using the following command.

rm -f /isobuild/custom/repodata/*
createrepo -g /isobuild/comps-rhel6-Server.xml -d --unique-md-filenames /isobuild/custom/

This then creates the files with the unique SHA256 checksum in the DVD top level repodata/ directory. An example of this is shown below:-

-r--r--r--  1 root root  463035 17 Oct 14:00 15334241501e71eb54ad91b428a1b9e56aee2824c015ccfdbc065d8b16c04e19-other.xml.gz
-r--r--r--  1 root root  166352 17 Oct 14:00 1995b5df9e976dece7eaedf28d8f908de9d2961cbf1eb4ea6fbca1e6359bac16-comps-rhel6-Server.xml.gz
-r--r--r--  1 root root  427170 17 Oct 14:00 1e9af68d10366dd64ec029ae3b04b1f793d81abfabff9700cedeafa7b1b5faa7-other.sqlite.bz2
-r--r--r--  1 root root  950077 17 Oct 14:00 47feabb6b96315377d52069f3f0a5a415b1204a7607716260c16e69a2c5421b8-primary.sqlite.bz2
-r--r--r--  1 root root  547723 17 Oct 14:00 561799eb2d4d9dac7b13ffab7254742a28e7d9142df6c22ec1ea7784456f93e9-filelists.xml.gz
-r--r--r--  1 root root  950725 17 Oct 14:00 6f4792d5709aafc4a3419ef2a06bee206770d55703abf3d165261d58118feb8d-comps-rhel6-Server.xml
-r--r--r--  1 root root  482240 17 Oct 14:00 8666d0ae94a3cd38e5608753caa33cdad96fbd4ca092e1f55930b584323e1675-primary.xml.gz
-r--r--r--  1 root root    2581 17 Oct 14:00 TRANS.TBL
-r--r--r--  1 root root  708577 17 Oct 14:00 fa3bfef517376f3d28c0e20ce16c0aecb6e4fefd171be5dafdeb18a4a701bda7-filelists.sqlite.bz2
-r--r--r--  1 root root    3739 17 Oct 14:00 repomd.xml

The repomod.xml file that is created differs from the official RedHat version in that it doesn't have an entry for the productid.gz file. The following URL gives the explanation of what this is and why it is used:- productid.gz


When you import the distribution, createrepo runs and recreates repomd.xml, which removes this element from the original:

<data type="productid">
<location href="repodata/productid.gz"/>
<checksum type="sha">c0150e34800edcef42a43d0d0f051b3b3a421b34</checksum><timestamp>1359577376</timestamp>
<open-checksum type="sha">5dfbaa2ef24689b4141ae655d3f352be62a128d7</open-checksum></data>

When the OS installs on the client, it checks the checksum from this element to the checksum of the productid.gz file. If they don't match then the installer cannot identify the OS, which results in the /etc/pki/product/69.pem not being created. 69.pem is just the productid file from the repo. This file is needed to successfully subscribe to the software channel at RHN.

# sha1sum productid.gz
c0150e34800edcef42a43d0d0f051b3b3a421b34  productid.gz

The symptom that this has happened is that if you attempt to subscribe via subscription-manager, then you get "no installed products" type error messages. You can fix the client by manually copying the productid file to /etc/pki/product/69.pem.

If you are not planning to use the RHN for updates because the system that you are building has no access to the public internet then this can be ignored.

Closing Notes

Editing the comps-rhel6-Server.xml file is fraught with problems. Be warned a simple typo can stop the whole kickstart process dead in its tracks with a python exception. My advice is to make small edits and create incremental backups.

Make sure that the .treeinfo file has the following:- repository = repodata otherwise the default repository might not be found.

The following is my build script to recreate the repodata and create the .iso image.

rm -f /isobuild/custom/repodata/*<CR>
createrepo -g /isobuild/comps-rhel6-Server.xml -d --unique-md-filenames /isobuild/custom/<CR>
mkisofs -r -J -T -V "RHEL6 x86_64" -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -o /isobuild/RHEL6-64-0914.iso /isobuild/custom<CR>
chmod a+rwx /isobuild/RHEL6-64-0914.iso<CR>

Obviously remove the <CR> from the commands. These are just there to show where the line ends because the text wraps round.