Skip to content

Commit 2fc2b82

Browse files
authored
YANG validation for ConfigDB Updates: MIRROR_SESSION use case (sonic-net#2430)
1 parent e16bdaa commit 2fc2b82

File tree

3 files changed

+129
-20
lines changed

3 files changed

+129
-20
lines changed

config/main.py

+46-20
Original file line numberDiff line numberDiff line change
@@ -2354,25 +2354,35 @@ def add_erspan(session_name, src_ip, dst_ip, dscp, ttl, gre_type, queue, policer
23542354
session_info['gre_type'] = gre_type
23552355

23562356
session_info = gather_session_info(session_info, policer, queue, src_port, direction)
2357+
ctx = click.get_current_context()
23572358

23582359
"""
23592360
For multi-npu platforms we need to program all front asic namespaces
23602361
"""
23612362
namespaces = multi_asic.get_all_namespaces()
23622363
if not namespaces['front_ns']:
2363-
config_db = ConfigDBConnector()
2364+
config_db = ValidatedConfigDBConnector(ConfigDBConnector())
23642365
config_db.connect()
2365-
if validate_mirror_session_config(config_db, session_name, None, src_port, direction) is False:
2366-
return
2367-
config_db.set_entry("MIRROR_SESSION", session_name, session_info)
2366+
if ADHOC_VALIDATION:
2367+
if validate_mirror_session_config(config_db, session_name, None, src_port, direction) is False:
2368+
return
2369+
try:
2370+
config_db.set_entry("MIRROR_SESSION", session_name, session_info)
2371+
except ValueError as e:
2372+
ctx.fail("Invalid ConfigDB. Error: {}".format(e))
2373+
23682374
else:
23692375
per_npu_configdb = {}
23702376
for front_asic_namespaces in namespaces['front_ns']:
2371-
per_npu_configdb[front_asic_namespaces] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces)
2377+
per_npu_configdb[front_asic_namespaces] = ValidatedConfigDBConnector(ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces))
23722378
per_npu_configdb[front_asic_namespaces].connect()
2373-
if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, None, src_port, direction) is False:
2374-
return
2375-
per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, session_info)
2379+
if ADHOC_VALIDATION:
2380+
if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, None, src_port, direction) is False:
2381+
return
2382+
try:
2383+
per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, session_info)
2384+
except ValueError as e:
2385+
ctx.fail("Invalid ConfigDB. Error: {}".format(e))
23762386

23772387
@mirror_session.group(cls=clicommon.AbbreviationGroup, name='span')
23782388
@click.pass_context
@@ -2404,25 +2414,34 @@ def add_span(session_name, dst_port, src_port, direction, queue, policer):
24042414
}
24052415

24062416
session_info = gather_session_info(session_info, policer, queue, src_port, direction)
2417+
ctx = click.get_current_context()
24072418

24082419
"""
24092420
For multi-npu platforms we need to program all front asic namespaces
24102421
"""
24112422
namespaces = multi_asic.get_all_namespaces()
24122423
if not namespaces['front_ns']:
2413-
config_db = ConfigDBConnector()
2424+
config_db = ValidatedConfigDBConnector(ConfigDBConnector())
24142425
config_db.connect()
2415-
if validate_mirror_session_config(config_db, session_name, dst_port, src_port, direction) is False:
2416-
return
2417-
config_db.set_entry("MIRROR_SESSION", session_name, session_info)
2426+
if ADHOC_VALIDATION:
2427+
if validate_mirror_session_config(config_db, session_name, dst_port, src_port, direction) is False:
2428+
return
2429+
try:
2430+
config_db.set_entry("MIRROR_SESSION", session_name, session_info)
2431+
except ValueError as e:
2432+
ctx.fail("Invalid ConfigDB. Error: {}".format(e))
24182433
else:
24192434
per_npu_configdb = {}
24202435
for front_asic_namespaces in namespaces['front_ns']:
2421-
per_npu_configdb[front_asic_namespaces] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces)
2436+
per_npu_configdb[front_asic_namespaces] = ValidatedConfigDBConnector(ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces))
24222437
per_npu_configdb[front_asic_namespaces].connect()
2423-
if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, dst_port, src_port, direction) is False:
2424-
return
2425-
per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, session_info)
2438+
if ADHOC_VALIDATION:
2439+
if validate_mirror_session_config(per_npu_configdb[front_asic_namespaces], session_name, dst_port, src_port, direction) is False:
2440+
return
2441+
try:
2442+
per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, session_info)
2443+
except ValueError as e:
2444+
ctx.fail("Invalid ConfigDB. Error: {}".format(e))
24262445

