From 0a6baf78d2fb57b7ed1512d22a9ca94366ea7238 Mon Sep 17 00:00:00 2001 From: malletvapid23 Date: Thu, 11 Aug 2022 09:19:44 +0300 Subject: [PATCH] Convert IPv6 addresses to lowercase in apply-patch (#2299) Fixes sonic-net/sonic-buildimage#11622 - What I did Convert IPv6 addresses to lowercase in apply-patch for remove op - How I did it python regex on 'remove' op in JSON patch input file - How to verify it Manual test of created bug, Unit test --- config/main.py | 14 ++++++++++++++ tests/ip_config_input/patch_ipv6.test | 6 ++++++ tests/ip_config_test.py | 21 +++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 tests/ip_config_input/patch_ipv6.test diff --git a/config/main.py b/config/main.py index cba02ad..5c74ec9 100644 --- a/config/main.py +++ b/config/main.py @@ -1362,6 +1362,20 @@ def apply_patch(ctx, patch_file_path, format, dry_run, ignore_non_yang_tables, i patch_as_json = json.loads(text) patch = jsonpatch.JsonPatch(patch_as_json) + # convert IPv6 addresses to lowercase + for patch_line in patch: + if 'remove' == patch_line['op']: + match = re.search(r"(?P/INTERFACE/\w+\|)(?P([a-fA-F0-9]{0,4}[:~]|::){1,7}[a-fA-F0-9]{0,4})" + "(?P.*)", str.format(patch_line['path'])) + if match: + prefix = match.group('prefix') + ipv6_address_str = match.group('ipv6_address') + suffix = match.group('suffix') + ipv6_address_str = ipv6_address_str.lower() + click.secho("converted ipv6 address to lowercase {} with prefix {} in value: {}" + .format(ipv6_address_str, prefix, patch_line['path'])) + patch_line['path'] = prefix + ipv6_address_str + suffix + config_format = ConfigFormat[format.upper()] GenericUpdater().apply_patch(patch, config_format, verbose, dry_run, ignore_non_yang_tables, ignore_path) diff --git a/tests/ip_config_input/patch_ipv6.test b/tests/ip_config_input/patch_ipv6.test new file mode 100644 index 0000000..00b43fd --- /dev/null +++ b/tests/ip_config_input/patch_ipv6.test @@ -0,0 +1,6 @@ +[ + { + "path": "/INTERFACE/Ethernet12|FC00::1~1126", + "op": "remove" + } +] diff --git a/tests/ip_config_test.py b/tests/ip_config_test.py index 47f82fb..85a765b 100644 --- a/tests/ip_config_test.py +++ b/tests/ip_config_test.py @@ -1,3 +1,5 @@ +import json +import jsonpatch import os import traceback from unittest import mock @@ -8,6 +10,9 @@ import show.main as show from utilities_common.db import Db +test_path = os.path.dirname(os.path.abspath(__file__)) +ip_config_input_path = os.path.join(test_path, "ip_config_input") + ERROR_MSG = "Error: IP address is not valid" class TestConfigIP(object): @@ -157,6 +162,22 @@ def test_add_del_interface_shortened_ipv6_with_leading_zeros(self): assert result.exit_code != 0 assert ('Ethernet68', '3000::1/64') not in db.cfgdb.get_table('INTERFACE') + def test_remove_interface_case_sensitive_mock_ipv6_w_apply_patch(self): + runner = CliRunner() + any_patch_as_json = [{"op": "remove", "path": "/INTERFACE/Ethernet12|FC00::1~1126"}] + any_patch = jsonpatch.JsonPatch(any_patch_as_json) + any_patch_as_text = json.dumps(any_patch_as_json) + ipv6_patch_file = os.path.join(ip_config_input_path, 'patch_ipv6.test') + + # config apply-patch patch + mock_generic_updater = mock.Mock() + with mock.patch('config.main.GenericUpdater', return_value=mock_generic_updater): + with mock.patch('builtins.open', mock.mock_open(read_data=any_patch_as_text)): + result = runner.invoke(config.config.commands["apply-patch"], [ipv6_patch_file], catch_exceptions=False) + print(result.exit_code, result.output) + assert "converted ipv6 address to lowercase fc00::1~1126 with prefix /INTERFACE/Ethernet12| in value: /INTERFACE/Ethernet12|FC00::1~1126" in result.output + + @classmethod def teardown_class(cls): os.environ['UTILITIES_UNIT_TESTING'] = "0"