Compare commits

...

7 Commits

Author SHA1 Message Date
e18aed96c8 Added a docker-compose 2026-03-17 19:39:28 +01:00
e66998b826 Got 3750-X monitoring working 2026-03-17 19:38:27 +01:00
c474f9c9c2 Added error handling for idrac 2026-03-17 19:09:11 +01:00
e06eea68cd Added customizable poolig interval 2026-03-07 22:02:37 +01:00
c9d07e7cef Added timeout exception for timeoud handling 2026-03-07 22:00:53 +01:00
10d14a06db Added a custom exception for timeout handling 2026-03-07 22:00:38 +01:00
78d240a1fc Added timeout crash avoidance 2026-03-06 22:59:56 +01:00
13 changed files with 548 additions and 220 deletions

View File

@@ -1,61 +1,52 @@
import os, asyncio
from models.ciscoModel import snmpPyCiscoData
from snmp.walker import walk_column_v3
from models.ciscoModel import C3750XciscoData
from models.snmpTimeOut import SNMPTimeoutError
from snmp.walker import walk_column_v3, walk_lobotomy_column_v3
from typing import Annotated, Final
# SNMP
from pysnmp.hlapi.v3arch.asyncio import *
# SNMP ENV-------------------------------------------
ROUND_PREC: Final[int] = int(os.getenv("ROUND_PREC", 2))
SNMPUSER: Final[str] = os.getenv("SNMPUSER", None)
SNMPPRIVKEY: Final[str] = os.getenv("SNMPPRIVKEY", None)
SNMPAUTHKEY: Final[str] = os.getenv("SNMPAUTHKEY", None)
# Right now I'll only use SHA
# SNMPAUTHPROTO: Final[str] = os.getenv("SNMPAUTHPROTO", "SHA")
# SNMPPRIVPROTO: Final[str] = os.getenv("SNMPPRIVPROTO", "SHA")
SNMPORT: Final[int] = int(os.getenv("SNMPORT", 161))
# Check if SNMP ENV are empty
if not SNMPUSER or not SNMPPRIVKEY or not SNMPAUTHKEY:
raise Exception("No SNMP user or/and PrivAuth passed")
# SNMP
USMUSRDATA = UsmUserData(
userName=SNMPUSER,
authKey=SNMPAUTHKEY,
privKey=SNMPPRIVKEY,
authProtocol=usmHMACSHAAuthProtocol,
privProtocol=usmAesCfb128Protocol,
)
# Cisco
async def ciscoPoolRemote(remoteIP: str, queueToInsrt: asyncio.Queue):
async def lobGetRemote(
remoteIP: str,
queueToInsrt: asyncio.Queue,
SNMPUSER: str,
SNMPAUTHKEY: str,
SNMPPRIVKEY: str,
ROUND_PREC: int = 2,
SNMPORT: int = 161
):
print("starting work on ", remoteIP)
# SNMPUSRDATA
USMUSRDATA = UsmUserData(
userName=SNMPUSER,
authKey=SNMPAUTHKEY,
privKey=SNMPPRIVKEY,
authProtocol=usmHMACSHAAuthProtocol,
privProtocol=usmAesCfb128Protocol,
)
snmpEngine = SnmpEngine()
iterator = get_cmd(
snmpEngine,
USMUSRDATA,
await UdpTransportTarget.create((remoteIP, SNMPORT)),
ContextData(),
# Get Hostname
ObjectType(ObjectIdentity(".1.3.6.1.2.1.1.5.0")),
#
ObjectType(ObjectIdentity(".1.3.6.1.2.1.1.5.0")), # 0
)
print(iterator)
errorIndication, errorStatus, errorIndex, varBinds = await iterator
if errorIndication:
print(errorIndication)
print(f"\n\n{errorIndication}\n\n")
if "No SNMP response received before timeout" in str(errorIndication):
raise SNMPTimeoutError(f"Host {remoteIP} timed out while walking")
raise RuntimeError(errorIndication)
elif errorStatus:
print(
"{} at {}".format(
@@ -67,18 +58,56 @@ async def ciscoPoolRemote(remoteIP: str, queueToInsrt: asyncio.Queue):
for varBind in varBinds:
print(" = ".join([x.prettyPrint() for x in varBind]))
try:
# System data
systemData = await walk_lobotomy_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.9.9.13.1.3", SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY)
# Uptime in seconds
uptimeSeconds = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.6.3.10.2.1.3", SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY)
# Last 5 second CPU usage
last5SecCPUsage = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.9.2.1.56", SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY)
# Last minute CPU usage
last1MinCPUsage = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.9.2.1.58", SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY)
# Last 5 minutes CPU usage
last5MinCPUsage = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.9.2.1.58", SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY)
except SNMPTimeoutError as e:
print(f"{e}\nContinuing regardless...")
return 1
except RuntimeError as e:
print(f"SNMP error on {remoteIP}: {e}")
return 1
snmpEngine.close_dispatcher()
returObj = snmpPyCiscoData()
returObj = C3750XciscoData(
hostname=varBinds[0][-1],
systemStatus=systemData[0].split(" ")[2], #[2],
systemTemp=systemData[1], #[2][-1],
last5SecUsage=last5SecCPUsage[0],
last1MinUsage=last1MinCPUsage[0],
last5MinUsage=last5MinCPUsage[0],
uptimeS=int(uptimeSeconds[0])
returObj(
hostname="X"
)
returnDict = {
"source": "CISCO",
"device": "3750X",
"value": returObj,
"type": "snmpPyCiscoData"
"type": "C3750XciscoData"
}
# return returnObj
await queueToInsrt.put(returnDict)

View File

@@ -69,3 +69,99 @@ async def fluxIDRACWriter(
return 0
# return {"STATUS": "succesfully inserted to InfluxDB"}
async def fluxDataWriter(
inpDict: dict
) -> int:
"""
Insert temperature data into InfluxDB
:inputQueue: Asyncio Queue that has what is needed to be sent
"""
# inputQueue have multiple such Dicts
# {
# "source": "IDRAC",
# "value": returnObj,
# "type": "snmpPyIDRACData"
# }
if write_fluxdb_api is None:
return 2
match inpDict["source"]:
case "CISCO":
match inpDict["device"]:
case "3750X":
# Prep InfluxDB data
inflxdb_3750X_Data_To_Send = (
influxdb_client.Point(INFXLUXDB_MEASUEREMENT)
.tag("SOURCE", inpDict["source"])
.tag("DEVICE", inpDict["device"])
.tag("TYPE", inpDict["type"])
.tag("HOSTNAME", inpDict["value"].hostname)
.field("systemStatus", inpDict["value"].systemStatus)
.field("systemTemp", inpDict["value"].systemTemp)
.field("last5SecUsage", inpDict["value"].last5SecUsage)
.field("last1MinUsage", inpDict["value"].last1MinUsage)
.field("last5MinUsage", inpDict["value"].last5MinUsage)
.field("uptimeS", inpDict["value"].uptimeS)
)
try:
write_fluxdb_api.write(bucket=INFLUXBCKT, org=INFLUXORG, record=inflxdb_3750X_Data_To_Send)
except Exception as e:
print(e)
return 1
case "NEXUS":
...
return 0
case _:
print(f"{inpDict['device']} is not supported.\nOnly '3750X' and 'Nexus' are.")
return 1
case "IDRAC":
# Prep InfluxDB data
inflxdb_IDRAC_Data_To_Send = (
influxdb_client.Point(INFXLUXDB_MEASUEREMENT)
.tag("SOURCE", inpDict["source"])
.tag("TYPE", inpDict["type"])
.tag("HOSTNAME", inpDict["value"].hostname)
.field("PowerDrawPSU1", inpDict["value"].powerDrawPSU1)
.field("PowerDrawPSU2", inpDict["value"].powerDrawPSU2)
.field("TotalBoardPower", inpDict["value"].powerDrawBoard)
.field("VoltagePSU1", inpDict["value"].voltagePSU1)
.field("VoltagePSU2", inpDict["value"].voltagePSU2)
.field("InletTemperature", inpDict["value"].inletTemp)
.field("ExhaustTemperature", inpDict["value"].exhaustTemp)
.field("TemperatureCPU1", inpDict["value"].cpu1Temp)
.field("TemperatureCPU2", inpDict["value"].cpu2Temp)
.field("UptimeInSeconds", inpDict["value"].uptimeS)
.field("UptimeInHours", inpDict["value"].uptimeH)
.field("UptimeInDays", inpDict["value"].uptimeD)
)
try:
write_fluxdb_api.write(bucket=INFLUXBCKT, org=INFLUXORG, record=inflxdb_IDRAC_Data_To_Send)
except Exception as e:
print(e)
return 1
case "FANS":
await eng.execute(
# changeMeLater
t1.insert(), [{"name": "some name 1"}, {"name": "some name 2"}]
)
case _:
print(f"No such source of data as {inpDict['source']}")
return 1
return 0
# asyncio.sleep(5)

View File

@@ -3,7 +3,8 @@ from sqlalchemy.ext.asyncio import create_async_engine
from typing import Annotated, Final
from dataclasses import asdict
from models.idracModel import snmpPyIDRACData
from models.sqlTable import idracMeasurement
from models.ciscoModel import C3750XciscoData
from models.sqlTable import idracMeasurement, C3750XMeasurement
# SQL ENV-------------------------------------------
USESQL: Final[int] = int(os.getenv("USESQL", 0))
@@ -27,7 +28,7 @@ else:
engine = None
async def sqlIDRACDataWriter(
async def sqlDataWriter(
inpDict: dict
) -> int:
@@ -44,10 +45,36 @@ async def sqlIDRACDataWriter(
match inpDict["source"]:
case "CISCO":
await eng.execute(
# changeMeLater
t1.insert(), [{"name": "some name 1"}, {"name": "some name 2"}]
)
match inpDict["device"]:
case "3750X":
payload = inpDict["value"] # snmpPyIDRACData
row = asdict(payload)
await eng.execute(
C3750XMeasurement.insert(),
[row]
)
return 0
case "NEXUS":
payload = inpDict["value"] # snmpPyIDRACData
row = asdict(payload)
await eng.execute(
NexusMeasurement.insert(),
[row]
)
return 0
case _:
print(f"{inpDict['device']} is not supported.\nOnly '3750X' and 'Nexus' are.")
return 1
# await eng.execute(
# # changeMeLater
# t1.insert(), [{"name": "some name 1"}, {"name": "some name 2"}]
# )
case "IDRAC":
payload = inpDict["value"] # snmpPyIDRACData
row = asdict(payload)

View File

@@ -1,7 +1,7 @@
import asyncio, os
from typing import Annotated, Final
from db.Influx import fluxIDRACWriter
from db.MariaDB import sqlIDRACDataWriter
from db.Influx import fluxDataWriter
from db.MariaDB import sqlDataWriter
USEINFLUX: Final[int] = int(os.getenv("USEINFLUX", 1))
USESQL: Final[int] = int(os.getenv("USESQL", 0))
@@ -15,7 +15,7 @@ async def ALLdbIDRACWriter(inputQueue: asyncio.Queue) -> None:
try:
if USESQL:
sqlResult = await sqlIDRACDataWriter(qu)
sqlResult = await sqlDataWriter(qu)
match sqlResult:
case 1:
print("Wrong source")
@@ -26,7 +26,7 @@ async def ALLdbIDRACWriter(inputQueue: asyncio.Queue) -> None:
case _:
print("Inserted in SQL")
if USEINFLUX:
fluxResult = await fluxIDRACWriter(qu)
fluxResult = await fluxDataWriter(qu)
match fluxResult:
case 1:
print("could not insert")

31
cont/docker-compose.yaml Normal file
View File

@@ -0,0 +1,31 @@
---
services:
snmpcollector:
container_name: snmpython
user: 1600:1600
image: shupotea/yuruc3/snmpython:latest
environment:
- USEINFLUX=1
- INFLXDBTOKEN=67676767
- INFLUXBCKT=pyusr-DEV
- INFLUXORG=staging
- INFLXDBURL=http://influxdb:8086
- INFXLUXDB_MEASUEREMENT=dev-pycollector
- USESQL=1
- DBADDR=mariadb
- DBUSR=root
- DBPWD=SomeDBPassword
- DBNAME=SomeDBName
- SNMPUSER=SNMPusr
- SNMPPRIVKEY=SomePassword
- SNMPAUTHKEY=SomePassword
- IDRAC78_HOST_LIST=192.168.20.7;192.168.20.10;192.168.20.8;192.168.20.12
- IDRAC9_HOST_LIST=192.168.20.4
- CISCO_3750_HOST_LIST=192.168.20.16
- CISCO_NEXUS_HOST_LIST=192.168.0.1;192.168.0.1;192.168.0.1;192.168.0.1
restart: unless-stopped

View File

@@ -6,39 +6,25 @@ from typing import Annotated, Final
# SNMP
from pysnmp.hlapi.v3arch.asyncio import *
# SNMP ENV-------------------------------------------
ROUND_PREC: Final[int] = int(os.getenv("ROUND_PREC", 2))
SNMPUSER: Final[str] = os.getenv("SNMPUSER", None)
SNMPPRIVKEY: Final[str] = os.getenv("SNMPPRIVKEY", None)
SNMPAUTHKEY: Final[str] = os.getenv("SNMPAUTHKEY", None)
# Right now I'll only use SHA
# SNMPAUTHPROTO: Final[str] = os.getenv("SNMPAUTHPROTO", "SHA")
# SNMPPRIVPROTO: Final[str] = os.getenv("SNMPPRIVPROTO", "SHA")
SNMPORT: Final[int] = int(os.getenv("SNMPORT", 161))
# Check if SNMP ENV are empty
if not SNMPUSER or not SNMPPRIVKEY or not SNMPAUTHKEY:
raise Exception("No SNMP user or/and PrivAuth passed")
# SNMP
USMUSRDATA = UsmUserData(
userName=SNMPUSER,
authKey=SNMPAUTHKEY,
privKey=SNMPPRIVKEY,
authProtocol=usmHMACSHAAuthProtocol,
privProtocol=usmAesCfb128Protocol,
)
# IDRAC78 get data for snmpPyIDRACData class
async def idrac7_8PoolRemote_v3(remoteIP: str, queueToInsrt: asyncio.Queue):
async def idrac7_8PoolRemote_v3(
remoteIP: str,
queueToInsrt: asyncio.Queue,
SNMPUSER: str,
SNMPAUTHKEY: str,
SNMPPRIVKEY: str,
ROUND_PREC: int = 2,
SNMPORT: int = 161
):
print("starting work on ", remoteIP)
# SNMPUSRDATA
USMUSRDATA = UsmUserData(
userName=SNMPUSER,
authKey=SNMPAUTHKEY,
privKey=SNMPPRIVKEY,
authProtocol=usmHMACSHAAuthProtocol,
privProtocol=usmAesCfb128Protocol,
)
snmpEngine = SnmpEngine()
# try CPU2 as CPU1 is always there
@@ -59,6 +45,10 @@ async def idrac7_8PoolRemote_v3(remoteIP: str, queueToInsrt: asyncio.Queue):
errorIndication, errorStatus, errorIndex, mainVarBinds = await mainIterator
if errorIndication:
if errorIndication == "No SNMP response received before timeout":
print(f"Host {remoteIP} timed out.\nContinuing...")
snmpEngine.close_dispatcher()
return 1
print(errorIndication)
elif errorStatus:
print(
@@ -71,28 +61,33 @@ async def idrac7_8PoolRemote_v3(remoteIP: str, queueToInsrt: asyncio.Queue):
for oid, val in mainVarBinds:
print(f"{oid.prettyPrint()} = {val.prettyPrint()}")
try:
# Get PSU1 current, [PSU2 current], total board power draw in watts
currentsCurrentResults = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.600.30.1.6", SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY)
# PSU1 OID name, [PSU2 OID name], system board power draw
currentsNamesResults = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.600.30.1.8", SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY)
# Get PSU1 current, [PSU2 current], total board power draw in watts
currentsCurrentResults = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.600.30.1.6")
# PSU1 OID name, [PSU2 OID name], system board power draw
currentsNamesResults = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.600.30.1.8")
# Inlet OID name .1, [Exhaust OID name], CPU1 temp OID name, [CPU2 tempOID name]
sensorNamesResults = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.700.20.1.8", SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY)
# Inlet temp, [Exhaust temp], CPU1 temp, [CPU2 temp]
sensorValuesResults = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.700.20.1.6", SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY)
# Inlet OID name .1, [Exhaust OID name], CPU1 temp OID name, [CPU2 tempOID name]
sensorNamesResults = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.700.20.1.8")
# Inlet temp, [Exhaust temp], CPU1 temp, [CPU2 temp]
sensorValuesResults = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.700.20.1.6")
# .1.3.6.1.4.1.674.10892.5.4.600.20.1.6.1
voltResult = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.600.20.1.6.1", SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY)
# .1.3.6.1.4.1.674.10892.5.4.600.20.1.6.1
voltResult = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.600.20.1.6.1")
hasExhaust = any("exhaust" in str(thing).lower() for thing in sensorNamesResults.values())
hasCPU2 = any("cpu2" in str(thing).lower() for thing in sensorNamesResults.values())
hasPSU2 = any("ps2" in str(thing).lower() for thing in currentsNamesResults.values())
hasExhaust = any("exhaust" in str(thing).lower() for thing in sensorNamesResults.values())
hasCPU2 = any("cpu2" in str(thing).lower() for thing in sensorNamesResults.values())
hasPSU2 = any("ps2" in str(thing).lower() for thing in currentsNamesResults.values())
except SNMPTimeoutError as e:
print(f"{e}\nContinuing regardless...")
return 1
except RuntimeError as e:
print(f"SNMP error on {remoteIP}: {e}")
return 1
snmpEngine.close_dispatcher()
print(voltResult)
# Exhaust CPU1 and CPU2 temp
exhaustTemp = None

View File

@@ -1,45 +1,36 @@
import os, asyncio
from models.idracModel import snmpPyIDRACData
from models.snmpTimeOut import SNMPTimeoutError
from snmp.walker import walk_column_v3
from typing import Annotated, Final
# SNMP
from pysnmp.hlapi.v3arch.asyncio import *
# SNMP ENV-------------------------------------------
ROUND_PREC: Final[int] = int(os.getenv("ROUND_PREC", 2))
SNMPUSER: Final[str] = os.getenv("SNMPUSER", None)
SNMPPRIVKEY: Final[str] = os.getenv("SNMPPRIVKEY", None)
SNMPAUTHKEY: Final[str] = os.getenv("SNMPAUTHKEY", None)
# Right now I'll only use SHA
# SNMPAUTHPROTO: Final[str] = os.getenv("SNMPAUTHPROTO", "SHA")
# SNMPPRIVPROTO: Final[str] = os.getenv("SNMPPRIVPROTO", "SHA")
SNMPORT: Final[int] = int(os.getenv("SNMPORT", 161))
# Check if SNMP ENV are empty
if not SNMPUSER or not SNMPPRIVKEY or not SNMPAUTHKEY:
raise Exception("No SNMP user or/and PrivAuth passed")
# SNMP
USMUSRDATA = UsmUserData(
userName=SNMPUSER,
authKey=SNMPAUTHKEY,
privKey=SNMPPRIVKEY,
authProtocol=usmHMACSHAAuthProtocol,
privProtocol=usmAesCfb128Protocol,
)
# IDRAC get data for snmpPyIDRACData class
async def idrac9PoolRemote_v3(remoteIP: str, queueToInsrt: asyncio.Queue):
async def idrac9PoolRemote_v3(
remoteIP: str,
queueToInsrt: asyncio.Queue,
SNMPUSER: str,
SNMPAUTHKEY: str,
SNMPPRIVKEY: str,
ROUND_PREC: int = 2,
SNMPORT: int = 161
):
print("starting work on ", remoteIP)
# SNMP
USMUSRDATA = UsmUserData(
userName=SNMPUSER,
authKey=SNMPAUTHKEY,
privKey=SNMPPRIVKEY,
authProtocol=usmHMACSHAAuthProtocol,
privProtocol=usmAesCfb128Protocol,
)
snmpEngine = SnmpEngine()
iterator = get_cmd(
@@ -56,6 +47,10 @@ async def idrac9PoolRemote_v3(remoteIP: str, queueToInsrt: asyncio.Queue):
errorIndication, errorStatus, errorIndex, mainVarBinds = await iterator
if errorIndication:
if errorIndication == "No SNMP response received before timeout":
print(f"Host {remoteIP} timed out.\nContinuing...")
snmpEngine.close_dispatcher()
return 1
print(errorIndication)
elif errorStatus:
print(
@@ -69,22 +64,30 @@ async def idrac9PoolRemote_v3(remoteIP: str, queueToInsrt: asyncio.Queue):
print(f"{oid.prettyPrint()} = {val.prettyPrint()}")
try:
# Get PSU1 current, [PSU2 current], total board power draw in watts
currentsCurrentResults = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.600.30.1.6")
# PSU1 OID name, [PSU2 OID name], system board power draw
currentsNamesResults = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.600.30.1.8")
# Get PSU1 current, [PSU2 current], total board power draw in watts
currentsCurrentResults = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.600.30.1.6", SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY)
# PSU1 OID name, [PSU2 OID name], system board power draw
currentsNamesResults = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.600.30.1.8", SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY)
# CPU1 OID name .1, [CPU2 OID name], Inlet temp OID name, [Exhaust temp OID name]
sensorNamesResults = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.700.20.1.8")
# CPU1 temp, [CPU2 temp], Inlet temp, [Exhaust temp]
sensorValuesResults = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.700.20.1.6")
# CPU1 OID name .1, [CPU2 OID name], Inlet temp OID name, [Exhaust temp OID name]
sensorNamesResults = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.700.20.1.8", SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY)
# CPU1 temp, [CPU2 temp], Inlet temp, [Exhaust temp]
sensorValuesResults = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.700.20.1.6", SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY)
# .1.3.6.1.4.1.674.10892.5.4.600.20.1.6.1
voltResult = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.600.20.1.6.1")
# .1.3.6.1.4.1.674.10892.5.4.600.20.1.6.1
voltResult = await walk_column_v3(snmpEngine, remoteIP, ".1.3.6.1.4.1.674.10892.5.4.600.20.1.6.1", SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY)
except SNMPTimeoutError as e:
print(f"{e}\nContinuing regardless...")
return 1
except RuntimeError as e:
print(f"SNMP error on {remoteIP}: {e}")
return 1
snmpEngine.close_dispatcher()
hasExhaust = any("exhaust" in str(thing).lower() for thing in sensorNamesResults.values())
hasCPU2 = any("cpu2" in str(thing).lower() for thing in sensorNamesResults.values())
hasPSU2 = any("ps2" in str(thing).lower() for thing in currentsNamesResults.values())

View File

@@ -8,38 +8,81 @@ from db.collectiveWriter import ALLdbIDRACWriter
# idrac SNMP
from idrac import idrac78, idrac9
# Cisco hosts
# from cisco import lob, nyater
from cisco import lob, nyater
# SNMP ENV-------------------------------------------
ROUND_PREC: Final[int] = int(os.getenv("ROUND_PREC", 2))
SNMPUSER: Final[str] = os.getenv("SNMPUSER", None)
SNMPPRIVKEY: Final[str] = os.getenv("SNMPPRIVKEY", None)
SNMPAUTHKEY: Final[str] = os.getenv("SNMPAUTHKEY", None)
# Right now I'll only use SHA
# SNMPAUTHPROTO: Final[str] = os.getenv("SNMPAUTHPROTO", "SHA")
# SNMPPRIVPROTO: Final[str] = os.getenv("SNMPPRIVPROTO", "SHA")
SNMPORT: Final[int] = int(os.getenv("SNMPORT", 161))
# Check if SNMP ENV are empty
if not SNMPUSER or not SNMPPRIVKEY or not SNMPAUTHKEY:
raise Exception("No SNMP user or/and PrivAuth passed")
# Program ENV---------------------------------------
try:
IDRAC78_HOST_LIST: Final[list] = os.getenv("IDRAC78_HOST_LIST", None).split(";")
IDRAC9_HOST_LIST: Final[list] = os.getenv("IDRAC9_HOST_LIST", None).split(";")
CISCO_HOST_LIST: Final[list] = os.getenv("CISCO_HOST_LIST", None).split(";")
IDRAC78_HOST_LIST: Final[list] = os.getenv("IDRAC78_HOST_LIST", []).split(";")
IDRAC9_HOST_LIST: Final[list] = os.getenv("IDRAC9_HOST_LIST", []).split(";")
except:
raise Exception("No IDRAC hosts variable")
try:
CISCO_3750_HOST_LIST: Final[list] = os.getenv("CISCO_3750_HOST_LIST", []).split(";")
except:
print("No 3750-X devices passed.\nContinuing with what is available.\n")
CISCO_3750_HOST_LIST = []
try:
CISCO_NEXUS_HOST_LIST: Final[list] = os.getenv("CISCO_NEXUS_HOST_LIST", []).split(";")
except:
print("No Nexus devices passed.\nContinuing with what is available.\n")
CISCO_NEXUS_HOST_LIST = []
GET_INTERVAL: Final[int] = int(os.getenv("GET_INTERVAL", 60))
# Flightchecks-------------------------------------------
# if HOST_LIST empty, raise Exception No hosts passed
if not IDRAC78_HOST_LIST and not CISCO_HOST_LIST and not IDRAC9_HOST_LIST:
raise Exception("No hosts passed\nExiting...")
# if not IDRAC78_HOST_LIST and not IDRAC9_HOST_LIST:
# raise Exception("No IDRAC hosts passed\nExiting...")
# for host in HOST_LIST check if valid IP and create a list with strings
for idrac78Host in IDRAC78_HOST_LIST:
try:
for idrac78Host in IDRAC78_HOST_LIST:
try:
ip = str(ipaddress.IPv4Address(idrac78Host))
except ValueError:
raise Exception(f" IP {ip} for IDRAC7/8 devices is invalid.\nExiting...")
except:
IDRAC78_HOST_LIST = []
for cisco3750Host in CISCO_3750_HOST_LIST:
try:
ip = str(ipaddress.IPv4Address(idrac78Host))
except ValueError:
raise Exception(f" IP {ip} for IDRAC7/8 devices is invalid.\nExiting...")
for ciscoHost in CISCO_HOST_LIST:
try:
ip = str(ipaddress.IPv4Address(ciscoHost))
ip = str(ipaddress.IPv4Address(cisco3750Host))
except ValueError:
raise Exception(f" IP {ip} for Cisco devices is invalid.\nExiting...")
for idrac9Host in IDRAC9_HOST_LIST:
for ciscoNexusHost in CISCO_NEXUS_HOST_LIST:
try:
ip = str(ipaddress.IPv4Address(idrac9Host))
ip = str(ipaddress.IPv4Address(ciscoNexusHost))
except ValueError:
raise Exception(f" IP {ip} for IDRAC9 devices is invalid.\nExiting...")
raise Exception(f" IP {ip} for Cisco devices is invalid.\nExiting...")
try:
for idrac9Host in IDRAC9_HOST_LIST:
try:
ip = str(ipaddress.IPv4Address(idrac9Host))
except ValueError:
raise Exception(f" IP {ip} for IDRAC9 devices is invalid.\nExiting...")
except:
IDRAC9_HOST_LIST = []
# Done under "Program ENV" on line ~18
@@ -48,48 +91,43 @@ for idrac9Host in IDRAC9_HOST_LIST:
async def main():
# Queues for storing states that a database needs to insert
# idracQueue = asyncio.Queue()
# ciscoQueue = asyncio.Queue()
# fanQueue = asyncio.Queue()
mainQueue = asyncio.Queue(maxsize=225)
asyncio.create_task(ALLdbIDRACWriter(mainQueue))
print("Starting tasks")
while True:
# IDRAC part
async with asyncio.TaskGroup() as tg:
for Idrac78IP in IDRAC78_HOST_LIST:
tg.create_task(idrac78.idrac7_8PoolRemote_v3(Idrac78IP, mainQueue))
tg.create_task(idrac78.idrac7_8PoolRemote_v3(
Idrac78IP, mainQueue,
SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY, ROUND_PREC, SNMPORT))
for Idrac9IP in IDRAC9_HOST_LIST:
tg.create_task(idrac9.idrac9PoolRemote_v3(Idrac9IP, mainQueue))
tg.create_task(idrac9.idrac9PoolRemote_v3(
Idrac9IP, mainQueue,
SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY, ROUND_PREC, SNMPORT))
# FANS
# tg.create_task(idracPoolRemoteFAN_v3(IdracIP, mainQueue))
# tg.create_task(idracPoolRemoteFAN_v3(IdracIP, mainQueue))
# CISCO devices
# for CiscoIP in CISCO_HOST_LIST:
# tg.create_task(ciscoPoolRemote(CiscoIP, mainQueue))
for cisco3750Xdev in CISCO_3750_HOST_LIST:
tg.create_task(lob.lobGetRemote(
cisco3750Xdev, mainQueue,
SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY, ROUND_PREC, SNMPORT))
await asyncio.sleep(20)
# for ciscoNexusDev in CISCO_NEXUS_HOST_LIST:
# tg.create_task(nyater(
# ciscoNexusDev, mainQueue,
# SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY, ROUND_PREC, SNMPORT))
await asyncio.sleep(GET_INTERVAL)
# yes = asyncio.run(idracPoolRemote_v3("192.168.20.7"))
# fan = asyncio.run(idracPoolRemoteFAN_v3("192.168.20.7"))
# print("fanThingy")
# # print(fan)
# for thing in fan:
# print(fan[thing]["name"], fan[thing]["rpm"])
# for thing in fan:
# print(thing)
# print("for loop")
# print(yes)
# print("End of code")
if __name__ == "__main__":
# qu = asyncio.Queue()
# asyncio.run(idracPoolRemote_v3("192.168.20.7", qu))
@@ -99,28 +137,3 @@ if __name__ == "__main__":
# loop = asyncio.get_event_loop()
# task = loop.create_task(main())
# poolRemote(HOST_LIST[0])
# while True:
# tasks = [poolRemote(ip) for ip in HOST_LIST]
# results = await asyncio.gather(*tasks)
# print(results)
# await asyncio.sleep(20)
# Create connections for MySQL and InfluxDB
# functions for inserting data into two DBs
# DNS lookup if the user passed a hostname
# if not given a specific IP for DNS server, fallback to 1.1.1.1
# maybe a class?
# store last value and check if it wasn't sent already to the database

View File

@@ -2,6 +2,34 @@ from dataclasses import dataclass
from typing import Optional, Annotated, Dict
@dataclass
class C3750XciscoData():
"""Dataclass for snmp data"""
hostname: str
systemStatus: str
systemTemp: int
last5SecUsage: int
last1MinUsage: int
last5MinUsage: int
uptimeS: int
# uptimeH: float
def __str__(self):
return (
f"{self.hostname}\n"
f"System status: {self.systemStatus} \n"
f"System temp: {self.systemTemp} C\n"
f"Last 5 second CPU usage: {self.last5SecUsage} %\n"
f"Last 1 minute CPU usage: {self.last1MinUsage} %\n"
f"Last 5 minutes CPU usage: {self.last5MinUsage} %\n"
f"Uptime: {self.uptimeS} Seconds\n"
)
@dataclass
class snmpPyCiscoData():
"""Dataclass for snmp data"""

View File

@@ -0,0 +1,2 @@
class SNMPTimeoutError(Exception):
pass

View File

@@ -26,3 +26,37 @@ idracMeasurement = Table(
Column("uptimeH", Numeric(8, 3)),
Column("uptimeD", Numeric(8, 3)),
)
C3750XMeasurement = Table(
"C3750XMeasurement",
metadata,
Column("id", Integer, primary_key=True, autoincrement=True),
Column("time_stamp", TIMESTAMP, server_default=text("CURRENT_TIMESTAMP"), nullable=False),
Column("hostname", String(64), nullable=False),
Column("systemStatus", String(64)),
Column("systemTemp", Numeric(7, 2)),
Column("last5SecUsage", Numeric(7, 2)),
Column("last1MinUsage", Numeric(7, 2)),
Column("last5MinUsage", Numeric(7, 2)),
Column("uptimeS", BigInteger),
)
NexusMeasurement = Table(
"NexusMeasurement",
metadata,
Column("id", Integer, primary_key=True, autoincrement=True),
Column("time_stamp", TIMESTAMP, server_default=text("CURRENT_TIMESTAMP"), nullable=False),
Column("hostname", String(64), nullable=False),
Column("systemStatus", String(64)),
Column("systemTemp", Numeric(7, 2)),
Column("last5SecUsage", Numeric(7, 2)),
Column("last1MinUsage", Numeric(7, 2)),
Column("last5MinUsage", Numeric(7, 2)),
Column("uptimeS", BigInteger),
)

View File

@@ -2,6 +2,7 @@ import asyncio, os
from typing import Annotated, Final
# SNMP
from pysnmp.hlapi.v3arch.asyncio import *
from models.snmpTimeOut import SNMPTimeoutError
# SNMP ENV-------------------------------------------
ROUND_PREC: Final[int] = int(os.getenv("ROUND_PREC", 2))
@@ -19,14 +20,6 @@ if not SNMPUSER or not SNMPPRIVKEY or not SNMPAUTHKEY:
raise Exception("No SNMP user or/and PrivAuth passed")
# SNMP
USMUSRDATA = UsmUserData(
userName=SNMPUSER,
authKey=SNMPAUTHKEY,
privKey=SNMPPRIVKEY,
authProtocol=usmHMACSHAAuthProtocol,
privProtocol=usmAesCfb128Protocol,
)
@@ -42,7 +35,23 @@ USMUSRDATA = UsmUserData(
# The value is always a string so it needs to be converted to int if needed
async def walk_column_v3(snmpEngine, remoteIP: str, base_oid: str) -> dict:
async def walk_column_v3(
snmpEngine,
remoteIP: str,
base_oid: str,
SNMPUSER: str,
SNMPAUTHKEY: str,
SNMPPRIVKEY: str
) -> dict:
# SNMP
USMUSRDATA = UsmUserData(
userName=SNMPUSER,
authKey=SNMPAUTHKEY,
privKey=SNMPPRIVKEY,
authProtocol=usmHMACSHAAuthProtocol,
privProtocol=usmAesCfb128Protocol,
)
rows = {}
async for errInd, errStat, errIdx, varBinds in walk_cmd(
snmpEngine,
@@ -53,6 +62,9 @@ async def walk_column_v3(snmpEngine, remoteIP: str, base_oid: str) -> dict:
lexicographicMode=False,
):
if errInd:
print(f"\n\n{errInd}\n\n")
if "No SNMP response received before timeout" in str(errInd):
raise SNMPTimeoutError(f"Host {remoteIP} timed out while walking {base_oid}")
raise RuntimeError(errInd)
if errStat:
raise RuntimeError(errStat.prettyPrint())
@@ -63,3 +75,43 @@ async def walk_column_v3(snmpEngine, remoteIP: str, base_oid: str) -> dict:
rows[idx] = val.prettyPrint()
return rows
async def walk_lobotomy_column_v3(
snmpEngine,
remoteIP: str,
base_oid: str,
SNMPUSER: str,
SNMPAUTHKEY: str,
SNMPPRIVKEY: str
) -> list:
# SNMP
USMUSRDATA = UsmUserData(
userName=SNMPUSER,
authKey=SNMPAUTHKEY,
privKey=SNMPPRIVKEY,
authProtocol=usmHMACSHAAuthProtocol,
privProtocol=usmAesCfb128Protocol,
)
elements = []
async for errInd, errStat, errIdx, varBinds in walk_cmd(
snmpEngine,
USMUSRDATA,
await UdpTransportTarget.create((remoteIP, SNMPORT)),
ContextData(),
ObjectType(ObjectIdentity(base_oid)),
lexicographicMode=False,
):
if errInd:
print(f"\n\n{errInd}\n\n")
if "No SNMP response received before timeout" in str(errInd):
raise SNMPTimeoutError(f"Host {remoteIP} timed out while walking {base_oid}")
raise RuntimeError(errInd)
if errStat:
raise RuntimeError(errStat.prettyPrint())
for oid, val in varBinds:
elements.append(val.prettyPrint())
return elements

View File

@@ -59,6 +59,24 @@ CREATE TABLE IDRACmeasurement (
INDEX idx_host_time (hostname, time_stamp)
);
-- New universal table type
CREATE TABLE C3750XMeasurement (
id MEDIUMINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
time_stamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
hostname VARCHAR(64) NOT NULL,
systemStatus VARCHAR(64) NOT NULL,
systemTemp DECIMAL(7,2) NOT NULL,
last5SecUsage DECIMAL(7,2) NOT NULL,
last1MinUsage DECIMAL(7,2) NOT NULL,
last5MinUsage DECIMAL(7,2) NOT NULL,
uptimeS BIGINT,
INDEX idx_time (time_stamp),
INDEX idx_host_time (hostname, time_stamp)
);
CREATE TABLE fansHOSTNAMEHERE (
id MEDIUMINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
time_stamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,