Skip to content

Commit

Permalink
Updated Commit Confirm EOS (#1291)
Browse files Browse the repository at this point in the history
* initial stub out of commit confirmation methods and args

* update method args and doc strings based on PR discussion

* update base driver tests with new confirm_commit methods

* Updates to commit_confirm driver

* Updates to new naming

* Implement commit_confirm for EOS

First shot as a proof of concept.

* EOS updates for commit confirm

* Commit confirm updates

* Black

* Updates for commit confirm

Co-authored-by: Richard Collins <rbcollins@gmail.com>
Co-authored-by: Andreas Thienemann <andreas@bawue.net>
  • Loading branch information
3 people committed Oct 2, 2020
1 parent b21bdf5 commit 7f107a9
Showing 1 changed file with 94 additions and 9 deletions.
103 changes: 94 additions & 9 deletions napalm/eos/eos.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
from napalm.base.base import NetworkDriver
from napalm.base.utils import string_parsers
from napalm.base.exceptions import (
CommitError,
ConnectionException,
MergeConfigException,
ReplaceConfigException,
Expand Down Expand Up @@ -191,6 +192,39 @@ def _lock(self):
]:
raise SessionLockedException("Session is already in use")

def _get_pending_commits(self):
"""
Return a dictionary of configuration sessions with pending commit confirms and
corresponding time when confirm needs to happen by (rounded to nearest second).
Example:
{'napalm_607123': 522}
"""
config_sessions = self.device.run_commands(
["show configuration sessions detail"]
)
# Still returns all of the configuration sessions (original data-struct was just a list)
config_sessions = config_sessions[0]["sessions"]

# Arista reports the commitBy time relative to uptime of the box... :-(
uptime = self.device.run_commands(["show version"])
uptime = uptime[0].get("uptime", -1)

pending_commits = {}
for session_name, session_dict in config_sessions.items():
if "pendingCommitTimer" in session_dict["state"]:
commit_by = session_dict.get("commitBy", -1)
# Set to -1 if something went wrong in the calculation.
if commit_by == -1 or uptime == -1:
pending_commits[session_name] = -1
elif uptime >= commit_by:
pending_commits[session_name] = -1
else:
confirm_by_seconds = commit_by - uptime
pending_commits[session_name] = round(confirm_by_seconds)

return pending_commits

@staticmethod
def _multiline_convert(config, start="banner login", end="EOF", depth=1):
"""Converts running-config HEREDOC into EAPI JSON dict"""
Expand Down Expand Up @@ -334,15 +368,48 @@ def commit_config(self, message="", revert_in=None):
raise NotImplementedError(
"Commit message not implemented for this platform"
)
commands = [
"copy startup-config flash:rollback-0",
"configure session {}".format(self.config_session),
"commit",
"write memory",
]

self.device.run_commands(commands)
self.config_session = None
if revert_in is not None:
if self.has_pending_commit():
raise CommitError("Pending commit confirm already in process!")

commands = [
"copy startup-config flash:rollback-0",
"configure session {}".format(self.config_session),
"commit timer {}".format(
time.strftime("%H:%M:%S", time.gmtime(revert_in))
),
]
self.device.run_commands(commands)
else:
commands = [
"copy startup-config flash:rollback-0",
"configure session {}".format(self.config_session),
"commit",
"write memory",
]
self.device.run_commands(commands)
self.config_session = None

def has_pending_commit(self):
"""Boolean indicating if there is a commit-confirm in process."""
pending_commits = self._get_pending_commits()
# pending_commits will return an empty dict, if there are no commit-confirms pending.
return bool(pending_commits)

def confirm_commit(self):
"""Send final commit to confirm an in-proces commit that requires confirmation."""
pending_commits = self._get_pending_commits()
# The specific 'config_session' must show up as a pending commit.
if pending_commits.get(self.config_session):
commands = [
"configure session {} commit".format(self.config_session),
"write memory",
]
self.device.run_commands(commands)
self.config_session = None
else:
raise CommitError("No pending commit-confirm found!")

def discard_config(self):
"""Implementation of NAPALM method discard_config."""
Expand All @@ -353,8 +420,26 @@ def discard_config(self):

def rollback(self):
"""Implementation of NAPALM method rollback."""
commands = ["configure replace flash:rollback-0", "write memory"]

# Commit-confirm check and abort
pending_commits = self._get_pending_commits()
if pending_commits:
# Make sure pending commit matches self.config_session
if pending_commits.get(self.config_session):
commands = [
"configure session {} abort".format(self.config_session),
"write memory",
]
else:
msg = "Current config session not found as pending commit-confirm"
raise CommitError(msg)

# Standard rollback
else:
commands = ["configure replace flash:rollback-0", "write memory"]

self.device.run_commands(commands)
self.config_session = None

def get_facts(self):
"""Implementation of NAPALM method get_facts."""
Expand Down

0 comments on commit 7f107a9

Please sign in to comment.