Big init
This commit is contained in:
75
cont/code/classes.py
Normal file
75
cont/code/classes.py
Normal file
@@ -0,0 +1,75 @@
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy import Column, Date, Float, Integer, String, text
|
||||
from datetime import datetime, timezone, timedelta
|
||||
from typing import Optional, Annotated
|
||||
from sqlalchemy.dialects.mysql import MEDIUMINT, TINYINT, TEXT, TIMESTAMP, FLOAT
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
|
||||
# -----------
|
||||
|
||||
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"] = time.time(),
|
||||
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 # The time since the Epoch of the last sent data*
|
||||
|
||||
|
||||
def ___str__():
|
||||
return self.__lastValue
|
||||
|
||||
def __changeLastSentValue(slef):
|
||||
self.__lastValue = self.__nextValue
|
||||
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"]):
|
||||
|
||||
...
|
||||
123
cont/code/funct.py
Normal file
123
cont/code/funct.py
Normal file
@@ -0,0 +1,123 @@
|
||||
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 typing import Annotated, Final
|
||||
from classes import *
|
||||
|
||||
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")
|
||||
|
||||
|
||||
# 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:
|
||||
|
||||
data = sensorsqldata(tableInp)
|
||||
# print("2")
|
||||
|
||||
if inpayload:
|
||||
# print("3")
|
||||
session.add(data(
|
||||
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(
|
||||
inpayload: Annotated[SensorPayload, "Payload"]
|
||||
) -> 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
|
||||
68
cont/code/main.py
Normal file
68
cont/code/main.py
Normal file
@@ -0,0 +1,68 @@
|
||||
# import pysnmp, sqlalchemy, ipaddress, os, influxdb_client, re, time
|
||||
# # SQL
|
||||
# from sqlalchemy import create_engine, exc # , Column, Integer, String, Numeric
|
||||
# from sqlalchemy.ext.declarative import declarative_base
|
||||
# from sqlalchemy.orm import sessionmaker
|
||||
# # InfluxDB
|
||||
# from influxdb_client import InfluxDBClient, Point, WritePrecision
|
||||
# from influxdb_client.client.write_api import SYNCHRONOUS, ASYNCHRONOUS, WriteOptions
|
||||
import pysnmp, ipaddress, os, re, time
|
||||
#SNMP
|
||||
from easysnmp import Session
|
||||
# QoL
|
||||
from typing import Annotated
|
||||
|
||||
|
||||
# Program ENV---------------------------------------
|
||||
HOST_LIST: Final[list] = os.getenv("HOST_LIST")
|
||||
try:
|
||||
RESOLV_ADDR: Final[str] = ipaddress(os.getenv("RESOLV_ADDR", "1.1.1.1"))
|
||||
except ValueError:
|
||||
raise Exception("Malformed DNS IP address.\nExiting...")
|
||||
|
||||
|
||||
# Flightchecks-------------------------------------------
|
||||
# Helper functions
|
||||
def check_host_string(input_text: Annotated[str, "Text to check"]):
|
||||
pattern = re.compile(r"^[A-Za-z].*$", re.IGNORECASE)
|
||||
return pattern.match(input_text)
|
||||
|
||||
|
||||
# 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
|
||||
HOST_LIST_STR = []
|
||||
for host in HOST_LIST:
|
||||
try:
|
||||
if not check_host_string(host):
|
||||
ip = str(ipaddress.IPv4Address(host))
|
||||
HOST_LIST_STR.append(ip)
|
||||
except ValueError:
|
||||
raise Exception("Malformed IP address.\nExiting...")
|
||||
|
||||
# Checking if DNS IP is a valid one
|
||||
# Done under "Program ENV" on line ~18
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Code-------------------------------------------
|
||||
|
||||
# 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
|
||||
40
cont/conf/Dockerfile
Normal file
40
cont/conf/Dockerfile
Normal file
@@ -0,0 +1,40 @@
|
||||
FROM alpine:latest
|
||||
|
||||
# https://docs.docker.com/reference/dockerfile/#environment-replacement
|
||||
# ENV PUID=1600
|
||||
# ENV USER=itsme
|
||||
|
||||
# VOLUME [""]
|
||||
|
||||
RUN apk update && \
|
||||
apk add python3 py3-pip su-exec curl && \
|
||||
mkdir -p /app/snmpython/
|
||||
|
||||
WORKDIR /app/snmpython/
|
||||
|
||||
COPY ../code/someMain.py /app/snmpython/
|
||||
|
||||
# COPY ./entrypoint.sh /entrypoint.sh
|
||||
# RUN chmod +x /entrypoint.sh
|
||||
|
||||
# Add user to run under
|
||||
# RUN adduser --disabled-password -u "${PUID}" "${USER}"
|
||||
# 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
|
||||
|
||||
# Set user. No need for root past this point
|
||||
# USER "${USER}"
|
||||
|
||||
# ENTRYPOINT ["/entrypoint.sh"]
|
||||
|
||||
# HEALTHCHECK --interval=3s --timeout=3s --retries=3 \
|
||||
# CMD curl --fail http://127.0.0.1:8181/health || exit 1
|
||||
|
||||
CMD ["/app/snmpython/someMain.py"]
|
||||
3
cont/conf/build.sh
Executable file
3
cont/conf/build.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
docker buildx build --platform linux/amd64 --tag tea.shupogaki.org/yuruc3/snmpython:v0 --debug --push .
|
||||
16
cont/conf/docker-compose.dev.yaml
Normal file
16
cont/conf/docker-compose.dev.yaml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
|
||||
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
|
||||
25
cont/conf/entrypoint.sh
Normal file
25
cont/conf/entrypoint.sh
Normal file
@@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
# Default to 1600 if not provided
|
||||
PUID="${PUID:-1000}"
|
||||
PGID="${PGID:-1000}"
|
||||
USER="${USER:-pythusr}"
|
||||
GROUP="${USER:-pythusr}"
|
||||
CHOWNPATH="/app/snmpython"
|
||||
|
||||
# Create group if missing
|
||||
if ! getent group "$GROUP" >/dev/null 2>&1; then
|
||||
addgroup -g "$PGID" "$GROUP"
|
||||
fi
|
||||
|
||||
# Create user if missing
|
||||
if ! id -u "$USER" >/dev/null 2>&1; then
|
||||
adduser -D -u "$PUID" -G "$GROUP" "$USER"
|
||||
fi
|
||||
|
||||
# Fix permissions (only do this on /app/API)
|
||||
chown -R "$PUID:$PGID" "$CHOWNPATH"
|
||||
|
||||
# Drop privileges & run command
|
||||
exec su-exec "$PUID:$PGID" "$@"
|
||||
12
cont/conf/requirements.txt
Normal file
12
cont/conf/requirements.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
# mysql-connector-python==9.2.0
|
||||
PyMySQL==1.1.1
|
||||
sqlmodel==0.0.24
|
||||
pydantic==2.10.6
|
||||
pydantic_core==2.27.2
|
||||
annotated-types==0.7.0
|
||||
typing==3.7.4.3
|
||||
pysnmp==7.1.22
|
||||
|
||||
# requests==2.32.3
|
||||
influxdb-client==1.49.0
|
||||
# influxdb3-python==0.18.0
|
||||
Reference in New Issue
Block a user