From 79070cfa7d773cafcddc536dbdc06a4869a6d306 Mon Sep 17 00:00:00 2001 From: Frank Brehm Date: Tue, 23 Apr 2024 17:07:19 +0200 Subject: [PATCH] Adding postinstall script for finishing network installation on multihomed Linux VMs. --- misc/switch-to-new.dnsmaster.pp-dns.com.sh | 291 +++++++++++++++++++++ postinstall-scripts/finish-network.sh | 219 ++++++++++++++++ postinstall-scripts/network-data.csv | 75 ++++++ 3 files changed, 585 insertions(+) create mode 100755 misc/switch-to-new.dnsmaster.pp-dns.com.sh create mode 100755 postinstall-scripts/finish-network.sh create mode 100644 postinstall-scripts/network-data.csv diff --git a/misc/switch-to-new.dnsmaster.pp-dns.com.sh b/misc/switch-to-new.dnsmaster.pp-dns.com.sh new file mode 100755 index 0000000..7a94f0d --- /dev/null +++ b/misc/switch-to-new.dnsmaster.pp-dns.com.sh @@ -0,0 +1,291 @@ +#!/bin/bash + +set -e +set -u + +BASE_NAME="$( basename ${0} )" +MY_REAL_NAME=$( readlink -f $0 ) +BIN_DIR=$( dirname "${MY_REAL_NAME}" ) + +RC_FILE='/usr/libexec/pixelpark/functions.rc' + +if [[ -f "${RC_FILE}" ]] ; then + . "${RC_FILE}" +else + echo "Bash resource file '${RC_FILE}' not found" >&2 + exit 5 +fi + +detect_color + +FILES_DIR="${BIN_DIR}/files" +ERRORS=0 + +DESCRIPTION=$( cat <<-EOF + Switching files to exchange the hostname and the IP addresses + on the next reboot + + EOF +) + +#------------------------------------------------------------------------------ +usage() { + cat <<-EOF + Usage: ${BASE_NAME} [Common Options] + ${BASE_NAME} [-h|--help] + ${BASE_NAME} [-V|--version] + + Common Options: + ${STD_USAGE_MSG} + EOF + +} + +#------------------------------------------------------------------------------ +CP() { + local cmd="cp" + if [[ "${VERBOSE}" == "y" ]] ; then + cmd+=" --verbose" + fi + if [[ "${SIMULATE}" == "y" ]] ; then + info "Executing: ${cmd} $*" + return + fi + eval ${cmd} "$@" +} + +#------------------------------------------------------------------------------ +get_options() { + + local tmp= + local base_dir= + + set +e + tmp=$( getopt -o ${STD_SHORT_OPTIONS} --long ${STD_LONG_OPTIONS} -n "${BASE_NAME}" -- "$@" ) + if [[ $? != 0 ]] ; then + echo "" >&2 + usage >&2 + exit 1 + fi + set -e + + # Note the quotes around `$TEMP': they are essential! + eval set -- "${tmp}" + eval_common_options "$@" + if [[ "${DEBUG}" == 'y' ]] ; then + declare -p REMAINING_OPTS + declare -p REMAINING_ARGS + fi + + if [[ "${#REMAINING_OPTS[@]}" -gt 0 ]] ; then + error "Unknown options: ${REMAINING_OPTS[*]}" + echo >&2 + usage >&2 + exit 2 + fi + + if [[ "${#REMAINING_ARGS[@]}" != "0" ]] ; then + error "Invalig arguments given: ${REMAINING_ARGS[*]}" + echo >&2 + usage >&2 + exit 2 + fi + + if [[ $(id -u -n) != "root" ]] ; then + error "You must ${RED}be root${NORMAL} to execute this script!" >&2 + exit 1 + fi + + if [[ ! -d "${FILES_DIR}" ]] ; then + error "Directory '${RED}${FILES_DIR}${NORMAL}' not found." + exit 5 + fi + +} + +#------------------------------------------------------------------------------ +do_filesync() { + + info "Syncing from directory '${GREEN}${FILES_DIR}${NORMAL}' ..." + cd "${FILES_DIR}" + + local oifs="${IFS}" + IFS=" +" + + local -a files=() + local f= + local fdate= + local i= + local target= + local backup= + local fabs= + + for f in $( find ./ -type f | sort ) ; do + f=$( echo ${f} | sed -e 's|^\./||' ) + if [[ ! -e "${f}" ]] ; then + error "File '${f}' does not really exists." + ERRORS=$(( ERRORS + 1 )) + continue + fi + + files+=( "${f}" ) + done + + IFS="${oifs}" + + for f in "${files[@]}" ; do + + empty_line + target="/${f}" + info "${CYAN}${target}${NORMAL}" + i=0 + if [[ -e "${target}" ]] ; then + if [[ ! -f "${target}" ]] ; then + error "Target file '${RED}${target}${NORMAL}' exists, but is not a regular file." + ERRORS=$(( ERRORS + 1 )) + continue + fi + + debug "Comparing source '${FILES_DIR}${f}' and target '${target}' ..." + if diff -q "${target}" "${f}" >/dev/null ; then + debug "Source '${f}' and target '${target}' are identic." + continue + fi + + fdate=$( date -r "${target}" +'%Y-%m-%d_%H:%M:%S' ) + backup=$( printf "%s.%s.%02d.bak" "${target}" "${fdate}" "$i" ) + while [[ -e "${backup}" ]] ; do + i=$(( i + 1 )) + backup=$( printf "%s.%s.%02d.bak" "${target}" "${fdate}" "$i" ) + done + debug "Copying '${CYAN}${target}${NORMAL}' => '${CYAN}${backup}${NORMAL}'" + CP -p "${target}" "${backup}" + fi + + fabs="${FILES_DIR}/${f}" + debug "Copying '${CYAN}${fabs}${NORMAL}' => '${CYAN}${target}${NORMAL}'" + CP -p "${fabs}" "${target}" + if [[ "${VERBOSE}" == "y" ]] ; then + ls -l -d --color=auto "${fabs}" "${target}"* || true + fi + + done + +} + +#------------------------------------------------------------------------------ +clean_puppet_certs() { + + empty_line + info "Cleaning up Puppet certificates ..." + local f= + + for f in /etc/puppetlabs/puppet/ssl/*/prd-dnsmaster*.pixelpark.com.pem \ + /etc/puppetlabs/puppet/ssl/*/dnsmaster.pp-dns.com.pem \ + /etc/puppetlabs/puppet/ssl/*/systemshare.pixelpark.com.pem ; do + if [[ ! -f "${f}" ]] ; then + continue + fi + RM "${f}" + done + empty_line + +} + +#------------------------------------------------------------------------------ +clean_ssh_host_keys() { + + empty_line + info "Cleaning up SSH host keys ..." + local f= + local fdate= + local backup= + local i= + + for f in /etc/ssh/ssh_host_* ; do + if [[ ! -f "${f}" ]] ; then + continue + fi + i=0 + fdate=$( date -r "${f}" +'%Y-%m-%d_%H:%M:%S' ) + backup=$( printf "%s.%s.%02d.bak" "${f}" "${fdate}" "$i" ) + while [[ -e "${backup}" ]] ; do + i=$(( i + 1 )) + backup=$( printf "%s.%s.%02d.bak" "${f}" "${fdate}" "$i" ) + done + debug "Moving '${CYAN}${f}${NORMAL}' => '${CYAN}${backup}${NORMAL}'" + MV "${f}" "${backup}" + done + +} + + +#------------------------------------------------------------------------------ +exec_nmcli() { + + local params="$1" + local cmd="nmcli connection ${params}" + + if [[ "${SIMULATE}" == "y" ]] ; then + info "Executing: ${cmd}" + else + debug "Executing: ${cmd}" + eval ${cmd} + fi +} + +#------------------------------------------------------------------------------ +do_nwm() { + + empty_line + info "Changing ${CYAN}network configuration${NORMAL} ..." + + empty_line + info "${CYAN}eth0${NORMAL}" + exec_nmcli "modify eth0 ipv4.addresses '217.66.53.86/24,217.66.53.87/24,217.66.53.97/24'" + + empty_line + info "${CYAN}eth1${NORMAL}" + exec_nmcli "modify eth1 ipv4.addresses '217.66.51.125/24'" + + empty_line + info "${CYAN}eth2${NORMAL}" + exec_nmcli "modify eth2 ipv4.addresses '77.74.232.20/28'" + + empty_line + info "${CYAN}eth3${NORMAL}" + exec_nmcli "modify eth3 ipv4.addresses '93.188.104.80/25'" + + empty_line + info "${CYAN}eth4${NORMAL}" + exec_nmcli "modify eth4 ipv4.addresses '93.188.109.5/28,93.188.109.6/28'" + +} + +#------------------------------------------------------------------------------ +main() { + + get_options "$@" + umask 0022 + clean_puppet_certs + clean_ssh_host_keys + do_filesync + do_nwm + + empty_line + warn "Don't forget to execute '${CYAN}ssh-keygen -A${NORMAL}' after reboot!" + +} + +main "$@" +if [[ "${ERRORS}" != "0" ]] ; then + empty_line + error "There were ${RED}${ERRORS}${NORMAL} errors during execution." + ERRORS=$(( ERRORS + 1 )) + exit "${ERRORS}" +fi + +exit 0 + +# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4 list diff --git a/postinstall-scripts/finish-network.sh b/postinstall-scripts/finish-network.sh new file mode 100755 index 0000000..2e69e4e --- /dev/null +++ b/postinstall-scripts/finish-network.sh @@ -0,0 +1,219 @@ +#!/bin/bash + +set -e +set -u + +BASE_NAME="$( basename ${0} )" +MY_REAL_NAME=$( readlink -f $0 ) +BIN_DIR=$( dirname "${MY_REAL_NAME}" ) +BASE_DIR=$( dirname "${BIN_DIR}" ) + +if [[ -f "${BIN_DIR}/functions.rc" ]] ; then + . "${BIN_DIR}/functions.rc" +else + echo "Bash resource file '${BIN_DIR}/functions.rc' not found" >&2 + exit 5 +fi + +FQDN=$( hostname -f ) + +DATA_FILE="${BIN_DIR}/network-data.csv" +if [[ ! -f "${DATA_FILE}" ]]; then + echo "Data file '${DATA_FILE}' not found" >&2 + exit 5 +fi + +declare -a INTERFACE=() + +detect_color + +#------------------------------------------------------------------------------ +DESCRIPTION=$( cat <<-EOF + Finishing network settings on prd-ns4.pixelpark.com. + + EOF +) + +#------------------------------------------------------------------------------ +usage() { + + cat <<-EOF + Usage: ${BASE_NAME} ${STD_USAGE} + ${BASE_NAME} [-h|--help] + ${BASE_NAME} [-V|--version] + + Options: + EOF + + echo "${STD_USAGE_MSG}" +} + +#------------------------------------------------------------------------------ +get_options() { + + local tmp= + local short_options="${STD_SHORT_OPTIONS}" + local long_options="${STD_LONG_OPTIONS}" + + set +e + tmp=$( getopt -o "${short_options}" --long "${long_options}" -n "${BASE_NAME}" -- "$@" ) + if [[ $? != 0 ]] ; then + echo "" >&2 + usage >&2 + exit 1 + fi + set -e + + # Note the quotes around `$TEMP': they are essential! + eval set -- "${tmp}" + eval_common_options "$@" + if [[ "${DEBUG}" == 'y' ]] ; then + declare -p REMAINING_OPTS + declare -p REMAINING_ARGS + fi + + local len="${#REMAINING_OPTS[*]}" + local i="0" + local j= + local arg= + while [[ "$i" -lt "${len}" ]] ; do + + arg="${REMAINING_OPTS[$i]}" + + case "${arg}" in + *) echo -e "Internal error - option '${RED}${arg}${NORMAL} was wrong!" + exit 1 + ;; + esac + done + +} + +#------------------------------------------------------------------------------ +exec_nmcli() { + + local params="$1" + local cmd="nmcli connection ${params}" + + if [[ "${SIMULATE}" == "y" ]] ; then + info "Executing: ${cmd}" + else + debug "Executing: ${cmd}" + eval ${cmd} + fi +} + +#------------------------------------------------------------------------------ +detect_necessary_interfaces() { + + debug "Detecting all Network interfaces to manage ..." + echo "Interfaces to manage:" + + local iface= + + for iface in $(cat "${DATA_FILE}" | grep -P "^${FQDN}\\s" | awk '{print $2}' | sort -u); do + echo " * ${iface}" + INTRERFACES+=( "${iface}" ) + done + +} + +#------------------------------------------------------------------------------ +get_connection() { + + local iface="$1" + + nmcli --terse connection show | grep -P ":${iface}\$" | awk -F: '{print $1}' + +} + +#------------------------------------------------------------------------------ +ensure_settings_dev() { + + local iface="$1" + local conn= + local setting= + local property= + + local -a settings=() + local cmd="nmcli connection" + + empty_line + + for setting in $(cat "${DATA_FILE}" | grep -P "^${FQDN}\\s+${iface}\\s" | awk '{print $3}' ); do + settings+=( "${setting}" ) + done + + conn=$( get_connection "${iface}" ) + local msg= + + if [[ -z "${conn}" ]] ; then + if ip -oneline link show | grep -P "^\\d+:\\s+${iface}:" >/dev/null ; then + : + else + error "Did not found Network device '${RED}${iface}${NORMAL}'." + return 5 + fi + + cmd+=" add type ethernet autoconnect yes ifname ${iface}" + msg="${CYAN}Creating NetworkManager connection for device '${GREEN}${iface}${CYAN}' ...${NORMAL}" + + else + cmd+=" modify '${conn}'" + msg="${CYAN}Modifying NetworkManager connection '${GREEN}${conn}${CYAN}' for device '${GREEN}${iface}${CYAN}' ...${NORMAL}" + fi + + for setting in "${settings[@]}" ; do + property=$(cat "${DATA_FILE}" | \ + grep -P "^${FQDN}\\s+${iface}\\s+${setting}\\s" | \ + sed -e "s/^${FQDN}[ ]*${iface}[ ]*${setting}[ ]*//" ) + cmd+=" ${setting} '$property'" + done + + info "${msg}" + if [[ "${SIMULATE}" == "y" ]] ; then + info "Should execute: ${cmd}" + else + info "Executing: ${cmd}" + eval ${cmd} + fi + +} + +#------------------------------------------------------------------------------ +ensure_all_settings() { + + local iface= + + for iface in "${INTRERFACES[@]}" ; do + ensure_settings_dev "${iface}" + done + +} + +################################################################################ +## +## Main +## +################################################################################ + +#------------------------------------------------------------------------------ +main() { + + get_options "$@" + set_locale "en_US.utf8" + + empty_line + info "Trying to ${CYAN}finish network configuration${NORMAL} ..." + empty_line + + detect_necessary_interfaces + ensure_all_settings + +} + +main "$@" + +exit 0 + +# vim: list diff --git a/postinstall-scripts/network-data.csv b/postinstall-scripts/network-data.csv new file mode 100644 index 0000000..11f4a68 --- /dev/null +++ b/postinstall-scripts/network-data.csv @@ -0,0 +1,75 @@ +# Host Device Setting Property + +# prd-ns1.pixelpark.com +prd-ns1.pixelpark.com ens160 ipv4.method manual +prd-ns1.pixelpark.com ens160 ipv4.addresses 93.188.110.60/28 +prd-ns1.pixelpark.com ens160 ipv4.gateway 93.188.110.49 +prd-ns1.pixelpark.com ens160 ipv4.dns 77.74.232.24,217.66.52.10,77.74.232.25 +prd-ns1.pixelpark.com ens160 ipv4.dns-search pixelpark.com,pp-dns.com,pixelpark.net +prd-ns1.pixelpark.com ens160 ipv4.dns-options timeout:1,attempts:1 +prd-ns1.pixelpark.com ens160 ipv6.method ignore + +prd-ns1.pixelpark.com ens192 ipv4.method manual +prd-ns1.pixelpark.com ens192 ipv4.addresses 217.66.51.53/24 +prd-ns1.pixelpark.com ens192 ipv4.routes 217.66.51.0/24 table=100, 0.0.0.0/0 217.66.51.1 table=100 +prd-ns1.pixelpark.com ens192 ipv4.routing-rules priority 5 from 217.66.51.0/24 table 100, priority 6 to 217.66.51.0/24 table 100 +prd-ns1.pixelpark.com ens192 ipv6.method ignore + +prd-ns1.pixelpark.com ens224 ipv4.method manual +prd-ns1.pixelpark.com ens224 ipv4.addresses 93.188.104.87/25 +prd-ns1.pixelpark.com ens224 ipv4.routes 93.188.104.0/25 table=200, 0.0.0.0/0 93.188.104.1 table=200 +prd-ns1.pixelpark.com ens224 ipv4.routing-rules priority 7 from 93.188.104.0/25 table 200, priority 8 to 93.188.104.0/25 table 200 +prd-ns1.pixelpark.com ens224 ipv6.method ignore + +# prd-ns1-new.pixelpark.com +prd-ns1-new.pixelpark.com ens160 ipv4.method manual +prd-ns1-new.pixelpark.com ens160 ipv4.addresses 93.188.110.51/28 +prd-ns1-new.pixelpark.com ens160 ipv4.gateway 93.188.110.49 +prd-ns1-new.pixelpark.com ens160 ipv4.dns 77.74.232.24,217.66.52.10,77.74.232.25 +prd-ns1-new.pixelpark.com ens160 ipv4.dns-search pixelpark.com,pp-dns.com,pixelpark.net +prd-ns1-new.pixelpark.com ens160 ipv4.dns-options timeout:1,attempts:1 +prd-ns1-new.pixelpark.com ens160 ipv6.method ignore + +prd-ns1-new.pixelpark.com ens192 ipv4.method manual +prd-ns1-new.pixelpark.com ens192 ipv4.addresses 217.66.51.29/24 +prd-ns1-new.pixelpark.com ens192 ipv4.routes 217.66.51.0/24 table=100, 0.0.0.0/0 217.66.51.1 table=100 +prd-ns1-new.pixelpark.com ens192 ipv4.routing-rules priority 5 from 217.66.51.0/24 table 100, priority 6 to 217.66.51.0/24 table 100 +prd-ns1-new.pixelpark.com ens192 ipv6.method ignore + +prd-ns1-new.pixelpark.com ens224 ipv4.method manual +prd-ns1-new.pixelpark.com ens224 ipv4.addresses 93.188.104.6/25 +prd-ns1-new.pixelpark.com ens224 ipv4.routes 93.188.104.0/25 table=200, 0.0.0.0/0 93.188.104.1 table=200 +prd-ns1-new.pixelpark.com ens224 ipv4.routing-rules priority 7 from 93.188.104.0/25 table 200, priority 8 to 93.188.104.0/25 table 200 +prd-ns1-new.pixelpark.com ens224 ipv6.method ignore + +# prd-ns4.pixelpark.com +prd-ns4.pixelpark.com ens160 ipv4.method manual +prd-ns4.pixelpark.com ens160 ipv4.addresses 77.74.232.21/28 +prd-ns4.pixelpark.com ens160 ipv4.gateway 77.74.232.17 +prd-ns4.pixelpark.com ens160 ipv4.dns 77.74.232.24,77.74.232.25,93.188.104.82 +prd-ns4.pixelpark.com ens160 ipv4.dns-search pixelpark.com,pp-dns.com,pixelpark.net +prd-ns4.pixelpark.com ens160 ipv4.dns-options timeout:1,attempts:1 +prd-ns4.pixelpark.com ens160 ipv6.method ignore + +prd-ns4.pixelpark.com ens192 ipv4.method manual +prd-ns4.pixelpark.com ens192 ipv4.addresses 93.188.104.81/25 +prd-ns4.pixelpark.com ens192 ipv4.routes 93.188.104.0/25 table=100, 0.0.0.0/0 93.188.104.1 table=100 +prd-ns4.pixelpark.com ens192 ipv4.routing-rules priority 5 from 93.188.104.0/25 table 100, priority 6 to 93.188.104.0/25 table 100 +prd-ns4.pixelpark.com ens192 ipv6.method ignore + +# prd-ns4-new.pixelpark.com +prd-ns4-new.pixelpark.com ens160 ipv4.method manual +prd-ns4-new.pixelpark.com ens160 ipv4.addresses 77.74.232.19/28 +prd-ns4-new.pixelpark.com ens160 ipv4.gateway 77.74.232.17 +prd-ns4-new.pixelpark.com ens160 ipv4.dns 77.74.232.24,77.74.232.25,93.188.104.82 +prd-ns4-new.pixelpark.com ens160 ipv4.dns-search pixelpark.com,pp-dns.com,pixelpark.net +prd-ns4-new.pixelpark.com ens160 ipv4.dns-options timeout:1,attempts:1 +prd-ns4-new.pixelpark.com ens160 ipv6.method ignore + +prd-ns4-new.pixelpark.com ens192 ipv4.method manual +prd-ns4-new.pixelpark.com ens192 ipv4.addresses 93.188.104.4/25 +prd-ns4-new.pixelpark.com ens192 ipv4.routes 93.188.104.0/25 table=100, 0.0.0.0/0 93.188.104.1 table=100 +prd-ns4-new.pixelpark.com ens192 ipv4.routing-rules priority 5 from 93.188.104.0/25 table 100, priority 6 to 93.188.104.0/25 table 100 +prd-ns4-new.pixelpark.com ens192 ipv6.method ignore + +# vim: list -- 2.39.5