Compare commits

..

4 Commits

Author SHA1 Message Date
5ea68b548e changed USE* envs to 0 and 1 2026-02-28 17:48:13 +01:00
cdf3b983bc Moved the project to asyncio 2026-02-28 17:48:01 +01:00
45ab7d2761 Notes on Redfish API standard 2026-02-28 17:47:43 +01:00
1cc6c7d3ee Added SQL structure for 2 tables 2026-02-28 17:47:27 +01:00
8 changed files with 465 additions and 293 deletions

7
REDFISH.md Normal file
View File

@@ -0,0 +1,7 @@
# RedFish
I have found that there is another method for getting data from IDRAC which is Redfish API.
Here is the documentation for IDRAC
https://www.dell.com/support/manuals/en-us/idrac8-lifecycle-controller-v2.70.70.70/idrac8_redfishapiguide_2.70.70.70/

View File

@@ -11,29 +11,31 @@ from dataclasses import dataclass
AlchemyBase = declarative_base() AlchemyBase = declarative_base()
# DATABASE "CLASSESS"-------------------------------------------- # DATABASE "CLASSESS"--------------------------------------------
def sensorsqldata(table_name: Annotated[str, "Name of the table"]): # class idracSQLTable(AlchemyBase):
# def __init__(self, inputData: snmpPyIDRACData):
# __table_args__ = {'extend_existing': True}
class SensorSQLDataClass(AlchemyBase): # __tablename__ = table_name
__table_args__ = {'extend_existing': True}
__tablename__ = table_name # id = Column(MEDIUMINT(unsigned=True), primary_key=True, autoincrement=True)
# time_stamp = Column(
# TIMESTAMP,
# server_default=text("CURRENT_TIMESTAMP"),
# server_onupdate=text("CURRENT_TIMESTAMP"),
# nullable=False,
# )
id = Column(MEDIUMINT(unsigned=True), primary_key=True, autoincrement=True) # inputData.hostname = Column(TEXT)
time_stamp = Column( # inputData.powerDrawPSU1 = Column(Float)
TIMESTAMP, # inputData.powerDrawPSU2 = Column(Float, nullable=True)
server_default=text("CURRENT_TIMESTAMP"), # inputData.voltagePSU1 = Column(Float)
server_onupdate=text("CURRENT_TIMESTAMP"), # inputData.voltagePSU2 = Column(Float, nullable=True)
nullable=False, # inputData.inletTemp = Column(Float)
) # inputData.exhaustTemp = Column(Float)
TEMP = Column(TINYINT) # inputData.cpu1Temp = Column(Float)
TEMP = Column(TEXT) # inputData.cpu2Temp = Column(Float, nullable=True)
TEMP = Column(Float) # inputData.uptimeH = Column(Float)
TEMP = Column(Float) # inputData.uptimeD = Column(Float, nullable=True)
TEMP = Column(Float, nullable=True)
TEMP = Column(Float, nullable=True)
TEMP = Column(Float, nullable=True)
return SensorSQLDataClass
# Custom-------------------------------------------- # Custom--------------------------------------------
@@ -115,5 +117,37 @@ class snmpPyIDRACData():
) )
@dataclass @dataclass
class idracFanStatus: class snmpPyCiscoData():
fans: Dict[str, int] # name/index -> rpm """Dataclass for snmp data"""
hostname: str
powerDrawPSU1: int
voltagePSU1: int
inletTemp: float
exhaustTemp: float
cpu1Temp: float
uptimeH: float
# optional fields
uptimeD: float | None = None
cpu2Temp: float | None = None
powerDrawPSU2: int | None = None
voltagePSU2: int | None = None
def __str__(self):
return (
f"{self.hostname}\n"
f"PSU1 {self.powerDrawPSU1} Watts\n"
f"PSU2 {self.powerDrawPSU2} Watts\n"
f"PSU1 {self.voltagePSU1} Volts\n"
f"PSU2 {self.voltagePSU2} Volts\n"
f"Inlet {self.inletTemp} C\n"
f"Exhaust {self.exhaustTemp} C\n"
f"CPU1 {self.cpu1Temp} C\n"
f"CPU2 {self.cpu2Temp} C\n"
f"Uptime {self.uptimeH} Hours\n"
f"Uptime {self.uptimeD} Days"
)
# @dataclass
# class idracFanStatus:
# fans: Dict[str, int] | None = Dict[None, None] # name/index -> rpm

