# # Copyright (c) 2022 Wind River Systems, Inc. # SPDX-License-Identifier: Apache-2.0 # ############################################################################ # # StarlingX Debian Unified System Node Install Kickstart # ############################################################################ # # This is the unified kickstart for Debian installation of system nodes. # # The Linux Assembly Tool (LAT) performs a unified install for all system # nodes and exposes boot loader environment variables to this kickstart. # # This kickstart must be called with the 'traits=' boot parameter. # Valid traits are: # # controller ... the controller function # storage ... the storage function # worker ... the worker function # lowlatency ... the low latency function # miniboot ... redfish subcloud install function # # Valid node personality trait groupings ... set configuration function # # traits=controller ... Controller # traits=controller,worker ... All-in-one # traits=controller,worker,lowlatency ... All-in-one Low Latency # traits=storage ... Storage # traits=worker ... Worker # traits=worker,lowlatency ... Worker Low Latency # # Kickstart Stages # # Pre Partition - Common Functions Script # Pre Partition - Volume Remove & Wipe Disk # Partition - Partition Disks & Create Volumes # Mkfs - Create Volume Groups & Logical Volumes # Post - Logical Volume Config # Post - Traits & Platform Config File update # Post - Set Kernel Args # Post - Interface Setup # Post - Kickstart Finalize Install UUID # Post - Log Filesystem Setup # Post Nochroot - Save Install scripts and Logs # ############################################################################ # # LAT disk install override debug tool interface. # # lat-disk --install-device=${instdev} \ # --fat-size=${FSZ} \ # --boot-size=${BSZ} \ # --root-size=${RSZ} \ # --var-size=${VSZ} \ # --inst-flux=0 # # Notes: exported environment variables changed in 'post' sections # do not change the original value. # ########################################################################### # # The first kickstart script creates '/tmp/lat/functions' common functions # file that can be loaded from any of the other hook sections. # ########################################################################### # Pre Partition - Common Functions Script %pre-part --interpreter=/bin/bash cat << EOF >> /tmp/lat/ks_functions.sh [ "\${HOOK_LABEL}" = "" ] && HOOK_LABEL="unknown" export LOG_DIR="var/log" export LAT_DIR="tmp/lat" export LOGFILE="/\${LAT_DIR}/kickstart.log" ############################################################################ # log utils ############################################################################ function log() { local dt="\$(date "+%Y-%m-%d %H:%M:%S.%3N")" echo "\$dt kickstart \${HOOK_LABEL} info: \$1" >>\${LOGFILE} } function ilog() { [ -z "$stdout" ] && stdout=1 local dt="$(date "+%Y-%m-%d %H:%M:%S.%3N")" echo "\$dt kickstart \${HOOK_LABEL} info: \$1" >&\${stdout} echo "\$dt kickstart \${HOOK_LABEL} info: \$1" >>\${LOGFILE} } function dlog() { if [ "\${debug}" ] ; then [ -z "\$stdout" ] && stdout=1 local dt="\$(date "+%Y-%m-%d %H:%M:%S.%3N")" echo "\$dt kickstart \${HOOK_LABEL} debug: \$1" >&\${stdout} echo "\$dt kickstart \${HOOK_LABEL} debug: \$1" >>\${LOGFILE} fi } function wlog() { [ -z "\$stdout" ] && stdout=1 local dt="\$(date "+%Y-%m-%d %H:%M:%S.%3N")" echo "\$dt kickstart \${HOOK_LABEL} warn: \$1" >&\${stdout} echo "\$dt kickstart \${HOOK_LABEL} warn: \$1" >>\${LOGFILE} } function elog() { [ -z "\$stdout" ] && stdout=1 local dt="\$(date "+%Y-%m-%d %H:%M:%S.%3N")" echo "\$dt kickstart \${HOOK_LABEL} error: \$1" >&\${stdout} echo "\$dt kickstart \${HOOK_LABEL} error: \$1" >>\${LOGFILE} } function report_failure_with_msg() { local msg=\${1} echo -e '\n\nInstallation failed.\n' wlog "Installation Failed: ERROR: \${msg}" shell_start exit 1 } ######################################################################## # Name : get_disk # Parameters: \$1 - ?????? # Returns : No return but common disk name is echo's to stdio ######################################################################### function get_disk() { echo "\$(cd /dev ; readlink -f \$1)" } ######################################################################### # Name : get_by_path # Parameters: \$1 - device name i.e. /dev/sda # Returns : echo of device name by-path # example: /dev/disk/by-path/pci-0000:03:00.0-scsi-0:2:0:0 ######################################################################### function get_by_path() { # log "Function: get_by_path '\${1}'" 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 } ######################################################################### # Name : get_disk_dev # Purpose : get the disk name # Returns : echo of the first disk name found ; base on coded priority ######################################################################### function get_disk_dev() { local disk # Detect HDD for blk_dev in vda vdb sda sdb dda ddb hda hdb; do if [ -d /sys/block/\$blk_dev ]; then disk=\$(ls -l /sys/block/\$blk_dev | grep -v usb | head -n1 | sed 's/^.*\([vsdh]d[a-z]\+\).*\$/\1/'); if [ -n "\$disk" ]; then echo "\$disk" return fi fi done for blk_dev in nvme0n1 nvme1n1; do if [ -d /sys/block/\$blk_dev ]; then disk=\$(ls -l /sys/block/\$blk_dev | grep -v usb | head -n1 | sed 's/^.*\(nvme[01]n1\).*\$/\1/'); if [ -n "\$disk" ]; then echo "\$disk" return fi fi done } ######################################################################### # Name : exec_retry # Purpose : Retry operations up to a caller specified ... # Parameters: $1 - retries - up to number of retries before giving up # $2 - time in seconds between each retry # $3 - the command string to execute # Returns : exit code from last command operation ######################################################################### function exec_retry() { local retries=\${1} local interval=\${2} local command=\${3} # local variables retry_count=1 local ret_code=0 local ret_stdout="" command="\${command}" # 2>&\$stdout" while [ \$retry_count -le \$retries ]; do # dlog "Running command: '\${command}'." ret_stdout=\$(eval \${command}) ret_code=\${?} [ \$ret_code -eq 0 ] && break wlog "Error running command '\${command}'. Try \${retry_count} of \${retries} retry in \${interval}s." wlog "ret_code: \${ret_code}, stdout: '\${ret_stdout}'." sleep \${interval} retry_count=\$((retry_count+1)) done echo "\${ret_stdout}" return \${ret_code} } ######################################################################### # Name : exec_no_fds # Purpose : Execute command (with retries) after closing fds # Parameters: $1 - List of volume file descriptors # $2 - the command string to execute # $3 - up to number of retries before giving up # $4 - time in seconds between each retry # Returns : exit code from last command operation ######################################################################### function exec_no_fds() { # Close open FDs when executing commands that complain about leaked FDs. local fds=\${1} local cmd=\${2} local retries=\${3} local interval=\${4} local ret_code=0 local ret_stdout="" for fd in \$fds do local cmd="\$cmd \$fd>&-" done if [ -z "\$retries" ]; then #wlog "Running command: '\$cmd'." eval "\$cmd" else ret_stdout=\$(exec_retry "\$retries" "\$interval" "\$cmd") ret_code=\$? echo "\${ret_stdout}" return \${ret_code} fi } ######################################################################### # Name : is_system_node_install # Returns : 1 if yes 'pxecontroller' is in $insturl boot arg ; else 0 ######################################################################### function is_system_node_install() { if [[ "\$insturl" == *"pxecontroller"* ]] ; then return 0 else return 1 fi } ######################################################################### # Name : update_platform_conf # Purpose : Update the platform.conf file with logging ######################################################################### PLATFORM_CONF="/etc/platform/platform.conf" function update_platform_conf() { ilog "update \${PLATFORM_CONF} : \${1}" echo "\${1}" >> \${PLATFORM_CONF} } ######################################################################### # Name : get_iface_from_ethname # Purpose : Translate eth# interface to the alternate predicitive # interface name'altname'. # Parameter: eth# name interface string to translate # Return : echo's of altname interface string ######################################################################### # TODO: Move to where its used if there is only one section caller function get_iface_from_ethname() { iface=\${1} # convert to predictive name altname=\$(udevadm info --export --query=property --path=/sys/class/net/\${iface} | grep ID_NET_NAME_ONBOARD) altname=\${altname#ID_NET_NAME_ONBOARD=} # The altname is seen enveloped with tick's ; 'eno1' # Handle with and without tick's just in case if [ -z "\${altname}" ] ; then log "Failed to translate \${iface} to predictive name" elif [ "\${altname::1}" = "'" ] ; then echo "\${altname:1:-1}" else echo "\${altname}" fi } function display_volume_info () { ilog "Volume Info:\${1}" pvscan 2>/dev/null pvscan 2>/dev/null >> \${LOGFILE} lvscan 2>/dev/null lvscan 2>/dev/null >> \${LOGFILE} pvdisplay 2>/dev/null pvdisplay 2>/dev/null >> \${LOGFILE} lvdisplay 2>/dev/null lvdisplay 2>/dev/null >> \${LOGFILE} } display_mount_info() { if [ \${debug} -ne 0 ] ; then echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" lsblk -o name,mountpoint,label,size,uuid echo "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" fi } function log_lvm_conf () { lvm_global_filter=\$(cat /etc/lvm/lvm.conf | grep "global_filter =") ilog "LVM 'global_filter' Config: \${lvm_global_filter}" lvm_preferred_names=\$(cat /etc/lvm/lvm.conf | grep "preferred_names =") ilog "LVM 'lvm_preferred_names' Config: \${lvm_preferred_names}" } function breakpoint() { echo "*** BREAKPOINT ***: \${1} ; type exit to continue" bash echo "continuing from breakpoint: \${1}" } function set_variable() { touch "/\${LAT_DIR}/\${1}" } function get_variable() { [ -e "/\${LAT_DIR}/\${1}" ] && return 1 return 0 } function clr_variable() { rm -f "/\${LAT_DIR}/\${1}" } ########################################################################## # Global Kickstart Constants # ########################################################################## # # NOTE: exported Variables from other segments are NOT visible from functions # BACKUP_PART_LABEL="Platform Backup" BACKUP_PART_NO=6 BACKUP_PART=\${instdev}\${BACKUP_PART_NO} DEFAULT_PERSISTENT_SIZE=30000 # Note that the BA5EBA11-0000-1111-2222- is the prefix used by STX and it's defined in sysinv constants.py. # Since the 000000000001 suffix is used by custom stx LVM partitions, # the next suffix is used for the persistent backup partition (000000000002) BACKUP_PART_GUID="BA5EBA11-0000-1111-2222-000000000002" # Node Personality Trait TRAIT__CONTROLLER="controller" TRAIT__STORAGE="storage" TRAIT__WORKER="worker" TRAIT__LOWLATENCY="lowlatency" # System Types SYSTEM_TYPE__AIO="All-in-one" SYSTEM_TYPE__STANDARD="Standard" # Node Subfunctions SUBFUNCTION__CONTROLLER="\${TRAIT__CONTROLLER}" SUBFUNCTION__STORAGE="\${TRAIT__STORAGE}" SUBFUNCTION__WORKER="\${TRAIT__WORKER}" SUBFUNCTION__AIO="\${TRAIT__CONTROLLER},\${TRAIT__WORKER}" SUBFUNCTION__AIO_LOWLATENCY="\${TRAIT__CONTROLLER},\${TRAIT__WORKER},\${TRAIT__LOWLATENCY}" VOLUME_GROUPS="cgts-vg" ROOTFS_SIZE=\${RSZ} # 20000 BOOT_SIZE=\${BSZ} # 500 EFI_SIZE=300 LOG_VOL_SIZE=8000 SCRATCH_VOL_SIZE=16000 EOF chmod 755 /tmp/lat/ks_functions.sh HOOK_LABEL="pre-part" . /tmp/lat/ks_functions.sh ########################################################################## # Global Kickstart variables # ########################################################################## export debug=0 export PLATFORM_BACKUP_SIZE=${DEFAULT_PERSISTENT_SIZE} # Assume there is no Platform Backup (persistent) Partition export BACKUP_CREATED=0 export BACKUP_PERSISTED=0 # Platform Backup Partition Info export BACKUP_PART_GUID=0 export BACKUP_PART_FIRST=0 export BACKUP_PART_END=0 export BACKUP_PART_SIZE=0 export BACKUP_PART_FLAGS=0 export BACKUP_PART_NAME="" export STOR_DEV_FDS="" ########################################################################## ilog "***********************************************" ilog "** Pre Partition - Volume Remove & Wipe Disk **" ilog "***********************************************" # Default traits to AIO if missing if [ -z "${traits}" ] ; then traits="controller,worker" wlog "traits option missing ; defaulting to \${traits}" fi export controller=false export storage=false export worker=false export lowlatency=false export miniboot=false export aio=false for trait in ${traits//,/ }; do # dlog "trait:${trait}" case ${trait} in "controller") controller=true ;; "storage") storage=true ;; "worker") worker=true ;; "lowlatency") lowlatency=true ;; "miniboot") miniboot=true ;; *) wlog "unknown trait '${trait}'" ;; esac done [ "${controller}" = true -a "${worker}" = true ] && aio=true grep -q 'debug_kickstart' /proc/cmdline if [ $? -eq 0 ]; then debug=1 fi ilog "LAT size parameters: FSZ=${FSZ} BSZ=${BSZ} RSZ=${RSZ} VSZ=${VSZ}" # First, parse /proc/cmdline to find the boot args set -- `cat /proc/cmdline` ilog "/proc/cmdline:$*" # for I in $*; do case "$I" in *=*) eval $I 2>/dev/null;; esac; done for arg in $*; do case "$arg" in *=*) eval $arg 2>/dev/null log "arg : $arg" ;; esac done # Note: This is equivalent to pre_disk_setup_common.cfg # Name : check_execs # Purpose: Confirm all the executables required by the kickstart are present # Returns: 1 of one or more executable are missing REQUIRED_EXECS="bc blkid dd lvcreate mkfs.ext4 partprobe pvremove pvs sgdisk vgcreate wipefs" function check_execs() { missing_exec=0 for x in ${REQUIRED_EXECS} ; do which ${x} > /dev/null 2>&1 if [ ${?} -ne 0 ] ; then elog "dependency check failed ; required '${x}' exec is missing" missing_exec=1 fi done return ${missing_exec} } # Log Traits [ "${controller}" = true ] && ilog "Controller Function" [ "${storage}" = true ] && ilog "Storage Function" [ "${worker}" = true ] && ilog "Worker Function" [ "${lowlatency}" = true ] && ilog "Low Latency Function" [ "${miniboot}" = true ] && ilog "Zero Touch Install Function" # Log System Type if [ ${aio} = true ] ; then ilog "${SYSTEM_TYPE__AIO} system" else ilog "${SYSTEM_TYPE__STANDARD} system" fi # Verify that all the required executables are presenty check_execs [ $? -ne 0 ] && report_failure_with_msg "Required executables are missing" #################################################### # pre_common_head (obsolete with lat) #################################################### # TODO: The installer does not have 'timezone' # Does LAT handle this ? wlog "timezone not set ; 'timezone --nontp --utc UTC'" ##################################################### # From pre_disk_setup_common.cfg ##################################################### if [ -n "$instdev" ] ; then instdev_by_path=$(get_by_path $instdev) if [ -z ${instdev_by_path} ] ; then report_failure_with_msg "invalid install device ${instdev}" else ilog "Install device: ${instdev} : ${instdev_by_path}" fi fi # Get all block devices of type disk in the system. # This includes solid state devices. # Note: /dev/* are managed by kernel tmpdevfs while links in # /dev/disk/by-path/ are managed by udev which updates them # asynchronously so avoid using them while performing partition # operations. ilog "Detected storage devices:" STOR_DEVS="" for f in /dev/disk/by-path/*; do dev=$(readlink -f $f) # dlog "found device ${f}" exec_retry 2 0.5 "lsblk --nodeps --pairs $dev" | grep -q 'TYPE="disk"' if [ $? -eq 0 ] ; then # ISSUE: Do /dev/sda only otherwise with sda,sdb,sdc the LAT boot # partitions show up on /dev/sdc even if instdev = /dev/sda # This issue is being investigated, Jira pending if [ "${dev}" = "/dev/sda" ] ; then STOR_DEVS="$STOR_DEVS $dev" ilog "Adding ${f} -> ${dev} to managed device list" fi fi done # Filter STOR_DEVS variable for any duplicates as on some systems udev # creates multiple links to the same device. This causes issues due to # attempting to acquire a flock on the same device multiple times. STOR_DEVS=$(echo "$STOR_DEVS" | xargs -n 1 | sort -u | xargs) ilog "Unique storage devices: $STOR_DEVS" if [ -z "$STOR_DEVS" ] ; then report_failure_with_msg "No storage devices available." fi # Lock all devices so that udev doesn't trigger a kernel partition table # rescan that removes and recreates all /dev nodes for partitions on those # devices. Since udev events are asynchronous this could lead to a case # where /dev/ links for existing partitions are briefly missing. # Missing /dev links leads to command execution failures. #STOR_DEV_FDS="$stdout" #for dev in $STOR_DEVS; do # exec {fd}>$dev || report_failure_with_msg "Error creating file descriptor for $dev." # flock -n "$fd" || report_failure_with_msg "Can't get a lock on fd $fd of device $dev." # STOR_DEV_FDS="$STOR_DEV_FDS $fd" # ilog "Locked ${dev} fd:${fd}" #done # Log info about system state at beginning of partitioning operation for dev in $STOR_DEVS; do ilog "Initial partition table for $dev is:" # log "Initial partition table for $dev is:" parted -s $dev unit mib print # parted -s $dev unit mib print >> ${LOGFILE} done display_volume_info "before" display_mount_info # Consider removing since LAT already handles this failure mode # Ensure specified device is not a USB drive udevadm info --query=property --name=${instdev} |grep -q '^ID_BUS=usb' if [ $? -eq 0 ]; then report_failure_with_msg "Specified installation ($instdev) device is a USB drive." fi # Log the disk setup ilog "Volume Groups : ${VOLUME_GROUPS} ; $STOR_DEV_FDS" # Deactivate existing volume groups to avoid Anaconda issues with pre-existing groups # TODO: May not need this Anaconda specific behavior work around vgs=$(exec_no_fds "$STOR_DEV_FDS" "vgs --noheadings -o vg_name 2>/dev/null") for vg in $vgs; do wlog "Disabling $vg" exec_no_fds "$STOR_DEV_FDS" "vgchange -an $vg 2>/dev/null" 5 0.5 [ $? -ne 0 ] && report_failure_with_msg "Failed to disable $vg." done # Remove the volume groups that have physical volumes on the root disk for vg in $(exec_no_fds "$STOR_DEV_FDS" "vgs --noheadings -o vg_name 2>/dev/null"); do exec_no_fds "$STOR_DEV_FDS" "pvs --select \"vg_name=$vg\" --noheadings -o pv_name 2>/dev/null" | grep -q "${instdev}" rc=$? if [ $rc -ne 0 ]; then wlog "Found $vg with no PV on rootfs, ignoring ; rc=${rc}" # continue fi # wlog "Removing LVs on $vg." # exec_no_fds "$STOR_DEV_FDS" "lvremove --force $vg 2>/dev/null" 5 0.5 || wlog "WARNING: Failed to remove lvs on $vg." # pvs=$(exec_no_fds "$STOR_DEV_FDS" "pvs --select \"vg_name=$vg\" --noheadings -o pv_name 2>/dev/null") # wlog "VG $vg has PVs: $(echo $pvs), removing them." # for pv in $pvs; do # wlog "Removing PV $pv." # exec_no_fds "$STOR_DEV_FDS" "pvremove --force --force --yes $pv 2>/dev/null" 5 0.5 # [ $? -ne 0 ] && report_failure_with_msg "Failed to remove PV." # done # Just delete the Volume Group , the logical volumes will be deleted under the covers vg_check=$(exec_no_fds "$STOR_DEV_FDS" "vgs --select \"vg_name=$vg\" --noheadings -o vg_name 2>/dev/null") if [ -n "$vg_check" ]; then wlog "Removing volume group $vg" exec_no_fds "$STOR_DEV_FDS" "vgremove --force $vg 2>/dev/null" 5 0.5 [ $? -ne 0 ] && report_failure_with_msg "Failed to remove VG." fi done # Log info about system state after partitioning removal operation. for dev in $STOR_DEVS; do log "After partition removal for $dev is:" parted -s $dev unit mib print >> ${LOGFILE} done display_volume_info "after" display_mount_info ONLYUSE_HDD="" part_type_guid_str="Partition GUID code" part_type_name_str="Partition name" part_type_size_str="Partition size" part_type_first_str="First sector" part_type_end_str="Last sector" part_type_flags_str="Attribute flags" 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 wlog "In upgrade, wiping only ${instdev}" WIPE_HDD=${instdev} ONLYUSE_HDD="$(basename ${instdev})" else # Make a list of all the hard drives that are to be wiped. # Never put the LAT install disk '${instdev}' in that list. WIPE_HDD="" # Partition type OSD has a unique globally identifier CEPH_OSD_GUID="4FBD7E29-9D25-41B8-AFD0-062C0CEFF05D" CEPH_JOURNAL_GUID="45B0969E-9B03-4F30-B4C6-B4B80CEFF106" # Check if we wipe OSDs if [ "$(curl -sf http://pxecontroller:6385/v1/ihosts/wipe_osds 2>/dev/null)" = "true" ]; then wlog "Wipe OSD data" WIPE_CEPH_OSDS="true" else wlog "Skip Ceph OSD data wipe." WIPE_CEPH_OSDS="false" fi for dev in $STOR_DEVS do # TODO: Allowing the install dev 'in' results in a failure mode where # every second install fails with the following error string # and unrecoverable mount failure. # # Logs: # # Warning: The kernel is still using the old partition table. # The new table will be used at the next reboot or after you # run partprobe(8) or kpartx(8) # and then # # Failure: # # mount: /sysroot: can't find LABEL=otaroot. # # Action: Find correct place to put partprobe # # Avoid wiping the install root disk # [ ${dev} == ${instdev} ] && continue # 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" pvs | grep -q "$dev *ceph" if [ $? -eq 0 ]; then wlog "skip rook provisoned disk $dev" continue fi 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=$(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 wlog "OSD found on $dev, skipping wipe" wipe_dev="false" break fi pvs | grep -q -e "${dev}${part_number} *ceph" -e "${dev}p${part_number} *ceph" if [ $? -eq 0 ]; then wlog "Rook OSD found on $dev$part_number, skip wipe" wipe_dev="false" break fi done if [ "$wipe_dev" == "false" ]; then ilog "Bypassing Wipe of ${dev}${part_number} ; reason: wipe_dev=false" continue else ilog "Allowing Wipe of ${dev}${part_number} ; reason: wipe_dev=true" fi fi # Add device to the wipe list devname=$(basename $dev) if [ -e $dev -a "$ISO_DEV" != "../../$devname" -a "$USB_DEV" != "../../$devname" ]; then ilog "Adding ${dev} to list of disks to be wipped" if [ -n "$WIPE_HDD" ]; then ilog "WIPE_HDD=$WIPE_HDD,$dev" WIPE_HDD=$WIPE_HDD,$dev else ilog "WIPE_HDD=$dev" WIPE_HDD=$dev fi fi done ilog "Not in upgrade" fi ilog "***************************************************" ilog "WIPE DISKs: ${WIPE_HDD}" ilog "***************************************************" by_dev=${instdev} # TODO: Avoid this loop if the instdev does not have by-path in its name for f in /dev/disk/by-path/*; do if [ "${f}" == "${instdev}" ] ; then by_dev=$(get_disk "${instdev}") break fi done for dev in ${WIPE_HDD//,/ } do ilog "Wiping $dev" # Clear previous GPT tables or LVM data on each disk. # # Rule: Exclude the persistent 'Platform backup' partition. # Note: Delete the first few bytes at the start and end of the partition. # This is required with GPT partitions because they save partition # info at both the start and the end of the block. # Get a list of partitions for this disk part_numbers=( $(parted -s $dev print | awk '$1 == "Number" {i=1; next}; i {print $1}') ) # For each '/dev/${dev}${part_number} apply wipe rules for part_number in "${part_numbers[@]}"; do sgdisk_part_info=$(sgdisk -i $part_number $dev) part_name=$(echo "$sgdisk_part_info" | grep "$part_type_name_str" | awk '{print $3;}') # special handling for the install device '${instdev}' if [ "${dev}" == "${by_dev}" ] ; then # Skip over the bios, efi and boot partitions that got us here. # LAT handles these partitions case ${part_name} in "'bios'") ilog "skipping ${part_name} on ${dev}${part_number}" continue ;; "'otaefi'") ilog "skipping ${part_name} on ${dev}${part_number}" continue ;; "'otaboot'") ilog "skipping ${part_name} on ${dev}${part_number}" continue ;; "'otaboot_b'") ilog "skipping ${part_name} on ${dev}${part_number}" continue ;; "'otaroot'") ilog "skipping ${part_name} on ${dev}${part_number}" continue ;; "'fluxdata'") ilog "skipping ${part_name} on ${dev}${part_number}" continue ;; *) dlog "wipe candidate ${part_name} on ${dev}${part_number}" ;; esac fi # Deal with ssd's which have different partition labelling convention part=$dev$part_number case $part in *"nvme"*) part=${dev}p${part_number} ;; esac # ISSUE: ERIK: These are never the same when the by-path instdev is used. # dev = /dev/sda instdev = by path string ilog "Checking platform-backup partition ... $dev : ${instdev} ${by_dev}" sgdisk_part_info=$(sgdisk -i $part_number $dev) part_type_guid=$(echo "$sgdisk_part_info" | grep "$part_type_guid_str" | awk '{print $4;}') BACKUP_PART_GUID=${part_type_guid} if [ "$dev" == "${by_dev}" -a "$part_type_guid" == $BACKUP_PART_GUID ] ; then BACKUP_PART_GUID=${part_type_guid} part_type_name=$(echo "$sgdisk_part_info" | grep "$part_type_name_str" | awk '{print $3,$4;}') BACKUP_PART_NAME=${part_type_name:1:-1} part_type_first=$(echo "$sgdisk_part_info" | grep "$part_type_first_str" | awk '{print $3;}') BACKUP_PART_FIRST=${part_type_first} part_type_end=$(echo "$sgdisk_part_info" | grep "$part_type_end_str" | awk '{print $3;}') BACKUP_PART_END=${part_type_end} part_type_size=$(echo "$sgdisk_part_info" | grep "$part_type_size_str" | awk '{print $3;}') BACKUP_PART_SIZE=${part_type_size} part_type_flags=$(echo "$sgdisk_part_info" | grep "$part_type_flags_str" | awk '{print $3;}') BACKUP_PART_FLAGS=${part_type_flags} # dlog "Platform Backup: ${BACKUP_PART_NAME}:${BACKUP_PART_FIRST}:${BACKUP_PART_END}:${BACKUP_PART_SIZE}:${BACKUP_PART_GUID}" part_fstype=$(exec_retry 5 0.5 "blkid -s TYPE -o value $part") if [ "${part_fstype}" == "ext4" ]; then ilog "Skipping wipe of persistent partition $part" BACKUP_CREATED=1 continue else ilog "Wipe Partition: part:${part} dev:${dev} pn:${part_number}" # dlog ".... guid:$part_type_guid:$BACKUP_PART_GUID - fs:${part_fstype}" fi fi if [ $WIPE_CEPH_OSDS == "true" -a "$part_type_guid" == $CEPH_JOURNAL_GUID ]; then # Journal partitions require additional wiping. Based on the ceph-manage-journal.py # script in the integ repo (at the ceph/ceph/files/ceph-manage-journal.py location) # wiping 100MB of data at the beginning of the partition should be enough. We also # wipe 100MB at the end, just to be safe. ilog "Wiping Ceph ${part_name} on ${part} start and end with dd" dd if=/dev/zero of=$part bs=1M count=100 2>/dev/null dd if=/dev/zero of=$part bs=1M count=100 seek=$(( `blockdev --getsz $part` / (1024 * 2) - 100 )) 2>/dev/null else ilog "STUBBED Wiping ${part_name} on ${part} start and end with dd" # dd if=/dev/zero of=$part bs=512 count=34 2>/dev/null # dd if=/dev/zero of=$part bs=512 count=34 seek=$((`blockdev --getsz $part` - 34)) 2>/dev/null fi done if [ ${BACKUP_CREATED} -eq 0 -o "${dev}" != "${by_dev}" ]; then ilog "Creating disk label for $dev" parted -s $dev mktable gpt ilog "... done" fi done # Zap all disks except for the install disk for dev in $STOR_DEVS; do if [ ${dev} != "${by_dev}" ] ; then ilog "Zapping ${dev}" sgdisk -Z ${dev} fi done wlog "Destroy otaroot partitions on root disk" for oldrootlabel in otaroot otaroot_1 otaroot_b otaroot_b_1 do oldrootpart=$(blkid --label $oldrootlabel) [ -z "$oldrootpart" ] && continue oldinstdev=/dev/$(lsblk $oldrootpart -n -o pkname) ilog "... destroying ${oldrootpart} on ${oldinstdev}" # sgdisk - Command-line GUID partition table (GPT) manipulator # Zap the entire partition ilog "... zapping ${oldinstdev}" sgdisk -Z ${oldinstdev} # partprobe - inform the OS of partition table changes # root@(none):/# partprobe /dev/sda -s # /dev/sda: gpt partitions 1 2 3 4 5 6 ilog "... probing ${oldinstdev}" partprobe ${oldinstdev} # wipefs - wipe a signature from a device ilog "... wiping ${oldinstdev}" wipefs --all --backup ${oldinstdev} done true %end ########################################################################### %part --interpreter=/bin/bash HOOK_LABEL=" part" . /tmp/lat/ks_functions.sh ilog "****************************************************" ilog "*** Partition - Partition Disks & Create Volumes ***" ilog "****************************************************" ilog "Allocate host partitions (MB) first:$first" ## NOTE: updates to partition sizes need to be also reflected in ## _controller_filesystem_limits() in sysinv/api/controllers/v1/istorconfig.py ROOTFS_PART_PREFIX=${instdev} #check if disk is nvme case $instdev in *"nvme"*) ROOTFS_PART_PREFIX=${instdev}p ;; esac ########################################################### # From pre_disk_controller.cfg ########################################################### # Only controllers have a persistent partition if [ "${controller}" = true ] ; then PLATFORM_BACKUP_SIZE=${DEFAULT_PERSISTENT_SIZE} if [ -z "$persistent_size" ]; then # Default backup partition size in MiB ilog "Platform Backup persistent size not on command line ; defaulting to ${DEFAULT_PERSISTENT_SIZE}" persistent_size=${DEFAULT_PERSISTENT_SIZE} fi if [ ${persistent_size} -lt ${DEFAULT_PERSISTENT_SIZE} ] ; then wlog "Cannot set persistent_size smaller than default size of ${DEFAULT_PERSISTENT_SIZE} KB" else PLATFORM_BACKUP_SIZE=${persistent_size} fi ilog "Platform Backup partition size: ${PLATFORM_BACKUP_SIZE}" if [ -d /sys/firmware/efi ] ; then ilog "UEFI Firmware" else ilog "BIOS Firmware" fi if [ ${BACKUP_CREATED} -eq 0 ] ; then ilog "Platform Backup partition CREATED" else BACKUP_PERSISTED=1 ilog "Platform Backup Partition PERSISTED" fi grub_pt_update end=$(($first+($PLATFORM_BACKUP_SIZE*1024*1024/$lsz)-1)) a="$a -n $p:$first:$end -c $p:platform_backup" fi # Auto expand grub_pt_update end=$last a="$a -n $p:$first:$end -c $p:plat_pv -t $p:8E00" dlog "Partition Table: ${a}" STOR_DEVS=$(echo "$STOR_DEVS" | xargs -n 1 | sort -u | xargs) [ -z "$STOR_DEVS" ] && report_failure_with_msg "No storage devices available." STOR_DEV_FDS="$stdout" for dev in $STOR_DEVS; do exec {fd}>$dev || report_failure_with_msg "Error creating file descriptor for $dev." STOR_DEV_FDS="$STOR_DEV_FDS $fd" done ilog "STOR_DEV_FDS Updated ; $STOR_DEV_FDS" ##################################################################### # From pre_disk_setup_tail.cfg ##################################################################### # Log info about system state at end of partitioning operation. # From pre_disk_setup_tail.cfg for dev in $STOR_DEVS; do log "Partition table at end of script for $dev is:" parted -s $dev unit mib print >> ${LOGFILE} done # Close all FDs and wait for udev to reshuffle all partitions. # wlog "Releasing storage device locks and FDs." #for fd in $STOR_DEV_FDS #do # flock -u "$fd" # exec {fd}>&- #done sleep 2 udevadm settle --timeout=300 || report_failure_with_msg "udevadm settle failed" lsblk -o name,mountpoint,label,size,uuid # Rescan LVM cache to avoid warnings for VGs that were recreated. pvscan --cache 2>/dev/null true %end ########################################################################### %mkfs --interpreter=/bin/bash HOOK_LABEL="mkfs" . /tmp/lat/ks_functions.sh ilog "****************************************************" ilog "** Mkfs - Create Volume Groups & Logical Volumes **" ilog "****************************************************" ####################################################### # From pre_disk_aio ###################################################### # TODO: Remove this duplicate for next update BACKUP_PART_GUID="BA5EBA11-0000-1111-2222-000000000002" # TODO: This causes a kernel panic # Action: Reverify # let -i gb=1024*1024*1024 gb=1073741824 ilog "LAT size parameters: FSZ=${FSZ} BSZ=${BSZ} RSZ=${RSZ} VSZ=${VSZ} gb:${gb}" if [ "${controller}" = true ] ; then LOG_VOL_SIZE=8000 SCRATCH_VOL_SIZE=16000 if [ ! -z "$persistent_size" ]; then # Default backup partition size in MiB persistent_size=${DEFAULT_PERSISTENT_SIZE} fi # PLATFORM_BACKUP_SIZE=${persistent_size} ilog "Persistent Size: $persistent_size ${PLATFORM_BACKUP_SIZE}" fi if [ "${aio}" = true ] ; then ## ## NOTE: updates to partition sizes need to be also reflected in ## - config/.../sysinv/conductor/manager.py:create_controller_filesystems() ## - 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 ## ## ## NOTE TO REVIEWERS: ## This section was talen from CentOS and needs to be updated for Debian. ## ##*********************************************************************** ## Large disk install (for disks over 240GB) ## - DB size is doubled to allow for upgrades ## ## BACKUP_OVERHEAD = 5GiB ## DEFAULT_PLATFORM_STOR_SIZE = 10GiB ## DEFAULT_DATABASE_STOR_SIZE = 10GiB ## BACKUP = DEFAULT_DATABASE_STOR_SIZE + ## DEFAULT_PLATFORM_STOR_SIZE + ## BACKUP_OVERHEAD = 25GiB ## LOG_VOL_SIZE = 8GiB ## SCRATCH_VOL_SIZE = 16GiB ## RABBIT_LV = 2GiB ## DEFAULT_EXTENSION_STOR_SIZE = 1GiB ## KUBERNETES_DOCKER_STOR_SIZE = 30GiB ## DOCKER_DISTRIBUTION_STOR_SIZE = 16GiB ## ETCD_STOR_SIZE = 5GiB ## CEPH_MON_SIZE = 20GiB ## KUBELET_STOR_SIZE = 10GiB ## DC_VAULT_SIZE = 15GiB ## RESERVED_PE = 16MiB (based on pesize=32768) ## ## CGCS_PV_SIZE = (10 + 2*10 + 25 + 8 + 16 + 2 + 1 + 30 + 16 + 5 + 20 + 10 + 15)GiB + 16MiB/1024 = 178.02GiB ## ##*********************************************************************** ## Small disk install - (for disks below 240GB) ## - DB size is doubled to allow for upgrades ## ## DEFAULT_PLATFORM_STOR_SIZE = 10GiB ## DEFAULT_SMALL_DATABASE_STOR_SIZE = 5GiB ## DEFAULT_SMALL_BACKUP_STOR_SIZE = 20GiB ## ## LOG_VOL_SIZE = 8GiB ## SCRATCH_VOL_SIZE = 16GiB ## RABBIT_LV = 2GiB ## DEFAULT_EXTENSION_STOR_SIZE = 1GiB ## KUBERNETES_DOCKER_STOR_SIZE = 30GiB ## DOCKER_DISTRIBUTION_STOR_SIZE = 16GiB ## ETCD_STOR_SIZE = 5GiB ## CEPH_MON_SIZE = 20GiB ## KUBELET_STOR_SIZE = 10GiB ## DC_VAULT_SIZE = 15GiB ## RESERVED_PE = 16MiB (based on pesize=32768) ## ## CGCS_PV_SIZE = (10 + 2*5 + 20 + 8 + 16 + 2 + 1 + 30 + 16 + 5 + 20 + 10 + 15)GiB + 16MiB/1024 = 163.02GiB ## ##*********************************************************************** ## Tiny disk install - (for disks below 154GB) ## ## NOTE: Tiny disk setup is mainly for StarlingX running in QEMU/KVM VM. ## ## DEFAULT_TINY_PLATFORM_STOR_SIZE = 1GiB ## DEFAULT_TINY_DATABASE_STOR_SIZE = 1GiB ## DEFAULT_TINY_BACKUP_STOR_SIZE = 1GiB ## ## LOG_VOL_SIZE = 3GiB ## SCRATCH_VOL_SIZE = 2GiB ## RABBIT_LV = 2GiB ## DEFAULT_EXTENSION_STOR_SIZE = 1GiB ## TINY_KUBERNETES_DOCKER_STOR_SIZE = 20GiB ## TINY_DOCKER_DISTRIBUTION_STOR_SIZE = 8GiB ## TINY_ETCD_STOR_SIZE = 1GiB ## TINY_KUBELET_STOR_SIZE = 2GiB ## ## CGCS_PV_SIZE = (1 + 2*1 + 1 + 3 + 2 + 2 + 1 + 20 + 8 + 1 + 2)GiB = 43GiB ## ## MINIMUM_TINY_DISK_SIZE = CGCS_PV_SIZE + ROOTFS_SIZE + EFI_SIZE + BOOT_SIZE + PLATFORM_BACKUP_SIZE ## = 43 + 15 + 0.3 + 0.5 + 1 = 60GiB # TODO: create a log representing 'free space" on self expand partition. # TODO: Do the math for this new environment # The default disk size thresholds must align with the ones in # config/.../sysinv/common/constants.py # which are DEFAULT_SMALL_DISK_SIZE # MINIMUM_SMALL_DISK_SIZE default_small_disk_size=240 minimum_small_disk_size=196 sz=$(blockdev --getsize64 ${instdev}) ilog "install disk size:$sz gb:$gb" # Round CGCS_PV_SIZE to the closest upper value that can be divided by 1024. if [ $sz -gt $(($default_small_disk_size*$gb)) ] ; then ilog "Large disk: CGCS_PV_SIZE=179GiB*1024=183296" CGCS_PV_SIZE=183296 elif [ $sz -ge $(($minimum_small_disk_size*$gb)) ] ; then ilog "Small disk: CGCS_PV_SIZE=164GiB*1024=167936" CGCS_PV_SIZE=167936 else ilog "Tiny disk: CGCS_PV_SIZE=43GiB*1024=44032" # Using a disk with a size under 60GiB will fail. CGCS_PV_SIZE=44032 LOG_VOL_SIZE=3000 SCRATCH_VOL_SIZE=2000 PLATFORM_BACKUP_SIZE=1000 fi elif [ "${controller}" = true ] ; then LOG_VOL_SIZE=8000 SCRATCH_VOL_SIZE=16000 fi ilog "CGCS_PV_SIZE : ${CGCS_PV_SIZE}" ilog "SCRATCH_VOL_SIZE : ${SCRATCH_VOL_SIZE}" ilog "ROOTFS_SIZE : ${ROOTFS_SIZE}" ilog "LOG_VOL_SIZE : ${LOG_VOL_SIZE}" ilog "PLATFORM_BACKUP_SIZE : ${PLATFORM_BACKUP_SIZE}" ilog "BACKUP_PART : ${BACKUP_PART}" ilog "BACKUP_PART_NO : ${BACKUP_PART_NO}" ilog "BACKUP_PART_LABEL : ${BACKUP_PART_LABEL}" ilog "BACKUP_PART_GUID : ${BACKUP_PART_GUID}" if [ "${controller}" = true ] ; then ilog "Backup Partition : ${BACKUP_PART}" if [ ${BACKUP_PERSISTED} -eq 0 ] ; then # TODO: Was hanging when the flock preceeded the sgdisk. # Action: Reverify # flock ${instdev} sgdisk --change-name=${BACKUP_PART_NO}:"${BACKUP_PART_LABEL}" --typecode=${BACKUP_PART_NO}:"${BACKUP_PART_GUID}" ${instdev} || exit 1 cat</tmp/backup-guid-change.sh ilog "Updating backup partition GUID" sgdisk --change-name=${BACKUP_PART_NO}:"${BACKUP_PART_LABEL}" --typecode=${BACKUP_PART_NO}:"${BACKUP_PART_GUID}" ${instdev} || exit 1 EOF fi fi ilog "cgts--vg-log--lv size: ${LOG_VOL_SIZE} MB" ilog "cgts--vg-scratch--lv : ${SCRATCH_VOL_SIZE} MB" ilog "Install disk: ${instdev} ; current partition index:$pi" vg="volume group" lv="logical volume" dev=$(get_disk "${instdev}") # Only init Platform Backup partition filesystem if the partition was just created pi=$((pi+1)) if [ ${BACKUP_PERSISTED} -eq 0 ] ; then ilog "Platform Backup filesystem init ${dev}${pi}" mkfs.ext4 -F -L platform_backup ${dev}${pi} [ ${?} -ne 0 ] && report_failure_with_msg "Failed Platform Backup partition filesystem init ${dev}${pi}" fi # Create Volume Group pi=$((pi+1)) # Log important LVM config settings log_lvm_conf ilog "Create ${vg} 'cgts-vg' ${dev}${pi} ; $STOR_DEV_FDS" exec_no_fds "$STOR_DEV_FDS" "vgcreate -y --force cgts-vg ${dev}${pi} 2>/dev/null" 5 0.5 [ ${?} -ne 0 ] && report_failure_with_msg "Failed to create ${vg} 'cgts-vg' ${dev}${pi}" # Create and Init the '/var/log' logical volume ilog "Create ${lv} 'log-lv' ; $STOR_DEV_FDS" exec_no_fds "$STOR_DEV_FDS" "lvcreate -y -n log-lv -L ${LOG_VOL_SIZE}MB cgts-vg 2>/dev/null" 5 0.5 [ ${?} -ne 0 ] && report_failure_with_msg "Failed to create ${lv} 'log-lv'" ilog "InitFs ${lv} 'log-lv'" mkfs.ext4 -F /dev/cgts-vg/log-lv [ ${?} -ne 0 ] && report_failure_with_msg "Failed to init ${lv} 'log-lv'" # Create and init the '/scratch' logical volume ilog "Create ${lv} 'scratch-lv' ; $STOR_DEV_FDS" exec_no_fds "$STOR_DEV_FDS" "lvcreate -y -n scratch-lv -L ${SCRATCH_VOL_SIZE}MB cgts-vg 2>/dev/null" 5 0.5 [ ${?} -ne 0 ] && report_failure_with_msg "Failed to create ${lv} 'scratch-lv'" ilog "InitFs ${lv} 'scratch-lv'" mkfs.ext4 -F /dev/cgts-vg/scratch-lv [ ${?} -ne 0 ] && report_failure_with_msg "Failed to init ${lv} 'scratch-lv'" ####################################################################### # From post_lvm_on_rootfs.cfg (all hosts) ####################################################################### # 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 perl -0777 -i -pe 's:(# Example\n)\t# preferred_names:$1 preferred_names:m' /etc/lvm/lvm.conf # Get the LVM disk partition and add it to the lvm.conf file LV_ROOTDISK=$(pvdisplay --select 'vg_name=cgts-vg' -C -o pv_name --noheadings) [ -z ${LV_ROOTDISK} ] && report_failure_with_msg "Failed to identify logical volume rootdisk via pvdisplay" # Edit the LVM config so LVM only looks for LVs on ${LV_ROOTDISK} ilog "Edit the LVM config so LVM only looks for LVs on the root disk" sed -i "s#^\( *\)global_filter = \[.*#\1global_filter = [ \"a|${LV_ROOTDISK}|\", \"r|.*|\" ]#" /etc/lvm/lvm.conf # Log important LVM config settings log_lvm_conf true %end ########################################################################### %post --interpreter=/bin/bash HOOK_LABEL="post" . /tmp/lat/ks_functions.sh ilog "****************************************************" ilog "**** Post - Traits & Platform Config File update **" ilog "****************************************************" set -- `env` dlog "env: $*" if false ; then # TODO: Why does LAT break into prompt when I do this for e in $*; do case "$e" in *=*) eval $e 2>/dev/null log "env : $e" ;; esac done fi ilog "Install traits: $traits" # Set node traits' state [ "${controller}" = true ] && ilog "Controller Function" [ "${storage}" = true ] && ilog "Storage Function" [ "${worker}" = true ] && ilog "Worker Function" [ "${lowlatency}" = true ] && ilog "Low Latency Function" [ "${controller}" = true -a ${worker} = true ] && aio=true # Parse traits to nodetype, subfunction and system_type # ----------------------------------------------------- # Set nodetype from traits if [ "${controller}" = true ] ; then nodetype=${TRAIT__CONTROLLER} ilog "Controller Function" elif [ "${storage}" = true ] ; then nodetype=${TRAIT__STORAGE} ilog "Storage Function" elif [ "${worker}" = true ] ; then nodetype=${TRAIT__WORKER} else elog "No personality traits specified ; defaulting to All-In-One" controller=true worker=true nodetype=${TRAIT__CONTROLLER} fi ilog "nodetype=${nodetype}" # Set system type and subfunction subfunction="" system_type="" system_mode="simplex" [ "${controller}" = true -a "${worker}" = true ] && aio=true if [ "${aio}" = true ] ; then ilog "${SYSTEM_TYPE__AIO} System" system_type="${SYSTEM_TYPE__AIO}" if [ "${rt}" = true ] ; then subfunction="${SUBFUNCTION__AIO_LOWLATENCY}" else subfunction="${SUBFUNCTION__AIO}" fi else ilog "${SYSTEM_TYPE__STANDARD} System" system_type="${SYSTEM_TYPE__STANDARD}" if [ "${worker}" = true ] ; then subfunction=${SUBFUNCTION__WORKER} elif [ "${storage}" = true ] ; then subfunction=${SUBFUNCTION__STORAGE} else subfunction=${SUBFUNCTION__CONTROLLER} fi fi ilog "subfunction=${subfunction}" ilog "system_type=${system_type}" ilog "system_mode=${system_mode}" # Create and Update /etc/platform/platform.conf # --------------------------------------------- if [ -e "${PLATFORM_CONF}" ] ; then wlog "removing temp platform.conf" fi ################################################################# # From post_platform_conf_controller.cfg # From post_platform_conf_aio.cfg # From post_platform_conf_aio_lowlatency.cfg ################################################################# ilog "create platform.conf and set personality traits" [ ! -d "/etc/platform" ] && mkdir -p -m 0775 /etc/platform cat < ${PLATFORM_CONF} nodetype=${nodetype} subfunction=${subfunction} system_type=${system_type} system_mode=${system_mode} EOF # Set http port # Persist the default http port number to platform configuration. # This will get overwritten when by manifest during sw configuration phase. http_port=$(echo $(cat /proc/cmdline |xargs -n1 echo |grep '^insturl=' | sed -r 's#^[^/]*://[^/]*:([0-9]*)/.*#\1#')) update_platform_conf "http_port=${http_port}" # TODO: Set sw release update_platform_conf "sw_release=xxxPLATFORM_RELEASExxx" ############################################################# # From post_common.cfg (all hosts) ############################################################# # Should handle controller-0 install from external server and USB is_system_node_install if [ ${?} -ne 0 ] ; then # Unset the hostname rm /etc/hostname if [ "${controller}" = true ] ; then echo "controller-0" > /etc/hostname fi fi # TODO: is this needed with LAT ?? # 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 if [ "${controller}" = true ] ; then # Add the WRCP GUID to the Platform backup partition. BACKUP_PART_CHANGE_FILE="/tmp/backup-guid-change.sh" if [ -f "${BACKUP_PART_CHANGE_FILE}" ] ; then ilog "Found ${BACKUP_PART_CHANGE_FILE} ; running to set Platform backup to persist" chmod 744 ${BACKUP_PART_CHANGE_FILE} # ISSUE: This hangs LAT with 'flock /dev/sda' # TODO : Discuss with Architects # # flock /dev/sda sgdisk --change-name=6:"Platform Backup" --typecode=6:"BA5EBA11-0000-1111-2222-000000000002" /dev/sda . ${BACKUP_PART_CHANGE_FILE} 2>/dev/null sleep 2 parted -l 2>/dev/null fi fi blkid >> ${LOGFILE} # TODO: See if other post_common.cfg content is needed true %end ########################################################################### %post --interpreter=/bin/bash HOOK_LABEL="post" . /tmp/lat/ks_functions.sh ilog "****************************************************" ilog "*** Post - Set Kernel Args ****" ilog "****************************************************" ########################################################### # From post_kernel_controller.cfg # From post_kernel_aio_worker.cfg ########################################################### . /etc/platform/platform.conf # Prepare the disk boot kernel comand line # ---------------------------------------- export KERN_OPTS="" ilog "Building KERN_OPTS" function add_kernel_option() { option="${1}" ilog "... adding: ${option}" # avoid adding leading space on first option if [ "${KERN_OPTS}" = "" ] ; then KERN_OPTS="${option}" else KERN_OPTS="${KERN_OPTS} ${option}" 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) security_feature="" # Handle security options # TODO: Create a list and loop over it security_options="nopti nospectre_v2 nospectre_v1" for o in ${security_options} do grep -q ${o} /proc/cmdline if [ $? -eq 0 ]; then add_kernel_option "${o}" if [ "${security_feature}" = "" ] ; then security_feature="${o}" else security_feature="${security_feature} ${o}" fi fi done # TODO: Remove as it turns out that this is not added by kickstarts. # Remove all reference to 'security_feature' above as well. # # add security_feature to platform.conf ; be sure not to add as empty. # [ -z "${security_feature}" ] && security_feature=none # update_platform_conf "security_feature=${security_feature}" [ "${KERN_OPTS}" != "" ] && ilog "Learned kernel params: ${KERN_OPTS}" if [ "${aio}" = true ] ; then ilog "Adding ${SYSTEM_TYPE__AIO} kernel options" if [ -e /etc/init.d/cpumap_functions.sh ] ; then # 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}') ilog "cpumap: n_cpus:${n_cpus}" n_numa=$(ls -d /sys/devices/system/node/node* 2>/dev/null | wc -l) ilog "cpumap: n_numa:${n_numa}" KERN_OPTS="${KERN_OPTS} iommu=pt" 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 [ "${aio}" = true -a ${n_cpus} -lt 4 ]; then report_failure_with_msg "At least 4 CPUs are required for ${SYSTEM_TYPE__AIO} node." fi # Add kernel options for cpu isolation / affinity if [ ${n_cpus} -gt 1 ] ; then base_cpulist=$(platform_expanded_cpu_list) ilog "cpumap: base_cpulist: ${base_cpulist}" base_cpumap=$(cpulist_to_cpumap ${base_cpulist} ${n_cpus}) ilog "cpumap: base_cpumap: ${base_cpumap}" avp_cpulist=$(vswitch_expanded_cpu_list) ilog "cpumap: avp_cpulist:${avp_cpulist}" if [ -e /etc/vswitch/vswitch.conf ] ; then # Update vswitch.conf sed -i "s/^VSWITCH_CPU_LIST=.*/VSWITCH_CPU_LIST=\"${avp_cpulist}\"/" /etc/vswitch/vswitch.conf else wlog "Missing /etc/vswitch/vswitch.conf ; update bypassed" fi norcu_cpumap=$(invert_cpumap ${base_cpumap} ${n_cpus}) ilog "cpumap: norcu_cpumap:${norcu_cpumap}" norcu_cpulist=$(cpumap_to_cpulist ${norcu_cpumap} ${n_cpus}) ilog "cpumap: norcu_cpulist:${norcu_cpulist}" if [ "${lowlatency}" = true ]; then KERN_OPTS="${KERN_OPTS} nohz_full=${norcu_cpulist}" fi KERN_OPTS="${KERN_OPTS} rcu_nocbs=${norcu_cpulist}" KERN_OPTS="${KERN_OPTS} kthread_cpus=${base_cpulist}" KERN_OPTS="${KERN_OPTS} irqaffinity=${norcu_cpulist}" fi else wlog "Missing /etc/init.d/cpumap_functions.sh ; cpumap setup bypassed" fi # Add kernel options to set NMI watchdog if [ "${lowlatency}" = true ] ; then add_kernel_option "nmi_watchdog=0 softlockup_panic=0" else add_kernel_option "nmi_watchdog=panic,1 softlockup_panic=1" fi if [[ "$(dmidecode -s system-product-name)" =~ ^ProLiant.*Gen8$ ]]; then add_kernel_option "intel_iommu=on,eth_no_rmrr" else add_kernel_option "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 add_kernel_option "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 add_kernel_option "kvm-intel.eptad=0" fi # k8s updates: #KERN_OPTS="${KERN_OPTS} cgroup_disable=memory" add_kernel_option "user_namespace.enable=1" # Add kernel option to avoid jiffies_lock contention on real-time kernel if [ "${lowlatency}" = true ] ; then add_kernel_option "skew_tick=1" fi elif [ "${controller}" = true ] ; then ilog "Adding ${TRAIT__CONTROLLER} function kernel options" ## Custom kernel options add_kernel_option "intel_iommu=off usbcore.autosuspend=-1" ## Setup the loop module to support up to 15 partitions so that we ## can enable the customer to manually resize images if needed. ## add_kernel_option "loop.max_part=15" ## Add kernel options to ensure an selinux is disabled add_kernel_option "selinux=0 enforcing=0" # Add kernel options to ensure NMI watchdog is enabled, if supported add_kernel_option "nmi_watchdog=panic,1 softlockup_panic=1" # Add kernel option to panic on a softdog timeout add_kernel_option "softdog.soft_panic=1" # 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 [ $? -ne 0 ] && add_kernel_option "biosdevname=0" # k8s updates add_kernel_option "user_namespace.enable=1" else wlog "TODO: system node install type kernel parameters, worker and storage" fi # TODO: Is this needed ? Certainlty not the Centos part # 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 # The uncommented code below updates the disk boot command for LAT ilog "Adding these kernel params to disk boot: ${KERN_OPTS}" if [ -n "${KERN_OPTS}" ] ; then # Add 'set kernel_params="${kernel_params} ${KERN_OPTS}"' to disk # boot command line by /boot/efi/EFI/BOOT/grub.cfg update grep -q "set kernel_params=.*${KERN_OPTS}" /boot/efi/EFI/BOOT/grub.cfg if [ ${?} -ne 0 ]; then sed -i "/set kernel_params=.*/a set kernel_params=\"\${kernel_params} ${KERN_OPTS}\"" /boot/efi/EFI/BOOT/grub.cfg fi else wlog "no kernel options added" fi ###################################################################### # From post_system_aio ###################################################################### if [ "${aio}" = true ] ; then ## 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)}') ilog "${SYSTEM_TYPE__AIO} MemTotal:${TOTALMEM}" 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 ilog "${SYSTEM_TYPE__AIO} Reserved Memory: ${RESERVEDMEM}" 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 worker_reserved=$(grep WORKER_BASE_RESERVED /etc/platform/worker_reserved.conf) ilog "${SYSTEM_TYPE__AIO} '${worker_reserved}'" # 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 worker_cpu_list=$(grep WORKER_CPU_LIST /etc/platform/worker_reserved.conf) ilog "${SYSTEM_TYPE__AIO} '${worker_cpu_list}'" fi true %end ########################################################################### %post --interpreter=/bin/bash HOOK_LABEL="post" . /tmp/lat/ks_functions.sh ilog "****************************************************" ilog "*** Post - Interface Setup ***" ilog "****************************************************" ########################################################### # From post_pxeboot_controller # From post_net_common.cfg ########################################################### # TODO: Not needed on a USB install. # TODO: Need to adjust fault handling or condition on USB install. # Obtain the boot interface from the PXE boot BOOTIF=$(cat /proc/cmdline |xargs -n1 echo |grep BOOTIF=) BOOTIF=${BOOTIF#BOOTIF=} mgmt_dev=lo mgmt_vlan=0 if [ -n "$BOOTIF" ] ; then BOOTIF=$(echo $BOOTIF | sed -r -e 's/.*(..-..-..-..-..-..)$/\1/' -e 's/-/:/g') ndev=`ip link show |grep -B 1 $BOOTIF |head -1 |awk '{print $2}' |sed -e 's/://'` if [ -n "$ndev" ] ; then # convert to predictive name mgmt_dev=$(get_iface_from_ethname $ndev) if [ "${mgmt_dev}" == "" ] ; then elog "failed to get predictive altname from ${ndev}" mgmt_dev=${ndev} # get vlan info for system node installs system_node=$(is_system_node_install) if [ "${system_node}" = true ] ; then # Retrieve the management VLAN from sysinv if it exists ilog "Querying system inventory for management vlan id" mgmt_vlan=`curl -sf http://pxecontroller:6385/v1/isystems/mgmtvlan` if [ ${?} -ne 0 ] ; then # TODO: uncomment to force install failure for product # report_failure_with_msg "Unable to communicate with System Inventory REST API. Aborting installation." wlog "ERROR: Unable to communicate with System Inventory REST API." fi fi else ilog "Management Interface: ${ndev} -> ${mgmt_dev}" fi else elog "ERROR:POST: Unable to determine mgmt interface from BOOTIF=$BOOTIF." # TODO: MAKE Default - Should not get here without BOOTIF set ; LAT guarantees that. # report_failure_with_msg "Unable to determine mgmt interface from BOOTIF=$BOOTIF." fi else elog "ERROR:POST: BOOTIF is not set. Unable to determine mgmt interface." # TODO: MAKE Default - Should not get here without BOOTIF set ; LAT guarantees that. fi if [ ! -e "/etc/network/interfaces" ] ; then cat << EOF >> /etc/network/interfaces # This file describes the network interfaces available on the system # and how to activate them. For more information , see interfaces(5) source /etc/network/interfaces.d/* EOF fi if [ ! -d "/etc/network/interfaces.d" ] ; then mkdir -p -m 0775 /etc/network/interfaces.d fi # Build networking scripts, starting with the localhost interface cat << EOF >> /etc/network/interfaces # The loopback network interface auto lo iface lo inet loopback EOF cat << EOF >> /etc/network/interfaces # management network interface allow-hotplug $mgmt_dev auto $mgmt_dev iface $mgmt_dev inet dhcp EOF ilog "Setup network scripts" 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. update_platform_conf "management_interface=$mgmt_dev" # Build networking scripts cat << EOF > /etc/network/interfaces.d/ifcfg-lo auto lo iface lo inet static address 127.0.0.1 netmask 255.0.0.0 post-up echo 0 > /proc/sys/net/ipv6/conf/lo/autoconf; echo 0 > /proc/sys/net/ipv6/conf/lo/accept_ra; echo 0 > /proc/sys/net/ipv6/conf/lo/accept_redirects EOF cat << EOF > /etc/network/interfaces.d/ifcfg-$mgmt_dev auto $mgmt_dev iface $mgmt_dev inet manual pre-up sleep 20 post-up echo 0 > /proc/sys/net/ipv6/conf/lo/autoconf; echo 0 > /proc/sys/net/ipv6/conf/lo/accept_ra; echo 0 > /proc/sys/net/ipv6/conf/lo/accept_redirects 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. update_platform_conf "management_interface=vlan$mgmt_vlan" # Build networking scripts cat << EOF > /etc/network/interfaces.d/ifcfg-lo auto lo iface lo $mgmt_address_family static address 127.0.0.1 netmask 255.0.0.0 post-up echo 0 > /proc/sys/net/ipv6/conf/lo/autoconf; echo 0 > /proc/sys/net/ipv6/conf/lo/accept_ra; echo 0 > /proc/sys/net/ipv6/conf/lo/accept_redirects EOF cat << EOF > /etc/network/interfaces.d/ifcfg-$mgmt_dev auto $mgmt_dev iface $mgmt_dev $mgmt_address_family manual pre-up sleep 20 post-up echo 0 > /proc/sys/net/ipv6/conf/lo/autoconf; echo 0 > /proc/sys/net/ipv6/conf/lo/accept_ra; echo 0 > /proc/sys/net/ipv6/conf/lo/accept_redirects EOF cat << EOF > /etc/network/interfaces.d/ifcfg-vlan$mgmt_vlan auto vlan$mgmt_vlan iface vlan$mgmt_vlan $mgmt_address_family dhcp vlan-raw-device $mgmt_dev pre-up sleep 20 post-up echo 0 > /proc/sys/net/ipv6/conf/lo/autoconf; echo 0 > /proc/sys/net/ipv6/conf/lo/accept_ra; echo 0 > /proc/sys/net/ipv6/conf/lo/accept_redirects EOF fi true %end ########################################################################## %post --interpreter=/bin/bash HOOK_LABEL="post" . /tmp/lat/ks_functions.sh ilog "****************************************************" ilog "*** Post - Kickstart Finalize Install UUID ***" ilog "****************************************************" # Create a uuid specific to this installation ilog "Add install uuid to feed and platform.conf" INSTALL_UUID=`uuidgen` [ ! -d "/var/www/pages/feed/rel-xxxPLATFORM_RELEASExxx" ] && mkdir -p -m 0755 /var/www/pages/feed/rel-xxxPLATFORM_RELEASExxx echo ${INSTALL_UUID} > /var/www/pages/feed/rel-xxxPLATFORM_RELEASExxx/install_uuid update_platform_conf "INSTALL_UUID=${INSTALL_UUID}" # Create first_boot flag touch /etc/platform/.first_boot true %end ########################################################################## %post --interpreter=/bin/bash HOOK_LABEL="post" . /tmp/lat/ks_functions.sh ilog "****************************************************" ilog "*** Post - Log Filesystem Setup ***" ilog "****************************************************" display_volume_info "final" true %end ########################################################################## %post --interpreter=/bin/bash --nochroot HOOK_LABEL="post_nochroot" . /tmp/lat/ks_functions.sh ilog "****************************************************" ilog "*** Post Nochroot - Save Install Scripts and Logs **" ilog "****************************************************" ilog "IMAGE_ROOTFS=${IMAGE_ROOTFS}" get_variable "ostree_repo_fetched" OSTREE_REPO_FETCHED=$? # Fetch ostree if [ "${controller}" = true -a ${OSTREE_REPO_FETCHED} -eq 0 ] ; then $(is_system_node_install) if [ $? -ne 0 ] ; then sw_release="xxxPLATFORM_RELEASExxx" pxeurl=$(echo $insturl | sed -e s/ostree_repo//) # -1 is all commits, positive number is that number of last commits commits="--depth=-1" pull_options="${commits} --mirror" feed="${IMAGE_ROOTFS}/var/www/pages/feed/rel-${sw_release}" repo="${feed}/ostree_repo" mkdir -p "${repo}" ilog "Pull ostree_repo to ${repo}" ostree --repo=${repo} init --mode=archive ostree --repo=${repo} remote add ${instbr} ${insturl} ostree --repo=${repo} pull ${pull_options} ${instbr}:${instbr} # TODO: Figure out a way on the second run /sysroot/ostree/2 # to avoid this error string # # error: Remote configuration for "starlingx" already exists: (in config) # Check for noverifyssl if grep -q noverifyssl /proc/cmdline; then NOVERIFYSSL_WGET_OPT="--no-check-certificate" else NOVERIFYSSL_WGET_OPT="" fi pushd ${feed} # TODO: Remove ; This is temporary until the kernel and initrd are fetched from ostree_repo wget ${NOVERIFYSSL_WGET_OPT} --spider --quiet ${pxeurl}/bzImage [ $? -ne 0 ] && report_failure_with_msg "Failed to find bzImage on pxeboot server ; ${sw_release} ${pxeurl}" wget ${NOVERIFYSSL_WGET_OPT} --reject 'index.html*' --quiet ${pxeurl}/bzImage [ $? -ne 0 ] && report_failure_with_msg "Failed to get bzImage from pxeboot server ; ${sw_release} ${pxeurl}" wget ${NOVERIFYSSL_WGET_OPT} --spider --quiet ${pxeurl}/initrd [ $? -ne 0 ] && report_failure_with_msg "Failed to find initrd on pxeboot server ; ${sw_release} ${pxeurl}" wget ${NOVERIFYSSL_WGET_OPT} --reject 'index.html*' --quiet ${pxeurl}/initrd [ $? -ne 0 ] && report_failure_with_msg "Failed to get initrd from pxeboot server ; ${sw_release} ${pxeurl}" # TODO: Not neeed once the kickstart is in the iso # Save the kickstart cp /${LAT_DIR}/lat-installer.ks ${feed}/kickstart.cfg # This fetch is only needed once because the repo is stored in /var set_variable "ostree_repo_fetched" popd fi fi # Save the install scripts and kickstart logs mount /dev/mapper/cgts--vg-log--lv "${IMAGE_ROOTFS}/${LOG_DIR}" if [ ${?} -ne 0 ] ; then elog "Failed to mount /dev/mapper/cgts--vg-log--lv" else if [ -e "${IMAGE_ROOTFS}/${LOG_DIR}" ]; then ilog "Saving installer data to /${LOG_DIR}" cp -a /${LAT_DIR} ${IMAGE_ROOTFS}/${LOG_DIR} cp /install ${IMAGE_ROOTFS}/${LOG_DIR}/lat else wlog "Could not save installer data" fi umount "${IMAGE_ROOTFS}/${LOG_DIR}" fi # 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' ${IMAGE_ROOTFS}/etc/lvm/lvm.conf #perl -0777 -i -pe 's:(# Example\n)\t# preferred_names:$1 preferred_names:m' ${IMAGE_ROOTFS}/etc/lvm/lvm.conf #sed -i "s#^\( *\)global_filter = \[.*#\1global_filter = [ \"a|${LV_ROOTDISK}|\", \"r|.*|\" ]#" ${IMAGE_ROOTFS}/etc/lvm/lvm.conf true %end