24272446

24282447
@mirror_session.command()
@@ -2434,16 +2453,23 @@ def remove(session_name):
24342453
For multi-npu platforms we need to program all front asic namespaces
24352454
"""
24362455
namespaces = multi_asic.get_all_namespaces()
2456+
ctx = click.get_current_context()
24372457
if not namespaces['front_ns']:
2438-
config_db = ConfigDBConnector()
2458+
config_db = ValidatedConfigDBConnector(ConfigDBConnector())
24392459
config_db.connect()
2440-
config_db.set_entry("MIRROR_SESSION", session_name, None)
2460+
try:
2461+
config_db.set_entry("MIRROR_SESSION", session_name, None)
2462+
except JsonPatchConflict as e:
2463+
ctx.fail("Invalid ConfigDB. Error: {}".format(e))
24412464
else:
24422465
per_npu_configdb = {}
24432466
for front_asic_namespaces in namespaces['front_ns']:
2444-
per_npu_configdb[front_asic_namespaces] = ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces)
2467+
per_npu_configdb[front_asic_namespaces] = ValidatedConfigDBConnector(ConfigDBConnector(use_unix_socket_path=True, namespace=front_asic_namespaces))
24452468
per_npu_configdb[front_asic_namespaces].connect()
2446-
per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, None)
2469+
try:
2470+
per_npu_configdb[front_asic_namespaces].set_entry("MIRROR_SESSION", session_name, None)
2471+
except JsonPatchConflict as e:
2472+
ctx.fail("Invalid ConfigDB. Error: {}".format(e))
24472473

24482474
#
24492475
# 'pfcwd' group ('config pfcwd ...')

tests/config_mirror_session_test.py

+82
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import pytest
22
import config.main as config
3+
import jsonpatch
34
from unittest import mock
45
from click.testing import CliRunner
6+
from mock import patch
7+
from jsonpatch import JsonPatchConflict
8+
from sonic_py_common import multi_asic
59

610
ERR_MSG_IP_FAILURE = "does not appear to be an IPv4 or IPv6 network"
711
ERR_MSG_IP_VERSION_FAILURE = "not a valid IPv4 address"
@@ -172,7 +176,34 @@ def test_mirror_session_erspan_add():
172176
mocked.assert_called_with("test_session", "100.1.1.1", "2.2.2.2", 8, 63, 0, 0, None, None, None)
173177

174178

179+
@patch("validated_config_db_connector.device_info.is_yang_config_validation_enabled", mock.Mock(return_value=True))
180+
@patch("config.validated_config_db_connector.ValidatedConfigDBConnector.validated_set_entry", mock.Mock(side_effect=ValueError))
181+
def test_mirror_session_erspan_add_invalid_yang_validation():
182+
config.ADHOC_VALIDATION = False
183+
runner = CliRunner()
184+
result = runner.invoke(
185+
config.config.commands["mirror_session"].commands["erspan"].commands["add"],
186+
["test_session", "100.1.1.1", "2.2.2.2", "8", "63", "10", "100"])
187+
print(result.output)
188+
assert "Invalid ConfigDB. Error" in result.output
189+
190+
191+
@patch("config.main.ConfigDBConnector", spec=True, connect=mock.Mock())
192+
@patch("config.main.multi_asic.get_all_namespaces", mock.Mock(return_value={'front_ns': 'sample_ns'}))
193+
@patch("validated_config_db_connector.device_info.is_yang_config_validation_enabled", mock.Mock(return_value=True))
194+
@patch("config.validated_config_db_connector.ValidatedConfigDBConnector.validated_set_entry", mock.Mock(side_effect=ValueError))
195+
def test_mirror_session_erspan_add_multi_asic_invalid_yang_validation(mock_db_connector):
196+
config.ADHOC_VALIDATION = False
197+
runner = CliRunner()
198+
result = runner.invoke(
199+
config.config.commands["mirror_session"].commands["erspan"].commands["add"],
200+
["test_session", "100.1.1.1", "2.2.2.2", "8", "63", "10", "100"])
201+
print(result.output)
202+
assert "Invalid ConfigDB. Error" in result.output
203+
204+
175205
def test_mirror_session_span_add():
206+
config.ADHOC_VALIDATION = True
176207
runner = CliRunner()
177208

178209
# Verify invalid queue
@@ -273,3 +304,54 @@ def test_mirror_session_span_add():
273304

274305
mocked.assert_called_with("test_session", "Ethernet0", "Ethernet4", "rx", 0, None)
275306

307+
308+
@patch("config.main.ConfigDBConnector", spec=True, connect=mock.Mock())
309+
@patch("config.main.multi_asic.get_all_namespaces", mock.Mock(return_value={'front_ns': 'sample_ns'}))
310+
@patch("validated_config_db_connector.device_info.is_yang_config_validation_enabled", mock.Mock(return_value=True))
311+
@patch("config.validated_config_db_connector.ValidatedConfigDBConnector.validated_set_entry", mock.Mock(side_effect=ValueError))
312+
def test_mirror_session_span_add_multi_asic_invalid_yang_validation(mock_db_connector):
313+
config.ADHOC_VALIDATION = False
314+
runner = CliRunner()
315+
result = runner.invoke(
316+
config.config.commands["mirror_session"].commands["span"].commands["add"],
317+
["test_session", "Ethernet0", "Ethernet4", "rx", "0"])
318+
print(result.output)
319+
assert "Invalid ConfigDB. Error" in result.output
320+
321+
322+
@patch("validated_config_db_connector.device_info.is_yang_config_validation_enabled", mock.Mock(return_value=True))
323+
@patch("config.validated_config_db_connector.ValidatedConfigDBConnector.validated_set_entry", mock.Mock(side_effect=ValueError))
324+
def test_mirror_session_span_add_invalid_yang_validation():
325+
config.ADHOC_VALIDATION = False
326+
runner = CliRunner()
327+
result = runner.invoke(
328+
config.config.commands["mirror_session"].commands["span"].commands["add"],
329+
["test_session", "Ethernet0", "Ethernet4", "rx", "0"])
330+
print(result.output)
331+
assert "Invalid ConfigDB. Error" in result.output
332+
333+
334+
@patch("config.main.multi_asic.get_all_namespaces", mock.Mock(return_value={'front_ns': 'sample_ns'}))
335+
@patch("validated_config_db_connector.device_info.is_yang_config_validation_enabled", mock.Mock(return_value=True))
336+
@patch("config.main.ConfigDBConnector", spec=True, connect=mock.Mock())
337+
@patch("config.validated_config_db_connector.ValidatedConfigDBConnector.validated_set_entry", mock.Mock(side_effect=JsonPatchConflict))
338+
def test_mirror_session_remove_multi_asic_invalid_yang_validation(mock_db_connector):
339+
config.ADHOC_VALIDATION = False
340+
runner = CliRunner()
341+
result = runner.invoke(
342+
config.config.commands["mirror_session"].commands["remove"],
343+
["mrr_sample"])
344+
print(result.output)
345+
assert "Invalid ConfigDB. Error" in result.output
346+
347+
348+
@patch("validated_config_db_connector.device_info.is_yang_config_validation_enabled", mock.Mock(return_value=True))
349+
@patch("config.validated_config_db_connector.ValidatedConfigDBConnector.validated_set_entry", mock.Mock(side_effect=JsonPatchConflict))
350+
def test_mirror_session_remove_invalid_yang_validation():
351+
config.ADHOC_VALIDATION = False
352+
runner = CliRunner()
353+
result = runner.invoke(
354+
config.config.commands["mirror_session"].commands["remove"],
355+
["mrr_sample"])
356+
print(result.output)
357+
assert "Invalid ConfigDB. Error" in result.output

tests/config_snmp_test.py

+1
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ def setup_class(cls):
118118

119119
# Add snmp community tests
120120
def test_config_snmp_community_add_new_community_ro(self):
121+
config.ADHOC_VALIDATION = True
121122
db = Db()
122123
runner = CliRunner()
123124
with mock.patch('utilities_common.cli.run_command') as mock_run_command:

0 commit comments

Comments
 (0)