Compare commits

...

6 Commits

Author SHA1 Message Date
fab9c3fafa Other insignificant tweaks 2026-02-26 19:49:46 +01:00
3092d795e7 Added local influxdb, mariadb and adminer for testing 2026-02-26 19:49:24 +01:00
29e50fe52f Tests with SNMPv1 2026-02-26 19:49:10 +01:00
8882ee5ee8 Tweaked the class that has IDRAC data 2026-02-26 19:48:56 +01:00
7a30a31a38 Moved everything to one folder 2026-02-26 17:34:00 +01:00
147dd9a3ed Added files for switch and router configuration 2026-02-26 17:13:04 +01:00
17 changed files with 379 additions and 176 deletions

4
.gitignore vendored
View File

@@ -1,2 +1,2 @@
cont/code/__pycache__ cont/__pycache__
cont/code/venv cont/venv

0
ciscoSNMPconf/lob.ios Normal file
View File

0
ciscoSNMPconf/nyater.ios Normal file
View File

View File

View File

@@ -3,16 +3,28 @@ FROM alpine:latest
# https://docs.docker.com/reference/dockerfile/#environment-replacement # https://docs.docker.com/reference/dockerfile/#environment-replacement
# ENV PUID=1600 # ENV PUID=1600
# ENV USER=itsme # ENV USER=itsme
# VOLUME [""] # VOLUME [""]
RUN apk update && \ RUN apk update && \
apk add python3 py3-pip su-exec curl && \ apk add python3 py3-pip su-exec curl
mkdir -p /app/snmpython/
RUN adduser -D -s /bin/sh -u 1600 pyusr
RUN mkdir -p /app/snmpython/ && \
chown -R 1600:1600 /app/snmpython/
USER pyusr
WORKDIR /app/snmpython/ WORKDIR /app/snmpython/
COPY ../code/someMain.py /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 ./entrypoint.sh /entrypoint.sh # COPY ./entrypoint.sh /entrypoint.sh
# RUN chmod +x /entrypoint.sh # RUN chmod +x /entrypoint.sh
@@ -22,11 +34,6 @@ COPY ../code/someMain.py /app/snmpython/
# RUN chown -R "${USER}" /app/snmpython # RUN chown -R "${USER}" /app/snmpython
COPY ./requirements.txt /app/snmpython/
RUN python3 -m venv venv && \
venv/bin/python3 -m pip install --upgrade pip && \
venv/bin/pip3 install -r requirements.txt
# venv/bin/pip3 install -r requirements.txt # venv/bin/pip3 install -r requirements.txt
# Set user. No need for root past this point # Set user. No need for root past this point
@@ -37,4 +44,4 @@ RUN python3 -m venv venv && \
# HEALTHCHECK --interval=3s --timeout=3s --retries=3 \ # HEALTHCHECK --interval=3s --timeout=3s --retries=3 \
# CMD curl --fail http://127.0.0.1:8181/health || exit 1 # CMD curl --fail http://127.0.0.1:8181/health || exit 1
CMD ["/app/snmpython/someMain.py"] CMD ["/app/snmpython/pyvenv/bin/python3", "/app/snmpython/main.py"]

View File

@@ -82,15 +82,34 @@ class snmpValueToHost():
# Dataclasses-------------------------------------------- # Dataclasses--------------------------------------------
@dataclass @dataclass
class snmpPyData(): class snmpPyIDRACData():
"""Dataclass for snmp data""" """Dataclass for snmp data"""
hostname: str hostname: str
powerDrawPSU1: int powerDrawPSU1: int
powerDrawPSU2: int
voltagePSU1: int voltagePSU1: int
voltagePSU2: int
inletTemp: float inletTemp: float
exhaustTemp: float exhaustTemp: float
uptime: int 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"{self.powerDrawPSU1}\n"
f"{self.powerDrawPSU2}\n"
f"{self.voltagePSU1}\n"
f"{self.voltagePSU2}\n"
f"{self.inletTemp}\n"
f"{self.exhaustTemp}\n"
f"{self.cpu1Temp}\n"
f"{self.cpu2Temp}\n"
f"{self.uptimeH}\n"
f"{self.uptimeD}"
)

