# # This file is part of pysmi software. # # Copyright (c) 2015-2019, Ilya Etingof # License: http://snmplabs.com/pysmi/license.html # import sys import re from time import strptime, strftime try: import json except ImportError: import simplejson as json try: from collections import OrderedDict except ImportError: from ordereddict import OrderedDict from pysmi.mibinfo import MibInfo from pysmi.codegen.base import AbstractCodeGen from pysmi import error from pysmi import debug if sys.version_info[0] > 2: # noinspection PyShadowingBuiltins unicode = str # noinspection PyShadowingBuiltins long = int class JsonCodeGen(AbstractCodeGen): """Builds JSON document representing MIB module supplied in form of an Abstract Syntax Tree on input. Instance of this class is supposed to be passed to *MibCompiler*, the rest is internal to *MibCompiler*. """ constImports = { 'SNMPv2-SMI': ('iso', 'NOTIFICATION-TYPE', # bug in some MIBs (e.g. A3COM-HUAWEI-DHCPSNOOP-MIB) 'MODULE-IDENTITY', 'OBJECT-TYPE', 'OBJECT-IDENTITY'), 'SNMPv2-TC': ('DisplayString', 'TEXTUAL-CONVENTION',), # XXX 'SNMPv2-CONF': ('MODULE-COMPLIANCE', 'NOTIFICATION-GROUP',), # XXX } # never compile these, they either: # - define MACROs (implementation supplies them) # - or carry conflicting OIDs (so that all IMPORT's of them will be rewritten) # - or have manual fixes # - or import base ASN.1 types from implementation-specific MIBs fakeMibs = ('ASN1', 'ASN1-ENUMERATION', 'ASN1-REFINEMENT') + AbstractCodeGen.baseMibs baseTypes = ['Integer', 'Integer32', 'Bits', 'ObjectIdentifier', 'OctetString'] typeClasses = { 'NetworkAddress': 'IpAddress', # RFC1065-SMI, RFC1155-SMI -> SNMPv2-SMI 'nullSpecific': 'zeroDotZero', # RFC1158-MIB -> SNMPv2-SMI 'ipRoutingTable': 'ipRouteTable', # RFC1158-MIB -> RFC1213-MIB 'snmpEnableAuthTraps': 'snmpEnableAuthenTraps' # RFC1158-MIB -> SNMPv2-MIB } smiv1IdxTypes = ['INTEGER', 'OCTET STRING', 'IPADDRESS', 'NETWORKADDRESS'] indent = ' ' * 4 fakeidx = 1000 # starting index for fake symbols def __init__(self): self._rows = set() self._cols = {} # k, v = name, datatype self._seenSyms = set() self._importMap = {} self._out = {} # k, v = name, generated code self._moduleIdentityOid = None self._moduleRevision = None self._enterpriseOid = None self._oids = set() self._complianceOids = [] self.moduleName = ['DUMMY'] self.genRules = {'text': True} self.symbolTable = {} @staticmethod def transOpers(symbol): return symbol.replace('-', '_') def prepData(self, pdata): data = [] for el in pdata: if not isinstance(el, tuple): data.append(el) elif len(el) == 1: data.append(el[0]) else: data.append( self.handlersTable[el[0]](self, self.prepData(el[1:])) ) return data def genImports(self, imports): # convertion to SNMPv2 toDel = [] for module in list(imports): if module in self.convertImportv2: for symbol in imports[module]: if symbol in self.convertImportv2[module]: toDel.append((module, symbol)) for newImport in self.convertImportv2[module][symbol]: newModule, newSymbol = newImport if newModule in imports: imports[newModule].append(newSymbol) else: imports[newModule] = [newSymbol] # removing converted symbols for d in toDel: imports[d[0]].remove(d[1]) # merging mib and constant imports for module in self.constImports: if module in imports: imports[module] += self.constImports[module] else: imports[module] = self.constImports[module] outDict = OrderedDict() outDict['class'] = 'imports' for module in sorted(imports): symbols = [] for symbol in set(imports[module]): symbols.append(symbol) if symbols: self._seenSyms.update( [self.transOpers(s) for s in symbols] ) self._importMap.update( [(self.transOpers(s), module) for s in symbols] ) if module not in outDict: outDict[module] = [] outDict[module].extend(symbols) return OrderedDict(imports=outDict), tuple(sorted(imports)) # noinspection PyMethodMayBeStatic def genLabel(self, symbol): return '-' in symbol and symbol or '' def addToExports(self, symbol, moduleIdentity=0): self._seenSyms.add(symbol) # noinspection PyUnusedLocal def regSym(self, symbol, outDict, parentOid=None, moduleIdentity=False, moduleCompliance=False): if symbol in self._seenSyms and symbol not in self._importMap: raise error.PySmiSemanticError('Duplicate symbol found: %s' % symbol) self.addToExports(symbol, moduleIdentity) self._out[symbol] = outDict if 'oid' in outDict: self._oids.add(outDict['oid']) if not self._enterpriseOid and outDict['oid'].startswith('1.3.6.1.4.1.'): self._enterpriseOid = '.'.join(outDict['oid'].split('.')[:7]) if moduleIdentity: if self._moduleIdentityOid: raise error.PySmiSemanticError('Duplicate module identity') self._moduleIdentityOid = outDict['oid'] if moduleCompliance: self._complianceOids.append(outDict['oid']) def genNumericOid(self, oid): numericOid = () for part in oid: if isinstance(part, tuple): parent, module = part if parent == 'iso': numericOid += (1,) continue if module not in self.symbolTable: # XXX do getname for possible future borrowed mibs raise error.PySmiSemanticError('no module "%s" in symbolTable' % module) if parent not in self.symbolTable[module]: raise error.PySmiSemanticError('no symbol "%s" in module "%s"' % (parent, module)) numericOid += self.genNumericOid(self.symbolTable[module][parent]['oid']) else: numericOid += (part,) return numericOid def getBaseType(self, symName, module): if module not in self.symbolTable: raise error.PySmiSemanticError('no module "%s" in symbolTable' % module) if symName not in self.symbolTable[module]: raise error.PySmiSemanticError('no symbol "%s" in module "%s"' % (symName, module)) symType, symSubtype = self.symbolTable[module][symName].get('syntax', (('', ''), '')) if not symType[0]: raise error.PySmiSemanticError('unknown type for symbol "%s"' % symName) if symType[0] in self.baseTypes: return symType, symSubtype else: baseSymType, baseSymSubtype = self.getBaseType(*symType) if isinstance(baseSymSubtype, list): if isinstance(symSubtype, list): symSubtype += baseSymSubtype else: symSubtype = baseSymSubtype return baseSymType, symSubtype # Clause generation functions # noinspection PyUnusedLocal def genAgentCapabilities(self, data): name, productRelease, status, description, reference, oid = data label = self.genLabel(name) name = self.transOpers(name) oidStr, parentOid = oid outDict = OrderedDict() outDict['name'] = name outDict['oid'] = oidStr outDict['class'] = 'agentcapabilities' if productRelease: outDict['productrelease'] = productRelease if status: outDict['status'] = status if self.genRules['text'] and description: outDict['description'] = description if self.genRules['text'] and reference: outDict['reference'] = reference self.regSym(name, outDict, parentOid) return outDict # noinspection PyUnusedLocal def genModuleIdentity(self, data): name, lastUpdated, organization, contactInfo, description, revisions, oid = data label = self.genLabel(name) name = self.transOpers(name) oidStr, parentOid = oid outDict = OrderedDict() outDict['name'] = name outDict['oid'] = oidStr outDict['class'] = 'moduleidentity' if revisions: outDict['revisions'] = revisions self._moduleRevision = revisions[0]['revision'] if self.genRules['text']: if lastUpdated: outDict['lastupdated'] = lastUpdated if organization: outDict['organization'] = organization if contactInfo: outDict['contactinfo'] = contactInfo if description: outDict['description'] = description self.regSym(name, outDict, parentOid, moduleIdentity=True) return outDict # noinspection PyUnusedLocal def genModuleCompliance(self, data): name, status, description, reference, compliances, oid = data label = self.genLabel(name) name = self.transOpers(name) oidStr, parentOid = oid outDict = OrderedDict() outDict['name'] = name outDict['oid'] = oidStr outDict['class'] = 'modulecompliance' if compliances: outDict['modulecompliance'] = compliances if status: outDict['status'] = status if self.genRules['text'] and description: outDict['description'] = description if self.genRules['text'] and reference: outDict['reference'] = reference self.regSym(name, outDict, parentOid, moduleCompliance=True) return outDict # noinspection PyUnusedLocal def genNotificationGroup(self, data): name, objects, status, description, reference, oid = data label = self.genLabel(name) name = self.transOpers(name) oidStr, parentOid = oid outDict = OrderedDict() outDict['name'] = name outDict['oid'] = oidStr outDict['class'] = 'notificationgroup' if objects: outDict['objects'] = [{'module': self._importMap.get(obj, self.moduleName[0]), 'object': self.transOpers(obj)} for obj in objects] if status: outDict['status'] = status if self.genRules['text'] and description: outDict['description'] = description if self.genRules['text'] and reference: outDict['reference'] = reference self.regSym(name, outDict, parentOid) return outDict # noinspection PyUnusedLocal def genNotificationType(self, data): name, objects, status, description, reference, oid = data label = self.genLabel(name) name = self.transOpers(name) oidStr, parentOid = oid outDict = OrderedDict() outDict['name'] = name outDict['oid'] = oidStr outDict['class'] = 'notificationtype' if objects: outDict['objects'] = [{'module': self._importMap.get(obj, self.moduleName[0]), 'object': self.transOpers(obj)} for obj in objects] if status: outDict['status'] = status if self.genRules['text'] and description: outDict['description'] = description if self.genRules['text'] and reference: outDict['reference'] = reference self.regSym(name, outDict, parentOid) return outDict # noinspection PyUnusedLocal def genObjectGroup(self, data): name, objects, status, description, reference, oid = data label = self.genLabel(name) name = self.transOpers(name) oidStr, parentOid = oid outDict = OrderedDict({'name': name, 'oid': oidStr, 'class': 'objectgroup'}) if objects: outDict['objects'] = [{'module': self._importMap.get(obj, self.moduleName[0]), 'object': self.transOpers(obj)} for obj in objects] if status: outDict['status'] = status if self.genRules['text'] and description: outDict['description'] = description if self.genRules['text'] and reference: outDict['reference'] = reference self.regSym(name, outDict, parentOid) return outDict # noinspection PyUnusedLocal def genObjectIdentity(self, data): name, status, description, reference, oid = data label = self.genLabel(name) name = self.transOpers(name) oidStr, parentOid = oid outDict = OrderedDict() outDict['name'] = name outDict['oid'] = oidStr outDict['class'] = 'objectidentity' if status: outDict['status'] = status if self.genRules['text'] and description: outDict['description'] = description if self.genRules['text'] and reference: outDict['reference'] = reference self.regSym(name, outDict, parentOid) return outDict # noinspection PyUnusedLocal def genObjectType(self, data): name, syntax, units, maxaccess, status, description, reference, augmention, index, defval, oid = data label = self.genLabel(name) name = self.transOpers(name) oidStr, parentOid = oid indexStr, fakeStrlist, fakeSyms = index or ('', '', []) defval = self.genDefVal(defval, objname=name) outDict = OrderedDict() outDict['name'] = name outDict['oid'] = oidStr if syntax[0]: nodetype = syntax[0] == 'Bits' and 'scalar' or syntax[0] # Bits hack nodetype = name in self.symbolTable[self.moduleName[0]]['_symtable_cols'] and 'column' or nodetype outDict['nodetype'] = nodetype outDict['class'] = 'objecttype' if syntax[1]: outDict['syntax'] = syntax[1] if defval: outDict['default'] = defval if units: outDict['units'] = units if maxaccess: outDict['maxaccess'] = maxaccess if indexStr: outDict['indices'] = indexStr if self.genRules['text'] and reference: outDict['reference'] = reference if augmention: augmention = self.transOpers(augmention) outDict['augmention'] = OrderedDict() outDict['augmention']['name'] = name outDict['augmention']['module'] = self.moduleName[0] outDict['augmention']['object'] = augmention if status: outDict['status'] = status if self.genRules['text'] and description: outDict['description'] = description self.regSym(name, outDict, parentOid) # TODO # if fakeSyms: # fake symbols for INDEX to support SMIv1 # for i in range(len(fakeSyms)): # fakeOutStr = fakeStrlist[i] % oidStr # self.regSym(fakeSyms[i], fakeOutStr, name) return outDict # noinspection PyUnusedLocal def genTrapType(self, data): name, enterprise, variables, description, reference, value = data label = self.genLabel(name) name = self.transOpers(name) enterpriseStr, parentOid = enterprise outDict = OrderedDict() outDict['name'] = name outDict['oid'] = enterpriseStr + '0.' + str(value) outDict['class'] = 'notificationtype' if variables: outDict['objects'] = [{'module': self._importMap.get(obj, self.moduleName[0]), 'object': self.transOpers(obj)} for obj in variables] if self.genRules['text'] and description: outDict['description'] = description if self.genRules['text'] and reference: outDict['reference'] = reference self.regSym(name, outDict, parentOid) return outDict # noinspection PyUnusedLocal def genTypeDeclaration(self, data): name, declaration = data outDict = OrderedDict() outDict['name'] = name outDict['class'] = 'type' if declaration: parentType, attrs = declaration if parentType: # skipping SEQUENCE case name = self.transOpers(name) outDict.update(attrs) self.regSym(name, outDict) return outDict # noinspection PyUnusedLocal def genValueDeclaration(self, data): name, oid = data label = self.genLabel(name) name = self.transOpers(name) oidStr, parentOid = oid outDict = OrderedDict() outDict['name'] = name outDict['oid'] = oidStr outDict['class'] = 'objectidentity' self.regSym(name, outDict, parentOid) return outDict # Subparts generation functions # noinspection PyMethodMayBeStatic,PyUnusedLocal def genBitNames(self, data): names = data[0] return names def genBits(self, data): bits = data[0] outDict = OrderedDict() outDict['type'] = 'Bits' outDict['class'] = 'type' outDict['bits'] = OrderedDict() for name, bit in sorted(bits, key=lambda x: x[1]): outDict['bits'][name] = bit return 'scalar', outDict # noinspection PyUnusedLocal def genCompliances(self, data): compliances = [] for complianceModule in data[0]: name = complianceModule[0] or self.moduleName[0] compliances += [{'object': self.transOpers(compl), 'module': name} for compl in complianceModule[1]] return compliances # noinspection PyUnusedLocal def genConceptualTable(self, data): row = data[0] if row[1] and row[1][-2:] == '()': row = row[1][:-2] self._rows.add(row) return 'table', '' # noinspection PyMethodMayBeStatic,PyUnusedLocal def genContactInfo(self, data): text = data[0] return self.textFilter('contact-info', text) # noinspection PyUnusedLocal def genDisplayHint(self, data): return data[0] # noinspection PyUnusedLocal def genDefVal(self, data, objname=None): if not data: return {} if not objname: return data outDict = OrderedDict() defval = data[0] defvalType = self.getBaseType(objname, self.moduleName[0]) if isinstance(defval, (int, long)): # number outDict.update(value=defval, format='decimal') elif self.isHex(defval): # hex if defvalType[0][0] in ('Integer32', 'Integer'): # common bug in MIBs outDict.update(value=str(int(len(defval) > 3 and defval[1:-2] or '0', 16)), format='hex') else: outDict.update(value=defval[1:-2], format='hex') elif self.isBinary(defval): # binary binval = defval[1:-2] if defvalType[0][0] in ('Integer32', 'Integer'): # common bug in MIBs outDict.update(value=str(int(binval or '0', 2)), format='bin') else: hexval = binval and hex(int(binval, 2))[2:] or '' outDict.update(value=hexval, format='hex') elif defval[0] == defval[-1] and defval[0] == '"': # quoted string if defval[1:-1] == '' and defvalType != 'OctetString': # common bug # a warning should be here return {} # we will set no default value outDict.update(value=defval[1:-1], format='string') else: # symbol (oid as defval) or name for enumeration member if (defvalType[0][0] == 'ObjectIdentifier' and (defval in self.symbolTable[self.moduleName[0]] or defval in self._importMap)): # oid module = self._importMap.get(defval, self.moduleName[0]) try: val = str(self.genNumericOid(self.symbolTable[module][defval]['oid'])) outDict.update(value=val, format='oid') except: # or no module if it will be borrowed later raise error.PySmiSemanticError('no symbol "%s" in module "%s"' % (defval, module)) # enumeration elif defvalType[0][0] in ('Integer32', 'Integer') and isinstance(defvalType[1], list): if isinstance(defval, list): # buggy MIB: DEFVAL { { ... } } defval = [dv for dv in defval if dv in dict(defvalType[1])] if defval: outDict.update(value=defval[0], format='enum') elif defval in dict(defvalType[1]): # good MIB: DEFVAL { ... } outDict.update(value=defval, format='enum') elif defvalType[0][0] == 'Bits': defvalBits = [] bits = dict(defvalType[1]) for bit in defval: bitValue = bits.get(bit, None) if bitValue is not None: defvalBits.append((bit, bitValue)) else: raise error.PySmiSemanticError('no such bit as "%s" for symbol "%s"' % (bit, objname)) outDict.update(value=self.genBits([defvalBits])[1], format='bits') return outDict else: raise error.PySmiSemanticError( 'unknown type "%s" for defval "%s" of symbol "%s"' % (defvalType, defval, objname)) return {'default': outDict} # noinspection PyMethodMayBeStatic def genDescription(self, data): return self.textFilter('description', data[0]) # noinspection PyMethodMayBeStatic def genReference(self, data): return self.textFilter('reference', data[0]) # noinspection PyMethodMayBeStatic def genStatus(self, data): return data[0] def genProductRelease(self, data): return data[0] def genEnumSpec(self, data): items = data[0] return {'enumeration': dict(items)} # noinspection PyUnusedLocal def genTableIndex(self, data): def genFakeSyms(fakeidx, idxType): objType = self.typeClasses.get(idxType, idxType) objType = self.transOpers(objType) return {'module': self.moduleName[0], object: objType} indexes = data[0] idxStrlist, fakeSyms, fakeStrlist = [], [], [] for idx in indexes: isImplied = idx[0] idxName = idx[1] if idxName in self.smiv1IdxTypes: # SMIv1 support idxType = idxName fakeSymStr, idxName = genFakeSyms(self.fakeidx, idxType) fakeStrlist.append(fakeSymStr) fakeSyms.append(idxName) self.fakeidx += 1 index = OrderedDict() index['module'] = self._importMap.get(idxName, self.moduleName[0]) index['object'] = idxName index['implied'] = isImplied idxStrlist.append(index) return idxStrlist, fakeStrlist, fakeSyms def genIntegerSubType(self, data): ranges = [] for rng in data[0]: vmin, vmax = len(rng) == 1 and (rng[0], rng[0]) or rng vmin, vmax = self.str2int(vmin), self.str2int(vmax) ran = OrderedDict() ran['min'] = vmin ran['max'] = vmax ranges.append(ran) return {'range': ranges} # noinspection PyMethodMayBeStatic,PyUnusedLocal def genMaxAccess(self, data): return data[0] def genOctetStringSubType(self, data): sizes = [] for rng in data[0]: vmin, vmax = len(rng) == 1 and (rng[0], rng[0]) or rng vmin, vmax = self.str2int(vmin), self.str2int(vmax) size = OrderedDict() size['min'] = vmin size['max'] = vmax sizes.append(size) return {'size': sizes} # noinspection PyUnusedLocal def genOid(self, data): out = () parent = '' for el in data[0]: if isinstance(el, (str, unicode)): parent = self.transOpers(el) out += ((parent, self._importMap.get(parent, self.moduleName[0])),) elif isinstance(el, (int, long)): out += (el,) elif isinstance(el, tuple): out += (el[1],) # XXX Do we need to create a new object el[0]? else: raise error.PySmiSemanticError('unknown datatype for OID: %s' % el) return '.'.join([str(x) for x in self.genNumericOid(out)]), parent # noinspection PyUnusedLocal def genObjects(self, data): if data[0]: return [self.transOpers(obj) for obj in data[0]] # XXX self.transOpers or not?? return [] # noinspection PyMethodMayBeStatic,PyUnusedLocal def genTime(self, data): times = [] for timeStr in data: if len(timeStr) == 11: timeStr = '19' + timeStr # XXX raise in strict mode # elif lenTimeStr != 13: # raise error.PySmiSemanticError("Invalid date %s" % t) try: times.append(strftime('%Y-%m-%d %H:%M', strptime(timeStr, '%Y%m%d%H%MZ'))) except ValueError: # XXX raise in strict mode # raise error.PySmiSemanticError("Invalid date %s: %s" % (t, sys.exc_info()[1])) timeStr = '197001010000Z' # dummy date for dates with typos times.append(strftime('%Y-%m-%d %H:%M', strptime(timeStr, '%Y%m%d%H%MZ'))) return times # noinspection PyMethodMayBeStatic,PyUnusedLocal def genLastUpdated(self, data): return data[0] # noinspection PyMethodMayBeStatic,PyUnusedLocal def genOrganization(self, data): return self.textFilter('organization', data[0]) # noinspection PyUnusedLocal def genRevisions(self, data): revisions = [] for x in data[0]: revision = OrderedDict() revision['revision'] = self.genTime([x[0]])[0] revision['description'] = self.textFilter('description', x[1][1]) revisions.append(revision) return revisions def genRow(self, data): row = data[0] row = self.transOpers(row) return row in self.symbolTable[self.moduleName[0]]['_symtable_rows'] and ( 'row', '') or self.genSimpleSyntax(data) # noinspection PyUnusedLocal def genSequence(self, data): cols = data[0] self._cols.update(cols) return '', '' def genSimpleSyntax(self, data): objType = data[0] objType = self.typeClasses.get(objType, objType) objType = self.transOpers(objType) subtype = len(data) == 2 and data[1] or {} outDict = OrderedDict() outDict['type'] = objType outDict['class'] = 'type' if subtype: outDict['constraints'] = subtype return 'scalar', outDict # noinspection PyUnusedLocal def genTypeDeclarationRHS(self, data): if len(data) == 1: parentType, attrs = data[0] outDict = OrderedDict() if not attrs: return outDict # just syntax outDict['type'] = attrs else: # Textual convention display, status, description, reference, syntax = data parentType, attrs = syntax outDict = OrderedDict() outDict['type'] = attrs outDict['class'] = 'textualconvention' if display: outDict['displayhint'] = display if status: outDict['status'] = status if self.genRules['text'] and description: outDict['description'] = description if self.genRules['text'] and reference: outDict['reference'] = reference return parentType, outDict # noinspection PyMethodMayBeStatic,PyUnusedLocal def genUnits(self, data): text = data[0] return self.textFilter('units', text) handlersTable = { 'agentCapabilitiesClause': genAgentCapabilities, 'moduleIdentityClause': genModuleIdentity, 'moduleComplianceClause': genModuleCompliance, 'notificationGroupClause': genNotificationGroup, 'notificationTypeClause': genNotificationType, 'objectGroupClause': genObjectGroup, 'objectIdentityClause': genObjectIdentity, 'objectTypeClause': genObjectType, 'trapTypeClause': genTrapType, 'typeDeclaration': genTypeDeclaration, 'valueDeclaration': genValueDeclaration, 'PRODUCT-RELEASE': genProductRelease, 'ApplicationSyntax': genSimpleSyntax, 'BitNames': genBitNames, 'BITS': genBits, 'ComplianceModules': genCompliances, 'conceptualTable': genConceptualTable, 'CONTACT-INFO': genContactInfo, 'DISPLAY-HINT': genDisplayHint, 'DEFVAL': genDefVal, 'DESCRIPTION': genDescription, 'REFERENCE': genReference, 'Status': genStatus, 'enumSpec': genEnumSpec, 'INDEX': genTableIndex, 'integerSubType': genIntegerSubType, 'MaxAccessPart': genMaxAccess, 'Notifications': genObjects, 'octetStringSubType': genOctetStringSubType, 'objectIdentifier': genOid, 'Objects': genObjects, 'LAST-UPDATED': genLastUpdated, 'ORGANIZATION': genOrganization, 'Revisions': genRevisions, 'row': genRow, 'SEQUENCE': genSequence, 'SimpleSyntax': genSimpleSyntax, 'typeDeclarationRHS': genTypeDeclarationRHS, 'UNITS': genUnits, 'VarTypes': genObjects, # 'a': lambda x: genXXX(x, 'CONSTRAINT') } def genCode(self, ast, symbolTable, **kwargs): self.genRules['text'] = kwargs.get('genTexts', False) self.textFilter = kwargs.get('textFilter') or (lambda symbol, text: re.sub('\s+', ' ', text)) self.symbolTable = symbolTable self._rows.clear() self._cols.clear() self._seenSyms.clear() self._importMap.clear() self._out.clear() self._moduleIdentityOid = None self._enterpriseOid = None self._oids = set() self._complianceOids = [] self.moduleName[0], moduleOid, imports, declarations = ast outDict, importedModules = self.genImports(imports and imports or {}) for declr in declarations or []: if declr: self.handlersTable[declr[0]](self, self.prepData(declr[1:])) for sym in self.symbolTable[self.moduleName[0]]['_symtable_order']: if sym not in self._out: raise error.PySmiCodegenError('No generated code for symbol %s' % sym) outDict[sym] = self._out[sym] if 'comments' in kwargs: outDict['meta'] = OrderedDict() outDict['meta']['comments'] = kwargs['comments'] outDict['meta']['module'] = self.moduleName[0] debug.logger & debug.flagCodegen and debug.logger( 'canonical MIB name %s (%s), imported MIB(s) %s, Python code size %s bytes' % ( self.moduleName[0], moduleOid, ','.join(importedModules) or '', len(outDict))) return MibInfo(oid=moduleOid, identity=self._moduleIdentityOid, name=self.moduleName[0], revision=self._moduleRevision, oids=self._oids, enterprise=self._enterpriseOid, compliance=self._complianceOids, imported=tuple([x for x in importedModules if x not in self.fakeMibs])), json.dumps(outDict, indent=2) def genIndex(self, processed, **kwargs): outDict = { 'meta': {}, 'identity': {}, 'enterprise': {}, 'compliance': {}, 'oids': {}, } if kwargs.get('old_index_data'): try: outDict.update( json.loads(kwargs['old_index_data']) ) except Exception: raise error.PySmiCodegenError('Index load error: %s' % sys.exc_info()[1]) def order(top): if isinstance(top, dict): new_top = OrderedDict() try: # first try to sort keys as OIDs for k in sorted(top, key=lambda x: [int(y) for y in x.split('.')]): new_top[k] = order(top[k]) except ValueError: for k in sorted(top): new_top[k] = order(top[k]) return new_top elif isinstance(top, list): new_top = [] for e in sorted(set(top)): new_top.append(order(e)) return new_top return top for module, status in processed.items(): modData = outDict['identity'] identity_oid = getattr(status, 'identity', None) if identity_oid: if identity_oid not in modData: modData[identity_oid] = [] modData[identity_oid].append(module) modData = outDict['enterprise'] enterprise_oid = getattr(status, 'enterprise', None) if enterprise_oid: if enterprise_oid not in modData: modData[enterprise_oid] = [] modData[enterprise_oid].append(module) modData = outDict['compliance'] compliance_oids = getattr(status, 'compliance', ()) for compliance_oid in compliance_oids: if compliance_oid not in modData: modData[compliance_oid] = [] modData[compliance_oid].append(module) modData = outDict['oids'] objects_oids = getattr(status, 'oids', ()) for object_oid in objects_oids: if object_oid not in modData: modData[object_oid] = [] modData[object_oid].append(module) if modData: unique_prefixes = {} for oid in sorted(modData, key=lambda x: x.count('.')): for oid_prefix, modules in unique_prefixes.items(): if oid.startswith(oid_prefix) and set(modules).issuperset(modData[oid]): break else: unique_prefixes[oid] = modData[oid] outDict['oids'] = unique_prefixes if 'comments' in kwargs: outDict['meta']['comments'] = kwargs['comments'] debug.logger & debug.flagCodegen and debug.logger( 'OID->MIB index built, %s entries' % len(processed)) return json.dumps(order(outDict), indent=2)