First commit
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
venv/
|
||||
*.csv
|
||||
.env
|
||||
15
Dockerfile
Normal file
15
Dockerfile
Normal file
@@ -0,0 +1,15 @@
|
||||
# Init image
|
||||
FROM python:slim
|
||||
WORKDIR /app
|
||||
|
||||
# Install requirements
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
# Import app
|
||||
COPY pybeemo .
|
||||
RUN chmod +x pybeemo
|
||||
|
||||
# Run it
|
||||
EXPOSE 8000
|
||||
CMD ["./pybeemo"]
|
||||
13
compose.yaml
Normal file
13
compose.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
services:
|
||||
pybeemo:
|
||||
container_name: pybeemo
|
||||
restart: always
|
||||
image: ramiuslr/pybeemo:latest # You should set this tag to a fixed version
|
||||
ports:
|
||||
- 8000:8000
|
||||
environment:
|
||||
PYBEEMO_USER: <username>
|
||||
PYBEEMO_PASSWORD: <password>
|
||||
# PYBEEMO_INTERVAL: optional, defaults to 30 mins
|
||||
...
|
||||
209
pybeemo
Executable file
209
pybeemo
Executable file
@@ -0,0 +1,209 @@
|
||||
#!/bin/env python
|
||||
|
||||
import http.server
|
||||
import io
|
||||
import os
|
||||
import socketserver
|
||||
import sys
|
||||
import time
|
||||
from datetime import datetime
|
||||
from threading import Lock, Thread
|
||||
|
||||
import pandas as pd
|
||||
from dotenv import load_dotenv
|
||||
from requests import Session
|
||||
|
||||
# Global variables
|
||||
data_lock = Lock()
|
||||
csv_data = {"licenses": None, "backupsets": None, "groups": None}
|
||||
|
||||
|
||||
class BeemoHandler(http.server.SimpleHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
with data_lock:
|
||||
if self.path == "/licenses.csv":
|
||||
self.serve_csv(csv_data["licenses"])
|
||||
elif self.path == "/backupsets.csv":
|
||||
self.serve_csv(csv_data["backupsets"])
|
||||
elif self.path == "/groups.csv":
|
||||
self.serve_csv(csv_data["groups"])
|
||||
else:
|
||||
self.send_response(404)
|
||||
self.end_headers()
|
||||
self.wfile.write(b"File not found")
|
||||
|
||||
def serve_csv(self, data):
|
||||
if data is None:
|
||||
self.send_response(503)
|
||||
self.send_header("Content-type", "text/plain")
|
||||
self.end_headers()
|
||||
self.wfile.write(b"Service unavailable - data not yet generated")
|
||||
return
|
||||
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", "text/csv")
|
||||
self.send_header(
|
||||
"Content-Disposition", "attachment; filename=" + self.path[1:]
|
||||
)
|
||||
self.send_header("Content-Length", str(len(data)))
|
||||
self.end_headers()
|
||||
self.wfile.write(data.encode("utf-8"))
|
||||
|
||||
|
||||
def main():
|
||||
# Read parameters from env
|
||||
load_dotenv()
|
||||
|
||||
username = os.getenv("PYBEEMO_USER")
|
||||
if not username:
|
||||
print("ERROR: Please set username")
|
||||
sys.exit(1)
|
||||
|
||||
password = os.getenv("PYBEEMO_PASSWORD")
|
||||
if not password:
|
||||
print("ERROR: Please set a password")
|
||||
sys.exit(1)
|
||||
|
||||
port = 8000
|
||||
|
||||
interval = os.getenv("PYBEEMO_INTERVAL")
|
||||
if not interval:
|
||||
print("No interval provided, setting default (30)")
|
||||
interval = 30
|
||||
else:
|
||||
interval = int(interval)
|
||||
|
||||
# Init persistent session
|
||||
s = Session()
|
||||
# Login
|
||||
login(s, username, password)
|
||||
# Start data update thread
|
||||
update_thread = Thread(target=update_data, args=(s, interval), daemon=True)
|
||||
update_thread.start()
|
||||
|
||||
# Start HTTP server
|
||||
Handler = BeemoHandler
|
||||
with socketserver.TCPServer(("", port), Handler) as httpd:
|
||||
print(f"[{datetime.now()}] Running at http://localhost:{port}")
|
||||
print("Available endpoints:")
|
||||
print(f" http://localhost:{port}/licenses.csv")
|
||||
print(f" http://localhost:{port}/backupsets.csv")
|
||||
print(f" http://localhost:{port}/groups.csv")
|
||||
print(f"Data refresh interval: {interval} minutes")
|
||||
httpd.serve_forever()
|
||||
|
||||
|
||||
def login(s: Session, username: str, password: str) -> bool:
|
||||
url = "https://client.beemotechnologie.com/login_validate.php"
|
||||
data = {
|
||||
"login": username,
|
||||
"mdp": password,
|
||||
"type": "login",
|
||||
}
|
||||
r = s.post(url, data=data)
|
||||
|
||||
# Handle failed login checking response url
|
||||
if r.url == "https://client.beemotechnologie.com/login.php":
|
||||
print("Login failure, please check username and password")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# Functions used to format retrieved data
|
||||
def get_licenses(s: Session):
|
||||
url = "https://client.beemotechnologie.com/logic/export_licence.php"
|
||||
r = io.BytesIO(s.get(url).content)
|
||||
cols = [
|
||||
"License",
|
||||
"Client",
|
||||
"Storage (GB)",
|
||||
"Remote Storage Quota (GB)",
|
||||
"Disk Usage",
|
||||
"Remote status",
|
||||
]
|
||||
df = pd.read_csv(r, usecols=cols, sep=";", encoding="ISO-8859-1")
|
||||
mapping = {
|
||||
"License": "Numéro de licence",
|
||||
"Client": "Client",
|
||||
"Storage (GB)": "Volume externalisé",
|
||||
"Remote Storage Quota (GB)": "Quota",
|
||||
"Disk Usage": "Utilisation du disque local",
|
||||
"Remote status": "Etat de l'externalisation",
|
||||
}
|
||||
df.rename(columns=mapping, inplace=True)
|
||||
df["Utilisation du disque local"] = df[
|
||||
"Utilisation du disque local"
|
||||
].str.replace("Unknown", "0")
|
||||
df["Utilisation du disque local"] = df[
|
||||
"Utilisation du disque local"
|
||||
].str.replace(" %", "")
|
||||
df["Utilisation du disque local"] = (
|
||||
df["Utilisation du disque local"].str.replace(",", ".").astype(float)
|
||||
)
|
||||
df["Etat de l'externalisation"] = df[
|
||||
"Etat de l'externalisation"
|
||||
].str.replace(" %", "")
|
||||
df["Ratio"] = df["Volume externalisé"] / df["Quota"] * 100
|
||||
df["Ratio"] = df["Ratio"].round(1)
|
||||
return df.to_csv(index=False)
|
||||
|
||||
|
||||
def get_backupsets(s: Session):
|
||||
url = "https://client.beemotechnologie.com/logic/export_jds.php"
|
||||
r = io.BytesIO(s.get(url).content)
|
||||
cols = ["License", "Client", "Backupsets", "Backup Status"]
|
||||
df = pd.read_csv(r, usecols=cols, sep=";", encoding="ISO-8859-1")
|
||||
mapping = {
|
||||
"License": "Numéro de licence",
|
||||
"Client": "Client",
|
||||
"Backupsets": "Jeu de sauvegarde",
|
||||
"Backup Status": "Etat",
|
||||
}
|
||||
df.rename(columns=mapping, inplace=True)
|
||||
df.query('Etat != "Ok"', inplace=True)
|
||||
return df.to_csv(index=False)
|
||||
|
||||
|
||||
def get_groups(s: Session):
|
||||
url = "https://client.beemotechnologie.com/logic/export_groupes.php"
|
||||
r = io.BytesIO(s.get(url).content)
|
||||
cols = ["Name", "Storage (GB)", "Remote Storage Quota (GB)"]
|
||||
df = pd.read_csv(r, usecols=cols, sep=";", encoding="ISO-8859-1")
|
||||
mapping = {
|
||||
"Name": "Client",
|
||||
"Storage (GB)": "Utilisé",
|
||||
"Remote Storage Quota (GB)": "Quota",
|
||||
}
|
||||
df.rename(columns=mapping, inplace=True)
|
||||
df["Utilisé"] = df["Utilisé"].str.replace(",", ".").astype(float)
|
||||
df["Ratio"] = df["Utilisé"] / df["Quota"] * 100
|
||||
df["Ratio"] = df["Ratio"].round(1)
|
||||
return df.to_csv(index=False)
|
||||
|
||||
|
||||
def update_data(s: Session, interval):
|
||||
while True:
|
||||
print(f"[{datetime.now()}] Updating data...")
|
||||
|
||||
# Update licenses
|
||||
data = get_licenses(s)
|
||||
with data_lock:
|
||||
csv_data["licenses"] = data
|
||||
print(f"[{datetime.now()}] Updated licenses.csv in memory")
|
||||
|
||||
# Update licenses
|
||||
data = get_backupsets(s)
|
||||
with data_lock:
|
||||
csv_data["backupsets"] = data
|
||||
print(f"[{datetime.now()}] Updated backupsets.csv in memory")
|
||||
|
||||
# Update groups
|
||||
data = get_groups(s)
|
||||
with data_lock:
|
||||
csv_data["groups"] = data
|
||||
print(f"[{datetime.now()}] Updated groups.csv in memory")
|
||||
|
||||
# Wait time interval before updating again
|
||||
time.sleep(interval * 60)
|
||||
|
||||
|
||||
main()
|
||||
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
pandas
|
||||
requests
|
||||
dotenv
|
||||
Reference in New Issue
Block a user