mirror of
https://github.com/CumulusNetworks/ifupdown2.git
synced 2024-05-06 15:54:50 +00:00
a193d8d1c0
Ticket: None Reviewed By: CCR-4692 Testing Done: smoke + scale tests If called with close_fds=True the subprocess module will try to close every fd from 3 to MAXFD before executing the specified command. This is done in Python not even with a C-implementation which truly affecting performances. This patch aims to better handle the file descriptor used by ifupdown2. Either by closing them after use or by setting the close-on-exec flag for the file descriptor, which causes the file descriptor to be automatically (and atomically) closed when any of the exec-family functions succeed. With the actual patch all tests are passing, I can't think of any future issue but if any a possible future modification might be to use the parameter 'preexec_fn', which allows us to set function which will be executed in the child process before executing the command line. We can always manually close any remaining open file descriptors with something like: >>> os.listdir('/proc/self/fd/') ['0', '1', '2', ‘3’, etc..] >>> for fd in os.listdir('/proc/self/fd/') >>> if int(fd) > 2: >>> os.close(fd) This patch is also totally re-organising the use of subprocesses. By removing all subprocess code redundancy.
214 lines
8.3 KiB
Python
214 lines
8.3 KiB
Python
#!/usr/bin/python
|
|
#
|
|
# Copyright 2015 Cumulus Networks, Inc. All rights reserved.
|
|
#
|
|
#
|
|
'''
|
|
The PolicyManager should be subclassed by addon modules
|
|
to read a JSON policy config file that is later used to
|
|
set defaults:
|
|
|
|
Initialize: This module defines a list of config file location based
|
|
on module. There are defined in the __init__(): All the
|
|
addon modules need to do is import the policymanager module.
|
|
|
|
import ifupdown.policymanager as policymanager
|
|
|
|
|
|
Provides: an API to retrieve link attributes based on addon module name,
|
|
interface name, and attribute.
|
|
|
|
The ifupdown.policymanager module provides a global object policymanager_api
|
|
that can be called like so:
|
|
|
|
speed_default = policymanager.policymanager_api.get_default(
|
|
module_name='ethtool',
|
|
ifname=ifaceobj.name,
|
|
attr='link-speed'
|
|
)
|
|
'''
|
|
|
|
import json
|
|
import logging
|
|
import glob
|
|
|
|
class policymanager():
|
|
def __init__(self):
|
|
# we should check for these files in order
|
|
# so that customers can override the /var/lib file settings
|
|
self.logger = logging.getLogger('ifupdown.' +
|
|
self.__class__.__name__)
|
|
|
|
# we grab the json files from a known location and make sure that
|
|
# the defaults_policy is checked first
|
|
user_files = glob.glob('/etc/network/ifupdown2/policy.d/*.json')
|
|
# grab the default module files
|
|
default_files = glob.glob('/var/lib/ifupdown2/policy.d/*.json')
|
|
# keep an array of defaults indexed by module name
|
|
self.system_policy_array = {}
|
|
for filename in default_files:
|
|
system_array = {}
|
|
try:
|
|
with open(filename, 'r') as fd:
|
|
system_array = json.load(fd)
|
|
self.logger.debug('reading %s system policy defaults config' \
|
|
% filename)
|
|
except Exception, e:
|
|
self.logger.info('could not read %s system policy defaults config' \
|
|
% filename)
|
|
self.logger.info(' exception is %s' % str(e))
|
|
|
|
for module in system_array.keys():
|
|
if self.system_policy_array.has_key(module):
|
|
self.logger.debug('warning: overwriting system module %s from file %s' \
|
|
% (module,filename))
|
|
self.system_policy_array[module] = system_array[module]
|
|
|
|
# take care of user defined policy defaults
|
|
self.user_policy_array = {}
|
|
for filename in user_files:
|
|
user_array = {}
|
|
try:
|
|
with open(filename, 'r') as fd:
|
|
user_array = json.load(fd)
|
|
self.logger.debug('reading %s policy user defaults config' \
|
|
% filename)
|
|
except Exception, e:
|
|
self.logger.debug('could not read %s user policy defaults config' \
|
|
% filename)
|
|
self.logger.debug(' exception is %s' % str(e))
|
|
# customer added module attributes
|
|
for module in user_array.keys():
|
|
if self.system_policy_array.has_key(module):
|
|
# warn user that we are overriding the system module setting
|
|
self.logger.debug('warning: overwriting system with user module %s from file %s' \
|
|
% (module,filename))
|
|
self.user_policy_array[module] = user_array[module]
|
|
return
|
|
|
|
def get_iface_default(self,module_name=None,ifname=None,attr=None):
|
|
'''
|
|
get_iface_default: Addon modules must use one of two types of access methods to
|
|
the default configs. In this method, we expect the default to be
|
|
either in
|
|
[module]['iface_defaults'][ifname][attr] or
|
|
[module]['defaults'][attr]
|
|
We first check the user_policy_array and return that value. But if
|
|
the user did not specify an override, we use the system_policy_array.
|
|
'''
|
|
# make sure we have an index
|
|
if (not ifname or not attr or not module_name):
|
|
return None
|
|
|
|
val = None
|
|
# users can specify defaults to override the systemwide settings
|
|
# look for user specific interface attribute iface_defaults first
|
|
try:
|
|
# looks for user specified value
|
|
val = self.user_policy_array[module_name]['iface_defaults'][ifname][attr]
|
|
return val
|
|
except (TypeError, KeyError, IndexError):
|
|
pass
|
|
try:
|
|
# failing that, there may be a user default for all intefaces
|
|
val = self.user_policy_array[module_name]['defaults'][attr]
|
|
return val
|
|
except (TypeError, KeyError, IndexError):
|
|
pass
|
|
try:
|
|
# failing that, look for system setting for the interface
|
|
val = self.system_policy_array[module_name]['iface_defaults'][ifname][attr]
|
|
return val
|
|
except (TypeError, KeyError, IndexError):
|
|
pass
|
|
try:
|
|
# failing that, look for system setting for all interfaces
|
|
val = self.system_policy_array[module_name]['defaults'][attr]
|
|
return val
|
|
except (TypeError, KeyError, IndexError):
|
|
pass
|
|
|
|
# could not find any system or user default so return Non
|
|
return val
|
|
|
|
def get_attr_default(self,module_name=None,attr=None):
|
|
'''
|
|
get_attr_default: Addon modules must use one of two types of access methods to
|
|
the default configs. In this method, we expect the default to be in
|
|
|
|
[module]['defaults'][attr]
|
|
|
|
We first check the user_policy_array and return that value. But if
|
|
the user did not specify an override, we use the system_policy_array.
|
|
'''
|
|
if (not attr or not module_name):
|
|
return None
|
|
# users can specify defaults to override the systemwide settings
|
|
# look for user specific attribute defaults first
|
|
val = None
|
|
try:
|
|
# looks for user specified value
|
|
val = self.user_policy_array[module_name]['defaults'][attr]
|
|
return val
|
|
except (TypeError, KeyError, IndexError):
|
|
pass
|
|
try:
|
|
# failing that, look for system setting
|
|
val = self.system_policy_array[module_name]['defaults'][attr]
|
|
return val
|
|
except (TypeError, KeyError, IndexError):
|
|
pass
|
|
|
|
return val
|
|
|
|
def get_module_globals(self,module_name=None,attr=None):
|
|
'''
|
|
get_module_globals: Addon modules must use one of two types of access methods to
|
|
the default configs. In this method, we expect the default to be in
|
|
|
|
[module]['module_globals'][attr]
|
|
|
|
We first check the user_policy_array and return that value. But if
|
|
the user did not specify an override, we use the system_policy_array.
|
|
'''
|
|
|
|
if (not attr or not module_name):
|
|
return None
|
|
# users can specify defaults to override the systemwide settings
|
|
# look for user specific attribute defaults first
|
|
val = None
|
|
try:
|
|
# looks for user specified value
|
|
val = self.user_policy_array[module_name]['module_globals'][attr]
|
|
return val
|
|
except (TypeError, KeyError, IndexError):
|
|
pass
|
|
try:
|
|
# failing that, look for system setting
|
|
val = self.system_policy_array[module_name]['module_globals'][attr]
|
|
return val
|
|
except (TypeError, KeyError, IndexError):
|
|
pass
|
|
|
|
return val
|
|
|
|
def get_module_default(self,module_name=None):
|
|
'''
|
|
get_module_default: Addon modules can also access the entire config
|
|
This method returns indexed by "system" and "user": these are the
|
|
system-wide and user-defined policy arrays for a specific module.
|
|
'''
|
|
if not module_name:
|
|
return None
|
|
if self.system_policy_array.get(module_name) and \
|
|
self.user_policy_array.get(module_name):
|
|
mod_array = {"system":self.system_policy_array[module_name],
|
|
"user":self.user_policy_array[module_name]}
|
|
else:
|
|
# the module must not have these defined, return None
|
|
mod_array = None
|
|
|
|
return mod_array
|
|
|
|
policymanager_api = policymanager()
|