Unfortunately, when using "VM Customization Specifications" when deploying ALT Linux OS, "open-vm-toos" scripts cannot correctly configure parameters such as host name, network settings, etc. for this system. To solve this problem, we will use a script that will take over the functionality that does not work correctly in the tools themselves.
Let's perform the following steps to configure "VM Customization Specifications":
1. Prepare an ATL Linux OS template with the installation of the required software, which should already be included with new hosts.
2. Be sure to install "open-vm-tools" and check that the "vmtoolsd" service is in autorun:
sudo apt-get install open-vm-tools
sudo systemctl enable vmtoolsd && sudo systemctl start vmtoolsd
3. Enable support for customization scripts:
sudo vmware-toolbox-cmd config set deployPkg enable-custom-scripts true
To check the current state of the parameter, run:
sudo vmware-toolbox-cmd config get deployPkg enable-custom-scripts
4. Next, configure "VM Customization Specifications" on vCenter Server. When setting up, we specify: OS type - Linux, host name generation rule, time zone, TCP/IP settings and add the following script:
#!/bin/bash
# Function to convert subnet mask to CIDR prefix
mask2cidr() {
local mask=$1
local n=0
IFS=.
for byte in $mask; do
case $byte in
255) n=$((n+8));;
254) n=$((n+7));;
252) n=$((n+6));;
248) n=$((n+5));;
240) n=$((n+4));;
224) n=$((n+3));;
192) n=$((n+2));;
128) n=$((n+1));;
0);;
*) echo 24; return 1;;
esac
done
echo $n
}
# Function to determine network management method
get_network_manager() {
local interface=$1
local options_file="/etc/net/ifaces/$interface/options"
# Check if configuration file exists
if [ -f "$options_file" ]; then
local nm_controlled=$(grep -E "^NM_CONTROLLED=" "$options_file" | cut -d= -f2)
local disabled=$(grep -E "^DISABLED=" "$options_file" | cut -d= -f2)
local systemd_controlled=$(grep -E "^SYSTEMD_CONTROLLED=" "$options_file" | cut -d= -f2)
if [ "$nm_controlled" = "yes" ]; then
echo "NetworkManager"
elif [ "$disabled" = "no" ]; then
echo "EtcNet"
elif [ "$systemd_controlled" = "yes" ]; then
echo "SystemD"
else
echo "Unknown"
fi
else
# If file doesn't exist, check active services
if systemctl is-active NetworkManager >/dev/null 2>&1; then
echo "NetworkManager"
elif systemctl is-active systemd-networkd >/dev/null 2>&1 && \
systemctl is-active systemd-resolved >/dev/null 2>&1; then
echo "SystemD"
elif systemctl is-active network >/dev/null 2>&1; then
echo "EtcNet"
else
echo "Unknown"
fi
fi
}
# Function to configure NetworkManager
configure_networkmanager() {
local interface=$1
local bootproto=$2
local ipaddr=$3
local netmask=$4
local gateway=$5
local dns_servers=$6
local domain=$7
# Create or modify connection
if [ "$bootproto" = "static" ]; then
local prefix_length=$(mask2cidr "$netmask")
nmcli con add type ethernet con-name "$interface" ifname "$interface" ip4 "$ipaddr/$prefix_length" gw4 "$gateway"
if [ -n "$dns_servers" ]; then
nmcli con mod "$interface" ipv4.dns "$dns_servers"
fi
if [ -n "$domain" ]; then
nmcli con mod "$interface" ipv4.dns-search "$domain"
fi
else
nmcli con add type ethernet con-name "$interface" ifname "$interface" ipv4.method auto
fi
# Activate connection
nmcli con up "$interface"
}
# Function to configure EtcNet
configure_etcnet() {
local interface=$1
local bootproto=$2
local ipaddr=$3
local netmask=$4
local gateway=$5
local dns_servers=$6
local domain=$7
local iface_dir="/etc/net/ifaces/$interface"
mkdir -p "$iface_dir"
# Update options file based on configuration type
if [ -f "$iface_dir/options" ]; then
# Update existing options file, preserving other parameters
if [ "$bootproto" = "static" ]; then
# Remove old BOOTPROTO and SYSTEMD_BOOTPROTO parameters if they exist
sed -i '/^BOOTPROTO=/d' "$iface_dir/options"
sed -i '/^SYSTEMD_BOOTPROTO=/d' "$iface_dir/options"
# Add new parameters
echo "BOOTPROTO=static" >> "$iface_dir/options"
echo "SYSTEMD_BOOTPROTO=static" >> "$iface_dir/options"
else
# Remove old BOOTPROTO and SYSTEMD_BOOTPROTO parameters if they exist
sed -i '/^BOOTPROTO=/d' "$iface_dir/options"
sed -i '/^SYSTEMD_BOOTPROTO=/d' "$iface_dir/options"
# Add new parameters
echo "BOOTPROTO=dhcp" >> "$iface_dir/options"
echo "SYSTEMD_BOOTPROTO=dhcp4" >> "$iface_dir/options"
fi
else
# Create new options file
if [ "$bootproto" = "static" ]; then
cat > "$iface_dir/options" <<EOF
BOOTPROTO=static
SYSTEMD_BOOTPROTO=static
EOF
else
cat > "$iface_dir/options" <<EOF
BOOTPROTO=dhcp
SYSTEMD_BOOTPROTO=dhcp4
EOF
fi
fi
if [ "$bootproto" = "static" ]; then
# Write IP address with CIDR prefix
PREFIX_LENGTH=$(mask2cidr "$netmask")
if [ -z "$PREFIX_LENGTH" ]; then
PREFIX_LENGTH=24
fi
echo "$ipaddr/$PREFIX_LENGTH" > "$iface_dir/ipv4address"
# Write default route
if [ -n "$gateway" ]; then
echo "default via $gateway" > "$iface_dir/ipv4route"
fi
# Configure DNS via resolv.conf in interface directory
if [ -n "$dns_servers" ]; then
# Create resolv.conf in interface directory
echo "# Generated by network configuration script" > "$iface_dir/resolv.conf"
if [ -n "$domain" ]; then
echo "domain $domain" >> "$iface_dir/resolv.conf"
echo "search $domain" >> "$iface_dir/resolv.conf"
fi
# Add DNS servers
for dns in $dns_servers; do
echo "nameserver $dns" >> "$iface_dir/resolv.conf"
done
fi
# Release DHCP lease for interface
if command -v /sbin/dhcpcd >/dev/null 2>&1; then
/sbin/dhcpcd -k "$interface" 2>/dev/null || true
fi
else
# For DHCP, clear possible previous static configurations
rm -f "$iface_dir/ipv4address"
rm -f "$iface_dir/ipv4route"
rm -f "$iface_dir/resolv.conf"
# Don't create type file as specified in requirements
fi
# Add interface to processing order
local order_file="/etc/net/ifaces.order"
if ! grep -q "^$interface$" "$order_file" 2>/dev/null; then
echo "$interface" >> "$order_file"
fi
# Restart network
systemctl restart network
}
# --- Function to clean logs and temporary files ---
clean_system() {
# Clean logs (preserving directory structure)
find /var/log -type f -name "*.log" -exec truncate -s 0 {} \;
find /var/log -type f -name "*.gz" -delete;
find /var/log -type f -name "*.old" -delete;
find /var/log -type f -name "lastlog" -exec rm -f {} \;
# Clean temporary files
rm -rf /tmp/*
rm -rf /var/tmp/*
# Clean command history and user data
for user_home in /home/*; do
if [[ -d "$user_home" ]]; then
user=$(basename "$user_home")
# Clean bash_history and other histories
truncate -s 0 "$user_home/.bash_history" 2>/dev/null || true
# Clean application caches
rm -rf "$user_home/.cache/*" 2>/dev/null || true
fi
done
# Clean root
truncate -s 0 /root/.bash_history 2>/dev/null || true
rm -rf /root/.cache/* 2>/dev/null || true
# Remove random seed files
rm -f /var/lib/systemd/random-seed
}
# --- Function to remove SSH host keys ---
reset_ssh_keys() {
rm -f /etc/ssh/ssh_host_*
# Keys will be generated on next SSH server start
}
if [ "$1" = "precustomization" ]; then
# Perform system cleanup
clean_system
reset_ssh_keys
# Check and create /etc/sysconfig/network-scripts directory if needed
if [ ! -d "/etc/sysconfig/network-scripts" ]; then
mkdir -p /etc/sysconfig/network-scripts
fi
# Pre-customization stage
VMCUST_DIR=$(ls -d /var/run/.vmware-imgcust* 2>/dev/null | head -n 1)
if [ -n "$VMCUST_DIR" ]; then
CUST_CFG_PATH="$VMCUST_DIR/cust.cfg"
if [ -f "$CUST_CFG_PATH" ]; then
cp "$CUST_CFG_PATH" "/root/cust.cfg"
fi
fi
elif [ "$1" = "postcustomization" ]; then
# Post-customization stage
if [ ! -f "/root/cust.cfg" ]; then
exit 1
fi
CFG_FILE="/root/cust.cfg"
# Parse configuration parameters
BOOTPROTO=$(awk -F' = ' '/^BOOTPROTO/ {line=$2} END{print tolower(line)}' "$CFG_FILE")
IPADDR=$(awk -F' = ' '/^IPADDR/ {line=$2} END{print line}' "$CFG_FILE")
NETMASK=$(awk -F' = ' '/^NETMASK/ {line=$2} END{print line}' "$CFG_FILE")
GATEWAY=$(awk -F' = ' '/^GATEWAY/ {line=$2} END{print line}' "$CFG_FILE")
HOSTNAME=$(awk -F' = ' '/^HOSTNAME/ {line=$2} END{print line}' "$CFG_FILE")
DOMAIN=$(awk -F' = ' '/^DOMAINNAME/ {line=$2} END{print line}' "$CFG_FILE")
MACADDR=$(awk -F' = ' '/^MACADDR/ {line=$2} END{print tolower(line)}' "$CFG_FILE")
DNS_SERVERS=$(awk -F' = ' '/^NAMESERVER\|[0-9]/ {print $2}' "$CFG_FILE" | tr '\n' ' ')
DNS_FROM_DHCP=$(awk -F' = ' '/^DNSFROMDHCP/ {line=$2} END{print tolower(line)}' "$CFG_FILE")
TIMEZONE=$(awk -F' = ' '/^TIMEZONE/ {line=$2} END{print line}' "$CFG_FILE")
UTC=$(awk -F' = ' '/^UTC/ {line=$2} END{print tolower(line)}' "$CFG_FILE")
# Determine network interface
INTERFACE=$(ip -o link | awk -v mac="$MACADDR" 'tolower($0) ~ mac {gsub(":", "", $2); print $2}')
if [ -z "$INTERFACE" ]; then
INTERFACE=$(ip route | awk '/default/ {print $5; exit}')
fi
# Determine network management method
NET_MGR=$(get_network_manager "$INTERFACE")
case "$NET_MGR" in
"NetworkManager")
configure_networkmanager "$INTERFACE" "$BOOTPROTO" "$IPADDR" "$NETMASK" "$GATEWAY" "$DNS_SERVERS" "$DOMAIN"
;;
"EtcNet")
configure_etcnet "$INTERFACE" "$BOOTPROTO" "$IPADDR" "$NETMASK" "$GATEWAY" "$DNS_SERVERS" "$DOMAIN"
;;
"SystemD")
# Existing SystemD configuration
rm -f /etc/systemd/network/*.network
rm -f /etc/systemd/resolved.conf.d/*.conf
# Create base configuration for loopback interface
cat > /etc/systemd/network/00-loopback.network <<EOF
[Match]
Name=lo
[Network]
Address=127.0.0.1/8
Address=::1/128
EOF
# Create configuration for main interface
CONFIG_FILE="/etc/systemd/network/alterator-${INTERFACE}.network"
if [ "$BOOTPROTO" = "static" ]; then
if [ -z "$IPADDR" ] || [ -z "$NETMASK" ]; then
exit 1
fi
PREFIX_LENGTH=$(mask2cidr "$NETMASK")
if [ -z "$PREFIX_LENGTH" ]; then
PREFIX_LENGTH=24
fi
# Create config for static IP with DNS
cat > "$CONFIG_FILE" <<EOF
[Match]
Name=$INTERFACE
[Network]
Address=$IPADDR/$PREFIX_LENGTH
Gateway=$GATEWAY
EOF
# Add DNS servers if needed
if { [ "$BOOTPROTO" = "static" ] || [ "$DNS_FROM_DHCP" = "no" ]; } && [ -n "$DNS_SERVERS" ]; then
for dns in $DNS_SERVERS; do
echo "DNS=$dns" >> "$CONFIG_FILE"
done
fi
else
# Create config for DHCP
cat > "$CONFIG_FILE" <<EOF
[Match]
Name=$INTERFACE
[Network]
DHCP=ipv4
[DHCPv4]
UseDomains=true
UseDNS=yes
EOF
# Add DNS servers if not using DNS from DHCP
if [ "$DNS_FROM_DHCP" = "no" ] && [ -n "$DNS_SERVERS" ]; then
for dns in $DNS_SERVERS; do
echo "DNS=$dns" >> "$CONFIG_FILE"
done
fi
fi
systemctl restart systemd-networkd
systemctl restart systemd-resolved
;;
*)
echo "Unknown network management method"
exit 1
;;
esac
# Common settings
hostnamectl set-hostname "$HOSTNAME"
sed -i "/127\.0\.1\.1/d" /etc/hosts
echo "127.0.1.1 $HOSTNAME.$DOMAIN $HOSTNAME" >> /etc/hosts
# Timezone configuration
if [ -n "$TIMEZONE" ]; then
timedatectl set-timezone "$TIMEZONE"
fi
# BIOS time format configuration (UTC or local)
if [ -n "$UTC" ]; then
if [ "$UTC" = "yes" ]; then
# Set UTC time in BIOS
timedatectl set-local-rtc 0
else
# Set local time in BIOS
timedatectl set-local-rtc 1
fi
fi
# Save configuration
{
echo "CONFIG_SOURCE=$CFG_FILE"
echo "BOOTPROTO=$BOOTPROTO"
echo "INTERFACE=$INTERFACE"
echo "HOSTNAME=$HOSTNAME"
echo "DOMAIN=$DOMAIN"
echo "TIMEZONE=$TIMEZONE"
echo "UTC=$UTC"
[ -n "$DNS_FROM_DHCP" ] && echo "DNS_FROM_DHCP=$DNS_FROM_DHCP"
[ -n "$DNS_SERVERS" ] && echo "DNS_SERVERS=\"$DNS_SERVERS\""
}
if [ "$BOOTPROTO" = "static" ]; then
{
echo "IP_ADDRESS=$IPADDR"
echo "NETMASK=$NETMASK"
echo "PREFIX_LENGTH=$PREFIX_LENGTH"
[ -n "$GATEWAY" ] && echo "GATEWAY=$GATEWAY"
}
fi
rm -f "/root/cust.cfg"
##############################################################################################
# PLACE FOR ADDITIONAL SYSTEM CONFIGURATION
# Here you can add commands for final machine setup:
# - Installation of required software
# - Configuration via Ansible or other configuration management systems
# - Execution of custom scripts
# - Setup of monitoring, logging and other services
##############################################################################################
fi
This script covers all possible network setup options: EtcNet, NetworkManager, Systemd-Networkd, both with static IP and with DHCP.
No comments:
Post a Comment