Skip to content

Commit 894b922

Browse files
committed
config: Ignore unknown options starting with ngs_
Currently, all unknown configuration options are passed to Netmiko. This allows to pass Netmiko-specific options easily from the NGS configuration. However, if Netmiko does not recognize an option, it crashes with an error such as: `__init__() got an unexpected keyword argument 'ngs_foo'` We now ignore any option that starts with `ngs_` to help with compatibility (old NGS with new config) and we print a warning instead of crashing. To give more context in this warning, we now pass the device name (as specified in the configuration) to the device class itself. Change-Id: Ife4e15d2c0462337b0a88a83a3ea0aef6fb78a41
1 parent e10c7cc commit 894b922

File tree

7 files changed

+43
-18
lines changed

7 files changed

+43
-18
lines changed

CONTRIBUTING.rst

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,13 @@ Creating new device plugins
5050
``networking_generic_switch.devices.GenericSwitch``
5151
and implement all the abstract methods it defines.
5252

53-
* Your class must accept a single argument for instantiation -
54-
a dictionary with all fields given in the device config section
55-
of the ML2 plugin config.
56-
This will be available as ``self.config`` in the instantiated object.
53+
* Your class must accept as first argument a dictionary that contains
54+
all fields given in the device config section of the ML2 plugin config.
55+
This will be available as ``self.config`` in the instantiated object.
56+
The second argument is the device name as specified in the configuration.
57+
It is recommended to accept and pass ``*args`` and ``**kwargs`` to the
58+
__init__ method of the parent class: this helps to stay compatible with
59+
future changes of the base class.
5760

5861
#. Register your class under ``generic_switch.devices`` entrypoint.
5962
#. Add your device config to the plugin configuration file

networking_generic_switch/devices/__init__.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,14 @@
4747
]
4848

4949

50-
def device_manager(device_cfg):
50+
def device_manager(device_cfg, device_name=""):
5151
device_type = device_cfg.get('device_type', '')
5252
try:
5353
mgr = stevedore.driver.DriverManager(
5454
namespace=GENERIC_SWITCH_NAMESPACE,
5555
name=device_type,
5656
invoke_on_load=True,
57-
invoke_args=(device_cfg,),
57+
invoke_args=(device_cfg, device_name),
5858
on_load_failure_callback=_load_failure_hook
5959
)
6060
except stevedore.exception.NoUniqueMatch as exc:
@@ -75,16 +75,25 @@ def _load_failure_hook(manager, entrypoint, exception):
7575

7676
class GenericSwitchDevice(object, metaclass=abc.ABCMeta):
7777

78-
def __init__(self, device_cfg):
78+
def __init__(self, device_cfg, device_name=""):
7979
self.ngs_config = {}
8080
self.config = {}
81+
self.device_name = device_name
8182
# Do not expose NGS internal options to device config.
8283
for opt in NGS_INTERNAL_OPTS:
8384
opt_name = opt['name']
8485
if opt_name in device_cfg.keys():
8586
self.ngs_config[opt_name] = device_cfg.pop(opt_name)
8687
elif 'default' in opt:
8788
self.ngs_config[opt_name] = opt['default']
89+
# Ignore any other option starting with 'ngs_' (to avoid passing
90+
# these options to Netmiko)
91+
for opt_name in [o for o in device_cfg.keys() if o.startswith("ngs_")]:
92+
LOG.warning("Ignoring unknown option '%(opt_name)s' for "
93+
"device %(device)s",
94+
{'opt_name': opt_name, 'device': self.device_name})
95+
device_cfg.pop(opt_name)
96+
8897
self.config = device_cfg
8998

9099
self._validate_network_name_format()

networking_generic_switch/devices/netmiko_devices/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ class NetmikoSwitch(devices.GenericSwitchDevice):
9696
device output that indicate a failure to apply configuration.
9797
"""
9898

99-
def __init__(self, device_cfg):
100-
super(NetmikoSwitch, self).__init__(device_cfg)
99+
def __init__(self, device_cfg, *args, **kwargs):
100+
super(NetmikoSwitch, self).__init__(device_cfg, *args, **kwargs)
101101
if self.NETMIKO_DEVICE_TYPE:
102102
device_type = self.NETMIKO_DEVICE_TYPE
103103
else:

networking_generic_switch/devices/netmiko_devices/dell.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@ def _switch_to_general_mode(self):
127127
self.PLUG_PORT_TO_NETWORK = self.PLUG_PORT_TO_NETWORK_GENERAL
128128
self.DELETE_PORT = self.DELETE_PORT_GENERAL
129129

130-
def __init__(self, device_cfg):
131-
super(DellPowerConnect, self).__init__(device_cfg)
130+
def __init__(self, device_cfg, *args, **kwargs):
131+
super(DellPowerConnect, self).__init__(device_cfg, *args, **kwargs)
132132
port_mode = self.ngs_config['ngs_switchport_mode']
133133
switchport_mode = {
134134
'general': self._switch_to_general_mode,

networking_generic_switch/devices/netmiko_devices/juniper.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,16 +72,17 @@ class Juniper(netmiko_devices.NetmikoSwitch):
7272
'vlan members {segmentation_id}',
7373
)
7474

75-
def __init__(self, device_cfg):
76-
super(Juniper, self).__init__(device_cfg)
77-
75+
def __init__(self, device_cfg, *args, **kwargs):
7876
# Do not expose Juniper internal options to device config.
77+
juniper_cfg = {}
7978
for opt in JUNIPER_INTERNAL_OPTS:
8079
opt_name = opt['name']
81-
if opt_name in self.config:
82-
self.ngs_config[opt_name] = self.config.pop(opt_name)
80+
if opt_name in device_cfg:
81+
juniper_cfg[opt_name] = device_cfg.pop(opt_name)
8382
elif 'default' in opt:
84-
self.ngs_config[opt_name] = opt['default']
83+
juniper_cfg[opt_name] = opt['default']
84+
super(Juniper, self).__init__(device_cfg, *args, **kwargs)
85+
self.ngs_config.update(juniper_cfg)
8586

8687
def send_config_set(self, net_connect, cmd_set):
8788
"""Send a set of configuration lines to the device.

networking_generic_switch/generic_switch_mech.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def initialize(self):
4545
gsw_devices = gsw_conf.get_devices()
4646
self.switches = {}
4747
for switch_info, device_cfg in gsw_devices.items():
48-
switch = devices.device_manager(device_cfg)
48+
switch = devices.device_manager(device_cfg, switch_info)
4949
self.switches[switch_info] = switch
5050

5151
LOG.info('Devices %s have been loaded', self.switches.keys())
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
upgrade:
3+
- |
4+
To improve logging, the device name is now passed to the device driver
5+
class. If you implemented an out-of-tree device driver inheriting from
6+
``GenericSwitchDevice`` or ``NetmikoSwitch``, your code needs to be adapted
7+
to accept this new argument to the ``__init__`` method. It is recommended
8+
to use the ``*args, **kwargs`` pattern to accept and pass all unhandled
9+
arguments to the base class.
10+
fixes:
11+
- |
12+
Ignore unknown options starting with ``ngs_`` instead of crashing.

0 commit comments

Comments
 (0)