Knowledge Base

Preserving for the future: Shell scripts, AoC, and more

My kickstart for Fedora 35 VMs

When I started this week's upgrades to my VM deployment logic, I had started with Fedora 36, but come to find out it's still in Beta. I had realized that the last time I worked on my Fedora vm installation task, it was last May and for version 34.

This is almost identical to my deployment of AlmaLinux 8, just for Fedora for which I include an Xfce desktop.

The kickstart file

# File: /mnt/public/Support/Platforms/Fedora/fc35x-ks.cfg
# Locations:
#    /mnt/public/Support/Platforms/Fedora/fc35x-ks.cfg
# Author: bgstack15
# Startdate: 2017-08-16
# Title: Kickstart for Fedora 35 xfce for ipa.internal.com
# Purpose: To provide an easy installation for VMs and other systems in the Internal 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-11-01 major revision to use local mirror
#    2017-11-04 converted for building directly into an iso file
#    2017-11-15 fedora 27
#    2018-05-05 fedora 28
#    2018-07-08 adjusted to use --network type=bridge,source=br0 instead of type=direct,source=eno1
#    2018-12-01 fedora 29
#    2019-05-05 fedora 30
#    2020-02-20 fedora 31
#    2020-05-05 fedora 32
#    2020-12-02 fedora 33
#    2021-05-04 fedora 34
#    2022-03-28 fedora 35
# Usage with virt-install:
#    vm=fc35x-01a ; time sudo virt-install -n "${vm}" --memory 2048 --vcpus=1 --os-variant=fedora32 --accelerate -v --disk path=/var/lib/libvirt/images/"${vm}".qcow2,size=30 -l /mnt/public/Support/SetupsBig/Linux/Fedora-Everything-netinst-x86_64-35-1.2.iso --initrd-inject=/mnt/public/Support/Platforms/Fedora/fc35x-ks.cfg --extra-args "inst.ks=file:/fc35x-ks.cfg SERVERNAME=${vm} NOTIFYEMAIL=bgstack15@gmail.com" --debug --network type=bridge,source=br0 --noautoconsole
#    vm=fc35x-01a; 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 --vckeymap=us --xlayouts=''
# Root password
rootpw --plaintext plaintextexamplepw
# my user
user --groups=wheel --name=bgstack15-local --password=$6$.gh9u7vg2HDJPPX/scrubbedpasswdentrygoeshere --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="https://www.example.com/mirror/fedora/linux/releases/35/Everything/x86_64/os/"

# Use text mode install
text
# SELinux configuration
selinux --enforcing
# Prepare X to run at boot
xconfig --startxonboot

# Use all local repositories
# Online repos
repo --name=internalrpm --baseurl=https://www.example.com/internal/repo/rpm/
repo --name=fedora --baseurl=https://www.example.com/mirror/fedora/linux/releases/$releasever/Everything/$basearch/os/
repo --name=updates --baseurl=https://www.example.com/mirror/fedora/linux/updates/$releasever/Everything/$basearch/
repo --name=rpmfusion-free --baseurl=https://www.example.com/mirror/rpmfusion/free/fedora/releases/$releasever/Everything/$basearch/os/
repo --name=rpmfusion-free-updates --baseurl=https://www.example.com/mirror/rpmfusion/free/fedora/updates/$releasever/$basearch/
repo --name=copr-bgstack15-stackrpms --baseurl=https://www.example.com/mirror/copr-bgstack15-stackrpms/fedora-$releasever-$basearch/
repo --name=copr-bgstack15-aftermozilla --baseurl=https://download.copr.fedorainfracloud.org/results/bgstack15/AfterMozilla/fedora-$releasever-$basearch/

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.internal.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.internal.com" > /tmp/network.ks
         ;;
      NOTIFYEMAIL*)
         eval $x
         echo "${NOTIFYEMAIL}" > /mnt/sysroot/root/notifyemail.txt
     ;;
   esac
done
cp -p /run/install/repo/ca-ipa.internal.com.crt /etc/pki/ca-trust/source/anchors/ 2>/dev/null || :
wget http://www.example.com/internal/certs/ca-ipa.internal.com.crt -O /etc/pki/ca-trust/source/anchors/ca-ipa.internal-wget.com.crt || :
update-ca-trust || :
%end

