From 5bd2e908b64eda036ce98a4980efad7fd2496eed Mon Sep 17 00:00:00 2001 From: ganglyu Date: Fri, 7 Jan 2022 10:34:50 +0800 Subject: [PATCH 1/9] [sonic-cfggen]: Update UT to run yang validation Signed-off-by: Gang Lv ganglv@microsoft.com --- src/sonic-config-engine/tests/test_cfggen.py | 31 ++++++++++++++++++ .../tests/test_minigraph_case.py | 31 ++++++++++++++++++ .../tests/test_multinpu_cfggen.py | 32 ++++++++++++++++++- 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index cbef4bbe8e5f..c60c29514799 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -1,11 +1,14 @@ import json import subprocess import os +import re +import sonic_yang import tests.common_utils as utils from unittest import TestCase +YANG_MODELS_DIR = "/usr/local/yang-models" TOR_ROUTER = 'ToRRouter' BACKEND_TOR_ROUTER = 'BackEndToRRouter' LEAF_ROUTER = 'LeafRouter' @@ -14,6 +17,8 @@ class TestCfgGen(TestCase): def setUp(self): + self.yang_parser = sonic_yang.SonicYang(YANG_MODELS_DIR) + self.yang_parser.loadYangModel() self.test_dir = os.path.dirname(os.path.realpath(__file__)) self.script_file = utils.PYTHON_INTERPRETTER + ' ' + os.path.join(self.test_dir, '..', 'sonic-cfggen') self.sample_graph = os.path.join(self.test_dir, 'sample_graph.xml') @@ -49,6 +54,32 @@ def tearDown(self): def run_script(self, argument, check_stderr=False, verbose=False): print('\n Running sonic-cfggen ' + argument) + if "-m" in argument: + pattern = r'-m\s+(\S+)\s*' + minigraph = re.findall(r'-m\s+(\S+)\s*', argument) + hwsku = re.findall(r'-S\s+(\S+)\s*', argument) + port_conf = re.findall(r'-p\s+(\S+)\s*', argument) + namespace = re.findall(r'-n\s+(\S+)\s*', argument) + if minigraph: + print('\n Validating yang schema') + cmd = self.script_file + ' -m ' + minigraph[0] + if hwsku: + cmd += ' -S ' + hwsku[0] + if port_conf: + cmd += ' -p ' + port_conf[0] + if namespace: + cmd += ' -n ' + namespace[0] + cmd += ' --print-data' + output = subprocess.check_output(cmd, shell=True).decode() + # "NULL": "NULL" is placeholder for redis, remove to pass yang validation. + output = output.replace("\"NULL\": \"NULL\"", "") + self.yang_parser.loadData(configdbJson=json.loads(output)) + try: + self.yang_parser.validate_data_tree() + except sonic_yang.SonicYangException as e: + print("yang data generated from %s is not valid"%(minigraph[0])) + raise + if check_stderr: output = subprocess.check_output(self.script_file + ' ' + argument, stderr=subprocess.STDOUT, shell=True) else: diff --git a/src/sonic-config-engine/tests/test_minigraph_case.py b/src/sonic-config-engine/tests/test_minigraph_case.py index 051f33c918ad..500da939afd6 100644 --- a/src/sonic-config-engine/tests/test_minigraph_case.py +++ b/src/sonic-config-engine/tests/test_minigraph_case.py @@ -1,18 +1,23 @@ import json import os import subprocess +import re +import sonic_yang import tests.common_utils as utils import minigraph from unittest import TestCase +YANG_MODELS_DIR = "/usr/local/yang-models" TOR_ROUTER = 'ToRRouter' BACKEND_TOR_ROUTER = 'BackEndToRRouter' class TestCfgGenCaseInsensitive(TestCase): def setUp(self): + self.yang_parser = sonic_yang.SonicYang(YANG_MODELS_DIR) + self.yang_parser.loadYangModel() self.test_dir = os.path.dirname(os.path.realpath(__file__)) self.script_file = utils.PYTHON_INTERPRETTER + ' ' + os.path.join(self.test_dir, '..', 'sonic-cfggen') self.sample_graph = os.path.join(self.test_dir, 'simple-sample-graph-case.xml') @@ -23,6 +28,32 @@ def setUp(self): def run_script(self, argument, check_stderr=False): print('\n Running sonic-cfggen ' + argument) + if "-m" in argument: + pattern = r'-m\s+(\S+)\s*' + minigraph = re.findall(r'-m\s+(\S+)\s*', argument) + hwsku = re.findall(r'-S\s+(\S+)\s*', argument) + port_conf = re.findall(r'-p\s+(\S+)\s*', argument) + namespace = re.findall(r'-n\s+(\S+)\s*', argument) + if minigraph: + print('\n Validating yang schema') + cmd = self.script_file + ' -m ' + minigraph[0] + if hwsku: + cmd += ' -S ' + hwsku[0] + if port_conf: + cmd += ' -p ' + port_conf[0] + if namespace: + cmd += ' -n ' + namespace[0] + cmd += ' --print-data' + output = subprocess.check_output(cmd, shell=True).decode() + # "NULL": "NULL" is placeholder for redis, remove to pass yang validation. + output = output.replace("\"NULL\": \"NULL\"", "") + self.yang_parser.loadData(configdbJson=json.loads(output)) + try: + self.yang_parser.validate_data_tree() + except sonic_yang.SonicYangException as e: + print("yang data generated from %s is not valid"%(minigraph[0])) + raise + if check_stderr: output = subprocess.check_output(self.script_file + ' ' + argument, stderr=subprocess.STDOUT, shell=True) else: diff --git a/src/sonic-config-engine/tests/test_multinpu_cfggen.py b/src/sonic-config-engine/tests/test_multinpu_cfggen.py index 8a79be743848..337810b5a258 100644 --- a/src/sonic-config-engine/tests/test_multinpu_cfggen.py +++ b/src/sonic-config-engine/tests/test_multinpu_cfggen.py @@ -5,12 +5,14 @@ import subprocess import unittest import yaml +import re +import sonic_yang import tests.common_utils as utils from unittest import TestCase - +YANG_MODELS_DIR = "/usr/local/yang-models" SKU = 'multi-npu-01' ASIC_SKU = 'multi-npu-asic' NUM_ASIC = 4 @@ -20,6 +22,8 @@ class TestMultiNpuCfgGen(TestCase): def setUp(self): + self.yang_parser = sonic_yang.SonicYang(YANG_MODELS_DIR) + self.yang_parser.loadYangModel() self.test_dir = os.path.dirname(os.path.realpath(__file__)) self.test_data_dir = os.path.join(self.test_dir, 'multi_npu_data') self.script_file = utils.PYTHON_INTERPRETTER + ' ' + os.path.join(self.test_dir, '..', 'sonic-cfggen') @@ -33,6 +37,32 @@ def setUp(self): def run_script(self, argument, check_stderr=False): print('\n Running sonic-cfggen ' + argument) + if "-m" in argument: + pattern = r'-m\s+(\S+)\s*' + minigraph = re.findall(r'-m\s+(\S+)\s*', argument) + hwsku = re.findall(r'-S\s+(\S+)\s*', argument) + port_conf = re.findall(r'-p\s+(\S+)\s*', argument) + namespace = re.findall(r'-n\s+(\S+)\s*', argument) + if minigraph: + print('\n Validating yang schema') + cmd = self.script_file + ' -m ' + minigraph[0] + if hwsku: + cmd += ' -S ' + hwsku[0] + if port_conf: + cmd += ' -p ' + port_conf[0] + if namespace: + cmd += ' -n ' + namespace[0] + cmd += ' --print-data' + output = subprocess.check_output(cmd, shell=True).decode() + # "NULL": "NULL" is placeholder for redis, remove to pass yang validation. + output = output.replace("\"NULL\": \"NULL\"", "") + self.yang_parser.loadData(configdbJson=json.loads(output)) + try: + self.yang_parser.validate_data_tree() + except sonic_yang.SonicYangException as e: + print("yang data generated from %s is not valid"%(minigraph[0])) + raise + if check_stderr: output = subprocess.check_output(self.script_file + ' ' + argument, stderr=subprocess.STDOUT, shell=True) else: From e2056e8a961b6777af81622be167c69ec2b7fe5f Mon Sep 17 00:00:00 2001 From: ganglyu Date: Fri, 7 Jan 2022 12:55:27 +0800 Subject: [PATCH 2/9] sonic_yang does not work for python2 Signed-off-by: Gang Lv ganglv@microsoft.com --- src/sonic-config-engine/tests/test_cfggen.py | 15 ++++++++++----- .../tests/test_minigraph_case.py | 15 ++++++++++----- .../tests/test_multinpu_cfggen.py | 15 ++++++++++----- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index c60c29514799..fcf936e1bc54 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -2,13 +2,17 @@ import subprocess import os import re +import sys -import sonic_yang import tests.common_utils as utils from unittest import TestCase -YANG_MODELS_DIR = "/usr/local/yang-models" +PY3x = sys.version_info >= (3, 0) +if PY3x: + import sonic_yang + YANG_MODELS_DIR = "/usr/local/yang-models" + TOR_ROUTER = 'ToRRouter' BACKEND_TOR_ROUTER = 'BackEndToRRouter' LEAF_ROUTER = 'LeafRouter' @@ -17,8 +21,9 @@ class TestCfgGen(TestCase): def setUp(self): - self.yang_parser = sonic_yang.SonicYang(YANG_MODELS_DIR) - self.yang_parser.loadYangModel() + if PY3x: + self.yang_parser = sonic_yang.SonicYang(YANG_MODELS_DIR) + self.yang_parser.loadYangModel() self.test_dir = os.path.dirname(os.path.realpath(__file__)) self.script_file = utils.PYTHON_INTERPRETTER + ' ' + os.path.join(self.test_dir, '..', 'sonic-cfggen') self.sample_graph = os.path.join(self.test_dir, 'sample_graph.xml') @@ -54,7 +59,7 @@ def tearDown(self): def run_script(self, argument, check_stderr=False, verbose=False): print('\n Running sonic-cfggen ' + argument) - if "-m" in argument: + if PY3x and "-m" in argument: pattern = r'-m\s+(\S+)\s*' minigraph = re.findall(r'-m\s+(\S+)\s*', argument) hwsku = re.findall(r'-S\s+(\S+)\s*', argument) diff --git a/src/sonic-config-engine/tests/test_minigraph_case.py b/src/sonic-config-engine/tests/test_minigraph_case.py index 500da939afd6..7022e407c1d2 100644 --- a/src/sonic-config-engine/tests/test_minigraph_case.py +++ b/src/sonic-config-engine/tests/test_minigraph_case.py @@ -2,22 +2,27 @@ import os import subprocess import re +import sys -import sonic_yang import tests.common_utils as utils import minigraph from unittest import TestCase -YANG_MODELS_DIR = "/usr/local/yang-models" +PY3x = sys.version_info >= (3, 0) +if PY3x: + import sonic_yang + YANG_MODELS_DIR = "/usr/local/yang-models" + TOR_ROUTER = 'ToRRouter' BACKEND_TOR_ROUTER = 'BackEndToRRouter' class TestCfgGenCaseInsensitive(TestCase): def setUp(self): - self.yang_parser = sonic_yang.SonicYang(YANG_MODELS_DIR) - self.yang_parser.loadYangModel() + if PY3x: + self.yang_parser = sonic_yang.SonicYang(YANG_MODELS_DIR) + self.yang_parser.loadYangModel() self.test_dir = os.path.dirname(os.path.realpath(__file__)) self.script_file = utils.PYTHON_INTERPRETTER + ' ' + os.path.join(self.test_dir, '..', 'sonic-cfggen') self.sample_graph = os.path.join(self.test_dir, 'simple-sample-graph-case.xml') @@ -28,7 +33,7 @@ def setUp(self): def run_script(self, argument, check_stderr=False): print('\n Running sonic-cfggen ' + argument) - if "-m" in argument: + if PY3x and "-m" in argument: pattern = r'-m\s+(\S+)\s*' minigraph = re.findall(r'-m\s+(\S+)\s*', argument) hwsku = re.findall(r'-S\s+(\S+)\s*', argument) diff --git a/src/sonic-config-engine/tests/test_multinpu_cfggen.py b/src/sonic-config-engine/tests/test_multinpu_cfggen.py index 337810b5a258..e225e96cdc13 100644 --- a/src/sonic-config-engine/tests/test_multinpu_cfggen.py +++ b/src/sonic-config-engine/tests/test_multinpu_cfggen.py @@ -6,13 +6,17 @@ import unittest import yaml import re +import sys -import sonic_yang import tests.common_utils as utils from unittest import TestCase -YANG_MODELS_DIR = "/usr/local/yang-models" +PY3x = sys.version_info >= (3, 0) +if PY3x: + import sonic_yang + YANG_MODELS_DIR = "/usr/local/yang-models" + SKU = 'multi-npu-01' ASIC_SKU = 'multi-npu-asic' NUM_ASIC = 4 @@ -22,8 +26,9 @@ class TestMultiNpuCfgGen(TestCase): def setUp(self): - self.yang_parser = sonic_yang.SonicYang(YANG_MODELS_DIR) - self.yang_parser.loadYangModel() + if PY3x: + self.yang_parser = sonic_yang.SonicYang(YANG_MODELS_DIR) + self.yang_parser.loadYangModel() self.test_dir = os.path.dirname(os.path.realpath(__file__)) self.test_data_dir = os.path.join(self.test_dir, 'multi_npu_data') self.script_file = utils.PYTHON_INTERPRETTER + ' ' + os.path.join(self.test_dir, '..', 'sonic-cfggen') @@ -37,7 +42,7 @@ def setUp(self): def run_script(self, argument, check_stderr=False): print('\n Running sonic-cfggen ' + argument) - if "-m" in argument: + if PY3x and "-m" in argument: pattern = r'-m\s+(\S+)\s*' minigraph = re.findall(r'-m\s+(\S+)\s*', argument) hwsku = re.findall(r'-S\s+(\S+)\s*', argument) From c27192cf92103001b6639047cb6083e479f89bad Mon Sep 17 00:00:00 2001 From: ganglyu Date: Mon, 10 Jan 2022 11:12:12 +0800 Subject: [PATCH 3/9] Reuse yang validation and use argparser to replace regular expression Signed-off-by: Gang Lv ganglv@microsoft.com --- src/sonic-config-engine/tests/common_utils.py | 49 +++++++++++++++++++ src/sonic-config-engine/tests/test_cfggen.py | 37 +------------- .../tests/test_minigraph_case.py | 37 +------------- .../tests/test_multinpu_cfggen.py | 36 +------------- 4 files changed, 55 insertions(+), 104 deletions(-) diff --git a/src/sonic-config-engine/tests/common_utils.py b/src/sonic-config-engine/tests/common_utils.py index 3d8a3029dad9..e7bde7ca5762 100644 --- a/src/sonic-config-engine/tests/common_utils.py +++ b/src/sonic-config-engine/tests/common_utils.py @@ -1,10 +1,16 @@ import json import re import sys +import os +import subprocess +import argparse +import shlex + PY3x = sys.version_info >= (3, 0) PYvX_DIR = "py3" if PY3x else "py2" PYTHON_INTERPRETTER = "python3" if PY3x else "python2" +YANG_MODELS_DIR = "/usr/local/yang-models" def tuple_to_str(tuplestr): """ Convert Python tuple '('elem1', 'elem2')' representation into string on the for "elem1|elem2" """ @@ -31,3 +37,46 @@ def liststr_to_dict(liststr): return list_obj +class YangWrapper(object): + def __init__(self, path=YANG_MODELS_DIR): + """ + sonic_yang only supports python3 + """ + if PY3x: + import sonic_yang + self.yang_parser = sonic_yang.SonicYang(path) + self.yang_parser.loadYangModel() + self.test_dir = os.path.dirname(os.path.realpath(__file__)) + self.script_file = PYTHON_INTERPRETTER + ' ' + os.path.join(self.test_dir, '..', 'sonic-cfggen') + + def validate(self, argument): + """ + Raise exception when yang validation failed + """ + if PY3x and "-m" in argument: + parser=argparse.ArgumentParser(description="Render configuration file from minigraph data and jinja2 template.") + parser.add_argument("-m", "--minigraph", help="minigraph xml file", nargs='?', const='/etc/sonic/minigraph.xml') + parser.add_argument("-k", "--hwsku", help="HwSKU") + parser.add_argument("-n", "--namespace", help="namespace name", nargs='?', const=None, default=None) + parser.add_argument("-p", "--port-config", help="port config file, used with -m or -k", nargs='?', const=None) + parser.add_argument("-S", "--hwsku-config", help="hwsku config file, used with -p and -m or -k", nargs='?', const=None) + args, unknown = parser.parse_known_args(shlex.split(argument)) + + print('\n Validating yang schema') + cmd = self.script_file + ' -m ' + args.minigraph + if args.hwsku is not None: + cmd += ' -k ' + args.hwsku + if args.hwsku_config is not None: + cmd += ' -S ' + args.hwsku_config + if args.port_config is not None: + cmd += ' -p ' + args.port_config + if args.namespace is not None: + cmd += ' -n ' + args.namespace + cmd += ' --print-data' + output = subprocess.check_output(cmd, shell=True).decode() + self.yang_parser.loadData(configdbJson=json.loads(output)) + try: + self.yang_parser.validate_data_tree() + except sonic_yang.SonicYangException as e: + print("yang data generated from %s is not valid"%(args.minigraph)) + raise \ No newline at end of file diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index fcf936e1bc54..661f87b9fdce 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -1,18 +1,11 @@ import json import subprocess import os -import re -import sys import tests.common_utils as utils from unittest import TestCase -PY3x = sys.version_info >= (3, 0) -if PY3x: - import sonic_yang - YANG_MODELS_DIR = "/usr/local/yang-models" - TOR_ROUTER = 'ToRRouter' BACKEND_TOR_ROUTER = 'BackEndToRRouter' LEAF_ROUTER = 'LeafRouter' @@ -21,9 +14,7 @@ class TestCfgGen(TestCase): def setUp(self): - if PY3x: - self.yang_parser = sonic_yang.SonicYang(YANG_MODELS_DIR) - self.yang_parser.loadYangModel() + self.yang = utils.YangWrapper() self.test_dir = os.path.dirname(os.path.realpath(__file__)) self.script_file = utils.PYTHON_INTERPRETTER + ' ' + os.path.join(self.test_dir, '..', 'sonic-cfggen') self.sample_graph = os.path.join(self.test_dir, 'sample_graph.xml') @@ -59,31 +50,7 @@ def tearDown(self): def run_script(self, argument, check_stderr=False, verbose=False): print('\n Running sonic-cfggen ' + argument) - if PY3x and "-m" in argument: - pattern = r'-m\s+(\S+)\s*' - minigraph = re.findall(r'-m\s+(\S+)\s*', argument) - hwsku = re.findall(r'-S\s+(\S+)\s*', argument) - port_conf = re.findall(r'-p\s+(\S+)\s*', argument) - namespace = re.findall(r'-n\s+(\S+)\s*', argument) - if minigraph: - print('\n Validating yang schema') - cmd = self.script_file + ' -m ' + minigraph[0] - if hwsku: - cmd += ' -S ' + hwsku[0] - if port_conf: - cmd += ' -p ' + port_conf[0] - if namespace: - cmd += ' -n ' + namespace[0] - cmd += ' --print-data' - output = subprocess.check_output(cmd, shell=True).decode() - # "NULL": "NULL" is placeholder for redis, remove to pass yang validation. - output = output.replace("\"NULL\": \"NULL\"", "") - self.yang_parser.loadData(configdbJson=json.loads(output)) - try: - self.yang_parser.validate_data_tree() - except sonic_yang.SonicYangException as e: - print("yang data generated from %s is not valid"%(minigraph[0])) - raise + self.yang.validate(argument) if check_stderr: output = subprocess.check_output(self.script_file + ' ' + argument, stderr=subprocess.STDOUT, shell=True) diff --git a/src/sonic-config-engine/tests/test_minigraph_case.py b/src/sonic-config-engine/tests/test_minigraph_case.py index 7022e407c1d2..4294fe71ca77 100644 --- a/src/sonic-config-engine/tests/test_minigraph_case.py +++ b/src/sonic-config-engine/tests/test_minigraph_case.py @@ -1,28 +1,19 @@ import json import os import subprocess -import re -import sys import tests.common_utils as utils import minigraph from unittest import TestCase -PY3x = sys.version_info >= (3, 0) -if PY3x: - import sonic_yang - YANG_MODELS_DIR = "/usr/local/yang-models" - TOR_ROUTER = 'ToRRouter' BACKEND_TOR_ROUTER = 'BackEndToRRouter' class TestCfgGenCaseInsensitive(TestCase): def setUp(self): - if PY3x: - self.yang_parser = sonic_yang.SonicYang(YANG_MODELS_DIR) - self.yang_parser.loadYangModel() + self.yang = utils.YangWrapper() self.test_dir = os.path.dirname(os.path.realpath(__file__)) self.script_file = utils.PYTHON_INTERPRETTER + ' ' + os.path.join(self.test_dir, '..', 'sonic-cfggen') self.sample_graph = os.path.join(self.test_dir, 'simple-sample-graph-case.xml') @@ -33,31 +24,7 @@ def setUp(self): def run_script(self, argument, check_stderr=False): print('\n Running sonic-cfggen ' + argument) - if PY3x and "-m" in argument: - pattern = r'-m\s+(\S+)\s*' - minigraph = re.findall(r'-m\s+(\S+)\s*', argument) - hwsku = re.findall(r'-S\s+(\S+)\s*', argument) - port_conf = re.findall(r'-p\s+(\S+)\s*', argument) - namespace = re.findall(r'-n\s+(\S+)\s*', argument) - if minigraph: - print('\n Validating yang schema') - cmd = self.script_file + ' -m ' + minigraph[0] - if hwsku: - cmd += ' -S ' + hwsku[0] - if port_conf: - cmd += ' -p ' + port_conf[0] - if namespace: - cmd += ' -n ' + namespace[0] - cmd += ' --print-data' - output = subprocess.check_output(cmd, shell=True).decode() - # "NULL": "NULL" is placeholder for redis, remove to pass yang validation. - output = output.replace("\"NULL\": \"NULL\"", "") - self.yang_parser.loadData(configdbJson=json.loads(output)) - try: - self.yang_parser.validate_data_tree() - except sonic_yang.SonicYangException as e: - print("yang data generated from %s is not valid"%(minigraph[0])) - raise + self.yang.validate(argument) if check_stderr: output = subprocess.check_output(self.script_file + ' ' + argument, stderr=subprocess.STDOUT, shell=True) diff --git a/src/sonic-config-engine/tests/test_multinpu_cfggen.py b/src/sonic-config-engine/tests/test_multinpu_cfggen.py index e225e96cdc13..1df9f87708b3 100644 --- a/src/sonic-config-engine/tests/test_multinpu_cfggen.py +++ b/src/sonic-config-engine/tests/test_multinpu_cfggen.py @@ -5,17 +5,11 @@ import subprocess import unittest import yaml -import re -import sys import tests.common_utils as utils from unittest import TestCase -PY3x = sys.version_info >= (3, 0) -if PY3x: - import sonic_yang - YANG_MODELS_DIR = "/usr/local/yang-models" SKU = 'multi-npu-01' ASIC_SKU = 'multi-npu-asic' @@ -26,9 +20,7 @@ class TestMultiNpuCfgGen(TestCase): def setUp(self): - if PY3x: - self.yang_parser = sonic_yang.SonicYang(YANG_MODELS_DIR) - self.yang_parser.loadYangModel() + self.yang = utils.YangWrapper() self.test_dir = os.path.dirname(os.path.realpath(__file__)) self.test_data_dir = os.path.join(self.test_dir, 'multi_npu_data') self.script_file = utils.PYTHON_INTERPRETTER + ' ' + os.path.join(self.test_dir, '..', 'sonic-cfggen') @@ -42,31 +34,7 @@ def setUp(self): def run_script(self, argument, check_stderr=False): print('\n Running sonic-cfggen ' + argument) - if PY3x and "-m" in argument: - pattern = r'-m\s+(\S+)\s*' - minigraph = re.findall(r'-m\s+(\S+)\s*', argument) - hwsku = re.findall(r'-S\s+(\S+)\s*', argument) - port_conf = re.findall(r'-p\s+(\S+)\s*', argument) - namespace = re.findall(r'-n\s+(\S+)\s*', argument) - if minigraph: - print('\n Validating yang schema') - cmd = self.script_file + ' -m ' + minigraph[0] - if hwsku: - cmd += ' -S ' + hwsku[0] - if port_conf: - cmd += ' -p ' + port_conf[0] - if namespace: - cmd += ' -n ' + namespace[0] - cmd += ' --print-data' - output = subprocess.check_output(cmd, shell=True).decode() - # "NULL": "NULL" is placeholder for redis, remove to pass yang validation. - output = output.replace("\"NULL\": \"NULL\"", "") - self.yang_parser.loadData(configdbJson=json.loads(output)) - try: - self.yang_parser.validate_data_tree() - except sonic_yang.SonicYangException as e: - print("yang data generated from %s is not valid"%(minigraph[0])) - raise + self.yang.validate(argument) if check_stderr: output = subprocess.check_output(self.script_file + ' ' + argument, stderr=subprocess.STDOUT, shell=True) From 593d2446eb2f4b25f8e7cc8b6e1ddf75b89b8086 Mon Sep 17 00:00:00 2001 From: ganglyu Date: Wed, 19 Jan 2022 13:57:35 +0800 Subject: [PATCH 4/9] Fix comment Signed-off-by: Gang Lv ganglv@microsoft.com --- src/sonic-config-engine/tests/common_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-config-engine/tests/common_utils.py b/src/sonic-config-engine/tests/common_utils.py index e7bde7ca5762..194373eec0fb 100644 --- a/src/sonic-config-engine/tests/common_utils.py +++ b/src/sonic-config-engine/tests/common_utils.py @@ -74,8 +74,8 @@ def validate(self, argument): cmd += ' -n ' + args.namespace cmd += ' --print-data' output = subprocess.check_output(cmd, shell=True).decode() - self.yang_parser.loadData(configdbJson=json.loads(output)) try: + self.yang_parser.loadData(configdbJson=json.loads(output)) self.yang_parser.validate_data_tree() except sonic_yang.SonicYangException as e: print("yang data generated from %s is not valid"%(args.minigraph)) From 3f40271ea3d26642cc8a4193f9a38022c5645d97 Mon Sep 17 00:00:00 2001 From: ganglyu Date: Wed, 19 Jan 2022 15:49:47 +0800 Subject: [PATCH 5/9] Update import Signed-off-by: Gang Lv ganglv@microsoft.com --- src/sonic-config-engine/tests/common_utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sonic-config-engine/tests/common_utils.py b/src/sonic-config-engine/tests/common_utils.py index 194373eec0fb..bb3865d77b40 100644 --- a/src/sonic-config-engine/tests/common_utils.py +++ b/src/sonic-config-engine/tests/common_utils.py @@ -54,6 +54,7 @@ def validate(self, argument): Raise exception when yang validation failed """ if PY3x and "-m" in argument: + import sonic_yang parser=argparse.ArgumentParser(description="Render configuration file from minigraph data and jinja2 template.") parser.add_argument("-m", "--minigraph", help="minigraph xml file", nargs='?', const='/etc/sonic/minigraph.xml') parser.add_argument("-k", "--hwsku", help="HwSKU") From eb97f30fefeb4bcc9b1afff91602922e65e76836 Mon Sep 17 00:00:00 2001 From: ganglyu Date: Wed, 19 Jan 2022 16:43:37 +0800 Subject: [PATCH 6/9] Should not raise exception and return False. Signed-off-by: Gang Lv ganglv@microsoft.com --- src/sonic-config-engine/tests/common_utils.py | 5 +++-- src/sonic-config-engine/tests/test_cfggen.py | 2 +- src/sonic-config-engine/tests/test_minigraph_case.py | 2 +- src/sonic-config-engine/tests/test_multinpu_cfggen.py | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sonic-config-engine/tests/common_utils.py b/src/sonic-config-engine/tests/common_utils.py index bb3865d77b40..58ad4cbe0893 100644 --- a/src/sonic-config-engine/tests/common_utils.py +++ b/src/sonic-config-engine/tests/common_utils.py @@ -79,5 +79,6 @@ def validate(self, argument): self.yang_parser.loadData(configdbJson=json.loads(output)) self.yang_parser.validate_data_tree() except sonic_yang.SonicYangException as e: - print("yang data generated from %s is not valid"%(args.minigraph)) - raise \ No newline at end of file + print("yang data generated from %s is not valid: %s"%(args.minigraph, str(e))) + return False + return True \ No newline at end of file diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index de3ba4cd10b3..032b2889dee6 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -50,7 +50,7 @@ def tearDown(self): def run_script(self, argument, check_stderr=False, verbose=False): print('\n Running sonic-cfggen ' + argument) - self.yang.validate(argument) + self.assertTrue(self.yang.validate(argument)) if check_stderr: output = subprocess.check_output(self.script_file + ' ' + argument, stderr=subprocess.STDOUT, shell=True) diff --git a/src/sonic-config-engine/tests/test_minigraph_case.py b/src/sonic-config-engine/tests/test_minigraph_case.py index 4294fe71ca77..f0331a176734 100644 --- a/src/sonic-config-engine/tests/test_minigraph_case.py +++ b/src/sonic-config-engine/tests/test_minigraph_case.py @@ -24,7 +24,7 @@ def setUp(self): def run_script(self, argument, check_stderr=False): print('\n Running sonic-cfggen ' + argument) - self.yang.validate(argument) + self.assertTrue(self.yang.validate(argument)) if check_stderr: output = subprocess.check_output(self.script_file + ' ' + argument, stderr=subprocess.STDOUT, shell=True) diff --git a/src/sonic-config-engine/tests/test_multinpu_cfggen.py b/src/sonic-config-engine/tests/test_multinpu_cfggen.py index 1df9f87708b3..f581a38868d1 100644 --- a/src/sonic-config-engine/tests/test_multinpu_cfggen.py +++ b/src/sonic-config-engine/tests/test_multinpu_cfggen.py @@ -34,7 +34,7 @@ def setUp(self): def run_script(self, argument, check_stderr=False): print('\n Running sonic-cfggen ' + argument) - self.yang.validate(argument) + self.assertTrue(self.yang.validate(argument)) if check_stderr: output = subprocess.check_output(self.script_file + ' ' + argument, stderr=subprocess.STDOUT, shell=True) From 183c814ca523e68b3d407f31616e15a352ec62c6 Mon Sep 17 00:00:00 2001 From: ganglyu Date: Wed, 19 Jan 2022 16:46:15 +0800 Subject: [PATCH 7/9] Add empty line. Signed-off-by: Gang Lv ganglv@microsoft.com --- src/sonic-config-engine/tests/common_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sonic-config-engine/tests/common_utils.py b/src/sonic-config-engine/tests/common_utils.py index 58ad4cbe0893..7759fc48ab55 100644 --- a/src/sonic-config-engine/tests/common_utils.py +++ b/src/sonic-config-engine/tests/common_utils.py @@ -81,4 +81,4 @@ def validate(self, argument): except sonic_yang.SonicYangException as e: print("yang data generated from %s is not valid: %s"%(args.minigraph, str(e))) return False - return True \ No newline at end of file + return True From 5e2e1af6a7e1e4fd9f144a96fc8b4c5072da90f0 Mon Sep 17 00:00:00 2001 From: ganglyu Date: Mon, 4 Apr 2022 07:30:53 +0000 Subject: [PATCH 8/9] Remove duplicated import --- src/sonic-config-engine/tests/common_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sonic-config-engine/tests/common_utils.py b/src/sonic-config-engine/tests/common_utils.py index 35fb968a8b2a..067eeb3fb928 100644 --- a/src/sonic-config-engine/tests/common_utils.py +++ b/src/sonic-config-engine/tests/common_utils.py @@ -3,7 +3,6 @@ import os import re import sys -import os import subprocess import argparse import shlex From 6d4af4d3f357efeb9863420b2fb81c111bcff650 Mon Sep 17 00:00:00 2001 From: ganglyu Date: Fri, 13 May 2022 08:38:06 +0800 Subject: [PATCH 9/9] check --- src/sonic-config-engine/tests/common_utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/sonic-config-engine/tests/common_utils.py b/src/sonic-config-engine/tests/common_utils.py index 067eeb3fb928..7b8d2b4e27a4 100644 --- a/src/sonic-config-engine/tests/common_utils.py +++ b/src/sonic-config-engine/tests/common_utils.py @@ -7,7 +7,6 @@ import argparse import shlex - PY3x = sys.version_info >= (3, 0) PYvX_DIR = "py3" if PY3x else "py2" PYTHON_INTERPRETTER = "python3" if PY3x else "python2"