View File

@@ -1,139 +0,0 @@
import ipaddress, os, re, time, funct, classes
#SNMP
# from easysnmp import Session
# QoL
from typing import Annotated, Final
# Program ENV---------------------------------------
HOST_LIST: Final[list] = os.getenv("HOST_LIST")
SNMPUSER: Final[str] = os.getenv("SNMPUSER", None)
SNMPPRIVKEY: Final[str] = os.getenv("SNMPPRIVKEY", None)
SNMPAUTHKEY: Final[str] = os.getenv("SNMPAUTHKEY", None)
SNMPAUTHPROTO: Final[str] = os.getenv("SNMPAUTHPROTO", "SHA")
SNMPPRIVPROTO: Final[str] = os.getenv("SNMPPRIVPROTO", "SHA")
SNMPORT: Final[int] = os.getenv("SNMPORT", 161)
# Flightchecks-------------------------------------------
if SNMPAUTHPROTO and SNMPPRIVPROTO == "SHA":
USMDATA = UsmUserData(
userName=SNMPUSER,
authKey=SNMPPRIVKEY,
privKey=SNMPAUTHKEY,
authProtocol=usmHMACSHAAuthProtocol,
privProtocol=usmHMACSHAAuthProtocol,
)
elif SNMPAUTHPROTO and SNMPPRIVPROTO == "AES128":
USMDATA = UsmUserData(
userName=SNMPUSER,
authKey=SNMPPRIVKEY,
privKey=SNMPAUTHKEY,
authProtocol=usmAesCfb128Protocol,
privProtocol=usmAesCfb128Protocol,
)
elif SNMPAUTHPROTO == "SHA" and SNMPPRIVPROTO == "AES128":
USMDATA = UsmUserData(
userName=SNMPUSER,
authKey=SNMPPRIVKEY,
privKey=SNMPAUTHKEY,
authProtocol=usmHMACSHAAuthProtocol,
privProtocol=usmAesCfb128Protocol,
)
elif SNMPAUTHPROTO == "AES128" and SNMPPRIVPROTO == "SHA":
USMDATA = UsmUserData(
userName=SNMPUSER,
authKey=SNMPPRIVKEY,
privKey=SNMPAUTHKEY,
authProtocol=usmAesCfb128Protocol,
privProtocol=usmHMACSHAAuthProtocol,
)
else:
raise Exception(f"No PrivAuth option like {SNMPPRIVPROTO}")
# Helper functions
def wattageCalc(amperageInp: float, voltageInp: float) -> float:
return amperageInp * voltageInp
# Check if some neccesary ENVs are passed
if not USEINFLUX and not USESQL:
raise Exception("No database selected to store the data")
# if HOST_LIST empty, raise Exception No hosts passed
if not HOST_LIST:
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:
try:
ip = str(ipaddress.IPv4Address(host))
except ValueError:
raise Exception(f" IP {ip} is invalid.\nExiting...")
# Done under "Program ENV" on line ~18
# Code-------------------------------------------
import asyncio
from pysnmp.hlapi.v3arch.asyncio import *
async def poolRemote(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(),
ObjectType(ObjectIdentity("SNMPv2-MIB", "sysDescr", 0)),
)
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()
# tasks = [poolRemote(ip) for ip in HOST_LIST]
# results = await asyncio.gather(*tasks)
# Create connections for MySQL and InfluxDB
# functions for inserting data into two DBs
# DNS lookup if the user passed a hostname
# if not given a specific IP for DNS server, fallback to 1.1.1.1
# maybe a class?
# store last value and check if it wasn't sent already to the database

View File

