Skip to content

Commit

Permalink
added copy match variable function and tests for issue 94
Browse files Browse the repository at this point in the history
  • Loading branch information
dmulyalin committed Dec 3, 2022
1 parent 9d0f1f3 commit 7d10950
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 18 deletions.
41 changes: 41 additions & 0 deletions docs/source/Match Variables/Functions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Action functions act upon match result to transform into desired state.
- append provided string to the end of match result
* - `chain`_
- add functions from chain variable
* - `copy`_
- copy match value into another variable
* - `count`_
- function to count matches
* - `default`_
Expand Down Expand Up @@ -2699,3 +2701,42 @@ Results::
}
]
]

copy
------------------------------------------------------------------------------
``{{ name | copy(variable_name) }}``

``variable_name`` - name of variable to copy match value into

THis function is useful to store processing match variable value into a
variable before or during processing.

**Example-1**

In this example we would like to store IP address into a variable but we also
want to extract last octet value.

Data::

interface Port-Channel11
ip address 1.1.1.123 255.255.255.255
!
interface Port-Channel22
ip address 1.1.1.124 255.255.255.255
!

Template::

interface {{ name }}
ip address {{ ip_last_octet | copy("ip_address") | split(".") | item(-1) }} {{ mask }}
Result::

[[[{'ip_address': '1.1.1.123',
'ip_last_octet': '123',
'mask': '255.255.255.255',
'name': 'Port-Channel11'},
{'ip_address': '1.1.1.124',
'ip_last_octet': '124',
'mask': '255.255.255.255',
'name': 'Port-Channel22'}]]]
82 changes: 79 additions & 3 deletions test/pytest/test_answers_and_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1743,7 +1743,7 @@ def qinq(data):
parser = ttp(data=data, template=template, log_level="ERROR")
parser.parse()
res = parser.result()
# pprint.pprint(res)
pprint.pprint(res)
assert res == [
[
{
Expand Down Expand Up @@ -2308,7 +2308,7 @@ def test_github_issue_37_cleaned_data_template():
parser = ttp(data=data, template=template, log_level="ERROR")
parser.parse()
res = parser.result()
# pprint.pprint(res)
pprint.pprint(res)
assert res == [
[
{
Expand Down Expand Up @@ -7362,4 +7362,80 @@ def test_issue_94_1():
'prefix_metric': 'true',
'priority': 'MISSING'}}}}}]]

# test_issue_94_1()
# test_issue_94_1()


def test_issue_89():
template = """
<input load="text">
interface Bundle-Ether801.101
description TTP MACRO TEST INTERFACE
mtu 9104
ipv4 address 192.168.1.1 255.255.255.0
ipv4 address 10.50.45.1 255.255.255.128 secondary
load-interval 30
encapsulation dot1q 101
!
</input>
<macro>
def is_trunk(data):
if "dot1q" in data:
data['trunk'] = True
else:
data['trunk'] = False
return data
</macro>
<group name="interfaces.{{ interface }}" macro="is_trunk">
interface {{ interface }}
description {{ description |ORPHRASE }}
mtu {{ mtu }}
vrf {{ vrf |default(None) }}
service-policy input {{ sp_ingress |default(None) }}
service-policy output {{ sp_egress |default(None) }}
ipv4 address {{ ipv4_addr |default(None) }} {{ ipv4_mask |default(None) }}
<group name="secondary">
ipv4 address {{ ipv4_addr |default(None) }} {{ ipv4_mask |default(None) }} secondary
</group>
ipv6 address {{ ipv6_addr |default(None) }}/{{ ipv6_mask |default(None) }}
encapsulation dot1q {{ dot1q }}
ipv4 access-group {{ ingress_acl_v4 |_exact_ |default(None) }} ingress
ipv4 access-group {{ egress_acl_v4 |_exact_ |default(None) }} egress
bundle id {{ lag_id }} mode {{ mode }}
ipv6 access-group {{ ingress_acl_v6 |_exact_ |default(None) }} ingress
ipv6 access-group {{ egress_acl_v6 |_exact_ |default(None) }} egress
shutdown {{ disabled |set(True) }}
! {{ _end_ }}
</group>
"""
parser = ttp(
template=template,
log_level="ERROR",
log_file="macro_test_1.log",
)
parser.parse()
res = parser.result()

pprint.pprint(res)
assert res == [[{'interfaces': {'Bundle-Ether801.101': {'description': 'TTP MACRO TEST INTERFACE',
'dot1q': '101',
'egress_acl_v4': None,
'egress_acl_v6': None,
'ingress_acl_v4': None,
'ingress_acl_v6': None,
'ipv4_addr': '192.168.1.1',
'ipv4_mask': '255.255.255.0',
'ipv6_addr': None,
'ipv6_mask': None,
'mtu': '9104',
'secondary': {'ipv4_addr': '10.50.45.1',
'ipv4_mask': '255.255.255.128'},
'sp_egress': None,
'sp_ingress': None,
'trunk': True,
'vrf': None}}}]]

