CumulusNetworks / ifupdown2

GNU General Public License v2.0
158 stars 72 forks source link

Scripts in if-up.d, if-down.d etc do not get variables they need. #218

Closed gurubert closed 1 year ago

gurubert commented 3 years ago

When replacing ifupdown with ifupdown2 on Debian 11 I noticed that scripts in /etc/network/if-*.d are not executed any more.

This breaks functionality, e.g. resolvconf.

julienfortin commented 3 years ago

Hi Robert,

Here's what I see on my debian 11:

➜  ~ ifup -av
info: requesting link dump
info: requesting address dump
info: requesting netconf dump
info: loading builtin modules from ['/usr/share/ifupdown2/addons']
info: module openvswitch not loaded (module init failed: no /usr/bin/ovs-vsctl found)
info: module openvswitch_port not loaded (module init failed: no /usr/bin/ovs-vsctl found)
info: module ppp not loaded (module init failed: no /usr/bin/pon found)
info: module batman_adv not loaded (module init failed: no /usr/sbin/batctl found)
info: executing /sbin/sysctl net.bridge.bridge-allow-multiple-vlans
info: module mstpctl not loaded (module init failed: no /sbin/mstpctl found)
info: executing /bin/ip rule show
info: executing /bin/ip -6 rule show
info: module ethtool not loaded (module init failed: /sbin/ethtool: not found)
info: address: using default mtu 1500
info: address: max_mtu undefined
info: executing /usr/sbin/ip vrf id
info: mgmt vrf_context = False
info: dhclient: dhclient_retry_on_failure set to 0
info: executing /bin/ip addr help
info: address metric support: OK
info: module ethtool not loaded (module init failed: /sbin/ethtool: not found)
info: module ppp not loaded (module init failed: no /usr/bin/pon found)
info: module mstpctl not loaded (module init failed: no /sbin/mstpctl found)
info: module batman_adv not loaded (module init failed: no /usr/sbin/batctl found)
info: module openvswitch_port not loaded (module init failed: no /usr/bin/ovs-vsctl found)
info: module openvswitch not loaded (module init failed: no /usr/bin/ovs-vsctl found)
info: looking for user scripts under /etc/network
info: loading scripts under /etc/network/if-pre-up.d ...
info: loading scripts under /etc/network/if-up.d ...
info: loading scripts under /etc/network/if-post-up.d ...
info: loading scripts under /etc/network/if-pre-down.d ...
info: loading scripts under /etc/network/if-down.d ...
info: loading scripts under /etc/network/if-post-down.d ...
info: 'link_master_slave' is set. slave admin state changes will be delayed till the masters admin state change.
info: using mgmt iface default prefix eth
info: processing interfaces file /etc/network/interfaces
info: lo: running ops ...
info: executing /sbin/sysctl net.mpls.conf.lo.input=0
info: executing /etc/network/if-pre-up.d/wpasupplicant
info: executing /etc/network/if-pre-up.d/wireless-tools
info: executing /etc/network/if-up.d/wpasupplicant
info: executing /etc/network/if-up.d/avahi-autoipd
info: enp0s3: running ops ...
info: executing /sbin/sysctl net.mpls.conf.enp0s3.input=0
info: executing /etc/network/if-pre-up.d/wpasupplicant
info: executing /etc/network/if-pre-up.d/wireless-tools
info: enp0s3: enabling syslog for dhcp configuration
info: dhclient4 already running on enp0s3. Not restarting.
info: executing /etc/network/if-up.d/wpasupplicant
info: executing /etc/network/if-up.d/avahi-autoipd
info: exit status 0
➜  ~ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux bookworm/sid"
NAME="Debian GNU/Linux"
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
➜  ~ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux bookworm/sid
Release:        unstable
Codename:       sid

Scripts are properly executed. Make sure addon_scripts_support is set to 1 in ifupdown2.conf

➜ ~ cat /etc/network/ifupdown2/ifupdown2.conf| grep addon_scripts_support addon_scripts_support=1 ➜ ~

If that still doesn't work, please share ifup/down/reload -d (debug) output.

Thanks

gurubert commented 3 years ago

I have the following situation: The VM is deployed on Proxmox with cloudinit-Support and a static IP. For the generation of /etc/resolv.conf the resolvconf package is installed.

/etc/network/interfaces.d/50-cloud-init contains:

auto lo
iface lo inet loopback
    dns-nameservers 192.0.2.2 198.51.100.2 203.0.113.2
    dns-search example.net

auto eth0
iface eth0 inet static
    address 10.128.8.4/22
    gateway 10.128.8.1

addon_scripts_support is by default 1 in ifupdown2.conf

/etc/network/if-up.d/ contains 000resolvconf which does get executed when running ifup lo or restarting networking.service:

debug: lo: up : running script /etc/network/if-up.d/000resolvconf
info: executing /etc/network/if-up.d/000resolvconf

But /etc/resolv.conf (a symlink to /run/resolvconf/resolv.conf) stays empty.

/etc/network/if-up.d/000resolvconf starts with a test on $ADDRFAM which should contain inet or inet6 but contains inet,inet.

The variables $IF_DNS_DOMAIN and $IF_DNS_SEARCH are not set.

