Skip to content

Commit 2ce2b78

Browse files
authored
Refix: Validate acl.json after parsing, add unit test (sonic-net#322)
* Refix: Validate acl.json after parsing, add unit test * Include test input files in package
1 parent ac43b20 commit 2ce2b78

9 files changed

Lines changed: 357 additions & 5 deletions

File tree

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,12 @@
44

55
Command-line utilities for SONiC
66

7+
## How to run unit test
8+
```python
9+
python2 -m py.test -v
10+
```
711

8-
# Contribution guide
12+
## Contribution guide
913

1014
All contributors must sign a contribution license agreement (CLA) before contributions can be accepted. This process is now automated via a GitHub bot when submitting new pull request. If the contributor has not yet signed a CLA, the bot will create a comment on the pull request containing a link to electronically sign the CLA.
1115

acl_loader/main.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,16 +193,25 @@ def is_table_control_plane(self, tname):
193193
"""
194194
return self.tables_db_info[tname]['type'].upper() == self.ACL_TABLE_TYPE_CTRLPLANE
195195

196+
@staticmethod
197+
def parse_acl_json(filename):
198+
yang_acl = pybindJSON.load(filename, openconfig_acl, "openconfig_acl")
199+
# Check pybindJSON parsing
200+
# pybindJSON.load will silently return an empty json object if input invalid
201+
with open(filename, 'r') as f:
202+
plain_json = json.load(f)
203+
if len(plain_json['acl']['acl-sets']['acl-set']) != len(yang_acl.acl.acl_sets.acl_set):
204+
raise AclLoaderException("Invalid input file %s" % filename)
205+
return yang_acl
206+
196207
def load_rules_from_file(self, filename):
197208
"""
198209
Load file with ACL rules configuration in openconfig ACL format. Convert rules
199210
to Config DB schema.
200211
:param filename: File in openconfig ACL format
201212
:return:
202213
"""
203-
self.yang_acl = pybindJSON.load(filename, openconfig_acl, "openconfig_acl")
204-
if pybindJSON.dumps(self.yang_acl) == '{}':
205-
raise AclLoaderException("Invalid input file %s" % filename)
214+
self.yang_acl = AclLoader.parse_acl_json(filename)
206215
self.convert_rules()
207216

208217
def convert_action(self, table_name, rule_idx, rule):

pytest.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[pytest]
2+
filterwarnings =
3+
ignore::DeprecationWarning

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ def get_test_suite():
3636
'undebug',
3737
],
3838
package_data={
39-
'show': ['aliases.ini']
39+
'show': ['aliases.ini'],
40+
'sonic-utilities-tests': ['acl_input/*'],
4041
},
4142
scripts=[
4243
'scripts/aclshow',
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
{
2+
"acl": {
3+
"acl-sets": {
4+
"acl-set": {
5+
"sonic-ssh-only": {
6+
"acl-entries": {
7+
"acl-entry": {
8+
"1": {
9+
"config": {
10+
"sequence-id": 1
11+
},
12+
"actions": {
13+
"config": {
14+
"forwarding-action": "ACCEPT"
15+
}
16+
},
17+
"ip": {
18+
"config": {
19+
"protocol": "IP_TCP",
20+
"source-ip-address": "192.168.0.0/18"
21+
}
22+
},
23+
"transport": {
24+
"config": {
25+
"destination-port": "22"
26+
}
27+
}
28+
},
29+
"2": {
30+
"config": {
31+
"sequence-id": 2
32+
},
33+
"actions": {
34+
"config": {
35+
"forwarding-action": "ACCEPT"
36+
}
37+
},
38+
"ip": {
39+
"config": {
40+
"protocol": "IP_TCP",
41+
"source-ip-address": "192.168.192.0/18"
42+
}
43+
},
44+
"transport": {
45+
"config": {
46+
"destination-port": "22"
47+
}
48+
}
49+
}
50+
}
51+
},
52+
"config": {
53+
"name": "sonic-ssh-only"
54+
}
55+
},
56+
"Sonic-SNMP_ACL": {
57+
"acl-entries": {
58+
"acl-entry": {
59+
"1": {
60+
"config": {
61+
"sequence-id": 1
62+
},
63+
"actions": {
64+
"config": {
65+
"forwarding-action": "ACCEPT"
66+
}
67+
},
68+
"ip": {
69+
"config": {
70+
"protocol": "IP_UDP",
71+
"source-ip-address": "192.168.0.0/18"
72+
}
73+
}
74+
}
75+
}
76+
},
77+
"config": {
78+
"name": "Sonic-SNMP_ACL"
79+
}
80+
},
81+
"sonic-everflow": {
82+
"acl-entries": {
83+
"acl-entry": {
84+
"1": {
85+
"config": {
86+
"sequence-id": 1
87+
},
88+
"actions": {
89+
"config": {
90+
"forwarding-action": "ACCEPT"
91+
}
92+
},
93+
"ip": {
94+
"config": {
95+
"protocol": "IP_TCP",
96+
"source-ip-address": "127.0.0.1/32",
97+
"destination-ip-address": "127.0.0.1/32"
98+
}
99+
},
100+
"transport": {
101+
"config": {
102+
"source-port": "0",
103+
"destination-port": "0"
104+
}
105+
}
106+
}
107+
}
108+
},
109+
"config": {
110+
"name": "sonic-everflow"
111+
}
112+
},
113+
"everflowV6": {
114+
"acl-entries": {
115+
"acl-entry": {
116+
"1": {
117+
"config": {
118+
"sequence-id": 1
119+
},
120+
"actions": {
121+
"config": {
122+
"forwarding-action": "ACCEPT"
123+
}
124+
},
125+
"ip": {
126+
"config": {
127+
"protocol": "IP_TCP",
128+
"source-ip-address": "::1/128",
129+
"destination-ip-address": "::1/128"
130+
}
131+
},
132+
"transport": {
133+
"config": {
134+
"source-port": "0",
135+
"destination-port": "0"
136+
}
137+
}
138+
}
139+
}
140+
},
141+
"config": {
142+
"name": "everflowV6"
143+
}
144+
}
145+
}
146+
}
147+
}
148+
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
{
2+
"acl": {
3+
"acl-sets": {
4+
"acl-set": {
5+
"sonic-ssh-only": {
6+
"acl-entries": {
7+
"acl-entry": {
8+
"1": {
9+
"config": {
10+
"sequence-id": 1
11+
},
12+
"actions": {
13+
"config": {
14+
"forwarding-action": "ACCEPT"
15+
}
16+
},
17+
"ip": {
18+
"config": {
19+
"protocol": "IP_TCP",
20+
"source-ip-address": "192.168.0.0/18"
21+
}
22+
},
23+
"transport": {
24+
"config": {
25+
"destination-port": "22"
26+
}
27+
}
28+
},
29+
"2": {
30+
"config": {
31+
"sequence-id": 2
32+
},
33+
"actions": {
34+
"config": {
35+
"forwarding-action": "ACCEPT"
36+
}
37+
},
38+
"ip": {
39+
"config": {
40+
"protocol": "IP_TCP",
41+
"source-ip-address": "192.168.192.0/18"
42+
}
43+
},
44+
"transport": {
45+
"config": {
46+
"destination-port": "22"
47+
}
48+
}
49+
}
50+
}
51+
},
52+
"config": {
53+
"name": "sonic-ssh-only"
54+
}
55+
},
56+
"Sonic-SNMP_ACL": {
57+
"acl-entries": {
58+
"acl-entry": {
59+
"1": {
60+
"config": {
61+
"sequence-id": 1
62+
},
63+
"actions": {
64+
"config": {
65+
"forwarding-action": "ACCEPT"
66+
}
67+
},
68+
"ip": {
69+
"config": {
70+
"protocol": "IP_UDP",
71+
"source-ip-address": "192.168.0.0/18"
72+
}
73+
}
74+
}
75+
}
76+
},
77+
"config": {
78+
"name": "Sonic-SNMP_ACL"
79+
}
80+
},
81+
"sonic-everflow": {
82+
"acl-entries": {
83+
"acl-entry": {
84+
"1": {
85+
"config": {
86+
"sequence-id": 1
87+
},
88+
"actions": {
89+
"config": {
90+
"forwarding-action": "ACCEPT"
91+
}
92+
},
93+
"ip": {
94+
"config": {
95+
"protocol": "IP_TCP",
96+
"source-ip-address": "127.0.0.1/32",
97+
"destination-ip-address": "127.0.0.1/32"
98+
}
99+
},
100+
"transport": {
101+
"config": {
102+
"source-port": "0",
103+
"destination-port": "0"
104+
}
105+
}
106+
}
107+
}
108+
},
109+
"config": {
110+
"name": "sonic-everflow"
111+
}
112+
},
113+
"everflowV6": {
114+
"acl-entries": {
115+
"acl-entry": {
116+
"1": {
117+
"config": {
118+
"sequence-id": 1
119+
},
120+
"actions": {
121+
"config": {
122+
"forwarding-action": "ACCEPT"
123+
}
124+
},
125+
"ip": {
126+
"config": {
127+
"protocol": "IP_TCP",
128+
"source-ip-address": "::1/128",
129+
"destination-ip-address": "::1/128"
130+
}
131+
},
132+
"transport": {
133+
"config": {
134+
"source-port": "0",
135+
"destination-port": "0"
136+
}
137+
}
138+
}
139+
}
140+
},
141+
"config": {
142+
"name": "everflowV6"
143+
}
144+
},
145+
"TimeStampHeader": "Configuration last updated on: [9/13/2018 11:00:16 AM]"
146+
}
147+
}
148+
}
149+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"acl": {
3+
"acl-sets": {
4+
"acl-set": {}
5+
}
6+
}
7+
}
8+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import sys
2+
import os
3+
import pytest
4+
from unittest import TestCase
5+
6+
test_path = os.path.dirname(os.path.abspath(__file__))
7+
modules_path = os.path.dirname(test_path)
8+
sys.path.insert(0, modules_path)
9+
10+
from acl_loader import *
11+
from acl_loader.main import *
12+
13+
class TestAclLoader(TestCase):
14+
def setUp(self):
15+
pass
16+
17+
def test_acl_empty(self):
18+
yang_acl = AclLoader.parse_acl_json(os.path.join(test_path, 'acl_input/empty_acl.json'))
19+
assert len(yang_acl.acl.acl_sets.acl_set) == 0
20+
21+
def test_valid(self):
22+
yang_acl = AclLoader.parse_acl_json(os.path.join(test_path, 'acl_input/acl1.json'))
23+
assert len(yang_acl.acl.acl_sets.acl_set) == 4
24+
25+
def test_invalid(self):
26+
with pytest.raises(AclLoaderException):
27+
yang_acl = AclLoader.parse_acl_json(os.path.join(test_path, 'acl_input/acl2.json'))

sonic-utilities-tests/pytest.ini

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[pytest]
2+
filterwarnings =
3+
ignore::DeprecationWarning

0 commit comments

Comments
 (0)