adds more intelligent save logic and diff to network config modules (#26565)

* adds more intelligent save logic and diff to network config modules

* adds sha1 property to NetworkConfig
* adds new argument save_when to argument_spec
* adds new argument diff_against to argument_spec
* adds new argument intended_config to argument_spec
* renames config argument to running_config with alias to config
* deprecates the use of the save argument
* before and after now work with src argument
* misc module clean

Modules updated
* nxos_config
* ios_config
* eos_config

Most notably this makes the save mechanism more intelligent for config
modules for devices that need to copy the ephemeral config to
non-volatile storage.

The diff_against argument allows the playbook task to control what the
device's running-config is diff'ed against. By default it will return
the diff of the startup-config.

* removes ios_config from pep8/legacy_files.txt

* extends the ignore lines argument to the module

* clean up CI errors

* add missing list brackets

* fixes typo

* fixes unit test cases

* remove last line break when returning config contents

* encode config string to bytes before hashing

* fix typo

* addresses feedback in PR

* update unit test cases
This commit is contained in:
Peter Sprygada 2017-07-11 20:34:20 -04:00 committed by GitHub
parent dc4037e5a7
commit 0b6f0e6c0d
6 changed files with 628 additions and 233 deletions

View file

@ -26,12 +26,20 @@
# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
import re
import hashlib
from ansible.module_utils.six.moves import zip
from ansible.module_utils._text import to_bytes
from ansible.module_utils.network_common import to_list
DEFAULT_COMMENT_TOKENS = ['#', '!', '/*', '*/', 'echo']
DEFAULT_IGNORE_LINES_RE = set([
re.compile("Using \d+ out of \d+ bytes"),
re.compile("Building configuration"),
re.compile("Current configuration : \d+ bytes")
])
class ConfigLine(object):
@ -97,6 +105,9 @@ def ignore_line(text, tokens=None):
for item in (tokens or DEFAULT_COMMENT_TOKENS):
if text.startswith(item):
return True
for regex in DEFAULT_IGNORE_LINES_RE:
if regex.match(text):
return True
def _obj_to_text(x):
@ -141,9 +152,16 @@ def dumps(objects, output='block', comments=False):
class NetworkConfig(object):
def __init__(self, indent=1, contents=None):
def __init__(self, indent=1, contents=None, ignore_lines=None):
self._indent = indent
self._items = list()
self._config_text = None
if ignore_lines:
for item in ignore_lines:
if not isinstance(item, re._pattern_type):
item = re.compile(item)
DEFAULT_IGNORE_LINES_RE.add(item)
if contents:
self.load(contents)
@ -152,6 +170,16 @@ class NetworkConfig(object):
def items(self):
return self._items
@property
def config_text(self):
return self._config_text
@property
def sha1(self):
sha1 = hashlib.sha1()
sha1.update(to_bytes(str(self), errors='surrogate_or_strict'))
return sha1.digest()
def __getitem__(self, key):
for line in self:
if line.text == key:
@ -168,6 +196,7 @@ class NetworkConfig(object):
return len(self._items)
def load(self, s):
self._config_text = s
self._items = self.parse(s)
def loadfp(self, fp):