Use virt-install to fully automate the install for CentOS/Fedora with kickstart

Here is my kickstart file for CentOS 7. I deploy VMs into my kvm environment with a oneliner, using this kickstart file.

How I use this

I define a variable, and plug it into the important parts.

vm=c7-04a ; time sudo virt-install -n "${vm}" --memory 2048 \
   --vcpus=1 --os-variant=centos7.0 --accelerate -v \
   --disk path=/var/lib/libvirt/images/"${vm}".qcow2,size=20 \
   -l /mnt/public/Support/SetupsBig/Linux/CentOS-7-x86_64-Minimal-1810.iso \
   --initrd-inject=/mnt/public/Support/Platforms/CentOS7/centos7-ks.cfg \
   --extra-args "ks=file:/centos7-ks.cfg SERVERNAME=${vm} NOTIFYEMAIL=bgstack15@gmail.com" \
   --debug --network type=bridge,source=br0 --noautoconsole

Some thoughts

I had to download the 1810 release of the iso, because there was something wrong with the repos or perhaps files in the previous isos, with how they interacted with either the virtual environment or the network or something. But the CentOS-7-x86_64-minimal-1810.iso was important.
I found the SERVERNAME trick on the Internet. You can iterate over /proc/cmdline and react to values you find there, in the %pre or %post scripts.
You will see that I use my own local repositories for the regular CentOS repos, and I add my own internal one (smith122/repo/rpm). Obviously you should find a suitable set of repos for your own.
You will also see that I attempt to download my CA certificates at various points. I’m pretty sure the %pre effort fails, because the system is not on the network yet.

Dependencies

The kickstart file

# File: /mnt/public/Support/Platforms/CentOS7/centos7-ks.cfg
# Locations:
#    /mnt/public/Support/Platforms/CentOS7/centos7-ks.cfg
# Author: bgstack15
# Startdate: 2017-06-02
# Title: Kickstart for CentOS 7 for ipa.smith122.com
# Purpose: To provide an easy installation for VMs and other systems in the Mersey network
# History:
#    2017-06 I learned how to use kickstart files for the RHCSA EX-200 exam
#    2017-08-08 Added notifyemail to --extra-args
#    2017-10-29 major revision to use local repository
#
#
#
#
# Usage with virt-install:
#    vm=c7-04a ; time sudo virt-install -n "${vm}" --memory 2048 --vcpus=1 --os-variant=centos7.0 --accelerate -v --disk path=/var/lib/libvirt/images/"${vm}".qcow2,size=20 -l /mnt/public/Support/SetupsBig/Linux/CentOS-7-x86_64-Minimal-1810.iso --initrd-inject=/mnt/public/Support/Platforms/CentOS7/centos7-ks.cfg --extra-args "ks=file:/centos7-ks.cfg SERVERNAME=${vm} NOTIFYEMAIL=bgstack15@gmail.com" --debug --network type=bridge,source=br0 --noautoconsole
#    vm=c7-04a; sudo virsh destroy "${vm}"; sudo virsh undefine --remove-all-storage "${vm}";
# Reference:
#    https://sysadmin.compxtreme.ro/automatically-set-the-hostname-during-kickstart-installation/
#    /mnt/public/Support/Platforms/CentOS7/install-vm.txt

#platform=x86, AMD64, or Intel EM64T
#version=DEVEL
# Install OS instead of upgrade
install
# Keyboard layouts
keyboard 'us'
# Root password
rootpw --plaintext SOMETHINGSTRONGHERE
# my user
user --groups=wheel --name=bgstack15-local --password=$6$.gh0u7vg2HDPJPX/$g4Y1l.q76fs7i0UK8t6h83bDIo2YnGGj/1DGeUzzbMTd0pBh4of6jNYWxxws/937sUiPgETqPsYFI5XNrkAle. --iscrypted --gecos="bgstack15-local"

# System language
lang en_US.UTF-8
# Firewall configuration
firewall --enabled --ssh
# Reboot after installation
reboot
# Network information
#attempting to put it in the included ks file that accepts hostname from the virsh command.
#network  --bootproto=dhcp --device=eth0 --ipv6=auto --activate
%include /tmp/network.ks
# System timezone
timezone America/New_York --utc
# System authorization information
auth  --useshadow  --passalgo=sha512
# Use network installation instead of CDROM installation media
url --url="http://www.ipa.smith122.com/mirror/centos/7/os/x86_64/"

# Use text mode install
text
# SELinux configuration
selinux --enforcing
# Do not configure the X Window System
skipx

