Skip to content
This repository has been archived by the owner on May 15, 2019. It is now read-only.

Add prefix and negate_prefix to container #67

Merged
merged 10 commits into from
Jul 3, 2017
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,19 @@ _process:
- mode: gate
when: "{{ protocol_key != 'static static' }}"
static:
_process: unnecessary
_process:
- mode: container
prefix: "ip route {{ static_key }}"
negate: "no ip route {{ static_key }}\n"
negate_prefix: "no ip route {{ static_key }}"
when: "{{ network_instance_key == 'global' }}"
in: "network-instances"
- mode: container
prefix: "ip route vrf {{ network_instance_key }} {{ static_key }}"
negate: "no ip route vrf {{ network_instance_key }} {{ static_key }}\n"
negate_prefix: "no ip route vrf {{ network_instance_key }} {{ static_key }}"
when: "{{ network_instance_key != 'global' }}"
in: "network-instances"
config:
_process: unnecessary
prefix:
Expand All @@ -15,29 +27,18 @@ static:
next-hop:
_process:
- mode: container
key_value: "ip route {{ static_key }} {{ next_hop_key }}\n"
negate: "no ip route {{ static_key }} {{ next_hop_key }}\n"
when: "{{ network_instance_key == 'global' }}"
in: "network-instances"
- mode: container
key_value: "ip route vrf {{ network_instance_key }} {{ static_key }} {{ next_hop_key }}\n"
negate: "no ip route vrf {{ network_instance_key }} {{ static_key }} {{ next_hop_key }}\n"
when: "{{ network_instance_key != 'global' }}"
in: "network-instances"
key_value: "{{ extra_vars.prefix }} {{ next_hop_key }}"
negate: "{{ extra_vars.negate_prefix }} {{ next_hop_key }}"
end: "\n"
config:
_process: unnecessary
index:
_process: not_implemented
metric:
_process:
- mode: element
value: "ip route {{ static_key }} {{ next_hop_key }} {{ model }}\n"
negate: "ip route {{ static_key }} {{ next_hop_key }} 1\n"
when: "{{ network_instance_key == 'global' }}"
- mode: element
value: "ip route vrf {{ network_instance_key }} {{ static_key }} {{ next_hop_key }} {{ model }}\n"
negate: "ip route vrf {{ network_instance_key }} {{ static_key }} {{ next_hop_key }} 1\n"
when: "{{ network_instance_key != 'global' }}"
value: " {{ model }}"
negate: " 1"
next-hop:
_process: unnecessary
recurse:
Expand Down
17 changes: 10 additions & 7 deletions napalm_yang/translator.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class Translator(object):

def __init__(self, model, profile,
translation=None, keys=None, bookmarks=None,
merge=None, replace=None, other=None):
merge=None, replace=None, other=None, extra_vars=None):
self.model = model
self.profile = profile
self._defining_module = model._defining_module
Expand All @@ -19,6 +19,7 @@ def __init__(self, model, profile,
self.translation = translation
self.keys = keys or {"parent_key": None}
self.bookmarks = bookmarks or {self._yang_name: translation, "parent": translation}
self.extra_vars = extra_vars or {}

self.merge = merge
self.replace = replace
Expand Down Expand Up @@ -62,15 +63,16 @@ def _translate_container(self, attribute, model, mapping, translation, other):
self.bookmarks["parent"] = translation

rule = helpers.resolve_rule(mapping["_process"], attribute, self.keys,
None, model, self.bookmarks)
self.extra_vars, model, self.bookmarks)

et = self.translator.translate_container(attribute, model, other, rule,
et, extra_vars = self.translator.translate_container(attribute, model, other, rule,
translation, self.bookmarks)

if et is None:
return

self.bookmarks[attribute] = et
self.extra_vars.update(extra_vars)
else:
et = translation

Expand All @@ -84,7 +86,7 @@ def _translate_container(self, attribute, model, mapping, translation, other):
if v._defining_module != self._defining_module and v._defining_module is not None:
logger.debug("Skipping attribute: {}:{}".format(v._defining_module, attribute))
translator = Translator(v, self.profile, et, self.keys,
self.bookmarks, self.merge, self.replace, other_attr)
self.bookmarks, self.merge, self.replace, other_attr, self.extra_vars)
translator.translate()
else:
self._translate(k, v, mapping[v._yang_name], et, other_attr)
Expand Down Expand Up @@ -112,11 +114,11 @@ def _translate_list(self, attribute, model, mapping, translation, other):
self.keys["parent_key"] = key

