From 9d6d06003aa96e57d5a2373da665c5363c0720f9 Mon Sep 17 00:00:00 2001 From: Austin de Coup-Crank Date: Wed, 6 Sep 2023 13:32:30 -0500 Subject: [PATCH 1/3] Closes #2005: Change rollback behavior --- napalm/nxos/nxos.py | 34 ++++++++++++++++++++++++++++++---- napalm/nxos_ssh/nxos_ssh.py | 33 ++++++++++++++++++--------------- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/napalm/nxos/nxos.py b/napalm/nxos/nxos.py index 0b46da0dd..3a738e779 100644 --- a/napalm/nxos/nxos.py +++ b/napalm/nxos/nxos.py @@ -191,6 +191,30 @@ def _send_command( ) -> Dict[str, Union[str, Dict[str, Any]]]: raise NotImplementedError + def _check_file_exists(self, cfg_file: str) -> bool: + """ + Check that the file exists on remote device using full path. + + cfg_file can be a full path, e.g.: bootflash:rollback_config.txt + or just a filename, e.g.: rollback_config.txt + + For example + # dir rollback_config.txt + 71803 Sep 06 14:13:33 2023 rollback_config.txt + + Usage for bootflash://sup-local + 6211682304 bytes used + 110314684416 bytes free + 116526366720 bytes total + """ + cmd = f"dir {cfg_file}" + output = self._send_command(command=cmd, raw_text=True) + if "No such file or directory" in output: + return False + elif cfg_file in output: + return True + return False + def _commit_merge(self) -> None: try: output = self._send_config(self.merge_candidate) @@ -918,10 +942,12 @@ def _load_cfg_from_checkpoint(self) -> None: def rollback(self) -> None: assert isinstance(self.device, NXOSDevice) - if self.changed: - self.device.rollback(self.rollback_cfg) - self._copy_run_start() - self.changed = False + if not self._check_file_exists(cfg_file=self.rollback_cfg): + msg = f"Rollback file '{self.rollback_cfg}' does not exist on device." + raise ReplaceConfigException(msg=msg) + self.device.rollback(self.rollback_cfg) + self._copy_run_start() + self.changed = False def get_facts(self) -> models.FactsDict: facts: models.FactsDict = {} # type: ignore diff --git a/napalm/nxos_ssh/nxos_ssh.py b/napalm/nxos_ssh/nxos_ssh.py index bdb01f5a9..2acee7cda 100644 --- a/napalm/nxos_ssh/nxos_ssh.py +++ b/napalm/nxos_ssh/nxos_ssh.py @@ -544,21 +544,24 @@ def _load_cfg_from_checkpoint(self): raise ReplaceConfigException(msg) def rollback(self): - if self.changed: - commands = [ - "terminal dont-ask", - "rollback running-config file {}".format(self.rollback_cfg), - "no terminal dont-ask", - ] - result = self._send_command_list( - commands, expect_string=r"[#>]", read_timeout=90 - ) - if "completed" not in result.lower(): - raise ReplaceConfigException(result) - # If hostname changes ensure Netmiko state is updated properly - self._netmiko_device.set_base_prompt() - self._copy_run_start() - self.changed = False + if not self._check_file_exists(self.rollback_cfg): + msg = f"Rollback file '{self.rollback_cfg}' does not exist on device." + raise ReplaceConfigException(msg=msg) + + commands = [ + "terminal dont-ask", + "rollback running-config file {}".format(self.rollback_cfg), + "no terminal dont-ask", + ] + result = self._send_command_list( + commands, expect_string=r"[#>]", read_timeout=90 + ) + if "completed" not in result.lower(): + raise ReplaceConfigException(result) + # If hostname changes ensure Netmiko state is updated properly + self._netmiko_device.set_base_prompt() + self._copy_run_start() + self.changed = False def _apply_key_map(self, key_map, table): new_dict = {} From 5e4f94803d15af346b9810d66aac6c3e90e0285a Mon Sep 17 00:00:00 2001 From: Austin de Coup-Crank Date: Wed, 6 Sep 2023 13:39:54 -0500 Subject: [PATCH 2/3] Fix mypy error --- napalm/nxos/nxos.py | 2 +- napalm/nxos_ssh/nxos_ssh.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/napalm/nxos/nxos.py b/napalm/nxos/nxos.py index 3a738e779..6e3c2b49e 100644 --- a/napalm/nxos/nxos.py +++ b/napalm/nxos/nxos.py @@ -944,7 +944,7 @@ def rollback(self) -> None: assert isinstance(self.device, NXOSDevice) if not self._check_file_exists(cfg_file=self.rollback_cfg): msg = f"Rollback file '{self.rollback_cfg}' does not exist on device." - raise ReplaceConfigException(msg=msg) + raise ReplaceConfigException(msg) self.device.rollback(self.rollback_cfg) self._copy_run_start() self.changed = False diff --git a/napalm/nxos_ssh/nxos_ssh.py b/napalm/nxos_ssh/nxos_ssh.py index 2acee7cda..9c9c15143 100644 --- a/napalm/nxos_ssh/nxos_ssh.py +++ b/napalm/nxos_ssh/nxos_ssh.py @@ -546,7 +546,7 @@ def _load_cfg_from_checkpoint(self): def rollback(self): if not self._check_file_exists(self.rollback_cfg): msg = f"Rollback file '{self.rollback_cfg}' does not exist on device." - raise ReplaceConfigException(msg=msg) + raise ReplaceConfigException(msg) commands = [ "terminal dont-ask", From b6b10b131c906f75502a7649f733689f43f8f021 Mon Sep 17 00:00:00 2001 From: Austin de Coup-Crank Date: Fri, 15 Sep 2023 14:27:19 -0500 Subject: [PATCH 3/3] Fix logic in _check_file_exists --- napalm/nxos/nxos.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/napalm/nxos/nxos.py b/napalm/nxos/nxos.py index 6e3c2b49e..93985a65f 100644 --- a/napalm/nxos/nxos.py +++ b/napalm/nxos/nxos.py @@ -211,9 +211,8 @@ def _check_file_exists(self, cfg_file: str) -> bool: output = self._send_command(command=cmd, raw_text=True) if "No such file or directory" in output: return False - elif cfg_file in output: + else: return True - return False def _commit_merge(self) -> None: try: