2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2026-09-04 20:17:55 +00:00

fix(xcat-core): configure Ubuntu networking with netplan in configeth

Write /etc/netplan/90-xcat-<nic>.yaml and `netplan apply` on Debian/Ubuntu nodes whose
network is rendered by netplan, instead of /etc/network/interfaces.d/* which ifupdown
is no longer present to read. The legacy branch is kept for nodes that still run
ifupdown, selected on whether netplan is actually installed. Fixes #7454.

The drop-in is regenerated in full on every change rather than edited in place. Its
inputs are recorded in "# xcat-state:" comment lines in the same file, which netplan
ignores, so the file stays the single source of truth and re-rendering is idempotent.
That is what makes the three properties below hold; an in-place sed editor cannot.

A NIC named <parent>.<vid> is emitted under vlans: with id and link, so netplan
recreates the VLAN after a reboot -- the ifupdown branch has always written
vlan-raw-device for these, and declaring them as plain ethernets would lose that. A
dotted name whose suffix is not numeric stays an ethernet.

Addresses keep the order they were added, and a route is deduplicated on the whole
(to, via) pair so a second route sharing a gateway is still written.

nicextraparams are carried across into the interface stanza, matching what the
ifupdown branch does with them.

Signed-off-by: Daniel Hilst <392820+dhilst@users.noreply.github.com>
This commit is contained in:
Daniel Hilst
2026-08-24 14:47:42 -03:00
parent f0944d3c7f
commit fff73aae5f
+177 -4
View File
@@ -40,6 +40,149 @@ fi
str_conf_file=""
str_conf_file_xcatbak=""
tmp_con_name=""
# ---------------------------------------------------------------------------
# netplan support (Ubuntu 18.04+, issue #7454)
#
# On a netplan-rendered Debian/Ubuntu node ifupdown is not installed and
# /etc/network/interfaces.d/* is ignored entirely, so writing there configures nothing.
# Write /etc/netplan/*.yaml and `netplan apply` instead.
#
# The drop-in this owns is regenerated in full on every change rather than edited in place,
# because inserting into the middle of a YAML list with sed reverses multi-address order and
# cannot tell one route's fields from another's. The inputs are kept in "# xcat-state:" comment
# lines at the top of the same file: netplan ignores comments, the file stays the single source
# of truth, and re-rendering is idempotent.
# ---------------------------------------------------------------------------
netplan_active=0
if command -v netplan >/dev/null 2>&1 && [ -d /etc/netplan ]; then
netplan_active=1
fi
# netplan_file <nic> -- the per-NIC drop-in this script owns. NETPLAN_DIR overrides the
# directory so the writers can be unit tested without touching the real configuration.
netplan_file(){
echo "${NETPLAN_DIR:-/etc/netplan}/90-xcat-${1}.yaml"
}
_netplan_state(){ # <nic> <kind> -- emit the recorded values of one kind, in insertion order
local f
f="$(netplan_file "$1")"
[ -f "$f" ] || return 0
sed -n "s/^# xcat-state: $2 //p" "$f"
}
_netplan_record(){ # <nic> <kind> <value> -- record once, preserving order
local nic="$1" kind="$2" value="$3" f
f="$(netplan_file "$nic")"
if [ -f "$f" ] && grep -qxF "# xcat-state: $kind $value" "$f"; then
return 0
fi
printf '# xcat-state: %s %s\n' "$kind" "$value" >> "$f"
}
# _netplan_render <nic> -- rebuild the whole drop-in from its recorded state.
# A NIC named <parent>.<vid> is a VLAN and MUST be declared under vlans: with id and link, or
# netplan will not recreate it after a reboot; anything else is a plain ethernet.
_netplan_render(){
local nic="$1" f tmp section parent vid addr route to via mtu name value
f="$(netplan_file "$nic")"
tmp="${f}.tmp.$$"
section="ethernets"
parent=""
vid=""
case "$nic" in
*.*)
parent="${nic%.*}"
vid="${nic##*.}"
case "$vid" in
''|*[!0-9]*) parent=""; vid="" ;; # not <parent>.<numeric vid>
*) section="vlans" ;;
esac
;;
esac
{
# keep the recorded state at the top so the next call can read it back
[ -f "$f" ] && grep '^# xcat-state: ' "$f"
echo "network:"
echo " version: 2"
echo " ${section}:"
echo " ${nic}:"
if [ "$section" = "vlans" ]; then
echo " id: ${vid}"
echo " link: ${parent}"
fi
if [ -n "$(_netplan_state "$nic" addr)" ]; then
echo " addresses:"
_netplan_state "$nic" addr | while read -r addr; do
[ -n "$addr" ] && echo " - ${addr}"
done
fi
mtu="$(_netplan_state "$nic" mtu | tail -1)"
[ -n "$mtu" ] && echo " mtu: ${mtu}"
if [ -n "$(_netplan_state "$nic" route)" ]; then
echo " routes:"
_netplan_state "$nic" route | while read -r route; do
to="${route%% *}"
via="${route#* }"
[ -n "$to" ] && printf ' - to: %s\n via: %s\n' "$to" "$via"
done
fi
# nicextraparams, passed through as interface keys. The ifupdown path below writes
# these into the interface stanza; dropping them on netplan nodes would silently
# discard configuration the user asked for.
_netplan_state "$nic" param | while read -r param; do
name="${param%% *}"
value="${param#* }"
[ -n "$name" ] && echo " ${name}: ${value}"
done
} > "$tmp"
mv -f "$tmp" "$f"
chmod 600 "$f" 2>/dev/null
}
# write_netplan_addr <nic> <addr/prefix> [mtu] -- add an address (IPv4 or IPv6). Idempotent per
# address, and preserves the order in which addresses were added.
write_netplan_addr(){
local nic="$1" cidr="$2" mtu="$3" f
f="$(netplan_file "$nic")"
[ -f "$f" ] || : > "$f"
_netplan_record "$nic" addr "$cidr"
if [ -n "$mtu" ] && [ "$mtu" != "$str_default_token" ]; then
# last mtu wins; drop any previously recorded one so the state stays single-valued
sed -i '/^# xcat-state: mtu /d' "$f"
_netplan_record "$nic" mtu "$mtu"
fi
_netplan_render "$nic"
}
# write_netplan_route <nic> <to> <via> -- add a route. Idempotent on the (to, via) pair.
write_netplan_route(){
local nic="$1" to="$2" via="$3" f
f="$(netplan_file "$nic")"
[ -f "$f" ] || return 0
_netplan_record "$nic" route "$to $via"
_netplan_render "$nic"
}
# write_netplan_param <nic> <name> <value> -- record a nicextraparams key for this interface.
write_netplan_param(){
local nic="$1" name="$2" value="$3" f
f="$(netplan_file "$nic")"
[ -f "$f" ] || : > "$f"
sed -i "/^# xcat-state: param ${name} /d" "$f"
_netplan_record "$nic" param "$name $value"
_netplan_render "$nic"
}
function configipv4(){
str_if_name=$1
str_v4ip=$2
@@ -111,7 +254,18 @@ function configipv4(){
if [[ ${str_if_name} == [a-zA-Z0-9]*.[0-9]* ]]; then
echo "VLAN=yes" >> $str_conf_file
fi
#debian ubuntu
#ubuntu/debian rendered by netplan (18.04+): ifupdown is absent and interfaces.d is
#ignored, so write /etc/netplan/*.yaml instead (issue #7454)
elif [ "$str_os_type" = "debian" ] && [ "$netplan_active" = "1" ];then
str_prefix=$(v4mask2prefix $str_v4mask)
write_netplan_addr "${str_if_name}" "${str_v4ip}/${str_prefix}" "${str_nic_mtu}"
i=0
while [ $i -lt ${#array_extra_param_names[@]} ]
do
write_netplan_param "${str_if_name}" "${array_extra_param_names[$i]}" "${array_extra_param_values[$i]}"
i=$((i+1))
done
#debian ubuntu (legacy ifupdown)
elif [ "$str_os_type" = "debian" ];then
str_conf_file="/etc/network/interfaces.d/${str_if_name}"
if [ $num_v4num -eq 0 ];then
@@ -290,6 +444,13 @@ configipv6(){
fi
i=$((i+1))
done
#ubuntu/debian rendered by netplan (18.04+) -- see configipv4 (issue #7454)
elif [ "$str_os_type" = "debian" ] && [ "$netplan_active" = "1" ];then
write_netplan_addr "${str_if_name}" "${str_v6ip}/${str_v6prefix}" "${str_nic_mtu}"
if [ "$str_v6gateway" != "$str_default_token" ] && [ -n "$str_v6gateway" ] \
&& echo "$str_v6gateway" | grep -qv 'xcatmaster'; then
write_netplan_route "${str_if_name}" "default" "${str_v6gateway}"
fi
elif [ "$str_os_type" = "debian" ];then
#debian or ubuntu
str_conf_file="/etc/network/interfaces.d/${str_if_name}"
@@ -393,7 +554,9 @@ function delete_nic_config_files(){
str_temp_name=$1
#delete the configuration files
#delete the configuration history
if [ "$str_os_type" = "debian" ];then
if [ "$str_os_type" = "debian" ] && [ "$netplan_active" = "1" ];then
rm -f "$(netplan_file "$str_temp_name")" 2>/dev/null
elif [ "$str_os_type" = "debian" ];then
rm -f /etc/network/interfaces.d/$str_temp_name 2>/dev/null
sed -i "/${str_temp_name}/d" /etc/network/xcat_history_important
elif [ "$str_os_type" = "sles" ];then
@@ -869,7 +1032,9 @@ elif [ "$1" = "-s" ];then
if [ "$UPDATENODE" = "1" ] || [ "$NODESETSTATE" = "netboot" ] || [ "$NODESETSTATE" = "statelite" ] || grep "REBOOT=TRUE" /opt/xcat/xcatinfo >/dev/null 2>&1; then
if_state=0
if [ "$str_os_type" = "debian" ];then
if [ "$str_os_type" = "debian" ] && [ "$netplan_active" = "1" ];then
: # netplan apply below reconfigures the interface; no ifdown needed
elif [ "$str_os_type" = "debian" ];then
ifdown --force $str_inst_nic
else
ip link set dev $str_inst_nic down
@@ -878,6 +1043,8 @@ elif [ "$1" = "-s" ];then
nmcli con modify $con_name ipv4.dns "${NAMESERVERS}"
nmcli con reload
nmcli con up $con_name
elif [ "$str_os_type" = "debian" ] && [ "$netplan_active" = "1" ]; then
netplan apply
else
ifup $str_inst_nic
fi
@@ -1285,7 +1452,13 @@ else
#restart the nic
if [ $bool_restart_flag -eq 1 ];then
if [ "$str_os_type" = "debian" ];then
if [ "$str_os_type" = "debian" ] && [ "$netplan_active" = "1" ];then
netplan apply
if [ $? -ne 0 ]; then
log_error "netplan apply failed."
error_code=1
fi
elif [ "$str_os_type" = "debian" ];then
ifup -a -i /etc/network/interfaces.d/$str_nic_name
if [ $? -ne 0 ]; then
log_error "ifup -a -i /etc/network/interfaces.d/$str_nic_name failed."