Mini Shell
#
# This file is part of pysmi software.
#
# Copyright (c) 2015-2019, Ilya Etingof <etingof@gmail.com>
# License: http://snmplabs.com/pysmi/license.html
#
# Build an internally used symbol table for each passed MIB.
#
import sys
from keyword import iskeyword
from pysmi.mibinfo import MibInfo
from pysmi.codegen.base import AbstractCodeGen, dorepr
from pysmi import error
from pysmi import debug
if sys.version_info[0] > 2:
# noinspection PyShadowingBuiltins
unicode = str
# noinspection PyShadowingBuiltins
long = int
class SymtableCodeGen(AbstractCodeGen):
symsTable = {
'MODULE-IDENTITY': ('ModuleIdentity',),
'OBJECT-TYPE': ('MibScalar', 'MibTable', 'MibTableRow', 'MibTableColumn'),
'NOTIFICATION-TYPE': ('NotificationType',),
'TEXTUAL-CONVENTION': ('TextualConvention',),
'MODULE-COMPLIANCE': ('ModuleCompliance',),
'OBJECT-GROUP': ('ObjectGroup',),
'NOTIFICATION-GROUP': ('NotificationGroup',),
'AGENT-CAPABILITIES': ('AgentCapabilities',),
'OBJECT-IDENTITY': ('ObjectIdentity',),
'TRAP-TYPE': ('NotificationType',), # smidump always uses NotificationType
'BITS': ('Bits',),
}
constImports = {
'SNMPv2-SMI': ('iso',
'Bits', # XXX
'Integer32', # XXX
'TimeTicks', # bug in some IETF MIBs
'Counter32', # bug in some IETF MIBs (e.g. DSA-MIB)
'Counter64', # bug in some MIBs (e.g.A3COM-HUAWEI-LswINF-MIB)
'NOTIFICATION-TYPE', # bug in some MIBs (e.g. A3COM-HUAWEI-DHCPSNOOP-MIB)
'Gauge32', # bug in some IETF MIBs (e.g. DSA-MIB)
'MODULE-IDENTITY', 'OBJECT-TYPE', 'OBJECT-IDENTITY', 'Unsigned32', 'IpAddress', # XXX
'MibIdentifier'), # OBJECT IDENTIFIER
'SNMPv2-TC': ('DisplayString', 'TEXTUAL-CONVENTION',), # XXX
'SNMPv2-CONF': ('MODULE-COMPLIANCE', 'NOTIFICATION-GROUP',), # XXX
}
baseTypes = ['Integer', 'Integer32', 'Bits', 'ObjectIdentifier', 'OctetString']
typeClasses = {
'COUNTER32': 'Counter32',
'COUNTER64': 'Counter64',
'GAUGE32': 'Gauge32',
'INTEGER': 'Integer32', # XXX
'INTEGER32': 'Integer32',
'IPADDRESS': 'IpAddress',
'NETWORKADDRESS': 'IpAddress',
'OBJECT IDENTIFIER': 'ObjectIdentifier',
'OCTET STRING': 'OctetString',
'OPAQUE': 'Opaque',
'TIMETICKS': 'TimeTicks',
'UNSIGNED32': 'Unsigned32',
'Counter': 'Counter32',
'Gauge': 'Gauge32',
'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']
ifTextStr = 'if mibBuilder.loadTexts: '
indent = ' ' * 4
fakeidx = 1000 # starting index for fake symbols
def __init__(self):
self._rows = set()
self._cols = {} # k, v = name, datatype
self._exports = set()
self._postponedSyms = {} # k, v = symbol, (parents, properties)
self._parentOids = set()
self._importMap = {} # k, v = symbol, MIB
self._symsOrder = []
self._out = {} # k, v = symbol, properties
self.moduleName = ['DUMMY']
self._moduleRevision = None
self.genRules = {'text': True}
def symTrans(self, symbol):
if symbol in self.symsTable:
return self.symsTable[symbol]
return symbol,
@staticmethod
def transOpers(symbol):
if iskeyword(symbol):
symbol = 'pysmi_' + symbol
return symbol.replace('-', '_')
def prepData(self, pdata, classmode=False):
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:], classmode=classmode), classmode=classmode))
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]
for module in sorted(imports):
symbols = ()
for symbol in set(imports[module]):
symbols += self.symTrans(symbol)
if symbols:
self._importMap.update([(self.transOpers(s), module) for s in symbols])
return {}, tuple(sorted(imports))
def allParentsExists(self, parents):
parentsExists = True
for parent in parents:
if not (parent in self._out or
parent in self._importMap or
parent in self.baseTypes or
parent in ('MibTable', 'MibTableRow', 'MibTableColumn') or
parent in self._rows):
parentsExists = False
break
return parentsExists
def regSym(self, symbol, symProps, parents=()):
if symbol in self._out or symbol in self._postponedSyms: # add to strict mode - or symbol in self._importMap:
raise error.PySmiSemanticError('Duplicate symbol found: %s' % symbol)
if self.allParentsExists(parents):
self._out[symbol] = symProps
self._symsOrder.append(symbol)
self.regPostponedSyms()
else:
self._postponedSyms[symbol] = (parents, symProps)
def regPostponedSyms(self):
regedSyms = []
for sym, val in self._postponedSyms.items():
parents, symProps = val
if self.allParentsExists(parents):
self._out[sym] = symProps
self._symsOrder.append(sym)
regedSyms.append(sym)
for sym in regedSyms:
self._postponedSyms.pop(sym)
# Clause handlers
# noinspection PyUnusedLocal
def genAgentCapabilities(self, data, classmode=False):
origName, release, status, description, reference, oid = data
pysmiName = self.transOpers(origName)
symProps = {'type': 'AgentCapabilities',
'oid': oid,
'origName': origName}
self.regSym(pysmiName, symProps)
# noinspection PyUnusedLocal
def genModuleIdentity(self, data, classmode=False):
origName, lastUpdated, organization, contactInfo, description, revisions, oid = data
pysmiName = self.transOpers(origName)
symProps = {'type': 'ModuleIdentity',
'oid': oid,
'origName': origName}
if revisions:
self._moduleRevision = revisions[0]
self.regSym(pysmiName, symProps)
# noinspection PyUnusedLocal
def genModuleCompliance(self, data, classmode=False):
origName, status, description, reference, compliances, oid = data
pysmiName = self.transOpers(origName)
symProps = {'type': 'ModuleCompliance',
'oid': oid,
'origName': origName}
self.regSym(pysmiName, symProps)
# noinspection PyUnusedLocal
def genNotificationGroup(self, data, classmode=False):
origName, objects, status, description, reference, oid = data
pysmiName = self.transOpers(origName)
symProps = {'type': 'NotificationGroup',
'oid': oid,
'origName': origName}
self.regSym(pysmiName, symProps)
# noinspection PyUnusedLocal
def genNotificationType(self, data, classmode=False):
origName, objects, status, description, reference, oid = data
pysmiName = self.transOpers(origName)
symProps = {'type': 'NotificationType',
'oid': oid,
'origName': origName}
self.regSym(pysmiName, symProps)
# noinspection PyUnusedLocal
def genObjectGroup(self, data, classmode=False):
origName, objects, status, description, reference, oid = data
pysmiName = self.transOpers(origName)
symProps = {'type': 'ObjectGroup',
'oid': oid,
'origName': origName}
self.regSym(pysmiName, symProps)
# noinspection PyUnusedLocal
def genObjectIdentity(self, data, classmode=False):
origName, status, description, reference, oid = data
pysmiName = self.transOpers(origName)
symProps = {'type': 'ObjectIdentity',
'oid': oid,
'origName': origName}
self.regSym(pysmiName, symProps)
# noinspection PyUnusedLocal
def genObjectType(self, data, classmode=False):
origName, syntax, units, maxaccess, status, description, reference, augmention, index, defval, oid = data
pysmiName = self.transOpers(origName)
symProps = {'type': 'ObjectType',
'oid': oid,
'syntax': syntax, # (type, module), subtype
'origName': origName}
parents = [syntax[0][0]]
if augmention:
parents.append(self.transOpers(augmention))
if defval: # XXX
symProps['defval'] = defval
if index and index[1]:
namepart, fakeIndexes, fakeSymSyntax = index
for fakeIdx, fakeSyntax in zip(fakeIndexes, fakeSymSyntax):
fakeName = namepart + str(fakeIdx)
fakeSymProps = {'type': 'fakeColumn',
'oid': oid + (fakeIdx,),
'syntax': fakeSyntax,
'origName': fakeName}
self.regSym(fakeName, fakeSymProps)
self.regSym(pysmiName, symProps, parents)
# noinspection PyUnusedLocal
def genTrapType(self, data, classmode=False):
origName, enterprise, variables, description, reference, value = data
pysmiName = self.transOpers(origName)
symProps = {'type': 'NotificationType',
'oid': enterprise + (0, value),
'origName': origName}
self.regSym(pysmiName, symProps)
# noinspection PyUnusedLocal
def genTypeDeclaration(self, data, classmode=False):
origName, declaration = data
pysmiName = self.transOpers(origName)
if declaration:
parentType, attrs = declaration
if parentType: # skipping SEQUENCE case
symProps = {'type': 'TypeDeclaration',
'syntax': declaration, # (type, module), subtype
'origName': origName}
self.regSym(pysmiName, symProps, [declaration[0][0]])
# noinspection PyUnusedLocal
def genValueDeclaration(self, data, classmode=False):
origName, oid = data
pysmiName = self.transOpers(origName)
symProps = {'type': 'MibIdentifier',
'oid': oid,
'origName': origName}
self.regSym(pysmiName, symProps)
# Subparts generation functions
# noinspection PyUnusedLocal,PyMethodMayBeStatic
def genBitNames(self, data, classmode=False):
names = data[0]
return names
# noinspection PyUnusedLocal,PyMethodMayBeStatic
def genBits(self, data, classmode=False):
bits = data[0]
return ('Bits', ''), bits
# noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic
def genCompliances(self, data, classmode=False):
return ''
# noinspection PyUnusedLocal
def genConceptualTable(self, data, classmode=False):
row = data[0]
if row[0] and row[0][0]:
self._rows.add(self.transOpers(row[0][0]))
return ('MibTable', ''), ''
# noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic
def genContactInfo(self, data, classmode=False):
return ''
# noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic
def genDisplayHint(self, data, classmode=False):
return ''
# noinspection PyUnusedLocal
def genDefVal(self, data, classmode=False): # XXX should be fixed, see pysnmp.py
defval = data[0]
if isinstance(defval, (int, long)): # number
val = str(defval)
elif self.isHex(defval): # hex
val = 'hexValue="' + defval[1:-2] + '"' # not working for Integer baseTypes
elif self.isBinary(defval): # binary
binval = defval[1:-2]
hexval = binval and hex(int(binval, 2))[2:] or ''
val = 'hexValue="' + hexval + '"'
elif isinstance(defval, list): # bits list
val = defval
elif defval[0] == defval[-1] and defval[0] == '"': # quoted strimg
val = dorepr(defval[1:-1])
else: # symbol (oid as defval) or name for enumeration member
if defval in self._out or defval in self._importMap:
val = defval + '.getName()'
else:
val = dorepr(defval)
return val
# noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic
def genDescription(self, data, classmode=False):
return ''
def genReference(self, data, classmode=False):
return ''
def genStatus(self, data, classmode=False):
return ''
def genProductRelease(self, data, classmode=False):
return ''
def genEnumSpec(self, data, classmode=False):
return self.genBits(data, classmode=classmode)[1]
def genIndex(self, data, classmode=False):
indexes = data[0]
fakeIdxName = 'pysmiFakeCol'
fakeIndexes, fakeSymsSyntax = [], []
for idx in indexes:
idxName = idx[1]
if idxName in self.smiv1IdxTypes: # SMIv1 support
idxType = idxName
objType = self.typeClasses.get(idxType, idxType)
objType = self.transOpers(objType)
fakeIndexes.append(self.fakeidx)
fakeSymsSyntax.append((('MibTableColumn', ''), objType))
self.fakeidx += 1
return fakeIdxName, fakeIndexes, fakeSymsSyntax
# noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic
def genIntegerSubType(self, data, classmode=False):
return ''
# noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic
def genMaxAccess(self, data, classmode=False):
return ''
# noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic
def genOctetStringSubType(self, data, classmode=False):
return ''
# noinspection PyUnusedLocal
def genOid(self, data, classmode=False):
out = ()
for el in data[0]:
if isinstance(el, (str, unicode)):
parent = self.transOpers(el)
self._parentOids.add(parent)
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 out
# noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic
def genObjects(self, data, classmode=False):
return ''
# noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic
def genTime(self, data, classmode=False):
return ''
# noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic
def genLastUpdated(self, data, classmode=False):
return data[0]
# noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic
def genOrganization(self, data, classmode=False):
return data[0]
# noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic
def genRevisions(self, data, classmode=False):
lastRevision, lastDescription = data[0][0][0], data[0][0][1][1]
return lastRevision, lastDescription
def genRow(self, data, classmode=False):
row = data[0]
row = self.transOpers(row)
return row in self._rows and (('MibTableRow', ''), '') or self.genSimpleSyntax(data, classmode=classmode)
# noinspection PyUnusedLocal
def genSequence(self, data, classmode=False):
cols = data[0]
self._cols.update(cols)
return '', ''
# noinspection PyUnusedLocal
def genSimpleSyntax(self, data, classmode=False):
objType = data[0]
module = ''
objType = self.typeClasses.get(objType, objType)
objType = self.transOpers(objType)
if objType not in self.baseTypes:
module = self._importMap.get(objType, self.moduleName[0])
subtype = len(data) == 2 and data[1] or ''
return (objType, module), subtype
# noinspection PyUnusedLocal,PyMethodMayBeStatic
def genTypeDeclarationRHS(self, data, classmode=False):
if len(data) == 1:
parentType, attrs = data[0] # just syntax
else:
# Textual convention
display, status, description, reference, syntax = data
parentType, attrs = syntax
return parentType, attrs
# noinspection PyUnusedLocal,PyUnusedLocal,PyMethodMayBeStatic
def genUnits(self, data, classmode=False):
return ''
handlersTable = {
'agentCapabilitiesClause': genAgentCapabilities,
'moduleIdentityClause': genModuleIdentity,
'moduleComplianceClause': genModuleCompliance,
'notificationGroupClause': genNotificationGroup,
'notificationTypeClause': genNotificationType,
'objectGroupClause': genObjectGroup,
'objectIdentityClause': genObjectIdentity,
'objectTypeClause': genObjectType,
'trapTypeClause': genTrapType,
'typeDeclaration': genTypeDeclaration,
'valueDeclaration': genValueDeclaration,
'ApplicationSyntax': genSimpleSyntax,
'BitNames': genBitNames,
'BITS': genBits,
'ComplianceModules': genCompliances,
'conceptualTable': genConceptualTable,
'CONTACT-INFO': genContactInfo,
'DISPLAY-HINT': genDisplayHint,
'DEFVAL': genDefVal,
'DESCRIPTION': genDescription,
'REFERENCE': genReference,
'Status': genStatus,
'PRODUCT-RELEASE': genProductRelease,
'enumSpec': genEnumSpec,
'INDEX': genIndex,
'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,
}
def genCode(self, ast, symbolTable, **kwargs):
self.genRules['text'] = kwargs.get('genTexts', False)
self._rows.clear()
self._cols.clear()
self._parentOids.clear()
self._symsOrder = []
self._postponedSyms.clear()
self._importMap.clear()
self._out = {} # should be new object, do not use `clear` method
self.moduleName[0], moduleOid, imports, declarations = ast
out, importedModules = self.genImports(imports or {})
for declr in declarations or []:
if declr:
clausetype = declr[0]
classmode = clausetype == 'typeDeclaration'
self.handlersTable[declr[0]](self, self.prepData(declr[1:], classmode), classmode)
if self._postponedSyms:
raise error.PySmiSemanticError('Unknown parents for symbols: %s' % ', '.join(self._postponedSyms))
for sym in self._parentOids:
if sym not in self._out and sym not in self._importMap:
raise error.PySmiSemanticError('Unknown parent symbol: %s' % sym)
self._out['_symtable_order'] = list(self._symsOrder)
self._out['_symtable_cols'] = list(self._cols)
self._out['_symtable_rows'] = list(self._rows)
debug.logger & debug.flagCodegen and debug.logger(
'canonical MIB name %s (%s), imported MIB(s) %s, Symbol table size %s symbols' % (
self.moduleName[0], moduleOid, ','.join(importedModules) or '<none>', len(self._out)))
return MibInfo(oid=None,
name=self.moduleName[0],
revision=self._moduleRevision,
imported=tuple([x for x in importedModules])), self._out
Zerion Mini Shell 1.0