Skip to content

Instantly share code, notes, and snippets.

@xunleii
Created December 30, 2020 20:44
Show Gist options
  • Save xunleii/08105c497725fd15724f4cedede00733 to your computer and use it in GitHub Desktop.
Save xunleii/08105c497725fd15724f4cedede00733 to your computer and use it in GitHub Desktop.
Synchronize Hetzner Cloud private network for k3os
#/etc/udev/rules.d/70-hetzner-net-routes.rules
SUBSYSTEM=="net", KERNEL=="eth*", RUN+="/usr/lib/sync-hetzner-routes"

Synchronize Hetzner Cloud private networks for k3os

This simple script creates the required route to allow communication between node on private network on k3os, following how Hetzner does on Ubuntu/Centos machines.

WARN: https://github.com/mikefarah/yq must be installed in order to fetch network metadata from Hetzner API

#!/bin/sh
set -o nounset
set -o errexit
# UDEV shell script synchronizing network routes with Hetzner network
# properties. It uses the Metadata Server to fetch information of private
# networks and add or remove routes according to the `udev` action and the
# modified net interface.
#
# WARN: it requires https://github.com/mikefarah/yq to parse and extract data
# from the Hetzner API.
#
# Example:
# #/etc/udev/rules.d/70-hetzner-net-routes.rules
# SUBSYSTEM=="net", KERNEL=="eth*", RUN+="/usr/lib/sync-hetzner-routes"
#
API_URL=http://169.254.169.254/hetzner/v1/metadata/private-networks
INTERFACE_WAIT_LIMIT=10
info() { echo '[INFO] ' "$@"; }
warn() { echo '[WARN] ' "$@" >&2; }
fatal() { echo '[ERROR] ' "$@" >&2; exit 1; }
fetch_metadata() {
TMP_METADATA="$(mktemp)"
curl -s "${API_URL}" > "${TMP_METADATA}"
info "metadata downloaded to ${TMP_METADATA}"
}
fetch_interface_ip() {
nretry=0
until [ ${nretry} -ge ${INTERFACE_WAIT_LIMIT} ]; do
interface_ip="$(ip -4 -o address show "${INTERFACE}" | awk '{print $4}' | cut -d'/' -f1)"
if [ -n "${interface_ip}" ]; then return; fi
warn "interface ${INTERFACE} doesn't have an IP... wait until $$INTERFACE_WAIT_LIMIT will be reached"
nretry=$((nretry+1))
sleep 1
done
fatal "failed to find \`${INTERFACE}\` IP: $$INTERFACE_WAIT_LIMIT reached"
}
add_route() {
fetch_interface_ip
fetch_metadata
network=$(yq eval '.[] | select(.ip=="'"${interface_ip}"'") | .network' "${TMP_METADATA}")
gateway=$(yq eval '.[] | select(.ip=="'"${interface_ip}"'") | .gateway' "${TMP_METADATA}")
if [ -z "${network}" ]; then fatal "no network found on Hetzner API for interface \`${INTERFACE}\` (ip: ${interface_ip})"; fi
if [ -z "${gateway}" ]; then fatal "no gateway found on Hetzner API for interface \`${INTERFACE}\` (ip: ${interface_ip})"; fi
ip route add "${network}" via "${gateway}" dev "${INTERFACE}"
}
remove_route() {
ip_route="$(ip route show | grep -E "dev ${INTERFACE} $")"
if [ -z "${ip_route}" ]; then fatal "no route found for interface \`${INTERFACE}\`"; fi
ip route del "${ip_route}"
}
case "${ACTION}" in
"add") add_route;;
"remove") remove_route;;
*) warn "action \`${ACTION}\` not handled... ignored"
esac
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment