mirror of
https://github.com/xcat2/xcat-core.git
synced 2026-09-04 12:07:56 +00:00
Merge pull request #7762 from VersatusHPC/fix/configeth-netplan
fix(xcat-core): configeth configures nothing on netplan-rendered Ubuntu nodes
This commit is contained in:
@@ -0,0 +1,334 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use File::Spec;
|
||||
use File::Temp qw(tempdir);
|
||||
use FindBin;
|
||||
use Test::More;
|
||||
|
||||
# Regression (issue #7454): on Ubuntu 18.04+ the network is rendered by netplan. ifupdown is
|
||||
# not installed and /etc/network/interfaces.d/* is ignored entirely, so configeth's Debian
|
||||
# branch configured nothing at all. It must write /etc/netplan/*.yaml and `netplan apply`.
|
||||
#
|
||||
# These tests drive configipv4/configipv6/delete_nic_config_files -- the branch selection that
|
||||
# is the actual fix -- rather than the private write_netplan_* writers underneath them. Driving
|
||||
# only the writers passes even when the netplan branch is deleted from configipv4 outright.
|
||||
#
|
||||
# netplan parses every file under /etc/netplan as ONE document, so anything it rejects takes the
|
||||
# whole node's network with it rather than one interface. Where netplan is installed (it is on
|
||||
# the ubuntu-24.04 CI runner) the last test feeds the generated tree to the real parser.
|
||||
|
||||
my $repo_root = File::Spec->rel2abs(
|
||||
File::Spec->catdir( $FindBin::Bin, '..', '..' )
|
||||
);
|
||||
my $configeth = File::Spec->catfile( $repo_root, 'xCAT', 'postscripts', 'configeth' );
|
||||
plan skip_all => "configeth not found" unless -f $configeth;
|
||||
|
||||
my $src = do { local $/; open my $fh, '<', $configeth or die $!; <$fh> };
|
||||
|
||||
# Everything from the netplan detection through delete_nic_config_files: the writers, the
|
||||
# configipv4/configipv6 dispatch, and the removal path. BAIL_OUT rather than skip, so that a
|
||||
# rename which stops this matching fails loudly instead of silently covering nothing.
|
||||
my ($unit) = $src =~ /^(netplan_active=0\n.*?\nfunction delete_nic_config_files\(\)\{.*?\n\})\n/ms;
|
||||
BAIL_OUT('could not extract the netplan unit from configeth') unless defined $unit;
|
||||
|
||||
my $dir = tempdir( CLEANUP => 1 );
|
||||
|
||||
# The real sentinel configeth uses for "this attribute is unset" (configeth sets
|
||||
# str_default_token="default"); a made-up token here would let a hard-coded literal pass.
|
||||
my ($token) = $src =~ /^str_default_token="([^"]+)"/m;
|
||||
BAIL_OUT('could not read str_default_token from configeth') unless defined $token;
|
||||
is( $token, 'default', 'the harness drives the sentinel configeth actually uses' );
|
||||
|
||||
my $run_no = 0;
|
||||
|
||||
# Run a snippet against the extracted unit. netplan/ifup/systemctl and wait_for_ifstate are
|
||||
# shadowed by shell functions, which bash resolves ahead of $PATH, so nothing here touches the
|
||||
# host's network however the suite is run -- and `netplan apply` is recorded, not executed.
|
||||
sub run_configeth {
|
||||
my ($script) = @_;
|
||||
$run_no++;
|
||||
my $root = File::Spec->catdir( $dir, "run$run_no" );
|
||||
mkdir $root;
|
||||
mkdir File::Spec->catdir( $root, 'etc' );
|
||||
mkdir File::Spec->catdir( $root, 'etc', 'netplan' );
|
||||
|
||||
my $harness = File::Spec->catfile( $root, 'harness.sh' );
|
||||
open my $fh, '>', $harness or die $!;
|
||||
print $fh <<"PRE";
|
||||
#!/bin/bash
|
||||
NODE=cn1
|
||||
str_default_token='$token'
|
||||
str_os_type=debian
|
||||
str_cfg_dir='$root/'
|
||||
export NETPLAN_DIR='$root/etc/netplan'
|
||||
log_info(){ :; }
|
||||
log_warn(){ echo "WARN: \$*" >> '$root/warnings'; }
|
||||
log_error(){ echo "ERR: \$*" >> '$root/warnings'; }
|
||||
netplan(){ echo "netplan \$*" >> '$root/applied'; }
|
||||
wait_for_ifstate(){ return 0; }
|
||||
ip(){ :; }
|
||||
v4mask2prefix(){
|
||||
local m=\$1 p=0 o
|
||||
for o in \${m//./ }; do
|
||||
case \$o in
|
||||
255) p=\$((p+8));; 254) p=\$((p+7));; 252) p=\$((p+6));; 248) p=\$((p+5));;
|
||||
240) p=\$((p+4));; 224) p=\$((p+3));; 192) p=\$((p+2));; 128) p=\$((p+1));;
|
||||
esac
|
||||
done
|
||||
echo \$p
|
||||
}
|
||||
parse_nic_extra_params(){
|
||||
unset array_extra_param_names array_extra_param_values
|
||||
local k=0 t
|
||||
for t in \$1; do
|
||||
array_extra_param_names[\$k]=\${t%%=*}
|
||||
array_extra_param_values[\$k]=\${t#*=}
|
||||
k=\$((k+1))
|
||||
done
|
||||
}
|
||||
declare -a array_extra_param_names
|
||||
declare -a array_extra_param_values
|
||||
PRE
|
||||
print $fh "$unit\n";
|
||||
# the detection above ran against the real host; these tests are about the netplan branch
|
||||
print $fh "netplan_active=1\n";
|
||||
print $fh "$script\n";
|
||||
close $fh;
|
||||
system( '/bin/bash', $harness ) == 0 or die "harness failed";
|
||||
return $root;
|
||||
}
|
||||
|
||||
sub yaml_of {
|
||||
my ( $root, $nic ) = @_;
|
||||
my $f = File::Spec->catfile( $root, 'etc', 'netplan', "90-xcat-$nic.yaml" );
|
||||
return '' unless -f $f;
|
||||
local $/;
|
||||
open my $fh, '<', $f or die $!;
|
||||
my $c = <$fh>;
|
||||
# the "# xcat-state:" lines are this writer's own bookkeeping, not netplan config
|
||||
$c =~ s/^# xcat-state:.*\n//mg;
|
||||
return $c;
|
||||
}
|
||||
|
||||
sub slurp { my ($p) = @_; return '' unless -f $p; local $/; open my $f, '<', $p or die $!; return <$f>; }
|
||||
|
||||
# --- configipv4 drives the netplan branch ------------------------------------
|
||||
# Two addresses, an mtu, a real nicextraparams pair, and an unset-mtu sentinel.
|
||||
my $r = run_configeth( <<'SH' );
|
||||
configipv4 eth0 10.0.0.5 10.0.0.0 255.255.255.0 0 "MTU=1500 ONBOOT=no" 1500
|
||||
configipv4 eth0 10.0.1.5 10.0.1.0 255.255.255.0 1 default default
|
||||
SH
|
||||
|
||||
my $eth0 = yaml_of( $r, 'eth0' );
|
||||
ok( length $eth0, 'configipv4 writes a netplan drop-in on a netplan node' );
|
||||
like( $eth0, qr/^ ethernets:$/m, 'a plain NIC is declared under ethernets:' );
|
||||
unlike( $eth0, qr/^ vlans:$/m, 'a plain NIC is not declared as a vlan' );
|
||||
like( $eth0, qr/addresses:\n\s*- 10\.0\.0\.5\/24\n\s*- 10\.0\.1\.5\/24/,
|
||||
'multiple addresses keep the order they were added' );
|
||||
like( $eth0, qr/^ mtu: 1500$/m, 'an MTU nicextraparam maps onto the netplan mtu key' );
|
||||
|
||||
# netplan merges same-id netdefs across files key by key, so an earlier cloud-init dhcp4:true
|
||||
# survives unless this stanza turns it off explicitly.
|
||||
like( $eth0, qr/^ dhcp4: false$/m, 'DHCP is switched off for a statically addressed NIC' );
|
||||
like( $eth0, qr/^ dhcp6: false$/m, 'DHCP6 is switched off for a statically addressed NIC' );
|
||||
|
||||
# ONBOOT is an ifcfg key with no netplan meaning; passing it through fails the whole file.
|
||||
unlike( $eth0, qr/ONBOOT/i, 'a nicextraparams key netplan does not know is not emitted' );
|
||||
like( slurp("$r/warnings"), qr/ONBOOT/, 'and dropping it is reported' );
|
||||
|
||||
# the sentinel arm: an unset mtu must not reach the file as the literal "default"
|
||||
unlike( $eth0, qr/mtu:\s*default/, 'an unset mtu is skipped rather than written as the sentinel' );
|
||||
|
||||
# --- an address removed from the nics table must actually go -------------------
|
||||
$r = run_configeth( <<'SH' );
|
||||
configipv4 eth0 10.0.0.5 10.0.0.0 255.255.255.0 0 default default
|
||||
configipv4 eth0 10.0.0.99 10.0.0.0 255.255.255.0 0 default default
|
||||
SH
|
||||
$eth0 = yaml_of( $r, 'eth0' );
|
||||
like( $eth0, qr/- 10\.0\.0\.99\/24/, 're-running with a new address writes the new address' );
|
||||
unlike( $eth0, qr/- 10\.0\.0\.5\/24/, 'and the address it replaces is dropped, not accumulated' );
|
||||
|
||||
# --- a VLAN interface ---------------------------------------------------------
|
||||
# The parent carries no address of its own, so nothing else declares it. netplan resolves link:
|
||||
# at parse time, so the parent has to be in this file or the whole configuration is rejected.
|
||||
$r = run_configeth( <<'SH' );
|
||||
configipv4 eth1.100 10.100.0.5 10.100.0.0 255.255.255.0 0 default default
|
||||
SH
|
||||
my $vlan = yaml_of( $r, 'eth1.100' );
|
||||
like( $vlan, qr/^ vlans:$/m, 'a <parent>.<vid> NIC is declared under vlans:' );
|
||||
like( $vlan, qr/^ id: 100$/m, 'the VLAN carries its id' );
|
||||
like( $vlan, qr/^ link: eth1$/m, 'the VLAN is linked to its parent interface' );
|
||||
like( $vlan, qr/^ ethernets:\n eth1: \{\}/m,
|
||||
'the VLAN parent is declared in the same file so link: resolves' );
|
||||
|
||||
# --- a dotted name that is NOT a vlan ----------------------------------------
|
||||
$r = run_configeth( <<'SH' );
|
||||
configipv4 eno1.custom 10.9.0.5 10.9.0.0 255.255.255.0 0 default default
|
||||
SH
|
||||
like( yaml_of( $r, 'eno1.custom' ), qr/^ ethernets:$/m,
|
||||
'a dotted name with a non-numeric suffix is not treated as a VLAN' );
|
||||
|
||||
# --- configipv6 drives the netplan branch too ---------------------------------
|
||||
$r = run_configeth( <<'SH' );
|
||||
configipv6 eth2 2001:db8::5 2001:db8:: 64 0 0 2001:db8::1 "MTU=9000 ONBOOT=no"
|
||||
SH
|
||||
my $v6 = yaml_of( $r, 'eth2' );
|
||||
like( $v6, qr/- 2001:db8::5\/64/, 'configipv6 writes the address' );
|
||||
|
||||
# "to: default" is only understood from netplan 0.103; 18.04 never ships past 0.99.
|
||||
like( $v6, qr/- to: ::\/0\n\s*via: 2001:db8::1/,
|
||||
'the v6 default route is written as an explicit CIDR, not the "default" alias' );
|
||||
unlike( $v6, qr/to:\s*default/, 'the "default" route alias is not emitted' );
|
||||
like( $v6, qr/^ mtu: 9000$/m, 'configipv6 carries nicextraparams into the stanza' );
|
||||
|
||||
# configipv6 takes no mtu argument; $str_nic_mtu would be whatever configipv4 last set.
|
||||
$r = run_configeth( <<'SH' );
|
||||
configipv4 eth3 10.0.3.5 10.0.3.0 255.255.255.0 0 default 1500
|
||||
configipv6 eth4 2001:db8:4::5 2001:db8:4:: 64 0 0 default default
|
||||
SH
|
||||
unlike( yaml_of( $r, 'eth4' ), qr/mtu:/,
|
||||
'a v6-only NIC does not inherit the MTU of a NIC configured before it' );
|
||||
|
||||
# --- route de-duplication -----------------------------------------------------
|
||||
$r = run_configeth( <<'SH' );
|
||||
configipv6 eth5 2001:db8:5::5 2001:db8:5:: 64 0 0 2001:db8:5::1 default
|
||||
configipv6 eth5 2001:db8:5::6 2001:db8:5:: 64 1 0 2001:db8:5::1 default
|
||||
write_netplan_route eth5 2001:db8:9::/64 2001:db8:5::1
|
||||
SH
|
||||
my $eth5 = yaml_of( $r, 'eth5' );
|
||||
my @defaults = ( $eth5 =~ /- to: ::\/0/g );
|
||||
is( scalar(@defaults), 1, 'an identical route added twice appears once' );
|
||||
like( $eth5, qr/- to: 2001:db8:9::\/64\n\s*via: 2001:db8:5::1/,
|
||||
'a second route sharing the same gateway is still written' );
|
||||
|
||||
# --- removal ------------------------------------------------------------------
|
||||
$r = run_configeth( <<'SH' );
|
||||
configipv4 eth6 10.0.6.5 10.0.6.0 255.255.255.0 0 default default
|
||||
echo "eth6" > "${str_cfg_dir}xcat_history_important"
|
||||
delete_nic_config_files eth6
|
||||
SH
|
||||
is( yaml_of( $r, 'eth6' ), '', 'delete_nic_config_files removes the netplan drop-in' );
|
||||
unlike( slurp("$r/xcat_history_important"), qr/eth6/,
|
||||
'and clears the NIC from xcat_history_important, as the other branches do' );
|
||||
|
||||
# --- a nicextraparams name containing a regex metacharacter --------------------
|
||||
$r = run_configeth( <<'SH' );
|
||||
configipv4 eth7 10.0.7.5 10.0.7.0 255.255.255.0 0 "a/b=c MTU=1400" default
|
||||
SH
|
||||
like( yaml_of( $r, 'eth7' ), qr/^ mtu: 1400$/m,
|
||||
'a param name with a "/" does not break the recorded state around it' );
|
||||
|
||||
# --- the apply is scoped to the NIC being configured where the backend allows it ------
|
||||
# `netplan apply` takes no interface argument and re-applies every netdef on the node, which
|
||||
# during the install postscripts stage would bounce the install NIC the postscript is running
|
||||
# over. Where systemd-networkd is the renderer and networkctl has the verbs, only this device
|
||||
# should be reconfigured.
|
||||
$r = run_configeth( <<'SH' );
|
||||
networkctl(){ echo "networkctl $*" >> "$str_cfg_dir/applied"; [ "$1" = "--help" ] && echo " reconfigure DEVICES... Reconfigure interfaces"; return 0; }
|
||||
systemctl(){ return 0; }
|
||||
netplan_apply eth0
|
||||
SH
|
||||
my $applied = slurp("$r/applied");
|
||||
like( $applied, qr/^networkctl reconfigure eth0$/m,
|
||||
'the apply is scoped to the NIC being configured' );
|
||||
like( $applied, qr/^netplan generate$/m,
|
||||
'the backend configuration is generated before reconfiguring the device' );
|
||||
unlike( $applied, qr/^netplan apply$/m,
|
||||
'and the node-wide apply is not used when a single device can be reconfigured' );
|
||||
|
||||
# Ubuntu 18.04 ships systemd 237, which has no `networkctl reconfigure`; the NetworkManager
|
||||
# renderer has no networkctl path at all. Both must still apply, node-wide.
|
||||
$r = run_configeth( <<'SH' );
|
||||
networkctl(){ echo "networkctl $*" >> "$str_cfg_dir/applied"; return 0; }
|
||||
systemctl(){ return 0; }
|
||||
netplan_apply eth0
|
||||
SH
|
||||
$applied = slurp("$r/applied");
|
||||
like( $applied, qr/^netplan apply$/m,
|
||||
'a backend that cannot reconfigure one device falls back to the node-wide apply' );
|
||||
unlike( $applied, qr/reconfigure/,
|
||||
'and does not attempt a verb it does not have' );
|
||||
|
||||
# --- and netplan itself must accept what we wrote -----------------------------
|
||||
# --root-dir is a filesystem root: netplan reads <root>/etc/netplan/*.yaml, which is why the
|
||||
# harness writes the drop-ins there rather than flat into the scratch directory.
|
||||
SKIP: {
|
||||
my $netplan = `command -v netplan 2>/dev/null`;
|
||||
chomp $netplan;
|
||||
skip 'netplan not installed', 1 unless $netplan && -x $netplan;
|
||||
|
||||
my $root = File::Spec->catdir( $dir, 'generate' );
|
||||
mkdir $root;
|
||||
mkdir File::Spec->catdir( $root, 'etc' );
|
||||
my $np = File::Spec->catdir( $root, 'etc', 'netplan' );
|
||||
mkdir $np;
|
||||
|
||||
# every shape this writer emits, in one tree, the way a real node accumulates them --
|
||||
# including a netdef an earlier-sorting file already declares as DHCP
|
||||
run_configeth_into( $np, <<'SH' );
|
||||
configipv4 eth0 10.0.0.5 10.0.0.0 255.255.255.0 0 "MTU=1500 ONBOOT=no" 1500
|
||||
configipv4 eth0 10.0.1.5 10.0.1.0 255.255.255.0 1 default default
|
||||
configipv4 eth1.100 10.100.0.5 10.100.0.0 255.255.255.0 0 default default
|
||||
configipv6 eth2 2001:db8::5 2001:db8:: 64 0 0 2001:db8::1 default
|
||||
SH
|
||||
open my $ci, '>', File::Spec->catfile( $np, '50-cloud-init.yaml' ) or die $!;
|
||||
print $ci "network:\n version: 2\n ethernets:\n eth0:\n dhcp4: true\n";
|
||||
close $ci;
|
||||
chmod 0600, glob("$np/*.yaml");
|
||||
|
||||
my $out = `netplan generate --root-dir '$root' 2>&1`;
|
||||
is( $? >> 8, 0, "netplan generate accepts the generated configuration" )
|
||||
or diag($out);
|
||||
}
|
||||
|
||||
# same harness, writing into a caller-chosen netplan directory
|
||||
sub run_configeth_into {
|
||||
my ( $np, $script ) = @_;
|
||||
my $root = File::Spec->catdir( $dir, "gen_stage" );
|
||||
mkdir $root;
|
||||
my $harness = File::Spec->catfile( $root, 'harness.sh' );
|
||||
open my $fh, '>', $harness or die $!;
|
||||
print $fh <<"PRE";
|
||||
#!/bin/bash
|
||||
NODE=cn1
|
||||
str_default_token='$token'
|
||||
str_os_type=debian
|
||||
str_cfg_dir='$root/'
|
||||
export NETPLAN_DIR='$np'
|
||||
log_info(){ :; }
|
||||
log_warn(){ :; }
|
||||
log_error(){ :; }
|
||||
netplan(){ :; }
|
||||
wait_for_ifstate(){ return 0; }
|
||||
ip(){ :; }
|
||||
v4mask2prefix(){
|
||||
local m=\$1 p=0 o
|
||||
for o in \${m//./ }; do
|
||||
case \$o in
|
||||
255) p=\$((p+8));; 254) p=\$((p+7));; 252) p=\$((p+6));; 248) p=\$((p+5));;
|
||||
240) p=\$((p+4));; 224) p=\$((p+3));; 192) p=\$((p+2));; 128) p=\$((p+1));;
|
||||
esac
|
||||
done
|
||||
echo \$p
|
||||
}
|
||||
parse_nic_extra_params(){
|
||||
unset array_extra_param_names array_extra_param_values
|
||||
local k=0 t
|
||||
for t in \$1; do
|
||||
array_extra_param_names[\$k]=\${t%%=*}
|
||||
array_extra_param_values[\$k]=\${t#*=}
|
||||
k=\$((k+1))
|
||||
done
|
||||
}
|
||||
declare -a array_extra_param_names
|
||||
declare -a array_extra_param_values
|
||||
PRE
|
||||
print $fh "$unit\nnetplan_active=1\n$script\n";
|
||||
close $fh;
|
||||
system( '/bin/bash', $harness ) == 0 or die "harness failed";
|
||||
return;
|
||||
}
|
||||
|
||||
done_testing();
|
||||
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use File::Spec;
|
||||
use File::Temp qw(tempdir);
|
||||
use FindBin;
|
||||
use Test::More;
|
||||
|
||||
# Regression: on a netplan-rendered node configeth took the NIC down on every reconfigure,
|
||||
# while the `netplan apply` that brings it back is gated on reboot_nic_bool. In the diskful
|
||||
# provision postscripts stage reboot_nic_bool is 0, so the interface went down and nothing
|
||||
# brought it back until the node rebooted -- over the very NIC the postscripts are talking on.
|
||||
#
|
||||
# The other two arms already pair the two halves: the ifupdown arm answers `ifdown` with an
|
||||
# unconditional `ifup`, and the redhat arm gates BOTH the down and the up on reboot_nic_bool.
|
||||
# Only the netplan arm took one half of the pair.
|
||||
#
|
||||
# This drives the two blocks configeth actually executes rather than matching its text: the
|
||||
# down-selection inside the modify branch, and the restart block underneath it. `ip` and
|
||||
# `netplan` are shadowed by shell functions, which bash resolves ahead of $PATH, so the host's
|
||||
# network is never touched -- every call is recorded to a file instead.
|
||||
|
||||
my $repo_root = File::Spec->rel2abs(
|
||||
File::Spec->catdir( $FindBin::Bin, '..', '..' )
|
||||
);
|
||||
my $configeth = File::Spec->catfile( $repo_root, 'xCAT', 'postscripts', 'configeth' );
|
||||
plan skip_all => "configeth not found" unless -f $configeth;
|
||||
|
||||
my $src = do { local $/; open my $fh, '<', $configeth or die $!; <$fh> };
|
||||
|
||||
# BAIL_OUT rather than skip: a rename that stops these matching must fail loudly instead of
|
||||
# silently covering nothing.
|
||||
my ($down_block) = $src =~ /\n( if \[ "\$str_nic_status" = "up" \];then\n.*?\n fi\n)/ms;
|
||||
BAIL_OUT('could not extract the nic-down block from configeth')
|
||||
unless defined $down_block;
|
||||
|
||||
my ($restart_block) = $src =~ /\n( #restart the nic\n if \[ \$bool_restart_flag -eq 1 \];then\n.*?\n fi\n)/ms;
|
||||
BAIL_OUT('could not extract the restart block from configeth')
|
||||
unless defined $restart_block;
|
||||
|
||||
my $dir = tempdir( CLEANUP => 1 );
|
||||
my $run_no = 0;
|
||||
|
||||
# Run both blocks back to back for one (reboot_nic_bool, arm) combination and return what the
|
||||
# script asked the system to do, in order.
|
||||
sub drive {
|
||||
my (%opt) = @_;
|
||||
$run_no++;
|
||||
my $root = File::Spec->catdir( $dir, "run$run_no" );
|
||||
mkdir $root;
|
||||
my $calls = File::Spec->catfile( $root, 'calls' );
|
||||
|
||||
my $harness = File::Spec->catfile( $root, 'harness.sh' );
|
||||
open my $fh, '>', $harness or die $!;
|
||||
print $fh <<"PRE";
|
||||
#!/bin/bash
|
||||
NODE=cn1
|
||||
str_nic_name=eth0
|
||||
str_nic_status=up
|
||||
str_os_type='$opt{os_type}'
|
||||
netplan_active='$opt{netplan_active}'
|
||||
networkmanager_active=0
|
||||
reboot_nic_bool=$opt{reboot_nic_bool}
|
||||
bool_modify_flag=1
|
||||
bool_restart_flag=1
|
||||
error_code=0
|
||||
array_ip_old_temp=()
|
||||
log_info(){ :; }
|
||||
log_warn(){ :; }
|
||||
log_error(){ echo "log_error \$*" >> '$calls'; }
|
||||
ip(){ echo "ip \$*" >> '$calls'; }
|
||||
ifdown(){ echo "ifdown \$*" >> '$calls'; }
|
||||
ifup(){ echo "ifup \$*" >> '$calls'; }
|
||||
nmcli(){ echo "nmcli \$*" >> '$calls'; }
|
||||
netplan(){ echo "netplan \$*" >> '$calls'; }
|
||||
networkctl(){ echo "networkctl \$*" >> '$calls'; }
|
||||
netplan_apply(){ echo "netplan_apply \$*" >> '$calls'; return 0; }
|
||||
wait_for_ifstate(){ echo 0; return 0; }
|
||||
PRE
|
||||
print $fh $down_block, "\n", $restart_block, "\n";
|
||||
close $fh;
|
||||
|
||||
system( '/bin/bash', $harness );
|
||||
return '' unless -f $calls;
|
||||
my $out = do { local $/; open my $c, '<', $calls or die $!; <$c> };
|
||||
return $out;
|
||||
}
|
||||
|
||||
# The bug, stated as behaviour: during the install postscripts stage the NIC must not be left
|
||||
# down. Either the link is not touched, or something brings it back.
|
||||
my $install = drive( os_type => 'debian', netplan_active => 1, reboot_nic_bool => 0 );
|
||||
my $took_down = $install =~ /^ip link set dev eth0 down/m;
|
||||
my $brought_up = $install =~ /^netplan_apply/m;
|
||||
ok( !$took_down || $brought_up,
|
||||
'netplan: with reboot_nic_bool=0 the NIC is not left down' );
|
||||
unlike( $install, qr/^ip link set dev eth0 down/m,
|
||||
'netplan: with reboot_nic_bool=0 the link is not taken down at all' );
|
||||
|
||||
# The redhat arm is the reference: it has always gated both halves.
|
||||
my $rh_install = drive( os_type => 'rhel', netplan_active => 0, reboot_nic_bool => 0 );
|
||||
unlike( $rh_install, qr/^ip link set dev eth0 down/m,
|
||||
'redhat: with reboot_nic_bool=0 the link is not taken down (reference behaviour)' );
|
||||
|
||||
# ifupdown pairs its own halves unconditionally, so it may take the link down.
|
||||
my $deb_install = drive( os_type => 'debian', netplan_active => 0, reboot_nic_bool => 0 );
|
||||
like( $deb_install, qr/^ifdown --force eth0/m,
|
||||
'ifupdown: takes the link down' );
|
||||
like( $deb_install, qr/^ifup -a -i /m,
|
||||
'ifupdown: and brings it back unconditionally, so it is never left down' );
|
||||
|
||||
# reboot_nic_bool=1 is the normal reconfigure: both halves must run.
|
||||
my $reboot = drive( os_type => 'debian', netplan_active => 1, reboot_nic_bool => 1 );
|
||||
like( $reboot, qr/^ip link set dev eth0 down/m,
|
||||
'netplan: with reboot_nic_bool=1 the link is taken down' );
|
||||
like( $reboot, qr/^netplan_apply eth0/m,
|
||||
'netplan: with reboot_nic_bool=1 the apply brings it back' );
|
||||
|
||||
my ($down_at) = $reboot =~ /\A(.*?)^netplan_apply/ms;
|
||||
ok( defined $down_at && $down_at =~ /ip link set dev eth0 down/,
|
||||
'netplan: the down happens before the apply, not after it' );
|
||||
|
||||
done_testing();
|
||||
+414
-8
@@ -40,6 +40,318 @@ 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 parses every file under /etc/netplan as one document, so a single rejected key takes
|
||||
# the whole node's network with it -- not just the interface being configured. That is why the
|
||||
# writers below validate rather than pass values through.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
netplan_active=0
|
||||
if command -v netplan >/dev/null 2>&1 && [ -d /etc/netplan ]; then
|
||||
netplan_active=1
|
||||
# netplan.io is Priority:important and a dependency of cloud-init, so its presence says
|
||||
# nothing about what actually renders this node. Only ifupdown both installed AND running
|
||||
# means /etc/network/interfaces is still the live configuration, in which case writing YAML
|
||||
# would orphan it. (checkservicestatus is no help here: servicemap has no entry for
|
||||
# "networking", so it returns 127 whatever the service is doing.)
|
||||
if command -v ifup >/dev/null 2>&1 && systemctl is-active networking >/dev/null 2>&1; then
|
||||
netplan_active=0
|
||||
fi
|
||||
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_touch(){ # <file> -- create the drop-in already unreadable to other users
|
||||
[ -f "$1" ] || ( umask 077; : > "$1" )
|
||||
}
|
||||
|
||||
_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_forget <file> <prefix> -- drop the recorded lines whose value starts with <prefix>.
|
||||
# awk index() is a literal string match: a nicextraparams key is admin-supplied and a '/' or a
|
||||
# regex metacharacter in a sed address would either error out or delete unrelated state.
|
||||
_netplan_forget(){
|
||||
local f="$1" pfx="$2" tmp
|
||||
[ -f "$f" ] || return 0
|
||||
tmp="${f}.forget.$$"
|
||||
if awk -v p="# xcat-state: $pfx" 'index($0, p) != 1' "$f" > "$tmp"; then
|
||||
mv -f "$tmp" "$f"
|
||||
else
|
||||
rm -f "$tmp"
|
||||
fi
|
||||
}
|
||||
|
||||
# _netplan_param_key <name> -- the netplan key a nicextraparams name maps to, or non-zero if it
|
||||
# has none. nicextraparams are ifcfg/ifupdown names -- the documented examples are
|
||||
# "MTU=1456 ONBOOT=no" -- and netplan rejects the entire configuration for one unknown key, so
|
||||
# anything without a netplan meaning has to be dropped rather than passed through.
|
||||
_netplan_param_key(){
|
||||
local k
|
||||
k=$(echo "$1" | tr 'A-Z' 'a-z')
|
||||
case "$k" in
|
||||
mtu|optional|critical|wakeonlan|dhcp4|dhcp6|accept-ra|ipv6-privacy) echo "$k"; return 0 ;;
|
||||
dhcp-identifier|activation-mode|ipv6-mtu|macaddress) echo "$k"; return 0 ;;
|
||||
esac
|
||||
return 1
|
||||
}
|
||||
|
||||
# _netplan_yaml_scalar <value> -- a value safe to paste into the generated YAML. Integers and
|
||||
# booleans keep their type (netplan wants mtu as an int, optional as a bool); anything else is
|
||||
# quoted so that a ':' or '#' in a value cannot invent a key or comment out the rest of a line.
|
||||
_netplan_yaml_scalar(){
|
||||
case "$1" in
|
||||
true|false) echo "$1"; return 0 ;;
|
||||
esac
|
||||
case "$1" in
|
||||
''|*[!0-9]*) ;;
|
||||
*) echo "$1"; return 0 ;;
|
||||
esac
|
||||
printf '"%s"\n' "$(echo "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g')"
|
||||
}
|
||||
|
||||
# _netplan_route_dest <via> -- the explicit default-route destination for the gateway's family.
|
||||
# "to: default" is only understood from netplan 0.103 onwards; Ubuntu 18.04 never ships past
|
||||
# 0.99 and a stock 20.04 ships 0.99 too, where it fails the whole file. The CIDR works on all.
|
||||
_netplan_route_dest(){
|
||||
case "$1" in
|
||||
*:*) echo "::/0" ;;
|
||||
*) echo "0.0.0.0/0" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# _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 param name value key
|
||||
local has_dhcp4=0 has_dhcp6=0
|
||||
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
|
||||
|
||||
# a nicextraparams key may set dhcp4/dhcp6 itself; do not then emit the default as well,
|
||||
# which would be a duplicate mapping key in the same stanza
|
||||
while read -r param; do
|
||||
key=$(_netplan_param_key "${param%% *}") || continue
|
||||
[ "$key" = "dhcp4" ] && has_dhcp4=1
|
||||
[ "$key" = "dhcp6" ] && has_dhcp6=1
|
||||
done <<EOF
|
||||
$(_netplan_state "$nic" param)
|
||||
EOF
|
||||
|
||||
( umask 077
|
||||
{
|
||||
# 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"
|
||||
if [ "$section" = "vlans" ]; then
|
||||
# netplan resolves link: at parse time and does not look ahead to files that sort
|
||||
# later, and 90-xcat-<parent>.<vid>.yaml always sorts before 90-xcat-<parent>.yaml
|
||||
# ('1' < 'y'). The parent may also carry no address of its own, in which case xCAT
|
||||
# never writes a file for it at all. Declaring it here as an empty netdef resolves
|
||||
# the reference without overriding any key the parent's own netdef sets.
|
||||
echo " ethernets:"
|
||||
echo " ${parent}: {}"
|
||||
fi
|
||||
echo " ${section}:"
|
||||
echo " ${nic}:"
|
||||
if [ "$section" = "vlans" ]; then
|
||||
echo " id: ${vid}"
|
||||
echo " link: ${parent}"
|
||||
fi
|
||||
# netplan merges netdefs of the same name across files key by key rather than replacing
|
||||
# them, so without these an earlier-sorting dhcp4:true -- cloud-init's
|
||||
# 50-cloud-init.yaml, or xCAT's own netboot drop-in -- survives and the node runs a DHCP
|
||||
# lease alongside the static address xCAT just assigned.
|
||||
[ $has_dhcp4 -eq 0 ] && echo " dhcp4: false"
|
||||
[ $has_dhcp6 -eq 0 ] && echo " dhcp6: false"
|
||||
|
||||
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" ] || continue
|
||||
[ "$to" = "default" ] && to="$(_netplan_route_dest "$via")"
|
||||
printf ' - to: %s\n via: %s\n' "$to" "$via"
|
||||
done
|
||||
fi
|
||||
|
||||
# nicextraparams, already normalised and filtered to keys netplan understands by
|
||||
# write_netplan_param below
|
||||
_netplan_state "$nic" param | while read -r param; do
|
||||
name="${param%% *}"
|
||||
value="${param#* }"
|
||||
[ -n "$name" ] && echo " ${name}: $(_netplan_yaml_scalar "$value")"
|
||||
done
|
||||
} > "$tmp" )
|
||||
|
||||
mv -f "$tmp" "$f"
|
||||
chmod 600 "$f" 2>/dev/null
|
||||
}
|
||||
|
||||
# netplan_reset_nic <nic> -- forget everything recorded for this NIC. Called for the first
|
||||
# address of a NIC, mirroring the truncating '>' of the ifupdown branch: without it an address
|
||||
# that was removed from the nics table is never dropped and the node keeps it forever.
|
||||
netplan_reset_nic(){
|
||||
rm -f "$(netplan_file "$1")" 2>/dev/null
|
||||
return 0
|
||||
}
|
||||
|
||||
# _netplan_can_reconfigure -- can one device be re-applied without disturbing the others?
|
||||
# Only when systemd-networkd is the renderer and networkctl carries the verbs (systemd 244+;
|
||||
# Ubuntu 18.04 ships 237 and does not). Probed rather than version-gated, so this follows the
|
||||
# node's actual backend -- under the NetworkManager renderer it is correctly false.
|
||||
_netplan_can_reconfigure(){
|
||||
command -v networkctl >/dev/null 2>&1 || return 1
|
||||
networkctl --help 2>&1 | grep -qw reconfigure || return 1
|
||||
systemctl is-active systemd-networkd >/dev/null 2>&1 || return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
# netplan_apply [nic] -- make the drop-in live, and verify the link actually came up.
|
||||
#
|
||||
# `netplan apply` takes no interface argument: it re-applies every netdef on the node, so
|
||||
# configuring one secondary NIC would also bounce the install NIC the postscripts are still
|
||||
# running over. Where the backend can scope it, generate the backend configuration and
|
||||
# reconfigure only <nic>. Anything that cannot be scoped -- a device netplan has yet to create,
|
||||
# the NetworkManager renderer, a systemd without the verbs -- falls back to the node-wide apply.
|
||||
#
|
||||
# `netplan apply` returns 0 even when it changed nothing, so its exit status alone cannot stand
|
||||
# in for the interface state the ifup path used to check.
|
||||
netplan_apply(){
|
||||
local nic="$1"
|
||||
if [ -n "$nic" ] && _netplan_can_reconfigure; then
|
||||
netplan generate
|
||||
if [ $? -ne 0 ]; then
|
||||
log_error "netplan generate failed."
|
||||
return 1
|
||||
fi
|
||||
networkctl reload >/dev/null 2>&1
|
||||
networkctl reconfigure "$nic" >/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
wait_for_ifstate "$nic" UP 20 5 >/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
log_error "bring $nic up failed."
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
log_info "configeth on $NODE: networkctl could not reconfigure $nic alone, applying all."
|
||||
fi
|
||||
netplan apply
|
||||
if [ $? -ne 0 ]; then
|
||||
log_error "netplan apply failed."
|
||||
return 1
|
||||
fi
|
||||
[ -n "$nic" ] || return 0
|
||||
wait_for_ifstate "$nic" UP 20 5 >/dev/null
|
||||
if [ $? -ne 0 ]; then
|
||||
log_error "bring $nic up failed."
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# 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")"
|
||||
_netplan_touch "$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
|
||||
_netplan_forget "$f" "mtu "
|
||||
_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 key
|
||||
key=$(_netplan_param_key "$name")
|
||||
if [ $? -ne 0 ]; then
|
||||
log_warn "configeth on $NODE: nicextraparams key '$name' has no netplan equivalent, ignored for $nic."
|
||||
return 0
|
||||
fi
|
||||
f="$(netplan_file "$nic")"
|
||||
_netplan_touch "$f"
|
||||
if [ "$key" = "mtu" ]; then
|
||||
# the same knob write_netplan_addr records; keeping one source avoids a duplicate key
|
||||
_netplan_forget "$f" "mtu "
|
||||
_netplan_record "$nic" mtu "$value"
|
||||
else
|
||||
_netplan_forget "$f" "param $key "
|
||||
_netplan_record "$nic" param "$key $value"
|
||||
fi
|
||||
_netplan_render "$nic"
|
||||
}
|
||||
function configipv4(){
|
||||
str_if_name=$1
|
||||
str_v4ip=$2
|
||||
@@ -111,7 +423,23 @@ 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
|
||||
#the first address of a NIC starts a fresh drop-in, the way the ifupdown branch below
|
||||
#truncates with '>' -- otherwise an address dropped from the nics table is never removed
|
||||
if [ $num_v4num -eq 0 ];then
|
||||
netplan_reset_nic "${str_if_name}"
|
||||
fi
|
||||
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 +618,26 @@ 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
|
||||
if [ $num_v4num -eq 0 -a $num_v6num -eq 0 ];then
|
||||
netplan_reset_nic "${str_if_name}"
|
||||
fi
|
||||
#configipv6 takes no mtu argument: $str_nic_mtu here would be whatever configipv4 last
|
||||
#assigned for this NIC, and the ifupdown v6 branch below writes no mtu at all
|
||||
write_netplan_addr "${str_if_name}" "${str_v6ip}/${str_v6prefix}" ""
|
||||
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
|
||||
#the ifupdown v6 branch below writes these into the stanza; dropping them here would
|
||||
#silently discard configuration on a v6-only NIC
|
||||
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
|
||||
elif [ "$str_os_type" = "debian" ];then
|
||||
#debian or ubuntu
|
||||
str_conf_file="/etc/network/interfaces.d/${str_if_name}"
|
||||
@@ -393,7 +741,10 @@ 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
|
||||
sed -i "/${str_temp_name}/d" "${str_cfg_dir}xcat_history_important" 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
|
||||
@@ -542,7 +893,10 @@ if [ "$1" = "-r" ];then
|
||||
#shut down the nic if it is on
|
||||
ip link show $str_nic_name | grep -i ',up'
|
||||
if [ $? -eq 0 ];then
|
||||
if [ "$str_os_type" = "debian" ];then
|
||||
if [ "$str_os_type" = "debian" ] && [ "$netplan_active" = "1" ];then
|
||||
#ifdown belongs to ifupdown and does not exist on a netplan-rendered node
|
||||
ip link set dev $str_nic_name down
|
||||
elif [ "$str_os_type" = "debian" ];then
|
||||
ifdown --force $str_nic_name
|
||||
else
|
||||
ip link set dev $str_nic_name down
|
||||
@@ -551,6 +905,14 @@ if [ "$1" = "-r" ];then
|
||||
|
||||
#delete the configuration files
|
||||
delete_nic_config_files $str_nic_name
|
||||
#the drop-in just removed WAS the live configuration; without applying, the address
|
||||
#stays on the link until the next reboot
|
||||
if [ "$str_os_type" = "debian" ] && [ "$netplan_active" = "1" ];then
|
||||
netplan_apply
|
||||
if [ $? -ne 0 ]; then
|
||||
error_code=1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
exit $error_code
|
||||
elif [ "$1" = "-s" ];then
|
||||
@@ -679,7 +1041,25 @@ elif [ "$1" = "-s" ];then
|
||||
|
||||
# cofniguring the interface
|
||||
|
||||
if [ -f "/etc/debian_version" ];then
|
||||
#ubuntu/debian rendered by netplan (18.04+): interfaces.d is ignored, so the install NIC
|
||||
#has to be written as a netplan drop-in too -- this is the path confignetwork takes for
|
||||
#every provisioned node, and leaving it on interfaces.d configured nothing (issue #7454)
|
||||
if [ -f "/etc/debian_version" ] && [ "$netplan_active" = "1" ];then
|
||||
netplan_reset_nic "${str_inst_nic}"
|
||||
str_inst_prefix=$(v4mask2prefix ${str_inst_mask})
|
||||
write_netplan_addr "${str_inst_nic}" "${str_inst_ip}/${str_inst_prefix}" "${str_inst_mtu}"
|
||||
if [ -n "$str_inst_gateway" ];then
|
||||
write_netplan_route "${str_inst_nic}" "default" "${str_inst_gateway}"
|
||||
fi
|
||||
i=0
|
||||
while [ $i -lt ${#array_extra_param_names[@]} ]
|
||||
do
|
||||
write_netplan_param "${str_inst_nic}" "${array_extra_param_names[$i]}" "${array_extra_param_values[$i]}"
|
||||
i=$((i+1))
|
||||
done
|
||||
hostname $NODE
|
||||
echo $NODE > /etc/hostname
|
||||
elif [ -f "/etc/debian_version" ];then
|
||||
str_conf_file="/etc/network/interfaces.d/${str_inst_nic}"
|
||||
echo "auto ${str_inst_nic}" > $str_conf_file
|
||||
echo "iface ${str_inst_nic} inet static" >> $str_conf_file
|
||||
@@ -869,12 +1249,19 @@ 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
|
||||
fi
|
||||
if [ $networkmanager_active -eq 1 ]; then
|
||||
#tested before NetworkManager: on an NM-rendered netplan node this is the correct arm,
|
||||
#and as an elif after it, it was dead code that fell through to an nmcli call with an
|
||||
#unset connection name
|
||||
if [ "$str_os_type" = "debian" ] && [ "$netplan_active" = "1" ]; then
|
||||
netplan_apply "$str_inst_nic" || error_code=1
|
||||
elif [ $networkmanager_active -eq 1 ]; then
|
||||
nmcli con modify $con_name ipv4.dns "${NAMESERVERS}"
|
||||
nmcli con reload
|
||||
nmcli con up $con_name
|
||||
@@ -1210,7 +1597,14 @@ else
|
||||
if [ $bool_modify_flag -eq 1 ];then
|
||||
if [ $bool_restart_flag -eq 1 ];then
|
||||
if [ "$str_nic_status" = "up" ];then
|
||||
if [ "$str_os_type" = "debian" ];then
|
||||
if [ "$str_os_type" = "debian" ] && [ "$netplan_active" = "1" ];then
|
||||
#the netplan_apply that brings the link back is gated on reboot_nic_bool,
|
||||
#so taking it down here ungated leaves the NIC down until the next reboot
|
||||
#in the provision postscripts stage -- over the NIC we are talking on.
|
||||
if [ $reboot_nic_bool -eq 1 ]; then
|
||||
ip link set dev $str_nic_name down > /dev/null 2>/dev/null
|
||||
fi
|
||||
elif [ "$str_os_type" = "debian" ];then
|
||||
ifdown --force $str_nic_name > /dev/null
|
||||
else
|
||||
if [ $reboot_nic_bool -eq 1 ]; then
|
||||
@@ -1285,7 +1679,19 @@ 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` has no per-interface form: it re-applies every netdef on the node.
|
||||
#In the diskful provision postscripts stage that would bounce the install NIC the
|
||||
#postscripts are still talking over, which is what reboot_nic_bool guards against
|
||||
#for the redhat arm below. The drop-in is written either way and takes effect at
|
||||
#boot, so skipping the apply here costs nothing.
|
||||
if [ $reboot_nic_bool -eq 1 ]; then
|
||||
netplan_apply "$str_nic_name"
|
||||
if [ $? -ne 0 ]; then
|
||||
error_code=1
|
||||
fi
|
||||
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."
|
||||
|
||||
Reference in New Issue
Block a user