@@ -1,16 +0,0 @@
---
services:
mdfanchanger:
container_name: snmpython-dev
user: 1600:1600
image: shupotea/yuruc3/snmpython:dev
build:
dockerfile: ./Dockerfile
environment:
- INFLUXTOKEN: "12345678"
- INFLUXHOST: ""
- HOST_LIST: ["192.168.0.1", "192.168.0.1", "192.168.0.1", "192.168.0.1"]
restart: unless-stopped

View File

@@ -0,0 +1,69 @@
---
services:
snmpcollector:
container_name: snmpython-dev
user: 1600:1600
image: shupotea/yuruc3/snmpython:dev
build:
dockerfile: ./Dockerfile
environment:
- USEINFLUX=True
- INFLXDBTOKEN=67676767
- INFLUXBCKT=pyusr-DEV
- INFLUXORG=staging
- INFLXDBURL=http://influxdb:8086
- INFXLUXDB_MEASUEREMENT=dev-pycollector
- DBADDR=mariadb
- DBUSR=root
- DBPWD=67676767
- DBNAME=pyCollector
- SNMPUSER=SNMPUSR
- SNMPPRIVKEY=123
- SNMPAUTHKEY=123
- 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
# - HOST_LIST=192.168.20.7
# restart: unless-stopped
restart: no
influxdb:
image: influxdb:2.7
container_name: influxdb-test
ports:
- "8086:8086"
environment:
- DOCKER_INFLUXDB_INIT_MODE=setup
- DOCKER_INFLUXDB_INIT_USERNAME=yuru
- DOCKER_INFLUXDB_INIT_PASSWORD=67676767
- DOCKER_INFLUXDB_INIT_ORG=staging
- DOCKER_INFLUXDB_INIT_BUCKET=pyusr-DEV
- DOCKER_INFLUXDB_INIT_ADMIN_TOKEN=67676767
volumes:
- influx:/var/lib/influxdb2
restart: unless-stopped
mariadb:
container_name: uberAPI-mdb
image: mariadb:latest
restart: always
volumes:
- mdb:/var/lib/mysql
environment:
MARIADB_ROOT_PASSWORD: "67676767"
ports:
- "3306:3306"
adminer:
image: adminer
container_name: adminer
restart: always
ports:
- "8180:8080"
volumes:
influx:
mdb:

View File

@@ -2,8 +2,8 @@
set -e set -e
# Default to 1600 if not provided # Default to 1600 if not provided
PUID="${PUID:-1000}" PUID="${PUID:-1600}"
PGID="${PGID:-1000}" PGID="${PGID:-1600}"
USER="${USER:-pythusr}" USER="${USER:-pythusr}"
GROUP="${USER:-pythusr}" GROUP="${USER:-pythusr}"
CHOWNPATH="/app/snmpython" CHOWNPATH="/app/snmpython"

View File

@@ -29,6 +29,13 @@ if USESQL:
DBNAME: Final[str] = os.getenv("DBNAME", "TEMP_SENSR") 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------------------------------------------- # DBprepare-------------------------------------------
# INFLUX # INFLUX
if USEINFLUX: if USEINFLUX:
@@ -45,7 +52,6 @@ if USESQL:
Session = sessionmaker(bind=engine) Session = sessionmaker(bind=engine)
def tempsnsrIntoSQLDB( def tempsnsrIntoSQLDB(
tableInp: Annotated[int, "Name of the table"], tableInp: Annotated[int, "Name of the table"],
insertData: Annotated[str, "Data to insert"] insertData: Annotated[str, "Data to insert"]
@@ -87,7 +93,8 @@ def tempsnsrIntoSQLDB(
def tempsnsrIntoFluxQLDB( def tempsnsrIntoFluxQLDB(
inpayload: Annotated[snmpPyData, "Payload"] inIdracPayload: Annotated[snmpPyIDRACData, "Payload"] | None = None,
inCiscoPayload: Annotated[int, "yes"] | None = None
) -> int: ) -> int:
""" """

256
cont/main.py Normal file
View File

@@ -0,0 +1,256 @@
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)
# 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