"""Mange config files on HPCOM7 devices.
"""
import os
import time
from pyhpecw7.features.errors import InvalidConfigFile
from ncclient.operations.rpc import RPCError
[docs]class Config(object):
"""This class is used to activate a new running config in real-time.
Args:
device (HPCOM7): connected instance of a ``pyhpecw7.comware.HPCOM7``
object.
filename (str): absolute path to the file that will be compared
and/or activated on the device.
Attributes:
device (HPCOM7): connected instance of a ``pyhpecw7.comware.HPCOM7``
object.
filename (str): absolute path to the file that will be compared
and/or activated on the device.
"""
def __init__(self, device, filename):
self.device = device
self.filename = filename
self.basename = os.path.basename(self.filename)
self._diff_response = ''
self._switch_response = []
self._original__diffs = []
self._diffs = []
def _get__diffs_from_switch(self):
"""Compare switch running config to desired new config file.
"""
cmds = 'display diff current-configuration configfile {0}'.format(
self.basename)
# raw string output taken directly from the switch showing the diff
self._diff_response = self.device.cli_display(cmds)
[docs] def compare_config(self):
"""Compare new config file to the existing current running config
Returns:
This returns a tuple of two elements that are both lists.
The first element has a summary of diffs (self._diffs) and
the second element is the exact output from the 'display diff'
command, but as a list (self._original__diffs).
"""
self._diffs = []
new_cfg = []
current_cfg = []
if not self._diff_response:
self._get__diffs_from_switch()
# same as _diff_response, but as a list with each line as an element
self._original__diffs = self._diff_response.split('\n')
for line in self._original__diffs:
if line.strip().startswith('-') and '#' not in line:
current_cfg.append(line.strip('-').strip())
elif line.strip().startswith('+') and '#' not in line:
new_cfg.append(line.strip('+').strip())
commands_to_apply = set(new_cfg).difference(current_cfg)
commands_to_remove = set(current_cfg).difference(new_cfg)
# diffs is summary of exactly which lines are changing in
# _original__diffs because _diffs from switch show everything
for each in commands_to_apply:
self._diffs.append('+' + each)
for each in commands_to_remove:
self._diffs.append('-' + each)
return self._diffs, self._original__diffs
# def activate_replacement_config(self):
# """Activate replacement config on host device
#
# This method immediately activates the new config
# file to be the new running config and does not perform a backup
# or new save as is done in ``build_config``.
#
# """
# try:
# # CLI response from switch during activation.
# self._switch_response = self.device.rollback(self.basename)
# except RPCError as err:
# if str(err).strip() == 'Operation failed.':
# raise InvalidConfigFile
#
# time.sleep(.5)
[docs] def build(self, stage=False):
"""Stage or execute configuration required to activate new config file.
This method stores the existing running configuration
as flash:/safety_file.cfg, loads the new config file,
and then stores the newly loaded file to flash:/startup.cfg.
Args:
stage (bool): whether to stage the commands or execute
immediately
Returns:
True if stage=True and staging is successful
List of etree.Element XML responses if immediate execution
"""
if stage:
backup = self.device.stage_config('safety_file.cfg', "save")
rollback = self.device.stage_config(self.basename, "rollback")
save = self.device.stage_config('startup.cfg', "save")
return backup and rollback and save
else:
responses = []
responses.append(self.device.save('safety_file.cfg'))
responses.append(self.device.rollback(self.basename))
responses.append(self.device.save('startup.cfg'))
return responses