pulido de argos, coredns y guacamole
This commit is contained in:
@@ -1,87 +0,0 @@
|
|||||||
apiVersion: v1
|
|
||||||
kind: ConfigMap
|
|
||||||
metadata:
|
|
||||||
name: argos-panel-config
|
|
||||||
namespace: argos-core
|
|
||||||
data:
|
|
||||||
app.py: |
|
|
||||||
import os, sqlite3, time
|
|
||||||
from fastapi import FastAPI, HTTPException
|
|
||||||
from fastapi.responses import HTMLResponse
|
|
||||||
from minio import Minio
|
|
||||||
from urllib.parse import urlparse
|
|
||||||
|
|
||||||
DB="/data/argos.db"
|
|
||||||
mc=Minio(os.getenv("MINIO_ENDPOINT","s3.argos.interna"),
|
|
||||||
access_key=os.getenv("MINIO_ACCESS_KEY"),
|
|
||||||
secret_key=os.getenv("MINIO_SECRET_KEY"),
|
|
||||||
secure=os.getenv("MINIO_SECURE","false").lower()=="true")
|
|
||||||
app=FastAPI()
|
|
||||||
|
|
||||||
def rows(limit=100, camera=None, since=None):
|
|
||||||
q="SELECT id, ts, edge, camera, label, s3url, thumb_s3 FROM events"
|
|
||||||
cond=[]; args=[]
|
|
||||||
if camera: cond.append("camera=?"); args.append(camera)
|
|
||||||
if since: cond.append("ts>=?"); args.append(int(since))
|
|
||||||
if cond: q+=" WHERE "+ " AND ".join(cond)
|
|
||||||
q+=" ORDER BY ts DESC LIMIT ?"; args.append(limit)
|
|
||||||
con=sqlite3.connect(DB); cur=con.cursor()
|
|
||||||
cur.execute(q, tuple(args)); r=cur.fetchall(); con.close()
|
|
||||||
return r
|
|
||||||
|
|
||||||
@app.get("/api/events")
|
|
||||||
def api_events(limit:int=100, camera:str=None, since:int=None):
|
|
||||||
return [dict(id=i, ts=t, edge=e, camera=c, label=l or "", s3url=s, thumb=th or "")
|
|
||||||
for (i,t,e,c,l,s,th) in rows(limit,camera,since)]
|
|
||||||
|
|
||||||
@app.get("/api/url/{event_id}")
|
|
||||||
def presign(event_id: str, expires: int = 600):
|
|
||||||
con=sqlite3.connect(DB); cur=con.cursor()
|
|
||||||
cur.execute("SELECT s3url FROM events WHERE id=?", (event_id,))
|
|
||||||
row=cur.fetchone(); con.close()
|
|
||||||
if not row: raise HTTPException(404, "Not found")
|
|
||||||
s3url=row[0]; p=urlparse(s3url); b=p.netloc; k=p.path.lstrip("/")
|
|
||||||
return {"url": mc.presigned_get_object(b, k, expires=expires)}
|
|
||||||
|
|
||||||
@app.get("/", response_class=HTMLResponse)
|
|
||||||
def index():
|
|
||||||
return """
|
|
||||||
<!doctype html><meta charset="utf-8"><title>ARGOS Panel</title>
|
|
||||||
<style>body{font-family:system-ui;margin:1.5rem} .grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px}
|
|
||||||
.card{border:1px solid #ddd;border-radius:10px;padding:10px} img{width:100%;height:160px;object-fit:cover;border-radius:8px}
|
|
||||||
button{padding:.4rem .6rem;margin-right:.3rem}</style>
|
|
||||||
<h1>ARGOS – Alarmas</h1>
|
|
||||||
<div class="grid" id="grid"></div>
|
|
||||||
<div style="margin-top:1rem"><video id="player" width="960" controls></video></div>
|
|
||||||
<script>
|
|
||||||
const fmt=t=>new Date(t*1000).toLocaleString();
|
|
||||||
async function load(){
|
|
||||||
const r=await fetch('/api/events?limit=100'); const data=await r.json();
|
|
||||||
const g=document.getElementById('grid'); g.innerHTML='';
|
|
||||||
for(const ev of data){
|
|
||||||
const d=document.createElement('div'); d.className='card';
|
|
||||||
const img = ev.thumb ? `<img src="${ev.thumb.replace('s3://','/api/url/THUMB?key=')}" alt="thumb">` : '';
|
|
||||||
d.innerHTML = `${img}<div><b>${ev.camera}</b> — ${fmt(ev.ts)}<br>${ev.label||''}</div>
|
|
||||||
<div style="margin-top:.4rem">
|
|
||||||
<button data-id="${ev.id}" data-action="clip">Ver clip</button>
|
|
||||||
<button data-path="${ev.camera}" data-action="live">En directo</button>
|
|
||||||
</div>`;
|
|
||||||
g.appendChild(d);
|
|
||||||
}
|
|
||||||
g.onclick=async (e)=>{
|
|
||||||
if(e.target.tagName!=='BUTTON') return;
|
|
||||||
const v=document.getElementById('player');
|
|
||||||
if(e.target.dataset.action==='clip'){
|
|
||||||
const id=e.target.dataset.id;
|
|
||||||
const j=await (await fetch('/api/url/'+id)).json();
|
|
||||||
v.src=j.url; v.play();
|
|
||||||
}else if(e.target.dataset.action==='live'){
|
|
||||||
const path=e.target.dataset.path;
|
|
||||||
// usa MediaMTX web player
|
|
||||||
window.open('http://mediamtx.argos.interna/?path='+encodeURIComponent(path),'_blank');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
load(); setInterval(load,10000);
|
|
||||||
</script>
|
|
||||||
"""
|
|
||||||
@@ -13,7 +13,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: mosquitto
|
- name: mosquitto
|
||||||
image: eclipse-mosquitto:2
|
image: eclipse-mosquitto:latest
|
||||||
ports:
|
ports:
|
||||||
- containerPort: 1883
|
- containerPort: 1883
|
||||||
volumeMounts:
|
volumeMounts:
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ spec:
|
|||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: panel
|
- name: panel
|
||||||
image: python:3.13.7-slim-bookworm
|
image: harbor.c2et.net/library/python:3.13.7-slim-bookworm
|
||||||
command: ["/bin/sh","-c"]
|
command: ["/bin/sh","-c"]
|
||||||
args:
|
args:
|
||||||
- |
|
- |
|
||||||
|
|||||||
0
argos/kubectl
Normal file
0
argos/kubectl
Normal file
@@ -33,6 +33,9 @@ data:
|
|||||||
192.168.0.100 admin.powervault1.c2et.net
|
192.168.0.100 admin.powervault1.c2et.net
|
||||||
192.168.0.100 admin.powervault2.c2et.net
|
192.168.0.100 admin.powervault2.c2et.net
|
||||||
192.168.0.100 ceph.c2et.net
|
192.168.0.100 ceph.c2et.net
|
||||||
|
192.168.0.100 heimdall.c2et.net
|
||||||
|
|
||||||
|
|
||||||
fallthrough
|
fallthrough
|
||||||
}
|
}
|
||||||
forward . /etc/resolv.conf
|
forward . /etc/resolv.conf
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ spec:
|
|||||||
volumeMounts:
|
volumeMounts:
|
||||||
- name: mysql-storage
|
- name: mysql-storage
|
||||||
mountPath: /var/lib/mysql
|
mountPath: /var/lib/mysql
|
||||||
|
subPath: data
|
||||||
volumes:
|
volumes:
|
||||||
- name: mysql-storage
|
- name: mysql-storage
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
|
|||||||
Reference in New Issue
Block a user