summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Sprygada <privateip@users.noreply.github.com>2016-07-09 17:32:12 -0400
committerGitHub <noreply@github.com>2016-07-09 17:32:12 -0400
commitb7c47f9eb3f5304b90786f219798700211d0f36e (patch)
treed425094a627d68d9a40cc8d00f8c3bf6bd3aad98
parentcddeadcab6e10300fd52fe0a01eeeef550f95ab1 (diff)
parent80ab80b6fd6f201232a4d9ca829062f2a9fe16e6 (diff)
downloadansible-b7c47f9eb3f5304b90786f219798700211d0f36e.tar.gz
Merge pull request #16663 from privateip/netcfg
adds additional capabilities to diff of network configs
-rw-r--r--lib/ansible/module_utils/netcfg.py190
1 files changed, 91 insertions, 99 deletions
diff --git a/lib/ansible/module_utils/netcfg.py b/lib/ansible/module_utils/netcfg.py
index f916956105..085fe18a64 100644
--- a/lib/ansible/module_utils/netcfg.py
+++ b/lib/ansible/module_utils/netcfg.py
@@ -28,6 +28,7 @@ from ansible.module_utils.network import to_list
DEFAULT_COMMENT_TOKENS = ['#', '!']
+
class ConfigLine(object):
def __init__(self, text):
@@ -106,6 +107,19 @@ def parse(lines, indent, comment_tokens=None):
return config
+def dumps(objects, output='block'):
+ if output == 'block':
+ items = [c.raw for c in objects]
+ elif output == 'commands':
+ items = [c.text for c in objects]
+ elif output == 'lines':
+ items = list()
+ for obj in objects:
+ line = list()
+ line.extend([p.text for p in obj.parents])
+ line.append(obj.text)
+ items.append(' '.join(line))
+ return '\n'.join(items)
class NetworkConfig(object):
@@ -113,6 +127,10 @@ class NetworkConfig(object):
self.indent = indent or 1
self._config = list()
self._device_os = device_os
+ self._syntax = 'block' # block, lines, junos
+
+ if self._device_os == 'junos':
+ self._syntax = 'junos'
if contents:
self.load(contents)
@@ -121,21 +139,10 @@ class NetworkConfig(object):
def items(self):
return self._config
- @property
- def lines(self):
- lines = list()
- for item, next_item in get_next(self.items):
- if next_item is None:
- lines.append(item.line)
- elif not next_item.line.startswith(item.line):
- lines.append(item.line)
- return lines
-
def __str__(self):
if self._device_os == 'junos':
- lines = self.to_lines(self.expand(self.items))
- return '\n'.join(lines)
- return self.to_block(self.expand(self.items))
+ return dumps(self.expand_line(self.items), 'lines')
+ return dumps(self.expand_line(self.items))
def load(self, contents):
self._config = parse(contents, indent=self.indent)
@@ -152,6 +159,21 @@ class NetworkConfig(object):
if parents == path[:-1]:
return item
+ def get_object(self, path):
+ for item in self.items:
+ if item.text == path[-1]:
+ parents = [p.text for p in item.parents]
+ if parents == path[:-1]:
+ return item
+
+ def get_section_objects(self, path):
+ if not isinstance(path, list):
+ path = [path]
+ obj = self.get_object(path)
+ if not obj:
+ raise ValueError('path does not exist in config')
+ return self.expand_section(obj)
+
def search(self, regexp, path=None):
regex = re.compile(r'^%s' % regexp, re.M)
@@ -177,7 +199,7 @@ class NetworkConfig(object):
regexp = r'%s' % regexp
return re.findall(regexp, str(self))
- def expand(self, objs):
+ def expand_line(self, objs):
visited = set()
expanded = list()
for o in objs:
@@ -189,35 +211,6 @@ class NetworkConfig(object):
visited.add(o)
return expanded
- def to_lines(self, objects):
- lines = list()
- for obj in objects:
- line = list()
- line.extend([p.text for p in obj.parents])
- line.append(obj.text)
- lines.append(' '.join(line))
- return lines
-
- def to_block(self, section):
- return '\n'.join([item.raw for item in section])
-
- def get_section(self, path):
- try:
- section = self.get_section_objects(path)
- if self._device_os == 'junos':
- return self.to_lines(section)
- return self.to_block(section)
- except ValueError:
- return list()
-
- def get_section_objects(self, path):
- if not isinstance(path, list):
- path = [path]
- obj = self.get_object(path)
- if not obj:
- raise ValueError('path does not exist in config')
- return self.expand_section(obj)
-
def expand_section(self, configobj, S=None):
if S is None:
S = list()
@@ -228,74 +221,73 @@ class NetworkConfig(object):
self.expand_section(child, S)
return S
- def get_object(self, path):
- for item in self.items:
- if item.text == path[-1]:
- parents = [p.text for p in item.parents]
- if parents == path[:-1]:
- return item
-
- def get_children(self, path):
- obj = self.get_object(path)
- if obj:
- return obj.children
+ def expand_block(self, objects, visited=None):
+ items = list()
- def difference(self, other, path=None, match='line', replace='line'):
- updates = list()
+ if not visited:
+ visited = set()
- config = self.items
- if path:
- config = self.get_children(path) or list()
+ for o in objects:
+ items.append(o)
+ visited.add(o)
+ for child in o.children:
+ items.extend(self.expand_block([child], visited))
- if match == 'line':
- for item in config:
- if item not in other.items:
- updates.append(item)
+ return items
- elif match == 'strict':
- if path:
- current = other.get_children(path) or list()
- else:
- current = other.items
+ def diff_line(self, other):
+ diff = list()
+ for item in self.items:
+ if item not in other.items:
+ diff.append(item)
+ return diff
+
+ def diff_strict(self, other):
+ diff = list()
+ for index, item in enumerate(self.items):
+ try:
+ if item != other.items[index]:
+ diff.append(item)
+ except IndexError:
+ diff.append(item)
+ return diff
+
+ def diff_exact(self, other):
+ diff = list()
+ if len(other.items) != len(self.items):
+ diff.extend(self.items)
+ else:
+ for ours, theirs in itertools.izip(self.items, other.items):
+ if ours != theirs:
+ diff.extend(self.items)
+ break
+ return diff
- for index, item in enumerate(config):
- try:
- if item != current[index]:
- updates.append(item)
- except IndexError:
- updates.append(item)
-
- elif match == 'exact':
- if path:
- current = other.get_children(path) or list()
- else:
- current = other.items
- if len(current) != len(config):
- updates.extend(config)
- else:
- for ours, theirs in itertools.izip(config, current):
- if ours != theirs:
- updates.extend(config)
- break
+ def difference(self, other, match='line', replace='line'):
+ try:
+ func = getattr(self, 'diff_%s' % match)
+ updates = func(other)
+ except AttributeError:
+ raise TypeError('invalid value for match keyword')
if self._device_os == 'junos':
return updates
- changes = list()
- for update in updates:
- if replace == 'block':
- if update.parents:
- changes.append(update.parents[-1])
- for child in update.parents[-1].children:
- changes.append(child)
+ if replace == 'block':
+ parents = list()
+ for u in updates:
+ if u.parents is None:
+ if u not in parents:
+ parents.append(u)
else:
- changes.append(update)
- else:
- changes.append(update)
- updates = self.expand(changes)
+ for p in u.parents:
+ if p not in parents:
+ parents.append(p)
+
+ return self.expand_block(parents)
- return [item.text for item in updates]
+ return self.expand_line(updates)
def replace(self, patterns, repl, parents=None, add_if_missing=False,
ignore_whitespace=True):