nixos_config/nixos/modules/services/oci-secondary-vnics.nix

126 lines
3.6 KiB
Nix

{ config, lib, pkgs, ... }:
let
cfg = config.alisceon.ociSecondaryVnics;
configureSecondaryVnics = pkgs.writeShellApplication {
name = "configure-oci-secondary-vnics";
runtimeInputs = [
pkgs.coreutils
pkgs.curl
pkgs.gnugrep
pkgs.iproute2
pkgs.jq
pkgs.systemd
];
text = ''
metadata_url="http://169.254.169.254/opc/v2/vnics"
network_dir="/run/systemd/network"
mkdir -p "$network_dir"
vnics="$(curl --fail --silent --show-error --max-time 10 \
-H "Authorization: Bearer Oracle" \
"$metadata_url")"
index=0
configured=0
while IFS= read -r vnic; do
index=$((index + 1))
mac="$(jq -r '.macAddr // empty' <<< "$vnic" | tr '[:upper:]' '[:lower:]')"
address="$(jq -r '.privateIp // empty' <<< "$vnic")"
cidr="$(jq -r '.subnetCidrBlock // empty' <<< "$vnic")"
gateway="$(jq -r '.virtualRouterIp // empty' <<< "$vnic")"
if [ -z "$mac" ] || [ -z "$address" ] || [ -z "$cidr" ] || [ -z "$gateway" ]; then
echo "Skipping incomplete OCI VNIC metadata entry: $vnic"
continue
fi
iface="$(
for candidate in /sys/class/net/*; do
[ -e "$candidate/address" ] || continue
candidate_mac="$(tr '[:upper:]' '[:lower:]' < "$candidate/address")"
if [ "$candidate_mac" = "$mac" ]; then
basename "$candidate"
break
fi
done
)"
if [ -z "$iface" ]; then
echo "Skipping OCI VNIC $mac: no matching Linux interface"
continue
fi
if ip -4 address show dev "$iface" | grep -q "inet $address/"; then
echo "OCI VNIC $iface already has $address configured"
continue
fi
prefix="''${cidr#*/}"
table=$((1000 + index))
priority=$((1000 + index))
unit_name="$(systemd-escape --template=20-oci-secondary-vnic@.network "$iface")"
network_file="$network_dir/$unit_name"
{
printf '%s\n' \
"[Match]" \
"MACAddress=$mac" \
"" \
"[Link]" \
"MTUBytes=9000" \
"" \
"[Network]" \
"Address=$address/$prefix" \
"" \
"[Route]" \
"Destination=$cidr" \
"Scope=link" \
"Table=$table" \
"" \
"[Route]" \
"Gateway=$gateway" \
"GatewayOnLink=yes" \
"Table=$table" \
"" \
"[RoutingPolicyRule]" \
"From=$address/32" \
"Table=$table" \
"Priority=$priority"
} > "$network_file"
echo "Configuring OCI secondary VNIC $iface as $address/$prefix via $gateway in table $table"
networkctl reload
networkctl reconfigure "$iface"
configured=1
done < <(jq -c '.[]' <<< "$vnics")
if [ "$configured" = 0 ]; then
echo "No unconfigured OCI secondary VNICs found"
fi
'';
};
in
{
options.alisceon.ociSecondaryVnics.enable =
lib.mkEnableOption "runtime configuration of OCI secondary VNICs from instance metadata";
config = lib.mkIf cfg.enable {
systemd.services.configure-oci-secondary-vnics = {
description = "Configure OCI secondary VNICs from instance metadata";
after = [
"network-online.target"
"systemd-networkd.service"
];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = lib.getExe configureSecondaryVnics;
};
};
}