@@ -129,31 +129,28 @@ def cropConfigDB(self, croppedFile=None, allowExtraTables=True):
129129
130130"""
131131Extract keys from table entry in Config DB and return in a dict
132- For Example: regex = <vlan_name>| and tableKey = "Vlan111|2a04:5555:45:6709::1/64"
133132
134- 1.) first code will extract key list from regex, i.e. vlan_name and ip_prefix.
135- 2.) then will create another regex(regexV) to extract Values from tableKey by
136- replacing " --> extractor i.e. (.*?)" in regex.
137- 3.) Then will extract values from tableKey with regexV.
138- 4.) Resulting Dict will be:
133+ Input:
134+ tableKey: Config DB Primary Key, Example tableKey = "Vlan111|2a04:5555:45:6709::1/64"
135+ keys: key string from YANG list, i.e. 'vlan_name ip-prefix'.
136+ regex: A regex to extract keys from tableKeys, good to have it as accurate as possible.
137+
138+ Return:
139139KeyDict = {"vlan_name": "Vlan111", "ip-prefix": "2a04:5555:45:6709::1/64"}
140140"""
141- def extractKey (self , tableKey , regex ):
141+ def extractKey (self , tableKey , keys , regex ):
142142
143- # get the keys from regex of key extractor
144- keyList = re .findall (r'<(.*?)>' , regex )
145- # create a regex to get values from tableKey
146- # and change separator to text in regexV
147- regexV = re .sub ('<.*?>' , '(.*?)' , regex )
148- regexV = re .sub ('\|' , '\\ |' , regexV )
143+ keyList = keys .split ()
144+ #self.logInFile("extractKey {}".format(keyList))
149145 # get the value groups
150- value = re .match (r'^' + regexV + '$' , tableKey )
146+ value = re .match (regex , tableKey )
151147 # create the keyDict
152148 i = 1
153149 keyDict = dict ()
154150 for k in keyList :
155151 if value .group (i ):
156152 keyDict [k ] = value .group (i )
153+ # self.logInFile("extractKey {} {}".format(k, keyDict[k]))
157154 else :
158155 raise Exception ("Value not found for {} in {}" .format (k , tableKey ))
159156 i = i + 1
@@ -254,37 +251,49 @@ def xlateList(self, model, yang, config, table):
254251 # TODO: define a keyExt dict as of now, but we should be able to extract
255252 # this from YANG model extentions.
256253 keyExt = {
257- "VLAN_INTERFACE" : "<vlan_name>|<ip-prefix>" ,
258- "ACL_RULE" : "<ACL_TABLE_NAME>|<RULE_NAME>" ,
259- "VLAN" : "<vlan_name>" ,
260- "VLAN_MEMBER" : "<vlan_name>|<port>" ,
261- "ACL_TABLE" : "<ACL_TABLE_NAME>" ,
262- "INTERFACE" : "<interface>|<ip-prefix>" ,
263- "PORT" : "<port_name>"
254+ "VLAN_INTERFACE_LIST" : "^(Vlan[a-zA-Z0-9_-]+)$" ,
255+ "VLAN_LIST" : "^(Vlan[a-zA-Z0-9_-]+)$" ,
256+ "VLAN_INTERFACE_IPPREFIX_LIST" : "^(Vlan[a-zA-Z0-9_-]+)\|([a-fA-F0-9:./]+$)" ,
257+ "VLAN_MEMBER_LIST" : "^(Vlan[a-zA-Z0-9-_]+)\|(Ethernet[0-9]+)$" ,
258+ "ACL_RULE_LIST" : "^([a-zA-Z0-9_-]+)\|([a-zA-Z0-9_-]+)$" ,
259+ "ACL_TABLE_LIST" : "^([a-zA-Z0-9-_]+)$" ,
260+ "INTERFACE_LIST" : "^(Ethernet[0-9]+)$" ,
261+ "INTERFACE_IPPREFIX_LIST" : "^(Ethernet[0-9]+)\|([a-fA-F0-9:./]+)$" ,
262+ "PORT_LIST" : "^(Ethernet[0-9]+)$" ,
263+ "LOOPBACK_INTERFACE_LIST" : "^([a-zA-Z0-9-_]+)$" ,
264+ "LOOPBACK_INTERFACE_IPPREFIX_LIST" : "^([a-zA-Z0-9-_]+)\|([a-fA-F0-9:./]+)$" ,
264265 }
265266 #create a dict to map each key under primary key with a dict yang model.
266267 #This is done to improve performance of mapping from values of TABLEs in
267268 #config DB to leaf in YANG LIST.
268269
269270 leafDict = self .createLeafDict (model )
270271
271- self .logInFile ("Xlate {}" .format (table ))
272- # Find and extracts key from each dict in config
273- for pkey in config :
272+ keyRegEx = keyExt [model ['@name' ]]
273+ # get keys from YANG model list itself
274+ listKeys = model ['key' ]['@value' ]
275+
276+ for pkey in config .keys ():
274277 try :
275278 vKey = None
276- self .logInFile ("xlate Extract pkey {} {}" .format (pkey ,keyExt [table ]))
277- keyDict = self .extractKey (pkey , keyExt [table ])
279+ self .logInFile ("xlateList Extract pkey {}" .format (pkey ))
280+ # Find and extracts key from each dict in config
281+ keyDict = self .extractKey (pkey , listKeys , keyRegEx )
278282 # fill rest of the values in keyDict
279283 for vKey in config [pkey ]:
280- self .logInFile ("xlate vkey {}" .format (vKey ), keyExt [ table ] )
284+ self .logInFile ("xlateList vkey {}" .format (vKey ))
281285 keyDict [vKey ] = self .findYangTypedValue (vKey , \
282286 config [pkey ][vKey ], leafDict )
283287 yang .append (keyDict )
288+ # delete pkey from config, done to match one key with one list
289+ del config [pkey ]
290+
284291 except Exception as e :
285- print ("Exception while Config DB --> YANG: pkey:{}, " \
292+ self .logInFile ("xlateList Exception {}" .format (e ))
293+ self .logInFile ("Exception while Config DB --> YANG: pkey:{}, " \
286294 "vKey:{}, value: {}" .format (pkey , vKey , config [pkey ].get (vKey )))
287- raise e
295+ # with multilist, we continue matching other keys.
296+ continue
288297
289298 return
290299
@@ -295,19 +304,36 @@ def xlateList(self, model, yang, config, table):
295304"""
296305def xlateContainer (self , model , yang , config , table ):
297306
298- # if container contains single list with containerName_LIST and
299- # config is not empty then xLate the list
307+ # To Handle mupltiple, Make a copy of config, because we delete keys
308+ # from config after each match. This is done to match one pkey with one list.
309+ configC = config .copy ()
310+
300311 clist = model .get ('list' )
312+ # If single list exists in container,
301313 if clist and isinstance (clist , dict ) and \
302- clist ['@name' ] == model ['@name' ]+ "_LIST" and bool (config ):
314+ clist ['@name' ] == model ['@name' ]+ "_LIST" and bool (configC ):
303315 #print(clist['@name'])
304316 yang [clist ['@name' ]] = list ()
305- self .xlateList (model ['list' ], yang [clist ['@name' ]], \
306- config , table )
317+ self .logInFile ("xlateContainer listD {}" .format (clist ['@name' ]))
318+ self .xlateList (clist , yang [clist ['@name' ]], \
319+ configC , table )
320+ # clean empty lists
321+ if len (yang [clist ['@name' ]]) == 0 :
322+ del yang [clist ['@name' ]]
307323 #print(yang[clist['@name']])
308324
309- # TODO: Handle mupltiple list and rest of the field in Container.
310- # We do not have any such instance in Yang model today.
325+ # If multi-list exists in container,
326+ elif clist and isinstance (clist , list ) and bool (configC ):
327+ for modelList in clist :
328+ yang [modelList ['@name' ]] = list ()
329+ self .logInFile ("xlateContainer listL {}" .format (modelList ['@name' ]))
330+ self .xlateList (modelList , yang [modelList ['@name' ]], configC , table )
331+ # clean empty lists
332+ if len (yang [modelList ['@name' ]]) == 0 :
333+ del yang [modelList ['@name' ]]
334+
335+ if len (configC ):
336+ raise (Exception ("All Keys are not parsed in {}" .format (table )))
311337
312338 return
313339
@@ -325,6 +351,7 @@ def xlateConfigDBtoYang(self, jIn, yangJ):
325351 # Add new top level container for first table in this container
326352 yangJ [key ] = dict () if yangJ .get (key ) is None else yangJ [key ]
327353 yangJ [key ][subkey ] = dict ()
354+ self .logInFile ("xlateConfigDBtoYang {}:{}" .format (key , subkey ))
328355 self .xlateContainer (cmap ['container' ], yangJ [key ][subkey ], \
329356 jIn [table ], table )
330357
@@ -389,7 +416,6 @@ def revYangConvert(val):
389416
390417 return vValue
391418
392-
393419"""
394420Rev xlate from <TABLE>_LIST to table in config DB
395421"""
@@ -398,26 +424,31 @@ def revXlateList(self, model, yang, config, table):
398424 # TODO: define a keyExt dict as of now, but we should be able to
399425 # extract this from YANG model extentions.
400426 keyExt = {
401- "VLAN_INTERFACE" : "<vlan_name>|<ip-prefix>" ,
402- "ACL_RULE" : "<ACL_TABLE_NAME>|<RULE_NAME>" ,
403- "VLAN" : "<vlan_name>" ,
404- "VLAN_MEMBER" : "<vlan_name>|<port>" ,
405- "ACL_TABLE" : "<ACL_TABLE_NAME>" ,
406- "INTERFACE" : "<interface>|<ip-prefix>" ,
407- "PORT" : "<port_name>"
427+ "VLAN_INTERFACE_IPPREFIX_LIST" : "<vlan_name>|<ip-prefix>" ,
428+ "VLAN_INTERFACE_LIST" : "<vlan_name>" ,
429+ "VLAN_MEMBER_LIST" : "<vlan_name>|<port>" ,
430+ "VLAN_LIST" : "<vlan_name>" ,
431+ "ACL_RULE_LIST" : "<ACL_TABLE_NAME>|<RULE_NAME>" ,
432+ "ACL_TABLE_LIST" : "<ACL_TABLE_NAME>" ,
433+ "INTERFACE_LIST" : "<port_name>" ,
434+ "INTERFACE_IPPREFIX_LIST" : "<port_name>|<ip-prefix>" ,
435+ "LOOPBACK_INTERFACE_LIST" : "<loopback_interface_name>" ,
436+ "LOOPBACK_INTERFACE_IPPREFIX_LIST" : "<loopback_interface_name>|<ip-prefix>" ,
437+ "PORT_LIST" : "<port_name>"
438+
408439 }
409440
441+ keyRegEx = keyExt [model ['@name' ]]
410442 # create a dict to map each key under primary key with a dict yang model.
411443 # This is done to improve performance of mapping from values of TABLEs in
412444 # config DB to leaf in YANG LIST.
413445 leafDict = self .createLeafDict (model )
414446
415- # list with name <TABLE>_LIST should be removed,
416- # right now we have only this instance of LIST
417- if model ['@name' ] == table + "_LIST" :
447+ # list with name <NAME>_LIST should be removed,
448+ if "_LIST" in model ['@name' ]:
418449 for entry in yang :
419450 # create key of config DB table
420- pkey , pkeydict = self .createKey (entry , keyExt [ table ] )
451+ pkey , pkeydict = self .createKey (entry , keyRegEx )
421452 config [pkey ]= dict ()
422453 # fill rest of the entries
423454 for key in entry :
@@ -438,9 +469,8 @@ def revXlateContainer(self, model, yang, config, table):
438469 modelList = model ['list' ]
439470 # Pass matching list from Yang Json
440471 self .revXlateList (modelList , yang [modelList ['@name' ]], config , table )
441- else :
442- # TODO: Container[TABLE] contains multiple lists. [Test Pending]
443- # No instance now.
472+
473+ elif isinstance (model ['list' ], list ):
444474 for modelList in model ['list' ]:
445475 self .revXlateList (modelList , yang [modelList ['@name' ]], config , table )
446476
@@ -575,10 +605,11 @@ def load_data(self, configdbJson, allowExtraTables=True):
575605 # reset xlate
576606 self .xlateJson = dict ()
577607 # self.jIn will be cropped
578- self .cropConfigDB ("cropped.json" , allowExtraTables )
608+ self .cropConfigDB (allowExtraTables = allowExtraTables )
579609 # xlated result will be in self.xlateJson
580610 self .xlateConfigDB ()
581611 #print(self.xlateJson)
612+ self .logInFile ("Try to load Data in the tree" )
582613 self .root = self .ctx .parse_data_mem (dumps (self .xlateJson ), \
583614 ly .LYD_JSON , ly .LYD_OPT_CONFIG | ly .LYD_OPT_STRICT )
584615
0 commit comments