View File

@@ -8,21 +8,22 @@ services:
build: build:
dockerfile: ./Dockerfile dockerfile: ./Dockerfile
environment: environment:
- USEINFLUX=True - USEINFLUX=1
- INFLXDBTOKEN=67676767 - INFLXDBTOKEN=67676767
- INFLUXBCKT=pyusr-DEV - INFLUXBCKT=pyusr-DEV
- INFLUXORG=staging - INFLUXORG=staging
- INFLXDBURL=http://influxdb:8086 - INFLXDBURL=http://influxdb:8086
- INFXLUXDB_MEASUEREMENT=dev-pycollector - INFXLUXDB_MEASUEREMENT=dev-pycollector
- USESQL=1
- DBADDR=mariadb - DBADDR=mariadb
- DBUSR=root - DBUSR=root
- DBPWD=67676767 - DBPWD=67676767
- DBNAME=pyCollector - DBNAME=pyCollector
- SNMPUSER=SNMPUSR - SNMPUSER=SNMPusrRO
- SNMPPRIVKEY=123 - SNMPPRIVKEY=67676767
- SNMPAUTHKEY=123 - SNMPAUTHKEY=67676767
- IDRAC_HOST_LIST=192.168.0.1;192.168.0.1;192.168.0.1;192.168.0.1 - IDRAC_HOST_LIST=192.168.0.1;192.168.0.1;192.168.0.1;192.168.0.1
- CISCO_HOST_LIST=192.168.0.1;192.168.0.1;192.168.0.1;192.168.0.1 - CISCO_HOST_LIST=192.168.0.1;192.168.0.1;192.168.0.1;192.168.0.1

View File

