diff --git a/.gitignore b/.gitignore index 45b35e56..a7c3ba77 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ develop-eggs .venv .coverage cover +.stestr # Others .*.swp diff --git a/networking_generic_switch/devices/netmiko_devices/__init__.py b/networking_generic_switch/devices/netmiko_devices/__init__.py index 5db17fca..045546b7 100644 --- a/networking_generic_switch/devices/netmiko_devices/__init__.py +++ b/networking_generic_switch/devices/netmiko_devices/__init__.py @@ -127,6 +127,9 @@ def _create_connection(): with net_connect: yield net_connect + def send_config_set(self, net_connect, config_commands): + return net_connect.send_config_set(config_commands=config_commands) + def send_commands_to_device(self, cmd_set): if not cmd_set: LOG.debug("Nothing to execute") @@ -136,8 +139,8 @@ def send_commands_to_device(self, cmd_set): with ngs_lock.PoolLock(self.locker, **self.lock_kwargs): with self._get_connection() as net_connect: net_connect.enable() - output = net_connect.send_config_set( - config_commands=cmd_set) + output = self.send_config_set( + net_connect, config_commands=cmd_set) # NOTE (vsaienko) always save configuration # when configuration is applied successfully. self.save_configuration(net_connect) diff --git a/networking_generic_switch/devices/netmiko_devices/juniper.py b/networking_generic_switch/devices/netmiko_devices/juniper.py index a64e46ad..a8827c06 100644 --- a/networking_generic_switch/devices/netmiko_devices/juniper.py +++ b/networking_generic_switch/devices/netmiko_devices/juniper.py @@ -11,6 +11,11 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. +import time + +import tenacity + +from netmiko.py23_compat import string_types from networking_generic_switch.devices import netmiko_devices @@ -49,6 +54,44 @@ class Juniper(netmiko_devices.NetmikoSwitch): 'vlan members {segmentation_id}', ) + @tenacity.retry(reraise=True, stop=tenacity.stop_after_attempt(3), + wait=tenacity.wait_fixed(14)) + def send_config_set(self, net_connect, config_commands=None, + exit_config_mode=True, delay_factor=1, max_loops=150, + strip_prompt=False, strip_command=False, + config_mode_cmd='configure private'): + """Temporarily overriding the send_config_set method from netmiko. + + Temporarily overriding the send_config_set method from netmiko, until + upstream patch is accepted: + + https://github.com/ktbyers/netmiko/pull/593 + + """ + + delay_factor = net_connect.select_delay_factor(delay_factor) + if config_commands is None: + return '' + elif isinstance(config_commands, string_types): + config_commands = (config_commands,) + + if not hasattr(config_commands, '__iter__'): + raise ValueError("Invalid argument passed into send_config_set") + + # Send config commands + output = net_connect.config_mode(config_mode_cmd) + for cmd in config_commands: + net_connect.write_channel(net_connect.normalize_cmd(cmd)) + time.sleep(delay_factor * .5) + + # Gather output + output += net_connect._read_channel_timing( + delay_factor=delay_factor, max_loops=max_loops) + if exit_config_mode: + output += net_connect.exit_config_mode() + output = net_connect._sanitize_output(output) + return output + def save_configuration(self, net_connect): """Save the device's configuration. diff --git a/networking_generic_switch/tests/unit/netmiko/test_juniper.py b/networking_generic_switch/tests/unit/netmiko/test_juniper.py index 3426e411..eeda6fa7 100644 --- a/networking_generic_switch/tests/unit/netmiko/test_juniper.py +++ b/networking_generic_switch/tests/unit/netmiko/test_juniper.py @@ -51,7 +51,8 @@ def test_add_network_with_trunk_ports(self, mock_exec): 'NetmikoSwitch.send_commands_to_device') def test_del_network(self, mock_exec): self.switch.del_network(33, '0ae071f55be943e480eae41fefe85b21') - mock_exec.assert_called_with(['delete vlans 0ae071f55be943e480eae41fefe85b21']) + mock_exec.assert_called_with([ + 'delete vlans 0ae071f55be943e480eae41fefe85b21']) @mock.patch('networking_generic_switch.devices.netmiko_devices.' 'NetmikoSwitch.send_commands_to_device')