From 84beafbfd377ede11682119a3d47a83827d7209b Mon Sep 17 00:00:00 2001 From: Praveen Chaudhary Date: Tue, 12 May 2020 23:11:41 -0700 Subject: [PATCH] [sonic_yang.py]: Categories public and private functions. Changes: 1.) Categories public and private functions. 2.) Minor spaces related changes. 3.) Defining class SonicYangException and using it in all public functions. 4.) Changing Class names to PascalCase. 5.) Keeping functions, which deals with Libyang, in lower_underscore_case, rest functions names are in camelCase. --- src/sonic-yang-mgmt/sonic_yang.py | 133 +++++------ src/sonic-yang-mgmt/sonic_yang_ext.py | 207 +++++++++--------- .../libyang-python-tests/test_sonic_yang.py | 64 +++--- 3 files changed, 205 insertions(+), 199 deletions(-) diff --git a/src/sonic-yang-mgmt/sonic_yang.py b/src/sonic-yang-mgmt/sonic_yang.py index cb7f5873fa33..a9ec2f0ad63e 100644 --- a/src/sonic-yang-mgmt/sonic_yang.py +++ b/src/sonic-yang-mgmt/sonic_yang.py @@ -3,14 +3,14 @@ from json import dump from glob import glob -from sonic_yang_ext import sonic_yang_ext_mixin +from sonic_yang_ext import SonicYangExtMixin, SonicYangException """ Yang schema and data tree python APIs based on libyang python Here, sonic_yang_ext_mixin extends funtionality of sonic_yang, i.e. it is mixin not parent class. """ -class sonic_yang(sonic_yang_ext_mixin): +class SonicYang(SonicYangExtMixin): def __init__(self, yang_dir, debug=False): self.yang_dir = yang_dir @@ -67,7 +67,7 @@ def fail(self, e): input: yang_file - full path of a Yang model file returns: Exception if error """ - def load_schema_module(self, yang_file): + def _load_schema_module(self, yang_file): try: return self.ctx.parse_module_path(yang_file, ly.LYS_IN_YANG) except Exception as e: @@ -79,10 +79,10 @@ def load_schema_module(self, yang_file): input: yang_files - a list of Yang model file full path returns: Exception if error """ - def load_schema_module_list(self, yang_files): + def _load_schema_module_list(self, yang_files): for file in yang_files: try: - self.load_schema_module(file) + self._load_schema_module(file) except Exception as e: self.fail(e) @@ -91,11 +91,11 @@ def load_schema_module_list(self, yang_files): input: yang_dir - the directory of the yang model files to be loaded returns: Exception if error """ - def load_schema_modules(self, yang_dir): + def _load_schema_modules(self, yang_dir): py = glob(yang_dir+"/*.yang") for file in py: try: - self.load_schema_module(file) + self._load_schema_module(file) except Exception as e: self.fail(e) @@ -104,7 +104,7 @@ def load_schema_modules(self, yang_dir): input: yang_dir, context returns: Exception if error, returrns context object if no error """ - def load_schema_modules_ctx(self, yang_dir=None): + def _load_schema_modules_ctx(self, yang_dir=None): if not yang_dir: yang_dir = self.yang_dir @@ -125,7 +125,7 @@ def load_schema_modules_ctx(self, yang_dir=None): input: data_file - the full path of the yang json data file to be loaded returns: Exception if error """ - def load_data_file(self, data_file): + def _load_data_file(self, data_file): try: data_node = self.ctx.parse_data_path(data_file, ly.LYD_JSON, ly.LYD_OPT_CONFIG | ly.LYD_OPT_STRICT) except Exception as e: @@ -139,7 +139,7 @@ def load_data_file(self, data_file): input: path returns: module name """ - def get_module_name(self, schema_xpath): + def _get_module_name(self, schema_xpath): module_name = schema_xpath.split(':')[0].strip('/') return module_name @@ -148,7 +148,7 @@ def get_module_name(self, schema_xpath): input: yang module name returns: Schema_Node object """ - def get_module(self, module_name): + def _get_module(self, module_name): mod = self.ctx.get_module(module_name) return mod @@ -157,26 +157,26 @@ def get_module(self, module_name): input: yang directory, list of yang files and list of data files (full path) returns: returns (context, root) if no error, or Exception if failed """ - def load_data_model (self, yang_dir, yang_files, data_files, output=None): + def _load_data_model(self, yang_dir, yang_files, data_files, output=None): if (self.ctx is None): self.ctx = ly.Context(yang_dir) try: - self.load_schema_module_list(yang_files) + self._load_schema_module_list(yang_files) if len(data_files) == 0: return (self.ctx, self.root) - self.load_data_file(data_files[0]) + self._load_data_file(data_files[0]) for i in range(1, len(data_files)): - self.merge_data(data_files[i]) + self._merge_data(data_files[i]) except Exception as e: print("Failed to load data files") self.fail(e) return if output is not None: - self.print_data_mem(output) + self._print_data_mem(output) return (self.ctx, self.root) @@ -184,7 +184,7 @@ def load_data_model (self, yang_dir, yang_files, data_files, output=None): print_data_mem(): print the data tree input: option: "JSON" or "XML" """ - def print_data_mem (self, option): + def _print_data_mem(self, option): if (option == "JSON"): mem = self.root.print_mem(ly.LYD_JSON, ly.LYP_WITHSIBLINGS | ly.LYP_FORMAT) else: @@ -196,7 +196,7 @@ def print_data_mem (self, option): save_data_file_json(): save the data tree in memory into json file input: outfile - full path of the file to save the data tree to """ - def save_data_file_json(self, outfile): + def _save_data_file_json(self, outfile): mem = self.root.print_mem(ly.LYD_JSON, ly.LYP_FORMAT) with open(outfile, 'w') as out: dump(mem, out, indent=4) @@ -206,7 +206,7 @@ def save_data_file_json(self, outfile): input: module name returns: JSON or XML format of the input yang module schema tree """ - def get_module_tree(self, module_name, format): + def _get_module_tree(self, module_name, format): result = None try: @@ -231,7 +231,7 @@ def get_module_tree(self, module_name, format): ctx: context returns: Exception if failed """ - def validate_data (self, node=None, ctx=None): + def _validate_data(self, node=None, ctx=None): if not node: node = self.root @@ -244,27 +244,28 @@ def validate_data (self, node=None, ctx=None): self.fail(e) """ - validate_data_tree(): validate the data tree + validate_data_tree(): validate the data tree. (Public) returns: Exception if failed """ - def validate_data_tree (self): + def validate_data_tree(self): try: - self.validate_data(self.root, self.ctx) + self._validate_data(self.root, self.ctx) except Exception as e: print("Failed to validate data tree") - self.fail(e) + raise SonicYangException("Failed to validate data tree\n{}".\ + format(str(e))) """ find_parent_data_node(): find the parent node object input: data_xpath - xpath of the data node returns: parent node """ - def find_parent_data_node (self, data_xpath): + def _find_parent_data_node(self, data_xpath): if (self.root is None): print("data not loaded") return None try: - data_node = self.find_data_node(data_xpath) + data_node = self._find_data_node(data_xpath) except Exception as e: print("Failed to find data node from xpath: " + str(data_xpath)) self.fail(e) @@ -280,15 +281,15 @@ def find_parent_data_node (self, data_xpath): returns: - xpath of parent data node - Exception if error """ - def get_parent_data_xpath (self, data_xpath): + def _get_parent_data_xpath(self, data_xpath): path="" try: - data_node = self.find_parent_data_node(data_xpath) + data_node = self._find_parent_data_node(data_xpath) except Exception as e: print("Failed to find parent node from xpath: " + str(data_xpath)) self.fail(e) else: - if (data_node is not None): + if data_node is not None: path = data_node.path() return path @@ -299,7 +300,7 @@ def get_parent_data_xpath (self, data_xpath): value: value of the new node returns: new Data_Node object if success, Exception if falied """ - def new_data_node(self, xpath, value): + def _new_data_node(self, xpath, value): val = str(value) try: data_node = self.root.new_path(self.ctx, xpath, val, 0, 0) @@ -316,7 +317,7 @@ def new_data_node(self, xpath, value): - None if not exist - Exception if there is error """ - def find_data_node(self, data_xpath): + def _find_data_node(self, data_xpath): try: set = self.root.find_path(data_xpath) except Exception as e: @@ -335,7 +336,7 @@ def find_data_node(self, data_xpath): input: xpath of the node returns: Schema_Node oject or None if not found """ - def find_schema_node(self, schema_xpath): + def _find_schema_node(self, schema_xpath): try: schema_set = self.ctx.find_path(schema_xpath) for schema_node in schema_set.schema(): @@ -357,7 +358,7 @@ def find_schema_node(self, schema_xpath): returns: - xpath of the schema node if success - Exception if error """ - def find_data_node_schema_xpath(self, data_xpath): + def _find_data_node_schema_xpath(self, data_xpath): path = "" try: set = self.root.find_path(data_xpath) @@ -374,11 +375,11 @@ def find_data_node_schema_xpath(self, data_xpath): input: xpath and value of the node to be added returns: Exception if failed """ - def add_data_node(self, data_xpath, value): + def _add_data_node(self, data_xpath, value): try: - self.new_data_node(data_xpath, value) + self._new_data_node(data_xpath, value) #check if the node added to the data tree - self.find_data_node(data_xpath) + self._find_data_node(data_xpath) except Exception as e: print("add_node(): Failed to add data node for xpath: " + str(data_xpath)) self.fail(e) @@ -388,13 +389,13 @@ def add_data_node(self, data_xpath, value): input: yang model directory and full path of the data json file to be merged returns: Exception if failed """ - def merge_data(self, data_file, yang_dir=None): + def _merge_data(self, data_file, yang_dir=None): #load all yang models to ctx if not yang_dir: yang_dir = self.yang_dir try: - ctx = self.load_schema_modules_ctx(yang_dir) + ctx = self._load_schema_modules_ctx(yang_dir) #source data node source_node = ctx.parse_data_path(str(data_file), ly.LYD_JSON, ly.LYD_OPT_CONFIG | ly.LYD_OPT_STRICT) @@ -405,17 +406,17 @@ def merge_data(self, data_file, yang_dir=None): self.fail(e) """ - _delete_node(): delete a node from the schema/data tree, internal function + _deleteNode(): delete a node from the schema/data tree, internal function input: xpath of the schema/data node returns: True - success False - failed """ - def _delete_node(self, xpath=None, node=None): + def _deleteNode(self, xpath=None, node=None): if node is None: - node = self.find_data_node(xpath) + node = self._find_data_node(xpath) if (node): node.unlink() - dnode = self.find_data_node(xpath) + dnode = self._find_data_node(xpath) if (dnode is None): #deleted node not found return True @@ -432,10 +433,10 @@ def _delete_node(self, xpath=None, node=None): input: data_xpath of the data node returns: value string of the node """ - def find_data_node_value(self, data_xpath): + def _find_data_node_value(self, data_xpath): output = "" try: - data_node = self.find_data_node(data_xpath) + data_node = self._find_data_node(data_xpath) except Exception as e: print("find_data_node_value(): Failed to find data node from xpath: {}".format(data_xpath)) self.fail(e) @@ -452,7 +453,7 @@ def find_data_node_value(self, data_xpath): input: xpath of the data node returns: Exception if failed """ - def set_data_node_value(self, data_xpath, value): + def _set_data_node_value(self, data_xpath, value): try: self.root.new_path(self.ctx, data_xpath, str(value), ly.LYD_ANYDATA_STRING, ly.LYD_PATH_OPT_UPDATE) except Exception as e: @@ -464,7 +465,7 @@ def set_data_node_value(self, data_xpath, value): input: xpath of the data node returns: list of xpath of the dataset """ - def find_data_nodes(self, data_xpath): + def _find_data_nodes(self, data_xpath): list = [] node = self.root.child() try: @@ -486,10 +487,10 @@ def find_data_nodes(self, data_xpath): returns: - list of xpath of the dependencies - Exception if schema node not found """ - def find_schema_dependencies (self, schema_xpath): + def _find_schema_dependencies(self, schema_xpath): ref_list = [] try: - schema_node = self.find_schema_node(schema_xpath) + schema_node = self._find_schema_node(schema_xpath) except Exception as e: print("Cound not find the schema node from xpath: " + str(schema_xpath)) self.fail(e) @@ -505,22 +506,21 @@ def find_schema_dependencies (self, schema_xpath): """ find_data_dependencies(): find the data dependencies from data xpath - input: data_xpath - xpath of data node + input: data_xpath - xpath of data node. (Public) returns: - list of xpath - Exception if error """ - def find_data_dependencies (self, data_xpath): + def find_data_dependencies(self, data_xpath): ref_list = [] node = self.root try: - data_node = self.find_data_node(data_xpath) + data_node = self._find_data_node(data_xpath) except Exception as e: print("find_data_dependencies(): Failed to find data node from xpath: {}".format(data_xapth)) - self.fail(e) return ref_list try: - value = str(self.find_data_node_value(data_xpath)) + value = str(self._find_data_node_value(data_xpath)) schema_node = ly.Schema_Node_Leaf(data_node.schema()) backlinks = schema_node.backlinks() @@ -534,7 +534,8 @@ def find_data_dependencies (self, data_xpath): ref_list.append(data_set.path()) except Exception as e: print('Failed to find node or dependencies for {}'.format(data_xpath)) - self.fail(e) + raise SonicYangException("Failed to find node or dependencies for \ + {}\n{}".format(data_xpath, str(e))) return ref_list @@ -543,10 +544,10 @@ def find_data_dependencies (self, data_xpath): input: name of the Yang module output: prefix of the Yang module """ - def get_module_prefix(self, module_name): + def _get_module_prefix(self, module_name): prefix = "" try: - module = self.get_module(module_name) + module = self._get_module(module_name) except Exception as e: self.fail(e) return prefix @@ -558,7 +559,7 @@ def get_module_prefix(self, module_name): input: string output: type """ - def str_to_type (self, type_str): + def _str_to_type(self, type_str): mapped_type = { "LY_TYPE_DER":ly.LY_TYPE_DER, "LY_TYPE_BINARY":ly.LY_TYPE_BINARY, @@ -588,9 +589,9 @@ def str_to_type (self, type_str): return mapped_type[type_str] - def get_data_type (self, schema_xpath): + def _get_data_type(self, schema_xpath): try: - schema_node = self.find_schema_node(schema_xpath) + schema_node = self._find_schema_node(schema_xpath) except Exception as e: print("get_data_type(): Failed to find schema node from xpath: {}".format(schema_xpath)) self.fail(e) @@ -606,8 +607,8 @@ def get_data_type (self, schema_xpath): input: data_xpath - xpath of a data node output: type of the node this leafref references to """ - def get_leafref_type (self, data_xpath): - data_node = self.find_data_node(data_xpath) + def _get_leafref_type(self, data_xpath): + data_node = self._find_data_node(data_xpath) if (data_node is not None): subtype = data_node.subtype() if (subtype is not None): @@ -624,8 +625,8 @@ def get_leafref_type (self, data_xpath): input: schema_xpath - xpath of a schema node output: path value of the leafref node """ - def get_leafref_path (self, schema_xpath): - schema_node = self.find_schema_node(schema_xpath) + def _get_leafref_path(self, schema_xpath): + schema_node = self._find_schema_node(schema_xpath) if (schema_node is not None): subtype = schema_node.subtype() if (subtype is not None): @@ -641,8 +642,8 @@ def get_leafref_path (self, schema_xpath): input: schema_xpath - xpath of a schema node output: type of the node this leafref references to """ - def get_leafref_type_schema (self, schema_xpath): - schema_node = self.find_schema_node(schema_xpath) + def _get_leafref_type_schema(self, schema_xpath): + schema_node = self._find_schema_node(schema_xpath) if (schema_node is not None): subtype = schema_node.subtype() if (subtype is not None): @@ -652,7 +653,7 @@ def get_leafref_type_schema (self, schema_xpath): subtype.type().info().lref().path() target = subtype.type().info().lref().target() target_path = target.path() - target_type = self.get_data_type(target_path) + target_type = self._get_data_type(target_path) return target_type return None diff --git a/src/sonic-yang-mgmt/sonic_yang_ext.py b/src/sonic-yang-mgmt/sonic_yang_ext.py index 7e293cbb67e2..3cfad3aaaf63 100644 --- a/src/sonic-yang-mgmt/sonic_yang_ext.py +++ b/src/sonic-yang-mgmt/sonic_yang_ext.py @@ -10,11 +10,17 @@ from xmltodict import parse from glob import glob +""" +This is the Exception thrown out of all public function of this class. +""" +class SonicYangException(Exception): + pass + # class sonic_yang methods, use mixin to extend sonic_yang -class sonic_yang_ext_mixin: +class SonicYangExtMixin: """ - load all YANG models, create JSON of yang models + load all YANG models, create JSON of yang models. (Public function) """ def loadYangModel(self): @@ -23,7 +29,7 @@ def loadYangModel(self): self.yangFiles = glob(self.yang_dir +"/*.yang") # load yang modules for file in self.yangFiles: - m = self.load_schema_module(file) + m = self._load_schema_module(file) if m is not None: self.sysLog(msg="module: {} is loaded successfully".format(m.name())) else: @@ -36,20 +42,20 @@ def loadYangModel(self): print(self.yangFiles) # load json for each yang model - self.loadJsonYangModel() + self._loadJsonYangModel() # create a map from config DB table to yang container - self.createDBTableToModuleMap() + self._createDBTableToModuleMap() except Exception as e: print("Yang Models Load failed") - raise e + raise SonicYangException("Yang Models Load failed\n{}".format(str(e))) return True """ load JSON schema format from yang models """ - def loadJsonYangModel(self): + def _loadJsonYangModel(self): try: for f in self.yangFiles: @@ -59,7 +65,6 @@ def loadJsonYangModel(self): self.yJson.append(parse(xml)) self.sysLog(msg="Parsed Json for {}".format(m.name())) except Exception as e: - print('JSON conversion for yang models failed') raise e return @@ -70,7 +75,7 @@ def loadJsonYangModel(self): written using below Guidelines: https://github.com/Azure/SONiC/blob/master/doc/mgmt/SONiC_YANG_Model_Guidelines.md. """ - def createDBTableToModuleMap(self): + def _createDBTableToModuleMap(self): for j in self.yJson: # get module name @@ -109,7 +114,7 @@ def createDBTableToModuleMap(self): """ Get module, topLevelContainer(TLC) and json container for a config DB table """ - def get_module_TLC_container(self, table): + def _getModuleTLCcontainer(self, table): cmap = self.confDbYangMap m = cmap[table]['module'] t = cmap[table]['topLevelContainer'] @@ -122,7 +127,7 @@ def get_module_TLC_container(self, table): provided. The Tables without YANG models are stored in self.tablesWithOutYangModels. """ - def cropConfigDB(self, croppedFile=None): + def _cropConfigDB(self, croppedFile=None): for table in self.jIn.keys(): if table not in self.confDbYangMap: @@ -153,7 +158,7 @@ def cropConfigDB(self, croppedFile=None): Return: KeyDict = {"vlan_name": "Vlan111", "ip-prefix": "2a04:5555:45:6709::1/64"} """ - def extractKey(self, tableKey, keys, regex): + def _extractKey(self, tableKey, keys, regex): keyList = keys.split() # get the value groups @@ -173,13 +178,13 @@ def extractKey(self, tableKey, keys, regex): """ Fill the dict based on leaf as a list or dict @model yang model object """ - def fillLeafDict(self, leafs, leafDict, isleafList=False): + def _fillLeafDict(self, leafs, leafDict, isleafList=False): if leafs is None: return # fill default values - def fillSteps(leaf): + def _fillSteps(leaf): leaf['__isleafList'] = isleafList leafDict[leaf['@name']] = leaf return @@ -187,10 +192,10 @@ def fillSteps(leaf): if isinstance(leafs, list): for leaf in leafs: #print("{}:{}".format(leaf['@name'], leaf)) - fillSteps(leaf) + _fillSteps(leaf) else: #print("{}:{}".format(leaf['@name'], leaf)) - fillSteps(leafs) + _fillSteps(leafs) return @@ -199,11 +204,11 @@ def fillSteps(leaf): This is done to improve performance of mapping from values of TABLEs in config DB to leaf in YANG LIST. """ - def createLeafDict(self, model): + def _createLeafDict(self, model): leafDict = dict() #Iterate over leaf, choices and leaf-list. - self.fillLeafDict(model.get('leaf'), leafDict) + self._fillLeafDict(model.get('leaf'), leafDict) #choices, this is tricky, since leafs are under cases in tree. choices = model.get('choice') @@ -211,10 +216,10 @@ def createLeafDict(self, model): for choice in choices: cases = choice['case'] for case in cases: - self.fillLeafDict(case.get('leaf'), leafDict) + self._fillLeafDict(case.get('leaf'), leafDict) # leaf-lists - self.fillLeafDict(model.get('leaf-list'), leafDict, True) + self._fillLeafDict(model.get('leaf-list'), leafDict, True) return leafDict @@ -223,10 +228,10 @@ def createLeafDict(self, model): key in Yang model. @model : A List of Leafs in Yang model list """ - def findYangTypedValue(self, key, value, leafDict): + def _findYangTypedValue(self, key, value, leafDict): # convert config DB string to yang Type - def yangConvert(val): + def _yangConvert(val): # Convert everything to string val = str(val) # find type of this key from yang leaf @@ -248,9 +253,9 @@ def yangConvert(val): if leafDict[key]['__isleafList']: vValue = list() for v in value: - vValue.append(yangConvert(v)) + vValue.append(_yangConvert(v)) else: - vValue = yangConvert(value) + vValue = _yangConvert(value) return vValue @@ -259,12 +264,12 @@ def yangConvert(val): This function will xlate from a dict in config DB to a Yang JSON list using yang model. Output will be go in self.xlateJson """ - def xlateList(self, model, yang, config, table): + def _xlateList(self, model, yang, config, table): #create a dict to map each key under primary key with a dict yang model. #This is done to improve performance of mapping from values of TABLEs in #config DB to leaf in YANG LIST. - leafDict = self.createLeafDict(model) + leafDict = self._createLeafDict(model) # fetch regex from YANG models. keyRegEx = model['ext:key-regex-configdb-to-yang']['@value'] @@ -281,11 +286,11 @@ def xlateList(self, model, yang, config, table): self.sysLog(syslog.LOG_DEBUG, "xlateList Extract pkey:{}".\ format(pkey)) # Find and extracts key from each dict in config - keyDict = self.extractKey(pkey, listKeys, keyRegEx) + keyDict = self._extractKey(pkey, listKeys, keyRegEx) # fill rest of the values in keyDict for vKey in config[pkey]: self.sysLog(syslog.LOG_DEBUG, "xlateList vkey {}".format(vKey)) - keyDict[vKey] = self.findYangTypedValue(vKey, \ + keyDict[vKey] = self._findYangTypedValue(vKey, \ config[pkey][vKey], leafDict) yang.append(keyDict) # delete pkey from config, done to match one key with one list @@ -303,12 +308,12 @@ def xlateList(self, model, yang, config, table): Process list inside a Container. This function will call xlateList based on list(s) present in Container. """ - def xlateListInContainer(self, model, yang, configC, table): + def _xlateListInContainer(self, model, yang, configC, table): clist = model #print(clist['@name']) yang[clist['@name']] = list() self.sysLog(msg="xlateProcessListOfContainer: {}".format(clist['@name'])) - self.xlateList(clist, yang[clist['@name']], configC, table) + self._xlateList(clist, yang[clist['@name']], configC, table) # clean empty lists if len(yang[clist['@name']]) == 0: del yang[clist['@name']] @@ -320,14 +325,14 @@ def xlateListInContainer(self, model, yang, configC, table): This function will call xlateContainer based on Container(s) present in outer Container. """ - def xlateContainerInContainer(self, model, yang, configC, table): + def _xlateContainerInContainer(self, model, yang, configC, table): ccontainer = model #print(ccontainer['@name']) yang[ccontainer['@name']] = dict() if not configC.get(ccontainer['@name']): return self.sysLog(msg="xlateProcessListOfContainer: {}".format(ccontainer['@name'])) - self.xlateContainer(ccontainer, yang[ccontainer['@name']], \ + self._xlateContainer(ccontainer, yang[ccontainer['@name']], \ configC[ccontainer['@name']], table) # clean empty container if len(yang[ccontainer['@name']]) == 0: @@ -342,7 +347,7 @@ def xlateContainerInContainer(self, model, yang, configC, table): This function will xlate from a dict in config DB to a Yang JSON container using yang model. Output will be stored in self.xlateJson """ - def xlateContainer(self, model, yang, config, table): + def _xlateContainer(self, model, yang, config, table): # To Handle multiple Lists, Make a copy of config, because we delete keys # from config after each match. This is done to match one pkey with one list. @@ -352,43 +357,44 @@ def xlateContainer(self, model, yang, config, table): # If single list exists in container, if clist and isinstance(clist, dict) and \ clist['@name'] == model['@name']+"_LIST" and bool(configC): - self.xlateListInContainer(clist, yang, configC, table) + self._xlateListInContainer(clist, yang, configC, table) # If multi-list exists in container, elif clist and isinstance(clist, list) and bool(configC): for modelList in clist: - self.xlateListInContainer(modelList, yang, configC, table) + self._xlateListInContainer(modelList, yang, configC, table) # Handle container(s) in container ccontainer = model.get('container') # If single list exists in container, if ccontainer and isinstance(ccontainer, dict) and bool(configC): - self.xlateContainerInContainer(ccontainer, yang, configC, table) + self._xlateContainerInContainer(ccontainer, yang, configC, table) # If multi-list exists in container, elif ccontainer and isinstance(ccontainer, list) and bool(configC): for modelContainer in ccontainer: - self.xlateContainerInContainer(modelContainer, yang, configC, table) + self._xlateContainerInContainer(modelContainer, yang, configC, table) ## Handle other leaves in container, - leafDict = self.createLeafDict(model) + leafDict = self._createLeafDict(model) for vKey in configC.keys(): #vkey must be a leaf\leaf-list\choice in container if leafDict.get(vKey): self.sysLog(syslog.LOG_DEBUG, "xlateContainer vkey {}".format(vKey)) - yang[vKey] = self.findYangTypedValue(vKey, configC[vKey], leafDict) + yang[vKey] = self._findYangTypedValue(vKey, configC[vKey], leafDict) # delete entry from copy of config del configC[vKey] # All entries in copy of config must have been parsed. if len(configC): self.sysLog(syslog.LOG_ERR, "Alert: Remaining keys in Config") - raise(Exception("All Keys are not parsed in {}".format(table))) + raise(Exception("All Keys are not parsed in {}\n{}".format(table, \ + configC.keys()))) return """ xlate ConfigDB json to Yang json """ - def xlateConfigDBtoYang(self, jIn, yangJ): + def _xlateConfigDBtoYang(self, jIn, yangJ): # find top level container for each table, and run the xlate_container. for table in jIn.keys(): @@ -400,7 +406,7 @@ def xlateConfigDBtoYang(self, jIn, yangJ): yangJ[key] = dict() if yangJ.get(key) is None else yangJ[key] yangJ[key][subkey] = dict() self.sysLog(msg="xlateConfigDBtoYang {}:{}".format(key, subkey)) - self.xlateContainer(cmap['container'], yangJ[key][subkey], \ + self._xlateContainer(cmap['container'], yangJ[key][subkey], \ jIn[table], table) return @@ -408,12 +414,12 @@ def xlateConfigDBtoYang(self, jIn, yangJ): """ Read config file and crop it as per yang models """ - def xlateConfigDB(self, xlateFile=None): + def _xlateConfigDB(self, xlateFile=None): jIn= self.jIn yangJ = self.xlateJson # xlation is written in self.xlateJson - self.xlateConfigDBtoYang(jIn, yangJ) + self._xlateConfigDBtoYang(jIn, yangJ) if xlateFile: with open(xlateFile, 'w') as f: @@ -424,7 +430,7 @@ def xlateConfigDB(self, xlateFile=None): """ create config DB table key from entry in yang JSON """ - def createKey(self, entry, regex): + def _createKey(self, entry, regex): keyDict = dict() keyV = regex @@ -447,10 +453,10 @@ def createKey(self, entry, regex): key in Yang model. @model : A List of Leafs in Yang model list """ - def revFindYangTypedValue(self, key, value, leafDict): + def _revFindYangTypedValue(self, key, value, leafDict): # convert yang Type to config DB string - def revYangConvert(val): + def _revYangConvert(val): # config DB has only strings, thank god for that :), wait not yet!!! return str(val) @@ -458,16 +464,16 @@ def revYangConvert(val): if leafDict[key]['__isleafList']: vValue = list() for v in value: - vValue.append(revYangConvert(v)) + vValue.append(_revYangConvert(v)) else: - vValue = revYangConvert(value) + vValue = _revYangConvert(value) return vValue """ Rev xlate from _LIST to table in config DB """ - def revXlateList(self, model, yang, config, table): + def _revXlateList(self, model, yang, config, table): # fetch regex from YANG models keyRegEx = model['ext:key-regex-yang-to-configdb']['@value'] @@ -476,19 +482,19 @@ def revXlateList(self, model, yang, config, table): # create a dict to map each key under primary key with a dict yang model. # This is done to improve performance of mapping from values of TABLEs in # config DB to leaf in YANG LIST. - leafDict = self.createLeafDict(model) + leafDict = self._createLeafDict(model) # list with name _LIST should be removed, if "_LIST" in model['@name']: for entry in yang: # create key of config DB table - pkey, pkeydict = self.createKey(entry, keyRegEx) + pkey, pkeydict = self._createKey(entry, keyRegEx) self.sysLog(syslog.LOG_DEBUG, "revXlateList pkey:{}".format(pkey)) config[pkey]= dict() # fill rest of the entries for key in entry: if key not in pkeydict: - config[pkey][key] = self.revFindYangTypedValue(key, \ + config[pkey][key] = self._revFindYangTypedValue(key, \ entry[key], leafDict) return @@ -496,64 +502,64 @@ def revXlateList(self, model, yang, config, table): """ Rev xlate a list inside a yang container """ - def revXlateListInContainer(self, model, yang, config, table): + def _revXlateListInContainer(self, model, yang, config, table): modelList = model # Pass matching list from Yang Json if exist if yang.get(modelList['@name']): self.sysLog(msg="revXlateListInContainer {}".format(modelList['@name'])) - self.revXlateList(modelList, yang[modelList['@name']], config, table) + self._revXlateList(modelList, yang[modelList['@name']], config, table) return """ Rev xlate a container inside a yang container """ - def revXlateContainerInContainer(self, model, yang, config, table): + def _revXlateContainerInContainer(self, model, yang, config, table): modelContainer = model # Pass matching list from Yang Json if exist if yang.get(modelContainer['@name']): config[modelContainer['@name']] = dict() self.sysLog(msg="revXlateContainerInContainer {}".format(modelContainer['@name'])) - self.revXlateContainer(modelContainer, yang[modelContainer['@name']], \ + self._revXlateContainer(modelContainer, yang[modelContainer['@name']], \ config[modelContainer['@name']], table) return """ Rev xlate from yang container to table in config DB """ - def revXlateContainer(self, model, yang, config, table): + def _revXlateContainer(self, model, yang, config, table): # IF container has only one list clist = model.get('list') if isinstance(clist, dict): - self.revXlateListInContainer(clist, yang, config, table) + self._revXlateListInContainer(clist, yang, config, table) # IF container has lists elif isinstance(clist, list): for modelList in clist: - self.revXlateListInContainer(modelList, yang, config, table) + self._revXlateListInContainer(modelList, yang, config, table) ccontainer = model.get('container') # IF container has only one inner container if isinstance(ccontainer, dict): - self.revXlateContainerInContainer(ccontainer, yang, config, table) + self._revXlateContainerInContainer(ccontainer, yang, config, table) # IF container has only many inner container elif isinstance(ccontainer, list): for modelContainer in ccontainer: - self.revXlateContainerInContainer(modelContainer, yang, config, table) + self._revXlateContainerInContainer(modelContainer, yang, config, table) ## Handle other leaves in container, - leafDict = self.createLeafDict(model) + leafDict = self._createLeafDict(model) for vKey in yang: #vkey must be a leaf\leaf-list\choice in container if leafDict.get(vKey): self.sysLog(syslog.LOG_DEBUG, "revXlateContainer vkey {}".format(vKey)) - config[vKey] = self.revFindYangTypedValue(vKey, yang[vKey], leafDict) + config[vKey] = self._revFindYangTypedValue(vKey, yang[vKey], leafDict) return """ rev xlate ConfigDB json to Yang json """ - def revXlateYangtoConfigDB(self, yangJ, cDbJson): + def _revXlateYangtoConfigDB(self, yangJ, cDbJson): yangJ = self.xlateJson cDbJson = self.revXlateJson @@ -569,7 +575,7 @@ def revXlateYangtoConfigDB(self, yangJ, cDbJson): cDbJson[table] = dict() #print(key + "--" + subkey) self.sysLog(msg="revXlateYangtoConfigDB {}".format(table)) - self.revXlateContainer(cmap['container'], yangJ[module_top][container], \ + self._revXlateContainer(cmap['container'], yangJ[module_top][container], \ cDbJson[table], table) return @@ -577,12 +583,12 @@ def revXlateYangtoConfigDB(self, yangJ, cDbJson): """ Reverse Translate tp config DB """ - def revXlateConfigDB(self, revXlateFile=None): + def _revXlateConfigDB(self, revXlateFile=None): yangJ = self.xlateJson cDbJson = self.revXlateJson # xlation is written in self.xlateJson - self.revXlateYangtoConfigDB(yangJ, cDbJson) + self._revXlateYangtoConfigDB(yangJ, cDbJson) if revXlateFile: with open(revXlateFile, 'w') as f: @@ -596,7 +602,7 @@ def revXlateConfigDB(self, revXlateFile=None): l = list name return: list if found else None """ - def findYangList(self, container, listName): + def _findYangList(self, container, listName): if isinstance(container['list'], dict): clist = container['list'] @@ -611,38 +617,37 @@ def findYangList(self, container, listName): """ Find xpath of the PORT Leaf in PORT container/list. Xpath of Leaf is needed, - because only leaf can have leafrefs depend on them. + because only leaf can have leafrefs depend on them. (Public) """ def findXpathPortLeaf(self, portName): try: table = "PORT" xpath = self.findXpathPort(portName) - module, topc, container = self.get_module_TLC_container(table) - list = self.findYangList(container, table+"_LIST") + module, topc, container = self._getModuleTLCcontainer(table) + list = self._findYangList(container, table+"_LIST") xpath = xpath + "/" + list['key']['@value'].split()[0] except Exception as e: print("find xpath of port Leaf failed") - raise e + raise SonicYangException("find xpath of port Leaf failed\n{}".format(str(e))) return xpath - """ - Find xpath of PORT + Find xpath of PORT. (Public) """ def findXpathPort(self, portName): try: table = "PORT" - module, topc, container = self.get_module_TLC_container(table) + module, topc, container = self._getModuleTLCcontainer(table) xpath = "/" + module + ":" + topc + "/" + table - list = self.findYangList(container, table+"_LIST") - xpath = self.findXpathList(xpath, list, [portName]) + list = self._findYangList(container, table+"_LIST") + xpath = self._findXpathList(xpath, list, [portName]) except Exception as e: print("find xpath of port failed") - raise e + raise SonicYangException("find xpath of port failed\n{}".format(str(e))) return xpath @@ -652,7 +657,7 @@ def findXpathPort(self, portName): list: YANG List keys: list of keys in YANG LIST """ - def findXpathList(self, xpath, list, keys): + def _findXpathList(self, xpath, list, keys): try: # add list name in xpath @@ -663,17 +668,16 @@ def findXpathList(self, xpath, list, keys): xpath = xpath + '['+listKey+'=\''+keys[i]+'\']' i = i + 1 except Exception as e: - print("find xpath of list failed") raise e return xpath """ - load_data: load Config DB, crop, xlate and create data tree from it. + load_data: load Config DB, crop, xlate and create data tree from it. (Public) input: data returns: True - success False - failed """ - def load_data(self, configdbJson): + def loadData(self, configdbJson): try: self.jIn = configdbJson @@ -681,9 +685,9 @@ def load_data(self, configdbJson): self.xlateJson = dict() self.tablesWithOutYang = dict() # self.jIn will be cropped - self.cropConfigDB() + self._cropConfigDB() # xlated result will be in self.xlateJson - self.xlateConfigDB() + self._xlateConfigDB() #print(self.xlateJson) self.sysLog(msg="Try to load Data in the tree") self.root = self.ctx.parse_data_mem(dumps(self.xlateJson), \ @@ -692,37 +696,38 @@ def load_data(self, configdbJson): except Exception as e: self.root = None print("Data Loading Failed") - raise e + raise SonicYangException("Data Loading Failed\n{}".format(str(e))) return True """ - Get data from Data tree, data tree will be assigned in self.xlateJson + Get data from Data tree, data tree will be assigned in self.xlateJson. (Public) """ - def get_data(self): + def getData(self): try: - self.xlateJson = loads(self.print_data_mem('JSON')) + self.xlateJson = loads(self._print_data_mem('JSON')) # reset reverse xlate self.revXlateJson = dict() # result will be stored self.revXlateJson - self.revXlateConfigDB() + self._revXlateConfigDB() except Exception as e: print("Get Data Tree Failed") - raise e + raise SonicYangException("Get Data Tree Failed\n{}".format(str(e))) return self.revXlateJson """ - Delete a node from data tree, if this is LEAF and KEY Delete the Parent + Delete a node from data tree, if this is LEAF and KEY Delete the Parent. + (Public) """ - def delete_node(self, xpath): + def deleteNode(self, xpath): # These MACROS used only here, can we get it from Libyang Header ? try: LYS_LEAF = 4 - node = self.find_data_node(xpath) + node = self._find_data_node(xpath) if node is None: raise('Node {} not found'.format(xpath)) @@ -732,19 +737,19 @@ def delete_node(self, xpath): leaf = ly.Schema_Node_Leaf(snode) if leaf.is_key(): # try to delete parent - nodeP = self.find_parent_node(xpath) + nodeP = self._find_parent_data_node(xpath) xpathP = nodeP.path() - if self._delete_node(xpath=xpathP, node=nodeP) == False: - raise Exception('_delete_node failed') + if self._deleteNode(xpath=xpathP, node=nodeP) == False: + raise Exception('_deleteNode failed') else: return True # delete non key element - if self._delete_node(xpath=xpath, node=node) == False: - raise Exception('_delete_node failed') + if self._deleteNode(xpath=xpath, node=node) == False: + raise Exception('_deleteNode failed') except Exception as e: - print(e) - raise Exception('Failed to delete node {}'.format(xpath)) + raise SonicYangException("Failed to delete node {}\n{}".\ + format( xpath, str(e))) return True diff --git a/src/sonic-yang-mgmt/tests/libyang-python-tests/test_sonic_yang.py b/src/sonic-yang-mgmt/tests/libyang-python-tests/test_sonic_yang.py index 3a470ddd056a..b5fa35842990 100644 --- a/src/sonic-yang-mgmt/tests/libyang-python-tests/test_sonic_yang.py +++ b/src/sonic-yang-mgmt/tests/libyang-python-tests/test_sonic_yang.py @@ -28,7 +28,7 @@ def data(self): @pytest.fixture(autouse=True, scope='class') def yang_s(self, data): yang_dir = str(data['yang_dir']) - yang_s = sy.sonic_yang(yang_dir) + yang_s = sy.SonicYang(yang_dir) return yang_s def jsonTestParser(self, file): @@ -64,7 +64,7 @@ def setup_class(self): def load_yang_model_file(self, yang_s, yang_dir, yang_file, module_name): yfile = yang_dir + yang_file try: - yang_s.load_schema_module(str(yfile)) + yang_s._load_schema_module(str(yfile)) except Exception as e: print(e) raise @@ -77,7 +77,7 @@ def test_load_yang_model_files(self, data, yang_s): module = str(module['module']) self.load_yang_model_file(yang_s, yang_dir, file, module) - assert yang_s.get_module(module) is not None + assert yang_s._get_module(module) is not None #test load non-exist yang module file def test_load_invalid_model_files(self, data, yang_s): @@ -91,10 +91,10 @@ def test_load_invalid_model_files(self, data, yang_s): #test load yang modules in directory def test_load_yang_model_dir(self, data, yang_s): yang_dir = data['yang_dir'] - yang_s.load_schema_modules(str(yang_dir)) + yang_s._load_schema_modules(str(yang_dir)) for module_name in data['modules']: - assert yang_s.get_module(str(module_name['module'])) is not None + assert yang_s._get_module(str(module_name['module'])) is not None #test load yang modules and data files def test_load_yang_model_data(self, data, yang_s): @@ -107,19 +107,19 @@ def test_load_yang_model_data(self, data, yang_s): data_files.append(data_file) data_files.append(data_merge_file) print(yang_files) - yang_s.load_data_model(yang_dir, yang_files, data_files) + yang_s._load_data_model(yang_dir, yang_files, data_files) #validate the data tree from data_merge_file is loaded for node in data['merged_nodes']: xpath = str(node['xpath']) value = str(node['value']) - val = yang_s.find_data_node_value(xpath) + val = yang_s._find_data_node_value(xpath) assert str(val) == str(value) #test load data file def test_load_data_file(self, data, yang_s): data_file = str(data['data_file']) - yang_s.load_data_file(data_file) + yang_s._load_data_file(data_file) #test_validate_data_tree(): def test_validate_data_tree(self, data, yang_s): @@ -130,7 +130,7 @@ def test_find_node(self, data, yang_s): for node in data['data_nodes']: expected = node['valid'] xpath = str(node['xpath']) - dnode = yang_s.find_data_node(xpath) + dnode = yang_s._find_data_node(xpath) if(expected == "True"): assert dnode is not None @@ -143,9 +143,9 @@ def test_add_node(self, data, yang_s): for node in data['new_nodes']: xpath = str(node['xpath']) value = node['value'] - yang_s.add_data_node(xpath, str(value)) + yang_s._add_data_node(xpath, str(value)) - data_node = yang_s.find_data_node(xpath) + data_node = yang_s._find_data_node(xpath) assert data_node is not None #test find node value @@ -155,23 +155,23 @@ def test_find_data_node_value(self, data, yang_s): value = str(node['value']) print(xpath) print(value) - val = yang_s.find_data_node_value(xpath) + val = yang_s._find_data_node_value(xpath) assert str(val) == str(value) #test delete data node def test_delete_node(self, data, yang_s): for node in data['delete_nodes']: xpath = str(node['xpath']) - yang_s._delete_node(xpath) + yang_s._deleteNode(xpath) #test set node's value def test_set_datanode_value(self, data, yang_s): for node in data['set_nodes']: xpath = str(node['xpath']) value = node['value'] - yang_s.set_data_node_value(xpath, value) + yang_s._set_data_node_value(xpath, value) - val = yang_s.find_data_node_value(xpath) + val = yang_s._find_data_node_value(xpath) assert str(val) == str(value) #test list of members @@ -179,7 +179,7 @@ def test_find_members(self, yang_s, data): for node in data['members']: members = node['members'] xpath = str(node['xpath']) - list = yang_s.find_data_nodes(xpath) + list = yang_s._find_data_nodes(xpath) assert list.sort() == members.sort() #get parent xpath @@ -187,7 +187,7 @@ def test_get_parent_data_xpath(self, yang_s, data): for node in data['parents']: xpath = str(node['xpath']) expected_xpath = str(node['parent']) - path = yang_s.get_parent_data_xpath(xpath) + path = yang_s._get_parent_data_xpath(xpath) assert path == expected_xpath #test find_data_node_schema_xpath @@ -195,7 +195,7 @@ def test_find_data_node_schema_xpath(self, yang_s, data): for node in data['schema_nodes']: xpath = str(node['xpath']) schema_xpath = str(node['value']) - path = yang_s.find_data_node_schema_xpath(xpath) + path = yang_s._find_data_node_schema_xpath(xpath) assert path == schema_xpath #test data dependencies @@ -211,14 +211,14 @@ def test_find_schema_dependencies(self, yang_s, data): for node in data['schema_dependencies']: xpath = str(node['xpath']) list = node['schema_dependencies'] - depend = yang_s.find_schema_dependencies(xpath) + depend = yang_s._find_schema_dependencies(xpath) assert set(depend) == set(list) #test merge data tree def test_merge_data_tree(self, data, yang_s): data_merge_file = data['data_merge_file'] yang_dir = str(data['yang_dir']) - yang_s.merge_data(data_merge_file, yang_dir) + yang_s._merge_data(data_merge_file, yang_dir) #yang_s.root.print_mem(ly.LYD_JSON, ly.LYP_FORMAT) #test get module prefix @@ -226,7 +226,7 @@ def test_get_module_prefix(self, yang_s, data): for node in data['prefix']: xpath = str(node['module_name']) expected = node['module_prefix'] - prefix = yang_s.get_module_prefix(xpath) + prefix = yang_s._get_module_prefix(xpath) assert expected == prefix #test get data type @@ -234,31 +234,31 @@ def test_get_data_type(self, yang_s, data): for node in data['data_type']: xpath = str(node['xpath']) expected = node['data_type'] - expected_type = yang_s.str_to_type(expected) - data_type = yang_s.get_data_type(xpath) + expected_type = yang_s._str_to_type(expected) + data_type = yang_s._get_data_type(xpath) assert expected_type == data_type def test_get_leafref_type(self, yang_s, data): for node in data['leafref_type']: xpath = str(node['xpath']) expected = node['data_type'] - expected_type = yang_s.str_to_type(expected) - data_type = yang_s.get_leafref_type(xpath) + expected_type = yang_s._str_to_type(expected) + data_type = yang_s._get_leafref_type(xpath) assert expected_type == data_type def test_get_leafref_path(self, yang_s, data): for node in data['leafref_path']: xpath = str(node['xpath']) expected_path = node['leafref_path'] - path = yang_s.get_leafref_path(xpath) + path = yang_s._get_leafref_path(xpath) assert expected_path == path def test_get_leafref_type_schema(self, yang_s, data): for node in data['leafref_type_schema']: xpath = str(node['xpath']) expected = node['data_type'] - expected_type = yang_s.str_to_type(expected) - data_type = yang_s.get_leafref_type_schema(xpath) + expected_type = yang_s._str_to_type(expected) + data_type = yang_s._get_leafref_type_schema(xpath) assert expected_type == data_type """ @@ -271,7 +271,7 @@ def sonic_yang_data(self): sonic_yang_dir = "../sonic-yang-models/yang-models/" sonic_yang_test_file = "../sonic-yang-models/tests/yang_model_tests/yangTest.json" - syc = sy.sonic_yang(sonic_yang_dir) + syc = sy.SonicYang(sonic_yang_dir) syc.loadYangModel() sonic_yang_data = dict() @@ -289,11 +289,11 @@ def test_xlate_rev_xlate(self, sonic_yang_data): jIn = self.readIjsonInput(test_file, 'SAMPLE_CONFIG_DB_JSON') - syc.load_data(json.loads(jIn)) + syc.loadData(json.loads(jIn)) # TODO: Make sure no extra table is loaded - syc.get_data() + syc.getData() if syc.jIn and syc.jIn == syc.revXlateJson: print("Xlate and Rev Xlate Passed") @@ -312,7 +312,7 @@ def test_table_with_no_yang(self, sonic_yang_data): jIn = self.readIjsonInput(test_file, 'SAMPLE_CONFIG_DB_JSON_1') - syc.load_data(json.loads(jIn)) + syc.loadData(json.loads(jIn)) ty = syc.tablesWithOutYang