@@ -1,17 +1,21 @@
import influxdb_client, sqlalchemy, random, os import influxdb_client, sqlalchemy, random, os, asyncio
# from sqlmodel import Field, Session, SQLModel, create_engine, select # from sqlmodel import Field, Session, SQLModel, create_engine, select
from sqlalchemy import create_engine, exc # , Column, Integer, String, Numeric # from sqlalchemy import create_engine, exc # , Column, Integer, String, Numeric
# from sqlalchemy.ext.declarative import declarative_base # from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker # from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.asyncio import create_async_engine
from classes import * from classes import *
from typing import Annotated, Final from typing import Annotated, Final
from influxdb_client import InfluxDBClient, Point, WritePrecision from influxdb_client import InfluxDBClient, Point, WritePrecision
from influxdb_client.client.write_api import SYNCHRONOUS, ASYNCHRONOUS, WriteOptions from influxdb_client.client.write_api import SYNCHRONOUS, ASYNCHRONOUS, WriteOptions
# import pymysql
# SNMP
from pysnmp.hlapi.v3arch.asyncio import *
# FluxQL ENV---------------------------------------- # FluxQL ENV----------------------------------------
USEINFLUX: Final[bool] = os.getenv("USEINFLUX", True) USEINFLUX: Final[int] = int(os.getenv("USEINFLUX", 1))
if USEINFLUX: if USEINFLUX:
INFLXDBTOKEN: Final[str] = os.getenv("INFLXDBTOKEN", "123" ) INFLXDBTOKEN: Final[str] = os.getenv("INFLXDBTOKEN", "123" )
INFLUXBCKT: Final[str] = os.getenv("INFLUXBCKT", "SNMPyth") INFLUXBCKT: Final[str] = os.getenv("INFLUXBCKT", "SNMPyth")
@@ -20,90 +24,126 @@ if USEINFLUX:
INFXLUXDB_MEASUEREMENT: Final[str] = os.getenv("INFXLUXDB_MEASUEREMENT", "SNMPyth-containrr") INFXLUXDB_MEASUEREMENT: Final[str] = os.getenv("INFXLUXDB_MEASUEREMENT", "SNMPyth-containrr")
INFLX_SEPARATE_POINTS: Final[float] = float(os.getenv("INFLX_SEPARATE_POINTS", 0.1)) INFLX_SEPARATE_POINTS: Final[float] = float(os.getenv("INFLX_SEPARATE_POINTS", 0.1))
# SQL ENV------------------------------------------- # SQL ENV-------------------------------------------
USESQL: Final[bool] = os.getenv("USESQL", False) USESQL: Final[int] = int(os.getenv("USESQL", 0))
if USESQL: if USESQL:
DBENGINE: Final[str] = os.getenv("DBENGINE", "mysql+pymysql") DBENGINE: Final[str] = os.getenv("DBENGINE", "mysql+asyncmy")
DBADDR: Final[str] = os.getenv("DBADDR", "127.0.0.1") DBADDR: Final[str] = os.getenv("DBADDR", "127.0.0.1")
DBUSR: Final[str] = os.getenv("DBUSR", "root") DBUSR: Final[str] = os.getenv("DBUSR", "root")
DBPWD: Final[str] = os.getenv("DBPWD", "6767") DBPWD: Final[str] = os.getenv("DBPWD", "6767")
DBNAME: Final[str] = os.getenv("DBNAME", "TEMP_SENSR") DBNAME: Final[str] = os.getenv("DBNAME", "TEMP_SENSR")
# SNMP ENV-------------------------------------------
ROUND_PREC: Final[int] = int(os.getenv("ROUND_PREC", 6))
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))
# Flightchecks------------------------------------------- # Flightchecks-------------------------------------------
# Check if some neccesary ENVs are passed # Check if some neccesary ENVs are passed
if not USEINFLUX and not USESQL: if not USEINFLUX and not USESQL:
raise Exception("No database selected to store the data") raise Exception("No database selected to store the data")
# Check if SNMP ENV are empty
if not SNMPUSER or not SNMPPRIVKEY or not SNMPAUTHKEY:
raise Exception("No SNMP user or/and PrivAuth passed")
# DBprepare------------------------------------------- # Prepare-------------------------------------------
# INFLUX # INFLUX
if USEINFLUX: if USEINFLUX:
fluxdb_client = influxdb_client.InfluxDBClient(url=INFLXDBURL, token=INFLXDBTOKEN, org=INFLUXORG) fluxdb_client = influxdb_client.InfluxDBClient(url=INFLXDBURL, token=INFLXDBTOKEN, org=INFLUXORG)
write_fluxdb_api = fluxdb_client.write_api(write_options=SYNCHRONOUS) write_fluxdb_api = fluxdb_client.write_api(write_options=ASYNCHRONOUS)
query_fluxdb_api = fluxdb_client.query_api() query_fluxdb_api = fluxdb_client.query_api()
else:
fluxdb_client = write_fluxdb_api = query_fluxdb_api = None
# SQL # SQL
if USESQL: if USESQL:
engine = create_engine( engine = create_async_engine(
f"{DBENGINE}://{DBUSR}:{DBPWD}@{DBADDR}/{DBNAME}", f"{DBENGINE}://{DBUSR}:{DBPWD}@{DBADDR}/{DBNAME}",
pool_pre_ping=True, # Check connection liveness before using and if needed, recconect # pool_pre_ping=True, # Check connection liveness before using and if needed, recconect
pool_recycle=3600 # recycle connections older than N (3600 in this case) seconds # pool_recycle=3600, # recycle connections older than N (3600 in this case) seconds
echo=True,
) )
Session = sessionmaker(bind=engine) else:
engine = None
# SNMP
USMUSRDATA = UsmUserData(
userName=SNMPUSER,
authKey=SNMPAUTHKEY,
privKey=SNMPPRIVKEY,
authProtocol=usmHMACSHAAuthProtocol,
privProtocol=usmAesCfb128Protocol,
)
def tempsnsrIntoSQLDB( # DB functions-------------------------------------------
tableInp: Annotated[int, "Name of the table"],
insertData: Annotated[str, "Data to insert"] async def sqlDataWriter(
inpDict: dict
) -> int: ) -> int:
f"""
Insert {DBNAME} data into MariaDB
:tableInp: Name of the table
:return: 0 if succesfull, 1 if rolled back on error, 2 if SQL is not enabled 3 if no such table
"""
if not USESQL: # inputQueue have multiple such Dicts
return 2 # {
# "source": "IDRAC",
# Check if table exists # "value": returnObj,
if not sqlalchemy.inspect(engine).has_table(tableInp): # "type": "snmpPyIDRACData"
# }
if engine is None:
return 3 return 3
with Session() as session:
try: try:
async with engine.begin() as eng:
match inpDict["source"]:
sqlData = sensorsqldata(tableInp) case "CISCO":
# print("2") await eng.execute(
# changeMeLater
t1.insert(), [{"name": "some name 1"}, {"name": "some name 2"}]
)
case "IDRAC":
await eng.execute(
# changeMeLater
t1.insert(), [{"name": "some name 1"}, {"name": "some name 2"}]
)
case "FANS":
await eng.execute(
# changeMeLater
t1.insert(), [{"name": "some name 1"}, {"name": "some name 2"}]
)
if inpayload: case _:
# print("3") print(f"No such source of data as {inpDict['source']}")
session.add(sqlData(
data = insertData,
))
# print("4")
session.commit() #Attempt to commit all the records
# print("good")
return 0
except Exception as e:
print(f"Error {e} when sending to mariadb")
session.rollback() #Rollback the changes on error
return 1 return 1
except Exception as e:
print(e)
return 2
def tempsnsrIntoFluxQLDB( return 0
inIdracPayload: Annotated[snmpPyIDRACData, "Payload"] | None = None,
inCiscoPayload: Annotated[int, "yes"] | None = None # asyncio.sleep(5)
async def fluxWriter(
inpDict: dict
) -> int: ) -> int:
""" """
Insert temperature data into InfluxDB Insert temperature data into InfluxDB
:inpayload: Payload :inputQueue: Asyncio Queue that has what is needed to be sent
:return: 0 if succesfull, 1 if general error, 2 if Influx is not enabled
""" """
if not USEINFLUX: # inputQueue have multiple such Dicts
# {
# "source": "IDRAC",
# "value": returnObj,
# "type": "snmpPyIDRACData"
# }
if write_fluxdb_api is None:
return 2 return 2
# Prep InfluxDB data # Prep InfluxDB data
inflxdb_Data_To_Send = ( inflxdb_Data_To_Send = (
influxdb_client.Point(f"{INFXLUXDB_MEASUEREMENT}") influxdb_client.Point(f"{INFXLUXDB_MEASUEREMENT}")
@@ -117,13 +157,234 @@ def tempsnsrIntoFluxQLDB(
.field("TEMP", inpayload.alttd) .field("TEMP", inpayload.alttd)
) )
# print(write_fluxdb_api.write(bucket=INFLUXBCKT, org=INFLUXORG, record=inflxdb_Data_To_Send)) try:
# if write_fluxdb_api.write(bucket=INFLUXBCKT, org=INFLUXORG, record=inflxdb_Data_To_Send) == None: write_fluxdb_api.write(bucket=INFLUXBCKT, org=INFLUXORG, record=inflxdb_Data_To_Send)
except Exception as e:
if write_fluxdb_api.write(bucket=INFLUXBCKT, org=INFLUXORG, record=inflxdb_Data_To_Send): print(e)
# return {"STATUS": "succesfully inserted to InfluxDB"}
print("0")
return 0
else:
print("1")
return 1 return 1
return 0
# return {"STATUS": "succesfully inserted to InfluxDB"}
async def ALLdbWriter(inputQueue: asyncio.Queue) -> None:
while True:
qu = await inputQueue.get()
try:
if USESQL:
sqlResult = await sqlDataWriter(qu)
match sqlResult:
case 1:
print("Wrong source")
case 2:
print("Error inserting to database")
case 3:
print("No engine defined")
case _:
print("nice")
if USEINFLUX:
fluxResult = await fluxWriter(qu)
match fluxResult:
case 1:
print("could not insert")
case 2:
print("Error with initializing Inxlux variables")
case _:
print("nice")
except Exception as e:
print(e)
finally:
inputQueue.task_done()
# SNMP functions-------------------------------------------
# Helper functions
# def wattageCalc(amperageInp: float, voltageInp: float) -> float:
# return amperageInp * voltageInp
# Cisco
async def ciscoPoolRemote(remoteIP: str, queueToInsrt: asyncio.Queue):
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")),
#
)
print(iterator)
errorIndication, errorStatus, errorIndex, varBinds = await iterator
if errorIndication:
print(errorIndication)
elif errorStatus:
print(
"{} at {}".format(
errorStatus.prettyPrint(),
errorIndex and varBinds[int(errorIndex) - 1][0] or "?",
)
)
else:
for varBind in varBinds:
print(" = ".join([x.prettyPrint() for x in varBind]))
snmpEngine.close_dispatcher()
returObj = snmpPyCiscoData()
returObj(
hostname="X"
)
returnDict = {
"source": "CISCO",
"value": returObj,
"type": "snmpPyCiscoData"
}
# return returnObj
queueToInsrt.put(returnDict)
# IDRAC get data for snmpPyIDRACData class
async def idracPoolRemote_v3(remoteIP: str, queueToInsrt: asyncio.Queue):
snmpEngine = SnmpEngine()
iterator = get_cmd(
snmpEngine,
# SNMPv1 = mpModel=0 (SNMPv2c would be mpModel=1)
# CommunityData("public", mpModel=0),
USMUSRDATA,
await UdpTransportTarget.create((remoteIP, SNMPORT)),
ContextData(),
# Hostname (sysName.0)
ObjectType(ObjectIdentity(".1.3.6.1.2.1.1.5.0")), #0
# PSU1 powerDraw and PSU2 powerDraw (Amps)
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.4.600.30.1.6.1.1")), #1
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.4.600.30.1.6.1.2")), #2
# (Volts)
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.4.600.20.1.6.1.31")), #3
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.4.600.20.1.6.1.32")), #4
# Get Inlet, Exhaust, CPU1, CPU2
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.4.700.20.1.6.1.1")), #5
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.4.700.20.1.6.1.2")), #6
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.4.700.20.1.6.1.3")), #7
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.4.700.20.1.6.1.4")), #8
# Uptime in seconds
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.2.5.0")), #9
)
errorIndication, errorStatus, errorIndex, varBinds = await iterator
if errorIndication:
print(errorIndication)
elif errorStatus:
print(
"{} at {}".format(
errorStatus.prettyPrint(),
errorIndex and varBinds[int(errorIndex) - 1][0] or "?",
)
)
else:
for oid, val in varBinds:
print(f"{oid.prettyPrint()} = {val.prettyPrint()}")
# for element in varBinds:
# print(element)
snmpEngine.close_dispatcher()
# print(varBinds[1][-1])
# print(type(varBinds[1][-1]))
returnObj = snmpPyIDRACData(
hostname=varBinds[0][-1],
# Hostname
powerDrawPSU1=round((int(varBinds[1][-1]) / 10) * (int(varBinds[3][-1]) / 1000), ROUND_PREC),
powerDrawPSU2=round((int(varBinds[2][-1]) / 10) * (int(varBinds[4][-1]) / 1000), ROUND_PREC),
# PSU1 and PSU2 power draw in Watts
voltagePSU1=round((int(varBinds[3][-1]) / 1000), ROUND_PREC),
voltagePSU2=round((int(varBinds[4][-1]) / 1000), ROUND_PREC),
# PSU1 and PSU2 voltages
inletTemp=int(varBinds[5][-1] / 10),
exhaustTemp=int(varBinds[6][-1] / 10),
# Inlet and Exhaust temp
cpu1Temp=int(varBinds[7][-1] / 10),
cpu2Temp=int(varBinds[8][-1] / 10),
# CPU1 and CPU2 temp
uptimeH=round(((int(varBinds[9][-1]) / 60) / 60), ROUND_PREC),
# seconds->minutes->hours
uptimeD=round((((int(varBinds[9][-1]) / 60) / 60) / 24), ROUND_PREC)
# seconds->minutes->hours->days
)
returnDict = {
"source": "IDRAC",
"value": returnObj,
"type": "snmpPyIDRACData"
}
# return returnObj
queueToInsrt.put(returnDict)
# IDRAC get FAN data
async def walk_column_v3(snmpEngine, remoteIP: str, base_oid: str) -> dict:
rows = {}
async for errInd, errStat, errIdx, varBinds in walk_cmd(
snmpEngine,
# CommunityData("public", mpModel=0),
USMUSRDATA,
await UdpTransportTarget.create((remoteIP, SNMPORT)),
ContextData(),
ObjectType(ObjectIdentity(base_oid)),
lexicographicMode=False,
):
if errInd:
raise RuntimeError(errInd)
if errStat:
raise RuntimeError(errStat.prettyPrint())
for oid, val in varBinds:
# index is typically the last sub-identifier
idx = int(oid.prettyPrint().split(".")[-1])
rows[idx] = val.prettyPrint()
return rows
async def idracPoolRemoteFAN_v3(remoteIP: str, queueToInsrt: asyncio.Queue) -> dict:
snmpEngine = SnmpEngine()
rpm_oid = "1.3.6.1.4.1.674.10892.5.4.700.12.1.6"
name_oid = "1.3.6.1.4.1.674.10892.5.4.700.12.1.19"
rpms, names = await asyncio.gather(
walk_column_v3(snmpEngine, remoteIP, rpm_oid),
walk_column_v3(snmpEngine, remoteIP, name_oid),
)
snmpEngine.close_dispatcher()
# merge by index
out = {}
for idx, rpm in rpms.items():
out[idx] = {"rpm": rpm, "name": names.get(idx).split(".")[2]}
returnDict = {
"source": "FANS",
"value": out,
"type": "Dict"
}

