diff --git a/cdist/conf/type/__network_interface/files/debian/00000-wait-for-ip b/cdist/conf/type/__network_interface/files/debian/00000-wait-for-ip new file mode 100755 index 00000000..3103ef62 --- /dev/null +++ b/cdist/conf/type/__network_interface/files/debian/00000-wait-for-ip @@ -0,0 +1,38 @@ +#!/bin/sh +# +# workaround the bloody upstart race conditions +# by delaying the emission of the net-device-up signal until the interface is +# really up and configured. +# +# environment variables: +# METHOD=dhcp +# MODE=start +# LOGICAL=eth0 +# PHASE=post-up +# ADDRFAM=inet +# VERBOSITY=0 +# PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin +# IF_METRIC=100 +# IFACE=eth0 +# PWD=/root + +# nothing to do for loopback +[ "$IFACE" = lo ] && exit 0 + +LOG_FILE="/tmp/wait-for-ip-${IFACE}.log" +cp /dev/null $LOG_FILE +RETRY=20 +index=0 + +if [ "$ADDRFAM" = "inet" -a "$METHOD" = "dhcp" ]; then + until [ -n "$ip" -o $index -eq $RETRY ]; do + ip=$(ip -o -family inet addr show dev $IFACE | awk '{split($4, a, "/"); print a[1]}') + index=$((index+1)) + sleep 0.5 + done + if [ -n "$ip" ]; then + echo "Interface $IFACE is up with ip $ip after $index of $RETRY tries." >> $LOG_FILE + else + echo "Interface $IFACE failed to come up with an ip address, giving up after $RETRY tries." >> $LOG_FILE + fi +fi diff --git a/cdist/conf/type/__network_interface/files/debian/ifupdown-symmetric-routing b/cdist/conf/type/__network_interface/files/debian/ifupdown-symmetric-routing new file mode 100755 index 00000000..cdb528ab --- /dev/null +++ b/cdist/conf/type/__network_interface/files/debian/ifupdown-symmetric-routing @@ -0,0 +1,64 @@ +#!/bin/sh +# +# See 'IFACE OPTIONS' in interfaces(5) for available variables. +# + +DEBUG= +#DEBUG=1 +debug() { + if [ "$DEBUG" ]; then + echo "[DEBUG] $@" >&2 + fi +} + +interface="$IFACE" + +# noop for loopback +[ "$interface" = "lo" ] && exit 0 + +# only work with ipv4 +[ "$ADDRFAM" = "inet" ] || exit 0 + +# Interface must be explicitly configured to do symmetric routing. +[ "${IF_SYMMETRIC_ROUTING:-no}" = "no" ] && exit 0 + + +case "$MODE" in + start) + action="up" + ;; + stop) + action="down" + ;; +esac + +case "$METHOD" in + dhcp) + LEASEFILE="/var/lib/dhcp/dhclient.${interface}.leases" + ip_address="$(awk '/fixed-address/ {sub(/;$/,""); print $2}' "$LEASEFILE" | tail -1)" + subnet_mask_or_prefix="$(awk '/option subnet-mask/ {sub(/;$/,""); print $3}' "$LEASEFILE" | tail -1)" + gateway="$(awk '/option routers/ {sub(/;$/,""); print $3}' "$LEASEFILE" | tail -1)" + ;; + static) + [ -n "$IF_ADDRESS" ] && ip_address="$IF_ADDRESS" + [ -n "$IF_NETMASK" ] && subnet_mask_or_prefix="$IF_NETMASK" + [ -n "$IF_GATEWAY" ] && gateway="$IF_GATEWAY" + ;; + *) + echo "Unknown/unsupported METHOD: $METHOD" >&2 + exit 1 + ;; +esac + +debug "$interface -----" +debug "action: $action" +debug "interface: $interface" +debug "ip_address: $ip_address" +debug "subnet_mask_or_prefix: $subnet_mask_or_prefix" +debug "gateway: $gateway" +debug "/$interface -----" + +if [ -n "$action" -a -n "$interface" -a -n "$ip_address" -a -n "$subnet_mask_or_prefix" ]; then + symmetric-routing "$action" "$interface" "$ip_address" "$subnet_mask_or_prefix" "$gateway" +fi + diff --git a/cdist/conf/type/__network_interface/files/debian/interfaces b/cdist/conf/type/__network_interface/files/debian/interfaces new file mode 100644 index 00000000..95fdb011 --- /dev/null +++ b/cdist/conf/type/__network_interface/files/debian/interfaces @@ -0,0 +1,9 @@ +# Generated by cdist __network_interface +# Changes will be overwritten. + +# loopback +auto lo +iface lo inet loopback + +# include per interface configurations +source /etc/network/interfaces.d/*.conf diff --git a/cdist/conf/type/__network_interface/files/debian/manifest b/cdist/conf/type/__network_interface/files/debian/manifest new file mode 100755 index 00000000..1e16c771 --- /dev/null +++ b/cdist/conf/type/__network_interface/files/debian/manifest @@ -0,0 +1,233 @@ +#!/bin/sh -e +# +# 2012-2018 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +__package ifupdown +# Use cumulus ifupdown2 instead of ifupown and ifenslave +# ifupdown2 is currently not compatible with network-wait-online. +#__package ifupdown \ +# --name ifupdown2 + +type_files="$__type/files/debian" +mkdir "$__object/files" +interface_filename="${__object_id}.conf" + +( +cat << DONE +# Created by cdist ${__type##*/} +# Do not change. Changes will be overwritten. +# + +DONE + +if [ -f "$__object/parameter/comment" ]; then + cat "$__object/parameter/comment" | awk '{ print "# "$0 }' +fi + +if [ -f "$__object/parameter/onboot" ]; then + printf "auto %s\n" "$name" +elif [ -f "$__object/parameter/hotplug" ]; then + printf "allow-hotplug %s\n" "$name" +fi + +ignored_parameters="linkdelay" +manually_handled_parameters="name comment extra-config state method onboot hotplug nodns noroute no-network-wait-online symmetric-routing bond-slaves" +case "$method" in + dhcp) + printf "iface %s inet %s\n" "$name" "$method" + ignored_parameters="$ignored_parameters address broadcast gateway netmask" + ;; + static|manual) + printf "iface %s inet %s\n" "$name" "$method" + ;; + *) + echo "Unsupported value for parameter --method. Got '$method'. See man page for supported values." >&2 + exit 1 + ;; +esac + +for param in $(ls "$__object/parameter/"); do + if echo "$ignored_parameters" | grep -w -q "$param"; then + continue + fi + if echo "$manually_handled_parameters" | grep -w -q "$param"; then + continue + fi + + if [ -f "$type_files/name-map" ]; then + key="$(awk -v param=$param '{ if ($1 == param) {print $2;} else { print param;} }' "$type_files/name-map")" + else + key="$param" + fi + printf " %s %s\n" "$key" "$(cat "$__object/parameter/$param")" +done + +if [ -f "$__object/parameter/bond-mode" -o -f "$__object/parameter/bond-primary" ]; then + # Note: ifenslave is not needed when using ifupdown2 + # install package required for bonding + __package ifenslave + if [ -f "$__object/parameter/bond-slaves" ]; then + printf ' bond-slaves %s\n' "$(cat "$__object/parameter/bond-slaves")" + else + # need this or the slave tries to bring the master up, but the master hangs waiting for a slave + printf ' bond-slaves none\n' + fi +fi + +if [ -f "$__object/parameter/no-network-wait-online" ]; then + # Do not consider this interface in network-wait-online.service + printf ' no-network-wait-online yes\n' +fi + +if [ -f "$__object/parameter/symmetric-routing" ]; then + # Deploy scripts that implement the feature ... + __file /sbin/symmetric-routing \ + --owner root --group root --mode 0755 \ + --source "$__type/files/symmetric-routing" + require="__package/ifupdown __file/sbin/symmetric-routing" \ + __file /etc/network/if-up.d/symmetric-routing \ + --owner root --group root --mode 0755 \ + --source "$__type/files/debian/ifupdown-symmetric-routing" + require="__package/ifupdown __file/etc/network/if-up.d/symmetric-routing" \ + __link /etc/network/if-down.d/symmetric-routing \ + --type symbolic \ + --source ../if-up.d/symmetric-routing + # ... then enable it in interface stanza file. + printf ' symmetric-routing yes\n' +fi + +if [ -n "$vlan" -a -n "$device" ]; then + # Explicit parent interface for vlans + printf ' vlan-raw-device %s\n' "$device" +fi + +if [ -f "$__object/parameter/extra-config" ]; then + extra_config="$(cat "$__object/parameter/extra-config")" + if [ "$extra_config" = "-" ]; then + extra_config="$__object/stdin" + fi + awk '{print " " $0}' "$extra_config" +fi + +) >> "$__object/files/$interface_filename" + +__directory /etc/network \ + --state present \ + --owner root \ + --group root \ + --mode 755 + +require="__directory/etc/network" \ + __directory /etc/network/interfaces.d \ + --state present \ + --owner root \ + --group root \ + --mode 755 + +require="__directory/etc/network" \ + __file /etc/network/interfaces \ + --source "$type_files/interfaces" \ + --owner root \ + --group root \ + --mode 644 + +require="__file/etc/network/interfaces __directory/etc/network/interfaces.d" \ + __file "/etc/network/interfaces.d/$interface_filename" \ + --owner root \ + --group root \ + --mode 644 \ + --source "$__object/files/$interface_filename" \ + --state "$state" + + +if [ "$method" = "dhcp" -a -f "$__object/parameter/noroute" ]; then +( +cat << DONE +# Created by cdist ${__type##*/} +# Do not change. Changes will be overwritten. +# + +if [ "\$interface" = "$name" ]; then + +case "\$reason" in + BOUND|RENEW|REBIND|REBOOT) + # prevent default gateway to be set by this interface + unset new_routers + ;; +esac + +fi +DONE +) | \ +__file "/etc/dhcp/dhclient-enter-hooks.d/cdist-__network_interface-${name}-noroute" \ + --owner root \ + --group root \ + --mode 644 \ + --source - \ + --state "$state" +fi # end noroute + +if [ "$method" = "dhcp" -a -f "$__object/parameter/nodns" ]; then +( +cat << DONE +# Created by cdist ${__type##*/} +# Do not change. Changes will be overwritten. +# + +if [ "\$interface" = "$name" ]; then + +# Prevent /etc/resolv.conf from being changed by this interface +# by overriding the default 'make_resolv_conf' function. +make_resolv_conf(){ + : +} + +fi +DONE +) | \ +__file "/etc/dhcp/dhclient-enter-hooks.d/cdist-__network_interface-${name}-nodns" \ + --owner root \ + --group root \ + --mode 644 \ + --source - \ + --state "$state" +fi # end nodns + + +os=$(cat "$__global/explorer/os") +if [ "$os" = "ubuntu" ]; then + # workaround the bloody upstart race conditions + # by deploying a script that delays the emission of the net-device-up + # signal until the interface is really up and configured. + #script_name="00000-wait-for-ip" + #__file "/etc/network/if-up.d/$script_name" \ + # --owner root --group root --mode 755 \ + # --source "$type_files/$script_name" + + # Deal with systemd network-online.target race conditions + require="__package/ifupdown" \ + __file /etc/network/if-pre-up.d/network-online \ + --owner root --group root --mode 0755 \ + --source "$__type/files/debian/network-online" + require="__file/etc/network/if-pre-up.d/network-online" \ + __link /etc/network/if-up.d/network-online \ + --type symbolic \ + --source ../if-pre-up.d/network-online +fi + diff --git a/cdist/conf/type/__network_interface/files/debian/network-online b/cdist/conf/type/__network_interface/files/debian/network-online new file mode 100644 index 00000000..c7e4836d --- /dev/null +++ b/cdist/conf/type/__network_interface/files/debian/network-online @@ -0,0 +1,49 @@ +#!/bin/sh +# +# See 'IFACE OPTIONS' in interfaces(5) for available variables. +# + +DEBUG= +#DEBUG=1 +debug() { + if [ "$DEBUG" ]; then + echo "[DEBUG] $@" >&2 + fi +} + +interface="$IFACE" + +# noop for loopback +[ "$interface" = "lo" ] && exit 0 + +# nothing usefull we could do for '--all' +[ "$interface" = "--all" ] && exit 0 + +# Interface is configured to not be considered by network-wait-online.service +[ "${IF_NO_NETWORK_WAIT_ONLINE:-no}" = "yes" ] && exit 0 + + +case "$MODE" in + start) + action="up" + ;; + stop) + action="down" + ;; +esac + +state_dir=/run/network-online-interfaces +mkdir -p "$state_dir" + +case "$PHASE" in + pre-up) + # Create flag file to wait for in network-wait-online.service + touch "$state_dir/$interface" + ;; + post-up) + # This interface is up! + # Remove the flag file that was created in /sbin/ifup-pre-local + # so that the network-wait-online.service can reach the network-online.target + rm -rf "$state_dir/$interface" + ;; +esac diff --git a/cdist/conf/type/__network_interface/files/network-wait-online.service b/cdist/conf/type/__network_interface/files/network-wait-online.service new file mode 100644 index 00000000..e194b91b --- /dev/null +++ b/cdist/conf/type/__network_interface/files/network-wait-online.service @@ -0,0 +1,17 @@ +[Unit] +Description=Wait for network to be configured +Documentation=man:ifup(8) +DefaultDependencies=no +Conflicts=shutdown.target +After=%NETWORK_SERVICE_NAME% +Before=network-online.target + +[Service] +Type=oneshot +RemainAfterExit=yes +TimeoutStartSec=3min +ExecStart=/bin/sh -ec 'while [ "$(ls -1 /run/network-online-interfaces/)" ]; do sleep 1; done' + +[Install] +WantedBy=network-online.target + diff --git a/cdist/conf/type/__network_interface/files/redhat/ifup-pre-local b/cdist/conf/type/__network_interface/files/redhat/ifup-pre-local new file mode 100755 index 00000000..0030906a --- /dev/null +++ b/cdist/conf/type/__network_interface/files/redhat/ifup-pre-local @@ -0,0 +1,39 @@ +#!/bin/sh + +#echo "/sbin/ifup-pre-local" >&2 +#set -x + +config="$1" +interface="$1" + +cd /etc/sysconfig/network-scripts +. ./network-functions + +[ -f ../network ] && . ../network + +need_config "$config" + +source_config + +# If not started at boot we don't care +[ "${ONBOOT:-no}" = "no" ] && exit 0 + +# noop for loopback +[ "$DEVICE" = "lo" ] && exit 0 + +state_dir=/run/network-online-interfaces +mkdir -p "$state_dir" + +if [ "${NO_NETWORK_WAIT_ONLINE:-no}" = "no" ]; then + # remember device for later use in network-wait-online.service + touch "$state_dir/$DEVICE" +fi + +# hackaround bugs in /etc/sysconfig/network-scripts/ifup +wait_for_device=20 +index=0 +until [ -d "/sys/class/net/$DEVICE" -o $index -eq $wait_for_device ]; do + echo "waiting for /sys/class/net/$DEVICE $index/$wait_for_device" >&2 + sleep 1 + index=$(($index + 1)) +done diff --git a/cdist/conf/type/__network_interface/files/redhat/ifupdown-local b/cdist/conf/type/__network_interface/files/redhat/ifupdown-local new file mode 100755 index 00000000..31a02d0b --- /dev/null +++ b/cdist/conf/type/__network_interface/files/redhat/ifupdown-local @@ -0,0 +1,84 @@ +#!/bin/sh + +myname="${0##*/}" + +case "$myname" in + ifup-local) + action="up" + ;; + ifdown-local|ifdown-pre-local) + action="down" + ;; + *) + echo "Unable to determine action from script name: $myname" >&2 + exit 1 + ;; +esac + +DEBUG= +#DEBUG=1 +debug() { + if [ "$DEBUG" ]; then + echo "[DEBUG] $@" >&2 + fi +} + +interface="$1" + +# noop for loopback +[ "$interface" = "lo" ] && exit 0 + + +cd /etc/sysconfig/network-scripts +. ./network-functions + +[ -f ../network ] && . ../network + +need_config "$interface" +source_config + +case "${BOOTPROTO}" in + bootp|dhcp) + generate_lease_file_name + ip_address="$(awk '/fixed-address/ {sub(/;$/,""); print $2}' "$LEASEFILE" | tail -1)" + subnet_mask_or_prefix="$(awk '/option subnet-mask/ {sub(/;$/,""); print $3}' "$LEASEFILE" | tail -1)" + gateway="$(awk '/option routers/ {sub(/;$/,""); print $3}' "$LEASEFILE" | tail -1)" + ;; + none) + # No ip address set -> nothing we could do + [ -n "$IPADDR" ] && ip_address="$IPADDR" + [ -n "$PREFIX" ] && subnet_mask_or_prefix="$PREFIX" || { + [ -n "$NETMASK" ] && subnet_mask_or_prefix="$NETMASK" + } + [ -n "$GATEWAY" ] && gateway="$GATEWAY" + ;; + *) + echo "Unknown/unsupported BOOTPROTO: $BOOTPROTO" >&2 + exit 1 + ;; +esac + +debug "$interface -----" +debug "action: $action" +debug "interface: $interface" +debug "ip_address: $ip_address" +debug "subnet_mask_or_prefix: $subnet_mask_or_prefix" +debug "gateway: $gateway" +debug "/$interface -----" + +# Interface must be explicitly configured to do symmetric routing. +if [ "${SYMMETRIC_ROUTING:-no}" = "yes" ]; then + if [ -n "$action" -a -n "$interface" -a -n "$ip_address" -a -n "$subnet_mask_or_prefix" ]; then + symmetric-routing "$action" "$interface" "$ip_address" "$subnet_mask_or_prefix" "$gateway" + fi +fi + +case "$action" in + up) + # This interface is up! + # Remove the flag file that was created in /sbin/ifup-pre-local + # so that the network-wait-online.service can reach the network-online.target + state_dir=/run/network-online-interfaces + rm -rf "$state_dir/$interface" + ;; +esac diff --git a/cdist/conf/type/__network_interface/files/redhat/manifest b/cdist/conf/type/__network_interface/files/redhat/manifest new file mode 100755 index 00000000..59f17818 --- /dev/null +++ b/cdist/conf/type/__network_interface/files/redhat/manifest @@ -0,0 +1,171 @@ +#!/bin/sh -e +# +# 2014 Steven Armstrong (steven-cdist at armstrong.cc) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +type_files="$__type/files/redhat" +mkdir "$__object/files" +interface_filename="ifcfg-${name}" + +( +cat << DONE +# Created by cdist ${__type##*/} +# Do not change. Changes will be overwritten. +# + +DONE + +if [ -f "$__object/parameter/comment" ]; then + cat "$__object/parameter/comment" | awk '{ print "# "$0 }' +fi + +printf 'DEVICE="%s"\n' "$name" +printf 'NM_CONTROLLED=no\n' +printf 'USERCTL=no\n' + +if [ -f "$__object/parameter/onboot" ]; then + printf 'ONBOOT=yes\n' +else + printf 'ONBOOT=no\n' +fi +if [ -f "$__object/parameter/hotplug" ]; then + printf 'HOTPLUG=yes\n' +else + printf 'HOTPLUG=no\n' +fi +if [ -f "$__object/parameter/nodns" ]; then + printf 'PEERDNS=no\n' +else + printf 'PEERDNS=yes\n' +fi +if [ -f "$__object/parameter/noroute" ]; then + printf 'DEFROUTE=no\n' +else + printf 'DEFROUTE=yes\n' +fi +if [ -f "$__object/parameter/no-network-wait-online" ]; then + printf 'NO_NETWORK_WAIT_ONLINE=yes\n' +fi +if [ -f "$__object/parameter/symmetric-routing" ]; then + # Deploy scripts that implement the feature ... + __file /sbin/symmetric-routing \ + --owner root --group root --mode 0755 \ + --source "$__type/files/symmetric-routing" + # ... then enable it in interface cfg file. + printf 'SYMMETRIC_ROUTING=yes\n' +fi + +ignored_parameters="" +manually_handled_parameters="name comment extra-config state method onboot hotplug nodns noroute no-network-wait-online symmetric-routing" +case "$method" in + dhcp) + printf 'BOOTPROTO=dhcp\n' + ignored_parameters="$ignored_parameters address broadcast gateway netmask" + ;; + static|manual) + printf 'BOOTPROTO=none\n' + ;; + *) + echo "Unsupported value for parameter --method. Got '$method'. See man page for supported values." >&2 + exit 1 + ;; +esac + +for param in $(ls "$__object/parameter/"); do + if echo "$ignored_parameters" | grep -w -q "$param"; then + continue + fi + if echo "$manually_handled_parameters" | grep -w -q "$param"; then + continue + fi + + case "$param" in + bond-master) + # if someone is my master, I am a slave + printf 'SLAVE=yes\n' + printf 'MASTER=%s\n' "$(cat "$__object/parameter/$param")" + ;; + bond-*) + key="$(echo "${param#*bond-}" | tr - _)" + if [ "$param" = "bond-arp-ip-target" ]; then + value="$(cat "$__object/parameter/$param" | tr '\n' ,)" + # strip trailing comma + value="${value%,}" + else + value="$(cat "$__object/parameter/$param")" + fi + printf '%s=%s\n' "$key" "$value" >> "$__object/files/bonding_opts" + ;; + *) + # check for redhat specific name for this parameter + if [ -f "$type_files/name-map" ]; then + key="$(awk -v param=$param '{ if ($1 == param) {print $2;} else { print param;} }' "$type_files/name-map")" + else + key="$param" + fi + # redhat likes things uppercase + key="$(echo "$key" | tr '[:lower:]' '[:upper:]')" + printf '%s=%s\n' "$key" "$(cat "$__object/parameter/$param")" + ;; + esac +done +if [ -f "$__object/files/bonding_opts" ]; then + value="$(cat "$__object/files/bonding_opts" | tr '\n' ' ')" + # strip trailing space + value="${value% }" + printf 'BONDING_OPTS="%s"\n' "$value" +fi + +if [ -n "$vlan" -a -n "$device" ]; then + # Enable vlan for this interface + printf 'VLAN=yes\n' +fi + +if [ -f "$__object/parameter/extra-config" ]; then + extra_config="$(cat "$__object/parameter/extra-config")" + if [ "$extra_config" = "-" ]; then + extra_config="$__object/stdin" + fi + cat "$extra_config" +fi + + +) >> "$__object/files/$interface_filename" + +__file "/etc/sysconfig/network-scripts/$interface_filename" \ + --owner root \ + --group root \ + --mode 644 \ + --source "$__object/files/$interface_filename" \ + --state "$state" + +# Deploy helper scripts +__file /sbin/ifupdown-local \ + --owner root --group root --mode 0755 \ + --source "$__type/files/redhat/ifupdown-local" +require="__file/sbin/ifupdown-local" \ + __link /sbin/ifup-local \ + --type symbolic \ + --source ./ifupdown-local +require="__file/sbin/ifupdown-local" \ + __link /sbin/ifdown-pre-local \ + --type symbolic \ + --source ./ifupdown-local +__file /sbin/ifup-pre-local \ + --owner root --group root --mode 0755 \ + --source "$__type/files/redhat/ifup-pre-local" diff --git a/cdist/conf/type/__network_interface/files/redhat/name-map b/cdist/conf/type/__network_interface/files/redhat/name-map new file mode 100644 index 00000000..3e4decf6 --- /dev/null +++ b/cdist/conf/type/__network_interface/files/redhat/name-map @@ -0,0 +1 @@ +address ipaddr diff --git a/cdist/conf/type/__network_interface/files/symmetric-routing b/cdist/conf/type/__network_interface/files/symmetric-routing new file mode 100755 index 00000000..ecedfff9 --- /dev/null +++ b/cdist/conf/type/__network_interface/files/symmetric-routing @@ -0,0 +1,240 @@ +#!/bin/sh +# + +set -e + +error() { + echo "[ERROR] $@" >&2 +} +die() { + error "$@" + exit 1 +} +info() { + echo "[INFO] $@" >&2 +} +debug() { + if [ "$DEBUG" ]; then + echo "[DEBUG] $@" >&2 + fi +} + +usage() { + cat << EOS 1>&2 +Usage: ${0##*/} [OPTIONS] ACTION INTERFACE IP_ADDRESS SUBNET_MASK_OR_PREFIX [GATEWAY] +(see -h for more information) +EOS +} + +help() { + usage 2>&1 | head -n -1 1>&2 + + cat << EOS 1>&2 + +Setup policy based routing for the given interface +to ensure symmetric routing. + +ACTION must be either 'up' or 'down' to add respectively remove the +routing table entries. + +Options: + -h show this help message + -d run in debug mode + -x run with 'set -x' set + -n no action, just show what would be done without doing it + +Examples: + ${0##*/} up eth1 192.168.42.23 255.255.255.0 192.168.0.1 + ${0##*/} down eth1 192.168.42.23 255.255.255.0 192.168.0.1 + # gateway is optional + ${0##*/} up eth1 192.168.42.23 255.255.255.0 + ${0##*/} down eth1 192.168.42.23 255.255.255.0 + # same but using prefix instead of subnet mask + ${0##*/} up eth1 192.168.42.23 24 192.168.0.1 + ${0##*/} down eth1 192.168.42.23 24 192.168.0.1 + +EOS +} + +die_usage() { + error "$@" + usage + exit 1 +} + + +### Utility functions + +# Convert ip to int. +ip2int() { + _ip="$1" + { IFS=. read _a _b _c _d; } << _done +$_ip +_done + echo $(((((((_a << 8) | _b) << 8) | _c) << 8) | _d)) + unset _ip _a _b _c _d +} + +# Convert int to ip. +int2ip() { + _ui32=$1; shift + _ip= + for _n in 1 2 3 4; do + _ip=$((_ui32 & 0xff))${_ip:+.}$_ip + _ui32=$((_ui32 >> 8)) + done + echo $_ip + unset _ui32 _ip _n +} + +# Convert the given prefix into a subnet mask. +mask_from_prefix() { + _prefix="$1" + _mask=$((0xffffffff << (32 - $_prefix))) + int2ip $_mask + unset _prefix _mask +} + +# Calculate network number from the given ip and prefix. +network_from_ip_and_prefix() { + _ip="$1" + _prefix="$2" + _addr=$(ip2int $_ip) + _mask=$((0xffffffff << (32 - $_prefix))) + int2ip $((_addr & _mask)) + unset _ip _prefix _addr _mask +} + +# Calculate number of bits in the given subnet mask. +prefix_from_mask() { + # Assumes there's no "255." after a non-255 byte in the mask + _mask="$1" + _x=${_mask##*255.} + set -- 0^^^128^192^224^240^248^252^254^ $(( (${#1} - ${#_x})*2 )) ${_x%%.*} + _x=${1%%$3*} + echo $(( $2 + (${#_x}/4) )) + unset _mask _x +} + +rt_tables=/etc/iproute2/rt_tables +#rt_tables=/tmp/rt_tables +# Get and if required create a routing table for the given table name. +table_id_from_name() { + _interface="$1" + _table_id=$(awk -vname=$_interface '{ if ($2 == name) print $1 }' "$rt_tables") + if [ -z "$_table_id" ]; then + # find unused table id and create a new table for this interface + _used_ids=$(awk '$1 !~ /^(#| |255|254|253|0)/ { print $1 }' "$rt_tables") + for _tid in $(seq 1 252); do + if echo "$_used_ids" | grep -q "$_tid"; then + continue + else + _table_id="$_tid" + [ $NOACTION ] || printf '%s %s\n' "$_table_id" "$_interface" >> "$rt_tables" + break + fi + done + fi + echo "$_table_id" + unset _interface _table_id _used_ids _tid +} + + +### Parse command line arguments + +NOACTION= +DEBUG= +SETX= +while getopts "ndxh" options +do + #echo "$flag" $OPTIND $OPTARG + case $options in + n) NOACTION=1;; + d) DEBUG=1;; + x) SETX=1;; + ?|h) help + exit 0 + ;; + *) usage + exit 1 + ;; + esac +done +# Strip arguments allready handled by getopts +shift $((OPTIND-1)) + +[ "$SETX" ] && set -x + +# Validate arguments +[ "$#" -ge 4 ] || die_usage "Expected at least 4 arguments, got: $#" + +action="$1" # up | down +interface="$2" +ip_address="$3" +subnet_mask_or_prefix="$4" +gateway="$5" + +debug "action: $action" +debug "interface: $interface" +debug "ip_address: $ip_address" +debug "subnet_mask_or_prefix: $subnet_mask_or_prefix" +debug "gateway: $gateway" + + +case "$subnet_mask_or_prefix" in + *.*) + # has a dot, must be a subnet mask + subnet_mask="$subnet_mask_or_prefix" + prefix=$(prefix_from_mask "$subnet_mask") + network="$(network_from_ip_and_prefix "$ip_address" "$prefix")" + ;; + *) + # no dot, must be prefix + prefix="$subnet_mask_or_prefix" + subnet_mask="$(mask_from_prefix "$prefix")" + network="$(network_from_ip_and_prefix "$ip_address" "$prefix")" + ;; +esac + +table_name="$interface" +table_id="$(table_id_from_name "$table_name")" + +debug "subnet_mask: $subnet_mask" +debug "prefix: $prefix" +debug "network: $network" +debug "table_name: $table_name" +debug "table_id: $table_id" + +( +case "$action" in + up) + # setup routing table for interface + printf 'ip route add "%s/%s" dev "%s" proto static src "%s" table "%s"\n' \ + "$network" "$prefix" "$interface" "$ip_address" "$table_name" + if [ -n "$gateway" ]; then + printf 'ip route add default via "%s" table "%s"\n' "$gateway" "$table_name" + fi + printf 'ip rule add from "%s" table "%s"\n' "$ip_address" "$table_name" + ;; + down) + printf 'ip rule del from "%s" table "%s"\n' "$ip_address" "$table_name" + if [ -n "$gateway" ]; then + printf 'ip route del default via "%s" table "%s"\n' "$gateway" "$table_name" + fi + printf 'ip route del "%s/%s" dev "%s" proto static src "%s" table "%s"\n' \ + "$network" "$prefix" "$interface" "$ip_address" "$table_name" + ;; + *) + echo "Unknown action: $action" >&2 + exit 1 + ;; +esac +# tell the kernel that it needs to re-parse the policy database +printf 'ip route flush cache\n' +) | ( + if [ "$NOACTION" ]; then + cat + else + /bin/sh -s + fi +) diff --git a/cdist/conf/type/__network_interface/man.text b/cdist/conf/type/__network_interface/man.text new file mode 100644 index 00000000..c9115e99 --- /dev/null +++ b/cdist/conf/type/__network_interface/man.text @@ -0,0 +1,167 @@ +cdist-type__network_interface(7) +================================ +Steven Armstrong + + +NAME +---- +cdist-type__network_interface - configure network interfaces + + +DESCRIPTION +----------- +Configures network interfaces on debian an redhat based systems. +Interface names containing a dot are assumed to be vlan tagged sub interfaces. +e.g. eth0.10 is vlan 10 on physical device eth0 + + +REQUIRED PARAMETERS +------------------- + + +OPTIONAL PARAMETERS +------------------- +name:: + The name of the physical or logical network device. + Defaults to __object_id. +method:: + The method for determining an IP address for the interface. + 'dhcp', 'static' or 'manual'. + Defaults to 'dhcp'. +address:: + The IP address of the network interface. + Only used if --method is not 'dhcp' +broadcast:: + Only used if --method is not 'dhcp' +comment:: +extra-config:: + additional config that is added to the generated interfaces file verbatim +gateway:: + Default gateway (dotted quad) + Only used if --method is not 'dhcp' +netmask:: + The subnet mask to apply to the interface + Only used if --method is not 'dhcp' +metric:: + Routing metric for the default gateway +mtu:: + The Maximum Transmission Unit size to use for the interface +state:: + 'present' or 'absent', defaults to 'present' +bond-arp-interval:: + Specifies (in milliseconds) how often ARP monitoring occurs. +bond-arp-ip-target:: + Specifies the target IP address of ARP requests when the arp_interval parameter is enabled. + Can be specified up to 16 times. +bond-master:: + The name of the master (bonding) interface to which this slave should be enslaved. +bond-miimon:: + Specifies (in milliseconds) how often MII link monitoring occurs. +bond-mode:: + Allows you to specify the bonding policy. The value can be one of: + balance-rr (0) + active-backup (1) + balance-xor (2) + broadcast (3) + 802.3ad (4) + balance-tlb (5) + balance-alb (6) +bond-primary:: + Specifies the interface name, such as eth0, of the primary device. +bond-slaves:: + The slave interfaces that form this bonding. +linkdelay:: + Only useable on Redhat based systems. + Time in seconds that the system should pause after the specific interface + is enabled. This may be useful if one interface is connected to a + switch which has spanning tree enabled and must wait for STP to + converge before the interface should be considered usable. + + +BOOLEAN PARAMETERS +------------------ +onboot: + Whether to bring the interface up on boot +hotplug:: + Allow/disallow hotplug support for this interface +nodns:: + Do not configure nameservers in /etc/resolv.conf. +noroute:: + Do not set default route. +no-network-wait-online:: + Do not consider this network interface in the network-wait-online.service unit. +symmetric-routing:: + Manage routing tables and rules to ensure symmetric routing. + + +EXAMPLES +-------- + +-------------------------------------------------------------------------------- +__network_interface eth0 --onboot +# Same thing, but explicitly define method +__network_interface eth0 --method dhcp --onboot + +__network_interface eth1 \ + --method static \ + --address 192.168.42.23 \ + --netmask 255.255.255.0 \ + --gateway 192.168.42.1 \ + --onboot + +__network_interface eth3 --method dhcp --hotplug + + +# Don't wait for Infiniband interface to be up before reaching systemd network-online.target +__network_interface ib0 --method dhcp --no-network-wait-online + +# active-backup bonding with 2 slaves +__network_interface bond0 \ + --onboot \ + --method static \ + --bond-mode active-backup \ + --bond-miimon 500 \ + --bond-primary eth5 \ + --address 10.205.9.65 \ + --netmask 255.255.224.0 + +__network_interface eth5 \ + --onboot \ + --method manual \ + --bond-master bond0 + +__network_interface eth6 \ + --onboot \ + --method manual \ + --bond-master bond0 + + +# extra config +__network_interface eth0 \ + --method dhcp \ + --extra-config - << DONE +post-up ip route add 10.205.0.0/19 via 10.205.161.1 +post-up ip route add 10.205.96.0/19 via 10.205.161.1 +pre-down ip route del 10.205.0.0/19 via 10.205.161.1 +pre-down ip route del 10.205.96.0/19 via 10.205.161.1 +DONE +-------------------------------------------------------------------------------- + + +SEE ALSO +-------- +- cdist-type(7) +- Redhat bonding documentation + https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/sec-Using_Channel_Bonding.html + https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Networking_Guide/sec-Using_Channel_Bonding.html + https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/s2-networkscripts-interfaces-chan.html +- Debian bonding documentation + /usr/share/doc/ifenslave-2.6/README.Debian.gz +- Symmetric routing + http://www.microhowto.info/howto/ensure_symmetric_routing_on_a_server_with_multiple_default_gateways.html + + +COPYING +------- +Copyright \(C) 2012-2016 Steven Armstrong. Free use of this software is +granted under the terms of the GNU General Public License version 3 (GPLv3). diff --git a/cdist/conf/type/__network_interface/manifest b/cdist/conf/type/__network_interface/manifest new file mode 100755 index 00000000..0fed7894 --- /dev/null +++ b/cdist/conf/type/__network_interface/manifest @@ -0,0 +1,86 @@ +#!/bin/sh -e +# +# 2012-2014 Steven Armstrong (steven-cdist at armstrong.cc) +# 2020 Adapted for upstream cdist by Darko Poljak (darko.poljak at gmail.com) +# +# This file is part of cdist. +# +# cdist is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# cdist is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with cdist. If not, see . +# + +os=$(cat "$__global/explorer/os") +osv="$(cat "$__global/explorer/os_version")" + +not_supported() { + echo "Your operating system ($os $osv) is currently not supported by this type (${__type##*/})." >&2 + echo "Please contribute an implementation for it if you can." >&2 + exit 1 +} + +case "$os" in + ubuntu) + osv_int="$(echo "$osv" | tr -d .)" + if [ "$osv_int" -lt 1110 ]; then + not_supported + fi + manifest_file="$__type/files/debian/manifest" + systemd_network_service_name="networking.service" + ;; + debian) + manifest_file="$__type/files/debian/manifest" + systemd_network_service_name="networking.service" + ;; + centos|redhat) + manifest_file="$__type/files/redhat/manifest" + systemd_network_service_name="network.service" + ;; + *) + not_supported + ;; +esac + +name="$(cat "$__object/parameter/name" 2>/dev/null || echo "$__object_id")" +method="$(cat "$__object/parameter/method")" +state="$(cat "$__object/parameter/state")" + +device= +vlan= +case "$name" in + *.*) + device="${name%.*}" + vlan="${name#*.}" + ;; +esac + + +# export variables +export name +export device +export vlan +export method +export state + +# run os specific manifest +"$manifest_file" + + +if grep -q systemd "$__global/explorer/init"; then + sed -e "s|%NETWORK_SERVICE_NAME%|${systemd_network_service_name}|" \ + "$__type/files/network-wait-online.service" | \ + __file /etc/systemd/system/network-wait-online.service \ + --owner root --group root --mode 0644 \ + --source - + require="__file/etc/systemd/system/network-wait-online.service" \ + __service network-wait-online --no-start +fi diff --git a/cdist/conf/type/__network_interface/parameter/boolean b/cdist/conf/type/__network_interface/parameter/boolean new file mode 100644 index 00000000..a15f76a2 --- /dev/null +++ b/cdist/conf/type/__network_interface/parameter/boolean @@ -0,0 +1,6 @@ +hotplug +nodns +noroute +onboot +no-network-wait-online +symmetric-routing diff --git a/cdist/conf/type/__network_interface/parameter/default/method b/cdist/conf/type/__network_interface/parameter/default/method new file mode 100644 index 00000000..72ab18f1 --- /dev/null +++ b/cdist/conf/type/__network_interface/parameter/default/method @@ -0,0 +1 @@ +dhcp diff --git a/cdist/conf/type/__network_interface/parameter/default/state b/cdist/conf/type/__network_interface/parameter/default/state new file mode 100644 index 00000000..e7f6134f --- /dev/null +++ b/cdist/conf/type/__network_interface/parameter/default/state @@ -0,0 +1 @@ +present diff --git a/cdist/conf/type/__network_interface/parameter/optional b/cdist/conf/type/__network_interface/parameter/optional new file mode 100644 index 00000000..17a87788 --- /dev/null +++ b/cdist/conf/type/__network_interface/parameter/optional @@ -0,0 +1,20 @@ +address +bond-arp-interval +bond-arp-ip-target +bond-master +bond-miimon +bond-mode +bond-primary +bond-slaves +broadcast +comment +extra-config +gateway +linkdelay +method +metric +mtu +name +netmask +network +state