Skip to content
Closed
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
22 changes: 16 additions & 6 deletions napalm/base/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,22 +178,32 @@ def compare_config(self):
"""
raise NotImplementedError

def commit_config(self):
def commit_config(self, confirmed=None, message=None):
Copy link
Member

Choose a reason for hiding this comment

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

We should document what "confirmed" is supposed to be.

Copy link
Member

Choose a reason for hiding this comment

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

I also really think we shouldn't name this variable confirmed. It is a terrible name; revert_in or timer are way better names.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

confirmed is logical and is the most widely adopted name for this function. Basically saying you have to confirm this commit in how many minutes.

I think we will probably just add more confusion by naming it something else.

But agreed...it needs documented.

Choose a reason for hiding this comment

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

+1 on revert_in, describes the intent better. confirmed nomenclature maybe better known by network engineers, but I wouldn't cater to them exclusively with this library, you may have engineers without that background.

"""
Commits the changes requested by the method load_replace_candidate or load_merge_candidate.
"""
raise NotImplementedError

def discard_config(self):
def commit_confirm(self):
"""Confirm pending commit."""
raise NotImplementedError

def commit_confirm_revert(self):
"""Abort pending commit confirm immediately and rollback to previous state"""
raise NotImplementedError

def has_pending_commit(self):
"""
Discards the configuration loaded into the candidate.
:return A boolean indicating whether any pending commit confirms exist.
"""
raise NotImplementedError

def discard_config(self):
"""Discards the configuration loaded into the candidate."""
raise NotImplementedError

def rollback(self):
"""
If changes were made, revert changes to the original state.
"""
"""If changes were made, revert changes to the original state."""
raise NotImplementedError

def get_facts(self):
Expand Down
17 changes: 17 additions & 0 deletions napalm/base/test/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,23 @@ def test_replacing_and_committing_config(self):

self.assertEqual(len(diff), 0)

def test_replacing_and_committing_config_with_confirm(self):
try:
self.device.load_replace_candidate(filename='%s/new_good.conf' % self.vendor)
self.device.commit_config(confirmed=5)
self.device.commit_confirm()
except NotImplementedError:
raise SkipTest()

# The diff should be empty as the configuration has been committed already
diff = self.device.compare_config()

# Reverting changes
self.device.load_replace_candidate(filename='%s/initial.conf' % self.vendor)
self.device.commit_config()

self.assertEqual(len(diff), 0)

def test_replacing_config_with_typo(self):
result = False
try:
Expand Down
5 changes: 4 additions & 1 deletion napalm/eos/eos.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,8 +256,11 @@ def compare_config(self):

return result.strip()

def commit_config(self):
def commit_config(self, confirmed=None, message=None):
"""Implementation of NAPALM method commit_config."""
if confirmed is not None:
raise NotImplementedError

commands = []
commands.append('copy startup-config flash:rollback-0')
commands.append('configure session {}'.format(self.config_session))
Expand Down
44 changes: 38 additions & 6 deletions napalm/ios/ios.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,9 +420,27 @@ def _commit_hostname_handler(self, cmd):
self.device.set_base_prompt()
return output

def commit_config(self):
def commit_confirm(self):
"""Confirm pending commit."""
cmd = "configure confirm"
self.device.send_command_expect(cmd)

def commit_confirm_revert(self):
"""Immediately revert pending commit confirm."""
cmd = "configure revert now"
self.device.send_command_expect(cmd)

def has_pending_commit(self):
"""
:return A boolean indicating whether any pending commit confirms exist.
"""
If replacement operation, perform 'configure replace' for the entire config.
cmd = "show archive config rollback timer"
search_pattern = r"No Rollback Confirmed Change pending"
output = self.device.send_command_expect(cmd)
return not bool(re.search(search_pattern, output, flags=re.I))

def commit_config(self, confirmed=None, message=None):
"""If replacement operation, perform 'configure replace' for the entire config.

If merge operation, perform copy <file> running-config.
"""
Expand All @@ -435,10 +453,24 @@ def commit_config(self):
cfg_file = self._gen_full_path(filename)
if not self._check_file_exists(cfg_file):
raise ReplaceConfigException("Candidate config file does not exist")
if self.auto_rollback_on_error:
cmd = 'configure replace {} force revert trigger error'.format(cfg_file)
else:
cmd = 'configure replace {} force'.format(cfg_file)
if not self.auto_rollback_on_error:
raise NotImplementedError("auto_rollback_on_error attribute has been removed")

cmd = 'configure replace {} force revert trigger error'.format(cfg_file)
if confirmed is not None:
confirmed = int(confirmed)
# Ensure within Cisco IOS thresholds (minutes)
CISCO_LOW_THRESHOLD = 1
CISCO_HIGH_THRESHOLD = 120
if CISCO_LOW_THRESHOLD <= confirmed <= CISCO_HIGH_THRESHOLD:
cmd = 'configure replace flash:/candidate_config.txt force ' \
'revert trigger error timer {}'.format(confirmed)
else:
msg = "Invalid value for 'confirmed'; Cisco IOS requires a value " \
"between: {}-{} minutes".format(CISCO_LOW_THRESHOLD,
CISCO_HIGH_THRESHOLD)
raise ValueError(msg)

output = self._commit_hostname_handler(cmd)
if ('original configuration has been successfully restored' in output) or \
('error' in output.lower()) or \
Expand Down
5 changes: 4 additions & 1 deletion napalm/iosxr/iosxr.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,10 @@ def compare_config(self):
else:
return self.device.compare_config().strip()

def commit_config(self):
def commit_config(self, confirmed=None, message=None):
if confirmed is not None:
Copy link
Member

Choose a reason for hiding this comment

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

IOS-XR too (also message).

raise NotImplementedError

if self.replace:
self.device.commit_replace_config()
else:
Expand Down
5 changes: 4 additions & 1 deletion napalm/junos/junos.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,11 @@ def compare_config(self):
else:
return diff.strip()

def commit_config(self):
def commit_config(self, confirmed=None, message=None):
"""Commit configuration."""
if confirmed is not None:
Copy link
Member

Choose a reason for hiding this comment

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

Junos supports commit confirmed (and message).

raise NotImplementedError

self.device.cu.commit(ignore_warning=self.ignore_warning)
if not self.config_lock:
self._unlock()
Expand Down
5 changes: 4 additions & 1 deletion napalm/nxos/nxos.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,10 @@ def _load_config(self):
raise ReplaceConfigException(rollback_result['msg'])
return True

def commit_config(self):
def commit_config(self, confirmed=None, message=None):
if confirmed is not None:
raise NotImplementedError

if self.loaded:
self.backup_file = 'config_' + str(datetime.now()).replace(' ', '_')
self._save_config(self.backup_file)
Expand Down
5 changes: 4 additions & 1 deletion napalm/nxos_ssh/nxos_ssh.py
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,10 @@ def _load_cfg_from_checkpoint(self):
return False
return True

def commit_config(self):
def commit_config(self, confirmed=None, message=None):
if confirmed is not None:
raise NotImplementedError

if self.loaded:
self.backup_file = 'config_' + str(datetime.now()).replace(' ', '_')
# Create Checkpoint from current running-config
Expand Down