fixes add() method in netcfg (#20041)

The add() method was not properly setting childen and parents objects
on instances of ConfigLine.  This only applied to the add method.  This
change fixes the problem by adding child and parent to the right
attribute.
This commit is contained in:
Peter Sprygada 2017-01-09 10:01:13 -05:00 committed by GitHub
parent 28050c1356
commit 5bbab91452

View file

@ -75,6 +75,14 @@ class ConfigLine(object):
config.append(self.raw)
return '\n'.join(config)
@property
def has_chilren(self):
return len(self._children) > 0
@property
def has_parents(self):
return len(self._parents) > 0
def add_child(self, obj):
assert isinstance(obj, ConfigLine), 'child must be of type `ConfigLine`'
self._children.append(obj)
@ -87,13 +95,36 @@ def ignore_line(text, tokens=None):
_obj_to_text = lambda x: [o.text for o in x]
_obj_to_raw = lambda x: [o.raw for o in x]
def dumps(objects, output='block'):
def _obj_to_block(objects, visited=None):
items = list()
for o in objects:
if o not in items:
items.append(o)
for child in o._children:
if child not in items:
items.append(child)
return _obj_to_raw(items)
def dumps(objects, output='block', comments=False):
if output == 'block':
item = _obj_to_raw(objects)
items = _obj_to_block(objects)
#elif output == 'block':
# items = _obj_to_raw(objects)
elif output == 'commands':
items = _obj_to_text(objects)
else:
raise TypeError('unknown value supplied for keyword output')
if output != 'commands':
if comments:
for index, item in enumerate(items):
nextitem = index + 1
if nextitem < len(items) and not item.startswith(' ') and items[nextitem].startswith(' '):
item = '!\n%s' % item
items[index] = item
items.append('!')
items.append('end')
return '\n'.join(items)
class NetworkConfig(object):
@ -186,21 +217,21 @@ class NetworkConfig(object):
if item.parents == path[:-1]:
return item
def get_section(self, path):
def get_block(self, path):
assert isinstance(path, list), 'path argument must be a list object'
obj = self.get_object(path)
if not obj:
raise ValueError('path does not exist in config')
return self._expand_section(obj)
return self._expand_block(obj)
def _expand_section(self, configobj, S=None):
def _expand_block(self, configobj, S=None):
if S is None:
S = list()
S.append(configobj)
for child in configobj._children:
if child in S:
continue
self._expand_section(child, S)
self._expand_block(child, S)
return S
def _diff_line(self, other):
@ -212,9 +243,9 @@ class NetworkConfig(object):
def _diff_strict(self, other):
updates = list()
for index, line in enumerate(self._items):
for index, line in enumerate(self.items):
try:
if line != other._lines[index]:
if line != other[index]:
updates.append(line)
except IndexError:
updates.append(line)
@ -222,22 +253,52 @@ class NetworkConfig(object):
def _diff_exact(self, other):
updates = list()
if len(other) != len(self._items):
updates.extend(self._items)
if len(other) != len(self.items):
updates.extend(self.items)
else:
for ours, theirs in zip(self._items, other):
for ours, theirs in zip(self.items, other):
if ours != theirs:
updates.extend(self._items)
updates.extend(self.items)
break
return updates
def difference(self, other, match='line', path=None, replace=None):
try:
meth = getattr(self, '_diff_%s' % match)
updates = meth(other)
except AttributeError:
raise TypeError('invalid value for match keyword argument, '
'valid values are line, strict, or exact')
"""Perform a config diff against the another network config
:param other: instance of NetworkConfig to diff against
:param match: type of diff to perform. valid values are 'line',
'strict', 'exact'
:param path: context in the network config to filter the diff
:param replace: the method used to generate the replacement lines.
valid values are 'block', 'line'
:returns: a string of lines that are different
"""
if path and match != 'line':
try:
other = other.get_block(path)
except ValueError:
other = list()
else:
other = other.items
# generate a list of ConfigLines that aren't in other
meth = getattr(self, '_diff_%s' % match)
updates = meth(other)
if replace == 'block':
parents = list()
for item in updates:
if not item.has_parents:
parents.append(item)
else:
for p in item._parents:
if p not in parents:
parents.append(p)
updates = list()
for item in parents:
updates.extend(self._expand_block(item))
visited = set()
expanded = list()
@ -269,7 +330,7 @@ class NetworkConfig(object):
for index, p in enumerate(parents):
try:
i = index + 1
obj = self.get_section(parents[:i])[0]
obj = self.get_block(parents[:i])[0]
ancestors.append(obj)
except ValueError:
@ -278,15 +339,15 @@ class NetworkConfig(object):
obj = ConfigLine(p)
obj.raw = p.rjust(len(p) + offset)
if ancestors:
obj.parents = list(ancestors)
ancestors[-1].children.append(obj)
obj._parents = list(ancestors)
ancestors[-1]._children.append(obj)
self.items.append(obj)
ancestors.append(obj)
# add child objects
for line in lines:
# check if child already exists
for child in ancestors[-1].children:
for child in ancestors[-1]._children:
if child.text == line:
break
else:
@ -294,5 +355,7 @@ class NetworkConfig(object):
item = ConfigLine(line)
item.raw = line.rjust(len(line) + offset)
item._parents = ancestors
ancestors[-1].children.append(item)
ancestors[-1]._children.append(item)
self.items.append(item)