1
0
mirror of https://github.com/CumulusNetworks/ifupdown2.git synced 2024-05-06 15:54:50 +00:00
Julien Fortin 4b1a6ffdaf policymanager: merge module policy instead of overriding duplicates
When module policies are split up in seperate files ifupdown2 doesn't merge
them together but simply overrides duplicates. This pathc fixes the issue
and merge the related policies together.

Signed-off-by: Julien Fortin <julien@cumulusnetworks.com>
2019-06-06 19:18:11 +08:00

232 lines
9.1 KiB
Python

#!/usr/bin/python
#
# Copyright 2015-2017 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 ifupdown2.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 glob
import logging
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.warning('could not read %s system policy defaults config' \
% filename)
self.logger.warning(' exception is %s' % str(e))
for module in system_array.keys():
if self.system_policy_array.has_key(module):
self.logger.debug("policymanager: merging system module %s policy with file %s" % (module, filename))
self.system_policy_array[module].update(system_array[module])
else:
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.warning('could not read %s user policy defaults config' \
% filename)
self.logger.warning(' 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))
if module in self.user_policy_array:
self.logger.debug("policymanager: merging user module %s policy with file %s" % (module, filename))
self.user_policy_array[module].update(user_array[module])
else:
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_defaults(self, module_name):
"""
get_module_defaults: returns a merged dictionary of default values
specified in policy files. Users provided values override system
values.
"""
if not module_name:
raise NotImplementedError('get_module_defaults: module name can\'t be None')
defaults = dict()
defaults.update(self.system_policy_array.get(module_name, {}).get('defaults', {}))
defaults.update(self.user_policy_array.get(module_name, {}).get('defaults', {}))
return defaults
def get_iface_defaults(self, module_name):
defaults = dict()
if not module_name:
self.logger.info('get_iface_defaults: module name can\'t be None')
else:
defaults.update(self.system_policy_array.get(module_name, {}).get('iface_defaults', {}))
defaults.update(self.user_policy_array.get(module_name, {}).get('iface_defaults', {}))
return defaults
policymanager_api = policymanager()
def reset():
global policymanager_api
policymanager_api = policymanager()