It looks like this is the compatability issue here. Executing the scripts works but the variables are missing or not set as with ifupdown.

gurubert commented 3 years ago

Looks like PR #32 for issue #14 did not catch all environment variables that are needed here.

gurubert commented 3 years ago

With ifupdown installed the relevant variables for lo seem to be:

ADDRFAM=inet
CLASS=auto
IFACE=lo
IFUPDOWN_lo=post-up
IF_DNS_NAMESERVERS=192.0.2.2 198.51.100.2 203.0.113.2
IF_DNS_SEARCH=example.net
LOGICAL=lo
METHOD=loopback
MODE=start
PHASE=post-up
VERBOSITY=0

When eth0 is in the post-up phase the script receives these variables:

ADDRFAM=inet
CLASS=auto
IFACE=eth0
IFUPDOWN_eth0=post-up
IF_ADDRESS=10.128.8.4
IF_BROADCAST=10.128.11.255
IF_GATEWAY=10.128.8.1
IF_NETMASK=255.255.252.0
LOGICAL=eth0
METHOD=static
MODE=start
PHASE=post-up
VERBOSITY=0
gedia commented 2 years ago

Same here. Environment vars are exported for stanzas in /etc/network/interfaces but not for /etc/network/interfaces.d/* included files. Moving configuration to /etc/network/interfaces resolves this.

32 seems unrelated as all config options are now exported as environment variables to scripts (which are always executed on debian 11 with ifupdown2 regardless of file configuration location), at least that's what I believe function generate_env() from class iface() is supposed to do, so there appears to be no need to explicitly export them.

I believe the problem lies in the processing of included configuration files somehow, as hinted at by the OP.

li-kunkun commented 2 years ago

@julienfortin @gurubert Hi, we have the same problem. https://github.com/CumulusNetworks/ifupdown2/pull/32 pass "ADDRFAM" variable as "inet,inet6" if the interface configured with ipv4 and ipv6. But, /etc/network/if-up.d/000resolvconf only support inet or inet6. When "inet,inet6" is passed, the script will not execute.

`set -x [ -x /sbin/resolvconf ] || exit 0

case "$ADDRFAM" in inet|inet6) : ;; *) exit 0 ;; esac`

It seems difficult to pass “inet” or “inet6” respectively, so I try to add "inet,inet6" in /etc/network/if-up.d/000resolvconf and /etc/network/if-down.d/resolvconf, and it seems to fix this problem. I don't know if there are any other problems or compatibility problems with other scripts

thenickdude commented 1 year ago

Add-on scripts not receiving environment variables like ADDRFAM is due to a bug in run_iface_op:

if ifupdownobj.config.get('addon_scripts_support', '0') == '1':
    # execute /etc/network/ scripts
    os.environ['IFACE'] = ifaceobj.name if ifaceobj.name else ''
    os.environ['LOGICAL'] = ifaceobj.name if ifaceobj.name else ''
    os.environ['METHOD'] = ifaceobj.addr_method if ifaceobj.addr_method else ''
    os.environ['ADDRFAM'] = ','.join(ifaceobj.addr_family) if ifaceobj.addr_family else ''
    for mname in ifupdownobj.script_ops.get(op, []):
        ifupdownobj.logger.debug('%s: %s : running script %s'
                                 %(ifacename, op, mname))
        try:
            utils.exec_command(mname, env=cenv)
        except Exception as e:
            if "permission denied" in str(e).lower():
                ifupdownobj.logger.warning('%s: %s %s' % (ifacename, op, str(e)))
            else:
                ifupdownobj.log_error('%s: %s %s' % (ifacename, op, str(e)))

Environment variables like ADDRFAM are being stored into the parent process's os.environ, but then exec_command() is called with an explicit environment argument env=cenv.

exec_command calls subprocess.Popen() with the passed env parameter, and this causes the child process to use cenv as its environment instead of inheriting the parent's environment, so it never sees any of the values stored into os.environ like ADDRFAM.

I patched that function like so and now the env variables work perfectly for me:

if ifupdownobj.config.get('addon_scripts_support', '0') == '1':
    # execute /etc/network/ scripts
    command_env = (cenv or {}).copy()
    command_env.update({
        'IFACE': ifaceobj.name if ifaceobj.name else '',
        'LOGICAL': ifaceobj.name if ifaceobj.name else '',
        'METHOD': ifaceobj.addr_method if ifaceobj.addr_method else '',
        'ADDRFAM': ','.join(ifaceobj.addr_family) if ifaceobj.addr_family else '',
    })

    for mname in ifupdownobj.script_ops.get(op, []):
        ifupdownobj.logger.debug('%s: %s : running script %s'
            %(ifacename, op, mname))
        try:
            utils.exec_command(mname, env=command_env)
        except Exception as e:
            if "permission denied" in str(e).lower():
                ifupdownobj.logger.warning('%s: %s %s' % (ifacename, op, str(e)))
            else:
                ifupdownobj.log_error('%s: %s %s' % (ifacename, op, str(e)))
sei-gseroka commented 1 year ago

@thenickdude Your patch worked perfectly for me as well. Have you considered submitting a PR?