translation_rule = helpers.resolve_rule(mapping["_process"], attribute,
self.keys, None, element, self.bookmarks)
self.keys, self.extra_vars, element, self.bookmarks)

self.translator.default_element(translation_rule, translation, self.bookmarks,
replacing=True)
et = self.translator.init_element(attribute, element, other_element, translation_rule,
et, extra_vars = self.translator.init_element(attribute, element, other_element, translation_rule,
translation, self.bookmarks)

if et is None:
Expand All @@ -125,6 +127,7 @@ def _translate_list(self, attribute, model, mapping, translation, other):

self.bookmarks[attribute][key] = et
self.bookmarks["parent"] = et
self.extra_vars.update(extra_vars)

self._translate(attribute, element, mapping, et, other_element)

Expand All @@ -149,7 +152,7 @@ def _default_element_list(self, attribute, running, mapping, translation, candid
self.keys["parent_key"] = key

translation_rule = helpers.resolve_rule(mapping["_process"], attribute,
self.keys, None, element,
self.keys, self.extra_vars, element,
self.bookmarks)

self.translator.default_element(translation_rule, translation, self.bookmarks)
Expand Down
19 changes: 12 additions & 7 deletions napalm_yang/translators/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,23 @@ def __init__(self, merge, replace):

def init_element(self, attribute, model, other, mapping, translation, bookmarks):
et = translation
extra_vars = {}
for m in mapping:
if m["mode"] == "skip":
continue
elif m["mode"] == "gate":
return
return None, {}

t = _find_translation_point(m, bookmarks, et)
method_name = "_init_element_{}".format(m["mode"])
et = getattr(self, method_name)(attribute, model, other, m, t)
if isinstance(et, tuple):
extra_vars = et[1]
et = et[0]
if et is False:
# if it's False we want to return None to signal we want to abort
return None
return et
return None, {}
return et, extra_vars

def default_element(self, mapping, translation, bookmarks, replacing=False):
t = translation
Expand All @@ -57,16 +61,17 @@ def translate_leaf(self, attribute, model, other, mapping, translation, bookmark

def translate_container(self, attribute, model, other, mapping, translation, bookmarks):
et = translation
extra_vars = {}
for m in mapping:
if m["mode"] == "skip":
continue
elif m["mode"] == "gate":
return
return None, {}

t = _find_translation_point(m, bookmarks, et)
method_name = "_translate_container_{}".format(m["mode"])
et = getattr(self, method_name)(attribute, model, other, m, t)
et, extra_vars = getattr(self, method_name)(attribute, model, other, m, t)
if et is False:
# if it's False we want to return None to signal we want to abort
return None
return et
return None, {}
return et, extra_vars
14 changes: 10 additions & 4 deletions napalm_yang/translators/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,28 +33,34 @@ def _translate_leaf_element(self, attribute, model, other, mapping, translation)
super()._translate_leaf_element(attribute, model, other, mapping, translation, force)

def _init_element_container(self, attribute, model, other, mapping, translation):
extra_vars = {}

if other is not None:
if not napalm_yang.utils.diff(model, other) and not self.replace:
# If objects are equal we return None as that aborts translating
# the rest of the object
return False
return False, {}

if not model._changed() and other is not None and not self.replace:
mapping["key_value"] = mapping["negate"]
if not model._changed() and other is not None and self.replace:
return translation
return translation, {}

mapping["key_element"] = "command"
mapping["container"] = model._yang_name

for i in ('prefix', 'negate_prefix'):
if i in mapping:
extra_vars[i] = mapping.pop(i)

t = super()._init_element_container(attribute, model, other, mapping, translation)

end = mapping.get("end", "")
if end and t is not None:
e = etree.SubElement(translation, "command")
e.text = end

return t
return t, extra_vars

# def _translate_container_container(self, attribute, model, other, mapping, translation):
# mapping["key_element"] = "container"
Expand All @@ -76,7 +82,7 @@ def _default_element_container(self, mapping, translation, replacing):

def _xml_to_text(self, xml, text=""):
for element in xml:
if element.tag == "command":
if element.tag == "command" and element.text is not None:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a container without key_value you'll get an empty <command/> element in the XML document. In that case element.text is None and the next line crashes.

I'll see if I can avoid creating the element in such cases.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably cleaner to do:

if element.tag == "command":
    text += element.text  or ""

But it doesn't matter, both do the same.

text += element.text
text += self._xml_to_text(element)
return text