init
This commit is contained in:
parent
dcb1307bb5
commit
1cdcd0581c
26
README.md
Normal file
26
README.md
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# Homelab Watchdog
|
||||
|
||||
Überwacht Server, Container und Netzwerkgeräte im Homelab.
|
||||
Eine Liste von Hosts wird zyklisch geprüft, nicht erreichbare
|
||||
dienste werden rot markiert und in MariaDB geloggt.
|
||||
|
||||
## Architektur: Hybrid Python + Rust
|
||||
|
||||
Nach Evaluation wurde eine hybride Architektur gewählt, um
|
||||
die steile Lernkurve von Rust (async, TUI, DB-Handling) zu
|
||||
vermeiden und trotzdem Rust zu lernen.
|
||||
|
||||
| Layer | Sprache | Aufgabe |
|
||||
|-------|---------|---------|
|
||||
| **Manager** | Python | TUI (`textual`/`rich`), Timer, Config, MariaDB, ruft Worker auf |
|
||||
| **Worker** | Rust | Kleine, synchron CLI-Binaries (z.B. `ping_worker`). IP als Arg, JSON auf stdout. |
|
||||
| **Datenbank** | MariaDB | Zentrale Wahrheit für Status, Fehler, Zeitstempel |
|
||||
|
||||
### Datenfluss
|
||||
1. Python Manager liest Host-Liste (JSON/DB).
|
||||
2. Alle X Minuten: `subprocess.run(["./ping_worker", "<ip>"])` pro Host.
|
||||
3. Rust Worker pingt synchron, gibt `{"address":"...","reachable":true,"rtt_ms":12}` aus.
|
||||
4. Python parst JSON, schreibt in MariaDB, aktualisiert TUI.
|
||||
|
||||
## Projektstruktur (geplant)
|
||||
|
||||
16
src/host.rs
16
src/host.rs
|
|
@ -11,4 +11,20 @@ pub(crate) struct Hosts {
|
|||
pub(crate) address: String,
|
||||
pub(crate) last_checked: Option<tokio::time::Instant>,
|
||||
pub(crate) state_since: tokio::time::Instant,
|
||||
}
|
||||
|
||||
pub(crate) fn generate_gen_hosts() {
|
||||
let google = Hosts {
|
||||
name:String::from("Google"),
|
||||
state: HostState::Offline,
|
||||
address:String :: from("8.8.8.8"),
|
||||
last_checked: None,
|
||||
state_since: tokio::time::Instant::now(),
|
||||
};
|
||||
let router = Hosts {
|
||||
name:String::from("Unify Router"),
|
||||
state: HostState::Offline,
|
||||
address:String :: from("192.168.0.1"),
|
||||
last_checked: None,
|
||||
state_since: tokio::time::Instant::now(),};
|
||||
}
|
||||
41
src/main.rs
41
src/main.rs
|
|
@ -1,38 +1,25 @@
|
|||
mod host;
|
||||
|
||||
use tokio::time::{sleep, Duration};
|
||||
use host::{Hosts, HostState};
|
||||
use host::{Hosts, HostState, generate_gen_hosts};
|
||||
use tokio::process::Command;
|
||||
|
||||
async fn example() {
|
||||
let time =5;
|
||||
println!("Time .. On");
|
||||
sleep(Duration::from_secs(time)).await;
|
||||
async fn ping_once(host: &Hosts) -> String {
|
||||
let output = Command::new("ping")
|
||||
.args(["-c", "1", &host.address])
|
||||
.output()
|
||||
.await;
|
||||
|
||||
// Transform bytes from output to string
|
||||
let text_output = String::from_utf8_lossy(&output.output()).to_string();
|
||||
|
||||
return text_output
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
let google = Hosts {
|
||||
name:String::from("Google"),
|
||||
state: HostState::Offline,
|
||||
address:String :: from("8.8.8.8"),
|
||||
last_checked: None,
|
||||
state_since: tokio::time::Instant::now(),
|
||||
};
|
||||
let router = Hosts {
|
||||
name:String::from("Unify Router"),
|
||||
state: HostState::Offline,
|
||||
address:String :: from("192.168.0.1"),
|
||||
last_checked: None,
|
||||
state_since: tokio::time::Instant::now(),
|
||||
};
|
||||
let pve1 = Hosts {
|
||||
name:String::from("pve Server 1"),
|
||||
state: HostState::Offline,
|
||||
address:String :: from("192.168.0.231"),
|
||||
last_checked: None,
|
||||
state_since: tokio::time::Instant::now(),
|
||||
};
|
||||
let list = vec![google, router, pve1];
|
||||
generate_gen_hosts();
|
||||
let list = vec![host.google, host.router];
|
||||
println!("{:?}", list);
|
||||
|
||||
example().await;
|
||||
|
|
|
|||
65
system_compress.txt
Normal file
65
system_compress.txt
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
=== KONTEXT KOMPENDIUM ===
|
||||
Nutzer: Daniel, SPS/Industrie-Hintergrund, KOP/SCL, Python, C#, JS, Rust-Anfänger.
|
||||
Stil: Step-by-Step, max 1-2 Schritte pro Antwort. Erklärungen mit SPS-Analogien.
|
||||
Kein fertiger Code als Lösung, nur Mini-Hinweise/Puzzleteile.
|
||||
Nutzer darf selbst puzzeln. Bei Frage "Lösung bitte" -> Lösung geben.
|
||||
|
||||
=== ARCHITEKTUR (Hybrid) ===
|
||||
Manager: Python (TUI, Timer, MariaDB, Config).
|
||||
Worker: Rust (sync CLI, single-purpose, JSON stdout).
|
||||
Kommunikation: subprocess.run(["./binary", "<ip>"], capture_output=True).
|
||||
KEIN async/TUI in Rust. KEIN PyO3/maturin. KEINE Rust-DLLs für Python.
|
||||
|
||||
=== AKTUELLES PROJEKT: ping_worker ===
|
||||
Separates Cargo-Projekt.
|
||||
Aufgabe: IP aus args -> ping -> JSON stdout.
|
||||
Status: Projekt neu, Cargo.toml steht, src/main.rs leer/Grundgerüst.
|
||||
Nächster Schritt: Station 1: env::args() parsen, IP ausgeben, Usage bei fehlendem Arg.
|
||||
|
||||
=== TECH STACK (ping_worker) ===
|
||||
[package] edition="2021" oder "2024" (Nutzer hat 2024, stable seit 1.85)
|
||||
[dependencies]
|
||||
serde = { version="1", features=["derive"] }
|
||||
serde_json = "1"
|
||||
KEIN tokio. KEIN anyhow. KEIN ratatui. KEIN crossterm.
|
||||
|
||||
=== WISSENSSTAND NUTZER (Rust) ===
|
||||
- Cargo.toml: dependencies, features (hat tokio full gemeistert).
|
||||
- struct, enum, Vec, #[derive(Debug)], Option<T>.
|
||||
- std::process::Command (Output, .status.success(), .stdout als Vec<u8>).
|
||||
- String::from_utf8_lossy -> Cow -> .to_string().
|
||||
- match / if let / ? Operator (Theorie, teilweise Praxis).
|
||||
- tokio::time::Instant (gelöscht aus aktuellem Scope).
|
||||
- env::args() (neu, aktuelle Station).
|
||||
- sync vs async Unterschied bekannt (blockierend vs Scheduler).
|
||||
|
||||
=== OFFENE PUNKTE / LEHRPLAN ===
|
||||
1. ping_worker: args parsen.
|
||||
2. ping_worker: Command::new("ping").args([...]).output() (sync!).
|
||||
3. ping_worker: Struct mit Serialize, JSON stdout.
|
||||
4. Python Manager: pymysql, textual/rich, Timer-Loop.
|
||||
5. MariaDB Schema: host_status (id, name, address, reachable, checked_at, error_msg).
|
||||
6. Integration Python <-> Rust.
|
||||
|
||||
=== DOs & DONTs ===
|
||||
DO: Kleine Schritte. DO: SPS-Analogien (DB=Vec/Struct, OB1=main loop, Baugruppe=Crate).
|
||||
DO: Einfache Vokabeln erklären (Ownership, Borrow, Lifetime, Result).
|
||||
DO: Bei Fehlermeldungen: Fehler 1,2,3 klar trennen, nicht alles auf einmal.
|
||||
DONT: Keine 5 Schritte auf einmal generieren.
|
||||
DONT: Kein komplexes async/await/TUI für diesen Worker.
|
||||
DONT: Kein "das ist einfach" sagen. Ehrlich über Rust-Steilheit.
|
||||
DONT: Kein globaler State in Rust (static/Mutex) für diesen Worker.
|
||||
|
||||
=== DATEISTRUKTUR (aktuell) ===
|
||||
homelab-watchdog/
|
||||
├── HomelabWatchdog/ (altes Projekt, mit tokio/ratatui, ruht)
|
||||
└── ping_worker/ (aktiv)
|
||||
├── Cargo.toml
|
||||
├── src/main.rs
|
||||
├── ai_chat_help.txt
|
||||
└── README.md
|
||||
|
||||
=== VERSIONS-HINWEISSE ===
|
||||
Rust Edition 2024 ist stable (Rust >= 1.85).
|
||||
tokio features = ["full"] nur wenn tokio verwendet wird (nicht hier).
|
||||
serde features = ["derive"] zwingend für #[derive(Serialize)].
|
||||
Loading…
Reference in New Issue
Block a user