%post
{
   set -x
   # Set temporary hostname
   #hostnamectl set-hostname renameme.ipa.internal.com;

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

   # Get local mirror repositories
   wget https://www.example.com/internal/repo/rpm/set-my-repos.sh --output-document /usr/local/sbin/set-my-repos.sh ; chmod +x /usr/local/sbin/set-my-scripts.sh ; sh -x /usr/local/sbin/set-my-repos.sh

   #dnf -y remove dnfdragora ;
   #dnf clean all ;
   #dnf update -y ;

   # Remove graphical boot and add serial console
   sed -i -r -e '/^GRUB_CMDLINE_LINUX=/{s/(\s*)(rhgb|quiet)\s*/\1/g;};' -e '/^GRUB_CMDLINE_LINUX=/{s/(\s*)\"$/ console=ttyS0 console=tty1\"/;}' /etc/default/grub
   grub2-mkconfig > /boot/grub2/grub.cfg

   systemctl enable sendmail.service && systemctl start sendmail.service
   # 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" )";
   } | $( find /usr/share/bgscripts/send.sh /usr/bin/send 2>/dev/null | head -n1 ) -f "root@$( hostname --fqdn )" \
      -h -s "${SERVER} is ${thisip}" $( cat /root/notifyemail.txt 2>/dev/null )

   # Ensure boot to runlevel 5
   systemctl set-default graphical.target

   # 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"
   tf=/etc/cron.d/01_init.cron
   touch "${tf}" ; chown root.root "${tf}" ; chmod 0600 "${tf}"
   cat <<-"EOFCRON" 1>"${tf}"
@reboot         root    su bgstack15-local -c "sudo /usr/bin/bgconf.py" 1>/root/clone.log 2>&1 ; rm -f /etc/cron.d/01_init.cron 1>/dev/null 2>&1 ; systemctl restart lightdm 1>/dev/null 2>&1 ;
EOFCRON

} 2>&1 | tee -a /root/install.log
%end

%packages
@core
@^xfce-desktop-environment
@xfce-apps
@xfce-media
autossh
bc
bgconf
bgscripts
bgscripts-core
bind-utils
cifs-utils
cryptsetup
-dnfdragora
-dnfdragora-updater
dosfstools
expect
-firefox
firewalld
freeipa-client
git
-hplip
iotop
lightdm-gtk
librewolf
locale-en_BS
mailx
man
mlocate
newmoon
net-tools
nfs-utils
numix-icon-theme-circle
p7zip
parted
python3-policycoreutils
qemu-guest-agent
rpm-build
rsync
scite
screen
sendmail
spice-vdagent
strace
sysstat
tcpdump
telnet
-thunderbird
vim
vlc
wget
xdg-themes-stackrpms
xfce4-whiskermenu-plugin
-gstreamer1-plugins-ugly*
%end

The narrative

This time, I had to troubleshoot my %post section many times until I learned that the yum commands were causing the disk to "remain online" which somehow causes a dbus error and prevents the OS installation from continuing (installing the bootloader, at least). I don't understand how a %post can happen before other things, but I haven't read the specs in a while.

One thing I am very appreciative of is that if my package list contains an unresolvable package, the installer will ask if I want to continue with that entry removed. I still needed to fix it, which in this case was the LibreWolf package available from my AfterMozilla copr and not my main one. I suppose I will need to mirror that copr locally too.

I now of course, use LibreWolf instead of Firefox. I also am now using my own custom locale-en_US glibc locale.

set-my-repos.sh

Set my repos has been improved to work out of the box on Fedora, CentOS 7, and AlmaLinux 8.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#!/bin/sh
# File: /mnt/public/www/internal/repo/rpm/set-my-repos.sh
# Location:
# Author: bgstack15
# Startdate: 2019-08-10 16:02
# Title: Script that Establishes the repos needed for GNU/Linux
# Purpose: Set up the 3 repos I always need on devuan clients
# History:
#     2019-09-24 forked from devuan set-my-repos.
#     2022-03-18 changed from C8 to A8, changed if-then line #44 to not use ! and instead use : else
#     2022-03-28 adapted to work with Fedora, C7, or A8
# Usage:
#    sudo set-my-repos.sh
# Reference:
#    /mnt/public/Support/Platforms/devuan/devuan.txt
# Improve:
# Documentation:

ALLREPOSGLOB="/etc/yum.repos.d/*.repo"
REPOSBASE="/etc/yum.repos.d"

# confirm key
confirm_key() {
   # call: confirm_key "${SEARCHPHRASE}" "${URL_OF_KEY}"
   ___ck_repo="${1}"
   ___ck_sp="${2}"
   ___ck_url="${3}"
   if rpm -q gpg-pubkey --qf '%{NAME}-%{VERSION}-%{RELEASE}\t%{SUMMARY}\n' 2>/dev/null | grep -qe "${___ck_sp}" ;
   then
      :
   else
      # not found so please add it
      echo "Adding key for ${___ck_repo}" 1>&2
      wget -O- "${___ck_url}" | sudo rpm --import -
   fi
}

# confirm repo
confirm_repo_byurl() {
   # call: confirm_repo "${REPO_FILENAME}" "${REPO_FILE_URL}" "${SEARCHGLOB}"
   ___cr_repo="${1}"
   ___cr_url="${2}"
   ___cr_sf="${3}"
   # if we cannot find a file matching the requested name in the glob
   if ! grep -q -F -e "${___cr_repo}" ${ALLREPOSGLOB} 2>/dev/null ;
   then
   #   :
   #else
      # not found so please download it
      echo "Adding repo ${___cr_repo}" 1>&2
      wget -O- "${___cr_url}" --quiet >> "${REPOSBASE}/${___cr_sf}"
   fi
}