# test_issue_89()
2 changes: 1 addition & 1 deletion test/pytest/test_group_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,7 @@ def test_expand_issue_65():
parser = ttp(template=template)
parser.parse()
res = parser.result()
# pprint.pprint(res)
pprint.pprint(res)
assert res == [[{'interfaces': {'interface': [{'config': {'description': 'to core-1',
'mtu': 9100},
'name': 'GigabitEthernet1/1',
Expand Down
27 changes: 27 additions & 0 deletions test/pytest/test_match_functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,3 +543,30 @@ def test_raise():


# test_raise()


def test_copy():
data = """
interface Port-Channel11
ip address 1.1.1.123 255.255.255.255
interface Port-Channel22
ip address 1.1.1.124 255.255.255.255
"""
template = """
interface {{ name }}
ip address {{ ip_last_octet | copy("ip_address") | split(".") | item(-1) }} {{ mask }}
"""
parser = ttp(data=data, template=template)
parser.parse()
res = parser.result()
pprint.pprint(res, width=100)
assert res == [[[{'ip_address': '1.1.1.123',
'ip_last_octet': '123',
'mask': '255.255.255.255',
'name': 'Port-Channel11'},
{'ip_address': '1.1.1.124',
'ip_last_octet': '124',
'mask': '255.255.255.255',
'name': 'Port-Channel22'}]]]

# test_copy()
7 changes: 7 additions & 0 deletions ttp/match/copy_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from copy import deepcopy

_name_map_ = {"copy_func": "copy"}


def copy_func(data, name):
return data, {"new_field": {name: deepcopy(data)}}
12 changes: 6 additions & 6 deletions ttp/match/string.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,19 +92,19 @@ def sprint(data):


def replaceall(data, *args):
vars = _ttp_["vars"]
vars_ = _ttp_["vars"]
args = list(args)
new = ""
if len(args) > 1:
new = args.pop(0)
for oldValue in args:
if oldValue in vars:
if isinstance(vars[oldValue], list):
for oldVal in vars[oldValue]:
if oldValue in vars_:
if isinstance(vars_[oldValue], list):
for oldVal in vars_[oldValue]:
if isinstance(oldVal, str):
data = data.replace(oldVal, new)
elif isinstance(vars[oldValue], dict):
for newVal, oldVal in vars[oldValue].items():
elif isinstance(vars_[oldValue], dict):
for newVal, oldVal in vars_[oldValue].items():
if isinstance(oldVal, list):
for i in oldVal:
if isinstance(i, str):
Expand Down
15 changes: 7 additions & 8 deletions ttp/ttp.py
Original file line number Diff line number Diff line change
Expand Up @@ -809,7 +809,7 @@ def get_template(self):
mainly to assist with troubleshooting ``extend`` tags processing.
"""
return "\n".join(t.template for t in self._templates)


"""
==============================================================================
Expand Down Expand Up @@ -2328,7 +2328,7 @@ def regex_headers(data):
def debug(self):
from pprint import pformat

text = r"Variable object {}, Variable name '{}' content:\n{}".format(
text = "Variable object {}, Variable name '{}' content:\n{}".format(
self, self.var_name, pformat(vars(self), indent=4)
)
log.debug(text)
Expand Down Expand Up @@ -3040,11 +3040,11 @@ def start(self, result, PATH, DEFAULTS=None, FUNCTIONS=None, REDICT=""):
if REDICT["GROUP"].parent_group_id == self.started_groups[-1]:
self.started_groups.append(REDICT["GROUP"].group_id)
break
# check if _line_ group started, don't remove previous started
# check if _line_ group started, don't remove previous started
# groups to allow collection of non matched lines - #94
if REDICT.get("IS_LINE"):
self.started_groups.append(REDICT["GROUP"].group_id)
break
break
_ = self.started_groups.pop()
# meaning top group started
else:
Expand Down Expand Up @@ -3073,11 +3073,11 @@ def startempty(self, result, PATH, DEFAULTS=None, FUNCTIONS=None, REDICT=""):
if REDICT["GROUP"].parent_group_id == self.started_groups[-1]:
self.started_groups.append(REDICT["GROUP"].group_id)
break
# check if _line_ group started, don't remove previous started
# check if _line_ group started, don't remove previous started
# groups to allow collection of non matched lines - #94
if REDICT.get("IS_LINE"):
self.started_groups.append(REDICT["GROUP"].group_id)
break
break
_ = self.started_groups.pop()
# meaning top group started
else:
Expand Down Expand Up @@ -3118,7 +3118,7 @@ def add(self, result, PATH, DEFAULTS=None, FUNCTIONS=None, REDICT=""):
)
# mark new record as needed to be merged with last item in results
self.record["merge_with_last"] = True
# no need to add DEFAULTS for this record as DEFAULTS processed already by previous group record
# no need to add DEFAULTS for this record, DEFAULTS added by previous group
self.record["DEFAULTS"] = {}

def join(self, result, PATH, DEFAULTS=None, FUNCTIONS=None, REDICT=""):
Expand Down Expand Up @@ -3208,7 +3208,6 @@ def processgrp(self):
# add default values to group results
for k, v in self.record["DEFAULTS"].items():
self.record["result"].setdefault(k, v)
# import pprint; pprint.pprint(self.record)
# process group functions
for item in self.record["FUNCTIONS"]:
func_name = item["name"]
Expand Down

0 comments on commit 7d10950

Please sign in to comment.