Add initial meta-stx to support StarlingX build
[pti/rtp.git] / meta-stx / conf / distro / files / ks / net_smallsystem_lowlatency_ks.cfg
diff --git a/meta-stx/conf/distro/files/ks/net_smallsystem_lowlatency_ks.cfg b/meta-stx/conf/distro/files/ks/net_smallsystem_lowlatency_ks.cfg
new file mode 100644 (file)
index 0000000..8b136a8
--- /dev/null
@@ -0,0 +1,1120 @@
+#
+# Copyright (c) 2019 Wind River Systems, Inc.
+# SPDX-License-Identifier: Apache-2.0
+#
+
+%pre
+# This file defines functions that can be used in %pre and %post kickstart sections, by including:
+# . /tmp/ks-functions.sh
+#
+
+cat <<END_FUNCTIONS >/tmp/ks-functions.sh
+#
+# Copyright (c) 2019 Wind River Systems, Inc.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+function get_by_path()
+{
+    local disk=\$(cd /dev ; readlink -f \$1)
+    for p in /dev/disk/by-path/*; do
+        if [ "\$disk" = "\$(readlink -f \$p)" ]; then
+            echo \$p
+            return
+        fi
+    done
+}
+
+function get_disk()
+{
+    echo \$(cd /dev ; readlink -f \$1)
+}
+
+function report_pre_failure_with_msg()
+{
+    local msg=\$1
+    echo -e '\n\nInstallation failed.\n'
+    echo "\$msg"
+
+    exit 1
+}
+
+function report_post_failure_with_msg()
+{
+    local msg=\$1
+    cat <<EOF >> /etc/motd
+
+Installation failed.
+\$msg
+
+EOF
+    echo "\$msg" >/etc/platform/installation_failed
+
+    echo -e '\n\nInstallation failed.\n'
+    echo "\$msg"
+
+    exit 1
+}
+
+function report_post_failure_with_logfile()
+{
+    local logfile=\$1
+    cat <<EOF >> /etc/motd
+
+Installation failed.
+Please see \$logfile for details of failure
+
+EOF
+    echo \$logfile >/etc/platform/installation_failed
+
+    echo -e '\n\nInstallation failed.\n'
+    cat \$logfile
+
+    exit 1
+}
+
+function get_http_port()
+{
+    echo \$(cat /proc/cmdline |xargs -n1 echo |grep '^inst.repo=' | sed -r 's#^[^/]*://[^/]*:([0-9]*)/.*#\1#')
+}
+
+END_FUNCTIONS
+
+%end
+
+%post
+# This file defines functions that can be used in %pre and %post kickstart sections, by including:
+# . /tmp/ks-functions.sh
+#
+
+cat <<END_FUNCTIONS >/tmp/ks-functions.sh
+#
+# Copyright (c) 2019 Wind River Systems, Inc.
+#
+# SPDX-License-Identifier: Apache-2.0
+#
+
+function get_by_path()
+{
+    local disk=\$(cd /dev ; readlink -f \$1)
+    for p in /dev/disk/by-path/*; do
+        if [ "\$disk" = "\$(readlink -f \$p)" ]; then
+            echo \$p
+            return
+        fi
+    done
+}
+
+function get_disk()
+{
+    echo \$(cd /dev ; readlink -f \$1)
+}
+
+function report_pre_failure_with_msg()
+{
+    local msg=\$1
+    echo -e '\n\nInstallation failed.\n'
+    echo "\$msg"
+
+    exit 1
+}
+
+function report_post_failure_with_msg()
+{
+    local msg=\$1
+    cat <<EOF >> /etc/motd
+
+Installation failed.
+\$msg
+
+EOF
+    echo "\$msg" >/etc/platform/installation_failed
+
+    echo -e '\n\nInstallation failed.\n'
+    echo "\$msg"
+
+    exit 1
+}
+
+function report_post_failure_with_logfile()
+{
+    local logfile=\$1
+    cat <<EOF >> /etc/motd
+
+Installation failed.
+Please see \$logfile for details of failure
+
+EOF
+    echo \$logfile >/etc/platform/installation_failed
+
+    echo -e '\n\nInstallation failed.\n'
+    cat \$logfile
+
+    exit 1
+}
+
+function get_http_port()
+{
+    echo \$(cat /proc/cmdline |xargs -n1 echo |grep '^inst.repo=' | sed -r 's#^[^/]*://[^/]*:([0-9]*)/.*#\1#')
+}
+
+END_FUNCTIONS
+
+%end
+
+
+# Template from: pre_common_head.cfg
+%pre --erroronfail
+
+# Source common functions
+. /tmp/ks-functions.sh
+
+# First, parse /proc/cmdline to find the boot args
+set -- `cat /proc/cmdline`
+for I in $*; do case "$I" in *=*) eval $I 2>/dev/null;; esac; done
+
+append=
+if [ -n "$console" ] ; then
+    append="console=$console"
+fi
+
+if [ -n "$security_profile" ]; then
+    append="$append security_profile=$security_profile"
+fi
+
+#### SECURITY PROFILE HANDLING (Pre Installation) ####
+if [ -n "$security_profile" ] && [ "$security_profile" == "extended" ]; then
+    # IMA specific boot options:
+    # Enable Kernel auditing
+    append="$append audit=1"
+else
+    # we need to blacklist the IMA and Integrity Modules
+    # on standard security profile
+    append="$append module_blacklist=integrity,ima"
+    
+    # Disable Kernel auditing in Standard Security Profile mode
+    append="$append audit=0"
+fi
+
+if [ -n "$tboot" ]; then
+    append="$append tboot=$tboot"
+else
+    append="$append tboot=false"
+fi
+
+boot_device_arg=
+if [ -n "$boot_device" ] ; then
+    boot_device_arg="--boot-drive=$(get_by_path $boot_device)"
+fi
+
+echo "bootloader --location=mbr $boot_device_arg --timeout=5 --append=\"$append\"" > /tmp/bootloader-include
+
+echo "timezone --nontp --utc UTC" >/tmp/timezone-include
+%end
+
+#version=DEVEL
+install
+lang en_US.UTF-8
+keyboard us
+%include /tmp/timezone-include
+# set to 'x' so we can use shadow password
+rootpw  --iscrypted x
+selinux --disabled
+authconfig --enableshadow --passalgo=sha512
+firewall --service=ssh
+
+# The following is the partition information you requested
+# Note that any partitions you deleted are not expressed
+# here so unless you clear all partitions first, this is
+# not guaranteed to work
+zerombr
+
+# Disk layout from %pre
+%include /tmp/part-include
+# Bootloader parms from %pre
+%include /tmp/bootloader-include
+
+reboot --eject
+
+
+# Template from: pre_net_common.cfg
+%pre
+
+# Setup ntp.conf and sync time
+cat <<EOF >/etc/ntp_kickstart.conf
+server pxecontroller
+EOF
+
+/usr/sbin/ntpd -g -q -n -c /etc/ntp_kickstart.conf
+if [ $? -eq 0 ]; then
+    /sbin/hwclock --systohc --utc
+fi
+
+%end
+
+
+# Template from: pre_pkglist_lowlatency.cfg
+%packages
+@core
+@base
+-kernel-module-igb-uio
+-kernel-module-wrs-avp
+-kernel
+-kernel-tools
+-kernel-tools-libs
+-kmod-drbd
+-kmod-e1000e
+-kmod-i40e
+-kmod-ixgbe
+-kmod-tpm
+-mlnx-ofa_kernel
+-mlnx-ofa_kernel-rt
+-mlnx-ofa_kernel-modules
+-qat16
+@platform-controller-worker-lowlatency
+@updates-controller-worker-lowlatency
+%end
+
+
+# Template from: pre_disk_setup_common.cfg
+%pre --erroronfail
+
+# Source common functions
+. /tmp/ks-functions.sh
+
+# This is a really fancy way of finding the first usable disk for the
+# install and not stomping on the USB device if it comes up first
+
+# First, parse /proc/cmdline to find the boot args
+set -- `cat /proc/cmdline`
+for I in $*; do case "$I" in *=*) eval $I 2>/dev/null;; esac; done
+
+# Find either the ISO or USB device first chopping off partition
+ISO_DEV=`readlink /dev/disk/by-label/oe_iso_boot`
+sdev=`echo $ISO_DEV | sed -e 's/.$//'`
+if [ -e /dev/disk/by-label/$sdev ] ; then
+    ISO_DEV=$sdev
+fi
+USB_DEV=`readlink /dev/disk/by-label/wr_usb_boot`
+sdev=`echo $USB_DEV | sed -e 's/.$//'`
+if [ -e /dev/disk/by-label/$sdev ] ; then
+    USB_DEV=$sdev
+fi
+
+# Temporary, until lab pxelinux.cfg files are updated to specify install devices
+if [ -z "$rootfs_device" -o -z "$boot_device" ]
+then
+    INST_HDD=""
+    # Prefer a vd* device if this is kvm/qemu
+    for e in vda vdb sda sdb nvme0n1; do
+        if [ -e /dev/$e -a "$ISO_DEV" != "../../$e" -a "$USB_DEV" != "../../$e" ] ; then
+            INST_HDD=$e
+            break
+        fi
+    done
+
+    # Set variables to $INST_HDD if not set
+    rootfs_device=${rootfs_device:-$INST_HDD}
+    boot_device=${boot_device:-$INST_HDD}
+fi
+
+# Convert to by-path
+orig_rootfs_device=$rootfs_device
+rootfs_device=$(get_by_path $rootfs_device)
+
+orig_boot_device=$boot_device
+boot_device=$(get_by_path $boot_device)
+
+if [ ! -e "$rootfs_device" -o ! -e "$boot_device" ] ; then
+    # Touch this file to prevent Anaconda from dying an ungraceful death
+    touch /tmp/part-include
+
+    report_pre_failure_with_msg "ERROR: Specified installation ($orig_rootfs_device) or boot ($orig_boot_device) device is invalid."
+fi
+
+# Ensure specified device is not a USB drive
+udevadm info --query=property --name=$rootfs_device |grep -q '^ID_BUS=usb' || \
+    udevadm info --query=property --name=$boot_device |grep -q '^ID_BUS=usb'
+if [ $? -eq 0 ]; then
+    # Touch this file to prevent Anaconda from dying an ungraceful death
+    touch /tmp/part-include
+
+    report_pre_failure_with_msg "ERROR: Specified installation ($orig_rootfs_device) or boot ($orig_boot_device) device is a USB drive."
+fi
+
+# Deactivate existing volume groups to avoid Anaconda issues with pre-existing groups
+vgs --noheadings -o vg_name | xargs --no-run-if-empty -n 1 vgchange -an
+
+# Remove volumes and group for cgts-vg, if any
+lvremove --force cgts-vg
+pvs --select 'vg_name=cgts-vg' --noheadings -o pv_name | xargs --no-run-if-empty pvremove --force --force --yes
+vgs --select 'vg_name=cgts-vg' --noheadings -o vg_name | xargs --no-run-if-empty vgremove --force
+
+ONLYUSE_HDD=""
+if [ "$(curl -sf http://pxecontroller:6385/v1/upgrade/$(hostname)/in_upgrade 2>/dev/null)" = "true" ]; then
+    # In an upgrade, only wipe the disk with the rootfs and boot partition
+    echo "In upgrade, wiping only $rootfs_device"
+    WIPE_HDD="$(get_disk $rootfs_device)"
+    ONLYUSE_HDD="$(basename $(get_disk $rootfs_device))"
+    if [ "$(get_disk $rootfs_device)" != "$(get_disk $boot_device)" ]; then
+        WIPE_HDD="$WIPE_HDD,$(get_disk $boot_device)"
+        ONLYUSE_HDD="$ONLYUSE_HDD,$(basename $(get_disk $boot_device))"
+    fi
+else
+    # Make a list of all the hard drives that are to be wiped
+    WIPE_HDD=""
+    # Partition type OSD has a unique globally identifier
+    part_type_guid_str="Partition GUID code"
+    CEPH_OSD_GUID="4FBD7E29-9D25-41B8-AFD0-062C0CEFF05D"
+
+    # Check if we wipe OSDs
+    if [ "$(curl -sf http://pxecontroller:6385/v1/ihosts/wipe_osds 2>/dev/null)" = "true" ]; then
+        echo "Wipe OSD data."
+        WIPE_CEPH_OSDS="true"
+    else
+        echo "Skip Ceph OSD data wipe."
+        WIPE_CEPH_OSDS="false"
+    fi
+
+    for f in /dev/disk/by-path/*
+    do
+        dev=$(readlink -f $f)
+        lsblk --nodeps --pairs $dev | grep -q 'TYPE="disk"'
+        if [ $? -ne 0 ]
+        then
+            continue
+        fi
+
+        # Avoid wiping USB drives
+        udevadm info --query=property --name=$dev |grep -q '^ID_BUS=usb' && continue
+
+        # Avoid wiping ceph osds if sysinv tells us so
+        if [ ${WIPE_CEPH_OSDS} == "false" ]; then
+            wipe_dev="true"
+            part_numbers=( `parted -s $dev print | awk '$1 == "Number" {i=1; next}; i {print $1}'` )
+            # Scanning the partitions looking for CEPH OSDs and
+            # skipping any disk found with such partitions
+            for part_number in "${part_numbers[@]}"; do
+                sgdisk_part_info=$(flock $dev sgdisk -i $part_number $dev)
+                part_type_guid=$(echo "$sgdisk_part_info" | grep "$part_type_guid_str" | awk '{print $4;}')
+                if [ "$part_type_guid" == $CEPH_OSD_GUID ]; then
+                    echo "OSD found on $dev, skipping wipe"
+                    wipe_dev="false"
+                    break
+                fi
+            done
+            if [ "$wipe_dev" == "false" ]; then
+                continue
+            fi
+        fi
+
+        # Add device to the wipe list
+        devname=$(basename $dev)
+        if [ -e $dev -a "$ISO_DEV" != "../../$devname" -a "$USB_DEV" != "../../$devname" ]; then
+            if [ -n "$WIPE_HDD" ]; then
+                WIPE_HDD=$WIPE_HDD,$dev
+            else
+                WIPE_HDD=$dev
+            fi
+        fi
+    done
+    echo "Not in upgrade, wiping disks: $WIPE_HDD"
+fi
+
+for dev in ${WIPE_HDD//,/ }
+do
+    # Clearing previous GPT tables or LVM data
+    # Delete the first few bytes at the start and end of the partition. This is required with
+    # GPT partitions, they save partition info at the start and the end of the block.
+    # Do this for each partition on the disk, as well.
+    partitions=$(lsblk -rip $dev -o TYPE,NAME |awk '$1 == "part" {print $2}')
+    for p in $partitions $dev
+    do
+        echo "Pre-wiping $p from kickstart"
+        dd if=/dev/zero of=$p bs=512 count=34
+        dd if=/dev/zero of=$p bs=512 count=34 seek=$((`blockdev --getsz $p` - 34))
+    done
+done
+
+# Check for remaining cgts-vg PVs, which could potentially happen
+# in an upgrade where we're not wiping all disks.
+# If we ever create other volume groups from kickstart in the future,
+# include them in this search as well.
+partitions=$(pvs --select 'vg_name=cgts-vg' -o pv_name --noheading | grep -v '\[unknown\]')
+for p in $partitions
+do
+    echo "Pre-wiping $p from kickstart (cgts-vg present)"
+    dd if=/dev/zero of=$p bs=512 count=34
+    dd if=/dev/zero of=$p bs=512 count=34 seek=$((`blockdev --getsz $p` - 34))
+done
+
+let -i gb=1024*1024*1024
+
+cat<<EOF>/tmp/part-include
+clearpart --all --drives=$WIPE_HDD --initlabel
+EOF
+
+if [ -n "$ONLYUSE_HDD" ]; then
+    cat<<EOF>>/tmp/part-include
+ignoredisk --only-use=$ONLYUSE_HDD
+EOF
+fi
+
+if [ -d /sys/firmware/efi ] ; then
+    cat<<EOF>>/tmp/part-include
+part /boot/efi --fstype=efi --size=300 --ondrive=$(get_disk $boot_device)
+EOF
+else
+    cat<<EOF>>/tmp/part-include
+part biosboot --asprimary --fstype=biosboot --size=1 --ondrive=$(get_disk $boot_device)
+EOF
+fi
+
+
+# Template from: pre_disk_aio.cfg
+
+## NOTE: updates to partition sizes need to be also reflected in
+##  - stx-config/.../sysinv/conductor/manager.py:create_controller_filesystems()
+##  - stx-config/.../sysinv/common/constants.py
+##
+## NOTE: When adding partitions, we currently have a max of 4 primary partitions.
+##       If more than 4 partitions are required, we can use a max of 3 --asprimary,
+##       to allow 1 primary logical partition with extended partitions
+##
+## NOTE: Max default PV size must align with the default controllerfs sizes
+##
+## BACKUP_OVERHEAD = 20
+##
+## Physical install (for disks over 240GB)
+##  - DB size is doubled to allow for upgrades
+##
+## DEFAULT_IMAGE_STOR_SIZE = 10
+## DEFAULT_DATABASE_STOR_SIZE = 20
+## DEFAULT_IMG_CONVERSION_STOR_SIZE = 20
+## BACKUP = DEFAULT_DATABASE_STOR_SIZE + DEFAULT_IMAGE_STOR_SIZE
+##                                     + BACKUP_OVERHEAD = 50
+## LOG_VOL_SIZE = 8192
+## SCRATCH_VOL_SIZE = 8192
+## RABBIT = 2048
+## PLATFORM = 2048
+## ANCHOR = 1024
+## EXTENSION = 1024
+## GNOCCHI = 5120
+## DOCKER = 30720
+## DOCKER_DIST = 16384
+## ETCD = 5120
+## CEPH_MON = 20480
+## KUBELET_VOL_SIZE = 10240
+## RESERVED_PE = 16 (based on pesize=32768)
+##
+## CGCS_PV_SIZE = 10240 + 2*20480 + 20480 + 51200 + 8196 + 8196 + 2048 +
+##                2048 + 1024 + 1024 + 5120 + 30720 + 16384 + 5120 +
+##                20480 + 10240 + 16 = 233496
+##
+## small install - (for disks below 240GB)
+##  - DB size is doubled to allow for upgrades
+##
+## DEFAULT_SMALL_IMAGE_STOR_SIZE = 10
+## DEFAULT_SMALL_DATABASE_STOR_SIZE = 10
+## DEFAULT_SMALL_IMG_CONVERSION_STOR_SIZE = 10
+## DEFAULT_SMALL_BACKUP_STOR_SIZE = 40
+##
+## LOG_VOL_SIZE = 8192
+## SCRATCH_VOL_SIZE = 8192
+## RABBIT = 2048
+## PLATFORM = 2048
+## ANCHOR = 1024
+## EXTENSION = 1024
+## GNOCCHI = 5120
+## DOCKER = 30720
+## DOCKER_DIST = 16384
+## ETCD = 5120
+## CEPH_MON = 20480
+## KUBELET_VOL_SIZE = 10240
+## RESERVED_PE = 16 (based on pesize=32768)
+##
+##
+## CGCS_PV_SIZE = 10240 + 2*10240 + 10240 + 40960 + 8192 + 8192 + 2048 +
+##                2048 + 1024 + 1024 + 5120 + 30720 + 16384 + 5120 +
+##                20480 + 10240 + 16 = 192528
+##
+## NOTE: To maintain upgrade compatability within the volume group, keep the
+## undersized LOG_VOL_SIZE and SCRATCH_VOL_SIZE, but size the minimally size
+## physical volume correctly.
+##
+##  R4 AIO installations:
+##  - R4 (case #1): /boot (0.5G), / (20G),
+##                  cgts-vg PV (239G), /local_pv (239G)
+##  - R4 (case #2): /boot (0.5G), / (20G),
+##                  cgts-vg PV (239G), cgts-vg (239G)
+##
+##  Upgrade migration will start with R5 install and create a partition to align
+##  above so filesystems within the volume group will be able to maintain their
+##  sizes in R5
+##    - R5 install  : /boot (0.5G), / (20G),
+##                    cgts-vg PV (142G), un-partitioned (336G)
+##    - R5 (case #1): /boot (0.5G), / (20G),
+##                    cgts-vg PV (142G), cgts-vg PV (97G), unpartitioned (239G)
+##    - R5 (case #2): /boot (0.5G), / (20G),
+##                    cgts-vg PV (142G), cgts-vg PV (336G)
+##
+
+sz=$(blockdev --getsize64 $(get_disk $rootfs_device))
+if [ $sz -le $((240*$gb)) ] ; then
+    # Round CGCS_PV_SIZE to the closest upper value that can be divided by 1024.
+    # 192528/1024=188.01. CGCS_PV_SIZE=189*1024=193536. Using a disk with a
+    # size under 189GiB will fail.
+    CGCS_PV_SIZE=193536
+else
+    # Round CGCS_PV_SIZE to the closest upper value that can be divided by 1024.
+    # 233496/1024=228.02. CGCS_PV_SIZE=229*1024=234496.
+    CGCS_PV_SIZE=234496
+fi
+
+ROOTFS_SIZE=20000
+LOG_VOL_SIZE=8000
+SCRATCH_VOL_SIZE=8000
+
+ROOTFS_OPTIONS="defaults"
+profile_mode=`cat /proc/cmdline |xargs -n1 echo |grep security_profile= | grep extended`
+if [ -n "$profile_mode" ]; then
+   # Enable iversion labelling for rootfs when IMA is enabled
+   ROOTFS_OPTIONS="${ROOTFS_OPTIONS},iversion"
+fi
+
+cat<<EOF>>/tmp/part-include
+part /boot --fstype=ext4 --asprimary --size=500 --ondrive=$(get_disk $rootfs_device) --fsoptions="$ROOTFS_OPTIONS"
+part pv.253004 --grow --size=500 --maxsize=$CGCS_PV_SIZE --ondrive=$(get_disk $rootfs_device)
+volgroup cgts-vg --pesize=32768 pv.253004
+logvol /var/log --fstype=ext4 --vgname=cgts-vg --size=$LOG_VOL_SIZE --name=log-lv
+logvol /scratch --fstype=ext4 --vgname=cgts-vg --size=$SCRATCH_VOL_SIZE --name=scratch-lv
+part / --fstype=ext4 --asprimary --size=$ROOTFS_SIZE --ondrive=$(get_disk $rootfs_device) --fsoptions="$ROOTFS_OPTIONS"
+EOF
+
+%end
+
+
+# Template from: post_platform_conf_aio_lowlatency.cfg
+%post --erroronfail
+
+# Source common functions
+. /tmp/ks-functions.sh
+
+# Set the security profile mode
+secprofile="standard"
+profile_mode=`cat /proc/cmdline |xargs -n1 echo |grep security_profile= | grep extended`
+if [ -n "$profile_mode" ]; then
+   secprofile="extended"
+fi
+
+mkdir -p -m 0775 /etc/platform
+cat <<EOF > /etc/platform/platform.conf
+nodetype=controller
+subfunction=controller,worker,lowlatency
+system_type=All-in-one
+security_profile=$secprofile
+EOF
+
+%end
+
+
+# Template from: post_common.cfg
+%post --erroronfail
+
+# Source common functions
+. /tmp/ks-functions.sh
+
+# Turn off locale support for i18n if is not installed
+if [ ! -d /usr/share/i18n ] ; then
+   rm -f /etc/sysconfig/i18n
+fi
+# Unset the hostname
+rm /etc/hostname
+
+# If using a serial install make sure to add a getty on the tty1
+conarg=`cat /proc/cmdline |xargs -n1 echo |grep console= |grep ttyS`
+if [ -n "$conarg" ] ; then
+   echo "1:2345:respawn:/sbin/mingetty tty1" >> /etc/inittab
+fi
+
+#### SECURITY PROFILE HANDLING (Post Installation) ####
+# Check if the Security profile mode is enabled
+# and load the appropriate kernel modules
+secprofile=`cat /proc/cmdline |xargs -n1 echo |grep security_profile= | grep extended`
+if [ -n "$secprofile" ]; then
+   echo "In Extended Security profile mode. Loading IMA kernel module"
+   systemctl enable auditd.service
+   # Add the securityfs mount for the IMA Runtime measurement list
+   echo "securityfs     /sys/kernel/security    securityfs    defaults,nodev 0 0" >> /etc/fstab
+else
+   # Disable audit daemon in the Standard Security Profile
+   systemctl disable auditd
+fi
+
+. /etc/platform/platform.conf
+# Configure smart package manager channels
+rm -rf /var/lib/smart
+mkdir /var/lib/smart
+/usr/bin/smart channel -y \
+    --add rpmdb type=rpm-sys name="RPM Database"
+/usr/bin/smart channel -y \
+    --add base type=rpm-md name="Base" baseurl=http://controller:${http_port:-8080}/feed/rel-19.12
+/usr/bin/smart channel -y \
+    --add updates type=rpm-md name="Patches" baseurl=http://controller:${http_port:-8080}/updates/rel-19.12
+
+# Configure smart to use rpm --nolinktos option
+/usr/bin/smart config --set rpm-nolinktos=true
+
+# Configure smart to use rpm --nosignature option
+/usr/bin/smart config --set rpm-check-signatures=false
+
+# Delete the CentOS yum repo files
+rm -f /etc/yum.repos.d/CentOS-*
+
+# Persist the boot device naming as UDEV rules so that if the network device
+# order changes post-install that we will still be able to DHCP from the
+# correct interface to reach the active controller.  For most nodes only the
+# management/boot interface needs to be persisted but because we require both
+# controllers to be identically configured and controller-0 and controller-1
+# are installed differently (e.g., controller-0 from USB and controller-1 from
+# network) it is not possible to know which interface to persist for
+# controller-0.  The simplest solution is to persist all interfaces.
+#
+mkdir -p /etc/udev/rules.d
+echo "# Persisted network interfaces from anaconda installer" > /etc/udev/rules.d/70-persistent-net.rules
+for dir in /sys/class/net/*; do
+    if [ -e ${dir}/device ]; then
+       dev=$(basename ${dir})
+       mac_address=$(cat /sys/class/net/${dev}/address)
+       echo "ACTION==\"add\", SUBSYSTEM==\"net\", DRIVERS==\"?*\", ATTR{address}==\"${mac_address}\", NAME=\"${dev}\"" >> /etc/udev/rules.d/70-persistent-net.rules
+    fi
+done
+
+# Mark the sysadmin password as expired immediately
+chage -d 0 sysadmin
+
+# Lock the root password
+passwd -l root
+
+# Enable tmpfs mount for /tmp
+# delete /var/tmp so that it can similinked in
+rm -rf /var/tmp
+systemctl enable tmp.mount
+
+# Disable automount of /dev/hugepages
+systemctl mask dev-hugepages.mount
+
+# Disable firewall
+systemctl disable firewalld
+
+# Disable libvirtd
+systemctl disable libvirtd.service
+
+# Enable rsyncd
+systemctl enable rsyncd.service
+
+# Allow root to run sudo from a non-tty (for scripts running as root that run sudo cmds)
+echo 'Defaults:root !requiretty' > /etc/sudoers.d/root
+
+# Make fstab just root read/writable
+chmod 600 /etc/fstab
+
+# Create first_boot flag
+touch /etc/platform/.first_boot
+
+%end
+
+# Template from: post_kernel_aio_and_worker.cfg
+%post --erroronfail
+
+# Source common functions
+. /tmp/ks-functions.sh
+
+# Source the generated platform.conf
+. /etc/platform/platform.conf
+
+# Update grub with custom kernel bootargs
+source /etc/init.d/cpumap_functions.sh
+n_cpus=$(cat /proc/cpuinfo 2>/dev/null | \
+  awk '/^[pP]rocessor/ { n +=1 } END { print (n>0) ? n : 1}')
+n_numa=$(ls -d /sys/devices/system/node/node* 2>/dev/null | wc -l)
+KERN_OPTS=" iommu=pt usbcore.autosuspend=-1"
+
+KERN_OPTS="${KERN_OPTS} hugepagesz=2M hugepages=0 default_hugepagesz=2M"
+
+# If this is an all-in-one system, we need at least 4 CPUs
+if [ "$system_type" = "All-in-one" -a ${n_cpus} -lt 4 ]; then
+    report_post_failure_with_msg "ERROR: At least 4 CPUs are required for controller+worker node."
+fi
+
+# Add kernel options for cpu isolation / affinity
+if [ ${n_cpus} -gt 1 ]
+then
+  base_cpulist=$(platform_expanded_cpu_list)
+  base_cpumap=$(cpulist_to_cpumap ${base_cpulist} ${n_cpus})
+  avp_cpulist=$(vswitch_expanded_cpu_list)
+  norcu_cpumap=$(invert_cpumap ${base_cpumap} ${n_cpus})
+  norcu_cpulist=$(cpumap_to_cpulist ${norcu_cpumap} ${n_cpus})
+
+  if [[ "$subfunction" =~ lowlatency ]]; then
+    KERN_OPTS="${KERN_OPTS} isolcpus=${norcu_cpulist}"
+    KERN_OPTS="${KERN_OPTS} nohz_full=${norcu_cpulist}"
+  else
+    KERN_OPTS="${KERN_OPTS} isolcpus=${avp_cpulist}"
+  fi
+  KERN_OPTS="${KERN_OPTS} rcu_nocbs=${norcu_cpulist}"
+  KERN_OPTS="${KERN_OPTS} kthread_cpus=${base_cpulist}"
+  KERN_OPTS="${KERN_OPTS} irqaffinity=${base_cpulist}"
+  # Update vswitch.conf
+  sed -i "s/^VSWITCH_CPU_LIST=.*/VSWITCH_CPU_LIST=\"${avp_cpulist}\"/" /etc/vswitch/vswitch.conf
+fi
+
+# Add kernel options to ensure an selinux is disabled
+KERN_OPTS="${KERN_OPTS} selinux=0 enforcing=0"
+
+# Add kernel options to set NMI watchdog
+if [[ "$subfunction" =~ lowlatency ]]; then
+  KERN_OPTS="${KERN_OPTS} nmi_watchdog=0 softlockup_panic=0"
+else
+  KERN_OPTS="${KERN_OPTS} nmi_watchdog=panic,1 softlockup_panic=1"
+fi
+
+if [[ "$(dmidecode -s system-product-name)" =~ ^ProLiant.*Gen8$ ]]; then
+  KERN_OPTS="${KERN_OPTS} intel_iommu=on,eth_no_rmrr"
+else
+  KERN_OPTS="${KERN_OPTS} intel_iommu=on"
+fi
+
+# Add kernel option to disable biosdevname if enabled
+# As this may already be in GRUB_CMDLINE_LINUX, only add if it is not already present
+grep -q '^GRUB_CMDLINE_LINUX=.*biosdevname=0' /etc/default/grub
+if [ $? -ne 0 ]; then
+  KERN_OPTS="${KERN_OPTS} biosdevname=0"
+fi
+
+# Add kernel options to disable kvm-intel.eptad on Broadwell
+# Broadwell: Model: 79, Model name: Intel(R) Xeon(R) CPU E5-2699 v4 @ 2.20GHz
+if grep -q -E "^model\s+:\s+79$" /proc/cpuinfo
+then
+  KERN_OPTS="${KERN_OPTS} kvm-intel.eptad=0"
+fi
+
+# k8s updates:
+#KERN_OPTS="${KERN_OPTS} cgroup_disable=memory"
+KERN_OPTS="${KERN_OPTS} user_namespace.enable=1"
+
+# Add kernel option to avoid jiffies_lock contention on real-time kernel
+if [[ "$subfunction" =~ lowlatency ]]; then
+  KERN_OPTS="${KERN_OPTS} skew_tick=1"
+fi
+
+# If the installer asked us to use security related kernel params, use
+# them in the grub line as well (until they can be configured via puppet)
+grep -q 'nopti' /proc/cmdline
+if [ $? -eq 0 ]; then
+    KERN_OPTS="${KERN_OPTS} nopti"
+fi
+grep -q 'nospectre_v2' /proc/cmdline
+if [ $? -eq 0 ]; then
+    KERN_OPTS="${KERN_OPTS} nospectre_v2"
+fi
+
+perl -pi -e 's/(GRUB_CMDLINE_LINUX=.*)\"/\1'"$KERN_OPTS"'\"/g' /etc/default/grub
+
+if [ -d /sys/firmware/efi ] ; then
+  grub2-mkconfig -o /boot/efi/EFI/centos/grub.cfg
+else
+  grub2-mkconfig -o /boot/grub2/grub.cfg
+fi
+
+%end
+
+
+# Template from: post_lvm_pv_on_rootfs.cfg
+%post --erroronfail
+
+# Source common functions
+. /tmp/ks-functions.sh
+
+# uncomment the global_filter line in lvm.conf
+perl -0777 -i.bak -pe 's:(# This configuration option has an automatic default value\.\n)\t# global_filter:$1        global_filter:m' /etc/lvm/lvm.conf
+
+# Determine which disk we created our PV on (i.e. the root disk)
+ROOTDISK=$(get_by_path $(pvdisplay --select 'vg_name=cgts-vg' -C -o pv_name --noheadings))
+if [ -z "$ROOTDISK" ]; then
+    report_post_failure_with_msg "ERROR: failed to identify rootdisk via pvdisplay"
+fi
+# Edit the LVM config so LVM only looks for LVs on the root disk
+sed -i "s#^\( *\)global_filter = \[.*#\1global_filter = [ \"a|${ROOTDISK}|\", \"r|.*|\" ]#" /etc/lvm/lvm.conf
+%end
+
+
+# Template from: post_system_aio.cfg
+%post --erroronfail
+
+# Source common functions
+. /tmp/ks-functions.sh
+
+# Source the generated platform.conf
+. /etc/platform/platform.conf
+
+## Reserve more memory for base processes since the controller has higher
+## memory requirements but cap it to better handle systems with large
+## amounts of memory
+TOTALMEM=$(grep MemTotal /proc/meminfo | awk '{print int($2/1024)}')
+
+if [ -e /sys/devices/system/node/node0 ]; then
+  RESERVEDMEM=$(grep MemTotal /sys/devices/system/node/node0/meminfo | awk '{printf "%d\n", $4/1024}')
+else
+  RESERVEDMEM=$(grep MemTotal /proc/meminfo | awk '{print int($2/1024/4)}')
+fi
+
+if [ ${RESERVEDMEM} -lt 6144 ]; then
+    RESERVEDMEM=6144
+elif [ ${RESERVEDMEM} -gt 14500 ]; then
+    RESERVEDMEM=14500
+elif [ ${RESERVEDMEM} -gt 8192 ]; then
+    RESERVEDMEM=8192
+fi
+
+sed -i -e "s#\(WORKER_BASE_RESERVED\)=.*#\1=(\"node0:${RESERVEDMEM}MB:1\" \"node1:2000MB:0\" \"node2:2000MB:0\" \"node3:2000MB:0\")#g" /etc/platform/worker_reserved.conf
+
+# Update WORKER_CPU_LIST
+N_CPUS=$(cat /proc/cpuinfo 2>/dev/null | awk '/^[pP]rocessor/ { n +=1 } END { print (n>0) ? n : 1}')
+sed -i "s/^WORKER_CPU_LIST=.*/WORKER_CPU_LIST=\"0-$((N_CPUS-1))\"/" /etc/platform/worker_reserved.conf
+
+%end
+
+
+# Template from: post_net_controller.cfg
+%post --erroronfail
+
+# Source common functions
+. /tmp/ks-functions.sh
+
+http_port=$(get_http_port)
+# Retrieve the installation uuid from the controller we booted from
+INSTALL_UUID=`curl -sf http://pxecontroller:${http_port:-8080}/feed/rel-19.12/install_uuid`
+if [ $? -ne 0 ]
+then
+  INSTALL_UUID=unknown
+fi
+
+grep -q INSTALL_UUID /etc/platform/platform.conf
+if [ $? -ne 0 ]; then
+    echo "INSTALL_UUID=$INSTALL_UUID" >> /etc/platform/platform.conf
+fi
+
+cd /www/pages
+# Sync software repository
+feed_url=http://pxecontroller:${http_port:-8080}/feed/
+anaconda_logdir=/var/log/anaconda
+mkdir -p $anaconda_logdir
+
+echo "Mirroring software repository (may take several minutes)..." >/dev/console
+wget --recursive --no-parent --no-host-directories --no-clobber --reject 'index.html*' --reject '*.log' $feed_url/ -o $anaconda_logdir/wget-feed-mirror.log \
+    || report_post_failure_with_logfile $anaconda_logdir/wget-feed-mirror.log
+
+# Sync patching repository
+updates_url=http://pxecontroller:${http_port:-8080}/updates/
+wget --mirror --no-parent --no-host-directories --reject 'index.html*' --reject '*.log' $updates_url/ -o $anaconda_logdir/wget-updates-mirror.log \
+    || report_post_failure_with_logfile $anaconda_logdir/wget-updates-mirror.log
+echo "Done" >/dev/console
+
+shopt -s nullglob
+
+# Check whether a second release is installed
+. /etc/build.info
+CURRENT_REL_DIR=rel-${SW_VERSION}
+OTHER_REL_DIR=
+for REL_DIR in /www/pages/feed/*; do
+    if [[ ! $REL_DIR =~ "${SW_VERSION}" ]]; then
+        OTHER_REL_DIR=`basename $REL_DIR`
+        OTHER_REL_VERSION=${OTHER_REL_DIR:4}
+        break
+    fi
+done
+
+# If second release is installed, find the latest version of the installer
+# RPM and install the pxeboot files we require to boot hosts with that release.
+if [ ! -z "$OTHER_REL_DIR" ]; then
+    PATCH_RPM=`find /www/pages/updates/${OTHER_REL_DIR}/Packages -name 'pxe-network-installer*' | sort -V | tail -1`
+    BASE_RPM=`find /www/pages/feed/${OTHER_REL_DIR}/Packages -name 'pxe-network-installer*' | sort -V | tail -1`
+
+    if [ ! -z "$PATCH_RPM" ]; then
+        INSTALL_RPM=$PATCH_RPM
+    elif [ ! -z "$BASE_RPM" ]; then
+        INSTALL_RPM=$BASE_RPM
+    else
+        report_post_failure_with_msg "ERROR: Unable to find pxe-network-installer RPM for $OTHER_REL_DIR. Aborting installation."
+    fi
+
+    echo "Installing pxeboot files for release $OTHER_REL_DIR from $INSTALL_RPM" >/dev/console
+    TMP_RPM=/tmp/pxe-network-installer
+    mkdir $TMP_RPM
+    pushd $TMP_RPM
+    /usr/bin/rpm2cpio $INSTALL_RPM | cpio -idm \
+        || report_post_failure_with_msg "Failed to extract pxe-network-installer"
+
+    cp -r $TMP_RPM/usr / \
+        || report_post_failure_with_msg "Failed to copy pxe-network-installer /usr"
+    cp -r $TMP_RPM/pxeboot/$OTHER_REL_DIR /pxeboot/ \
+        || report_post_failure_with_msg "Failed to copy pxe-network-installer /pxeboot/$OTHER_REL_DIR"
+    cp $TMP_RPM/pxeboot/pxelinux.cfg.files/*-$OTHER_REL_VERSION /pxeboot/pxelinux.cfg.files/ \
+        || report_post_failure_with_msg "Failed to copy pxe-network-installer pxelinux.cfg files"
+
+    rm -rf $TMP_RPM
+fi
+
+%end
+
+# Template from: post_net_common.cfg
+%pre --erroronfail
+
+# Source common functions
+. /tmp/ks-functions.sh
+
+http_port=$(get_http_port)
+echo "repo --name=base --baseurl=http://pxecontroller:${http_port:-8080}/feed/rel-19.12/" > /tmp/repo-include
+echo "repo --name=updates --baseurl=http://pxecontroller:${http_port:-8080}/updates/rel-19.12/" > /tmp/repo-include
+
+%end
+
+# Repository arguments from %pre
+%include /tmp/repo-include
+
+
+%post --erroronfail
+
+# Source common functions
+. /tmp/ks-functions.sh
+
+# Persist the http port to the platform configuration
+echo http_port=$(get_http_port) >> /etc/platform/platform.conf
+
+# Obtain the boot interface from the PXE boot
+BOOTIF=`cat /proc/cmdline |xargs -n1 echo |grep BOOTIF=`
+if [ -d /sys/firmware/efi ] ; then
+    BOOTIF=${BOOTIF#BOOTIF=}
+else
+    BOOTIF=${BOOTIF#BOOTIF=01-}
+    BOOTIF=${BOOTIF//-/:}
+fi
+
+mgmt_dev=none
+mgmt_vlan=0
+if [ -n "$BOOTIF" ] ; then
+    ndev=`ip link show |grep -B 1 $BOOTIF |head -1 |awk '{print $2}' |sed -e 's/://'`
+    if [ -n "$ndev" ] ; then
+        mgmt_dev=$ndev
+        # Retrieve the management VLAN from sysinv if it exists
+        mgmt_vlan=`curl -sf http://pxecontroller:6385/v1/isystems/mgmtvlan`
+        if [ $? -ne 0 ]
+        then
+          report_post_failure_with_msg "ERROR: Unable to communicate with System Inventory REST API. Aborting installation."
+        fi
+    else
+        report_post_failure_with_msg "ERROR: Unable to determine mgmt interface from BOOTIF=$BOOTIF."
+    fi
+else
+    report_post_failure_with_msg "ERROR: BOOTIF is not set. Unable to determine mgmt interface."
+fi
+
+if [ $mgmt_vlan -eq 0 ] ; then
+
+    # Persist the boot device to the platform configuration. This will get
+    # overwritten later if the management_interface is on a bonded interface.
+    echo management_interface=$mgmt_dev >> /etc/platform/platform.conf
+
+    # Build networking scripts
+    cat << EOF > /etc/sysconfig/network-scripts/ifcfg-lo
+DEVICE=lo
+IPADDR=127.0.0.1
+NETMASK=255.0.0.0
+NETWORK=127.0.0.0
+BROADCAST=127.255.255.255
+ONBOOT=yes
+IPV6_AUTOCONF=no
+NAME=loopback
+EOF
+
+    cat << EOF > /etc/sysconfig/network-scripts/ifcfg-$mgmt_dev
+DEVICE=$mgmt_dev
+BOOTPROTO=dhcp
+ONBOOT=yes
+IPV6_AUTOCONF=no
+LINKDELAY=20
+EOF
+
+else
+
+    # Check whether to use inet or inet6
+    ipv6_addr=$(dig +short AAAA controller)
+    if [[ -n "$ipv6_addr" ]]
+    then
+        mgmt_address_family=inet6
+        ipv6init=yes
+        dhcpv6c=yes
+        dhclientargs=-1
+    else
+        mgmt_address_family=inet
+        ipv6init=no
+        dhcpv6c=no
+        dhclientargs=
+    fi
+
+    # Persist the boot device to the platform configuration. This will get
+    # overwritten later if the management_interface is on a bonded interface.
+    echo management_interface=vlan$mgmt_vlan >> /etc/platform/platform.conf
+
+    # Build networking scripts
+    cat << EOF > /etc/sysconfig/network-scripts/ifcfg-lo
+DEVICE=lo
+IPADDR=127.0.0.1
+NETMASK=255.0.0.0
+NETWORK=127.0.0.0
+BROADCAST=127.255.255.255
+ONBOOT=yes
+IPV6_AUTOCONF=no
+NAME=loopback
+EOF
+
+    cat << EOF > /etc/sysconfig/network-scripts/ifcfg-$mgmt_dev
+DEVICE=$mgmt_dev
+BOOTPROTO=none
+ONBOOT=yes
+IPV6_AUTOCONF=no
+LINKDELAY=20
+EOF
+
+    cat << EOF > /etc/sysconfig/network-scripts/ifcfg-vlan$mgmt_vlan
+DEVICE=vlan$mgmt_vlan
+BOOTPROTO=dhcp
+DHCLIENTARGS=$dhclientargs
+IPV6INIT=$ipv6init
+DHCPV6C=$dhcpv6c
+ONBOOT=yes
+IPV6_AUTOCONF=no
+PHYSDEV=$mgmt_dev
+VLAN=yes
+LINKDELAY=20
+EOF
+
+    # Reject DHCPOFFER from DHCP server that doesn't send
+    # wrs-install-uuid option
+    echo "require wrs-install-uuid;" >>/etc/dhcp/dhclient.conf
+    echo "require dhcp6.wrs-install-uuid;" >>/etc/dhcp/dhclient.conf
+
+    # Bring up the mgmt vlan so that a dhcp lease is acquired and an address is
+    # setup prior to the post-install reboot.  This is so that the timing of the IP
+    # address allocation is similar to how normal/non-pxe installation works.
+    mgmt_iface=vlan$mgmt_vlan
+    dhclient_family=$([[ $mgmt_address_family == "inet" ]] && echo -4 || echo -6)
+    ip link add link $mgmt_dev name $mgmt_iface type vlan id $mgmt_vlan
+    ip link set up dev $mgmt_iface
+    dhclient $dhclient_family $mgmt_iface || true
+
+fi
+
+%end