Compare commits
30 Commits
2296c89878
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| e18aed96c8 | |||
| e66998b826 | |||
| c474f9c9c2 | |||
| e06eea68cd | |||
| c9d07e7cef | |||
| 10d14a06db | |||
| 78d240a1fc | |||
| faf343b176 | |||
| 10e6ae2347 | |||
| fcf3643ff8 | |||
| 0b497c1abe | |||
| 674eaef47a | |||
| d3d274b2a1 | |||
| 583a72ac98 | |||
| 11dc0397e7 | |||
| 44665891ab | |||
| 28e0a1da34 | |||
| 222e64c113 | |||
| 886f7bbd19 | |||
| f7d28b31b8 | |||
| 912ce9c10e | |||
| 943954ed9d | |||
| 1936976312 | |||
| b074b9d633 | |||
| 15f7783aeb | |||
| d8d6a7aad3 | |||
| 5ea68b548e | |||
| cdf3b983bc | |||
| 45ab7d2761 | |||
| 1cc6c7d3ee |
13
IDRACconfigutarion.md
Normal file
13
IDRACconfigutarion.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# IDRAC7/8
|
||||
|
||||
First under **IDRAC Settings** go to **Network**, and then to **Services**. There scroll down to **SNMP Agent** section and check the **Enabled** checkbox, set **SNMP Protocol** to **SNMP v3**. Under **SNMP Discovery Port Number** the SNMP port can be changed.
|
||||
|
||||
Thereafter under **IDRAC Settings** and **User Authentication** create a user. Do it by clicking a **User ID** number that does not have any user associated with it. Then click **Next** and check the **Enable User** checkbox, set a proper **User Name** for the user, set password under both **New Password** and **Confirm New Password**. After doing that, scroll down to **SNMP v3** section, check the **Enable SNMP v3** checkbox and select **SHA** under **Authentication type** and **AES** under **Privacy type**.
|
||||
|
||||
Remember to click **Apply** at the end to save the user.
|
||||
|
||||
# IDRAC9
|
||||
|
||||
Hover over **IDRAC Settings** and click **Services**. There go to **SNMP Agent** and do the same thing as in IDRAC7 or IDRAC8.
|
||||
|
||||
After enabling SNMP go to **Users** under **IDRAC Settings** and click **Local Users**. Click **Add** and fill the same fields as in IDRAC7 or IDRAC8.
|
||||
82
MIBs.md
82
MIBs.md
@@ -1,4 +1,4 @@
|
||||
# IDRAC8
|
||||
# IDRAC7/8
|
||||
|
||||
## temperatureProbeReading
|
||||
|
||||
@@ -63,4 +63,82 @@ Get the CPU name(s)
|
||||
|
||||
.1.3.6.1.4.1.674.10892.5.2.5.0 (systemPowerUpTime)
|
||||
|
||||
Uptime in seconds
|
||||
Uptime in seconds
|
||||
|
||||
|
||||
|
||||
# IDRAC9
|
||||
|
||||
Here the power OID is different :(
|
||||
|
||||
|
||||
## Power
|
||||
|
||||
Here are the OIDs for string
|
||||
|
||||
SNMPv2-SMI::enterprises.674.10892.5.4.600.30.1.8.1.1 = STRING: "PS1 Current 1"
|
||||
SNMPv2-SMI::enterprises.674.10892.5.4.600.30.1.8.1.2 = STRING: "PS2 Current 2"
|
||||
SNMPv2-SMI::enterprises.674.10892.5.4.600.30.1.8.1.3 = STRING: "System Board Pwr Consumption"
|
||||
|
||||
### Current and Watts
|
||||
|
||||
and here are OIDs for intigers. They show miliamps*100. So when ...6.1.1 show 2 it means 2/10 so 100mA = 0.1A.
|
||||
|
||||
BUT the last one is the total board power which is in Watts
|
||||
|
||||
SNMPv2-SMI::enterprises.674.10892.5.4.600.30.1.6.1.1 = INTEGER: 2
|
||||
SNMPv2-SMI::enterprises.674.10892.5.4.600.30.1.6.1.2 = INTEGER: 10
|
||||
SNMPv2-SMI::enterprises.674.10892.5.4.600.30.1.6.1.3 = INTEGER: 240
|
||||
|
||||
### Voltage
|
||||
|
||||
Here are OIDs for Voltage. They need to be divided by 1000 to get 236.000 Volts
|
||||
|
||||
PSU1 and PSU2
|
||||
|
||||
SNMPv2-SMI::enterprises.674.10892.5.4.600.20.1.6.1.33 = INTEGER: 236000
|
||||
SNMPv2-SMI::enterprises.674.10892.5.4.600.20.1.6.1.34 = INTEGER: 236000
|
||||
|
||||
## Temperatures
|
||||
|
||||
Here are the strings for the temp readings
|
||||
|
||||
SNMPv2-SMI::enterprises.674.10892.5.4.700.20.1.8.1.1 = STRING: "CPU1 Temp"
|
||||
SNMPv2-SMI::enterprises.674.10892.5.4.700.20.1.8.1.2 = STRING: "CPU2 Temp"
|
||||
SNMPv2-SMI::enterprises.674.10892.5.4.700.20.1.8.1.3 = STRING: "System Board Inlet Temp"
|
||||
SNMPv2-SMI::enterprises.674.10892.5.4.700.20.1.8.1.4 = STRING: "System Board Exhaust Temp"
|
||||
|
||||
|
||||
These are temperature readings for inlet and exhaust. They need to be divided by 10 so that 260/10 = 26 C
|
||||
|
||||
SNMPv2-SMI::enterprises.674.10892.5.4.700.20.1.6.1.1 = INTEGER: 550
|
||||
SNMPv2-SMI::enterprises.674.10892.5.4.700.20.1.6.1.2 = INTEGER: 560
|
||||
SNMPv2-SMI::enterprises.674.10892.5.4.700.20.1.6.1.3 = INTEGER: 260
|
||||
SNMPv2-SMI::enterprises.674.10892.5.4.700.20.1.6.1.4 = INTEGER: 310
|
||||
|
||||
|
||||
|
||||
# NXOS 9.3
|
||||
|
||||
|
||||
## Temperature
|
||||
|
||||
1.3.6.1.4.1.9.9.91.1.1.1.1.4.XXXX (entSensorStatus)
|
||||
|
||||
This OID has temperatures
|
||||
|
||||
```
|
||||
iso.3.6.1.4.1.9.9.91.1.1.1.1.4.38486 = INTEGER: 30
|
||||
iso.3.6.1.4.1.9.9.91.1.1.1.1.4.38487 = INTEGER: 43
|
||||
iso.3.6.1.4.1.9.9.91.1.1.1.1.4.38488 = INTEGER: 51
|
||||
iso.3.6.1.4.1.9.9.91.1.1.1.1.4.38489 = INTEGER: 61
|
||||
```
|
||||
|
||||
### Sensor names
|
||||
|
||||
```
|
||||
iso.3.6.1.2.1.47.1.1.1.1.7.38486 = STRING: "module-1 FRONT"
|
||||
iso.3.6.1.2.1.47.1.1.1.1.7.38487 = STRING: "module-1 BACK"
|
||||
iso.3.6.1.2.1.47.1.1.1.1.7.38488 = STRING: "module-1 CPU"
|
||||
iso.3.6.1.2.1.47.1.1.1.1.7.38489 = STRING: "module-1 Sugarbowl"
|
||||
```
|
||||
|
||||
5
README.md
Normal file
5
README.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Hi
|
||||
|
||||
<p align="center">
|
||||
<img src="https://data.shupogaki.org/assets/HBX2LV4aMAAstst.png" alt="">
|
||||
</p>
|
||||
7
REDFISH.md
Normal file
7
REDFISH.md
Normal 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/
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
! IOS 15.0(1)SE2
|
||||
|
||||
! Optional
|
||||
access-list 10 permit 192.168.1.50
|
||||
snmp-server group MONITOR v3 priv access 10
|
||||
snmp-server user username MONITOR v3 auth sha password123 priv aes 128 password123
|
||||
@@ -0,0 +1,9 @@
|
||||
! NXOS 9.3
|
||||
|
||||
! ACL
|
||||
! ip access-list SNMP-SERVERS
|
||||
! permit ip 192.168.1.50/32 any
|
||||
|
||||
snmp-server user snmpuser auth sha 123 priv aes-128 123
|
||||
! Make the user RO
|
||||
username snmpuser role network-operator
|
||||
@@ -15,16 +15,22 @@ USER pyusr
|
||||
|
||||
WORKDIR /app/snmpython/
|
||||
|
||||
|
||||
COPY ./requirements.txt /app/snmpython/
|
||||
RUN python3 -m venv pyvenv && \
|
||||
pyvenv/bin/python3 -m pip install --upgrade pip && \
|
||||
pyvenv/bin/pip3 install -r requirements.txt
|
||||
|
||||
COPY ./main.py /app/snmpython/
|
||||
COPY ./funct.py /app/snmpython/
|
||||
COPY ./classes.py /app/snmpython/
|
||||
# COPY ../code/MIBs/ /app/snmpython/MIBs
|
||||
COPY ./mainRE.py /app/snmpython/
|
||||
|
||||
RUN mkdir cisco db idrac models snmp
|
||||
|
||||
ADD cisco /app/snmpython/cisco
|
||||
ADD db /app/snmpython/db
|
||||
ADD idrac /app/snmpython/idrac
|
||||
ADD models /app/snmpython/models
|
||||
ADD snmp /app/snmpython/snmp
|
||||
|
||||
# COPY ../code/MIBs/ /app/snmpython/MIBs
|
||||
|
||||
# COPY ./entrypoint.sh /entrypoint.sh
|
||||
# RUN chmod +x /entrypoint.sh
|
||||
@@ -44,4 +50,4 @@ COPY ./classes.py /app/snmpython/
|
||||
# HEALTHCHECK --interval=3s --timeout=3s --retries=3 \
|
||||
# CMD curl --fail http://127.0.0.1:8181/health || exit 1
|
||||
|
||||
CMD ["/app/snmpython/pyvenv/bin/python3", "/app/snmpython/main.py"]
|
||||
CMD ["/app/snmpython/pyvenv/bin/python3", "/app/snmpython/mainRE.py"]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
0
cont/cisco/__init__.py
Normal file
0
cont/cisco/__init__.py
Normal file
113
cont/cisco/lob.py
Normal file
113
cont/cisco/lob.py
Normal file
@@ -0,0 +1,113 @@
|
||||
import os, asyncio
|
||||
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 *
|
||||
|
||||
# Cisco
|
||||
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")), # 0
|
||||
)
|
||||
errorIndication, errorStatus, errorIndex, varBinds = await iterator
|
||||
|
||||
if 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(
|
||||
errorStatus.prettyPrint(),
|
||||
errorIndex and varBinds[int(errorIndex) - 1][0] or "?",
|
||||
)
|
||||
)
|
||||
else:
|
||||
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 = 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])
|
||||
|
||||
)
|
||||
|
||||
returnDict = {
|
||||
"source": "CISCO",
|
||||
"device": "3750X",
|
||||
"value": returObj,
|
||||
"type": "C3750XciscoData"
|
||||
}
|
||||
await queueToInsrt.put(returnDict)
|
||||
85
cont/cisco/nyater.py
Normal file
85
cont/cisco/nyater.py
Normal file
@@ -0,0 +1,85 @@
|
||||
# NYATER
|
||||
import os, asyncio
|
||||
from models.ciscoModel import snmpPyCiscoData
|
||||
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,
|
||||
)
|
||||
|
||||
|
||||
|
||||
# Cisco
|
||||
async def ciscoPoolRemote(remoteIP: str, queueToInsrt: asyncio.Queue):
|
||||
print("starting work on ", remoteIP)
|
||||
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
|
||||
await queueToInsrt.put(returnDict)
|
||||
119
cont/classes.py
119
cont/classes.py
@@ -1,119 +0,0 @@
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy import Column, Date, Float, Integer, String, text
|
||||
from datetime import datetime, timezone, timedelta
|
||||
from typing import Optional, Annotated, Dict
|
||||
from sqlalchemy.dialects.mysql import MEDIUMINT, TINYINT, TEXT, TIMESTAMP, FLOAT
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from dataclasses import dataclass
|
||||
|
||||
# -----------
|
||||
|
||||
AlchemyBase = declarative_base()
|
||||
|
||||
# DATABASE "CLASSESS"--------------------------------------------
|
||||
def sensorsqldata(table_name: Annotated[str, "Name of the table"]):
|
||||
|
||||
class SensorSQLDataClass(AlchemyBase):
|
||||
__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,
|
||||
)
|
||||
TEMP = Column(TINYINT)
|
||||
TEMP = Column(TEXT)
|
||||
TEMP = Column(Float)
|
||||
TEMP = Column(Float)
|
||||
TEMP = Column(Float, nullable=True)
|
||||
TEMP = Column(Float, nullable=True)
|
||||
TEMP = Column(Float, nullable=True)
|
||||
|
||||
return SensorSQLDataClass
|
||||
|
||||
|
||||
# Custom--------------------------------------------
|
||||
class snmpValueToHost():
|
||||
def __init__(self,
|
||||
lastV: Annotated[str, "Last value\nNone when initializing"] = None,
|
||||
remote: Annotated[str, "Needs to be a valid IP address"] = None,
|
||||
nextV: Annotated[str, "Value to insert next\nNone when initializing"] = None,
|
||||
lasttime: Annotated[float, "Last time since sending data\nSince Epoch, so time.time()"] = None,
|
||||
lastStatus: Annotated[bool, "True if value newest value was inserted\nFalse if data is pending to be sent"] = False
|
||||
):
|
||||
self.__lastValue = lastV # Save last sent value
|
||||
self.__remote = remote # Remote IP address of the SNMP client
|
||||
self.__nextValue = nextV # Next value to send. Maybe will be used
|
||||
self.__lastSentStatus = lastStatus # If previously sent new data, set to True.
|
||||
self.__lastSentTime = lasttime if lasttime else time.time() # The time since the Epoch of the last sent data*
|
||||
|
||||
|
||||
def ___str__(self):
|
||||
return self.__lastValue
|
||||
|
||||
def __changeLastSentValue(self, newValue: int) -> bool:
|
||||
self.__nextValue == newValue
|
||||
self.__lastValue = self.__nextValue
|
||||
self.__nextValue == None
|
||||
return True
|
||||
|
||||
def __updateLastSentTime(self):
|
||||
self.__lastSentTime = time.time()
|
||||
return True
|
||||
|
||||
def __updateSentStatus(self):
|
||||
if self.__lastSentStatus:
|
||||
self.__lastSentStatus = False
|
||||
return False
|
||||
else:
|
||||
self.__lastSentStatus = True
|
||||
return True
|
||||
|
||||
def updateStats(self, nextV: Annotated[int, "Value that will be set as the new one"]):
|
||||
__changeLastSentValue(nextV)
|
||||
__updateLastSentTime()
|
||||
...
|
||||
|
||||
|
||||
# Dataclasses--------------------------------------------
|
||||
|
||||
@dataclass
|
||||
class snmpPyIDRACData():
|
||||
"""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] # name/index -> rpm
|
||||
167
cont/db/Influx.py
Normal file
167
cont/db/Influx.py
Normal file
@@ -0,0 +1,167 @@
|
||||
import influxdb_client, os, asyncio
|
||||
from influxdb_client import InfluxDBClient, Point, WritePrecision
|
||||
from influxdb_client.client.write_api import SYNCHRONOUS, ASYNCHRONOUS, WriteOptions
|
||||
from typing import Annotated, Final
|
||||
from models.idracModel import snmpPyIDRACData
|
||||
|
||||
# FluxQL ENV----------------------------------------
|
||||
USEINFLUX: Final[int] = int(os.getenv("USEINFLUX", 1))
|
||||
if USEINFLUX:
|
||||
INFLXDBTOKEN: Final[str] = os.getenv("INFLXDBTOKEN", "123" )
|
||||
INFLUXBCKT: Final[str] = os.getenv("INFLUXBCKT", "SNMPyth")
|
||||
INFLUXORG: Final[str] = os.getenv("INFLUXORG", "staging")
|
||||
INFLXDBURL: Final[str] = os.getenv("INFLXDBURL", "http://localhost:8086")
|
||||
INFXLUXDB_MEASUEREMENT: Final[str] = os.getenv("INFXLUXDB_MEASUEREMENT", "SNMPyth-containrr")
|
||||
INFLX_SEPARATE_POINTS: Final[float] = float(os.getenv("INFLX_SEPARATE_POINTS", 0.1))
|
||||
|
||||
# Prepare-------------------------------------------
|
||||
# INFLUX
|
||||
if USEINFLUX:
|
||||
fluxdb_client = influxdb_client.InfluxDBClient(url=INFLXDBURL, token=INFLXDBTOKEN, org=INFLUXORG)
|
||||
write_fluxdb_api = fluxdb_client.write_api(write_options=ASYNCHRONOUS)
|
||||
query_fluxdb_api = fluxdb_client.query_api()
|
||||
else:
|
||||
fluxdb_client = write_fluxdb_api = query_fluxdb_api = None
|
||||
|
||||
async def fluxIDRACWriter(
|
||||
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
|
||||
|
||||
# Prep InfluxDB data
|
||||
inflxdb_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_Data_To_Send)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return 1
|
||||
|
||||
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)
|
||||
103
cont/db/MariaDB.py
Normal file
103
cont/db/MariaDB.py
Normal file
@@ -0,0 +1,103 @@
|
||||
import sqlalchemy, os, asyncio
|
||||
from sqlalchemy.ext.asyncio import create_async_engine
|
||||
from typing import Annotated, Final
|
||||
from dataclasses import asdict
|
||||
from models.idracModel import snmpPyIDRACData
|
||||
from models.ciscoModel import C3750XciscoData
|
||||
from models.sqlTable import idracMeasurement, C3750XMeasurement
|
||||
|
||||
# SQL ENV-------------------------------------------
|
||||
USESQL: Final[int] = int(os.getenv("USESQL", 0))
|
||||
if USESQL:
|
||||
DBENGINE: Final[str] = os.getenv("DBENGINE", "mysql+asyncmy")
|
||||
DBADDR: Final[str] = os.getenv("DBADDR", "127.0.0.1")
|
||||
DBUSR: Final[str] = os.getenv("DBUSR", "root")
|
||||
DBPWD: Final[str] = os.getenv("DBPWD", "6767")
|
||||
DBNAME: Final[str] = os.getenv("DBNAME", "TEMP_SENSR")
|
||||
|
||||
|
||||
# SQL
|
||||
if USESQL:
|
||||
engine = create_async_engine(
|
||||
f"{DBENGINE}://{DBUSR}:{DBPWD}@{DBADDR}/{DBNAME}",
|
||||
# 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
|
||||
echo=True,
|
||||
)
|
||||
else:
|
||||
engine = None
|
||||
|
||||
|
||||
async def sqlDataWriter(
|
||||
inpDict: dict
|
||||
) -> int:
|
||||
|
||||
# inputQueue have multiple such Dicts
|
||||
# {
|
||||
# "source": "IDRAC",
|
||||
# "value": returnObj,
|
||||
# "type": "snmpPyIDRACData"
|
||||
# }
|
||||
if engine is None:
|
||||
return 3
|
||||
try:
|
||||
async with engine.begin() as eng:
|
||||
match inpDict["source"]:
|
||||
|
||||
case "CISCO":
|
||||
|
||||
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)
|
||||
|
||||
await eng.execute(
|
||||
idracMeasurement.insert(),
|
||||
[row]
|
||||
)
|
||||
return 0
|
||||
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
|
||||
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return 2
|
||||
|
||||
return 0
|
||||
|
||||
# asyncio.sleep(5)
|
||||
0
cont/db/__init__.py
Normal file
0
cont/db/__init__.py
Normal file
40
cont/db/collectiveWriter.py
Normal file
40
cont/db/collectiveWriter.py
Normal file
@@ -0,0 +1,40 @@
|
||||
import asyncio, os
|
||||
from typing import Annotated, Final
|
||||
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))
|
||||
|
||||
async def ALLdbIDRACWriter(inputQueue: asyncio.Queue) -> None:
|
||||
while True:
|
||||
|
||||
# print(inputQueue)
|
||||
|
||||
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("Inserted in SQL")
|
||||
if USEINFLUX:
|
||||
fluxResult = await fluxDataWriter(qu)
|
||||
match fluxResult:
|
||||
case 1:
|
||||
print("could not insert")
|
||||
case 2:
|
||||
print("Error with initializing Inxlux variables")
|
||||
case _:
|
||||
print("Inserted to InfluxDB")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
finally:
|
||||
inputQueue.task_done()
|
||||
@@ -8,21 +8,22 @@ services:
|
||||
build:
|
||||
dockerfile: ./Dockerfile
|
||||
environment:
|
||||
- USEINFLUX=True
|
||||
- USEINFLUX=1
|
||||
- INFLXDBTOKEN=67676767
|
||||
- INFLUXBCKT=pyusr-DEV
|
||||
- INFLUXORG=staging
|
||||
- INFLXDBURL=http://influxdb:8086
|
||||
- INFXLUXDB_MEASUEREMENT=dev-pycollector
|
||||
|
||||
- USESQL=1
|
||||
- DBADDR=mariadb
|
||||
- DBUSR=root
|
||||
- DBPWD=67676767
|
||||
- DBNAME=pyCollector
|
||||
|
||||
- SNMPUSER=SNMPUSR
|
||||
- SNMPPRIVKEY=123
|
||||
- SNMPAUTHKEY=123
|
||||
- SNMPUSER=SNMPusrRO
|
||||
- SNMPPRIVKEY=67676767
|
||||
- SNMPAUTHKEY=67676767
|
||||
|
||||
- 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
|
||||
|
||||
31
cont/docker-compose.yaml
Normal file
31
cont/docker-compose.yaml
Normal 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
|
||||
129
cont/funct.py
129
cont/funct.py
@@ -1,129 +0,0 @@
|
||||
import influxdb_client, sqlalchemy, random, os
|
||||
# from sqlmodel import Field, Session, SQLModel, create_engine, select
|
||||
from sqlalchemy import create_engine, exc # , Column, Integer, String, Numeric
|
||||
# from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from classes import *
|
||||
from typing import Annotated, Final
|
||||
|
||||
from influxdb_client import InfluxDBClient, Point, WritePrecision
|
||||
from influxdb_client.client.write_api import SYNCHRONOUS, ASYNCHRONOUS, WriteOptions
|
||||
# import pymysql
|
||||
|
||||
# FluxQL ENV----------------------------------------
|
||||
USEINFLUX: Final[bool] = os.getenv("USEINFLUX", True)
|
||||
if USEINFLUX:
|
||||
INFLXDBTOKEN: Final[str] = os.getenv("INFLXDBTOKEN", "123" )
|
||||
INFLUXBCKT: Final[str] = os.getenv("INFLUXBCKT", "SNMPyth")
|
||||
INFLUXORG: Final[str] = os.getenv("INFLUXORG", "staging")
|
||||
INFLXDBURL: Final[str] = os.getenv("INFLXDBURL", "http://localhost:8086")
|
||||
INFXLUXDB_MEASUEREMENT: Final[str] = os.getenv("INFXLUXDB_MEASUEREMENT", "SNMPyth-containrr")
|
||||
INFLX_SEPARATE_POINTS: Final[float] = float(os.getenv("INFLX_SEPARATE_POINTS", 0.1))
|
||||
# SQL ENV-------------------------------------------
|
||||
USESQL: Final[bool] = os.getenv("USESQL", False)
|
||||
if USESQL:
|
||||
DBENGINE: Final[str] = os.getenv("DBENGINE", "mysql+pymysql")
|
||||
DBADDR: Final[str] = os.getenv("DBADDR", "127.0.0.1")
|
||||
DBUSR: Final[str] = os.getenv("DBUSR", "root")
|
||||
DBPWD: Final[str] = os.getenv("DBPWD", "6767")
|
||||
DBNAME: Final[str] = os.getenv("DBNAME", "TEMP_SENSR")
|
||||
|
||||
|
||||
|
||||
# Flightchecks-------------------------------------------
|
||||
# Check if some neccesary ENVs are passed
|
||||
if not USEINFLUX and not USESQL:
|
||||
raise Exception("No database selected to store the data")
|
||||
|
||||
|
||||
# DBprepare-------------------------------------------
|
||||
# INFLUX
|
||||
if USEINFLUX:
|
||||
fluxdb_client = influxdb_client.InfluxDBClient(url=INFLXDBURL, token=INFLXDBTOKEN, org=INFLUXORG)
|
||||
write_fluxdb_api = fluxdb_client.write_api(write_options=SYNCHRONOUS)
|
||||
query_fluxdb_api = fluxdb_client.query_api()
|
||||
# SQL
|
||||
if USESQL:
|
||||
engine = create_engine(
|
||||
f"{DBENGINE}://{DBUSR}:{DBPWD}@{DBADDR}/{DBNAME}",
|
||||
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
|
||||
)
|
||||
Session = sessionmaker(bind=engine)
|
||||
|
||||
|
||||
def tempsnsrIntoSQLDB(
|
||||
tableInp: Annotated[int, "Name of the table"],
|
||||
insertData: Annotated[str, "Data to insert"]
|
||||
) -> 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:
|
||||
return 2
|
||||
|
||||
# Check if table exists
|
||||
if not sqlalchemy.inspect(engine).has_table(tableInp):
|
||||
return 3
|
||||
|
||||
with Session() as session:
|
||||
|
||||
try:
|
||||
|
||||
sqlData = sensorsqldata(tableInp)
|
||||
# print("2")
|
||||
|
||||
if inpayload:
|
||||
# print("3")
|
||||
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
|
||||
|
||||
|
||||
def tempsnsrIntoFluxQLDB(
|
||||
inIdracPayload: Annotated[snmpPyIDRACData, "Payload"] | None = None,
|
||||
inCiscoPayload: Annotated[int, "yes"] | None = None
|
||||
) -> int:
|
||||
|
||||
"""
|
||||
Insert temperature data into InfluxDB
|
||||
:inpayload: Payload
|
||||
:return: 0 if succesfull, 1 if general error, 2 if Influx is not enabled
|
||||
"""
|
||||
if not USEINFLUX:
|
||||
return 2
|
||||
# Prep InfluxDB data
|
||||
inflxdb_Data_To_Send = (
|
||||
influxdb_client.Point(f"{INFXLUXDB_MEASUEREMENT}")
|
||||
.tag("PLACE", inpayload.name)
|
||||
.tag("TEMP", sensorIDinp)
|
||||
.tag("TEMP", whatTheSensor)
|
||||
.field("TEMP", inpayload.temp)
|
||||
.field("TEMP", inpayload.humid)
|
||||
.field("TEMP", inpayload.hicc)
|
||||
.field("TEMP", inpayload.presss)
|
||||
.field("TEMP", inpayload.alttd)
|
||||
)
|
||||
|
||||
# print(write_fluxdb_api.write(bucket=INFLUXBCKT, org=INFLUXORG, record=inflxdb_Data_To_Send))
|
||||
# if write_fluxdb_api.write(bucket=INFLUXBCKT, org=INFLUXORG, record=inflxdb_Data_To_Send) == None:
|
||||
|
||||
if write_fluxdb_api.write(bucket=INFLUXBCKT, org=INFLUXORG, record=inflxdb_Data_To_Send):
|
||||
# return {"STATUS": "succesfully inserted to InfluxDB"}
|
||||
print("0")
|
||||
return 0
|
||||
else:
|
||||
print("1")
|
||||
return 1
|
||||
0
cont/idrac/__init__.py
Normal file
0
cont/idrac/__init__.py
Normal file
62
cont/idrac/fans.py
Normal file
62
cont/idrac/fans.py
Normal file
@@ -0,0 +1,62 @@
|
||||
import os, asyncio
|
||||
from models.fanModel import fanModel
|
||||
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,
|
||||
)
|
||||
|
||||
|
||||
|
||||
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"
|
||||
}
|
||||
|
||||
await queueToInsrt.put(returnDict)
|
||||
208
cont/idrac/idrac78.py
Normal file
208
cont/idrac/idrac78.py
Normal file
@@ -0,0 +1,208 @@
|
||||
import os, asyncio
|
||||
from models.idracModel import snmpPyIDRACData
|
||||
from snmp.walker import walk_column_v3
|
||||
from typing import Annotated, Final
|
||||
|
||||
# SNMP
|
||||
from pysnmp.hlapi.v3arch.asyncio import *
|
||||
|
||||
# IDRAC78 get data for snmpPyIDRACData class
|
||||
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
|
||||
|
||||
mainIterator = 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
|
||||
# Uptime in seconds
|
||||
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.2.5.0")), #1
|
||||
)
|
||||
|
||||
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(
|
||||
"{} at {}".format(
|
||||
errorStatus.prettyPrint(),
|
||||
errorIndex and mainVarBinds[int(errorIndex) - 1][0] or "?",
|
||||
)
|
||||
)
|
||||
else:
|
||||
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)
|
||||
|
||||
# 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)
|
||||
|
||||
# .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)
|
||||
|
||||
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()
|
||||
|
||||
# Exhaust CPU1 and CPU2 temp
|
||||
|
||||
exhaustTemp = None
|
||||
cpu2Temp = None
|
||||
if len(currentsCurrentResults) == 1 and int(mainVarBinds[1][-1]) == 0:
|
||||
exhaustTemp = int(sensorValuesResults[2]) / 10
|
||||
cpu1Temp = None
|
||||
elif hasExhaust and hasCPU2:
|
||||
exhaustTemp = int(sensorValuesResults[2]) / 10
|
||||
cpu1Temp = int(sensorValuesResults[3]) / 10
|
||||
cpu2Temp = int(sensorValuesResults[4]) / 10
|
||||
elif hasExhaust and not hasCPU2:
|
||||
exhaustTemp = int(sensorValuesResults[2]) / 10
|
||||
cpu1Temp = int(sensorValuesResults[3]) / 10
|
||||
elif hasCPU2 and not hasExhaust:
|
||||
cpu1Temp = int(sensorValuesResults[3]) / 10
|
||||
cpu2Temp = int(sensorValuesResults[4]) / 10
|
||||
else:
|
||||
cpu1Temp = int(sensorValuesResults[2]) / 10
|
||||
|
||||
# If power draw is 0; I.E. if server is turned off
|
||||
if len(currentsCurrentResults) == 1 and int(mainVarBinds[1][-1]) == 0:
|
||||
returnObj = snmpPyIDRACData(
|
||||
hostname=mainVarBinds[0][-1],
|
||||
# Hostname
|
||||
|
||||
powerDrawPSU1=None,
|
||||
powerDrawPSU2=None,
|
||||
# PSU1 and PSU2 power draw in Watts
|
||||
|
||||
# board power draw
|
||||
powerDrawBoard=None,
|
||||
|
||||
voltagePSU1=None,
|
||||
voltagePSU2=None,
|
||||
# PSU1 and PSU2 voltages
|
||||
|
||||
inletTemp=(int(sensorValuesResults[1]) / 10),
|
||||
exhaustTemp=exhaustTemp,
|
||||
# Inlet and Exhaust temp
|
||||
|
||||
cpu1Temp=None,
|
||||
cpu2Temp=None,
|
||||
# CPU1 and CPU2 temp
|
||||
|
||||
uptimeS=int(mainVarBinds[1][-1]),
|
||||
# seconds
|
||||
uptimeH=round(((int(mainVarBinds[1][-1]) / 60) / 60), ROUND_PREC),
|
||||
# seconds->minutes->hours
|
||||
uptimeD=round((((int(mainVarBinds[1][-1]) / 60) / 60) / 24), ROUND_PREC)
|
||||
# seconds->minutes->hours->days
|
||||
)
|
||||
returnDict = {
|
||||
"source": "IDRAC",
|
||||
"value": returnObj,
|
||||
"type": "snmpPyIDRACData"
|
||||
}
|
||||
# return returnObj
|
||||
await queueToInsrt.put(returnDict)
|
||||
return 1
|
||||
|
||||
|
||||
voltList = []
|
||||
for thing in voltResult:
|
||||
voltList.append(voltResult[thing])
|
||||
|
||||
# PSU2 values and board power
|
||||
psu2PowerDraw = None
|
||||
psu2Amperage = None
|
||||
psu2Voltage = None
|
||||
|
||||
if hasPSU2:
|
||||
psu2PowerDraw = round((int(currentsCurrentResults[2]) / 10) * (int(voltList[1]) / 1000), ROUND_PREC)
|
||||
psu2Amperage = int(currentsCurrentResults[2]) / 10
|
||||
psu2Voltage = round((int(voltList[1]) / 1000), ROUND_PREC)
|
||||
boardPowerDraw = int(currentsCurrentResults[3])
|
||||
else:
|
||||
boardPowerDraw = int(currentsCurrentResults[2])
|
||||
|
||||
|
||||
returnObj = snmpPyIDRACData(
|
||||
hostname=mainVarBinds[0][-1],
|
||||
# Hostname
|
||||
|
||||
powerDrawPSU1=round((int(currentsCurrentResults[1]) / 10) * (int(voltList[0]) / 1000), ROUND_PREC),
|
||||
powerDrawPSU2=psu2PowerDraw,
|
||||
# PSU1 and PSU2 power draw in Watts
|
||||
|
||||
# board power draw
|
||||
powerDrawBoard=boardPowerDraw,
|
||||
|
||||
voltagePSU1=round((int(voltList[0]) / 1000), ROUND_PREC),
|
||||
voltagePSU2=psu2Voltage,
|
||||
# PSU1 and PSU2 voltages
|
||||
|
||||
inletTemp=(int(sensorValuesResults[1]) / 10),
|
||||
exhaustTemp=exhaustTemp,
|
||||
# Inlet and Exhaust temp
|
||||
|
||||
cpu1Temp=cpu1Temp,
|
||||
cpu2Temp=cpu2Temp,
|
||||
# CPU1 and CPU2 temp
|
||||
|
||||
uptimeS=int(mainVarBinds[1][-1]),
|
||||
# seconds
|
||||
uptimeH=round(((int(mainVarBinds[1][-1]) / 60) / 60), ROUND_PREC),
|
||||
# seconds->minutes->hours
|
||||
uptimeD=round((((int(mainVarBinds[1][-1]) / 60) / 60) / 24), ROUND_PREC)
|
||||
# seconds->minutes->hours->days
|
||||
)
|
||||
|
||||
returnDict = {
|
||||
"source": "IDRAC",
|
||||
"value": returnObj,
|
||||
"type": "snmpPyIDRACData"
|
||||
}
|
||||
# return returnObj
|
||||
await queueToInsrt.put(returnDict)
|
||||
218
cont/idrac/idrac9.py
Normal file
218
cont/idrac/idrac9.py
Normal file
@@ -0,0 +1,218 @@
|
||||
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 *
|
||||
|
||||
|
||||
# IDRAC get data for snmpPyIDRACData class
|
||||
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(
|
||||
snmpEngine,
|
||||
USMUSRDATA,
|
||||
await UdpTransportTarget.create((remoteIP, SNMPORT)),
|
||||
ContextData(),
|
||||
# Hostname (sysName.0)
|
||||
ObjectType(ObjectIdentity(".1.3.6.1.2.1.1.5.0")), #0
|
||||
# Uptime in seconds
|
||||
ObjectType(ObjectIdentity(".1.3.6.1.4.1.674.10892.5.2.5.0")), #1
|
||||
|
||||
)
|
||||
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(
|
||||
"{} at {}".format(
|
||||
errorStatus.prettyPrint(),
|
||||
errorIndex and mainVarBinds[int(errorIndex) - 1][0] or "?",
|
||||
)
|
||||
)
|
||||
else:
|
||||
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)
|
||||
|
||||
# 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", 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())
|
||||
|
||||
|
||||
# Exhaust CPU1 and CPU2 temp
|
||||
|
||||
exhaustTemp = None
|
||||
inletTemp = None
|
||||
cpu2Temp = None
|
||||
if len(currentsCurrentResults) == 1 and int(mainVarBinds[1][-1]) == 0:
|
||||
exhaustTemp = int(sensorValuesResults[2]) / 10
|
||||
inletTemp = int(sensorValuesResults[1]) / 10
|
||||
cpu1Temp = None
|
||||
elif hasExhaust and hasCPU2:
|
||||
exhaustTemp = int(sensorValuesResults[4]) / 10
|
||||
inletTemp = int(sensorValuesResults[3]) / 10
|
||||
cpu2Temp = int(sensorValuesResults[2]) / 10
|
||||
elif hasExhaust and not hasCPU2:
|
||||
exhaustTemp = int(sensorValuesResults[3]) / 10
|
||||
inletTemp = int(sensorValuesResults[2]) / 10
|
||||
elif hasCPU2 and not hasExhaust:
|
||||
inletTemp = int(sensorValuesResults[3]) / 10
|
||||
cpu2Temp = int(sensorValuesResults[2]) / 10
|
||||
else:
|
||||
inletTemp = int(sensorValuesResults[2]) / 10
|
||||
|
||||
if len(currentsCurrentResults) == 1 and int(mainVarBinds[1][-1]) == 0:
|
||||
returnObj = snmpPyIDRACData(
|
||||
hostname=mainVarBinds[0][-1],
|
||||
# Hostname
|
||||
|
||||
powerDrawPSU1=None,
|
||||
powerDrawPSU2=None,
|
||||
# PSU1 and PSU2 power draw in Watts
|
||||
|
||||
# board power draw
|
||||
powerDrawBoard=None,
|
||||
|
||||
voltagePSU1=None,
|
||||
voltagePSU2=None,
|
||||
# PSU1 and PSU2 voltages
|
||||
|
||||
inletTemp=inletTemp,
|
||||
exhaustTemp=exhaustTemp,
|
||||
# Inlet and Exhaust temp
|
||||
|
||||
cpu1Temp=None,
|
||||
cpu2Temp=None,
|
||||
# CPU1 and CPU2 temp
|
||||
|
||||
uptimeS=int(mainVarBinds[1][-1]),
|
||||
# seconds
|
||||
uptimeH=round(((int(mainVarBinds[1][-1]) / 60) / 60), ROUND_PREC),
|
||||
# seconds->minutes->hours
|
||||
uptimeD=round((((int(mainVarBinds[1][-1]) / 60) / 60) / 24), ROUND_PREC)
|
||||
# seconds->minutes->hours->days
|
||||
)
|
||||
|
||||
returnDict = {
|
||||
"source": "IDRAC",
|
||||
"value": returnObj,
|
||||
"type": "snmpPyIDRACData"
|
||||
}
|
||||
# return returnObj
|
||||
await queueToInsrt.put(returnDict)
|
||||
return 1
|
||||
|
||||
|
||||
voltList = []
|
||||
for thing in voltResult:
|
||||
voltList.append(voltResult[thing])
|
||||
|
||||
# PSU2 values and board power
|
||||
psu2PowerDraw = None
|
||||
psu2Amperage = None
|
||||
psu2Voltage = None
|
||||
psu1PowerDraw = None
|
||||
psu1Amperage = None
|
||||
psu1Voltage = None
|
||||
|
||||
if hasPSU2:
|
||||
psu2PowerDraw = round((int(currentsCurrentResults[2]) / 10) * (int(voltList[1]) / 1000), ROUND_PREC)
|
||||
psu2Amperage = int(currentsCurrentResults[2]) / 10
|
||||
psu2Voltage = round((int(voltList[1]) / 1000), ROUND_PREC)
|
||||
boardPowerDraw = int(currentsCurrentResults[3])
|
||||
else:
|
||||
boardPowerDraw = int(currentsCurrentResults[2])
|
||||
|
||||
returnObj = snmpPyIDRACData(
|
||||
hostname=mainVarBinds[0][-1],
|
||||
# Hostname
|
||||
|
||||
powerDrawPSU1=round((int(currentsCurrentResults[1]) / 10) * (int(voltList[0]) / 1000), ROUND_PREC),
|
||||
powerDrawPSU2=psu2PowerDraw,
|
||||
# PSU1 and PSU2 power draw in Watts
|
||||
|
||||
# board power draw
|
||||
powerDrawBoard=boardPowerDraw,
|
||||
|
||||
voltagePSU1=round((int(voltList[0]) / 1000), ROUND_PREC),
|
||||
voltagePSU2=psu2Voltage,
|
||||
# PSU1 and PSU2 voltages
|
||||
|
||||
inletTemp=inletTemp,
|
||||
exhaustTemp=exhaustTemp,
|
||||
# Inlet and Exhaust temp
|
||||
|
||||
cpu1Temp=int(sensorValuesResults[1]) / 10,
|
||||
cpu2Temp=cpu2Temp,
|
||||
# CPU1 and CPU2 temp
|
||||
|
||||
uptimeS=int(mainVarBinds[1][-1]),
|
||||
# seconds
|
||||
uptimeH=round(((int(mainVarBinds[1][-1]) / 60) / 60), ROUND_PREC),
|
||||
# seconds->minutes->hours
|
||||
uptimeD=round((((int(mainVarBinds[1][-1]) / 60) / 60) / 24), ROUND_PREC)
|
||||
# seconds->minutes->hours->days
|
||||
)
|
||||
|
||||
returnDict = {
|
||||
"source": "IDRAC",
|
||||
"value": returnObj,
|
||||
"type": "snmpPyIDRACData"
|
||||
}
|
||||
# return returnObj
|
||||
await queueToInsrt.put(returnDict)
|
||||
|
||||
258
cont/main.py
258
cont/main.py
@@ -1,258 +0,0 @@
|
||||
import ipaddress, os, re, time, funct, classes, asyncio
|
||||
# SNMP
|
||||
from pysnmp.hlapi.v3arch.asyncio import *
|
||||
# QoL
|
||||
from typing import Annotated, Final
|
||||
# functions
|
||||
from funct import *
|
||||
# additional classes
|
||||
from classes import *
|
||||
|
||||
# Program ENV---------------------------------------
|
||||
ROUND_PREC: Final[int] = os.getenv("ROUND_PREC", 6)
|
||||
IDRAC_HOST_LIST: Final[list] = os.getenv("IDRAC_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-------------------------------------------
|
||||
# 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 not IDRAC_HOST_LIST and not CISCO_HOST_LIST:
|
||||
raise Exception("No hosts passed\nExiting...")
|
||||
|
||||
# for host in HOST_LIST check if valid IP and create a list with strings
|
||||
for idracHost in IDRAC_HOST_LIST:
|
||||
try:
|
||||
ip = str(ipaddress.IPv4Address(idracHost))
|
||||
except ValueError:
|
||||
raise Exception(f" IP {ip} for IDRAC devices is invalid.\nExiting...")
|
||||
for ciscoHost in CISCO_HOST_LIST:
|
||||
try:
|
||||
ip = str(ipaddress.IPv4Address(ciscoHost))
|
||||
except ValueError:
|
||||
raise Exception(f" IP {ip} for Cisco devices is invalid.\nExiting...")
|
||||
|
||||
# Done under "Program ENV" on line ~18
|
||||
|
||||
|
||||
# Code-------------------------------------------
|
||||
|
||||
# Helper functions
|
||||
def wattageCalc(amperageInp: float, voltageInp: float) -> float:
|
||||
return amperageInp * voltageInp
|
||||
|
||||
|
||||
async def ciscoPoolRemote(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(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(
|
||||
snmpEngine,
|
||||
# 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)
|
||||
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
|
||||
)
|
||||
|
||||
|
||||
return returnObj
|
||||
|
||||
|
||||
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])
|
||||
# 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
|
||||
|
||||
139
cont/mainRE.py
Normal file
139
cont/mainRE.py
Normal file
@@ -0,0 +1,139 @@
|
||||
import ipaddress, os, re, time, asyncio
|
||||
# SNMP
|
||||
from pysnmp.hlapi.v3arch.asyncio import *
|
||||
# QoL
|
||||
from typing import Annotated, Final
|
||||
# functions
|
||||
from db.collectiveWriter import ALLdbIDRACWriter
|
||||
# idrac SNMP
|
||||
from idrac import idrac78, idrac9
|
||||
# Cisco hosts
|
||||
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", []).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 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
|
||||
|
||||
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(cisco3750Host))
|
||||
except ValueError:
|
||||
raise Exception(f" IP {ip} for Cisco devices is invalid.\nExiting...")
|
||||
|
||||
|
||||
for ciscoNexusHost in CISCO_NEXUS_HOST_LIST:
|
||||
try:
|
||||
ip = str(ipaddress.IPv4Address(ciscoNexusHost))
|
||||
except ValueError:
|
||||
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
|
||||
|
||||
|
||||
# Code-------------------------------------------
|
||||
|
||||
async def main():
|
||||
|
||||
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,
|
||||
SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY, ROUND_PREC, SNMPORT))
|
||||
|
||||
for Idrac9IP in IDRAC9_HOST_LIST:
|
||||
tg.create_task(idrac9.idrac9PoolRemote_v3(
|
||||
Idrac9IP, mainQueue,
|
||||
SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY, ROUND_PREC, SNMPORT))
|
||||
# FANS
|
||||
# tg.create_task(idracPoolRemoteFAN_v3(IdracIP, mainQueue))
|
||||
|
||||
# CISCO devices
|
||||
for cisco3750Xdev in CISCO_3750_HOST_LIST:
|
||||
tg.create_task(lob.lobGetRemote(
|
||||
cisco3750Xdev, mainQueue,
|
||||
SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY, ROUND_PREC, SNMPORT))
|
||||
|
||||
# for ciscoNexusDev in CISCO_NEXUS_HOST_LIST:
|
||||
# tg.create_task(nyater(
|
||||
# ciscoNexusDev, mainQueue,
|
||||
# SNMPUSER, SNMPAUTHKEY, SNMPPRIVKEY, ROUND_PREC, SNMPORT))
|
||||
|
||||
await asyncio.sleep(GET_INTERVAL)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# qu = asyncio.Queue()
|
||||
# asyncio.run(idracPoolRemote_v3("192.168.20.7", qu))
|
||||
print("Starting")
|
||||
asyncio.run(main())
|
||||
|
||||
# loop = asyncio.get_event_loop()
|
||||
# task = loop.create_task(main())
|
||||
|
||||
0
cont/models/__init__.py
Normal file
0
cont/models/__init__.py
Normal file
66
cont/models/ciscoModel.py
Normal file
66
cont/models/ciscoModel.py
Normal file
@@ -0,0 +1,66 @@
|
||||
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"""
|
||||
hostname: str
|
||||
powerDrawPSU1: int
|
||||
voltagePSU1: int
|
||||
inletTemp: float
|
||||
exhaustTemp: float
|
||||
cpu1Temp: float
|
||||
uptimeS: int
|
||||
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.uptimeS} Seconds\n"
|
||||
f"Uptime {self.uptimeH} Hours\n"
|
||||
f"Uptime {self.uptimeD} Days"
|
||||
)
|
||||
7
cont/models/fanModel.py
Normal file
7
cont/models/fanModel.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional, Annotated, Dict
|
||||
|
||||
|
||||
@dataclass
|
||||
class idracFanStatus:
|
||||
fans: Dict[str, int] | None = Dict[None, None] # name/index -> rpm
|
||||
43
cont/models/idracModel.py
Normal file
43
cont/models/idracModel.py
Normal file
@@ -0,0 +1,43 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional, Annotated, Dict
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@dataclass
|
||||
class snmpPyIDRACData():
|
||||
"""Dataclass for snmp data"""
|
||||
hostname: str
|
||||
powerDrawPSU1: int
|
||||
voltagePSU1: int
|
||||
inletTemp: float
|
||||
exhaustTemp: float
|
||||
cpu1Temp: float
|
||||
uptimeS: int
|
||||
uptimeH: float
|
||||
|
||||
# optional fields
|
||||
uptimeD: float | None = None
|
||||
cpu2Temp: float | None = None
|
||||
powerDrawPSU2: int | None = None
|
||||
powerDrawBoard: 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"Board {self.powerDrawBoard} 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"
|
||||
)
|
||||
2
cont/models/snmpTimeOut.py
Normal file
2
cont/models/snmpTimeOut.py
Normal file
@@ -0,0 +1,2 @@
|
||||
class SNMPTimeoutError(Exception):
|
||||
pass
|
||||
62
cont/models/sqlTable.py
Normal file
62
cont/models/sqlTable.py
Normal file
@@ -0,0 +1,62 @@
|
||||
from sqlalchemy import Table, Column, MetaData, Integer, String, TIMESTAMP, BigInteger, Numeric, text
|
||||
|
||||
|
||||
|
||||
metadata = MetaData()
|
||||
|
||||
idracMeasurement = Table(
|
||||
"IDRACmeasurement",
|
||||
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("powerDrawPSU1", Numeric(7, 2)),
|
||||
Column("powerDrawPSU2", Numeric(7, 2)),
|
||||
Column("powerDrawBoard", Numeric(7, 2)),
|
||||
Column("voltagePSU1", Numeric(7, 2)),
|
||||
Column("voltagePSU2", Numeric(7, 2)),
|
||||
|
||||
Column("inletTemp", Numeric(5, 2)),
|
||||
Column("exhaustTemp", Numeric(5, 2)),
|
||||
Column("cpu1Temp", Numeric(5, 2)),
|
||||
Column("cpu2Temp", Numeric(5, 2)),
|
||||
|
||||
Column("uptimeS", BigInteger),
|
||||
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),
|
||||
)
|
||||
@@ -1,11 +1,14 @@
|
||||
# mysql-connector-python==9.2.0
|
||||
PyMySQL==1.1.1
|
||||
sqlmodel==0.0.24
|
||||
pydantic==2.10.6
|
||||
pydantic_core==2.27.2
|
||||
PyMySQL==1.1.2
|
||||
sqlmodel==0.0.37
|
||||
sqlalchemy[asyncio]==2.0.47
|
||||
asyncmy==0.2.11
|
||||
pydantic==2.12.5
|
||||
pydantic_core==2.41.5
|
||||
annotated-types==0.7.0
|
||||
typing==3.7.4.3
|
||||
pysnmp==7.1.22
|
||||
# requests==2.32.3
|
||||
influxdb-client==1.49.0
|
||||
cryptography==46.0.5
|
||||
# requests==2.32.5
|
||||
influxdb-client==1.50.0
|
||||
# influxdb3-python==0.18.0
|
||||
0
cont/snmp/__init__.py
Normal file
0
cont/snmp/__init__.py
Normal file
117
cont/snmp/walker.py
Normal file
117
cont/snmp/walker.py
Normal file
@@ -0,0 +1,117 @@
|
||||
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))
|
||||
|
||||
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")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Return a following object
|
||||
|
||||
# {
|
||||
# 1: "SomeObject",
|
||||
# 2: "someOtherObject"
|
||||
# }
|
||||
|
||||
# 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,
|
||||
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,
|
||||
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:
|
||||
# index is typically the last sub-identifier
|
||||
idx = int(oid.prettyPrint().split(".")[-1])
|
||||
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
|
||||
73
tables.sql
73
tables.sql
@@ -22,22 +22,75 @@ SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO';
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
-- Event for deleting rows older than 3 days
|
||||
-- Enable scheduler
|
||||
SET GLOBAL event_scheduler = ON;
|
||||
|
||||
-- Event that runs every hour and deletes old rows
|
||||
-- Delete 2,5k rows at the time to avoid long locks
|
||||
CREATE EVENT IF NOT EXISTS evPurgeOldIdracRows
|
||||
ON SCHEDULE EVERY 1 HOUR
|
||||
DO
|
||||
DELETE FROM IDRACmeasurement
|
||||
WHERE time_stamp < (NOW() - INTERVAL 3 DAY)
|
||||
LIMIT 2500;
|
||||
|
||||
|
||||
|
||||
-- New universal table type
|
||||
CREATE TABLE newUniversalSensorTable (
|
||||
CREATE TABLE IDRACmeasurement (
|
||||
id MEDIUMINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
||||
time_stamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
hostname VARCHAR(64) NOT NULL,
|
||||
powerDrawPSU1 DECIMAL(7,2),
|
||||
powerDrawPSU2 DECIMAL(7,2) NULL,
|
||||
powerDrawBoard DECIMAL(7,2) NULL, -- Thing for IDRAC9 as it has a Raw Power Consumption value
|
||||
voltagePSU1 DECIMAL(7,2),
|
||||
voltagePSU2 DECIMAL(7,2) NULL,
|
||||
inletTemp DECIMAL(5,2),
|
||||
exhaustTemp DECIMAL(5,2),
|
||||
cpu1Temp DECIMAL(5,2),
|
||||
cpu2Temp DECIMAL(5,2) NULL,
|
||||
uptimeS BIGINT,
|
||||
uptimeH DECIMAL(8,3),
|
||||
uptimeD DECIMAL(8,3) NULL,
|
||||
|
||||
INDEX idx_time (time_stamp),
|
||||
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,
|
||||
hostname TEXT(30),
|
||||
powerDrawPSU1 TINYINT(100),
|
||||
powerDrawPSU2 TINYINT(100) NULL,
|
||||
voltagePSU1 TINYINT(100),
|
||||
voltagePSU2 TINYINT(100) NULL,
|
||||
inletTemp FLOAT,
|
||||
exhaustTemp FLOAT,
|
||||
uptime INT NULL,
|
||||
pressure FLOAT NULL,
|
||||
altitude FLOAT NULL
|
||||
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
|
||||
|
||||
);
|
||||
Reference in New Issue
Block a user