# Use all local repositories
# Online repos
repo --name=smith122rpm --baseurl=https://www.ipa.smith122.com/smith122/repo/rpm/
repo --name=base --baseurl=https://www.ipa.smith122.com/mirror/centos/$releasever/os/$basearch/
repo --name=updates --baseurl=https://www.ipa.smith122.com/mirror/centos/$releasever/updates/$basearch/
repo --name=extras --baseurl=https://www.ipa.smith122.com/mirror/centos/$releasever/extras/$basearch/
repo --name=epel --baseurl=https://www.ipa.smith122.com/mirror/fedora/epel/$releasever/$basearch

# Offline repos
#
#
#
#
#

firstboot --disabled

# System bootloader configuration
bootloader --location=mbr
# Partition clearing information
clearpart --all --initlabel
# Disk partitioning information
autopart --type=lvm

%pre
echo "network  --bootproto=dhcp --device=eth0 --ipv6=auto --activate --hostname renameme.ipa.smith122.com" > /tmp/network.ks
for x in $( cat /proc/cmdline );
do
   case $x in
      SERVERNAME*)
         eval $x
         echo "network  --bootproto=dhcp --device=eth0 --ipv6=auto --activate --hostname ${SERVERNAME}.ipa.smith122.com" > /tmp/network.ks
         ;;
      NOTIFYEMAIL*)
         eval $x
         echo "${NOTIFYEMAIL}" > /mnt/sysroot/root/notifyemail.txt
         ;;
   esac
done
cp -p /run/install/repo/ca-ipa.smith122.com.crt /etc/pki/ca-trust/source/anchors/ 2>/dev/null || :
wget http://www.ipa.smith122.com/smith122/certs/ca-ipa.smith122.com.crt -O /etc/pki/ca-trust/source/anchors/ca-ipa.smith122-wget.com.crt || :
update-ca-trust || :
%end

%post
(
   # Set temporary hostname
   #hostnamectl set-hostname renameme.ipa.smith122.com;

   # Get local mirror root ca certificate
   wget http://www.ipa.smith122.com/smith122/certs/ca-ipa.smith122.com.crt -O /etc/pki/ca-trust/source/anchors/ca-ipa.smith122.com.crt && update-ca-trust

   # Get local mirror repositories
   wget https://www.ipa.smith122.com/smith122/repo/rpm/smith122rpm.repo -O /etc/yum.repos.d/smith122rpm.repo;
   wget http://www.ipa.smith122.com/smith122/repo/rpm/smith122rpm.mirrorlist -O /etc/yum.repos.d/smith122rpm.mirrorlist
   distro=centos7 ; wget https://www.ipa.smith122.com/smith122/repo/mirror/smith122-bundle-${distro}.repo -O /etc/yum.repos.d/smith122-bundle-${distro}.repo && grep -oP "(? /boot/grub2/grub.cfg

   # postfix is already started by default on centos7
   # Send IP address to myself
   thisip="$( ifconfig 2>/dev/null | awk '/Bcast|broadcast/{print $2}' | tr -cd '[^0-9\.\n]' | head -n1 )"
   {
      echo "${SERVER} has IP ${thisip}."
      echo "system finished kickstart at $( date "+%Y-%m-%d %T" )";
   } | /usr/share/bgscripts/send.sh -f "root@$( hostname --fqdn )" \
      -h -s "${SERVER} is ${thisip}" $( cat /root/notifyemail.txt 2>/dev/null )

   # No changes to graphical boot
   #

   # fix the mkhomedir problem
   systemctl enable oddjobd.service && systemctl start oddjobd.service

   # Personal customizations
   mkdir -p /mnt/bgstack15 /mnt/public
   su bgstack15-local -c "sudo /usr/share/bgconf/bgconf.py"

) >> /root/install.log 2>&1
%end

%packages
@core
@^minimal
autossh
bc
bgconf
bgscripts-core
bind-utils
cifs-utils
cryptsetup
dosfstools
epel-release
expect
firewalld
git
iotop
ipa-client
-iwl*-firmware
mailx
man
mlocate
net-tools
nfs-utils
ntp
p7zip
parted
policycoreutils-python
rpm-build
rsync
screen
strace
sysstat
tcpdump
telnet
vim
wget
yum-utils
%end

Add custom kickstart file and root ca certificates to iso file

Introduction and goals

This is intended to be one of my longer posts. This article describes how to accomplish the following tasks:

  1. Insert custom kickstart files into an iso file
  2. Insert custom root CA certificates into the initrd.img of an iso file, so you can fetch a custom repository over https
  3. Write a sample kickstart file
  4. Open up the initrd.img to add more files

The example file used is Fedora-Workstation-netinst-x86_64-27-1.6.iso available from https://getfedora.org/en/workstation/download/

The files

You will need a few files, including:

  1. kickstart file
  2. Root certificate

Kickstart files

My 2 different kickstart files are
fc27c-ks.cfg (saved to WordPress as a .doc, but it is truly just a plain text file)
fc27x-ks.cfg
Quite a few things to note about the content:
I had to use http for all my local repositories, even though I got the ca certficate loaded. I think how my ISP bounces back my https traffic causes enough slowdown on the ssl handshake it prevents anaconda from using it correctly. It was working earlier in the day but I had to disable it.
Observe in the %pre scriptlet the lines

