Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closes #2005: Change rollback behavior #2006

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions napalm/nxos/nxos.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,29 @@ 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
else:
return True

def _commit_merge(self) -> None:
try:
output = self._send_config(self.merge_candidate)
Expand Down Expand Up @@ -918,10 +941,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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might not be the right exception i.e. what are the cases where rollback gets called. We probably need to look at that a bit more. I generally view a ReplaceConfigException as an exception you get when you try to do the replace config operation.

I guess we could raise a generic NapalmException

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I copied ReplaceConfigException from other code that raises that exception during a rollback. I thought about raising NapalmException or creating a new RollbackConfigException, but I don't have strong preferences here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, let me look some more. I only looked at it quickly (it could make the most sense given what we have previously done).

self.device.rollback(self.rollback_cfg)
self._copy_run_start()
self.changed = False

def get_facts(self) -> models.FactsDict:
facts: models.FactsDict = {} # type: ignore
Expand Down
33 changes: 18 additions & 15 deletions napalm/nxos_ssh/nxos_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -553,21 +553,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)

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 = {}
Expand Down