# MAIN
distro="$( . /etc/os-release ; echo "${ID}${VERSION_ID%%.*}" )"
# calculate copr repo filename
copr_d=fedora
grep -qiE 'ID=.*(almalinux|centos|redhat)' /etc/os-release && copr_d=epel
copr_v="$( . /etc/os-release ; echo "${VERSION_ID%%.*}" )"

# REPO 1: internal bundle
bundle_name="[baseos-internal]"
grep -qiE 'ID=.*(fedora)' /etc/os-release && bundle_name="[fedora-internal]"
confirm_repo_byurl "${bundle_name}" "https://www.example.com/internal/repo/mirror/internal-bundle-${distro}.repo" "internal-bundle-${distro}.repo"
# It is a good idea to run this too.
grep -oP "(?<=^\[).*(?=-internal])" /etc/yum.repos.d/internal-bundle-${distro}.repo | while read thisrepo; do yum-config-manager --disable "${thisrepo}"; dnf config-manager --disable "${thisrepo}" ; done

# REPO 2: local internalrpm
confirm_repo_byurl "[internalrpm]" "https://www.example.com/internal/repo/rpm/internalrpm.repo" "internalrpm.repo"
wget --continue "https://www.example.com/internal/repo/rpm/internalrpm.mirrorlist" --output-document "${REPOSBASE}/internalrpm.mirrorlist" --quiet

# REPO 3: copr
# yum will download key and ask for confirmation during first use.
confirm_repo_byurl "[copr:copr.fedorainfracloud.org:bgstack15:stackrpms]" "https://www.example.com/internal/repo/mirror/bgstack15-stackrpms-${copr_d}-${copr_v}.repo" "bgstack15-stackrpms-${copr_d}-${copr_v}.repo"

And the internal-bundle-fedora35.repo file:

# internal-bundle-fedora35.repo
# Install with:
# distro=fedora35 ; sudo wget https://www.example.com/internal/repo/mirror/internal-bundle-${distro}.repo -O /etc/yum.repos.d/internal-bundle-${distro}.repo && grep -oP "(?<=^\[).*(?=-internal])" /etc/yum.repos.d/internal-bundle-${distro}.repo | while read thisrepo; do sudo dnf config-manager --set-disabled "${thisrepo}"; done ; sudo wget https://www.example.com/internal/repo/mirror/RPM-GPG-KEY-rpmfusion-free-fedora-35 -O /etc/pki/rpm-gpg/RPM-GPG-KEY-rpmfusion-free-fedora-35

[fedora-internal]
name=Fedora $releasever - $basearch internal
#metalink=https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch
#baseurl=http://download.fedoraproject.org/pub/fedora/linux/releases/$releasever/Everything/$basearch/os/
baseurl=http://www.example.com/mirror/fedora/linux/releases/$releasever/Everything/$basearch/os/
enabled=1
metadata_expire=7d
repo_gpgcheck=0
type=rpm
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch
skip_if_unavailable=False

[updates-internal]
name=Fedora $releasever - $basearch - Updates internal
failovermethod=priority
#metalink=https://mirrors.fedoraproject.org/metalink?repo=updates-released-f$releasever&arch=$basearch
#baseurl=http://download.fedoraproject.org/pub/fedora/linux/updates/$releasever/Everything/$basearch/
baseurl=http://www.example.com/mirror/fedora/linux/updates/$releasever/Everything/$basearch/
enabled=1
repo_gpgcheck=0
type=rpm
gpgcheck=1
metadata_expire=6h
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-fedora-$releasever-$basearch
skip_if_unavailable=False

[rpmfusion-free-internal]
name=RPM Fusion for Fedora $releasever - Free internal
#metalink=https://mirrors.rpmfusion.org/metalink?repo=free-fedora-$releasever&arch=$basearch
#baseurl=http://download1.rpmfusion.org/free/fedora/releases/$releasever/Everything/$basearch/os/
baseurl=http://www.example.com/mirror/rpmfusion/free/fedora/releases/$releasever/Everything/$basearch/os/
enabled=1
metadata_expire=14d
type=rpm-md
gpgcheck=1
repo_gpgcheck=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rpmfusion-free-fedora-$releasever

[rpmfusion-free-updates-internal]
name=RPM Fusion for Fedora $releasever - Free - Updates internal
#metalink=https://mirrors.rpmfusion.org/metalink?repo=free-fedora-updates-released-$releasever&arch=$basearch
#baseurl=http://download1.rpmfusion.org/free/fedora/updates/$releasever/$basearch/
baseurl=http://www.example.com/mirror/rpmfusion/free/fedora/updates/$releasever/$basearch/
enabled=1
type=rpm-md
gpgcheck=1
repo_gpgcheck=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rpmfusion-free-fedora-$releasever

Comments