View File

@@ -9,28 +9,15 @@ from funct import *
from classes import * from classes import *
# Program ENV--------------------------------------- # Program ENV---------------------------------------
ROUND_PREC: Final[int] = os.getenv("ROUND_PREC", 6)
IDRAC_HOST_LIST: Final[list] = os.getenv("IDRAC_HOST_LIST").split(";") IDRAC_HOST_LIST: Final[list] = os.getenv("IDRAC_HOST_LIST").split(";")
CISCO_HOST_LIST: Final[list] = os.getenv("CISCO_HOST_LIST").split(";") CISCO_HOST_LIST: Final[list] = os.getenv("CISCO_HOST_LIST").split(";")
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] = os.getenv("SNMPORT", 161)
# Flightchecks------------------------------------------- # Flightchecks-------------------------------------------
# Check if SNMP ENV are empty
if not SNMPUSER or not SNMPPRIVKEY or not SNMPAUTHKEY:
raise Exception("No SNMP user or/and PrivAuth passed")
# if HOST_LIST empty, raise Exception No hosts passed # if HOST_LIST empty, raise Exception No hosts passed
if not IDRAC_HOST_LIST and not CISCO_HOST_LIST: if not IDRAC_HOST_LIST and not CISCO_HOST_LIST:
raise Exception("No hosts passed\nExiting...") raise Exception("No hosts passed\nExiting...")
# for host in HOST_LIST check if valid IP and create a list with strings # for host in HOST_LIST check if valid IP and create a list with strings
for idracHost in IDRAC_HOST_LIST: for idracHost in IDRAC_HOST_LIST:
try: try:
@@ -48,185 +35,53 @@ for ciscoHost in CISCO_HOST_LIST:
# Code------------------------------------------- # Code-------------------------------------------
# Helper functions async def main():
def wattageCalc(amperageInp: float, voltageInp: float) -> float:
return amperageInp * voltageInp # Queues for storing states that a database needs to insert
# idracQueue = asyncio.Queue()
# ciscoQueue = asyncio.Queue()
# fanQueue = asyncio.Queue()
mainQueue(maxsize=225)
while True:
tasks = []
# IDRAC part
async with asyncio.TaskGroup() as tg:
for IdracIP in IDRAC_HOST_LIST:
tasks.append(tg.create_task(idracPoolRemote_v3(IdracIP, mainQueue)))
# tasks.append(tg.create_task(idracPoolRemoteFAN_v3(IdracIP, mainQueue)))
async def ciscoPoolRemote(remoteIP: str): # for CiscoIP in CISCO_HOST_LIST:
snmpEngine = SnmpEngine() # tasks.append(tg.create_task(ciscoPoolRemote(CiscoIP, mainQueue)))
iterator = get_cmd( sleep(20)
snmpEngine,
UsmUserData(
userName=SNMPUSER,
authKey=SNMPPRIVKEY,
privKey=SNMPAUTHKEY,
authProtocol=usmHMACSHAAuthProtocol,
privProtocol=usmHMACSHAAuthProtocol,
),
await UdpTransportTarget.create((remoteIP, SNMPORT)),
ContextData(),
# Get Hostname
ObjectType(ObjectIdentity(".1.3.6.1.2.1.1.5.0")),
#
)
print(iterator)
errorIndication, errorStatus, errorIndex, varBinds = await iterator
if errorIndication:
print(errorIndication)
elif errorStatus:
print(
"{} at {}".format(
errorStatus.prettyPrint(),
errorIndex and varBinds[int(errorIndex) - 1][0] or "?",
)
)
else:
for varBind in varBinds:
print(" = ".join([x.prettyPrint() for x in varBind]))
snmpEngine.close_dispatcher()
async def idracPoolRemote(remoteIP: str):
snmpEngine = SnmpEngine()
iterator = get_cmd(
snmpEngine,
UsmUserData(
userName=SNMPUSER,
authKey=SNMPPRIVKEY,
privKey=SNMPAUTHKEY,
authProtocol=usmHMACSHAAuthProtocol,
privProtocol=usmHMACSHAAuthProtocol,
),
await UdpTransportTarget.create((remoteIP, SNMPORT)),
ContextData(),
# Get Hostname
ObjectType(ObjectIdentity(".1.3.6.1.2.1.1.5.0")),
#
)
print(iterator)
errorIndication, errorStatus, errorIndex, varBinds = await iterator
if errorIndication:
print(errorIndication)
elif errorStatus:
print(
"{} at {}".format(
errorStatus.prettyPrint(),
errorIndex and varBinds[int(errorIndex) - 1][0] or "?",
)
)
else:
for varBind in varBinds:
print(" = ".join([x.prettyPrint() for x in varBind]))
snmpEngine.close_dispatcher()
async def idracPoolRemote_v1(remoteIP: str):
snmpEngine = SnmpEngine()
iterator = get_cmd( # yes = asyncio.run(idracPoolRemote_v3("192.168.20.7"))
snmpEngine, # fan = asyncio.run(idracPoolRemoteFAN_v3("192.168.20.7"))
# SNMPv1 = mpModel=0 (SNMPv2c would be mpModel=1)
CommunityData("public", mpModel=0),
await UdpTransportTarget.create((remoteIP, SNMPORT)),
ContextData(),
# Hostname (sysName.0)
ObjectType(ObjectIdentity(".1.3.6.1.2.1.1.5.0")), #0
# PSU1 powerDraw and PSU2 powerDraw (Amps) # print("fanThingy")
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.4.600.30.1.6.1.1")), #1 # # print(fan)
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.4.600.30.1.6.1.2")), #2 # for thing in fan:
# (Volts) # print(fan[thing]["name"], fan[thing]["rpm"])
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.4.600.20.1.6.1.31")), #3 # for thing in fan:
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.4.600.20.1.6.1.32")), #4 # print(thing)
# Get Inlet, Exhaust, CPU1, CPU2 # print("for loop")
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.4.700.20.1.6.1.1")), #5 # print(yes)
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.4.700.20.1.6.1.2")), #6
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.4.700.20.1.6.1.3")), #7
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.4.700.20.1.6.1.4")), #8
# Uptime in seconds # print("End of code")
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.2.5.0")), #9
)
errorIndication, errorStatus, errorIndex, varBinds = await iterator if __name__ == "__main__":
if errorIndication:
print(errorIndication)
elif errorStatus:
print(
"{} at {}".format(
errorStatus.prettyPrint(),
errorIndex and varBinds[int(errorIndex) - 1][0] or "?",
)
)
else:
for oid, val in varBinds:
print(f"{oid.prettyPrint()} = {val.prettyPrint()}")
# for element in varBinds:
# print(element)
snmpEngine.close_dispatcher()
# print(varBinds[1][-1])
# print(type(varBinds[1][-1]))
returnObj = snmpPyIDRACData(
hostname=varBinds[0][-1],
# Hostname
powerDrawPSU1=round((int(varBinds[1][-1]) / 10) * (int(varBinds[3][-1]) / 1000), ROUND_PREC),
powerDrawPSU2=round((int(varBinds[2][-1]) / 10) * (int(varBinds[4][-1]) / 1000), ROUND_PREC),
# PSU1 and PSU2 power draw in Watts
voltagePSU1=round((int(varBinds[3][-1]) / 1000), ROUND_PREC),
voltagePSU2=round((int(varBinds[4][-1]) / 1000), ROUND_PREC),
# PSU1 and PSU2 voltages
inletTemp=int(varBinds[5][-1] / 10),
exhaustTemp=int(varBinds[6][-1] / 10),
# Inlet and Exhaust temp
cpu1Temp=int(varBinds[7][-1] / 10),
cpu2Temp=int(varBinds[8][-1] / 10),
# CPU1 and CPU2 temp
uptimeH=round(((int(varBinds[9][-1]) / 60) / 60), ROUND_PREC),
# seconds->minutes->hours
uptimeD=round((((int(varBinds[9][-1]) / 60) / 60) / 24), ROUND_PREC)
# seconds->minutes->hours->days
)
return returnObj loop = asyncio.get_event_loop()
task = loop.create_task(main())
yes = asyncio.run(idracPoolRemote_v1("192.168.20.7"))
print("for loop")
print(yes)
x = idracFanStatus(6)
# print(yes.hostname)
# print(yes.powerDrawPSU1)
# print(yes.powerDrawPSU2)
# print(yes.voltagePSU1)
# print(yes.voltagePSU2)
# print(yes.inletTemp)
# print(yes.exhaustTemp)
# print(yes.uptimeH)
# print(yes.uptimeD)
# poolRemote(HOST_LIST[0]) # poolRemote(HOST_LIST[0])
@@ -239,12 +94,6 @@ x = idracFanStatus(6)
# await asyncio.sleep(20) # await asyncio.sleep(20)
# Create connections for MySQL and InfluxDB # Create connections for MySQL and InfluxDB
# functions for inserting data into two DBs # functions for inserting data into two DBs

