Skip to content

Instantly share code, notes, and snippets.

@imkiva
Last active August 4, 2023 07:53
Show Gist options
  • Save imkiva/9289a9707851730e5b9d8f8893b64089 to your computer and use it in GitHub Desktop.
Save imkiva/9289a9707851730e5b9d8f8893b64089 to your computer and use it in GitHub Desktop.
ovfyes - Configuring ubuntu server with properties from VMware vApps
#!/usr/bin/env bash
RUN_ONCE_FILE="/etc/ovfyes-run-once"
RUN_EACH_BOOT_FILE="/etc/ovfyes-run-each-boot"
NETPLAN_FILE="/etc/netplan/00-installer-config.yaml"
OFVENV_DEBUG="$(cat <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<Environment
xmlns="http://schemas.dmtf.org/ovf/environment/1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oe="http://schemas.dmtf.org/ovf/environment/1"
xmlns:ve="http://www.vmware.com/schema/ovfenv"
oe:id="happy-vm"
ve:vCenterId="vm-276701735">
<PlatformSection>
<Kind>VMware ESXi</Kind>
<Version>7.0.3</Version>
<Vendor>VMware, Inc.</Vendor>
<Locale>en</Locale>
</PlatformSection>
<PropertySection>
<Property oe:key="IPAddress" oe:value="192.168.44.44"/>
<Property oe:key="IPDNS" oe:value="198.18.0.2"/>
<Property oe:key="IPGateway" oe:value="192.168.50.30"/>
<Property oe:key="IPNetmask" oe:value="255.255.0.0"/>
<Property oe:key="UserPassword" oe:value="happy123"/>
<Property oe:key="Username" oe:value="happy"/>
<Property oe:key="Hostname" oe:value="happy-vm"/>
</PropertySection>
<ve:EthernetAdapterSection>
<ve:Adapter ve:mac="00:50:56:b8:36:fc" ve:network="VMNetwork" ve:unitNumber="7"/>
</ve:EthernetAdapterSection>
<Entity oe:id="happy-vm-wrong">
</Entity>
</Environment>
EOF
)"
NETPLAN_TEMPLATE="$(cat <<EOF
# This is the network config written by 'ovfyes'
network:
ethernets:
__NETWORK_INTERFACE__:
addresses:
- __IP_CIDR__
nameservers:
addresses:
- __DNS__
search: []
routes:
- to: default
via: __GATEWAY__
version: 2
EOF
)"
DEBUG=false
if [[ "$1"x == "debug"x ]]; then
DEBUG=true
fi
if [[ "$DEBUG" != "true" ]]; then
OvfEnv="$(vmtoolsd --cmd 'info-get guestinfo.ovfenv')"
else
if command -v vmtoolsd >/dev/null 2>&1; then
OvfEnv="$(vmtoolsd --cmd 'info-get guestinfo.ovfenv')"
else
OvfEnv="$OFVENV_DEBUG"
fi
fi
apply-hostname-config() {
local HOSTNAME=$(echo $OvfEnv | grep -oP 'oe:id="\K[^"]+' | head -n1)
# if oe:id is empty, try to get it from vApp property
if [[ -z "$HOSTNAME" ]]; then
HOSTNAME=$(echo $OvfEnv | grep -oP 'oe:key="Hostname" oe:value="\K[^"]+' | head -n1)
fi
# set hostname if non-empty
if [[ -z "$HOSTNAME" ]]; then
return
fi
if [[ "$DEBUG" != "true" ]]; then
hostnamectl set-hostname "$HOSTNAME"
else
echo "hostnamectl set-hostname \"$HOSTNAME\""
fi
}
apply-user-config() {
local USERNAME=$(echo $OvfEnv | grep -oP 'oe:key="Username" oe:value="\K[^"]+')
local PASSWORD=$(echo $OvfEnv | grep -oP 'oe:key="UserPassword" oe:value="\K[^"]+')
# If both are non-empty, add the user with the following configs:
# - Create home directory
# - Create primary group with same name as username
# - Add to auxliary groups: adm, cdrom, dip, plugdev, lxd, sudo
# - Set password to PASSWORD
if [[ -z "$USERNAME" || -z "$PASSWORD" ]]; then
return
fi
if [[ "$DEBUG" != "true" ]]; then
useradd -m -U -G "adm,cdrom,dip,plugdev,lxd,sudo" "$USERNAME"
echo "$USERNAME:$PASSWORD" | chpasswd
else
echo "useradd -m -U -G \"adm,cdrom,dip,plugdev,lxd,sudo\" \"$USERNAME\""
echo "echo \"$USERNAME:$PASSWORD\" | chpasswd"
fi
}
get-nic-name() {
local MAC=$(echo $OvfEnv | grep -oP 'oe:mac="\K[^"]+')
# First try to detect network interface using MAC address
if [[ -n "$MAC" ]]; then
local name=$(ip a | grep -B1 "$MAC" | head -n1 | awk -F': ' '{ print $2 }')
if [[ -n "$name" ]]; then
echo "$name"
fi
fi
# No MAC address, detect network interface using ip command
local name="$(ip -br link | awk '{print $1}' | grep -v 'lo')"
# If network interface is empty, default to ens160
if [[ -z "$name" ]]; then
name="ens160"
fi
echo "$name"
}
apply-network-config() {
local IP_ADDRESS=$(echo $OvfEnv | grep -oP 'oe:key="IPAddress" oe:value="\K[^"]+' | head -n1)
local DNS=$(echo $OvfEnv | grep -oP 'oe:key="IPDNS" oe:value="\K[^"]+' | head -n1)
local GATEWAY=$(echo $OvfEnv | grep -oP 'oe:key="IPGateway" oe:value="\K[^"]+' | head -n1)
local NETMASK=$(echo $OvfEnv | grep -oP 'oe:key="IPNetmask" oe:value="\K[^"]+' | head -n1)
if [[ -z "$IP_ADDRESS" || -z "$DNS" || -z "$GATEWAY" || -z "$NETMASK" ]]; then
return
fi
# Convert netmask to CIDR notation using bash bitwise operation
local CIDR=0
for octet in $(echo $NETMASK | tr '.' ' '); do
for (( i = 0; i < 8; i++ )); do
(( octet & (1 << (7 - i)) )) && CIDR=$((CIDR + 1))
done
done
local IP_CIDR="$IP_ADDRESS/$CIDR"
# Detect network interface using ip command
local NETWORK_INTERFACE=$(get-nic-name)
# Create a new netplan configuration file
local NETPLAN_CONFIG=$(echo -e "$NETPLAN_TEMPLATE" \
| sed "s|__NETWORK_INTERFACE__|${NETWORK_INTERFACE}|g" \
| sed "s|__IP_CIDR__|${IP_CIDR}|g" \
| sed "s|__DNS__|${DNS}|g" \
| sed "s|__GATEWAY__|${GATEWAY}|g"
)
# Apply the netplan configuration
if [[ "$DEBUG" != "true" ]]; then
echo "$NETPLAN_CONFIG" > "$NETPLAN_FILE"
netplan apply
else
echo "$NETPLAN_CONFIG"
fi
}
# If we are in run-once mode, exit if we already finished the task
if [[ "$DEBUG" != "true" && -f "$RUN_ONCE_FILE" && ! -f "$RUN_EACH_BOOT_FILE" ]]; then
exit 0
fi
# otherwise, if we are in run-each-boot mode, reconfigure network and hostname
apply-hostname-config
apply-network-config
# users can only be configured once
if [[ ! -f "$RUN_ONCE_FILE" ]]; then
apply-user-config
fi
# tell next time, we had ran once
if [[ "$DEBUG" != "true" ]]; then
touch "$RUN_ONCE_FILE"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment