From 19346c232a040e01912e9cc388bb90577023d965 Mon Sep 17 00:00:00 2001 From: Eric MacDonald Date: Sun, 3 Dec 2023 14:46:04 +0000 Subject: [PATCH] Add sysinv query for host's mgmt_ip and hostname based on bootif mac The newly introduced unauthenticated 'mgmt_ip' API in sysinv, as referenced by the 'depends-on' link below, has been added to initiate a query for the current host's management IP and hostname. This information is needed by the kickstart to create a static 'ifcfg-' file so that the management interface is automatically setup on the first boot following a fresh install. The significance of this step lies in enabling a pre-configuration of IPsec on the management network before host configuration takes place. This update also - creates a dhcp ifcfg-pxeboot file to automatically update the management interface with a pxeboot dhcp address. - creates an initial /etc/resolv.conf file with the active controller's floating ip and the pxecontroller ip addresses which are also needed by the IPSec setup pre-configuration following the first reboot after node install. Additionally, this update involves a refinement in terminology. The variable previously named 'mgmt_dev' has been aptly renamed 'boot_dev' to more accurately reflect the nomenclature of the interface in use. Test Plan: PASS: Verify AIO DX install of IPV4 and IPV6 with and without vlans PASS: Verify IPV4 worker node install PASS: Verify management interface 'ifcfg-' file is created - cases: with and without vlan PASS: Verify pxeboot interface 'ifcfg-pxeboot' is created (ipv4 only) PASS: Verify kickstart fails the install if it receives badly formatted sysinv mgmt_ip query or None. PASS: Verify resolve.conf updated with nameserver PASS: Verify resolve.conf updated with nameserver PASS: Verify kickstart logging Depends-On: https://review.opendev.org/c/starlingx/config/+/901981 Story: 2010940 Task: 49162 Change-Id: I429522305fcff66e5c78195f4bf3c5b82826c1d8 Signed-off-by: Eric MacDonald --- kickstart/files/kickstart.cfg | 217 ++++++++++++++++++++++++++-------- 1 file changed, 168 insertions(+), 49 deletions(-) diff --git a/kickstart/files/kickstart.cfg b/kickstart/files/kickstart.cfg index fcc51cc7..6af5e981 100644 --- a/kickstart/files/kickstart.cfg +++ b/kickstart/files/kickstart.cfg @@ -2537,15 +2537,78 @@ ilog "************************************" # Obtain the boot interface from the PXE boot BOOTIF=$(cat /proc/cmdline |xargs -n1 echo |grep BOOTIF=) BOOTIF=${BOOTIF#BOOTIF=} -mgmt_dev=lo +boot_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 + +# host_info is fetched from system inventory by curl using +# the sysinv public api with the boot interface mac address. +# curl -sf http://pxecontroller:6385/v1/ihosts//mgmt_ip +# +# System inventory returns the following quoted string containing +# the hostname, management ip and netmask (prefix) that matches the +# supplied mac address. +# +# " /" +# +# This information is used to create a management network interface +# setup file for /etc/network/interfaces.d/ifcfg_ so that IPSec +# can be configured early in the first reboot following the install. +# Specifically before config / puppet manifests are run. +host_info="" + +# The management ip and netmask are extracted from ${host_info} +mgmt_ip="" +mgmt_nm=0 +mgmt_gw=0 + +if [ -n "${BOOTIF}" ] ; then + # convert xx-xx-xx-xx-xx-xx to xx:xx:xx:xx:xx:xx + BOOTIF=$(echo ${BOOTIF} | sed -r -e 's/.*(..-..-..-..-..-..)$/\1/' -e 's/-/:/g') + if is_system_node_install -eq 0 ; then + get_mgmt_ip_cmd="curl -sf http://pxecontroller:6385/v1/ihosts/${BOOTIF}/mgmt_ip" + host_info=`${get_mgmt_ip_cmd}` + rc=$? + if [ ${rc} -ne 0 ] ; then + elog "Failed command: ${get_mgmt_ip_cmd}" + report_failure_with_msg "Unable to fetch management network IP from System Inventory REST API. Aborting installation. rc:${rc}" + elif [[ ${#host_info} -lt 8 ]] ; then + report_failure_with_msg "Host Info fetched from System Inventory REST API is invalid : [${host_info}]. Aborting installation." + else + # remove unwanted string quotes + ilog "Host Info: ${host_info}" + mgmt_nm=$(echo "${host_info}" | grep -o '"netmask": "[^"]*' | cut -d'"' -f4) + mgmt_ip=$(echo "${host_info}" | grep -o '"address": "[^"]*' | cut -d'"' -f4) + ilog "... mgmt_ip=${mgmt_ip} and mgmt_nm=${mgmt_nm}" + if [ -z "${mgmt_ip}" -o "${mgmt_ip}" == "None" -o -z "${mgmt_nm}" -o "${mgmt_nm}" = "None" ] ; then + report_failure_with_msg "Unable to parse management ip and netmask from sysinv queried mgmt_ip info : value:${host_info}. Aborting Installation." + else + mgmt_gw=$(echo "${mgmt_ip}" | awk -F'.' -v OFS='.' '{$NF=1}1') + ilog "... mgmt_gw=${mgmt_gw}" + fi + + hostname=$(echo "${host_info}" | grep -o '"hostname": "[^"]*' | cut -d'"' -f4) + if [ -z "${hostname}" -o "${hostname}" == "None" ] ; then + report_failure_with_msg "Unable to parse hostname from sysinv queried mgmt_ip info: value:${host_info}. Aborting Installation." + else + ilog "adding ${hostname} to ${IMAGE_ROOTFS}/etc/hostname" + echo "${hostname}" > ${IMAGE_ROOTFS}/etc/hostname + fi + + floating=$(echo "${host_info}" | grep -o '"floating": "[^"]*' | cut -d'"' -f4) + if [ -z "${floating}" -o "${floating}" == "None" ] ; then + report_failure_with_msg "Unable to parse floating ip from sysinv queried mgmt_ip info: value:${host_info}. Aborting Installation." + else + ilog "adding nameserver ${floating} to ${IMAGE_ROOTFS}/etc/resolv.conf" + echo "nameserver ${floating}" >> ${IMAGE_ROOTFS}/etc/resolv.conf + fi + fi + fi + + 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 + boot_dev=$(get_iface_from_ethname ${ndev}) + if [ "${boot_dev}" == "" ] ; then report_failure_with_msg "failed to get predictive altname from ${ndev}" fi # get vlan info for system node installs @@ -2557,19 +2620,19 @@ if [ -n "$BOOTIF" ] ; then if [ ${rc} -ne 0 ] ; then report_failure_with_msg "Unable to communicate with System Inventory REST API. Aborting installation. rc:${rc}" fi - ilog "Management Interface: ${ndev} -> ${mgmt_dev} -> vlan${mgmt_vlan}" + ilog "Pxeboot Interface: ${ndev} -> ${boot_dev} -> vlan${mgmt_vlan}" else - ilog "Management Interface: ${ndev} -> ${mgmt_dev}" + ilog "Pxeboot Interface: ${ndev} -> ${boot_dev}" fi else - report_failure_with_msg "Unable to determine mgmt interface from BOOTIF=$BOOTIF." + report_failure_with_msg "Unable to determine boot interface from BOOTIF=$BOOTIF." fi else - wlog "BOOTIF is not set. Unable to determine mgmt interface." + wlog "BOOTIF is not set. Unable to determine boot interface." fi -ilog "mgmt_dev : $mgmt_dev" -ilog "mgmt_vlan: $mgmt_vlan" +ilog "boot_dev : ${boot_dev}" +ilog "mgmt_vlan: ${mgmt_vlan}" if [ ! -e "${IMAGE_ROOTFS}/etc/network/interfaces" ] ; then cat << EOF >> ${IMAGE_ROOTFS}/etc/network/interfaces @@ -2585,64 +2648,120 @@ fi ilog "Setup network scripts" -if [ $mgmt_vlan -eq 0 ] ; then +# Create the default ipv4 pxeboot network interface setup file +if [[ ${boot_dev} != "lo" && is_system_node_install -eq 0 ]] ; then + + # create a pxeboot network setup script based on the pxeboot assigned ip + pxeboot_ip=$(ip -o -4 addr show ${boot_dev} | awk '{print $4}' | cut -d/ -f1) + ifcfg_file="${IMAGE_ROOTFS}/etc/network/interfaces.d/ifcfg-pxeboot" + ilog "dhcp leased pxeboot_ip is ${pxeboot_ip}" + ilog "Creating dhcp pxeboot ${ifcfg_file}" + cat << EOF > ${ifcfg_file} +auto ${boot_dev}:2 +iface ${boot_dev}:2 inet dhcp + post-up echo 0 > /proc/sys/net/ipv6/conf/${boot_dev}/autoconf; echo 0 > /proc/sys/net/ipv6/conf/${boot_dev}/accept_ra; echo 0 > /proc/sys/net/ipv6/conf/${boot_dev}/accept_redirects +EOF + + # add the pxecontroller ip address to /etc/resolv.conf + output=$(nslookup pxecontroller | grep "Name:" -C 1 | grep Address) + if [ -z "${output}" ] ; then + wlog "nslookup pxecontroller did not yield an ip address" + else + pxeboot_gw=$(echo "${output}" | awk '{print $2}') + ilog "adding nameserver ${pxeboot_gw} to ${IMAGE_ROOTFS}/etc/resolv.conf" + echo "nameserver ${pxeboot_gw}" >> ${IMAGE_ROOTFS}/etc/resolv.conf + fi + +fi + +# Check if this is a vlan setup +if [ ${mgmt_vlan} -eq 0 ] ; then + + # Not vlan path # 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" + update_platform_conf "management_interface=${boot_dev}" # Build networking scripts cat << EOF > ${IMAGE_ROOTFS}/etc/network/interfaces.d/ifcfg-lo auto lo iface lo inet loopback EOF - -if [ $mgmt_dev != "lo" ]; then - ilog "Creating ${IMAGE_ROOTFS}/etc/network/interfaces.d/ifcfg-$mgmt_dev" - cat << EOF > ${IMAGE_ROOTFS}/etc/network/interfaces.d/ifcfg-$mgmt_dev -auto $mgmt_dev -iface $mgmt_dev inet dhcp - post-up echo 0 > /proc/sys/net/ipv6/conf/$mgmt_dev/autoconf; echo 0 > /proc/sys/net/ipv6/conf/$mgmt_dev/accept_ra; echo 0 > /proc/sys/net/ipv6/conf/$mgmt_dev/accept_redirects + if [[ ${boot_dev} != "lo" && is_system_node_install -eq 0 ]] ; then + # setup the management interface with the sysinv supplied static address + if [ -n "${host_info}" ] ; then + ifcfg_file="${IMAGE_ROOTFS}/etc/network/interfaces.d/ifcfg-${boot_dev}" + ilog "Creating static mgmt ${ifcfg_file}" + cat << EOF > ${ifcfg_file} +auto ${boot_dev} +iface ${boot_dev} inet static + address ${mgmt_ip} + netmask ${mgmt_nm} + gateway ${mgmt_gw} + post-up echo 0 > /proc/sys/net/ipv6/conf/${boot_dev}/autoconf; echo 0 > /proc/sys/net/ipv6/conf/${boot_dev}/accept_ra; echo 0 > /proc/sys/net/ipv6/conf/${boot_dev}/accept_redirects EOF -fi + fi + else + # Is a pxeboot but not a system node install - likely controller-0 + # Setup boot interface with DHCP so we can log into the server following the install. + # This will get changed during ansible bootstrap + ifcfg_file=${IMAGE_ROOTFS}/etc/network/interfaces.d/ifcfg-${boot_dev} + ilog "Creating dhcp mgmt ${ifcfg_file}" + cat << EOF > ${ifcfg_file} +auto ${boot_dev} +iface ${boot_dev} inet dhcp + post-up echo 0 > /proc/sys/net/ipv6/conf/${boot_dev}/autoconf; echo 0 > /proc/sys/net/ipv6/conf/${boot_dev}/accept_ra; echo 0 > /proc/sys/net/ipv6/conf/${boot_dev}/accept_redirects +EOF + fi else # vlan - ilog "Configuring vlan: mgmt_iface=vlan$mgmt_vlan" + ilog "Configuring vlan: boot_iface=vlan${mgmt_vlan}" # Check whether to use inet or inet6 ipv6_addr=$(dig +short AAAA controller.internal) - if [[ -n "$ipv6_addr" ]] + if [[ -n "${ipv6_addr}" ]] then - mgmt_address_family=inet6 + boot_address_family=inet6 ipv6init=yes dhcpv6c=yes else - mgmt_address_family=inet + boot_address_family=inet ipv6init=no dhcpv6c=no 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" + update_platform_conf "management_interface=vlan${mgmt_vlan}" # Build networking scripts cat << EOF > ${IMAGE_ROOTFS}/etc/network/interfaces.d/ifcfg-lo auto lo -iface lo $mgmt_address_family loopback +iface lo ${boot_address_family} loopback EOF - cat << EOF > ${IMAGE_ROOTFS}/etc/network/interfaces.d/ifcfg-$mgmt_dev -auto $mgmt_dev -iface $mgmt_dev $mgmt_address_family manual - post-up echo 0 > /proc/sys/net/ipv6/conf/$mgmt_dev/autoconf; echo 0 > /proc/sys/net/ipv6/conf/$mgmt_dev/accept_ra; echo 0 > /proc/sys/net/ipv6/conf/$mgmt_dev/accept_redirects + ifcfg_file="${IMAGE_ROOTFS}/etc/network/interfaces.d/ifcfg-${boot_dev}" + ilog "Creating manual mgmt ${ifcfg_file}" + cat << EOF > ${ifcfg_file} +auto ${boot_dev} +iface ${boot_dev} ${boot_address_family} manual + address ${mgmt_ip} + netmask ${mgmt_nm} + gateway ${mgmt_gw} + post-up echo 0 > /proc/sys/net/ipv6/conf/${boot_dev}/autoconf; echo 0 > /proc/sys/net/ipv6/conf/${boot_dev}/accept_ra; echo 0 > /proc/sys/net/ipv6/conf/${boot_dev}/accept_redirects EOF - cat << EOF > ${IMAGE_ROOTFS}/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 - post-up echo 0 > /proc/sys/net/ipv6/conf/vlan$mgmt_vlan/autoconf; echo 0 > /proc/sys/net/ipv6/conf/vlan$mgmt_vlan/accept_ra; echo 0 > /proc/sys/net/ipv6/conf/vlan$mgmt_vlan/accept_redirects + ifcfg_file="${IMAGE_ROOTFS}/etc/network/interfaces.d/ifcfg-vlan${mgmt_vlan}" + ilog "Creating static mgmt vlan ${ifcfg_file}" + cat << EOF > ${ifcfg_file} +auto vlan${mgmt_vlan} +iface vlan${mgmt_vlan} ${boot_address_family} static + address ${mgmt_ip} + netmask ${mgmt_nm} + gateway ${mgmt_gw} + vlan-raw-device ${boot_dev} + post-up echo 0 > /proc/sys/net/ipv6/conf/vlan${mgmt_vlan}/autoconf; echo 0 > /proc/sys/net/ipv6/conf/vlan${mgmt_vlan}/accept_ra; echo 0 > /proc/sys/net/ipv6/conf/vlan${mgmt_vlan}/accept_redirects EOF # Reject DHCPOFFER from DHCP server that doesn't send @@ -2653,24 +2772,24 @@ EOF echo "send dhcp6.client-id = concat(00:03:00, hardware);" >>/etc/dhcp/dhclient.conf echo "send dhcp-client-identifier = concat(00:03:00, hardware);" >>/etc/dhcp/dhclient.conf - # Bring up the mgmt vlan so that a dhcp lease is acquired and an address is + # Bring up the boot 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 - ilog "mgmt_iface=vlan$mgmt_vlan" - ilog "mgmt_address_family: $mgmt_address_family" + boot_iface=vlan${mgmt_vlan} + ilog "boot_iface=vlan${mgmt_vlan}" + ilog "boot_address_family: ${boot_address_family}" - dhclient_family=$([[ $mgmt_address_family == "inet" ]] && echo -4 || echo -6) - ilog "dhclient_family: $dhclient_family" - ilog "ip link add link $mgmt_dev name $mgmt_iface type vlan id $mgmt_vlan" + dhclient_family=$([[ ${boot_address_family} == "inet" ]] && echo -4 || echo -6) + ilog "dhclient_family: ${dhclient_family}" + ilog "ip link add link ${boot_dev} name ${boot_iface} type vlan id ${mgmt_vlan}" - ip link add link $mgmt_dev name $mgmt_iface type vlan id $mgmt_vlan + ip link add link ${boot_dev} name ${boot_iface} type vlan id ${mgmt_vlan} - ilog "ip link set up dev $mgmt_iface" - ip link set up dev $mgmt_iface + ilog "ip link set up dev ${boot_iface}" + ip link set up dev ${boot_iface} timeout_value=60 - dhclient_request="/usr/sbin/dhclient $dhclient_family $mgmt_iface" + dhclient_request="/usr/sbin/dhclient $dhclient_family $boot_iface" ilog "timeout ${timeout_value} ${dhclient_request}" timeout ${timeout_value} ${dhclient_request} rc=${?}