View File

@@ -1,11 +1,13 @@
# mysql-connector-python==9.2.0 # mysql-connector-python==9.2.0
PyMySQL==1.1.1 PyMySQL==1.1.1
sqlmodel==0.0.24 sqlmodel==0.0.24
sqlalchemy[asyncio]
pydantic==2.10.6 pydantic==2.10.6
pydantic_core==2.27.2 pydantic_core==2.27.2
annotated-types==0.7.0 annotated-types==0.7.0
typing==3.7.4.3 typing==3.7.4.3
pysnmp==7.1.22 pysnmp==7.1.22
cryptography==46.0.5
# requests==2.32.3 # requests==2.32.3
influxdb-client==1.49.0 influxdb-client==1.49.0
# influxdb3-python==0.18.0 # influxdb3-python==0.18.0

0
cont/sqlFunct.py Normal file
View File

View File

@@ -25,19 +25,37 @@ SET NAMES utf8mb4;
-- New universal table type -- New universal table type
CREATE TABLE newUniversalSensorTable ( CREATE TABLE idracHOSTNAMECHANGEME (
id MEDIUMINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, id MEDIUMINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
time_stamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, time_stamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
hostname TEXT(30), hostname TEXT(30),
powerDrawPSU1 TINYINT(100), powerDrawPSU1 FLOAT,
powerDrawPSU2 TINYINT(100) NULL, powerDrawPSU2 FLOAT NULL,
voltagePSU1 TINYINT(100), voltagePSU1 TINYINT(100),
voltagePSU2 TINYINT(100) NULL, voltagePSU2 TINYINT(100) NULL,
inletTemp FLOAT, inletTemp FLOAT,
exhaustTemp FLOAT, exhaustTemp FLOAT,
uptime INT NULL, cpu1Temp FLOAT,
pressure FLOAT NULL, cpu2Temp FLOAT NULL,
altitude FLOAT NULL uptimeH INT ,
uptimeD FLOAT NULL
); );
CREATE TABLE fansHOSTNAMEHERE (
id MEDIUMINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
time_stamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
hostname TEXT(30),
FANxxxRPM INT
);
CREATE TABLE ciscoHOSTNAMEHERE (
id MEDIUMINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
time_stamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
hostname TEXT(30),
something INT
);