Format with black
This commit is contained in:
@ -11,19 +11,23 @@ import logging
|
|||||||
from agentx.agent import Agent
|
from agentx.agent import Agent
|
||||||
from agentx.dataset import DataSet
|
from agentx.dataset import DataSet
|
||||||
|
|
||||||
|
|
||||||
def setup_logging(debug=False):
|
def setup_logging(debug=False):
|
||||||
if debug:
|
if debug:
|
||||||
level = logging.DEBUG
|
level = logging.DEBUG
|
||||||
else:
|
else:
|
||||||
level = logging.INFO
|
level = logging.INFO
|
||||||
logger = logging.getLogger('agentx')
|
logger = logging.getLogger("agentx")
|
||||||
logger.setLevel(level)
|
logger.setLevel(level)
|
||||||
formatter = logging.Formatter('[%(levelname)-8s] %(name)17s - %(funcName)-15s: %(message)s')
|
formatter = logging.Formatter(
|
||||||
|
"[%(levelname)-8s] %(name)17s - %(funcName)-15s: %(message)s"
|
||||||
|
)
|
||||||
ch = logging.StreamHandler()
|
ch = logging.StreamHandler()
|
||||||
ch.setLevel(level)
|
ch.setLevel(level)
|
||||||
ch.setFormatter(formatter)
|
ch.setFormatter(formatter)
|
||||||
logger.addHandler(ch)
|
logger.addHandler(ch)
|
||||||
|
|
||||||
|
|
||||||
AGENTX_EMPTY_PDU = 1
|
AGENTX_EMPTY_PDU = 1
|
||||||
AGENTX_OPEN_PDU = 1
|
AGENTX_OPEN_PDU = 1
|
||||||
AGENTX_CLOSE_PDU = 2
|
AGENTX_CLOSE_PDU = 2
|
||||||
|
@ -12,14 +12,15 @@ import agentx
|
|||||||
from agentx.dataset import DataSet
|
from agentx.dataset import DataSet
|
||||||
from agentx.network import Network
|
from agentx.network import Network
|
||||||
|
|
||||||
|
|
||||||
class NullHandler(logging.Handler):
|
class NullHandler(logging.Handler):
|
||||||
def emit(self, record):
|
def emit(self, record):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Agent(object):
|
class Agent(object):
|
||||||
def __init__(self, server_address='/var/agentx/master', period=30.0):
|
def __init__(self, server_address="/var/agentx/master", period=30.0):
|
||||||
self.logger = logging.getLogger('agentx.agent')
|
self.logger = logging.getLogger("agentx.agent")
|
||||||
self.logger.addHandler(NullHandler())
|
self.logger.addHandler(NullHandler())
|
||||||
|
|
||||||
self._servingset = DataSet()
|
self._servingset = DataSet()
|
||||||
@ -27,7 +28,7 @@ class Agent(object):
|
|||||||
self._lastupdate = 0
|
self._lastupdate = 0
|
||||||
self._update_period = period # Seconds
|
self._update_period = period # Seconds
|
||||||
|
|
||||||
self._net = Network(server_address = server_address)
|
self._net = Network(server_address=server_address)
|
||||||
|
|
||||||
self._oid_list = []
|
self._oid_list = []
|
||||||
|
|
||||||
@ -41,43 +42,44 @@ class Agent(object):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.logger.info('Calling setup')
|
self.logger.info("Calling setup")
|
||||||
if not self.setup():
|
if not self.setup():
|
||||||
self.logger.error('Setup failed - exiting')
|
self.logger.error("Setup failed - exiting")
|
||||||
return
|
return
|
||||||
|
|
||||||
self.logger.info('Initial update')
|
self.logger.info("Initial update")
|
||||||
self._update()
|
self._update()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
if not self._net.is_connected():
|
if not self._net.is_connected():
|
||||||
self.logger.info('Opening AgentX connection')
|
self.logger.info("Opening AgentX connection")
|
||||||
self._net.start(self._oid_list)
|
self._net.start(self._oid_list)
|
||||||
|
|
||||||
if time.time() - self._lastupdate > self._update_period:
|
if time.time() - self._lastupdate > self._update_period:
|
||||||
if not self._update():
|
if not self._update():
|
||||||
self.logger.warning('Update failed, last successful update was %s' % self._lastupdate)
|
self.logger.warning(
|
||||||
|
"Update failed, last successful update was %s"
|
||||||
|
% self._lastupdate
|
||||||
|
)
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._net.run()
|
self._net.run()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error('An exception occurred: %s' % e)
|
self.logger.error("An exception occurred: %s" % e)
|
||||||
self.logger.error('Reconnecting')
|
self.logger.error("Reconnecting")
|
||||||
self._net.disconnect()
|
self._net.disconnect()
|
||||||
time.sleep(0.1)
|
time.sleep(0.1)
|
||||||
|
|
||||||
def stop(self):
|
def stop(self):
|
||||||
self.logger.debug('Stopping')
|
self.logger.debug("Stopping")
|
||||||
self._net.disconnect()
|
self._net.disconnect()
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
# Override this
|
# Override this
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
# Override this
|
# Override this
|
||||||
pass
|
pass
|
||||||
@ -88,5 +90,5 @@ class Agent(object):
|
|||||||
|
|
||||||
for oid in oid_list:
|
for oid in oid_list:
|
||||||
if not oid in self._oid_list:
|
if not oid in self._oid_list:
|
||||||
self.logger.debug('Adding %s to list' % oid)
|
self.logger.debug("Adding %s to list" % oid)
|
||||||
self._oid_list.append(oid)
|
self._oid_list.append(oid)
|
||||||
|
@ -9,38 +9,36 @@ from __future__ import (
|
|||||||
import time
|
import time
|
||||||
import agentx
|
import agentx
|
||||||
|
|
||||||
|
|
||||||
class DataSetError(Exception):
|
class DataSetError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class DataSet():
|
|
||||||
|
class DataSet:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self._data = {}
|
self._data = {}
|
||||||
|
|
||||||
def set(self, oid, oid_type, value):
|
def set(self, oid, oid_type, value):
|
||||||
if oid_type.startswith('int'):
|
if oid_type.startswith("int"):
|
||||||
t = agentx.TYPE_INTEGER
|
t = agentx.TYPE_INTEGER
|
||||||
elif oid_type.startswith('str'):
|
elif oid_type.startswith("str"):
|
||||||
t = agentx.TYPE_OCTETSTRING
|
t = agentx.TYPE_OCTETSTRING
|
||||||
elif oid_type.startswith('oid'):
|
elif oid_type.startswith("oid"):
|
||||||
t = agentx.TYPE_OBJECTIDENTIFIER
|
t = agentx.TYPE_OBJECTIDENTIFIER
|
||||||
elif oid_type.startswith('ip'):
|
elif oid_type.startswith("ip"):
|
||||||
t = agentx.TYPE_IPADDRESS
|
t = agentx.TYPE_IPADDRESS
|
||||||
elif oid_type == 'counter32' or oid_type == 'uint32' or oid_type == 'u32':
|
elif oid_type == "counter32" or oid_type == "uint32" or oid_type == "u32":
|
||||||
t = agentx.TYPE_COUNTER32
|
t = agentx.TYPE_COUNTER32
|
||||||
elif oid_type == 'gauge32':
|
elif oid_type == "gauge32":
|
||||||
t = agentx.TYPE_GAUGE32
|
t = agentx.TYPE_GAUGE32
|
||||||
elif oid_type.startswith('time') or oid_type.startswith('tick'):
|
elif oid_type.startswith("time") or oid_type.startswith("tick"):
|
||||||
t = agentx.TYPE_TIMETICKS
|
t = agentx.TYPE_TIMETICKS
|
||||||
elif oid_type.startswith('opaque'):
|
elif oid_type.startswith("opaque"):
|
||||||
t = agentx.TYPE_OPAQUE
|
t = agentx.TYPE_OPAQUE
|
||||||
elif oid_type == 'counter64' or oid_type == 'uint64' or oid_type == 'u64':
|
elif oid_type == "counter64" or oid_type == "uint64" or oid_type == "u64":
|
||||||
t = agentx.TYPE_COUNTER64
|
t = agentx.TYPE_COUNTER64
|
||||||
else:
|
else:
|
||||||
raise DataSetErrror('Invalid oid_type: %s' % (oid_type))
|
raise DataSetErrror("Invalid oid_type: %s" % (oid_type))
|
||||||
return
|
return
|
||||||
|
|
||||||
self._data[oid] = {
|
self._data[oid] = {"name": oid, "type": t, "value": value}
|
||||||
'name': oid,
|
|
||||||
'type': t,
|
|
||||||
'value': value
|
|
||||||
}
|
|
||||||
|
@ -17,15 +17,17 @@ class NullHandler(logging.Handler):
|
|||||||
def emit(self, record):
|
def emit(self, record):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
logger = logging.getLogger('agentx.network')
|
|
||||||
|
logger = logging.getLogger("agentx.network")
|
||||||
logger.addHandler(NullHandler())
|
logger.addHandler(NullHandler())
|
||||||
|
|
||||||
|
|
||||||
class NetworkError(Exception):
|
class NetworkError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Network():
|
class Network:
|
||||||
def __init__(self, server_address = '/var/agentx/master'):
|
def __init__(self, server_address="/var/agentx/master"):
|
||||||
|
|
||||||
self.session_id = 0
|
self.session_id = 0
|
||||||
self.transaction_id = 0
|
self.transaction_id = 0
|
||||||
@ -35,8 +37,7 @@ class Network():
|
|||||||
self.data_idx = []
|
self.data_idx = []
|
||||||
self._connected = False
|
self._connected = False
|
||||||
self._server_address = server_address
|
self._server_address = server_address
|
||||||
self._timeout = 0.1 # Seconds
|
self._timeout = 0.1 # Seconds
|
||||||
|
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
if self._connected:
|
if self._connected:
|
||||||
@ -44,12 +45,12 @@ class Network():
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
logger.info("Connecting to %s" % self._server_address)
|
logger.info("Connecting to %s" % self._server_address)
|
||||||
if self._server_address.startswith('/'):
|
if self._server_address.startswith("/"):
|
||||||
self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
self.socket.connect(self._server_address)
|
self.socket.connect(self._server_address)
|
||||||
else:
|
else:
|
||||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
host, port=self._server_address.split(':')
|
host, port = self._server_address.split(":")
|
||||||
|
|
||||||
self.socket.connect((host, int(port)))
|
self.socket.connect((host, int(port)))
|
||||||
self.socket.settimeout(self._timeout)
|
self.socket.settimeout(self._timeout)
|
||||||
@ -76,7 +77,9 @@ class Network():
|
|||||||
self.data = newdata.copy()
|
self.data = newdata.copy()
|
||||||
|
|
||||||
del self.data_idx
|
del self.data_idx
|
||||||
self.data_idx = sorted(self.data.keys(), key=lambda k: tuple(int(part) for part in k.split('.')))
|
self.data_idx = sorted(
|
||||||
|
self.data.keys(), key=lambda k: tuple(int(part) for part in k.split("."))
|
||||||
|
)
|
||||||
|
|
||||||
def new_pdu(self, type):
|
def new_pdu(self, type):
|
||||||
pdu = PDU(type)
|
pdu = PDU(type)
|
||||||
@ -93,15 +96,18 @@ class Network():
|
|||||||
return pdu
|
return pdu
|
||||||
|
|
||||||
def send_pdu(self, pdu):
|
def send_pdu(self, pdu):
|
||||||
if self.debug: pdu.dump()
|
if self.debug:
|
||||||
|
pdu.dump()
|
||||||
self.socket.send(pdu.encode())
|
self.socket.send(pdu.encode())
|
||||||
|
|
||||||
def recv_pdu(self):
|
def recv_pdu(self):
|
||||||
buf = self.socket.recv(100000)
|
buf = self.socket.recv(100000)
|
||||||
if not buf: return None
|
if not buf:
|
||||||
|
return None
|
||||||
pdu = PDU()
|
pdu = PDU()
|
||||||
pdu.decode(buf)
|
pdu.decode(buf)
|
||||||
if self.debug: pdu.dump()
|
if self.debug:
|
||||||
|
pdu.dump()
|
||||||
return pdu
|
return pdu
|
||||||
|
|
||||||
# =========================================
|
# =========================================
|
||||||
@ -109,7 +115,7 @@ class Network():
|
|||||||
def _get_next_oid(self, oid, endoid):
|
def _get_next_oid(self, oid, endoid):
|
||||||
if oid in self.data:
|
if oid in self.data:
|
||||||
# Exact match found
|
# Exact match found
|
||||||
#logger.debug('get_next_oid, exact match of %s' % oid)
|
# logger.debug('get_next_oid, exact match of %s' % oid)
|
||||||
idx = self.data_idx.index(oid)
|
idx = self.data_idx.index(oid)
|
||||||
if idx == (len(self.data_idx) - 1):
|
if idx == (len(self.data_idx) - 1):
|
||||||
# Last Item in MIB, No match!
|
# Last Item in MIB, No match!
|
||||||
@ -117,11 +123,11 @@ class Network():
|
|||||||
return self.data_idx[idx + 1]
|
return self.data_idx[idx + 1]
|
||||||
else:
|
else:
|
||||||
# No exact match, find prefix
|
# No exact match, find prefix
|
||||||
#logger.debug('get_next_oid, no exact match of %s' % oid)
|
# logger.debug('get_next_oid, no exact match of %s' % oid)
|
||||||
slist = oid.split('.')
|
slist = oid.split(".")
|
||||||
elist = endoid.split('.')
|
elist = endoid.split(".")
|
||||||
for tmp_oid in self.data_idx:
|
for tmp_oid in self.data_idx:
|
||||||
tlist = tmp_oid.split('.')
|
tlist = tmp_oid.split(".")
|
||||||
for i in range(len(tlist)):
|
for i in range(len(tlist)):
|
||||||
try:
|
try:
|
||||||
sok = int(slist[i]) <= int(tlist[i])
|
sok = int(slist[i]) <= int(tlist[i])
|
||||||
@ -166,13 +172,13 @@ class Network():
|
|||||||
def is_connected(self):
|
def is_connected(self):
|
||||||
return self._connected
|
return self._connected
|
||||||
|
|
||||||
def run(self, timeout = 0.1):
|
def run(self, timeout=0.1):
|
||||||
if not self._connected:
|
if not self._connected:
|
||||||
raise NetworkError('Not connected')
|
raise NetworkError("Not connected")
|
||||||
|
|
||||||
if timeout != self._timeout:
|
if timeout != self._timeout:
|
||||||
self.socket.settimeout(timeout)
|
self.socket.settimeout(timeout)
|
||||||
self._timeout = timeout
|
self._timeout = timeout
|
||||||
|
|
||||||
try:
|
try:
|
||||||
request = self.recv_pdu()
|
request = self.recv_pdu()
|
||||||
@ -195,11 +201,13 @@ class Network():
|
|||||||
response.values.append(self.data[oid])
|
response.values.append(self.data[oid])
|
||||||
else:
|
else:
|
||||||
logger.debug("OID Not Found!")
|
logger.debug("OID Not Found!")
|
||||||
response.values.append({
|
response.values.append(
|
||||||
'type': agentx.TYPE_NOSUCHOBJECT,
|
{
|
||||||
'name': rvalue[0],
|
"type": agentx.TYPE_NOSUCHOBJECT,
|
||||||
'value': 0
|
"name": rvalue[0],
|
||||||
})
|
"value": 0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
elif request.type == agentx.AGENTX_GETNEXT_PDU:
|
elif request.type == agentx.AGENTX_GETNEXT_PDU:
|
||||||
logger.debug("Received GET_NEXT PDU")
|
logger.debug("Received GET_NEXT PDU")
|
||||||
@ -209,11 +217,13 @@ class Network():
|
|||||||
if oid:
|
if oid:
|
||||||
response.values.append(self.data[oid])
|
response.values.append(self.data[oid])
|
||||||
else:
|
else:
|
||||||
response.values.append({
|
response.values.append(
|
||||||
'type': agentx.TYPE_ENDOFMIBVIEW,
|
{
|
||||||
'name': rvalue[0],
|
"type": agentx.TYPE_ENDOFMIBVIEW,
|
||||||
'value': 0
|
"name": rvalue[0],
|
||||||
})
|
"value": 0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.warn("Received unsupported PDU %d" % request.type)
|
logger.warn("Received unsupported PDU %d" % request.type)
|
||||||
|
221
agentx/pdu.py
221
agentx/pdu.py
@ -12,10 +12,13 @@ import pprint
|
|||||||
import logging
|
import logging
|
||||||
import agentx
|
import agentx
|
||||||
|
|
||||||
|
|
||||||
class NullHandler(logging.Handler):
|
class NullHandler(logging.Handler):
|
||||||
def emit(self, record):
|
def emit(self, record):
|
||||||
pass
|
pass
|
||||||
logger = logging.getLogger('agentx.pdu')
|
|
||||||
|
|
||||||
|
logger = logging.getLogger("agentx.pdu")
|
||||||
logger.addHandler(NullHandler())
|
logger.addHandler(NullHandler())
|
||||||
|
|
||||||
|
|
||||||
@ -27,34 +30,32 @@ class PDU(object):
|
|||||||
self.packet_id = 0
|
self.packet_id = 0
|
||||||
self.error = agentx.ERROR_NOAGENTXERROR
|
self.error = agentx.ERROR_NOAGENTXERROR
|
||||||
self.error_index = 0
|
self.error_index = 0
|
||||||
self.decode_buf = ''
|
self.decode_buf = ""
|
||||||
self.state = {}
|
self.state = {}
|
||||||
self.values = []
|
self.values = []
|
||||||
|
|
||||||
def dump(self):
|
def dump(self):
|
||||||
name = agentx.PDU_TYPE_NAME[self.type]
|
name = agentx.PDU_TYPE_NAME[self.type]
|
||||||
logger.debug('PDU DUMP: New PDU')
|
logger.debug("PDU DUMP: New PDU")
|
||||||
logger.debug(
|
logger.debug(
|
||||||
'PDU DUMP: Meta : [%s: %d %d %d]' %
|
"PDU DUMP: Meta : [%s: %d %d %d]"
|
||||||
(name, self.session_id, self.transaction_id, self.packet_id))
|
% (name, self.session_id, self.transaction_id, self.packet_id)
|
||||||
if 'payload_length' in self.state:
|
)
|
||||||
logger.debug('PDU DUMP: Length : %s' %
|
if "payload_length" in self.state:
|
||||||
self.state['payload_length'])
|
logger.debug("PDU DUMP: Length : %s" % self.state["payload_length"])
|
||||||
if hasattr(self, 'response'):
|
if hasattr(self, "response"):
|
||||||
logger.debug('PDU DUMP: Response : %s' % self.response)
|
logger.debug("PDU DUMP: Response : %s" % self.response)
|
||||||
if hasattr(self, 'values'):
|
if hasattr(self, "values"):
|
||||||
logger.debug('PDU DUMP: Values : %s' %
|
logger.debug("PDU DUMP: Values : %s" % pprint.pformat(self.values))
|
||||||
pprint.pformat(self.values))
|
if hasattr(self, "range_list"):
|
||||||
if hasattr(self, 'range_list'):
|
logger.debug("PDU DUMP: Range list: %s" % pprint.pformat(self.range_list))
|
||||||
logger.debug('PDU DUMP: Range list: %s' %
|
|
||||||
pprint.pformat(self.range_list))
|
|
||||||
|
|
||||||
# ====================================================
|
# ====================================================
|
||||||
# encode functions
|
# encode functions
|
||||||
|
|
||||||
def encode_oid(self, oid, include=0):
|
def encode_oid(self, oid, include=0):
|
||||||
oid = oid.strip()
|
oid = oid.strip()
|
||||||
oid = oid.split('.')
|
oid = oid.split(".")
|
||||||
oid = [int(i) for i in oid]
|
oid = [int(i) for i in oid]
|
||||||
if len(oid) > 5 and oid[:4] == [1, 3, 6, 1]:
|
if len(oid) > 5 and oid[:4] == [1, 3, 6, 1]:
|
||||||
# prefix
|
# prefix
|
||||||
@ -63,66 +64,70 @@ class PDU(object):
|
|||||||
else:
|
else:
|
||||||
# no prefix
|
# no prefix
|
||||||
prefix = 0
|
prefix = 0
|
||||||
buf = struct.pack('BBBB', len(oid), prefix, include, 0)
|
buf = struct.pack("BBBB", len(oid), prefix, include, 0)
|
||||||
for i in range(len(oid)):
|
for i in range(len(oid)):
|
||||||
buf += struct.pack('!L', oid[i])
|
buf += struct.pack("!L", oid[i])
|
||||||
return buf
|
return buf
|
||||||
|
|
||||||
def encode_octet(self, octet):
|
def encode_octet(self, octet):
|
||||||
octet = octet.encode("utf-8")
|
octet = octet.encode("utf-8")
|
||||||
buf = struct.pack('!L', len(octet))
|
buf = struct.pack("!L", len(octet))
|
||||||
buf += octet
|
buf += octet
|
||||||
padding = (4 - (len(octet) % 4)) % 4
|
padding = (4 - (len(octet) % 4)) % 4
|
||||||
buf += chr(0).encode() * padding
|
buf += chr(0).encode() * padding
|
||||||
return buf
|
return buf
|
||||||
|
|
||||||
def encode_value(self, type, name, value):
|
def encode_value(self, type, name, value):
|
||||||
buf = struct.pack('!HH', type, 0)
|
buf = struct.pack("!HH", type, 0)
|
||||||
buf += self.encode_oid(name)
|
buf += self.encode_oid(name)
|
||||||
if type in [agentx.TYPE_INTEGER]:
|
if type in [agentx.TYPE_INTEGER]:
|
||||||
buf += struct.pack('!l', value)
|
buf += struct.pack("!l", value)
|
||||||
elif type in [
|
elif type in [
|
||||||
agentx.TYPE_COUNTER32, agentx.TYPE_GAUGE32,
|
agentx.TYPE_COUNTER32,
|
||||||
agentx.TYPE_TIMETICKS
|
agentx.TYPE_GAUGE32,
|
||||||
|
agentx.TYPE_TIMETICKS,
|
||||||
]:
|
]:
|
||||||
buf += struct.pack('!L', value)
|
buf += struct.pack("!L", value)
|
||||||
elif type in [agentx.TYPE_COUNTER64]:
|
elif type in [agentx.TYPE_COUNTER64]:
|
||||||
buf += struct.pack('!Q', value)
|
buf += struct.pack("!Q", value)
|
||||||
elif type in [agentx.TYPE_OBJECTIDENTIFIER]:
|
elif type in [agentx.TYPE_OBJECTIDENTIFIER]:
|
||||||
buf += self.encode_oid(value)
|
buf += self.encode_oid(value)
|
||||||
elif type in [
|
elif type in [
|
||||||
agentx.TYPE_IPADDRESS, agentx.TYPE_OPAQUE,
|
agentx.TYPE_IPADDRESS,
|
||||||
agentx.TYPE_OCTETSTRING
|
agentx.TYPE_OPAQUE,
|
||||||
|
agentx.TYPE_OCTETSTRING,
|
||||||
]:
|
]:
|
||||||
buf += self.encode_octet(value)
|
buf += self.encode_octet(value)
|
||||||
elif type in [
|
elif type in [
|
||||||
agentx.TYPE_NULL, agentx.TYPE_NOSUCHOBJECT,
|
agentx.TYPE_NULL,
|
||||||
agentx.TYPE_NOSUCHINSTANCE, agentx.TYPE_ENDOFMIBVIEW
|
agentx.TYPE_NOSUCHOBJECT,
|
||||||
|
agentx.TYPE_NOSUCHINSTANCE,
|
||||||
|
agentx.TYPE_ENDOFMIBVIEW,
|
||||||
]:
|
]:
|
||||||
# No data
|
# No data
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
logger.error('Unknown Type:' % type)
|
logger.error("Unknown Type:" % type)
|
||||||
return buf
|
return buf
|
||||||
|
|
||||||
def encode_header(self, pdu_type, payload_length=0, flags=0):
|
def encode_header(self, pdu_type, payload_length=0, flags=0):
|
||||||
flags = flags | 0x10 # Bit 5 = all ints in NETWORK_BYTE_ORDER
|
flags = flags | 0x10 # Bit 5 = all ints in NETWORK_BYTE_ORDER
|
||||||
buf = struct.pack('BBBB', 1, pdu_type, flags, 0)
|
buf = struct.pack("BBBB", 1, pdu_type, flags, 0)
|
||||||
buf += struct.pack('!L', self.session_id) # sessionID
|
buf += struct.pack("!L", self.session_id) # sessionID
|
||||||
buf += struct.pack('!L', self.transaction_id) # transactionID
|
buf += struct.pack("!L", self.transaction_id) # transactionID
|
||||||
buf += struct.pack('!L', self.packet_id) # packetID
|
buf += struct.pack("!L", self.packet_id) # packetID
|
||||||
buf += struct.pack('!L', payload_length)
|
buf += struct.pack("!L", payload_length)
|
||||||
return buf
|
return buf
|
||||||
|
|
||||||
def encode(self):
|
def encode(self):
|
||||||
buf = b''
|
buf = b""
|
||||||
if self.type == agentx.AGENTX_OPEN_PDU:
|
if self.type == agentx.AGENTX_OPEN_PDU:
|
||||||
# timeout
|
# timeout
|
||||||
buf += struct.pack('!BBBB', 5, 0, 0, 0)
|
buf += struct.pack("!BBBB", 5, 0, 0, 0)
|
||||||
# agent OID
|
# agent OID
|
||||||
buf += struct.pack('!L', 0)
|
buf += struct.pack("!L", 0)
|
||||||
# Agent Desc
|
# Agent Desc
|
||||||
buf += self.encode_octet('MyAgent')
|
buf += self.encode_octet("MyAgent")
|
||||||
|
|
||||||
elif self.type == agentx.AGENTX_PING_PDU:
|
elif self.type == agentx.AGENTX_PING_PDU:
|
||||||
# No extra data
|
# No extra data
|
||||||
@ -132,15 +137,14 @@ class PDU(object):
|
|||||||
range_subid = 0
|
range_subid = 0
|
||||||
timeout = 5
|
timeout = 5
|
||||||
priority = 127
|
priority = 127
|
||||||
buf += struct.pack('BBBB', timeout, priority, range_subid, 0)
|
buf += struct.pack("BBBB", timeout, priority, range_subid, 0)
|
||||||
# Sub Tree
|
# Sub Tree
|
||||||
buf += self.encode_oid(self.oid)
|
buf += self.encode_oid(self.oid)
|
||||||
|
|
||||||
elif self.type == agentx.AGENTX_RESPONSE_PDU:
|
elif self.type == agentx.AGENTX_RESPONSE_PDU:
|
||||||
buf += struct.pack('!LHH', 0, self.error, self.error_index)
|
buf += struct.pack("!LHH", 0, self.error, self.error_index)
|
||||||
for value in self.values:
|
for value in self.values:
|
||||||
buf += self.encode_value(value['type'], value['name'],
|
buf += self.encode_value(value["type"], value["name"], value["value"])
|
||||||
value['value'])
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Unsupported PDU type
|
# Unsupported PDU type
|
||||||
@ -156,27 +160,27 @@ class PDU(object):
|
|||||||
|
|
||||||
def decode_oid(self):
|
def decode_oid(self):
|
||||||
try:
|
try:
|
||||||
t = struct.unpack('!BBBB', self.decode_buf[:4])
|
t = struct.unpack("!BBBB", self.decode_buf[:4])
|
||||||
self.decode_buf = self.decode_buf[4:]
|
self.decode_buf = self.decode_buf[4:]
|
||||||
ret = {
|
ret = {
|
||||||
'n_subid': t[0],
|
"n_subid": t[0],
|
||||||
'prefix': t[1],
|
"prefix": t[1],
|
||||||
'include': t[2],
|
"include": t[2],
|
||||||
'reserved': t[3],
|
"reserved": t[3],
|
||||||
}
|
}
|
||||||
sub_ids = []
|
sub_ids = []
|
||||||
if ret['prefix']:
|
if ret["prefix"]:
|
||||||
sub_ids = [1, 3, 6, 1]
|
sub_ids = [1, 3, 6, 1]
|
||||||
sub_ids.append(ret['prefix'])
|
sub_ids.append(ret["prefix"])
|
||||||
for i in range(ret['n_subid']):
|
for i in range(ret["n_subid"]):
|
||||||
t = struct.unpack('!L', self.decode_buf[:4])
|
t = struct.unpack("!L", self.decode_buf[:4])
|
||||||
self.decode_buf = self.decode_buf[4:]
|
self.decode_buf = self.decode_buf[4:]
|
||||||
sub_ids.append(t[0])
|
sub_ids.append(t[0])
|
||||||
oid = '.'.join(str(i) for i in sub_ids)
|
oid = ".".join(str(i) for i in sub_ids)
|
||||||
return oid, ret['include']
|
return oid, ret["include"]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception('Invalid packing OID header')
|
logger.exception("Invalid packing OID header")
|
||||||
logger.debug('%s' % pprint.pformat(self.decode_buf))
|
logger.debug("%s" % pprint.pformat(self.decode_buf))
|
||||||
|
|
||||||
def decode_search_range(self):
|
def decode_search_range(self):
|
||||||
start_oid, include = self.decode_oid()
|
start_oid, include = self.decode_oid()
|
||||||
@ -193,115 +197,122 @@ class PDU(object):
|
|||||||
|
|
||||||
def decode_octet(self):
|
def decode_octet(self):
|
||||||
try:
|
try:
|
||||||
t = struct.unpack('!L', self.decode_buf[:4])
|
t = struct.unpack("!L", self.decode_buf[:4])
|
||||||
l = t[0]
|
l = t[0]
|
||||||
self.decode_buf = self.decode_buf[4:]
|
self.decode_buf = self.decode_buf[4:]
|
||||||
padding = 4 - (l % 4)
|
padding = 4 - (l % 4)
|
||||||
buf = self.decode_buf[:l]
|
buf = self.decode_buf[:l]
|
||||||
self.decode_buf = self.decode_buf[l + padding:]
|
self.decode_buf = self.decode_buf[l + padding :]
|
||||||
return buf
|
return buf
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception('Invalid packing octet header')
|
logger.exception("Invalid packing octet header")
|
||||||
|
|
||||||
def decode_value(self):
|
def decode_value(self):
|
||||||
try:
|
try:
|
||||||
vtype, _ = struct.unpack('!HH', self.decode_buf[:4])
|
vtype, _ = struct.unpack("!HH", self.decode_buf[:4])
|
||||||
self.decode_buf = self.decode_buf[4:]
|
self.decode_buf = self.decode_buf[4:]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception('Invalid packing value header')
|
logger.exception("Invalid packing value header")
|
||||||
oid, _ = self.decode_oid()
|
oid, _ = self.decode_oid()
|
||||||
if vtype in [
|
if vtype in [
|
||||||
agentx.TYPE_INTEGER, agentx.TYPE_COUNTER32,
|
agentx.TYPE_INTEGER,
|
||||||
agentx.TYPE_GAUGE32, agentx.TYPE_TIMETICKS
|
agentx.TYPE_COUNTER32,
|
||||||
|
agentx.TYPE_GAUGE32,
|
||||||
|
agentx.TYPE_TIMETICKS,
|
||||||
]:
|
]:
|
||||||
data = struct.unpack('!L', self.decode_buf[:4])
|
data = struct.unpack("!L", self.decode_buf[:4])
|
||||||
data = data[0]
|
data = data[0]
|
||||||
self.decode_buf = self.decode_buf[4:]
|
self.decode_buf = self.decode_buf[4:]
|
||||||
elif vtype in [agentx.TYPE_COUNTER64]:
|
elif vtype in [agentx.TYPE_COUNTER64]:
|
||||||
data = struct.unpack('!Q', self.decode_buf[:8])
|
data = struct.unpack("!Q", self.decode_buf[:8])
|
||||||
data = data[0]
|
data = data[0]
|
||||||
self.decode_buf = self.decode_buf[8:]
|
self.decode_buf = self.decode_buf[8:]
|
||||||
elif vtype in [agentx.TYPE_OBJECTIDENTIFIER]:
|
elif vtype in [agentx.TYPE_OBJECTIDENTIFIER]:
|
||||||
data, _ = self.decode_oid()
|
data, _ = self.decode_oid()
|
||||||
elif vtype in [
|
elif vtype in [
|
||||||
agentx.TYPE_IPADDRESS, agentx.TYPE_OPAQUE,
|
agentx.TYPE_IPADDRESS,
|
||||||
agentx.TYPE_OCTETSTRING
|
agentx.TYPE_OPAQUE,
|
||||||
|
agentx.TYPE_OCTETSTRING,
|
||||||
]:
|
]:
|
||||||
data = self.decode_octet()
|
data = self.decode_octet()
|
||||||
elif vtype in [
|
elif vtype in [
|
||||||
agentx.TYPE_NULL, agentx.TYPE_NOSUCHOBJECT,
|
agentx.TYPE_NULL,
|
||||||
agentx.TYPE_NOSUCHINSTANCE, agentx.TYPE_ENDOFMIBVIEW
|
agentx.TYPE_NOSUCHOBJECT,
|
||||||
|
agentx.TYPE_NOSUCHINSTANCE,
|
||||||
|
agentx.TYPE_ENDOFMIBVIEW,
|
||||||
]:
|
]:
|
||||||
# No data
|
# No data
|
||||||
data = None
|
data = None
|
||||||
else:
|
else:
|
||||||
logger.error('Unknown Type: %s' % vtype)
|
logger.error("Unknown Type: %s" % vtype)
|
||||||
return {'type': vtype, 'name': oid, 'data': data}
|
return {"type": vtype, "name": oid, "data": data}
|
||||||
|
|
||||||
def decode_header(self):
|
def decode_header(self):
|
||||||
try:
|
try:
|
||||||
t = struct.unpack('!BBBBLLLL', self.decode_buf[:20])
|
t = struct.unpack("!BBBBLLLL", self.decode_buf[:20])
|
||||||
self.decode_buf = self.decode_buf[20:]
|
self.decode_buf = self.decode_buf[20:]
|
||||||
ret = {
|
ret = {
|
||||||
'version': t[0],
|
"version": t[0],
|
||||||
'pdu_type': t[1],
|
"pdu_type": t[1],
|
||||||
'pdu_type_name': agentx.PDU_TYPE_NAME[t[1]],
|
"pdu_type_name": agentx.PDU_TYPE_NAME[t[1]],
|
||||||
'flags': t[2],
|
"flags": t[2],
|
||||||
'reserved': t[3],
|
"reserved": t[3],
|
||||||
'session_id': t[4],
|
"session_id": t[4],
|
||||||
'transaction_id': t[5],
|
"transaction_id": t[5],
|
||||||
'packet_id': t[6],
|
"packet_id": t[6],
|
||||||
'payload_length': t[7],
|
"payload_length": t[7],
|
||||||
}
|
}
|
||||||
self.state = ret
|
self.state = ret
|
||||||
self.type = ret['pdu_type']
|
self.type = ret["pdu_type"]
|
||||||
self.session_id = ret['session_id']
|
self.session_id = ret["session_id"]
|
||||||
self.packet_id = ret['packet_id']
|
self.packet_id = ret["packet_id"]
|
||||||
self.transaction_id = ret['transaction_id']
|
self.transaction_id = ret["transaction_id"]
|
||||||
self.decode_buf = self.decode_buf[:ret['payload_length']]
|
self.decode_buf = self.decode_buf[: ret["payload_length"]]
|
||||||
if ret['flags'] & 0x08: # content present
|
if ret["flags"] & 0x08: # content present
|
||||||
context = self.decode_octet()
|
context = self.decode_octet()
|
||||||
logger.debug('Context: %s' % context)
|
logger.debug("Context: %s" % context)
|
||||||
return ret
|
return ret
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception('Invalid packing: %d' % len(self.decode_buf))
|
logger.exception("Invalid packing: %d" % len(self.decode_buf))
|
||||||
logger.debug('%s' % pprint.pformat(self.decode_buf))
|
logger.debug("%s" % pprint.pformat(self.decode_buf))
|
||||||
|
|
||||||
def decode(self, buf):
|
def decode(self, buf):
|
||||||
self.set_decode_buf(buf)
|
self.set_decode_buf(buf)
|
||||||
ret = self.decode_header()
|
ret = self.decode_header()
|
||||||
if ret['pdu_type'] == agentx.AGENTX_RESPONSE_PDU:
|
if ret["pdu_type"] == agentx.AGENTX_RESPONSE_PDU:
|
||||||
# Decode Response Header
|
# Decode Response Header
|
||||||
t = struct.unpack('!LHH', self.decode_buf[:8])
|
t = struct.unpack("!LHH", self.decode_buf[:8])
|
||||||
self.decode_buf = self.decode_buf[8:]
|
self.decode_buf = self.decode_buf[8:]
|
||||||
self.response = {
|
self.response = {
|
||||||
'sysUpTime': t[0],
|
"sysUpTime": t[0],
|
||||||
'error': t[1],
|
"error": t[1],
|
||||||
'error_name': agentx.ERROR_NAMES[t[1]],
|
"error_name": agentx.ERROR_NAMES[t[1]],
|
||||||
'index': t[2],
|
"index": t[2],
|
||||||
}
|
}
|
||||||
# Decode VarBindList
|
# Decode VarBindList
|
||||||
self.values = []
|
self.values = []
|
||||||
while len(self.decode_buf):
|
while len(self.decode_buf):
|
||||||
self.values.append(self.decode_value())
|
self.values.append(self.decode_value())
|
||||||
|
|
||||||
elif ret['pdu_type'] == agentx.AGENTX_GET_PDU:
|
elif ret["pdu_type"] == agentx.AGENTX_GET_PDU:
|
||||||
self.range_list = self.decode_search_range_list()
|
self.range_list = self.decode_search_range_list()
|
||||||
|
|
||||||
elif ret['pdu_type'] == agentx.AGENTX_GETNEXT_PDU:
|
elif ret["pdu_type"] == agentx.AGENTX_GETNEXT_PDU:
|
||||||
self.range_list = self.decode_search_range_list()
|
self.range_list = self.decode_search_range_list()
|
||||||
|
|
||||||
elif ret['pdu_type'] == agentx.AGENTX_TESTSET_PDU:
|
elif ret["pdu_type"] == agentx.AGENTX_TESTSET_PDU:
|
||||||
# Decode VarBindList
|
# Decode VarBindList
|
||||||
self.values = []
|
self.values = []
|
||||||
while len(self.decode_buf):
|
while len(self.decode_buf):
|
||||||
self.values.append(self.decode_value())
|
self.values.append(self.decode_value())
|
||||||
elif ret['pdu_type'] in [
|
elif ret["pdu_type"] in [
|
||||||
agentx.AGENTX_COMMITSET_PDU, agentx.AGENTX_UNDOSET_PDU,
|
agentx.AGENTX_COMMITSET_PDU,
|
||||||
agentx.AGENTX_CLEANUPSET_PDU
|
agentx.AGENTX_UNDOSET_PDU,
|
||||||
|
agentx.AGENTX_CLEANUPSET_PDU,
|
||||||
]:
|
]:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
pdu_type_str = agentx.PDU_TYPE_NAME.get(
|
pdu_type_str = agentx.PDU_TYPE_NAME.get(
|
||||||
ret['pdu_type'], 'Unknown:' + str(ret['pdu_type']))
|
ret["pdu_type"], "Unknown:" + str(ret["pdu_type"])
|
||||||
logger.error('Unsupported PDU type:' + pdu_type_str)
|
)
|
||||||
|
logger.error("Unsupported PDU type:" + pdu_type_str)
|
||||||
|
@ -13,9 +13,10 @@ except ImportError:
|
|||||||
print("ERROR: install argparse manually: sudo pip install argparse")
|
print("ERROR: install argparse manually: sudo pip install argparse")
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
|
|
||||||
def get_phy_by_sw_if_index(ifaces, sw_if_index):
|
def get_phy_by_sw_if_index(ifaces, sw_if_index):
|
||||||
try:
|
try:
|
||||||
for k,v in ifaces.items():
|
for k, v in ifaces.items():
|
||||||
if v.sw_if_index == sw_if_index:
|
if v.sw_if_index == sw_if_index:
|
||||||
return v
|
return v
|
||||||
except:
|
except:
|
||||||
@ -25,7 +26,7 @@ def get_phy_by_sw_if_index(ifaces, sw_if_index):
|
|||||||
|
|
||||||
def get_lcp_by_host_sw_if_index(lcp, host_sw_if_index):
|
def get_lcp_by_host_sw_if_index(lcp, host_sw_if_index):
|
||||||
try:
|
try:
|
||||||
for k,v in lcp.items():
|
for k, v in lcp.items():
|
||||||
if v.host_sw_if_index == host_sw_if_index:
|
if v.host_sw_if_index == host_sw_if_index:
|
||||||
return v
|
return v
|
||||||
except:
|
except:
|
||||||
@ -35,27 +36,27 @@ def get_lcp_by_host_sw_if_index(lcp, host_sw_if_index):
|
|||||||
|
|
||||||
def get_description_by_ifname(config, name):
|
def get_description_by_ifname(config, name):
|
||||||
try:
|
try:
|
||||||
if 'interfaces' in config:
|
if "interfaces" in config:
|
||||||
for ifname, iface in config['interfaces'].items():
|
for ifname, iface in config["interfaces"].items():
|
||||||
if ifname == name:
|
if ifname == name:
|
||||||
return iface['description']
|
return iface["description"]
|
||||||
if 'sub-interfaces' in iface:
|
if "sub-interfaces" in iface:
|
||||||
for sub_id, sub_iface in iface['sub-interfaces'].items():
|
for sub_id, sub_iface in iface["sub-interfaces"].items():
|
||||||
sub_ifname = "%s.%d" % (ifname, sub_id)
|
sub_ifname = "%s.%d" % (ifname, sub_id)
|
||||||
if name == sub_ifname:
|
if name == sub_ifname:
|
||||||
return sub_iface['description']
|
return sub_iface["description"]
|
||||||
if 'loopbacks' in config:
|
if "loopbacks" in config:
|
||||||
for ifname, iface in config['loopbacks'].items():
|
for ifname, iface in config["loopbacks"].items():
|
||||||
if ifname == name:
|
if ifname == name:
|
||||||
return iface['description']
|
return iface["description"]
|
||||||
if 'taps' in config:
|
if "taps" in config:
|
||||||
for ifname, iface in config['taps'].items():
|
for ifname, iface in config["taps"].items():
|
||||||
if ifname == name:
|
if ifname == name:
|
||||||
return iface['description']
|
return iface["description"]
|
||||||
if 'vxlan_tunnels' in config:
|
if "vxlan_tunnels" in config:
|
||||||
for ifname, iface in config['vxlan_tunnels'].items():
|
for ifname, iface in config["vxlan_tunnels"].items():
|
||||||
if ifname == name:
|
if ifname == name:
|
||||||
return iface['description']
|
return iface["description"]
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
return None
|
return None
|
||||||
@ -70,32 +71,31 @@ class MyAgent(agentx.Agent):
|
|||||||
try:
|
try:
|
||||||
with open(args.config, "r") as f:
|
with open(args.config, "r") as f:
|
||||||
self.logger.info("Loading configfile %s" % args.config)
|
self.logger.info("Loading configfile %s" % args.config)
|
||||||
self.config = yaml.load(f, Loader = yaml.FullLoader)
|
self.config = yaml.load(f, Loader=yaml.FullLoader)
|
||||||
self.logger.debug("Config: %s" % self.config)
|
self.logger.debug("Config: %s" % self.config)
|
||||||
except:
|
except:
|
||||||
self.logger.error("Couldn't read config from %s" % args.config)
|
self.logger.error("Couldn't read config from %s" % args.config)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.logger.info("Connecting to VPP Stats Segment")
|
self.logger.info("Connecting to VPP Stats Segment")
|
||||||
vppstat = VPPStats(socketname='/run/vpp/stats.sock', timeout=2)
|
vppstat = VPPStats(socketname="/run/vpp/stats.sock", timeout=2)
|
||||||
vppstat.connect()
|
vppstat.connect()
|
||||||
except:
|
except:
|
||||||
self.logger.error("Could not connect to VPPStats segment")
|
self.logger.error("Could not connect to VPPStats segment")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
vpp = VPPApi(clientname='vpp-snmp-agent')
|
vpp = VPPApi(clientname="vpp-snmp-agent")
|
||||||
vpp.connect()
|
vpp.connect()
|
||||||
except:
|
except:
|
||||||
self.logger.error("Could not connect to VPP API")
|
self.logger.error("Could not connect to VPP API")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.register('1.3.6.1.2.1.2.2.1')
|
self.register("1.3.6.1.2.1.2.2.1")
|
||||||
self.register('1.3.6.1.2.1.31.1.1.1')
|
self.register("1.3.6.1.2.1.31.1.1.1")
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
global vppstat, vpp, args
|
global vppstat, vpp, args
|
||||||
|
|
||||||
@ -115,51 +115,61 @@ class MyAgent(agentx.Agent):
|
|||||||
ifaces = vpp.get_ifaces()
|
ifaces = vpp.get_ifaces()
|
||||||
lcp = vpp.get_lcp()
|
lcp = vpp.get_lcp()
|
||||||
|
|
||||||
num_ifaces=len(ifaces)
|
num_ifaces = len(ifaces)
|
||||||
num_vppstat=len(vppstat['/if/names'])
|
num_vppstat = len(vppstat["/if/names"])
|
||||||
num_lcp=len(lcp)
|
num_lcp = len(lcp)
|
||||||
self.logger.debug("LCP: %s" % (lcp))
|
self.logger.debug("LCP: %s" % (lcp))
|
||||||
self.logger.debug("Retrieved Interfaces: vppapi=%d vppstats=%d lcp=%d" % (num_ifaces, num_vppstat, num_lcp))
|
self.logger.debug(
|
||||||
|
"Retrieved Interfaces: vppapi=%d vppstats=%d lcp=%d"
|
||||||
|
% (num_ifaces, num_vppstat, num_lcp)
|
||||||
|
)
|
||||||
|
|
||||||
if num_ifaces != num_vppstat:
|
if num_ifaces != num_vppstat:
|
||||||
self.logger.warning("Interfaces count mismatch: vppapi=%d vppstats=%d" % (num_ifaces, num_vppstat))
|
self.logger.warning(
|
||||||
|
"Interfaces count mismatch: vppapi=%d vppstats=%d"
|
||||||
|
% (num_ifaces, num_vppstat)
|
||||||
|
)
|
||||||
|
|
||||||
for i in range(len(vppstat['/if/names'])):
|
for i in range(len(vppstat["/if/names"])):
|
||||||
ifname = vppstat['/if/names'][i]
|
ifname = vppstat["/if/names"][i]
|
||||||
idx = 1000+i
|
idx = 1000 + i
|
||||||
|
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.1.%u' % (idx), 'int', idx)
|
ds.set("1.3.6.1.2.1.2.2.1.1.%u" % (idx), "int", idx)
|
||||||
|
|
||||||
ifName=ifname
|
ifName = ifname
|
||||||
ifAlias=None
|
ifAlias = None
|
||||||
try:
|
try:
|
||||||
if self.config and ifname.startswith('tap'):
|
if self.config and ifname.startswith("tap"):
|
||||||
host_sw_if_index = ifaces[ifname].sw_if_index
|
host_sw_if_index = ifaces[ifname].sw_if_index
|
||||||
lip = get_lcp_by_host_sw_if_index(lcp, host_sw_if_index)
|
lip = get_lcp_by_host_sw_if_index(lcp, host_sw_if_index)
|
||||||
if lip:
|
if lip:
|
||||||
phy = get_phy_by_sw_if_index(ifaces, lip.phy_sw_if_index)
|
phy = get_phy_by_sw_if_index(ifaces, lip.phy_sw_if_index)
|
||||||
ifName = lip.host_if_name
|
ifName = lip.host_if_name
|
||||||
self.logger.debug("Setting ifName of %s to '%s'" % (ifname, ifName))
|
self.logger.debug(
|
||||||
|
"Setting ifName of %s to '%s'" % (ifname, ifName)
|
||||||
|
)
|
||||||
if phy:
|
if phy:
|
||||||
ifAlias = "LCP %s (%s)" % (phy.interface_name,ifname)
|
ifAlias = "LCP %s (%s)" % (phy.interface_name, ifname)
|
||||||
self.logger.debug("Setting ifAlias of %s to '%s'" % (ifname, ifAlias))
|
self.logger.debug(
|
||||||
|
"Setting ifAlias of %s to '%s'" % (ifname, ifAlias)
|
||||||
|
)
|
||||||
except:
|
except:
|
||||||
self.logger.debug("No config entry found for ifname %s" % (ifname))
|
self.logger.debug("No config entry found for ifname %s" % (ifname))
|
||||||
pass
|
pass
|
||||||
|
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.2.%u' % (idx), 'str', ifName)
|
ds.set("1.3.6.1.2.1.2.2.1.2.%u" % (idx), "str", ifName)
|
||||||
|
|
||||||
if ifname.startswith("loop"):
|
if ifname.startswith("loop"):
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.3.%u' % (idx), 'int', 24) # softwareLoopback
|
ds.set("1.3.6.1.2.1.2.2.1.3.%u" % (idx), "int", 24) # softwareLoopback
|
||||||
else:
|
else:
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.3.%u' % (idx), 'int', 6) # ethermet-csmacd
|
ds.set("1.3.6.1.2.1.2.2.1.3.%u" % (idx), "int", 6) # ethermet-csmacd
|
||||||
|
|
||||||
mtu = 0
|
mtu = 0
|
||||||
if not ifname in ifaces:
|
if not ifname in ifaces:
|
||||||
self.logger.warning("Could not get MTU for interface %s", ifname)
|
self.logger.warning("Could not get MTU for interface %s", ifname)
|
||||||
else:
|
else:
|
||||||
mtu = ifaces[ifname].mtu[0]
|
mtu = ifaces[ifname].mtu[0]
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.4.%u' % (idx), 'int', mtu)
|
ds.set("1.3.6.1.2.1.2.2.1.4.%u" % (idx), "int", mtu)
|
||||||
|
|
||||||
speed = 0
|
speed = 0
|
||||||
if ifname.startswith("loop") or ifname.startswith("tap"):
|
if ifname.startswith("loop") or ifname.startswith("tap"):
|
||||||
@ -168,26 +178,30 @@ class MyAgent(agentx.Agent):
|
|||||||
self.logger.warning("Could not get link speed for interface %s", ifname)
|
self.logger.warning("Could not get link speed for interface %s", ifname)
|
||||||
else:
|
else:
|
||||||
speed = ifaces[ifname].link_speed * 1000
|
speed = ifaces[ifname].link_speed * 1000
|
||||||
if speed >= 2**32:
|
if speed >= 2 ** 32:
|
||||||
speed = 2**32 - 1
|
speed = 2 ** 32 - 1
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.5.%u' % (idx), 'gauge32', speed)
|
ds.set("1.3.6.1.2.1.2.2.1.5.%u" % (idx), "gauge32", speed)
|
||||||
|
|
||||||
mac = "00:00:00:00:00:00"
|
mac = "00:00:00:00:00:00"
|
||||||
if not ifname in ifaces:
|
if not ifname in ifaces:
|
||||||
self.logger.warning("Could not get PhysAddress for interface %s", ifname)
|
self.logger.warning(
|
||||||
|
"Could not get PhysAddress for interface %s", ifname
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
mac = str(ifaces[ifname].l2_address)
|
mac = str(ifaces[ifname].l2_address)
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.6.%u' % (idx), 'str', mac)
|
ds.set("1.3.6.1.2.1.2.2.1.6.%u" % (idx), "str", mac)
|
||||||
|
|
||||||
admin_status = 3 # testing
|
admin_status = 3 # testing
|
||||||
if not ifname in ifaces:
|
if not ifname in ifaces:
|
||||||
self.logger.warning("Could not get AdminStatus for interface %s", ifname)
|
self.logger.warning(
|
||||||
|
"Could not get AdminStatus for interface %s", ifname
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
if int(ifaces[ifname].flags) & 1:
|
if int(ifaces[ifname].flags) & 1:
|
||||||
admin_status = 1 # up
|
admin_status = 1 # up
|
||||||
else:
|
else:
|
||||||
admin_status = 2 # down
|
admin_status = 2 # down
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.7.%u' % (idx), 'int', admin_status)
|
ds.set("1.3.6.1.2.1.2.2.1.7.%u" % (idx), "int", admin_status)
|
||||||
|
|
||||||
oper_status = 3 # testing
|
oper_status = 3 # testing
|
||||||
if not ifname in ifaces:
|
if not ifname in ifaces:
|
||||||
@ -197,36 +211,124 @@ class MyAgent(agentx.Agent):
|
|||||||
oper_status = 1 # up
|
oper_status = 1 # up
|
||||||
else:
|
else:
|
||||||
oper_status = 2 # down
|
oper_status = 2 # down
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.8.%u' % (idx), 'int', oper_status)
|
ds.set("1.3.6.1.2.1.2.2.1.8.%u" % (idx), "int", oper_status)
|
||||||
|
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.9.%u' % (idx), 'ticks', 0)
|
ds.set("1.3.6.1.2.1.2.2.1.9.%u" % (idx), "ticks", 0)
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.10.%u' % (idx), 'u32', vppstat['/if/rx'][:, i].sum_octets() % 2**32)
|
ds.set(
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.11.%u' % (idx), 'u32', vppstat['/if/rx'][:, i].sum_packets() % 2**32)
|
"1.3.6.1.2.1.2.2.1.10.%u" % (idx),
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.12.%u' % (idx), 'u32', vppstat['/if/rx-multicast'][:, i].sum_packets() % 2**32)
|
"u32",
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.13.%u' % (idx), 'u32', vppstat['/if/rx-no-buf'][:, i].sum() % 2**32)
|
vppstat["/if/rx"][:, i].sum_octets() % 2 ** 32,
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.14.%u' % (idx), 'u32', vppstat['/if/rx-error'][:, i].sum() % 2**32)
|
)
|
||||||
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.2.2.1.11.%u" % (idx),
|
||||||
|
"u32",
|
||||||
|
vppstat["/if/rx"][:, i].sum_packets() % 2 ** 32,
|
||||||
|
)
|
||||||
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.2.2.1.12.%u" % (idx),
|
||||||
|
"u32",
|
||||||
|
vppstat["/if/rx-multicast"][:, i].sum_packets() % 2 ** 32,
|
||||||
|
)
|
||||||
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.2.2.1.13.%u" % (idx),
|
||||||
|
"u32",
|
||||||
|
vppstat["/if/rx-no-buf"][:, i].sum() % 2 ** 32,
|
||||||
|
)
|
||||||
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.2.2.1.14.%u" % (idx),
|
||||||
|
"u32",
|
||||||
|
vppstat["/if/rx-error"][:, i].sum() % 2 ** 32,
|
||||||
|
)
|
||||||
|
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.16.%u' % (idx), 'u32', vppstat['/if/tx'][:, i].sum_octets() % 2**32)
|
ds.set(
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.17.%u' % (idx), 'u32', vppstat['/if/tx'][:, i].sum_packets() % 2**32)
|
"1.3.6.1.2.1.2.2.1.16.%u" % (idx),
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.18.%u' % (idx), 'u32', vppstat['/if/tx-multicast'][:, i].sum_packets() % 2**32)
|
"u32",
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.19.%u' % (idx), 'u32', vppstat['/if/drops'][:, i].sum() % 2**32)
|
vppstat["/if/tx"][:, i].sum_octets() % 2 ** 32,
|
||||||
ds.set('1.3.6.1.2.1.2.2.1.20.%u' % (idx), 'u32', vppstat['/if/tx-error'][:, i].sum() % 2**32)
|
)
|
||||||
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.2.2.1.17.%u" % (idx),
|
||||||
|
"u32",
|
||||||
|
vppstat["/if/tx"][:, i].sum_packets() % 2 ** 32,
|
||||||
|
)
|
||||||
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.2.2.1.18.%u" % (idx),
|
||||||
|
"u32",
|
||||||
|
vppstat["/if/tx-multicast"][:, i].sum_packets() % 2 ** 32,
|
||||||
|
)
|
||||||
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.2.2.1.19.%u" % (idx),
|
||||||
|
"u32",
|
||||||
|
vppstat["/if/drops"][:, i].sum() % 2 ** 32,
|
||||||
|
)
|
||||||
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.2.2.1.20.%u" % (idx),
|
||||||
|
"u32",
|
||||||
|
vppstat["/if/tx-error"][:, i].sum() % 2 ** 32,
|
||||||
|
)
|
||||||
|
|
||||||
ds.set('1.3.6.1.2.1.31.1.1.1.1.%u' % (idx), 'str', ifName)
|
ds.set("1.3.6.1.2.1.31.1.1.1.1.%u" % (idx), "str", ifName)
|
||||||
ds.set('1.3.6.1.2.1.31.1.1.1.2.%u' % (idx), 'u32', vppstat['/if/rx-multicast'][:, i].sum_packets() % 2**32)
|
ds.set(
|
||||||
ds.set('1.3.6.1.2.1.31.1.1.1.3.%u' % (idx), 'u32', vppstat['/if/rx-broadcast'][:, i].sum_packets() % 2**32)
|
"1.3.6.1.2.1.31.1.1.1.2.%u" % (idx),
|
||||||
ds.set('1.3.6.1.2.1.31.1.1.1.4.%u' % (idx), 'u32', vppstat['/if/tx-multicast'][:, i].sum_packets() % 2**32)
|
"u32",
|
||||||
ds.set('1.3.6.1.2.1.31.1.1.1.5.%u' % (idx), 'u32', vppstat['/if/tx-broadcast'][:, i].sum_packets() % 2**32)
|
vppstat["/if/rx-multicast"][:, i].sum_packets() % 2 ** 32,
|
||||||
|
)
|
||||||
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.31.1.1.1.3.%u" % (idx),
|
||||||
|
"u32",
|
||||||
|
vppstat["/if/rx-broadcast"][:, i].sum_packets() % 2 ** 32,
|
||||||
|
)
|
||||||
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.31.1.1.1.4.%u" % (idx),
|
||||||
|
"u32",
|
||||||
|
vppstat["/if/tx-multicast"][:, i].sum_packets() % 2 ** 32,
|
||||||
|
)
|
||||||
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.31.1.1.1.5.%u" % (idx),
|
||||||
|
"u32",
|
||||||
|
vppstat["/if/tx-broadcast"][:, i].sum_packets() % 2 ** 32,
|
||||||
|
)
|
||||||
|
|
||||||
ds.set('1.3.6.1.2.1.31.1.1.1.6.%u' % (idx), 'u64', vppstat['/if/rx'][:, i].sum_octets())
|
ds.set(
|
||||||
ds.set('1.3.6.1.2.1.31.1.1.1.7.%u' % (idx), 'u64', vppstat['/if/rx'][:, i].sum_packets())
|
"1.3.6.1.2.1.31.1.1.1.6.%u" % (idx),
|
||||||
ds.set('1.3.6.1.2.1.31.1.1.1.8.%u' % (idx), 'u64', vppstat['/if/rx-multicast'][:, i].sum_packets())
|
"u64",
|
||||||
ds.set('1.3.6.1.2.1.31.1.1.1.9.%u' % (idx), 'u64', vppstat['/if/rx-broadcast'][:, i].sum_packets())
|
vppstat["/if/rx"][:, i].sum_octets(),
|
||||||
|
)
|
||||||
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.31.1.1.1.7.%u" % (idx),
|
||||||
|
"u64",
|
||||||
|
vppstat["/if/rx"][:, i].sum_packets(),
|
||||||
|
)
|
||||||
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.31.1.1.1.8.%u" % (idx),
|
||||||
|
"u64",
|
||||||
|
vppstat["/if/rx-multicast"][:, i].sum_packets(),
|
||||||
|
)
|
||||||
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.31.1.1.1.9.%u" % (idx),
|
||||||
|
"u64",
|
||||||
|
vppstat["/if/rx-broadcast"][:, i].sum_packets(),
|
||||||
|
)
|
||||||
|
|
||||||
ds.set('1.3.6.1.2.1.31.1.1.1.10.%u' % (idx), 'u64', vppstat['/if/tx'][:, i].sum_octets())
|
ds.set(
|
||||||
ds.set('1.3.6.1.2.1.31.1.1.1.11.%u' % (idx), 'u64', vppstat['/if/tx'][:, i].sum_packets())
|
"1.3.6.1.2.1.31.1.1.1.10.%u" % (idx),
|
||||||
ds.set('1.3.6.1.2.1.31.1.1.1.12.%u' % (idx), 'u64', vppstat['/if/tx-multicast'][:, i].sum_packets())
|
"u64",
|
||||||
ds.set('1.3.6.1.2.1.31.1.1.1.13.%u' % (idx), 'u64', vppstat['/if/tx-broadcast'][:, i].sum_packets())
|
vppstat["/if/tx"][:, i].sum_octets(),
|
||||||
|
)
|
||||||
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.31.1.1.1.11.%u" % (idx),
|
||||||
|
"u64",
|
||||||
|
vppstat["/if/tx"][:, i].sum_packets(),
|
||||||
|
)
|
||||||
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.31.1.1.1.12.%u" % (idx),
|
||||||
|
"u64",
|
||||||
|
vppstat["/if/tx-multicast"][:, i].sum_packets(),
|
||||||
|
)
|
||||||
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.31.1.1.1.13.%u" % (idx),
|
||||||
|
"u64",
|
||||||
|
vppstat["/if/tx-broadcast"][:, i].sum_packets(),
|
||||||
|
)
|
||||||
|
|
||||||
speed = 0
|
speed = 0
|
||||||
if ifname.startswith("loop") or ifname.startswith("tap"):
|
if ifname.startswith("loop") or ifname.startswith("tap"):
|
||||||
@ -235,34 +337,65 @@ class MyAgent(agentx.Agent):
|
|||||||
self.logger.warning("Could not get link speed for interface %s", ifname)
|
self.logger.warning("Could not get link speed for interface %s", ifname)
|
||||||
else:
|
else:
|
||||||
speed = int(ifaces[ifname].link_speed / 1000)
|
speed = int(ifaces[ifname].link_speed / 1000)
|
||||||
ds.set('1.3.6.1.2.1.31.1.1.1.15.%u' % (idx), 'gauge32', speed)
|
ds.set("1.3.6.1.2.1.31.1.1.1.15.%u" % (idx), "gauge32", speed)
|
||||||
|
|
||||||
ds.set('1.3.6.1.2.1.31.1.1.1.16.%u' % (idx), 'int', 2) # Hardcode to false(2)
|
ds.set(
|
||||||
ds.set('1.3.6.1.2.1.31.1.1.1.17.%u' % (idx), 'int', 1) # Hardcode to true(1)
|
"1.3.6.1.2.1.31.1.1.1.16.%u" % (idx), "int", 2
|
||||||
|
) # Hardcode to false(2)
|
||||||
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.31.1.1.1.17.%u" % (idx), "int", 1
|
||||||
|
) # Hardcode to true(1)
|
||||||
|
|
||||||
if self.config and not ifAlias:
|
if self.config and not ifAlias:
|
||||||
try:
|
try:
|
||||||
descr = get_description_by_ifname(self.config, ifname)
|
descr = get_description_by_ifname(self.config, ifname)
|
||||||
if descr:
|
if descr:
|
||||||
self.logger.debug("Setting ifAlias of %s to config description '%s'" % (ifname, descr))
|
self.logger.debug(
|
||||||
|
"Setting ifAlias of %s to config description '%s'"
|
||||||
|
% (ifname, descr)
|
||||||
|
)
|
||||||
ifAlias = descr
|
ifAlias = descr
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
if not ifAlias:
|
if not ifAlias:
|
||||||
self.logger.debug("Setting ifAlias of %s to ifname %s" % (ifname, ifname))
|
self.logger.debug(
|
||||||
|
"Setting ifAlias of %s to ifname %s" % (ifname, ifname)
|
||||||
|
)
|
||||||
ifAlias = ifname
|
ifAlias = ifname
|
||||||
ds.set('1.3.6.1.2.1.31.1.1.1.18.%u' % (idx), 'str', ifAlias)
|
ds.set("1.3.6.1.2.1.31.1.1.1.18.%u" % (idx), "str", ifAlias)
|
||||||
ds.set('1.3.6.1.2.1.31.1.1.1.19.%u' % (idx), 'ticks', 0) # Hardcode to Timeticks: (0) 0:00:00.00
|
ds.set(
|
||||||
|
"1.3.6.1.2.1.31.1.1.1.19.%u" % (idx), "ticks", 0
|
||||||
|
) # Hardcode to Timeticks: (0) 0:00:00.00
|
||||||
return ds
|
return ds
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
global args
|
global args
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
|
parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter)
|
||||||
parser.add_argument('-a', dest='address', default="localhost:705", type=str, help="""Location of the SNMPd agent (unix-path or host:port), default localhost:705""")
|
parser.add_argument(
|
||||||
parser.add_argument('-p', dest='period', type=int, default=30, help="""Period to poll VPP, default 30 (seconds)""")
|
"-a",
|
||||||
parser.add_argument('-c', dest='config', type=str, help="""Optional vppcfg YAML configuration file, default empty""")
|
dest="address",
|
||||||
parser.add_argument('-d', dest='debug', action='store_true', help="""Enable debug, default False""")
|
default="localhost:705",
|
||||||
|
type=str,
|
||||||
|
help="""Location of the SNMPd agent (unix-path or host:port), default localhost:705""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-p",
|
||||||
|
dest="period",
|
||||||
|
type=int,
|
||||||
|
default=30,
|
||||||
|
help="""Period to poll VPP, default 30 (seconds)""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-c",
|
||||||
|
dest="config",
|
||||||
|
type=str,
|
||||||
|
help="""Optional vppcfg YAML configuration file, default empty""",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-d", dest="debug", action="store_true", help="""Enable debug, default False"""
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
if args.debug:
|
if args.debug:
|
||||||
@ -281,5 +414,6 @@ def main():
|
|||||||
|
|
||||||
sys.exit(-1)
|
sys.exit(-1)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
25
vppapi.py
25
vppapi.py
@ -1,7 +1,7 @@
|
|||||||
'''
|
"""
|
||||||
The functions in this file interact with the VPP API to retrieve certain
|
The functions in this file interact with the VPP API to retrieve certain
|
||||||
interface metadata.
|
interface metadata.
|
||||||
'''
|
"""
|
||||||
|
|
||||||
from vpp_papi import VPPApiClient
|
from vpp_papi import VPPApiClient
|
||||||
import os
|
import os
|
||||||
@ -13,12 +13,14 @@ import socket
|
|||||||
class NullHandler(logging.Handler):
|
class NullHandler(logging.Handler):
|
||||||
def emit(self, record):
|
def emit(self, record):
|
||||||
pass
|
pass
|
||||||
logger = logging.getLogger('agentx.vppapi')
|
|
||||||
|
|
||||||
|
logger = logging.getLogger("agentx.vppapi")
|
||||||
logger.addHandler(NullHandler())
|
logger.addHandler(NullHandler())
|
||||||
|
|
||||||
|
|
||||||
class VPPApi():
|
class VPPApi:
|
||||||
def __init__(self, address='/run/vpp/api.sock', clientname='vppapi-client'):
|
def __init__(self, address="/run/vpp/api.sock", clientname="vppapi-client"):
|
||||||
self.address = address
|
self.address = address
|
||||||
self.connected = False
|
self.connected = False
|
||||||
self.clientname = clientname
|
self.clientname = clientname
|
||||||
@ -28,28 +30,27 @@ class VPPApi():
|
|||||||
if self.connected:
|
if self.connected:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
vpp_json_dir = '/usr/share/vpp/api/'
|
vpp_json_dir = "/usr/share/vpp/api/"
|
||||||
|
|
||||||
# construct a list of all the json api files
|
# construct a list of all the json api files
|
||||||
jsonfiles = []
|
jsonfiles = []
|
||||||
for root, dirnames, filenames in os.walk(vpp_json_dir):
|
for root, dirnames, filenames in os.walk(vpp_json_dir):
|
||||||
for filename in fnmatch.filter(filenames, '*.api.json'):
|
for filename in fnmatch.filter(filenames, "*.api.json"):
|
||||||
jsonfiles.append(os.path.join(root, filename))
|
jsonfiles.append(os.path.join(root, filename))
|
||||||
|
|
||||||
if not jsonfiles:
|
if not jsonfiles:
|
||||||
logger.error('no json api files found')
|
logger.error("no json api files found")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.vpp = VPPApiClient(apifiles=jsonfiles,
|
self.vpp = VPPApiClient(apifiles=jsonfiles, server_address=self.address)
|
||||||
server_address=self.address)
|
|
||||||
try:
|
try:
|
||||||
logger.info('Connecting to VPP')
|
logger.info("Connecting to VPP")
|
||||||
self.vpp.connect(self.clientname)
|
self.vpp.connect(self.clientname)
|
||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
v = self.vpp.api.show_version()
|
v = self.vpp.api.show_version()
|
||||||
logger.info('VPP version is %s' % v.version)
|
logger.info("VPP version is %s" % v.version)
|
||||||
|
|
||||||
self.connected = True
|
self.connected = True
|
||||||
return True
|
return True
|
||||||
|
205
vppstats.py
205
vppstats.py
@ -1,4 +1,4 @@
|
|||||||
'''
|
"""
|
||||||
VPPStats is a shared memory implementation that exposes the VPP statseg as
|
VPPStats is a shared memory implementation that exposes the VPP statseg as
|
||||||
an associative array. Counters can be accessed in either dimension.
|
an associative array. Counters can be accessed in either dimension.
|
||||||
stat['/if/rx'] - returns 2D lists
|
stat['/if/rx'] - returns 2D lists
|
||||||
@ -30,7 +30,7 @@ Usage:
|
|||||||
|
|
||||||
stat.disconnect()
|
stat.disconnect()
|
||||||
|
|
||||||
'''
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
@ -40,31 +40,36 @@ from struct import Struct
|
|||||||
import time
|
import time
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
|
||||||
def recv_fd(sock):
|
def recv_fd(sock):
|
||||||
'''Get file descriptor for memory map'''
|
"""Get file descriptor for memory map"""
|
||||||
fds = array.array("i") # Array of ints
|
fds = array.array("i") # Array of ints
|
||||||
_, ancdata, _, _ = sock.recvmsg(0, socket.CMSG_LEN(4))
|
_, ancdata, _, _ = sock.recvmsg(0, socket.CMSG_LEN(4))
|
||||||
for cmsg_level, cmsg_type, cmsg_data in ancdata:
|
for cmsg_level, cmsg_type, cmsg_data in ancdata:
|
||||||
if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS:
|
if cmsg_level == socket.SOL_SOCKET and cmsg_type == socket.SCM_RIGHTS:
|
||||||
fds.frombytes(cmsg_data[:len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])
|
fds.frombytes(cmsg_data[: len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])
|
||||||
return list(fds)[0]
|
return list(fds)[0]
|
||||||
|
|
||||||
VEC_LEN_FMT = Struct('I')
|
|
||||||
|
VEC_LEN_FMT = Struct("I")
|
||||||
|
|
||||||
|
|
||||||
def get_vec_len(stats, vector_offset):
|
def get_vec_len(stats, vector_offset):
|
||||||
'''Equivalent to VPP vec_len()'''
|
"""Equivalent to VPP vec_len()"""
|
||||||
return VEC_LEN_FMT.unpack_from(stats.statseg, vector_offset - 8)[0]
|
return VEC_LEN_FMT.unpack_from(stats.statseg, vector_offset - 8)[0]
|
||||||
|
|
||||||
|
|
||||||
def get_string(stats, ptr):
|
def get_string(stats, ptr):
|
||||||
'''Get a string from a VPP vector'''
|
"""Get a string from a VPP vector"""
|
||||||
namevector = ptr - stats.base
|
namevector = ptr - stats.base
|
||||||
namevectorlen = get_vec_len(stats, namevector)
|
namevectorlen = get_vec_len(stats, namevector)
|
||||||
if namevector + namevectorlen >= stats.size:
|
if namevector + namevectorlen >= stats.size:
|
||||||
raise IOError('String overruns stats segment')
|
raise IOError("String overruns stats segment")
|
||||||
return stats.statseg[namevector:namevector+namevectorlen-1].decode('ascii')
|
return stats.statseg[namevector : namevector + namevectorlen - 1].decode("ascii")
|
||||||
|
|
||||||
|
|
||||||
class StatsVector:
|
class StatsVector:
|
||||||
'''A class representing a VPP vector'''
|
"""A class representing a VPP vector"""
|
||||||
|
|
||||||
def __init__(self, stats, ptr, fmt):
|
def __init__(self, stats, ptr, fmt):
|
||||||
self.vec_start = ptr - stats.base
|
self.vec_start = ptr - stats.base
|
||||||
@ -76,28 +81,35 @@ class StatsVector:
|
|||||||
self.stats = stats
|
self.stats = stats
|
||||||
|
|
||||||
if self.vec_start + self.vec_len * self.elementsize >= stats.size:
|
if self.vec_start + self.vec_len * self.elementsize >= stats.size:
|
||||||
raise IOError('Vector overruns stats segment')
|
raise IOError("Vector overruns stats segment")
|
||||||
|
|
||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
with self.stats.lock:
|
with self.stats.lock:
|
||||||
return self.struct.iter_unpack(self.statseg[self.vec_start:self.vec_start +
|
return self.struct.iter_unpack(
|
||||||
self.elementsize*self.vec_len])
|
self.statseg[
|
||||||
|
self.vec_start : self.vec_start + self.elementsize * self.vec_len
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
def __getitem__(self, index):
|
def __getitem__(self, index):
|
||||||
if index > self.vec_len:
|
if index > self.vec_len:
|
||||||
raise IOError('Index beyond end of vector')
|
raise IOError("Index beyond end of vector")
|
||||||
with self.stats.lock:
|
with self.stats.lock:
|
||||||
if self.fmtlen == 1:
|
if self.fmtlen == 1:
|
||||||
return self.struct.unpack_from(self.statseg, self.vec_start +
|
return self.struct.unpack_from(
|
||||||
(index * self.elementsize))[0]
|
self.statseg, self.vec_start + (index * self.elementsize)
|
||||||
return self.struct.unpack_from(self.statseg, self.vec_start +
|
)[0]
|
||||||
(index * self.elementsize))
|
return self.struct.unpack_from(
|
||||||
|
self.statseg, self.vec_start + (index * self.elementsize)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class VPPStats:
|
||||||
|
"""Main class implementing Python access to the VPP statistics segment"""
|
||||||
|
|
||||||
class VPPStats():
|
|
||||||
'''Main class implementing Python access to the VPP statistics segment'''
|
|
||||||
# pylint: disable=too-many-instance-attributes
|
# pylint: disable=too-many-instance-attributes
|
||||||
shared_headerfmt = Struct('QPQQPP')
|
shared_headerfmt = Struct("QPQQPP")
|
||||||
default_socketname = '/run/vpp/stats.sock'
|
default_socketname = "/run/vpp/stats.sock"
|
||||||
|
|
||||||
def __init__(self, socketname=default_socketname, timeout=10):
|
def __init__(self, socketname=default_socketname, timeout=10):
|
||||||
self.socketname = socketname
|
self.socketname = socketname
|
||||||
@ -110,7 +122,7 @@ class VPPStats():
|
|||||||
self.statseg = 0
|
self.statseg = 0
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
'''Connect to stats segment'''
|
"""Connect to stats segment"""
|
||||||
if self.connected:
|
if self.connected:
|
||||||
return
|
return
|
||||||
sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET)
|
||||||
@ -120,61 +132,64 @@ class VPPStats():
|
|||||||
sock.close()
|
sock.close()
|
||||||
|
|
||||||
stat_result = os.fstat(mfd)
|
stat_result = os.fstat(mfd)
|
||||||
self.statseg = mmap.mmap(mfd, stat_result.st_size, mmap.PROT_READ, mmap.MAP_SHARED)
|
self.statseg = mmap.mmap(
|
||||||
|
mfd, stat_result.st_size, mmap.PROT_READ, mmap.MAP_SHARED
|
||||||
|
)
|
||||||
os.close(mfd)
|
os.close(mfd)
|
||||||
|
|
||||||
self.size = stat_result.st_size
|
self.size = stat_result.st_size
|
||||||
if self.version != 2:
|
if self.version != 2:
|
||||||
raise Exception('Incompatbile stat segment version {}'
|
raise Exception("Incompatbile stat segment version {}".format(self.version))
|
||||||
.format(self.version))
|
|
||||||
|
|
||||||
self.refresh()
|
self.refresh()
|
||||||
self.connected = True
|
self.connected = True
|
||||||
|
|
||||||
def disconnect(self):
|
def disconnect(self):
|
||||||
'''Disconnect from stats segment'''
|
"""Disconnect from stats segment"""
|
||||||
if self.connected:
|
if self.connected:
|
||||||
self.statseg.close()
|
self.statseg.close()
|
||||||
self.connected = False
|
self.connected = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def version(self):
|
def version(self):
|
||||||
'''Get version of stats segment'''
|
"""Get version of stats segment"""
|
||||||
return self.shared_headerfmt.unpack_from(self.statseg)[0]
|
return self.shared_headerfmt.unpack_from(self.statseg)[0]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def base(self):
|
def base(self):
|
||||||
'''Get base pointer of stats segment'''
|
"""Get base pointer of stats segment"""
|
||||||
return self.shared_headerfmt.unpack_from(self.statseg)[1]
|
return self.shared_headerfmt.unpack_from(self.statseg)[1]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def epoch(self):
|
def epoch(self):
|
||||||
'''Get current epoch value from stats segment'''
|
"""Get current epoch value from stats segment"""
|
||||||
return self.shared_headerfmt.unpack_from(self.statseg)[2]
|
return self.shared_headerfmt.unpack_from(self.statseg)[2]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def in_progress(self):
|
def in_progress(self):
|
||||||
'''Get value of in_progress from stats segment'''
|
"""Get value of in_progress from stats segment"""
|
||||||
return self.shared_headerfmt.unpack_from(self.statseg)[3]
|
return self.shared_headerfmt.unpack_from(self.statseg)[3]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def directory_vector(self):
|
def directory_vector(self):
|
||||||
'''Get pointer of directory vector'''
|
"""Get pointer of directory vector"""
|
||||||
return self.shared_headerfmt.unpack_from(self.statseg)[4]
|
return self.shared_headerfmt.unpack_from(self.statseg)[4]
|
||||||
|
|
||||||
elementfmt = 'IQ128s'
|
elementfmt = "IQ128s"
|
||||||
|
|
||||||
def refresh(self, blocking=True):
|
def refresh(self, blocking=True):
|
||||||
'''Refresh directory vector cache (epoch changed)'''
|
"""Refresh directory vector cache (epoch changed)"""
|
||||||
directory = {}
|
directory = {}
|
||||||
directory_by_idx = {}
|
directory_by_idx = {}
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
with self.lock:
|
with self.lock:
|
||||||
self.last_epoch = self.epoch
|
self.last_epoch = self.epoch
|
||||||
for i, direntry in enumerate(StatsVector(self, self.directory_vector, self.elementfmt)):
|
for i, direntry in enumerate(
|
||||||
path_raw = direntry[2].find(b'\x00')
|
StatsVector(self, self.directory_vector, self.elementfmt)
|
||||||
path = direntry[2][:path_raw].decode('ascii')
|
):
|
||||||
|
path_raw = direntry[2].find(b"\x00")
|
||||||
|
path = direntry[2][:path_raw].decode("ascii")
|
||||||
directory[path] = StatsEntry(direntry[0], direntry[1])
|
directory[path] = StatsEntry(direntry[0], direntry[1])
|
||||||
directory_by_idx[i] = path
|
directory_by_idx[i] = path
|
||||||
self.directory = directory
|
self.directory = directory
|
||||||
@ -200,14 +215,12 @@ class VPPStats():
|
|||||||
def __iter__(self):
|
def __iter__(self):
|
||||||
return iter(self.directory.items())
|
return iter(self.directory.items())
|
||||||
|
|
||||||
|
|
||||||
def set_errors(self, blocking=True):
|
def set_errors(self, blocking=True):
|
||||||
'''Return dictionary of error counters > 0'''
|
"""Return dictionary of error counters > 0"""
|
||||||
if not self.connected:
|
if not self.connected:
|
||||||
self.connect()
|
self.connect()
|
||||||
|
|
||||||
errors = {k: v for k, v in self.directory.items()
|
errors = {k: v for k, v in self.directory.items() if k.startswith("/err/")}
|
||||||
if k.startswith("/err/")}
|
|
||||||
result = {}
|
result = {}
|
||||||
for k in errors:
|
for k in errors:
|
||||||
try:
|
try:
|
||||||
@ -219,23 +232,23 @@ class VPPStats():
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def set_errors_str(self, blocking=True):
|
def set_errors_str(self, blocking=True):
|
||||||
'''Return all errors counters > 0 pretty printed'''
|
"""Return all errors counters > 0 pretty printed"""
|
||||||
error_string = ['ERRORS:']
|
error_string = ["ERRORS:"]
|
||||||
error_counters = self.set_errors(blocking)
|
error_counters = self.set_errors(blocking)
|
||||||
for k in sorted(error_counters):
|
for k in sorted(error_counters):
|
||||||
error_string.append('{:<60}{:>10}'.format(k, error_counters[k]))
|
error_string.append("{:<60}{:>10}".format(k, error_counters[k]))
|
||||||
return '%s\n' % '\n'.join(error_string)
|
return "%s\n" % "\n".join(error_string)
|
||||||
|
|
||||||
def get_counter(self, name, blocking=True):
|
def get_counter(self, name, blocking=True):
|
||||||
'''Alternative call to __getitem__'''
|
"""Alternative call to __getitem__"""
|
||||||
return self.__getitem__(name, blocking)
|
return self.__getitem__(name, blocking)
|
||||||
|
|
||||||
def get_err_counter(self, name, blocking=True):
|
def get_err_counter(self, name, blocking=True):
|
||||||
'''Alternative call to __getitem__'''
|
"""Alternative call to __getitem__"""
|
||||||
return self.__getitem__(name, blocking).sum()
|
return self.__getitem__(name, blocking).sum()
|
||||||
|
|
||||||
def ls(self, patterns):
|
def ls(self, patterns):
|
||||||
'''Returns list of counters matching pattern'''
|
"""Returns list of counters matching pattern"""
|
||||||
# pylint: disable=invalid-name
|
# pylint: disable=invalid-name
|
||||||
if not self.connected:
|
if not self.connected:
|
||||||
self.connect()
|
self.connect()
|
||||||
@ -245,20 +258,24 @@ class VPPStats():
|
|||||||
if self.last_epoch != self.epoch:
|
if self.last_epoch != self.epoch:
|
||||||
self.refresh()
|
self.refresh()
|
||||||
|
|
||||||
return [k for k, v in self.directory.items()
|
return [
|
||||||
if any(re.match(pattern, k) for pattern in regex)]
|
k
|
||||||
|
for k, v in self.directory.items()
|
||||||
|
if any(re.match(pattern, k) for pattern in regex)
|
||||||
|
]
|
||||||
|
|
||||||
def dump(self, counters, blocking=True):
|
def dump(self, counters, blocking=True):
|
||||||
'''Given a list of counters return a dictionary of results'''
|
"""Given a list of counters return a dictionary of results"""
|
||||||
if not self.connected:
|
if not self.connected:
|
||||||
self.connect()
|
self.connect()
|
||||||
result = {}
|
result = {}
|
||||||
for cnt in counters:
|
for cnt in counters:
|
||||||
result[cnt] = self.__getitem__(cnt,blocking)
|
result[cnt] = self.__getitem__(cnt, blocking)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
class StatsLock():
|
|
||||||
'''Stat segment optimistic locking'''
|
class StatsLock:
|
||||||
|
"""Stat segment optimistic locking"""
|
||||||
|
|
||||||
def __init__(self, stats):
|
def __init__(self, stats):
|
||||||
self.stats = stats
|
self.stats = stats
|
||||||
@ -273,7 +290,7 @@ class StatsLock():
|
|||||||
self.release()
|
self.release()
|
||||||
|
|
||||||
def acquire(self, blocking=True, timeout=-1):
|
def acquire(self, blocking=True, timeout=-1):
|
||||||
'''Acquire the lock. Await in progress to go false. Record epoch.'''
|
"""Acquire the lock. Await in progress to go false. Record epoch."""
|
||||||
self.epoch = self.stats.epoch
|
self.epoch = self.stats.epoch
|
||||||
if timeout > 0:
|
if timeout > 0:
|
||||||
start = time.monotonic()
|
start = time.monotonic()
|
||||||
@ -286,46 +303,49 @@ class StatsLock():
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def release(self):
|
def release(self):
|
||||||
'''Check if data read while locked is valid'''
|
"""Check if data read while locked is valid"""
|
||||||
if self.stats.in_progress or self.stats.epoch != self.epoch:
|
if self.stats.in_progress or self.stats.epoch != self.epoch:
|
||||||
raise IOError('Optimistic lock failed, retry')
|
raise IOError("Optimistic lock failed, retry")
|
||||||
|
|
||||||
def locked(self):
|
def locked(self):
|
||||||
'''Not used'''
|
"""Not used"""
|
||||||
|
|
||||||
|
|
||||||
class StatsCombinedList(list):
|
class StatsCombinedList(list):
|
||||||
'''Column slicing for Combined counters list'''
|
"""Column slicing for Combined counters list"""
|
||||||
|
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
'''Supports partial numpy style 2d support. Slice by column [:,1]'''
|
"""Supports partial numpy style 2d support. Slice by column [:,1]"""
|
||||||
if isinstance(item, int):
|
if isinstance(item, int):
|
||||||
return list.__getitem__(self, item)
|
return list.__getitem__(self, item)
|
||||||
return CombinedList([row[item[1]] for row in self])
|
return CombinedList([row[item[1]] for row in self])
|
||||||
|
|
||||||
|
|
||||||
class CombinedList(list):
|
class CombinedList(list):
|
||||||
'''Combined Counters 2-dimensional by thread by index of packets/octets'''
|
"""Combined Counters 2-dimensional by thread by index of packets/octets"""
|
||||||
|
|
||||||
def packets(self):
|
def packets(self):
|
||||||
'''Return column (2nd dimension). Packets for all threads'''
|
"""Return column (2nd dimension). Packets for all threads"""
|
||||||
return [pair[0] for pair in self]
|
return [pair[0] for pair in self]
|
||||||
|
|
||||||
def octets(self):
|
def octets(self):
|
||||||
'''Return column (2nd dimension). Octets for all threads'''
|
"""Return column (2nd dimension). Octets for all threads"""
|
||||||
return [pair[1] for pair in self]
|
return [pair[1] for pair in self]
|
||||||
|
|
||||||
def sum_packets(self):
|
def sum_packets(self):
|
||||||
'''Return column (2nd dimension). Sum of all packets for all threads'''
|
"""Return column (2nd dimension). Sum of all packets for all threads"""
|
||||||
return sum(self.packets())
|
return sum(self.packets())
|
||||||
|
|
||||||
def sum_octets(self):
|
def sum_octets(self):
|
||||||
'''Return column (2nd dimension). Sum of all octets for all threads'''
|
"""Return column (2nd dimension). Sum of all octets for all threads"""
|
||||||
return sum(self.octets())
|
return sum(self.octets())
|
||||||
|
|
||||||
|
|
||||||
class StatsTuple(tuple):
|
class StatsTuple(tuple):
|
||||||
'''A Combined vector tuple (packets, octets)'''
|
"""A Combined vector tuple (packets, octets)"""
|
||||||
|
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
self.dictionary = {'packets': data[0], 'bytes': data[1]}
|
self.dictionary = {"packets": data[0], "bytes": data[1]}
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
@ -334,28 +354,32 @@ class StatsTuple(tuple):
|
|||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
if isinstance(item, int):
|
if isinstance(item, int):
|
||||||
return tuple.__getitem__(self, item)
|
return tuple.__getitem__(self, item)
|
||||||
if item == 'packets':
|
if item == "packets":
|
||||||
return tuple.__getitem__(self, 0)
|
return tuple.__getitem__(self, 0)
|
||||||
return tuple.__getitem__(self, 1)
|
return tuple.__getitem__(self, 1)
|
||||||
|
|
||||||
|
|
||||||
class StatsSimpleList(list):
|
class StatsSimpleList(list):
|
||||||
'''Simple Counters 2-dimensional by thread by index of packets'''
|
"""Simple Counters 2-dimensional by thread by index of packets"""
|
||||||
|
|
||||||
def __getitem__(self, item):
|
def __getitem__(self, item):
|
||||||
'''Supports partial numpy style 2d support. Slice by column [:,1]'''
|
"""Supports partial numpy style 2d support. Slice by column [:,1]"""
|
||||||
if isinstance(item, int):
|
if isinstance(item, int):
|
||||||
return list.__getitem__(self, item)
|
return list.__getitem__(self, item)
|
||||||
return SimpleList([row[item[1]] for row in self])
|
return SimpleList([row[item[1]] for row in self])
|
||||||
|
|
||||||
|
|
||||||
class SimpleList(list):
|
class SimpleList(list):
|
||||||
'''Simple counter'''
|
"""Simple counter"""
|
||||||
|
|
||||||
def sum(self):
|
def sum(self):
|
||||||
'''Sum the vector'''
|
"""Sum the vector"""
|
||||||
return sum(self)
|
return sum(self)
|
||||||
|
|
||||||
class StatsEntry():
|
|
||||||
'''An individual stats entry'''
|
class StatsEntry:
|
||||||
|
"""An individual stats entry"""
|
||||||
|
|
||||||
# pylint: disable=unused-argument,no-self-use
|
# pylint: disable=unused-argument,no-self-use
|
||||||
|
|
||||||
def __init__(self, stattype, statvalue):
|
def __init__(self, stattype, statvalue):
|
||||||
@ -376,47 +400,48 @@ class StatsEntry():
|
|||||||
self.function = self.illegal
|
self.function = self.illegal
|
||||||
|
|
||||||
def illegal(self, stats):
|
def illegal(self, stats):
|
||||||
'''Invalid or unknown counter type'''
|
"""Invalid or unknown counter type"""
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def scalar(self, stats):
|
def scalar(self, stats):
|
||||||
'''Scalar counter'''
|
"""Scalar counter"""
|
||||||
return self.value
|
return self.value
|
||||||
|
|
||||||
def simple(self, stats):
|
def simple(self, stats):
|
||||||
'''Simple counter'''
|
"""Simple counter"""
|
||||||
counter = StatsSimpleList()
|
counter = StatsSimpleList()
|
||||||
for threads in StatsVector(stats, self.value, 'P'):
|
for threads in StatsVector(stats, self.value, "P"):
|
||||||
clist = [v[0] for v in StatsVector(stats, threads[0], 'Q')]
|
clist = [v[0] for v in StatsVector(stats, threads[0], "Q")]
|
||||||
counter.append(clist)
|
counter.append(clist)
|
||||||
return counter
|
return counter
|
||||||
|
|
||||||
def combined(self, stats):
|
def combined(self, stats):
|
||||||
'''Combined counter'''
|
"""Combined counter"""
|
||||||
counter = StatsCombinedList()
|
counter = StatsCombinedList()
|
||||||
for threads in StatsVector(stats, self.value, 'P'):
|
for threads in StatsVector(stats, self.value, "P"):
|
||||||
clist = [StatsTuple(cnt) for cnt in StatsVector(stats, threads[0], 'QQ')]
|
clist = [StatsTuple(cnt) for cnt in StatsVector(stats, threads[0], "QQ")]
|
||||||
counter.append(clist)
|
counter.append(clist)
|
||||||
return counter
|
return counter
|
||||||
|
|
||||||
def name(self, stats):
|
def name(self, stats):
|
||||||
'''Name counter'''
|
"""Name counter"""
|
||||||
counter = []
|
counter = []
|
||||||
for name in StatsVector(stats, self.value, 'P'):
|
for name in StatsVector(stats, self.value, "P"):
|
||||||
if name[0]:
|
if name[0]:
|
||||||
counter.append(get_string(stats, name[0]))
|
counter.append(get_string(stats, name[0]))
|
||||||
return counter
|
return counter
|
||||||
|
|
||||||
SYMLINK_FMT1 = Struct('II')
|
SYMLINK_FMT1 = Struct("II")
|
||||||
SYMLINK_FMT2 = Struct('Q')
|
SYMLINK_FMT2 = Struct("Q")
|
||||||
|
|
||||||
def symlink(self, stats):
|
def symlink(self, stats):
|
||||||
'''Symlink counter'''
|
"""Symlink counter"""
|
||||||
b = self.SYMLINK_FMT2.pack(self.value)
|
b = self.SYMLINK_FMT2.pack(self.value)
|
||||||
index1, index2 = self.SYMLINK_FMT1.unpack(b)
|
index1, index2 = self.SYMLINK_FMT1.unpack(b)
|
||||||
name = stats.directory_by_idx[index1]
|
name = stats.directory_by_idx[index1]
|
||||||
return stats[name][:,index2]
|
return stats[name][:, index2]
|
||||||
|
|
||||||
def get_counter(self, stats):
|
def get_counter(self, stats):
|
||||||
'''Return a list of counters'''
|
"""Return a list of counters"""
|
||||||
if stats:
|
if stats:
|
||||||
return self.function(stats)
|
return self.function(stats)
|
||||||
|
Reference in New Issue
Block a user