Last active
August 4, 2023 07:53
-
-
Save imkiva/9289a9707851730e5b9d8f8893b64089 to your computer and use it in GitHub Desktop.
ovfyes - Configuring ubuntu server with properties from VMware vApps
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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