diff --git a/addons/address.py b/addons/address.py index 293d13d..b35206e 100644 --- a/addons/address.py +++ b/addons/address.py @@ -13,8 +13,10 @@ try: from ifupdownaddons.modulebase import moduleBase from ifupdownaddons.iproute2 import iproute2 from ifupdownaddons.dhclient import dhclient + import ifupdown.policymanager as policymanager import ifupdown.rtnetlink_api as rtnetlink_api import ifupdown.ifupdownconfig as ifupdownConfig + import ifupdown.ifupdownflags as ifupdownflags except ImportError, e: raise ImportError (str(e) + "- required module not found") @@ -72,6 +74,7 @@ class address(moduleBase): moduleBase.__init__(self, *args, **kargs) self.ipcmd = None self._bridge_fdb_query_cache = {} + self.default_mtu = policymanager.policymanager_api.get_attr_default(module_name=self.__class__.__name__, attr='mtu') def _address_valid(self, addrs): if not addrs: @@ -192,7 +195,7 @@ class address(moduleBase): 'iface stanzas, skip purging existing addresses') purge_addresses = 'no' - if not self.PERFMODE and purge_addresses == 'yes': + if not ifupdownflags.flags.PERFMODE and purge_addresses == 'yes': # if perfmode is not set and purge addresses is not set to 'no' # lets purge addresses not in the config runningaddrs = self.ipcmd.addr_get(ifaceobj.name, details=False) @@ -240,7 +243,7 @@ class address(moduleBase): addr_method = ifaceobj.addr_method try: # release any stale dhcp addresses if present - if (addr_method != "dhcp" and not self.PERFMODE and + if (addr_method != "dhcp" and not ifupdownflags.flags.PERFMODE and not (ifaceobj.flags & iface.HAS_SIBLINGS)): # if not running in perf mode and ifaceobj does not have # any sibling iface objects, kill any stale dhclient @@ -260,6 +263,20 @@ class address(moduleBase): mtu = ifaceobj.get_attr_value_first('mtu') if mtu: self.ipcmd.link_set(ifaceobj.name, 'mtu', mtu) + + # logical devices like bridges and vlan devices rely on mtu + # from their lower devices. ie mtu travels from + # lower devices to upper devices. For bonds mtu travels from + # upper to lower devices. running mtu depends on upper and + # lower device mtu. With all this implicit mtu + # config by the kernel in play, it becomes almost impossible + # to decide if the running mtu is valid. It will require + # some more thinking. Commenting this for now. + #elif self.default_mtu: + # running_mtu = self.ipcmd.link_get_mtu(ifaceobj.name) + # if running_mtu != self.default_mtu: + # self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu) + alias = ifaceobj.get_attr_value_first('alias') if alias: self.ipcmd.link_set_alias(ifaceobj.name, alias) @@ -268,7 +285,7 @@ class address(moduleBase): hwaddress = self._get_hwaddress(ifaceobj) if hwaddress: running_hwaddress = None - if not self.PERFMODE: # system is clean + if not ifupdownflags.flags.PERFMODE: # system is clean running_hwaddress = self.ipcmd.link_get_hwaddress(ifaceobj.name) if hwaddress != running_hwaddress: slave_down = False @@ -314,10 +331,13 @@ class address(moduleBase): #self.ipcmd.addr_del(ifaceobj.name, ifaceobj.get_attr_value('address')[0]) else: self.ipcmd.del_addr_all(ifaceobj.name) + mtu = ifaceobj.get_attr_value_first('mtu') + if (mtu and self.default_mtu and (mtu != self.default_mtu)): + self.ipcmd.link_set(ifaceobj.name, 'mtu', self.default_mtu) alias = ifaceobj.get_attr_value_first('alias') if alias: filename = '/sys/class/net/%s/ifalias' %ifaceobj.name - self.logger.info('Executing echo "" > %s' %filename) + self.logger.info('executing echo "" > %s' %filename) os.system('echo "" > %s' %filename) # XXX hwaddress reset cannot happen because we dont know last # address. @@ -444,7 +464,7 @@ class address(moduleBase): if (dhclientcmd.is_running(ifaceobjrunning.name) or dhclientcmd.is_running6(ifaceobjrunning.name)): # If dhcp is configured on the interface, we skip it - return + return isloopback = self.ipcmd.link_isloopback(ifaceobjrunning.name) if isloopback: default_addrs = ['127.0.0.1/8', '::1/128'] @@ -464,7 +484,7 @@ class address(moduleBase): mtu != self.get_mod_subattr('mtu', 'default'))): ifaceobjrunning.update_config('mtu', mtu) alias = self.ipcmd.link_get_alias(ifaceobjrunning.name) - if alias: + if alias: ifaceobjrunning.update_config('alias', alias) _run_ops = {'up' : _up, @@ -478,7 +498,7 @@ class address(moduleBase): def _init_command_handlers(self): if not self.ipcmd: - self.ipcmd = iproute2(**self.get_flags()) + self.ipcmd = iproute2() def run(self, ifaceobj, operation, query_ifaceobj=None, ifaceobj_getfunc=None): """ run address configuration on the interface object passed as argument diff --git a/addons/addressvirtual.py b/addons/addressvirtual.py index bfe640c..de07bdb 100644 --- a/addons/addressvirtual.py +++ b/addons/addressvirtual.py @@ -9,6 +9,8 @@ from ifupdownaddons.modulebase import moduleBase from ifupdownaddons.iproute2 import iproute2 import ifupdown.statemanager as statemanager import ifupdown.rtnetlink_api as rtnetlink_api +import ifupdown.ifupdownflags as ifupdownflags + from ipaddr import IPNetwork import logging import os @@ -142,7 +144,7 @@ class addressvirtual(moduleBase): return maclist def _apply_address_config(self, ifaceobj, address_virtual_list): - purge_existing = False if self.PERFMODE else True + purge_existing = False if ifupdownflags.flags.PERFMODE else True hwaddress = [] self.ipcmd.batch_start() @@ -338,7 +340,7 @@ class addressvirtual(moduleBase): def _init_command_handlers(self): if not self.ipcmd: - self.ipcmd = iproute2(**self.get_flags()) + self.ipcmd = iproute2() def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args): """ run vlan configuration on the interface object passed as argument diff --git a/addons/bond.py b/addons/bond.py index 2a4255d..882f543 100644 --- a/addons/bond.py +++ b/addons/bond.py @@ -12,6 +12,7 @@ from ifupdownaddons.bondutil import bondutil from ifupdownaddons.iproute2 import iproute2 import ifupdown.rtnetlink_api as rtnetlink_api import ifupdown.policymanager as policymanager +import ifupdown.ifupdownflags as ifupdownflags class bond(moduleBase): """ ifupdown2 addon module to configure bond interfaces """ @@ -167,10 +168,12 @@ class bond(moduleBase): if attrname == 'bond-mode' and attrval == '802.3ad': dattrname = 'bond-min-links' min_links = ifaceobj.get_attr_value_first(dattrname) - if not min_links or min_links == '0': - self.logger.warn('%s: required attribute %s' + if not min_links: + min_links = self.bondcmd.get_min_links(ifaceobj.name) + if min_links == '0': + self.logger.warn('%s: attribute %s' %(ifaceobj.name, dattrname) + - ' not present or set to \'0\'') + ' is set to \'0\'') elif policy_default_val: return policy_default_val return attrval @@ -219,13 +222,14 @@ class bond(moduleBase): self.logger.debug('%s: no slaves found' %ifaceobj.name) return - if not self.PERFMODE: + if not ifupdownflags.flags.PERFMODE: runningslaves = self.bondcmd.get_slaves(ifaceobj.name); clag_bond = self._is_clag_bond(ifaceobj) for slave in Set(slaves).difference(Set(runningslaves)): - if not self.PERFMODE and not self.ipcmd.link_exists(slave): + if (not ifupdownflags.flags.PERFMODE and + not self.ipcmd.link_exists(slave)): self.log_warn('%s: skipping slave %s, does not exist' %(ifaceobj.name, slave)) continue @@ -365,11 +369,10 @@ class bond(moduleBase): return self._run_ops.keys() def _init_command_handlers(self): - flags = self.get_flags() if not self.ipcmd: - self.ipcmd = iproute2(**flags) + self.ipcmd = iproute2() if not self.bondcmd: - self.bondcmd = bondutil(**flags) + self.bondcmd = bondutil() def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args): """ run bond configuration on the interface object passed as argument diff --git a/addons/bridge.py b/addons/bridge.py index 3f152cd..aadee7c 100644 --- a/addons/bridge.py +++ b/addons/bridge.py @@ -12,6 +12,7 @@ from ifupdownaddons.bridgeutils import brctl from ifupdownaddons.iproute2 import iproute2 from collections import Counter import ifupdown.rtnetlink_api as rtnetlink_api +import ifupdown.ifupdownflags as ifupdownflags import itertools import re import time @@ -347,7 +348,7 @@ class bridge(moduleBase): self._process_bridge_waitport(ifaceobj, bridgeports) self.ipcmd.batch_start() # Delete active ports not in the new port list - if not self.PERFMODE: + if not ifupdownflags.flags.PERFMODE: runningbridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name) if runningbridgeports: for bport in runningbridgeports: @@ -364,7 +365,8 @@ class bridge(moduleBase): newbridgeports = Set(bridgeports).difference(Set(runningbridgeports)) for bridgeport in newbridgeports: try: - if not self.DRYRUN and not self.ipcmd.link_exists(bridgeport): + if (not ifupdownflags.flags.DRYRUN and + not self.ipcmd.link_exists(bridgeport)): self.log_warn('%s: bridge port %s does not exist' %(ifaceobj.name, bridgeport)) err += 1 @@ -476,7 +478,7 @@ class bridge(moduleBase): attrval = ifaceobj.get_attr_value_first('bridge-mcqv4src') if attrval: running_mcqv4src = {} - if not self.PERFMODE: + if not ifupdownflags.flags.PERFMODE: running_mcqv4src = self.brctlcmd.get_mcqv4src(ifaceobj.name) mcqs = {} srclist = attrval.split() @@ -993,38 +995,47 @@ class bridge(moduleBase): bridgename = self._get_bridgename(ifaceobj) add_port = True if bridgename: - if self.ipcmd.bridge_is_vlan_aware(bridgename): - if add_port: - # add ifaceobj to bridge - self.ipcmd.link_set(ifaceobj.name, 'master', bridgename) - bridge_vids = self._get_bridge_vids(bridgename, - ifaceobj_getfunc) - bridge_pvid = self._get_bridge_pvid(bridgename, - ifaceobj_getfunc) - self._apply_bridge_vlan_aware_port_settings_all(ifaceobj, - bridge_vids, - bridge_pvid) - self._apply_bridge_port_settings(ifaceobj, bridgename=bridgename) - ifaceobj.module_flags[self.name] = ifaceobj.module_flags.setdefault(self.name,0) | \ + if self.ipcmd.bridge_is_vlan_aware(bridgename): + if add_port: + # add ifaceobj to bridge + self.ipcmd.link_set(ifaceobj.name, 'master', bridgename) + bridge_vids = self._get_bridge_vids(bridgename, + ifaceobj_getfunc) + bridge_pvid = self._get_bridge_pvid(bridgename, + ifaceobj_getfunc) + self._apply_bridge_vlan_aware_port_settings_all(ifaceobj, + bridge_vids, + bridge_pvid) + self._apply_bridge_port_settings(ifaceobj, bridgename=bridgename) + ifaceobj.module_flags[self.name] = ifaceobj.module_flags.setdefault(self.name,0) | \ bridgeFlags.PORT_PROCESSED - return + return if not self._is_bridge(ifaceobj): return err = False errstr = '' running_ports = '' + bridge_just_created = False try: - if not self.PERFMODE: + if not ifupdownflags.flags.PERFMODE: if not self.ipcmd.link_exists(ifaceobj.name): self.ipcmd.link_create(ifaceobj.name, 'bridge') + bridge_just_created = True else: self.ipcmd.link_create(ifaceobj.name, 'bridge') + bridge_just_created = True except Exception, e: raise Exception(str(e)) try: if ifaceobj.get_attr_value_first('bridge-vlan-aware') == 'yes': - self.ipcmd.link_set(ifaceobj.name, 'vlan_filtering', '1', False, "bridge") + if (bridge_just_created or + not self.ipcmd.bridge_is_vlan_aware(ifaceobj.name)): + self.ipcmd.link_set(ifaceobj.name, 'vlan_filtering', '1', + False, "bridge") + if not bridge_just_created: + ifaceobj.module_flags[self.name] = ifaceobj.module_flags.setdefault(self.name,0) | bridgeFlags.PORT_PROCESSED_OVERRIDE + except Exception, e: raise Exception(str(e)) @@ -1676,11 +1687,10 @@ class bridge(moduleBase): return self._run_ops.keys() def _init_command_handlers(self): - flags = self.get_flags() if not self.ipcmd: - self.ipcmd = iproute2(**flags) + self.ipcmd = iproute2() if not self.brctlcmd: - self.brctlcmd = brctl(**flags) + self.brctlcmd = brctl() def run(self, ifaceobj, operation, query_ifaceobj=None, ifaceobj_getfunc=None): diff --git a/addons/bridgevlan.py b/addons/bridgevlan.py index 44824c7..ef40ef2 100644 --- a/addons/bridgevlan.py +++ b/addons/bridgevlan.py @@ -8,6 +8,7 @@ from ifupdown.iface import * from ifupdownaddons.modulebase import moduleBase from ifupdownaddons.iproute2 import iproute2 from ifupdownaddons.bridgeutils import brctl +import ifupdown.ifupdownflags as ifupdownflags import logging class bridgevlan(moduleBase): @@ -67,7 +68,7 @@ class bridgevlan(moduleBase): return running_mcqv4src = {} - if not self.PERFMODE: + if not ifupdownflags.flags.PERFMODE: running_mcqv4src = self.brctlcmd.get_mcqv4src(bridgename) if running_mcqv4src: r_mcqv4src = running_mcqv4src.get(vlan) @@ -137,9 +138,9 @@ class bridgevlan(moduleBase): def _init_command_handlers(self): if not self.ipcmd: - self.ipcmd = iproute2(**self.get_flags()) + self.ipcmd = iproute2() if not self.brctlcmd: - self.brctlcmd = brctl(**self.get_flags()) + self.brctlcmd = brctl() def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args): """ run vlan configuration on the interface object passed as argument diff --git a/addons/dhcp.py b/addons/dhcp.py index d9eee77..14988b9 100644 --- a/addons/dhcp.py +++ b/addons/dhcp.py @@ -12,6 +12,7 @@ try: from ifupdownaddons.modulebase import moduleBase from ifupdownaddons.dhclient import dhclient from ifupdownaddons.iproute2 import iproute2 + import ifupdown.ifupdownflags as ifupdownflags except ImportError, e: raise ImportError (str(e) + "- required module not found") @@ -31,17 +32,24 @@ class dhcp(moduleBase): ifaceobj.name) return try: + dhclient_cmd_prefix = None dhcp_wait = policymanager.policymanager_api.get_attr_default( module_name=self.__class__.__name__, attr='dhcp-wait') wait = not str(dhcp_wait).lower() == "no" + vrf = ifaceobj.get_attr_value_first('vrf') + if (vrf and self.vrf_exec_cmd_prefix and + self.ipcmd.link_exists(vrf)): + dhclient_cmd_prefix = '%s %s' %(self.vrf_exec_cmd_prefix, vrf) + if ifaceobj.addr_family == 'inet': # First release any existing dhclient processes try: - if not self.PERFMODE: + if not ifupdownflags.flags.PERFMODE: self.dhclientcmd.stop(ifaceobj.name) except: pass - self.dhclientcmd.start(ifaceobj.name, wait=wait) + self.dhclientcmd.start(ifaceobj.name, wait=wait, + cmd_prefix=dhclient_cmd_prefix) elif ifaceobj.addr_family == 'inet6': accept_ra = ifaceobj.get_attr_value_first('accept_ra') if accept_ra: @@ -57,12 +65,18 @@ class dhcp(moduleBase): self.dhclientcmd.stop6(ifaceobj.name) except: pass - self.dhclientcmd.start6(ifaceobj.name, wait=wait) + self.dhclientcmd.start6(ifaceobj.name, wait=wait, + cmd_prefix=dhclient_cmd_prefix) except Exception, e: self.log_error(str(e)) def _down(self, ifaceobj): - self.dhclientcmd.release(ifaceobj.name) + dhclient_cmd_prefix = None + vrf = ifaceobj.get_attr_value_first('vrf') + if (vrf and self.vrf_exec_cmd_prefix and + self.ipcmd.link_exists(vrf)): + dhclient_cmd_prefix = '%s %s' %(self.vrf_exec_cmd_prefix, vrf) + self.dhclientcmd.release(ifaceobj.name, dhclient_cmd_prefix) self.ipcmd.link_down(ifaceobj.name) def _query_check(self, ifaceobj, ifaceobjcurr): @@ -103,7 +117,7 @@ class dhcp(moduleBase): def _init_command_handlers(self): if not self.ipcmd: - self.ipcmd = iproute2(**self.get_flags()) + self.ipcmd = iproute2() def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args): """ run dhcp configuration on the interface object passed as argument diff --git a/addons/ethtool.py b/addons/ethtool.py index e96f288..d1f9a16 100644 --- a/addons/ethtool.py +++ b/addons/ethtool.py @@ -241,7 +241,7 @@ class ethtool(moduleBase,utilsBase): def _init_command_handlers(self): if not self.ipcmd: - self.ipcmd = iproute2(**self.get_flags()) + self.ipcmd = iproute2() def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args): """ run ethtool configuration on the interface object passed as diff --git a/addons/link.py b/addons/link.py index 867141d..98f315d 100644 --- a/addons/link.py +++ b/addons/link.py @@ -9,6 +9,7 @@ from ifupdown.iface import * from ifupdownaddons.modulebase import moduleBase from ifupdownaddons.iproute2 import iproute2 +import ifupdown.ifupdownflags as ifupdownflags import logging class link(moduleBase): @@ -32,7 +33,8 @@ class link(moduleBase): ifaceobj.get_attr_value_first('link-type')) def _down(self, ifaceobj): - if not self.PERFMODE and not self.ipcmd.link_exists(ifaceobj.name): + if (not ifupdownflags.flags.PERFMODE and + not self.ipcmd.link_exists(ifaceobj.name)): return try: self.ipcmd.link_delete(ifaceobj.name) @@ -60,7 +62,7 @@ class link(moduleBase): def _init_command_handlers(self): if not self.ipcmd: - self.ipcmd = iproute2(**self.get_flags()) + self.ipcmd = iproute2() def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args): op_handler = self._run_ops.get(operation) diff --git a/addons/mstpctl.py b/addons/mstpctl.py index 4ceca70..26b628f 100644 --- a/addons/mstpctl.py +++ b/addons/mstpctl.py @@ -12,6 +12,7 @@ from ifupdownaddons.bridgeutils import brctl from ifupdownaddons.iproute2 import iproute2 from ifupdownaddons.mstpctlutil import mstpctlutil from ifupdownaddons.systemutils import systemUtils +import ifupdown.ifupdownflags as ifupdownflags class mstpctlFlags: PORT_PROCESSED = 0x1 @@ -236,7 +237,7 @@ class mstpctl(moduleBase): runningbridgeports = [] # Delete active ports not in the new port list - if not self.PERFMODE: + if not ifupdownflags.flags.PERFMODE: runningbridgeports = self.brctlcmd.get_bridge_ports(ifaceobj.name) if runningbridgeports: [self.ipcmd.link_set(bport, 'nomaster') @@ -249,7 +250,8 @@ class mstpctl(moduleBase): err = 0 for bridgeport in Set(bridgeports).difference(Set(runningbridgeports)): try: - if not self.DRYRUN and not self.ipcmd.link_exists(bridgeport): + if (not ifupdownflags.flags.DRYRUN and + not self.ipcmd.link_exists(bridgeport)): self.log_warn('%s: bridge port %s does not exist' %(ifaceobj.name, bridgeport)) err += 1 @@ -263,7 +265,7 @@ class mstpctl(moduleBase): self.log_error('error configuring bridge (missing ports)') def _apply_bridge_settings(self, ifaceobj): - check = False if self.PERFMODE else True + check = False if ifupdownflags.flags.PERFMODE else True try: # set bridge attributes for attrname, dstattrname in self._attrs_map.items(): @@ -331,7 +333,7 @@ class mstpctl(moduleBase): bridgeifaceobj=None, stp_running_on=True, mstpd_running=True): - check = False if self.PERFMODE else True + check = False if ifupdownflags.flags.PERFMODE else True applied = False if not bridgename and bridgeifaceobj: bridgename = bridgeifaceobj.name @@ -446,7 +448,7 @@ class mstpctl(moduleBase): # If bridge ports specified with mstpctl attr, create the # bridge and also add its ports self.ipcmd.batch_start() - if not self.PERFMODE: + if not ifupdownflags.flags.PERFMODE: if not self.ipcmd.link_exists(ifaceobj.name): self.ipcmd.link_create(ifaceobj.name, 'bridge') else: @@ -809,13 +811,12 @@ class mstpctl(moduleBase): return self._run_ops.keys() def _init_command_handlers(self): - flags = self.get_flags() if not self.ipcmd: - self.ipcmd = iproute2(**flags) + self.ipcmd = iproute2() if not self.brctlcmd: - self.brctlcmd = brctl(**flags) + self.brctlcmd = brctl() if not self.mstpctlcmd: - self.mstpctlcmd = mstpctlutil(**flags) + self.mstpctlcmd = mstpctlutil() def run(self, ifaceobj, operation, query_ifaceobj=None, ifaceobj_getfunc=None, **extra_args): diff --git a/addons/usercmds.py b/addons/usercmds.py index 72915ea..12cef6c 100644 --- a/addons/usercmds.py +++ b/addons/usercmds.py @@ -6,6 +6,10 @@ import subprocess import ifupdownaddons +import signal + +from ifupdown.utils import utils +import ifupdown.ifupdownflags as ifupdownflags class usercmds(ifupdownaddons.modulebase.moduleBase): """ ifupdown2 addon module to configure user specified commands """ @@ -35,18 +39,21 @@ class usercmds(ifupdownaddons.modulebase.moduleBase): cmd_returncode = 0 try: self.logger.info('executing %s' %cmd) - if self.DRYRUN: + if ifupdownflags.flags.DRYRUN: return ch = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True, stderr=subprocess.STDOUT, close_fds=True) + utils.enable_subprocess_signal_forwarding(ch, signal.SIGINT) cmd_returncode = ch.wait() cmdout = ch.communicate()[0] except Exception, e: raise Exception('failed to execute cmd \'%s\' (%s)' %(cmd, str(e))) + finally: + utils.disable_subprocess_signal_forwarding(signal.SIGINT) if cmd_returncode != 0: raise Exception(cmdout) return cmdout diff --git a/addons/vlan.py b/addons/vlan.py index c877d55..85e7b75 100644 --- a/addons/vlan.py +++ b/addons/vlan.py @@ -8,6 +8,7 @@ from ifupdown.iface import * from ifupdownaddons.modulebase import moduleBase from ifupdownaddons.iproute2 import iproute2 import ifupdown.rtnetlink_api as rtnetlink_api +import ifupdown.ifupdownflags as ifupdownflags import logging import re @@ -132,7 +133,7 @@ class vlan(moduleBase): vlanrawdevice = self._get_vlan_raw_device(ifaceobj) if not vlanrawdevice: raise Exception('could not determine vlan raw device') - if not self.PERFMODE: + if not ifupdownflags.flags.PERFMODE: if not self.ipcmd.link_exists(vlanrawdevice): raise Exception('rawdevice %s not present' %vlanrawdevice) if self.ipcmd.link_exists(ifaceobj.name): @@ -151,7 +152,8 @@ class vlan(moduleBase): vlanrawdevice = self._get_vlan_raw_device(ifaceobj) if not vlanrawdevice: raise Exception('could not determine vlan raw device') - if not self.PERFMODE and not self.ipcmd.link_exists(ifaceobj.name): + if (not ifupdownflags.flags.PERFMODE and + not self.ipcmd.link_exists(ifaceobj.name)): return try: self.ipcmd.link_delete(ifaceobj.name) @@ -203,9 +205,8 @@ class vlan(moduleBase): def _init_command_handlers(self): if not self.ipcmd: - self.ipcmd = iproute2(**self.get_flags()) + self.ipcmd = iproute2() - def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args): """ run vlan configuration on the interface object passed as argument diff --git a/addons/vrf.py b/addons/vrf.py index 3639051..92e619e 100644 --- a/addons/vrf.py +++ b/addons/vrf.py @@ -13,6 +13,7 @@ from ifupdown.iface import * import ifupdown.policymanager as policymanager import ifupdownaddons import ifupdown.rtnetlink_api as rtnetlink_api +import ifupdown.ifupdownflags as ifupdownflags from ifupdownaddons.modulebase import moduleBase from ifupdownaddons.bondutil import bondutil from ifupdownaddons.iproute2 import iproute2 @@ -50,7 +51,7 @@ class vrf(moduleBase): self.bondcmd = None self.dhclientcmd = None self.name = self.__class__.__name__ - if self.PERFMODE: + if ifupdownflags.flags.PERFMODE: # if perf mode is set, remove vrf map file. # start afresh. PERFMODE is set at boot if os.path.exists(self.iproute2_vrf_filename): @@ -97,6 +98,7 @@ class vrf(moduleBase): self.vrf_fix_local_table = True self.vrf_count = 0 self.vrf_cgroup_create = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-cgroup-create') + if not self.vrf_cgroup_create: self.vrf_cgroup_create = False elif self.vrf_cgroup_create == 'yes': @@ -104,6 +106,7 @@ class vrf(moduleBase): else: self.vrf_cgroup_create = False self.vrf_mgmt_devname = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-mgmt-devname') + self.vrf_helper = policymanager.policymanager_api.get_module_globals(module_name=self.__class__.__name__, attr='vrf-helper') def _iproute2_vrf_map_initialize(self): if self._iproute2_vrf_map_initialized: @@ -243,14 +246,24 @@ class vrf(moduleBase): return str(t) return None + def _iproute2_is_vrf_tableid_inuse(self, vrf_dev_name, table_id): + old_vrf_name = self.iproute2_vrf_map.get(int(table_id)) + if old_vrf_name and old_vrf_name != vrf_dev_name: + self.log_error('table id %s already assigned to vrf dev %s' + %(table_id, old_vrf_name)) + def _iproute2_vrf_table_entry_add(self, vrf_dev_name, table_id): old_vrf_name = self.iproute2_vrf_map.get(int(table_id)) - if not old_vrf_name or (old_vrf_name != vrf_dev_name): + if not old_vrf_name: self.iproute2_vrf_map[int(table_id)] = vrf_dev_name if self.iproute2_vrf_map_fd: self.iproute2_vrf_map_fd.write('%s %s\n' %(table_id, vrf_dev_name)) self.iproute2_vrf_map_fd.flush() + return + if old_vrf_name != vrf_dev_name: + self.log_error('table id %d already assigned to vrf dev %s' + %(table_id, old_vrf_name)) def _iproute2_vrf_table_entry_del(self, table_id): try: @@ -307,27 +320,35 @@ class vrf(moduleBase): %mobj.name) self.logger.info('%s: table id auto: selected table id %s\n' %(mobj.name, vrf_table)) - self._up_vrf_dev(mobj, vrf_table, False) + try: + self._up_vrf_dev(mobj, vrf_table, False) + except Exception: + raise break self._handle_existing_connections(ifaceobj, vrfname) self.ipcmd.link_set(ifacename, 'master', vrfname) return - def _down_dhcp_slave(self, ifaceobj): + def _down_dhcp_slave(self, ifaceobj, vrfname): try: - self.dhclientcmd.release(ifaceobj.name) + dhclient_cmd_prefix = None + if (vrfname and self.vrf_exec_cmd_prefix and + self.ipcmd.link_exists(vrfname)): + dhclient_cmd_prefix = '%s %s' %(self.vrf_exec_cmd_prefix, + vrfname) + self.dhclientcmd.release(ifaceobj.name, dhclient_cmd_prefix) except: # ignore any dhclient release errors pass def _handle_existing_connections(self, ifaceobj, vrfname): - if not ifaceobj or self.PERFMODE: + if not ifaceobj or ifupdownflags.flags.PERFMODE: return if (self.vrf_mgmt_devname and self.vrf_mgmt_devname == vrfname): self._kill_ssh_connections(ifaceobj.name) if self._is_dhcp_slave(ifaceobj): - self._down_dhcp_slave(ifaceobj) + self._down_dhcp_slave(ifaceobj, vrfname) def _up_vrf_slave(self, ifacename, vrfname, ifaceobj=None, ifaceobj_getfunc=None, vrf_exists=False): @@ -351,24 +372,26 @@ class vrf(moduleBase): rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name) if rule in self.ip_rule_cache: - rule_cmd = ip_rule_cmd %('', pref, 'oif', vrf_dev_name, vrf_table) + rule_cmd = ip_rule_cmd %('', pref, 'oif', vrf_dev_name, + vrf_dev_name) self.exec_command(rule_cmd) rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name) if rule in self.ip_rule_cache: - rule_cmd = ip_rule_cmd %('', pref, 'iif', vrf_dev_name, vrf_table) + rule_cmd = ip_rule_cmd %('', pref, 'iif', vrf_dev_name, + vrf_dev_name) self.exec_command(rule_cmd) rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name) if rule in self.ip6_rule_cache: rule_cmd = ip_rule_cmd %('-6', pref, 'oif', vrf_dev_name, - vrf_table) + vrf_dev_name) self.exec_command(rule_cmd) rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name) if rule in self.ip6_rule_cache: rule_cmd = ip_rule_cmd %('-6', pref, 'iif', vrf_dev_name, - vrf_table) + vrf_dev_name) self.exec_command(rule_cmd) def _add_vrf_rules(self, vrf_dev_name, vrf_table): @@ -399,23 +422,26 @@ class vrf(moduleBase): rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name) if rule not in self.ip_rule_cache: - rule_cmd = ip_rule_cmd %('', pref, 'oif', vrf_dev_name, vrf_table) + rule_cmd = ip_rule_cmd %('', pref, 'oif', vrf_dev_name, + vrf_dev_name) self.exec_command(rule_cmd) rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name) if rule not in self.ip_rule_cache: - rule_cmd = ip_rule_cmd %('', pref, 'iif', vrf_dev_name, vrf_table) + rule_cmd = ip_rule_cmd %('', pref, 'iif', vrf_dev_name, + vrf_dev_name) self.exec_command(rule_cmd) rule = ip_rule_out_format %(pref, 'oif', vrf_dev_name, vrf_dev_name) if rule not in self.ip6_rule_cache: - rule_cmd = ip_rule_cmd %('-6', pref, 'oif', vrf_dev_name, vrf_table) + rule_cmd = ip_rule_cmd %('-6', pref, 'oif', vrf_dev_name, + vrf_dev_name) self.exec_command(rule_cmd) rule = ip_rule_out_format %(pref, 'iif', vrf_dev_name, vrf_dev_name) if rule not in self.ip6_rule_cache: rule_cmd = ip_rule_cmd %('-6', pref, 'iif', vrf_dev_name, - vrf_table) + vrf_dev_name) self.exec_command(rule_cmd) def _add_vrf_slaves(self, ifaceobj, ifaceobj_getfunc=None): @@ -460,29 +486,13 @@ class vrf(moduleBase): %(ifaceobj.name, s, str(e))) pass - def _create_cgroup(self, ifaceobj): - if not self.vrf_cgroup_create: - return - try: - if not os.path.exists('/sys/fs/cgroup/l3mdev/%s' %ifaceobj.name): - self.exec_command('/usr/bin/cgcreate -g l3mdev:%s' %ifaceobj.name) - except Exception, e: - self.log_error('%s: cgroup create failed (%s)\n' - %(ifaceobj.name, str(e)), ifaceobj) - try: - self.exec_command('/usr/bin/cgset -r l3mdev.master-device=%s %s' - %(ifaceobj.name, ifaceobj.name)) - except Exception, e: - self.log_warn('%s: cgset failed (%s)\n' - %(ifaceobj.name, str(e)), ifaceobj) - def _set_vrf_dev_processed_flag(self, ifaceobj): ifaceobj.module_flags[self.name] = \ ifaceobj.module_flags.setdefault(self.name, 0) | \ vrfPrivFlags.PROCESSED def _check_vrf_dev_processed_flag(self, ifaceobj): - if (ifaceobj.module_flags.get(self.name, 0x0) & vrfPrivFlags.PROCESSED): + if (ifaceobj.module_flags.get(self.name, 0) & vrfPrivFlags.PROCESSED): return True return False @@ -495,6 +505,8 @@ class vrf(moduleBase): %ifaceobj.name) self.logger.info('%s: table id auto: selected table id %s\n' %(ifaceobj.name, vrf_table)) + else: + self._iproute2_is_vrf_tableid_inuse(ifaceobj.name, vrf_table) if not vrf_table.isdigit(): self.log_error('%s: vrf-table must be an integer or \'auto\'' @@ -515,6 +527,8 @@ class vrf(moduleBase): except Exception, e: self.log_error('%s: create failed (%s)\n' %(ifaceobj.name, str(e))) + if vrf_table != 'auto': + self._iproute2_vrf_table_entry_add(ifaceobj.name, vrf_table) else: if vrf_table == 'auto': vrf_table = self._get_iproute2_vrf_table(ifaceobj.name) @@ -529,49 +543,12 @@ class vrf(moduleBase): if vrf_table != running_table: self.log_error('%s: cannot change vrf table id,running table id %s is different from config id %s' %(ifaceobj.name, running_table, vrf_table)) - if vrf_table != 'auto': - self._iproute2_vrf_table_entry_add(ifaceobj.name, vrf_table) - return vrf_table - def _add_del_vrf_default_route(self, ifaceobj, vrf_table, add=True): - vrf_default_route = ifaceobj.get_attr_value_first('vrf-default-route') - if not vrf_default_route: - vrf_default_route = policymanager.policymanager_api.get_attr_default( - module_name=self.__class__.__name__, - attr='vrf-default-route') - if not vrf_default_route: - return - if str(vrf_default_route).lower() == "yes": - try: - if add: - self.exec_command('ip route add table %s unreachable ' - 'default metric %d' %(vrf_table, 240)) - else: - self.exec_command('ip route del table %s unreachable ' - 'default metric %d' %(vrf_table, 240)) - except OSError, e: - if add and e.errno != 17: - raise - else: - self.logger.info('%s: error deleting default route (%s)' - %(ifaceobj.name, str(e))) - pass - - try: - if add: - self.exec_command('ip -6 route add table %s unreachable ' - 'default metric %d' %(vrf_table, 240)) - else: - self.exec_command('ip -6 route del table %s unreachable ' - 'default metric %d' %(vrf_table, 240)) - except OSError, e: - if add and e.errno != 17: - raise - else: - self.logger.info('%s: error deleting default route (%s)' - %(ifaceobj.name, str(e))) - pass + def _up_vrf_helper(self, ifaceobj, vrf_table): + if self.vrf_helper: + self.exec_command('%s create %s %s' %(self.vrf_helper, + ifaceobj.name, vrf_table)) def _up_vrf_dev(self, ifaceobj, vrf_table, add_slaves=True, ifaceobj_getfunc=None): @@ -582,13 +559,16 @@ class vrf(moduleBase): if self._check_vrf_dev_processed_flag(ifaceobj): return True - vrf_table = self._create_vrf_dev(ifaceobj, vrf_table) + try: + vrf_table = self._create_vrf_dev(ifaceobj, vrf_table) + except Exception, e: + self.log_error('%s: %s' %(ifaceobj.name, str(e))) + try: self._add_vrf_rules(ifaceobj.name, vrf_table) - self._create_cgroup(ifaceobj) + self._up_vrf_helper(ifaceobj, vrf_table) if add_slaves: self._add_vrf_slaves(ifaceobj, ifaceobj_getfunc) - self._add_del_vrf_default_route(ifaceobj, vrf_table) self._set_vrf_dev_processed_flag(ifaceobj) rtnetlink_api.rtnl_api.link_set(ifaceobj.name, "up") except Exception, e: @@ -681,19 +661,17 @@ class vrf(moduleBase): # check if we were a slave before master = self.ipcmd.link_get_master(ifaceobj.name) if master: + self._iproute2_vrf_map_initialize() if self._is_vrf_dev(master): self._down_vrf_slave(ifaceobj.name, ifaceobj, master) except Exception, e: self.log_error(str(e)) - def _delete_cgroup(self, ifaceobj): - try: - if os.path.exists('/sys/fs/cgroup/l3mdev/%s' %ifaceobj.name): - self.exec_command('/usr/bin/cgdelete -g l3mdev:%s' %ifaceobj.name) - except Exception, e: - self.log_info('%s: cgroup delete failed (%s)\n' - %(ifaceobj.name, str(e)), ifaceobj) + def _down_vrf_helper(self, ifaceobj, vrf_table): + if self.vrf_helper: + self.exec_command('%s delete %s %s' %(self.vrf_helper, + ifaceobj.name, vrf_table)) def _down_vrf_dev(self, ifaceobj, vrf_table, ifaceobj_getfunc=None): @@ -701,7 +679,7 @@ class vrf(moduleBase): vrf_table = self._get_iproute2_vrf_table(ifaceobj.name) try: - self.exec_command('/usr/cumulus/bin/cl-vrf service disable %s' %ifaceobj.name) + self.exec_command('/usr/bin/vrf service disable %s' %ifaceobj.name) except Exception, e: self.logger.info('%s: %s' %(ifaceobj.name, str(e))) pass @@ -718,6 +696,8 @@ class vrf(moduleBase): self.logger.info('%s: %s' %(ifaceobj.name, str(e))) pass + self._down_vrf_helper(ifaceobj, vrf_table) + try: self._del_vrf_rules(ifaceobj.name, vrf_table) except Exception, e: @@ -732,8 +712,6 @@ class vrf(moduleBase): try: self._iproute2_vrf_table_entry_del(vrf_table) - self._add_del_vrf_default_route(ifaceobj, vrf_table, False) - self._delete_cgroup(ifaceobj) except Exception, e: self.logger.info('%s: %s' %(ifaceobj.name, str(e))) pass @@ -838,13 +816,12 @@ class vrf(moduleBase): return self._run_ops.keys() def _init_command_handlers(self): - flags = self.get_flags() if not self.ipcmd: - self.ipcmd = iproute2(**flags) + self.ipcmd = iproute2() if not self.bondcmd: - self.bondcmd = bondutil(**flags) + self.bondcmd = bondutil() if not self.dhclientcmd: - self.dhclientcmd = dhclient(**flags) + self.dhclientcmd = dhclient() def run(self, ifaceobj, operation, query_ifaceobj=None, ifaceobj_getfunc=None, **extra_args): diff --git a/addons/vrrpd.py b/addons/vrrpd.py index 9791141..c6718bc 100644 --- a/addons/vrrpd.py +++ b/addons/vrrpd.py @@ -10,6 +10,7 @@ try: from ifupdown.iface import * from ifupdownaddons.modulebase import moduleBase from ifupdownaddons.iproute2 import iproute2 + import ifupdown.ifupdownflags as ifupdownflags import os import glob import logging @@ -70,7 +71,7 @@ class vrrpd(moduleBase): """ up vrrpd -n -D -i $IFACE -v 1 -p 20 10.0.1.254 up ifplugd -i $IFACE -b -f -u0 -d1 -I -p -q """ - if (not self.DRYRUN and + if (not ifupdownflags.flags.DRYRUN and not os.path.exists('/sys/class/net/%s' %ifaceobj.name)): return diff --git a/addons/vxlan.py b/addons/vxlan.py index e7e5d57..8e2513d 100644 --- a/addons/vxlan.py +++ b/addons/vxlan.py @@ -76,8 +76,10 @@ class vxlan(moduleBase): except Exception, e: self.log_warn(str(e)) - def _query_check_n_update(self, ifaceobjcurr, attrname, attrval, + def _query_check_n_update(self, ifaceobj, ifaceobjcurr, attrname, attrval, running_attrval): + if not ifaceobj.get_attr_value_first(attrname): + return if running_attrval and attrval == running_attrval: ifaceobjcurr.update_config_with_status(attrname, attrval, 0) else: @@ -105,7 +107,7 @@ class vxlan(moduleBase): ifaceobjcurr.check_n_update_config_with_status_many(ifaceobj, self.get_mod_attrs(), -1) return - self._query_check_n_update(ifaceobjcurr, 'vxlan-id', + self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-id', ifaceobj.get_attr_value_first('vxlan-id'), vxlanattrs.get('vxlanid')) @@ -114,10 +116,10 @@ class vxlan(moduleBase): if running_attrval == self._clagd_vxlan_anycast_ip: # if local ip is anycast_ip, then let query_check to go through attrval = self._clagd_vxlan_anycast_ip - self._query_check_n_update(ifaceobjcurr, 'vxlan-local-tunnelip', + self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-local-tunnelip', attrval, running_attrval) - self._query_check_n_update(ifaceobjcurr, 'vxlan-svcnodeip', + self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-svcnodeip', ifaceobj.get_attr_value_first('vxlan-svcnodeip'), vxlanattrs.get('svcnode')) @@ -140,7 +142,7 @@ class vxlan(moduleBase): ageing = ifaceobj.get_attr_value_first('vxlan-ageing') if not ageing: ageing = self.get_mod_subattr('vxlan-ageing', 'default') - self._query_check_n_update(ifaceobjcurr, 'vxlan-ageing', + self._query_check_n_update(ifaceobj, ifaceobjcurr, 'vxlan-ageing', ageing, vxlanattrs.get('ageing')) def _query_running(self, ifaceobjrunning): @@ -179,7 +181,7 @@ class vxlan(moduleBase): def _init_command_handlers(self): if not self.ipcmd: - self.ipcmd = iproute2(**self.get_flags()) + self.ipcmd = iproute2() def run(self, ifaceobj, operation, query_ifaceobj=None, **extra_args): op_handler = self._run_ops.get(operation) diff --git a/debian/changelog b/debian/changelog index 61ea391..1ebd4f5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +ifupdown2 (1.1-cl3u2) UNRELEASED; urgency=medium + + * Dry-run upgrade test, will be replaced with proper text at the release time. + + -- dev-support Tue, 19 Apr 2016 14:35:52 -0700 + ifupdown2 (1.1-cl3u1) unstable; urgency=low * Initial release. diff --git a/debian/ifupdown2.dirs b/debian/ifupdown2.dirs index eccff3d..675c5f6 100644 --- a/debian/ifupdown2.dirs +++ b/debian/ifupdown2.dirs @@ -1,2 +1,3 @@ /etc/network/interfaces.d/ /var/lib/ifupdown2/policy.d/ +/var/lib/ifupdown2/hooks/ diff --git a/ifupdown/ifupdownbase.py b/ifupdown/ifupdownbase.py index 2a6b480..acf75d2 100644 --- a/ifupdown/ifupdownbase.py +++ b/ifupdown/ifupdownbase.py @@ -11,8 +11,13 @@ import logging import subprocess import re import os -from iface import * import rtnetlink_api as rtnetlink_api +import signal +import shlex + +from iface import * +from ifupdown.utils import utils +import ifupdownflags as ifupdownflags class ifupdownBase(object): @@ -24,26 +29,29 @@ class ifupdownBase(object): cmd_returncode = 0 cmdout = '' try: - self.logger.info('Executing ' + cmd) - if self.DRYRUN: + self.logger.info('executing ' + cmd) + if ifupdownflags.flags.DRYRUN: return cmdout - ch = subprocess.Popen(cmd.split(), + ch = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, shell=False, env=cmdenv, stderr=subprocess.STDOUT, close_fds=True) + utils.enable_subprocess_signal_forwarding(ch, signal.SIGINT) cmdout = ch.communicate()[0] cmd_returncode = ch.wait() except OSError, e: raise Exception('could not execute ' + cmd + '(' + str(e) + ')') + finally: + utils.disable_subprocess_signal_forwarding(signal.SIGINT) if cmd_returncode != 0: raise Exception('error executing cmd \'%s\'' %cmd + '\n(' + cmdout.strip('\n ') + ')') return cmdout def ignore_error(self, errmsg): - if (self.FORCE == True or re.search(r'exists', errmsg, + if (ifupdownflags.flags.FORCE == True or re.search(r'exists', errmsg, re.IGNORECASE | re.MULTILINE) is not None): return True return False diff --git a/ifupdown/ifupdownflags.py b/ifupdown/ifupdownflags.py new file mode 100644 index 0000000..5b7c386 --- /dev/null +++ b/ifupdown/ifupdownflags.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +# +# Copyright 2015 Cumulus Networks, Inc. All rights reserved. +# +# Author: Roopa Prabhu, roopa@cumulusnetworks.com +# +# + +class ifupdownFlags(): + + def __init__(self): + self.FORCE = False + self.DRYRUN = False + self.NOWAIT = False + self.PERFMODE = False + self.CACHE = False + + # Flags + self.CACHE_FLAGS = 0x0 + +flags = ifupdownFlags() diff --git a/ifupdown/ifupdownmain.py b/ifupdown/ifupdownmain.py index c6717b7..b3ab306 100644 --- a/ifupdown/ifupdownmain.py +++ b/ifupdown/ifupdownmain.py @@ -17,6 +17,7 @@ import copy import json import ifupdown.statemanager as statemanager import ifupdown.ifupdownconfig as ifupdownConfig +import ifupdown.ifupdownflags as ifupdownflags from networkinterfaces import * from iface import * from scheduler import * @@ -38,16 +39,6 @@ _crossmark = u'\u2717' _success_sym = '(%s)' %_tickmark _error_sym = '(%s)' %_crossmark -class ifupdownFlags(): - FORCE = False - DRYRUN = False - NOWAIT = False - PERFMODE = False - CACHE = False - - # Flags - CACHE_FLAGS = 0x0 - class ifupdownMainFlags(): WITH_DEPENDS = False ALL = False @@ -195,13 +186,14 @@ class ifupdownMain(ifupdownBase): AttributeError, KeyError """ self.logger = logging.getLogger('ifupdown') - self.FORCE = force - self.DRYRUN = dryrun - self.NOWAIT = nowait - self.PERFMODE = perfmode - self.CACHE = cache + ifupdownflags.flags.FORCE = force + ifupdownflags.flags.DRYRUN = dryrun + ifupdownflags.flags.NOWAIT = nowait + ifupdownflags.flags.PERFMODE = perfmode + ifupdownflags.flags.CACHE = cache + # Can be used to provide hints for caching - self.CACHE_FLAGS = 0x0 + ifupdownflags.flags.CACHE_FLAGS = 0x0 self.flags = ifupdownMainFlags() @@ -219,14 +211,6 @@ class ifupdownMain(ifupdownBase): self.flags.DELETE_DEPENDENT_IFACES_WITH_NOCONFIG = False self.flags.ADDONS_ENABLE = addons_enable - # Copy flags into ifupdownFlags - # XXX: before we transition fully to ifupdownFlags - ifupdownFlags.FORCE = force - ifupdownFlags.DRYRUN = dryrun - ifupdownFlags.NOWAIT = nowait - ifupdownFlags.PERFMODE = perfmode - ifupdownFlags.CACHE = cache - self.ifaces = OrderedDict() self.njobs = njobs self.pp = pprint.PrettyPrinter(indent=4) @@ -826,12 +810,7 @@ class ifupdownMain(ifupdownBase): mclass = getattr(m, mname) except: raise - minstance = mclass(force=self.FORCE, - dryrun=self.DRYRUN, - nowait=self.NOWAIT, - perfmode=self.PERFMODE, - cache=self.CACHE, - cacheflags=self.CACHE_FLAGS) + minstance = mclass() self.modules[mname] = minstance try: self.module_attrs[mname] = minstance.get_modinfo() @@ -1157,7 +1136,7 @@ class ifupdownMain(ifupdownBase): if self.flags.WITH_DEPENDS else False) finally: self._process_delay_admin_state_queue('up') - if not self.DRYRUN and self.flags.ADDONS_ENABLE: + if not ifupdownflags.flags.DRYRUN and self.flags.ADDONS_ENABLE: self._save_state() if not iface_read_ret or not ret: @@ -1224,7 +1203,7 @@ class ifupdownMain(ifupdownBase): if self.flags.WITH_DEPENDS else False) finally: self._process_delay_admin_state_queue('down') - if not self.DRYRUN and self.flags.ADDONS_ENABLE: + if not ifupdownflags.flags.DRYRUN and self.flags.ADDONS_ENABLE: self._save_state() def query(self, ops, auto=False, allow_classes=None, ifacenames=None, @@ -1390,7 +1369,7 @@ class ifupdownMain(ifupdownBase): ret = self._sched_ifaces(interfaces_to_up, upops, followdependents=True if self.flags.WITH_DEPENDS else False) - if self.DRYRUN: + if ifupdownflags.flags.DRYRUN: return self._save_state() @@ -1579,7 +1558,7 @@ class ifupdownMain(ifupdownBase): pass finally: self._process_delay_admin_state_queue('up') - if self.DRYRUN: + if ifupdownflags.flags.DRYRUN: return self._save_state() diff --git a/ifupdown/rtnetlink_api.py b/ifupdown/rtnetlink_api.py index 390a642..31d3f4b 100644 --- a/ifupdown/rtnetlink_api.py +++ b/ifupdown/rtnetlink_api.py @@ -12,7 +12,7 @@ from socket import AF_BRIDGE from iff import IFF_UP from rtnetlink import * import os -import ifupdownmain +import ifupdownflags as ifupdownflags class rtnetlinkApi(RtNetlink): @@ -42,7 +42,7 @@ class rtnetlinkApi(RtNetlink): def create_vlan(self, link, ifname, vlanid): self.logger.info('rtnetlink: ip link add link %s name %s type vlan id %s' %(link, ifname, vlanid)) - if ifupdownmain.ifupdownFlags.DRYRUN: + if ifupdownflags.flags.DRYRUN: return try: ifindex = self.get_ifindex(link) @@ -66,7 +66,7 @@ class rtnetlinkApi(RtNetlink): def create_macvlan(self, ifname, link, mode='private'): self.logger.info('rtnetlink: ip link add link %s name %s type macvlan mode private' %(link, ifname)) - if ifupdownmain.ifupdownFlags.DRYRUN: + if ifupdownflags.flags.DRYRUN: return try: ifindex = self.get_ifindex(link) @@ -91,7 +91,7 @@ class rtnetlinkApi(RtNetlink): def link_set(self, ifname, state): flags = 0 self.logger.info('rtnetlink: ip link set dev %s %s' %(ifname, state)) - if ifupdownmain.ifupdownFlags.DRYRUN: + if ifupdownflags.flags.DRYRUN: return if state == "up": @@ -106,9 +106,8 @@ class rtnetlinkApi(RtNetlink): self.process_wait([token]) def link_set_protodown(self, ifname, state): - flags = 0 self.logger.info('rtnetlink: setting link %s protodown %s' %(ifname, state)) - if ifupdownmain.ifupdownFlags.DRYRUN: + if ifupdownflags.flags.DRYRUN: return protodown = 1 if state == "on" else 0 @@ -123,7 +122,7 @@ class rtnetlinkApi(RtNetlink): def link_set_hwaddress(self, ifname, hwaddress): flags = 0 self.logger.info('rtnetlink: ip link set dev %s address %s' %(ifname, hwaddress)) - if ifupdownmain.ifupdownFlags.DRYRUN: + if ifupdownflags.flags.DRYRUN: return flags &= ~IFF_UP @@ -139,7 +138,7 @@ class rtnetlinkApi(RtNetlink): def addr_add(self, ifname, address, broadcast=None, peer=None, scope=None, preferred_lifetime=None): self.logger.info('rtnetlink: setting address') - if ifupdownmain.ifupdownFlags.DRYRUN: + if ifupdownflags.flags.DRYRUN: return try: @@ -176,7 +175,7 @@ class rtnetlinkApi(RtNetlink): ifi_change = IFF_UP rtas = {} self.logger.info('rtnetlink: setting link %s %s' %(ifname, state)) - if ifupdownmain.ifupdownFlags.DRYRUN: + if ifupdownflags.flags.DRYRUN: return if not ifattrs: return @@ -214,7 +213,7 @@ class rtnetlinkApi(RtNetlink): %(vid, 'untagged' if untagged else '', 'pvid' if pvid else '', dev, 'self' if not master else '')) - if ifupdownmain.ifupdownFlags.DRYRUN: + if ifupdownflags.flags.DRYRUN: return try: ifindex = self.get_ifindex(dev) diff --git a/ifupdown/scheduler.py b/ifupdown/scheduler.py index 92a7b2d..3202f9b 100644 --- a/ifupdown/scheduler.py +++ b/ifupdown/scheduler.py @@ -8,6 +8,7 @@ # from statemanager import * +import ifupdown.ifupdownflags as ifupdownflags from iface import * from graph import * from collections import deque @@ -179,7 +180,7 @@ class ifaceScheduler(): if (ifupdownobj.flags.SCHED_SKIP_CHECK_UPPERIFACES): return True - if (ifupdownobj.FORCE or + if (ifupdownflags.flags.FORCE or not ifupdownobj.flags.ADDONS_ENABLE or (not ifupdownobj.is_ifaceobj_noconfig(ifaceobj) and ifupdownobj.config.get('warn_on_ifdown', '0') == '0' and diff --git a/ifupdown/utils.py b/ifupdown/utils.py index 970ee03..458999e 100644 --- a/ifupdown/utils.py +++ b/ifupdown/utils.py @@ -9,6 +9,15 @@ import os import fcntl import re +import signal + +from functools import partial + +def signal_handler_f(ps, sig, frame): + if ps: + ps.send_signal(sig) + if sig == signal.SIGINT: + raise KeyboardInterrupt class utils(): @@ -58,3 +67,11 @@ class utils(): else: return False + @classmethod + def enable_subprocess_signal_forwarding(cls, ps, sig): + signal.signal(sig, partial(signal_handler_f, ps)) + + @classmethod + def disable_subprocess_signal_forwarding(cls, sig): + signal.signal(sig, signal.SIG_DFL) + diff --git a/ifupdownaddons/bondutil.py b/ifupdownaddons/bondutil.py index dd153a1..027f468 100644 --- a/ifupdownaddons/bondutil.py +++ b/ifupdownaddons/bondutil.py @@ -6,6 +6,7 @@ import os import re +import ifupdown.ifupdownflags as ifupdownflags from ifupdown.iface import * from utilsbase import * from iproute2 import * @@ -19,7 +20,7 @@ class bondutil(utilsBase): def __init__(self, *args, **kargs): utilsBase.__init__(self, *args, **kargs) - if self.CACHE and not self._cache_fill_done: + if ifupdownflags.flags.CACHE and not self._cache_fill_done: self._bond_linkinfo_fill_all() self._cache_fill_done = True @@ -67,11 +68,12 @@ class bondutil(utilsBase): [self._bond_linkinfo_fill_attrs(b) for b in bondstr.split()] def _bond_linkinfo_fill(self, bondname, refresh=False): - try: - linkCache.get_attr([bondname, 'linkinfo', 'slaves']) - return - except: - pass + if not refresh: + try: + linkCache.get_attr([bondname, 'linkinfo', 'slaves']) + return + except: + pass bondstr = self.read_file_oneline('/sys/class/net/bonding_masters') if (not bondstr or bondname not in bondstr.split()): raise Exception('bond %s not found' %bondname) @@ -79,9 +81,9 @@ class bondutil(utilsBase): def _cache_get(self, attrlist, refresh=False): try: - if self.DRYRUN: + if ifupdownflags.flags.DRYRUN: return None - if self.CACHE: + if ifupdownflags.flags.CACHE: if not bondutil._cache_fill_done: self._bond_linkinfo_fill_all() bondutil._cache_fill_done = True @@ -108,7 +110,7 @@ class bondutil(utilsBase): return False def _cache_update(self, attrlist, value): - if self.DRYRUN: return + if ifupdownflags.flags.DRYRUN: return try: if attrlist[-1] == 'slaves': linkCache.add_to_attrlist(attrlist, value) @@ -118,7 +120,7 @@ class bondutil(utilsBase): pass def _cache_delete(self, attrlist, value=None): - if self.DRYRUN: return + if ifupdownflags.flags.DRYRUN: return try: if attrlist[-1] == 'slaves': linkCache.remove_from_attrlist(attrlist, value) @@ -128,7 +130,7 @@ class bondutil(utilsBase): pass def _cache_invalidate(self): - if self.DRYRUN: return + if ifupdownflags.flags.DRYRUN: return linkCache.invalidate() def set_attrs(self, bondname, attrdict, prehook): @@ -143,11 +145,12 @@ class bondutil(utilsBase): try: if ((attrname not in ['lacp_rate', 'lacp_bypass']) or - ('mode', '802.3ad') in attrdict.items()): + self._cache_check([bondname, 'linkinfo', 'mode'], '802.3ad', + True)): self.write_file('/sys/class/net/%s/bonding/%s' %(bondname, attrname), attrval) except Exception, e: - if self.FORCE: + if ifupdownflags.flags.FORCE: self.logger.warn(str(e)) pass else: @@ -323,7 +326,7 @@ class bondutil(utilsBase): try: self.remove_slave(bondname, slave) except Exception, e: - if not self.FORCE: + if not ifupdownflags.flags.FORCE: raise Exception('error removing slave %s' %slave + ' from bond %s' %bondname + '(%s)' %str(e)) diff --git a/ifupdownaddons/bridgeutils.py b/ifupdownaddons/bridgeutils.py index 73f28b1..962f98d 100644 --- a/ifupdownaddons/bridgeutils.py +++ b/ifupdownaddons/bridgeutils.py @@ -9,6 +9,7 @@ from utilsbase import * import os import re import logging +import ifupdown.ifupdownflags as ifupdownflags from cache import * class brctl(utilsBase): @@ -19,7 +20,7 @@ class brctl(utilsBase): def __init__(self, *args, **kargs): utilsBase.__init__(self, *args, **kargs) - if self.CACHE and not brctl._cache_fill_done: + if ifupdownflags.flags.CACHE and not brctl._cache_fill_done: self._bridge_fill() brctl._cache_fill_done = True @@ -147,9 +148,9 @@ class brctl(utilsBase): def _cache_get(self, attrlist, refresh=False): try: - if self.DRYRUN: + if ifupdownflags.flags.DRYRUN: return None - if self.CACHE: + if ifupdownflags.flags.CACHE: if not self._cache_fill_done: self._bridge_fill() self._cache_fill_done = True @@ -176,21 +177,21 @@ class brctl(utilsBase): return False def _cache_update(self, attrlist, value): - if self.DRYRUN: return + if ifupdownflags.flags.DRYRUN: return try: linkCache.add_attr(attrlist, value) except: pass def _cache_delete(self, attrlist): - if self.DRYRUN: return + if ifupdownflags.flags.DRYRUN: return try: linkCache.del_attr(attrlist) except: pass def _cache_invalidate(self): - if self.DRYRUN: return + if ifupdownflags.flags.DRYRUN: return linkCache.invalidate() def create_bridge(self, bridgename): @@ -230,7 +231,7 @@ class brctl(utilsBase): 'ports', bridgeportname]) if portattrs == None: portattrs = {} for k, v in attrdict.iteritems(): - if self.CACHE: + if ifupdownflags.flags.CACHE: curval = portattrs.get(k) if curval and curval == v: continue diff --git a/ifupdownaddons/dhclient.py b/ifupdownaddons/dhclient.py index d7e21f4..6056a66 100644 --- a/ifupdownaddons/dhclient.py +++ b/ifupdownaddons/dhclient.py @@ -29,7 +29,18 @@ class dhclient(utilsBase): def is_running6(self, ifacename): return self._pid_exists('/run/dhclient6.%s.pid' %ifacename) - def stop(self, ifacename): + def _run_dhclient_cmd(self, cmd, cmd_prefix=None): + if not cmd_prefix: + cmd_aslist = [] + else: + cmd_aslist = cmd_prefix.split() + if cmd_aslist: + cmd_aslist.extend(cmd) + else: + cmd_aslist = cmd + self.subprocess_check_call(cmd_aslist) + + def stop(self, ifacename, cmd_prefix=None): if os.path.exists('/sbin/dhclient3'): cmd = ['/sbin/dhclient3', '-x', '-pf', '/run/dhclient.%s.pid' %ifacename, '-lf', @@ -40,23 +51,24 @@ class dhclient(utilsBase): '/run/dhclient.%s.pid' %ifacename, '-lf', '/var/lib/dhcp/dhclient.%s.leases' %ifacename, '%s' %ifacename] - self.subprocess_check_call(cmd) + self._run_dhclient_cmd(cmd, cmd_prefix) - def start(self, ifacename, wait=True): + def start(self, ifacename, wait=True, cmd_prefix=None): if os.path.exists('/sbin/dhclient3'): cmd = ['/sbin/dhclient3', '-pf', '/run/dhclient.%s.pid' %ifacename, '-lf', '/var/lib/dhcp3/dhclient.%s.leases' %ifacename, '%s' %ifacename] else: - cmd = ['/sbin/dhclient', '-pf', '/run/dhclient.%s.pid' %ifacename, - '-lf', '/var/lib/dhcp/dhclient.%s.leases' %ifacename, + cmd = ['/sbin/dhclient', '-pf', + '/run/dhclient.%s.pid' %ifacename, '-lf', + '/var/lib/dhcp/dhclient.%s.leases' %ifacename, '%s' %ifacename] if not wait: cmd.append('-nw') - self.subprocess_check_call(cmd) + self._run_dhclient_cmd(cmd, cmd_prefix) - def release(self, ifacename): + def release(self, ifacename, cmd_prefix=None): if os.path.exists('/sbin/dhclient3'): cmd = ['/sbin/dhclient3', '-r', '-pf', '/run/dhclient.%s.pid' %ifacename, '-lf', @@ -67,25 +79,27 @@ class dhclient(utilsBase): '/run/dhclient.%s.pid' %ifacename, '-lf', '/var/lib/dhcp/dhclient.%s.leases' %ifacename, '%s' %ifacename] - self.subprocess_check_call(cmd) + self._run_dhclient_cmd(cmd, cmd_prefix) - def start6(self, ifacename, wait=True): - cmd = ['dhclient', '-6', '-pf', + def start6(self, ifacename, wait=True, cmd_prefix=None): + cmd = ['/sbin/dhclient', '-6', '-pf', '/run/dhclient6.%s.pid' %ifacename, '-lf', '/var/lib/dhcp/dhclient.%s.leases ' %ifacename, '%s' %ifacename] if not wait: cmd.append('-nw') - self.subprocess_check_call(cmd) + self._run_dhclient_cmd(cmd, cmd_prefix) - def stop6(self, ifacename): - self.subprocess_check_call(['dhclient', '-6', '-x', '-pf', - '/run/dhclient.%s.pid' %ifacename, '-lf', - '/var/lib/dhcp/dhclient.%s.leases ' %ifacename, - '%s' %ifacename]) + def stop6(self, ifacename, cmd_prefix=None): + cmd = ['/sbin/dhclient', '-6', '-x', '-pf', + '/run/dhclient.%s.pid' %ifacename, '-lf', + '/var/lib/dhcp/dhclient.%s.leases ' %ifacename, + '%s' %ifacename] + self._run_dhclient_cmd(cmd, cmd_prefix) - def release6(self, ifacename): - self.subprocess_check_call(['dhclient', '-6', '-r', '-pf', - '/run/dhclient6.%s.pid' %ifacename, '-lf', - '/var/lib/dhcp/dhclient6.%s.leases' %ifacename, - '%s' %ifacename]) + def release6(self, ifacename, cmd_prefix=None): + cmd = ['/sbin/dhclient', '-6', '-r', '-pf', + '/run/dhclient6.%s.pid' %ifacename, '-lf', + '/var/lib/dhcp/dhclient6.%s.leases' %ifacename, + '%s' %ifacename] + self._run_dhclient_cmd(cmd, cmd_prefix) diff --git a/ifupdownaddons/iproute2.py b/ifupdownaddons/iproute2.py index c0711a7..7b1466c 100644 --- a/ifupdownaddons/iproute2.py +++ b/ifupdownaddons/iproute2.py @@ -6,10 +6,15 @@ import os import glob +import shlex +import signal + +from ifupdown.utils import utils from collections import OrderedDict from utilsbase import * from systemutils import * from cache import * +import ifupdown.ifupdownflags as ifupdownflags VXLAN_UDP_PORT = 4789 @@ -24,7 +29,7 @@ class iproute2(utilsBase): def __init__(self, *args, **kargs): utilsBase.__init__(self, *args, **kargs) - if self.CACHE: + if ifupdownflags.flags.CACHE: self._fill_cache() def _fill_cache(self): @@ -130,9 +135,9 @@ class iproute2(utilsBase): if ifacename argument given, fill cache for ifacename, else fill cache for all interfaces in the system """ - linkout = {} if iproute2._cache_fill_done and not refresh: return + try: # Check if ifacename is already full, in which case, return if ifacename and not refresh: @@ -177,9 +182,9 @@ class iproute2(utilsBase): def _cache_get(self, type, attrlist, refresh=False): try: - if self.DRYRUN: + if ifupdownflags.flags.DRYRUN: return False - if self.CACHE: + if ifupdownflags.flags.CACHE: if self._fill_cache(): # if we filled the cache, return new data return linkCache.get_attr(attrlist) @@ -211,14 +216,14 @@ class iproute2(utilsBase): return False def _cache_update(self, attrlist, value): - if self.DRYRUN: return + if ifupdownflags.flags.DRYRUN: return try: linkCache.add_attr(attrlist, value) except: pass def _cache_delete(self, attrlist): - if self.DRYRUN: return + if ifupdownflags.flags.DRYRUN: return try: linkCache.del_attr(attrlist) except: @@ -226,6 +231,7 @@ class iproute2(utilsBase): def _cache_invalidate(self): linkCache.invalidate() + iproute2._cache_fill_done = False def batch_start(self): self.ipbatcbuf = '' @@ -494,9 +500,11 @@ class iproute2(utilsBase): cmd = 'bridge fdb show brport %s' % dev cur_peers = [] try: - ps = subprocess.Popen((cmd).split(), stdout=subprocess.PIPE, close_fds=True) + ps = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, close_fds=True) + utils.enable_subprocess_signal_forwarding(ps, signal.SIGINT) output = subprocess.check_output(('grep', '00:00:00:00:00:00'), stdin=ps.stdout) ps.wait() + utils.disable_subprocess_signal_forwarding(signal.SIGINT) try: ppat = re.compile('\s+dst\s+(\d+.\d+.\d+.\d+)\s+') for l in output.split('\n'): @@ -509,6 +517,8 @@ class iproute2(utilsBase): except subprocess.CalledProcessError as e: if e.returncode != 1: self.logger.error(str(e)) + finally: + utils.disable_subprocess_signal_forwarding(signal.SIGINT) return cur_peers @@ -581,7 +591,7 @@ class iproute2(utilsBase): self._cache_update([name], {}) def link_exists(self, ifacename): - if self.DRYRUN: + if ifupdownflags.flags.DRYRUN: return True return os.path.exists('/sys/class/net/%s' %ifacename) diff --git a/ifupdownaddons/modulebase.py b/ifupdownaddons/modulebase.py index 9b6bd7f..b6c8d78 100644 --- a/ifupdownaddons/modulebase.py +++ b/ifupdownaddons/modulebase.py @@ -10,12 +10,13 @@ import io import logging import subprocess import traceback +import signal +import shlex + +from ifupdown.utils import utils from ifupdown.iface import * -#from ifupdownaddons.iproute2 import * -#from ifupdownaddons.dhclient import * -#from ifupdownaddons.bridgeutils import * -#from ifupdownaddons.mstpctlutil import * -#from ifupdownaddons.bondutil import * +import ifupdown.policymanager as policymanager +import ifupdown.ifupdownflags as ifupdownflags class moduleBase(object): """ Base class for ifupdown addon modules @@ -25,14 +26,11 @@ class moduleBase(object): def __init__(self, *args, **kargs): modulename = self.__class__.__name__ self.logger = logging.getLogger('ifupdown.' + modulename) - self.FORCE = kargs.get('force', False) - """force interface configuration""" - self.DRYRUN = kargs.get('dryrun', False) - """only predend you are applying configuration, dont really do it""" - self.NOWAIT = kargs.get('nowait', False) - self.PERFMODE = kargs.get('perfmode', False) - self.CACHE = kargs.get('cache', False) - self.CACHE_FLAGS = kargs.get('cacheflags', 0x0) + + # vrfs are a global concept and a vrf context can be applicable + # to all global vrf commands. Get the default vrf-exec-cmd-prefix + # here so that all modules can use it + self.vrf_exec_cmd_prefix = policymanager.policymanager_api.get_module_globals('vrf', attr='vrf-exec-cmd-prefix') def log_warn(self, str, ifaceobj=None): """ log a warning if err str is not one of which we should ignore """ @@ -77,18 +75,21 @@ class moduleBase(object): try: self.logger.info('Executing ' + cmd) - if self.DRYRUN: + if ifupdownflags.flags.DRYRUN: return cmdout - ch = subprocess.Popen(cmd.split(), + ch = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, shell=False, env=cmdenv, stderr=subprocess.STDOUT, close_fds=True) + utils.enable_subprocess_signal_forwarding(ch, signal.SIGINT) cmdout = ch.communicate()[0] cmd_returncode = ch.wait() except OSError, e: raise Exception('could not execute ' + cmd + '(' + str(e) + ')') + finally: + utils.disable_subprocess_signal_forwarding(signal.SIGINT) if cmd_returncode != 0: raise Exception('error executing cmd \'%s\'' %cmd + '(' + cmdout.strip('\n ') + ')') @@ -107,19 +108,22 @@ class moduleBase(object): try: self.logger.info('Executing %s (stdin=%s)' %(cmd, stdinbuf)) - if self.DRYRUN: + if ifupdownflags.flags.DRYRUN: return cmdout - ch = subprocess.Popen(cmd.split(), + ch = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=False, env=cmdenv, stderr=subprocess.STDOUT, close_fds=True) + utils.enable_subprocess_signal_forwarding(ch, signal.SIGINT) cmdout = ch.communicate(input=stdinbuf)[0] cmd_returncode = ch.wait() except OSError, e: raise Exception('could not execute ' + cmd + '(' + str(e) + ')') + finally: + utils.disable_subprocess_signal_forwarding(signal.SIGINT) if cmd_returncode != 0: raise Exception('error executing cmd \'%s (%s)\'' %(cmd, stdinbuf) + '(' + cmdout.strip('\n ') + ')') @@ -254,7 +258,7 @@ class moduleBase(object): return portlist def ignore_error(self, errmsg): - if (self.FORCE or re.search(r'exists', errmsg, + if (ifupdownflags.flags.FORCE or re.search(r'exists', errmsg, re.IGNORECASE | re.MULTILINE)): return True return False @@ -264,7 +268,7 @@ class moduleBase(object): try: self.logger.info('writing \'%s\'' %strexpr + ' to file %s' %filename) - if self.DRYRUN: + if ifupdownflags.flags.DRYRUN: return 0 with open(filename, 'w') as f: f.write(strexpr) @@ -374,11 +378,6 @@ class moduleBase(object): except: return None - def get_flags(self): - return dict(force=self.FORCE, dryrun=self.DRYRUN, nowait=self.NOWAIT, - perfmode=self.PERFMODE, cache=self.CACHE, - cacheflags=self.CACHE_FLAGS) - def _get_reserved_vlan_range(self): start = end = 0 get_resvvlan = '/usr/share/python-ifupdown2/get_reserved_vlan_range.sh' diff --git a/ifupdownaddons/mstpctlutil.py b/ifupdownaddons/mstpctlutil.py index 75a1f51..1096cdb 100644 --- a/ifupdownaddons/mstpctlutil.py +++ b/ifupdownaddons/mstpctlutil.py @@ -77,8 +77,9 @@ class mstpctlutil(utilsBase): try: showall_output = self.subprocess_check_output(['/sbin/mstpctl', 'showportdetail', bridgename, 'json']) - except: - pass + except Exception as e: + self.logger.info(str(e)) + return if not showall_output or showall_output == '': return showall_output = showall_output.strip('\n') diff --git a/ifupdownaddons/utilsbase.py b/ifupdownaddons/utilsbase.py index 73fdfd5..a490c8f 100644 --- a/ifupdownaddons/utilsbase.py +++ b/ifupdownaddons/utilsbase.py @@ -8,10 +8,13 @@ import logging import subprocess import re import io +import signal +import shlex + +from ifupdown.utils import utils +import ifupdown.ifupdownflags as ifupdownflags from ifupdown.iface import * from cache import * - -#import timeit import time import logging @@ -30,11 +33,6 @@ class utilsBase(object): def __init__(self, *args, **kargs): modulename = self.__class__.__name__ self.logger = logging.getLogger('ifupdown.' + modulename) - self.FORCE = kargs.get('force', False) - self.DRYRUN = kargs.get('dryrun', False) - self.NOWAIT = kargs.get('nowait', False) - self.PERFMODE = kargs.get('perfmode', False) - self.CACHE = kargs.get('cache', False) def exec_commandl(self, cmdl, cmdenv=None): """ Executes command """ @@ -43,18 +41,21 @@ class utilsBase(object): cmdout = '' try: self.logger.info('executing ' + ' '.join(cmdl)) - if self.DRYRUN: + if ifupdownflags.flags.DRYRUN: return cmdout ch = subprocess.Popen(cmdl, stdout=subprocess.PIPE, shell=False, env=cmdenv, stderr=subprocess.STDOUT, close_fds=True) + utils.enable_subprocess_signal_forwarding(ch, signal.SIGINT) cmdout = ch.communicate()[0] cmd_returncode = ch.wait() except OSError, e: raise Exception('failed to execute cmd \'%s\' (%s)' %(' '.join(cmdl), str(e))) + finally: + utils.disable_subprocess_signal_forwarding(signal.SIGINT) if cmd_returncode != 0: raise Exception('failed to execute cmd \'%s\'' %' '.join(cmdl) + '(' + cmdout.strip('\n ') + ')') @@ -63,7 +64,7 @@ class utilsBase(object): def exec_command(self, cmd, cmdenv=None): """ Executes command given as string in the argument cmd """ - return self.exec_commandl(cmd.split(), cmdenv) + return self.exec_commandl(shlex.split(cmd), cmdenv) def exec_command_talk_stdin(self, cmd, stdinbuf): """ Executes command and writes to stdin of the process """ @@ -71,19 +72,22 @@ class utilsBase(object): cmdout = '' try: self.logger.info('executing %s [%s]' %(cmd, stdinbuf)) - if self.DRYRUN: + if ifupdownflags.flags.DRYRUN: return cmdout - ch = subprocess.Popen(cmd.split(), + ch = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stdin=subprocess.PIPE, shell=False, stderr=subprocess.STDOUT, close_fds=True) + utils.enable_subprocess_signal_forwarding(ch, signal.SIGINT) cmdout = ch.communicate(input=stdinbuf)[0] cmd_returncode = ch.wait() except OSError, e: raise Exception('failed to execute cmd \'%s\' (%s)' %(cmd, str(e))) + finally: + utils.disable_subprocess_signal_forwarding(signal.SIGINT) if cmd_returncode != 0: raise Exception('failed to execute cmd \'%s [%s]\'' %(cmd, stdinbuf) + '(' + cmdout.strip('\n ') + ')') @@ -91,13 +95,16 @@ class utilsBase(object): def subprocess_check_output(self, cmdl): self.logger.info('executing ' + ' '.join(cmdl)) - if self.DRYRUN: + if ifupdownflags.flags.DRYRUN: return try: return subprocess.check_output(cmdl, stderr=subprocess.STDOUT) - except Exception, e: + except subprocess.CalledProcessError as e: raise Exception('failed to execute cmd \'%s\' (%s)' %(' '.join(cmdl), e.output)) + except Exception as e: + raise Exception('failed to execute cmd \'%s\' (%s)' + %(' '.join(cmdl), str(e))) def subprocess_check_call(self, cmdl): """ subprocess check_call implementation using popen @@ -108,17 +115,20 @@ class utilsBase(object): cmd_returncode = 0 try: self.logger.info('executing ' + ' '.join(cmdl)) - if self.DRYRUN: + if ifupdownflags.flags.DRYRUN: return ch = subprocess.Popen(cmdl, stdout=None, shell=False, stderr=None, close_fds=True) + utils.enable_subprocess_signal_forwarding(ch, signal.SIGINT) cmd_returncode = ch.wait() except Exception, e: raise Exception('failed to execute cmd \'%s\' (%s)' %(' '.join(cmdl), str(e))) + finally: + utils.disable_subprocess_signal_forwarding(signal.SIGINT) if cmd_returncode != 0: raise Exception('failed to execute cmd \'%s\'' %' '.join(cmdl)) @@ -128,7 +138,7 @@ class utilsBase(object): try: self.logger.info('writing \'%s\'' %strexpr + ' to file %s' %filename) - if self.DRYRUN: + if ifupdownflags.flags.DRYRUN: return 0 with open(filename, 'w') as f: f.write(strexpr)