cp -p /run/install/repo/ca-ipa.smith122.com.crt /etc/pki/ca-trust/source/anchors 2>/dev/null || :
update-ca-trust || :

These 2 lines load up the root certificate authority cert into the running initrd trusted keys, so the ssl connections are trusted.
Please see the attached or indicated files.

Root certificate

A root certificate is the certificate that signs other certificates for that namespace. I use my own in my ipa domain, and I use it on my web server. So to connect with ssl because I want to encrypt everything possible, I need this cert in the runtime environment on the iso disc image. My root ca file is
not shared on this blog. Go get your own!

The steps

Mount original iso

mkdir -p /mnt/originaliso
mount -v -o loop /mnt/public/Support/SetupsBig/Linux/Fedora-Workstation-netinst-x86_64-27-1.6.iso /mnt/originaliso/

Copy contents to work directory

mkdir -p /mnt/newiso ; cd /mnt/
time cp -pr originaliso/* newiso/

Copy in kickstart files

cp -pf /mnt/public/Support/Platforms/Fedora/fc27{x,c}-ks.cfg /mnt/newiso/
chown root:root /mnt/newiso/*ks.cfg
echo done

Tell disc to use new ks file

This task:

  • Adds xfce and cinnamon menu options
  • Find all the append= lines, and add to the end this attribute: ks=hd:LABEL=fc26:/fc26x-ks.cfg

The important piece is to have the LABEL= the volume name that you give the mkisofs -V “label” a few commands later in this article. If you really want to use a file:/ks.cfg, then you have to open up the initrd, which Appendix A demonstrates.

Fedora 27 xfce and cinnamon
label=fc27
tf=/mnt/newiso/isolinux/isolinux.cfg
sed -r -e "/append/{s/LABEL=([A-Za-z0-9_\-]*)(\s|:)/LABEL=${label}\2/;s/quiet//;};" -e '/label linux/,/^\s*$/H;' -e '/^\s*$/{x;};' "${tf}" | \
awk "BEGIN{a=0;b=0;labels[1]=\"xfce\";labels[2]=\"cinnamon\";} /^label [^l]/{b=b+1} b < 1 && /label linux/{a=a+1;\$0=\$0\" \"labels[a];} b < 1 && /menu label/{\$0=\$0\" \"labels[a];} b < 1 && /append/{\$0=\$0\"ks=hd:LABEL=${label}:/${label}\"substr(labels[a],1,1)\"-ks.cfg\";} {print;}" > "${tf}.$$"
mv -f "${tf}.$$" "${tf}"
Centos 7
label=centos7
tf=/mnt/newiso/isolinux/isolinux.cfg
sed -r -e "/append/{s/LABEL=([A-Za-z0-9_\-]*)(\s|:)/LABEL=${label}\2/;s/quiet//;};" "${tf}" | \
awk "BEGIN{a=0;b=0;labels[1]=\"with my bgstack15 custom kickstart\";} /^label [^l]/{b=b+1} b < 1 && /label linux/{a=a+1;\$0=\$0\" \"labels[a];} b < 1 && /menu label/{\$0=\$0\" \"labels[a];} b < 1 && /append/{\$0=\$0\"ks=hd:LABEL=${label}:/${label}-ks.cfg\";} {print;}" > "${tf}.$$"
mv -f "${tf}.$$" "${tf}"

Copy in certificate file

This will be used by the kickstart file and injected into the running initrd so https connections can be trusted to download the repos.

/bin/cp -pf /mnt/public/www/smith122/certs/ca-ipa.smith122.com.crt /mnt/newiso/
chown root:root /mnt/newiso/*.crt

Make new iso

Fedora 27
label=fc27
ti="${label}manual.iso"; cd /mnt/newiso;
rm -f /mnt/newiso/"${ti:-NOTHINGTODELETE}" ; __func() { mkisofs -V "${label}" -m '*.iso' -o "../${ti}" -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -r -J -v -T . ; implantisomd5 "/mnt/${ti}" ; } ; time __func
CentOS 7
ti=centos7manual.iso ; cd /mnt/newiso ;
rm -f /mnt/newiso/"${ti:-NOTHINGTODELETE}" ; __func() { mkisofs -V "${label}" -m '*.iso' -o "../${ti}" -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -r -J -v -T . ; implantisomd5 "/mnt/${ti}" ; } ; time __func

Copy to server so vm1 can access

time su bgstack15 -c "cp -pf /mnt/${ti} /mnt/public/Support/SetupsBig/Linux/";
echo done

Next steps

After that, the iso is ready to be burned to disc or used by virt-install. I have not actually tried burning a disc or usb drive, but I assume it’s pretty similar to a regular Live iso.
For virt-install, I was simply unable to get my fancy customized iso to work fully automatically. For a regular, unattended vm install, I use the regular Fedora netinstall iso and I inject my kickstart file.

vm=fc27x-02a ; time sudo virt-install -n "${vm}" --memory 2048 --vcpus=1 --os-variant=fedora25 --accelerate -v --disk path=/var/lib/libvirt/images/"${vm}".qcow2,size=20 -l /mnt/public/Support/SetupsBig/Linux/Fedora-Workstation-netinst-x86_64-27-1.6.iso  --initrd-inject=/mnt/public/Support/Platforms/Fedora/fc27x-ks.cfg --extra-args "ks=file:/fc27x-ks.cfg SERVERNAME=${vm} NOTIFYEMAIL=myemailhere@gmail.com" --debug --network type=direct,source=eno1

And to destroy that vm when I’m done with it:

vm=fc27x-02a; sudo virsh destroy "${vm}"; sudo virsh undefine --remove-all-storage "${vm}";

But this custom iso that we built is ready to be inserted into a vm, where you can manually select the xfce or the cinnamon option. After that initial menu choice, everything else is automatic and unattended.

Appendices</h1

Appendix A: Modify initrd.img file

Right after step “Copy in certificate file,” if you want to modify the initrd.img file, you can use these steps:

Open initrd.img xz file

mkdir -p /mnt/initrd1; cd /mnt/initrd1; time xzcat /mnt/originaliso/isolinux/initrd.img | cpio -d -i -m

Perform any file modifications to that filesystem in /mnt/initrd1.

Assemble new initrd.img file

cd /mnt/initrd1 ; time find . | cpio -o -H newc | xz --check=crc32 --x86 --lzma2=dict=512KiB > /mnt/newiso/isolinux/initrd.img

References

Weblinks

  1. https://serverfault.com/questions/549121/kickstart-installation-from-usb-kickstart-location#783512
  2. https://access.redhat.com/discussions/762253
  3. https://duckduckgo.com/?q=initrd+ks%3Dcdrom%3A&t=ffab&ia=qa
  4. https://serverfault.com/questions/549121/kickstart-installation-from-usb-kickstart-location
  5. http://www.smorgasbork.com/2012/01/04/building-a-custom-centos-6-kickstart-disc-part-3/
  6. https://unix.stackexchange.com/questions/90913/how-to-open-the-clonezilla-initrd-img
  7. https://tutel.me/c/unix/questions/391000/customized+iso+will+not+install+from+a+local+kickstart+on+the+installation+cd

Internal documents

~/2017/Systems/guides/Add custom kickstart to iso file.odt

Inject hostname into kickstart

The story

I have been learning how to automate my centos installations in my virtual environment. I’ve learned how to use the virsh command line to spin up a new vm the way I like, and to feed it a kickstart file. I also learned how to use kickstarts.

Set hostname automatically with a kickstart

In the main area of the kickstart file, include this line:

%include /tmp/network.ks

Include in your %pre section this section:

%pre
echo "network  --bootproto=dhcp --device=eth0 --ipv6=auto --activate --hostname renameme.ipa.example.com" > /tmp/network.ks
for x in $( cat /proc/cmdline );
do
   case $x in SERVERNAME*)
      eval $x
      echo "network  --bootproto=dhcp --device=eth0 --ipv6=auto --activate --hostname ${SERVERNAME}.ipa.example.com" > /tmp/network.ks
      ;;
   esac
done
%end

To paraphrase the post I’m duplicating for myself, you need the first echo redirection to the file in case there was no SERVERNAME= parameter given to the kernel.
When you boot, you need to include on the kernel command (usually the “linux” one), the value SERVERNAME=myhostname.

For my virsh command, that is:

vm=centos7-02a ; virt-install -n "${vm}" --memory 2048 --vcpus=1 --os-variant=rhel7.2 --accelerate -v --disk path=/var/lib/libvirt/images/"${vm}".qcow2,size=20 -l /mnt/public/Support/SetupsBig/CentOS-7-x86_64-Minimal-1511.iso  --initrd-inject=/mnt/public/Public/centos7-ks.cfg --extra-args "ks=file:/centos7-ks.cfg SERVERNAME=${vm}" --debug --network type=direct,source=eno1

References

  1. Install system-config-kickstart on Fedora 25 http://bytefreaks.net/gnulinux/fedora-25-workaround-to-install-system-config-kickstart
    sudo dnf install
    https://kojipkgs.fedoraproject.org/packages/system-config-date/1.10.9/3.fc25/noarch/system-config-date-1.10.9-3.fc25.noarch.rpm python-kickstart system-config-kickstart;
  2. https://sysadmin.compxtreme.ro/automatically-set-the-hostname-during-kickstart-installation/