Document full architecture, design, API, features, deployment, and security.
Adds diagrams and expands the ATC demo path so the cockpit is fully described in-repo.
This commit is contained in:
@@ -1,11 +1,27 @@
|
||||
# OME Cockpit — demo path
|
||||
# OME Cockpit — ATC demo path
|
||||
|
||||
URL: http://atc-portal01.dell-atc.lan:3090
|
||||
**URL:** http://atc-portal01.dell-atc.lan:3090
|
||||
**AI companion:** http://atc-portal01.dell-atc.lan:3080 (OpenManage AI)
|
||||
|
||||
1. Watch live pulse lines from OME hub to connected iDRACs/servers
|
||||
2. Filter a subnet (10.0.40 / 10.0.41) in the left rail
|
||||
3. Click a glowing node → inspector (IP, model, service tag, power)
|
||||
4. Click **OpenManage AI** → chat drawer with OME Copilot
|
||||
5. Use **Connected only** to focus the live fabric
|
||||
## 5-minute walkthrough
|
||||
|
||||
OpenManage AI standalone remains at :3080
|
||||
1. **Topology** — Watch pulse lines from OME hub to connected nodes; try Orbit → Galaxy → Clusters.
|
||||
2. **KPI popup** — Click **Offline** or **Live power**; search a host; use **Focus on map** / **SSH terminal**.
|
||||
3. **Filters** — Enable **Connected only**; confirm empty-map behavior if Servers+iDRACs both off; **Reset filters**.
|
||||
4. **Inspector** — Select a connected node → **Load full inventory + app landscape** (firmware/software).
|
||||
5. **SSH** — Quick Connect → SSH terminal → log in with **your** username (not root).
|
||||
6. **Chat** — Cockpit chat → pick `llama3-70b-gptq` or `OME Copilot` → “List critical alerts with IP”.
|
||||
7. **Ops desk** — Create a ticket as Jody, accept as Laurens.
|
||||
8. **New node story** — When OME gains a device after cockpit baseline, a toast/card appears.
|
||||
|
||||
## Talking points
|
||||
|
||||
- Single pane for OME fleet + GPU + LLM + remote shell
|
||||
- Context stays live via WebSocket snapshots (~12–15s OME poll, ~2s GPU)
|
||||
- Design is Dell-branded mission control, not a spreadsheet
|
||||
|
||||
## Related docs
|
||||
|
||||
- [ARCHITECTURE.md](docs/ARCHITECTURE.md)
|
||||
- [DESIGN.md](docs/DESIGN.md)
|
||||
- [FEATURES.md](docs/FEATURES.md)
|
||||
|
||||
@@ -1,23 +1,94 @@
|
||||
# Dell OpenManage Cockpit (ATC)
|
||||
|
||||
Interactive fleet operations UI for Dell OpenManage Enterprise.
|
||||
Interactive operations cockpit for **Dell OpenManage Enterprise** in the Dell ATC lab.
|
||||
|
||||
## Features
|
||||
- Live topology (Orbit / Galaxy / Clusters / Lanes / Helix)
|
||||
- KPI context popups, triage, ops desk tickets
|
||||
- In-browser SSH terminal (own username/password)
|
||||
- Cockpit chat against vLLM / OpenManage AI models
|
||||
- Full inventory + application/firmware landscape from OME
|
||||
**Live URL (lab):** http://atc-portal01.dell-atc.lan:3090
|
||||
**Forgejo:** http://atc-mgt01.dell-atc.lan:3001/mo/ome-cockpit
|
||||
**Companion AI stack:** http://atc-mgt01.dell-atc.lan:3001/mo/openmanage-ai · http://atc-portal01.dell-atc.lan:3080
|
||||
|
||||
---
|
||||
|
||||
## What it is
|
||||
|
||||
A single-pane ops UI for ATC admins (Jody van Dongen, Laurens Rammers, Mohamed El Kadi) that:
|
||||
|
||||
- Polls OME for devices, power, alerts, and groups
|
||||
- Renders a live topology with multiple layouts and color modes
|
||||
- Surfaces KPI context popups, realtime triage, and an ops ticket desk
|
||||
- Embeds an in-browser SSH terminal (user-chosen credentials)
|
||||
- Chats against vLLM / OpenManage AI models with a live fleet context pack
|
||||
- Loads full OME inventory + firmware/software landscape per device
|
||||
|
||||
---
|
||||
|
||||
## Documentation map
|
||||
|
||||
| Doc | Contents |
|
||||
|-----|----------|
|
||||
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | System context, components, data flows, protocols |
|
||||
| [docs/DESIGN.md](docs/DESIGN.md) | Visual language, layout, interaction design |
|
||||
| [docs/API.md](docs/API.md) | HTTP + WebSocket API reference |
|
||||
| [docs/FEATURES.md](docs/FEATURES.md) | Feature catalog (UI + backend behaviors) |
|
||||
| [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md) | Install, env, ports, ops, troubleshooting |
|
||||
| [docs/SECURITY.md](docs/SECURITY.md) | Secrets, SSH allowlist, multi-user limits |
|
||||
| [DEMO.md](DEMO.md) | Short demo script for ATC walkthroughs |
|
||||
|
||||
---
|
||||
|
||||
## Quick start
|
||||
|
||||
## Run
|
||||
```bash
|
||||
cp .env.example .env # fill OME + vLLM settings
|
||||
cp .env.example .env
|
||||
# Fill OME_URL / OME_USER / OME_PASSWORD, VLLM_URL, GPU_METRICS_URL, OPENWEBUI_*
|
||||
docker compose up -d --build
|
||||
```
|
||||
|
||||
UI: `http://<host>:3090`
|
||||
Open http://localhost:3090
|
||||
|
||||
## Layout
|
||||
- `api/main.py` — FastAPI (OME poll, chat, SSH bridge, tickets)
|
||||
- `ui/` — static frontend
|
||||
- `docker-compose.yml` / `Dockerfile`
|
||||
Hot-reload: `ui/` and `api/main.py` are bind-mounted read-only into the container.
|
||||
|
||||
---
|
||||
|
||||
## Repository layout
|
||||
|
||||
```
|
||||
ome-cockpit/
|
||||
├── api/
|
||||
│ ├── main.py # FastAPI app (OME poll, WS, chat, SSH, tickets)
|
||||
│ ├── requirements.txt
|
||||
│ └── Dockerfile # (legacy/alternate; root Dockerfile is used)
|
||||
├── ui/
|
||||
│ ├── index.html # Shell + modals
|
||||
│ ├── app.js # Topology canvas, KPIs, filters, inspector
|
||||
│ ├── ops.js # Ops desk, chat drawer, triage, feed collapse
|
||||
│ ├── ssh.js # In-browser SSH client (xterm)
|
||||
│ ├── styles.css
|
||||
│ ├── vendor/xterm/ # Vendored xterm + fit addon (no CDN dependency)
|
||||
│ └── dell*.png|svg # Branding
|
||||
├── data/ # Runtime SQLite (gitignored)
|
||||
├── docker-compose.yml
|
||||
├── Dockerfile
|
||||
├── .env.example
|
||||
└── docs/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Lab topology (reference)
|
||||
|
||||
```
|
||||
┌────────────────────┐ poll/REST ┌──────────────────────────┐
|
||||
│ ome-cockpit :3090 │ ───────────────► │ cov-omeprod01 (OME 4.7) │
|
||||
│ atc-portal01 │ │ 10.0.21.104 │
|
||||
└────────┬───────────┘ └──────────────────────────┘
|
||||
│
|
||||
├─ chat/completions ──► vLLM atc-gpu-prod :8000 (llama3-70b-gptq)
|
||||
├─ /api/gpu ──────────► GPU metrics sidecar :9110
|
||||
└─ optional models ───► OpenManage AI Open WebUI :3080
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## License / ownership
|
||||
|
||||
Internal Dell ATC lab tooling. Not for public redistribution of credentials or production secrets.
|
||||
|
||||
+203
@@ -0,0 +1,203 @@
|
||||
# API reference
|
||||
|
||||
Base URL (lab): `http://atc-portal01.dell-atc.lan:3090`
|
||||
Internal container port: `8090`
|
||||
|
||||
All JSON unless noted. No auth middleware in lab build (protect at network edge).
|
||||
|
||||
---
|
||||
|
||||
## Health & fleet
|
||||
|
||||
### `GET /api/health`
|
||||
|
||||
```json
|
||||
{ "status": "ok", "updated_at": 1784252683.4, "pulse": 12 }
|
||||
```
|
||||
|
||||
### `GET /api/fleet`
|
||||
|
||||
Full in-memory snapshot:
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `ome` | Appliance name/version/url |
|
||||
| `summary` | totals, connected, offline, watts, samples |
|
||||
| `devices[]` | normalized nodes |
|
||||
| `subnets[]` | /24 aggregates |
|
||||
| `groups[]` | OME groups (names) |
|
||||
| `models[]` | server model counts |
|
||||
| `alerts[]` | recent alert feed |
|
||||
| `events[]` | fleet deltas (incl. device_new/removed) |
|
||||
| `context` | alert_severity, hottest, notifications, … |
|
||||
| `gpu` | latest GPU matrix |
|
||||
| `pulse` | monotonic refresh counter |
|
||||
| `openwebui_url` | companion AI URL |
|
||||
|
||||
### `WS /ws/fleet`
|
||||
|
||||
- On connect: immediate `{type:"snapshot", data}`
|
||||
- Then server pushes `{type:"snapshot"}` / `{type:"gpu"}` / `{type:"error"}`
|
||||
- Client may send any text ping; server mainly broadcasts
|
||||
|
||||
---
|
||||
|
||||
## Devices
|
||||
|
||||
### `GET /api/devices/{device_id}`
|
||||
|
||||
On-demand OME inventory enrichment.
|
||||
|
||||
Response highlights:
|
||||
|
||||
```json
|
||||
{
|
||||
"device": { "...fleet node..." },
|
||||
"power": { "watts": 320, "avg_watts": 300, "peak_watts": 400, "energy_kwh": 12.3 },
|
||||
"inventory_types": ["serverProcessors", "deviceSoftware", "..."],
|
||||
"inventory": { "deviceSoftware": [ /* raw OME rows */ ], "...": [] },
|
||||
"landscape": {
|
||||
"os": [],
|
||||
"software": [],
|
||||
"firmware": [],
|
||||
"drivers": [],
|
||||
"applications": [],
|
||||
"management": [],
|
||||
"licenses": []
|
||||
},
|
||||
"_ts": 1784252700.0
|
||||
}
|
||||
```
|
||||
|
||||
Cached ~300 seconds per device.
|
||||
|
||||
---
|
||||
|
||||
## GPU
|
||||
|
||||
### `GET /api/gpu`
|
||||
|
||||
Latest GPU sidecar payload (also present on fleet snapshot).
|
||||
|
||||
---
|
||||
|
||||
## Chat & models
|
||||
|
||||
### `GET /api/models`
|
||||
|
||||
```json
|
||||
{
|
||||
"default": "llama3-70b-gptq",
|
||||
"models": [
|
||||
{ "id": "llama3-70b-gptq", "name": "llama3-70b-gptq", "source": "openwebui|vllm" },
|
||||
{ "id": "ome-copilot", "name": "OME Copilot", "source": "openwebui" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### `POST /api/chat`
|
||||
|
||||
```json
|
||||
{
|
||||
"message": "List critical systems",
|
||||
"history": [{ "role": "user", "content": "..." }],
|
||||
"focus_device_id": 50374,
|
||||
"model": "llama3-70b-gptq"
|
||||
}
|
||||
```
|
||||
|
||||
Response:
|
||||
|
||||
```json
|
||||
{
|
||||
"reply": "...",
|
||||
"model": "llama3-70b-gptq",
|
||||
"backend": "vllm|openwebui",
|
||||
"gpu": {},
|
||||
"context_bytes": 4104
|
||||
}
|
||||
```
|
||||
|
||||
Errors: `502` with upstream detail (context length, auth, etc.).
|
||||
|
||||
---
|
||||
|
||||
## Tickets (Ops desk)
|
||||
|
||||
Admins (fixed lab list): `jody`, `laurens` (+ names in API).
|
||||
|
||||
| Method | Path | Purpose |
|
||||
|--------|------|---------|
|
||||
| GET | `/api/admins` | Admin directory |
|
||||
| GET | `/api/tickets` | List tickets |
|
||||
| POST | `/api/tickets` | Create |
|
||||
| GET | `/api/tickets/{id}` | Detail + messages |
|
||||
| POST | `/api/tickets/{id}/messages` | Add note |
|
||||
| PATCH | `/api/tickets/{id}` | status / assignee / priority / accepted_by |
|
||||
| DELETE | `/api/tickets/{id}` | Delete |
|
||||
|
||||
SQLite file: `$COCKPIT_DATA/ops.db` (default `/data/ops.db`).
|
||||
|
||||
---
|
||||
|
||||
## SSH
|
||||
|
||||
### `WS /ws/ssh`
|
||||
|
||||
**Message 1 (client → server):**
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "auth",
|
||||
"host": "10.0.41.50",
|
||||
"port": 22,
|
||||
"username": "jody",
|
||||
"password": "***",
|
||||
"cols": 120,
|
||||
"rows": 40,
|
||||
"term": "xterm-256color"
|
||||
}
|
||||
```
|
||||
|
||||
**Server control messages:** `{type:"status|ready|error|pong", message?: string}`
|
||||
**Thereafter:** raw terminal bytes as WebSocket text.
|
||||
|
||||
**Client control (optional JSON):**
|
||||
|
||||
```json
|
||||
{ "type": "resize", "cols": 100, "rows": 30 }
|
||||
{ "type": "ping" }
|
||||
```
|
||||
|
||||
Constraints:
|
||||
|
||||
- `host` must appear as a management IP in the current fleet snapshot
|
||||
- Max 25 concurrent bridges; max 3 per client IP
|
||||
- Idle timeout ~30 minutes
|
||||
|
||||
### `GET /api/ssh/sessions`
|
||||
|
||||
Ops visibility (no secrets):
|
||||
|
||||
```json
|
||||
{ "active": 2, "max": 25, "sessions": [{ "id": "...", "client": "10.0.10.65", "host": "10.0.41.50", "user": "jody", "age_sec": 42 }] }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Static assets
|
||||
|
||||
| Path | File |
|
||||
|------|------|
|
||||
| `/` | `ui/index.html` (no-store cache) |
|
||||
| `/app.js` `/ops.js` `/ssh.js` `/styles.css` | UI |
|
||||
| `/vendor/xterm/*` | Terminal library |
|
||||
| `/dell.png` etc. | Branding |
|
||||
|
||||
---
|
||||
|
||||
## Environment (settings)
|
||||
|
||||
Mapped via `pydantic-settings` from `.env` (see `.env.example`):
|
||||
|
||||
`OME_URL`, `OME_USER`, `OME_PASSWORD`, `POLL_INTERVAL`, `OPENWEBUI_URL`, `OPENWEBUI_EMAIL`, `OPENWEBUI_PASSWORD`, `GPU_METRICS_URL`, `VLLM_URL`, `VLLM_MODEL`, `VLLM_MAX_TOKENS`, `CHAT_SYSTEM_CHARS`, `COCKPIT_DATA`, `CORS_ORIGINS`
|
||||
@@ -0,0 +1,163 @@
|
||||
# Architecture
|
||||
|
||||
## 1. System context
|
||||
|
||||
OME Cockpit is a **BFF + SPA** running on `atc-portal01` (Docker). It does **not** embed OME; it continuously aggregates OME REST data, enriches with GPU telemetry and LLM chat, and pushes live snapshots to browsers over WebSocket.
|
||||
|
||||
### Actors
|
||||
|
||||
| Actor | Role |
|
||||
|-------|------|
|
||||
| ATC admin (browser) | Operates fleet via UI |
|
||||
| OpenManage Enterprise | Source of truth for devices/alerts/inventory |
|
||||
| vLLM (`atc-gpu-prod:8000`) | LLM inference for Cockpit chat |
|
||||
| Open WebUI (`:3080`) | Model catalog + virtual models (`ome-copilot`, `arena-model`) |
|
||||
| GPU metrics sidecar (`:9110`) | NVIDIA V100 utilization/power |
|
||||
| Target servers / iDRACs | SSH endpoints opened from the browser via cockpit bridge |
|
||||
|
||||
---
|
||||
|
||||
## 2. Runtime components
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Docker: ome-cockpit │
|
||||
│ uvicorn → FastAPI (main.py) :8090 → host :3090 │
|
||||
│ │
|
||||
│ Background tasks: │
|
||||
│ • poll_loop() ~POLL_INTERVAL (default 12–15s) │
|
||||
│ • gpu_loop() ~2s │
|
||||
│ │
|
||||
│ In-memory STATE + WebSocket fan-out │
|
||||
│ SQLite tickets → /data/ops.db │
|
||||
│ Static UI → /ui (bind-mount) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### Process model
|
||||
|
||||
- **Single uvicorn worker** (important): fleet `STATE`, WebSocket client sets, and SSH session registry are in-process memory. Do not scale to multiple workers without an external shared store.
|
||||
- UI assets and `main.py` are bind-mounted for lab hot-reload; image rebuild needed when Python dependencies change (`asyncssh`, etc.).
|
||||
|
||||
---
|
||||
|
||||
## 3. Data flows
|
||||
|
||||
### 3.1 Fleet snapshot (OME → UI)
|
||||
|
||||
1. `poll_loop` authenticates to OME `SessionService/Sessions`
|
||||
2. Fetches devices, groups, alerts (paged `$top`)
|
||||
3. For a capped set of connected servers, fetches `/Power`
|
||||
4. Normalizes into cockpit device nodes (`is_server`, `is_idrac`, subnet, watts, …)
|
||||
5. Diffs against `PREV_DEVICES` → `EVENT_FEED` (connection/power/status + **device_new** / **device_removed**)
|
||||
6. Writes `STATE`, broadcasts `{type:"snapshot", data: STATE}` to all `/ws/fleet` clients
|
||||
|
||||
Browser `app.js` applies snapshot → layout → canvas draw loop; `ops.js` updates GPU, tickets, notifications.
|
||||
|
||||
### 3.2 Device inventory (on demand)
|
||||
|
||||
`GET /api/devices/{id}`:
|
||||
|
||||
1. Resolves node from current `STATE`
|
||||
2. Opens OME session
|
||||
3. Reads `InventoryTypes` for that device and pulls each `InventoryDetails('…')`
|
||||
4. Builds normalized `landscape` (OS, firmware, drivers, applications, management, licenses)
|
||||
5. Caches in `DETAIL_CACHE` (~300s)
|
||||
|
||||
### 3.3 Chat
|
||||
|
||||
`POST /api/chat`:
|
||||
|
||||
1. Builds compact fleet system prompt (`build_fleet_context`, char-budgeted for 4096-token models)
|
||||
2. Routes:
|
||||
- `llama3-70b-gptq` (and similar) → direct vLLM `/v1/chat/completions`
|
||||
- `ome-copilot` / `arena-model` → Open WebUI `/api/chat/completions` (service login)
|
||||
3. Retries with tighter context on vLLM context-length 400 errors
|
||||
|
||||
### 3.4 SSH bridge
|
||||
|
||||
Browser `ssh.js` (xterm) → `WS /ws/ssh`:
|
||||
|
||||
1. First message: JSON `{type:"auth", host, port, username, password, cols, rows}`
|
||||
2. Server allowlists `host` against current fleet IPs only
|
||||
3. `asyncssh.connect` + interactive shell process
|
||||
4. Bidirectional pump; resize via JSON control messages
|
||||
5. Concurrency: global semaphore (25) + max 3 sessions per client IP; idle timeout 30 min
|
||||
|
||||
### 3.5 GPU telemetry
|
||||
|
||||
`gpu_loop` polls `GPU_METRICS_URL/api/gpu` every ~2s and broadcasts `{type:"gpu"}` (and embeds GPU in fleet snapshots).
|
||||
|
||||
---
|
||||
|
||||
## 4. Frontend architecture
|
||||
|
||||
| File | Responsibility |
|
||||
|------|----------------|
|
||||
| `index.html` | App chrome, rails, stage, drawers, modals (KPI, triage, connect, SSH, tickets) |
|
||||
| `app.js` | Canvas topology, camera, filters, KPIs, inspector, inventory render, KPI popup |
|
||||
| `ops.js` | Ops desk CRUD, chat drawer, triage modal, live-feed collapse/drag, GPU matrix |
|
||||
| `ssh.js` | SSH modal + xterm session lifecycle |
|
||||
| `styles.css` | Design tokens + component styles |
|
||||
| `vendor/xterm/*` | Local terminal assets (CDN-independent) |
|
||||
|
||||
### State
|
||||
|
||||
- Primary client state lives in `app.js` `state` (data, filters, camera, layoutMode, inventoryCache, …)
|
||||
- Shared bridge: `window.cockpit` and `window.cockpitSsh`
|
||||
|
||||
### Rendering
|
||||
|
||||
- Topology is an **immediate-mode canvas** (`requestAnimationFrame`), not DOM nodes for devices
|
||||
- Camera = translate + scale; layouts write target coordinates (`tx`/`ty`) with lerp for motion
|
||||
- Pulse packets on links are decorative; toggle via **Animate link pulse**
|
||||
|
||||
---
|
||||
|
||||
## 5. Persistence
|
||||
|
||||
| Store | Path | Contents |
|
||||
|-------|------|----------|
|
||||
| SQLite | `/data/ops.db` (`COCKPIT_DATA`) | Tickets + ticket_messages |
|
||||
| Browser localStorage | client | `feed_collapsed`, `feed_bottom`, `cockpit_ssh_user`, `cockpit_chat_model`, actor |
|
||||
| In-memory | process | Fleet STATE, DETAIL_CACHE, SSH_SESSIONS, EVENT_FEED |
|
||||
|
||||
---
|
||||
|
||||
## 6. External contracts
|
||||
|
||||
### OME (OpenManage Enterprise 4.7)
|
||||
|
||||
- Session auth header `X-Auth-Token`
|
||||
- Device types: server `Type == 1000`; iDRAC via `SubDeviceType == "iDRAC"`
|
||||
- Inventory via per-device `InventoryTypes` + `InventoryDetails`
|
||||
|
||||
### vLLM OpenAI-compatible API
|
||||
|
||||
- `GET /v1/models`, `POST /v1/chat/completions`
|
||||
- Lab model `llama3-70b-gptq` with **max context 4096** → prompt budgeting is mandatory
|
||||
|
||||
### Open WebUI
|
||||
|
||||
- Sign-in → Bearer token (cached ~1h)
|
||||
- `GET /api/models`, `POST /api/chat/completions`
|
||||
|
||||
---
|
||||
|
||||
## 7. Failure domains
|
||||
|
||||
| Failure | UX impact | Mitigation |
|
||||
|---------|-----------|------------|
|
||||
| OME down | Stale/empty fleet | Health + last `updated_at`; poll retries |
|
||||
| vLLM 400 context | Chat errors | Slim context + retry |
|
||||
| Open WebUI auth missing | Virtual models unavailable | Falls back to vLLM list / error message |
|
||||
| SSH to non-fleet IP | Rejected | Allowlist |
|
||||
| Multi-user SSH overload | Queue/reject | Semaphore + per-IP cap |
|
||||
| Soft inspector refresh | Inventory preserved | `softRefreshInspector` + inventory cache |
|
||||
|
||||
---
|
||||
|
||||
## 8. Related systems (out of repo)
|
||||
|
||||
- **OpenManage AI** (`mo/openmanage-ai`): Open WebUI branding + OME REST tool for demos
|
||||
- Native OME MCP at `https://ome/mcp` exists but session stickiness is unreliable in this lab — Cockpit does not depend on it
|
||||
@@ -0,0 +1,114 @@
|
||||
# Deployment
|
||||
|
||||
## Lab hosts
|
||||
|
||||
| Host | Role | Notes |
|
||||
|------|------|-------|
|
||||
| `atc-portal01` `10.0.21.49` | Runs cockpit + OpenManage AI containers | Primary deploy target |
|
||||
| `cov-omeprod01` `10.0.21.104` | OME 4.7.0 | HTTPS, lab admin account |
|
||||
| `atc-gpu-prod` `10.0.10.106` | vLLM `:8000`, GPU metrics `:9110` | Model `llama3-70b-gptq` |
|
||||
| `atc-mgt01` | Forgejo `:3001` | Source of truth for git |
|
||||
|
||||
**Paths on portal**
|
||||
|
||||
- Cockpit: `/home/lab/ome-cockpit` (symlink/convention; compose here)
|
||||
- OpenManage AI: `/home/lab/openmanage`
|
||||
|
||||
**Published ports**
|
||||
|
||||
- Cockpit UI/API: **3090 → 8090**
|
||||
- OpenManage AI: **3080**
|
||||
|
||||
---
|
||||
|
||||
## Install / upgrade
|
||||
|
||||
```bash
|
||||
cd /home/lab/ome-cockpit
|
||||
cp .env.example .env # first time
|
||||
# edit secrets
|
||||
docker compose up -d --build
|
||||
docker compose ps
|
||||
curl -sS http://127.0.0.1:3090/api/health
|
||||
```
|
||||
|
||||
Dependency changes (e.g. `asyncssh`) require **image rebuild**.
|
||||
UI/`main.py` edits apply via bind mounts; hard-refresh browsers (`Ctrl+Shift+R`). Index is served `Cache-Control: no-store`.
|
||||
|
||||
---
|
||||
|
||||
## Environment reference
|
||||
|
||||
See `.env.example`. Critical keys:
|
||||
|
||||
| Variable | Purpose |
|
||||
|----------|---------|
|
||||
| `OME_URL` | e.g. `https://cov-omeprod01.dell-atc.lan` |
|
||||
| `OME_USER` / `OME_PASSWORD` | API session |
|
||||
| `POLL_INTERVAL` | Seconds between OME polls |
|
||||
| `VLLM_URL` | e.g. `http://10.0.10.106:8000/v1` |
|
||||
| `VLLM_MODEL` | Default chat model id |
|
||||
| `VLLM_MAX_TOKENS` | Completion cap (lab ~700) |
|
||||
| `CHAT_SYSTEM_CHARS` | System prompt budget (~5500) |
|
||||
| `GPU_METRICS_URL` | e.g. `http://10.0.10.106:9110` |
|
||||
| `OPENWEBUI_URL` | Companion AI |
|
||||
| `OPENWEBUI_EMAIL` / `OPENWEBUI_PASSWORD` | Service login for model list + virtual models |
|
||||
| `COCKPIT_DATA` | SQLite directory (default `/data`) |
|
||||
|
||||
**Never commit `.env`.**
|
||||
|
||||
---
|
||||
|
||||
## Compose volumes
|
||||
|
||||
```yaml
|
||||
volumes:
|
||||
- ./ui:/ui:ro
|
||||
- ./api/main.py:/app/main.py:ro
|
||||
- ./data:/data
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Health checks
|
||||
|
||||
```bash
|
||||
curl -sS http://127.0.0.1:3090/api/health
|
||||
curl -sS http://127.0.0.1:3090/api/fleet | python3 -c "import sys,json;d=json.load(sys.stdin);print(d['summary'])"
|
||||
curl -sS http://127.0.0.1:3090/api/ssh/sessions
|
||||
docker logs ome-cockpit --tail 100
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Git workflow
|
||||
|
||||
Remote: `http://atc-mgt01.dell-atc.lan:3001/mo/ome-cockpit.git`
|
||||
|
||||
```bash
|
||||
cd /home/lab/ome-cockpit
|
||||
git status
|
||||
# commit after reviewing diffs — never stage .env / data
|
||||
git push origin main # requires Forgejo credentials/token for user mo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
| Symptom | Check |
|
||||
|---------|-------|
|
||||
| Empty topology | Filters (Servers/iDRACs), OME creds, `docker logs` |
|
||||
| Chat 400/502 | Context size; vLLM up; try Reset chat / smaller history |
|
||||
| SSH modal blank | `/vendor/xterm/xterm.min.js` 200; hard refresh |
|
||||
| SSH “not in fleet” | Device has no management IP in snapshot |
|
||||
| Inventory vanishes | Should be fixed via soft refresh; hard reload if old JS cached |
|
||||
| GPU empty | Sidecar `:9110`, firewall from portal → GPU host |
|
||||
|
||||
---
|
||||
|
||||
## Backup
|
||||
|
||||
- Code: Forgejo
|
||||
- Tickets: backup `/home/lab/ome-cockpit/data/ops.db`
|
||||
- Secrets: out-of-band password manager — not git
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
# Design
|
||||
|
||||
## 1. Product intent
|
||||
|
||||
OME Cockpit is a **mission-control surface**, not a generic admin table. The first viewport must read as one composition: brand + live fleet fabric + actionable chrome.
|
||||
|
||||
Primary users: ATC admins who need to **see**, **triage**, **connect**, and **handoff** quickly during demos and live ops.
|
||||
|
||||
---
|
||||
|
||||
## 2. Visual language
|
||||
|
||||
### Brand
|
||||
|
||||
- Dell mark (`dell.png`) is a first-class signal in the top bar and modal headers
|
||||
- Brand click returns to cockpit home (`/`), never external dell.com
|
||||
|
||||
### Palette (CSS variables in `styles.css`)
|
||||
|
||||
| Token | Role |
|
||||
|-------|------|
|
||||
| Dell blue / bright | Primary actions, brand accents |
|
||||
| Cyan | Live/connected signals, KPI values |
|
||||
| Amber | Warning / offline emphasis |
|
||||
| Red | Critical |
|
||||
| Deep navy panels | Rails, drawers, modals over dark stage |
|
||||
|
||||
### Typography
|
||||
|
||||
- **IBM Plex Sans** — UI chrome, headings
|
||||
- **IBM Plex Mono** — IPs, KPIs, telemetry, terminal-adjacent metadata
|
||||
|
||||
### Motion
|
||||
|
||||
Intentional, not decorative noise:
|
||||
|
||||
1. Link pulse packets on connected OME edges
|
||||
2. Node lerp when layouts/filters change
|
||||
3. Notification cards slide in for new devices
|
||||
|
||||
Pulse can be disabled (**Animate link pulse**) for calm viewing.
|
||||
|
||||
---
|
||||
|
||||
## 3. Spatial layout
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ TOPBAR: brand | KPI strip | Reset / OME / Ops / Chat │
|
||||
├──────────┬───────────────────────────────┬───────────────────┤
|
||||
│ LEFT │ STAGE │ RIGHT │
|
||||
│ RAIL │ ctx-bar │ INSPECTOR │
|
||||
│ viz │ canvas topology │ │
|
||||
│ filters │ live feed (dockable) │ │
|
||||
│ color │ legend / hints │ │
|
||||
│ gpu │ │ │
|
||||
│ alerts │ │ │
|
||||
│ nets… │ │ │
|
||||
├──────────┴───────────────────────────────┴───────────────────┤
|
||||
│ TICKER: OME · pulse · watts · connected · alerts · visible │
|
||||
└──────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
Drawers (chat, ops, AI iframe) slide from the right over a scrim. Modals center for connect / SSH / triage / KPI context / tickets.
|
||||
|
||||
---
|
||||
|
||||
## 4. Interaction model
|
||||
|
||||
### Everything clickable
|
||||
|
||||
| Surface | Click behavior |
|
||||
|---------|----------------|
|
||||
| KPI tiles | Open **Fleet context** popup (list + detail + actions) |
|
||||
| Topology node | Inspector; double-click → Quick Connect |
|
||||
| Alerts / feed items | Triage modal / focus device |
|
||||
| Ticker chips | Focus modes / triage |
|
||||
| SSH actions | In-app terminal login (no hardcoded `root@`) |
|
||||
|
||||
### Filters (include semantics)
|
||||
|
||||
- **Servers** / **iDRACs** are include toggles
|
||||
- **Both off ⇒ empty map** with on-canvas guidance (never silently show all)
|
||||
- **Reset filters** restores defaults (Servers on, pulse on)
|
||||
- **Reset view** re-layouts and fits camera to visible nodes
|
||||
|
||||
### Inspector inventory
|
||||
|
||||
Button **Load full inventory + app landscape** fetches OME inventory types and renders:
|
||||
|
||||
- OS, firmware landscape, software/components, management agents, licenses
|
||||
- Hardware sections (CPU, memory, disks, RAID, NIC, PSU, FRU, location, health, …)
|
||||
|
||||
Inventory is **cached per device** and survives soft fleet refreshes (`softRefreshInspector`).
|
||||
|
||||
---
|
||||
|
||||
## 5. Topology design
|
||||
|
||||
### Layouts
|
||||
|
||||
| Mode | Idea |
|
||||
|------|------|
|
||||
| Orbit | Hub + concentric subnet rings |
|
||||
| Galaxy | Spiral arms per subnet |
|
||||
| Clusters | Subnet islands around OME |
|
||||
| Lanes | Horizontal subnet highways |
|
||||
| Helix | Depth coil sorted by connectivity/power |
|
||||
|
||||
### Color modes
|
||||
|
||||
Status · Power (W) · Connection · Model · Subnet
|
||||
|
||||
### Camera
|
||||
|
||||
Pan (drag), zoom (wheel), fit (`Reset view` / auto-fit on filter & layout changes).
|
||||
|
||||
---
|
||||
|
||||
## 6. Modals & drawers (design contracts)
|
||||
|
||||
### KPI Fleet context
|
||||
|
||||
- Summary pills (counts, watts, subnets)
|
||||
- Search + sort
|
||||
- Left list / right detail
|
||||
- Actions: Focus, SSH, Quick Connect, Inventory, Chat, iDRAC Web
|
||||
- Apply / clear map filter
|
||||
|
||||
### SSH terminal
|
||||
|
||||
- Login form first (host prefilled from fleet IP, username/password user-owned)
|
||||
- Then xterm session
|
||||
- Host must be in current OME fleet allowlist
|
||||
|
||||
### Ops desk
|
||||
|
||||
- Acting-as identity (Jody / Laurens)
|
||||
- Ticket list filters, accept/assign/status/notes/delete
|
||||
|
||||
### Notifications
|
||||
|
||||
New/removed server or iDRAC → toast + stacked notify cards (click focuses device).
|
||||
|
||||
---
|
||||
|
||||
## 7. Accessibility & ops UX notes
|
||||
|
||||
- Modals use `aria-hidden` and Escape-to-close
|
||||
- Scrim closes the active overlay mode (`kpi`, `ssh`, `connect`, drawers, …)
|
||||
- Orange accent is reserved for **SSH / iDRAC connection affordances** (`.conn-link`), not general chrome
|
||||
- Index served with `Cache-Control: no-store` to reduce stale-UI issues after deploys
|
||||
|
||||
---
|
||||
|
||||
## 8. Non-goals (design)
|
||||
|
||||
- Not a full CMDB or change-management suite
|
||||
- Not a replacement for the OME HTML console (linked out)
|
||||
- Not multi-region HA UI (single lab instance)
|
||||
@@ -0,0 +1,75 @@
|
||||
# Diagrams
|
||||
|
||||
## End-to-end context
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
Admin[ATC Admin Browser]
|
||||
Cockpit[OME Cockpit :3090]
|
||||
OME[OpenManage Enterprise]
|
||||
VLLM[vLLM llama3-70b]
|
||||
GPU[GPU metrics :9110]
|
||||
OWUI[OpenManage AI :3080]
|
||||
Node[Server / iDRAC SSH]
|
||||
|
||||
Admin -->|HTTPS/HTTP + WS| Cockpit
|
||||
Cockpit -->|REST session| OME
|
||||
Cockpit -->|chat/completions| VLLM
|
||||
Cockpit -->|models + virtual chat| OWUI
|
||||
Cockpit -->|/api/gpu| GPU
|
||||
Admin -->|xterm WS /ws/ssh| Cockpit
|
||||
Cockpit -->|asyncssh| Node
|
||||
```
|
||||
|
||||
## Fleet poll sequence
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant P as poll_loop
|
||||
participant O as OME
|
||||
participant S as STATE
|
||||
participant WS as Browser WS clients
|
||||
|
||||
P->>O: Session login
|
||||
P->>O: Devices / Groups / Alerts / Power samples
|
||||
P->>P: Normalize + diff PREV_DEVICES
|
||||
P->>S: Update snapshot + events
|
||||
P->>WS: broadcast snapshot
|
||||
P->>O: Session delete
|
||||
```
|
||||
|
||||
## SSH session
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant UI as ssh.js / xterm
|
||||
participant API as /ws/ssh
|
||||
participant Target as Device SSHD
|
||||
|
||||
UI->>API: auth JSON (user/pass/host)
|
||||
API->>API: allowlist host in fleet
|
||||
API->>Target: asyncssh connect + shell
|
||||
API-->>UI: ready
|
||||
loop Terminal I/O
|
||||
UI->>API: keystrokes
|
||||
API->>Target: stdin
|
||||
Target-->>API: stdout
|
||||
API-->>UI: terminal text
|
||||
end
|
||||
```
|
||||
|
||||
## Frontend module map
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
HTML[index.html shell]
|
||||
APP[app.js topology + KPI + inspector]
|
||||
OPS[ops.js tickets + chat + triage + feed]
|
||||
SSH[ssh.js terminal]
|
||||
HTML --> APP
|
||||
HTML --> OPS
|
||||
HTML --> SSH
|
||||
APP <-->|window.cockpit| OPS
|
||||
APP --> SSH
|
||||
OPS --> SSH
|
||||
```
|
||||
@@ -0,0 +1,81 @@
|
||||
# Features
|
||||
|
||||
## Topology & visualization
|
||||
|
||||
- Layouts: Orbit, Galaxy, Clusters, Lanes, Helix
|
||||
- Color modes: Status, Power, Connection, Model, Subnet
|
||||
- Live pulse packets on connected OME links (toggleable)
|
||||
- Pan / zoom / Reset view (fit-to-fleet)
|
||||
- Hover tips; click = inspector; double-click = Quick Connect
|
||||
- Ghost offline links optional
|
||||
|
||||
## Filters & focus
|
||||
|
||||
- Include toggles: Servers, iDRACs (both off → empty map + message)
|
||||
- Connected only, Powered on, Has power reading, Min watts, Search
|
||||
- Network / model / group rails
|
||||
- Clear / Reset filters restores defaults
|
||||
- KPI **Apply as map filter** aligns map to the KPI cohort
|
||||
|
||||
## KPI fleet context popups
|
||||
|
||||
Every top KPI tile opens an interactive modal:
|
||||
|
||||
- Nodes, Servers, iDRACs, Connected, Offline, Powered on, Live power, Avg/node, Power samples
|
||||
- Summary pills, search, sort
|
||||
- Per-device actions: Focus, SSH, Quick Connect, Inventory, Chat, iDRAC Web
|
||||
|
||||
## Inspector & inventory
|
||||
|
||||
- Live identity, connection, power fields
|
||||
- Soft-refresh on fleet poll (does not wipe loaded inventory)
|
||||
- Full inventory + application/firmware landscape from OME `InventoryTypes`
|
||||
- Inventory cache per device id
|
||||
|
||||
## Live feed & notifications
|
||||
|
||||
- Collapsible / lightly draggable live feed
|
||||
- Merged events + alerts + hottest power
|
||||
- **New device / removed device** toasts + notify cards when OME inventory changes after baseline poll
|
||||
|
||||
## Triage
|
||||
|
||||
- Critical / Warning / Events / Hottest / All feed
|
||||
- Search, detail pane, jump to connect / chat / tickets
|
||||
|
||||
## Quick Connect
|
||||
|
||||
- iDRAC Web (new tab)
|
||||
- SSH terminal (in-app)
|
||||
- Ask AI / Inspector shortcuts
|
||||
- No hardcoded `ssh://root@…` links
|
||||
|
||||
## In-browser SSH
|
||||
|
||||
- Username + password login popup (username remembered locally)
|
||||
- xterm.js vendored locally
|
||||
- Fleet IP allowlist; multi-user session caps
|
||||
|
||||
## Cockpit chat
|
||||
|
||||
- Model selector (Open WebUI catalog + vLLM)
|
||||
- Fleet-aware system context (budgeted for 4096-token models)
|
||||
- Quick prompts; focus device context
|
||||
- Backends: vLLM direct or Open WebUI virtual models
|
||||
|
||||
## Ops desk
|
||||
|
||||
- Tickets for Jody / Laurens handoff
|
||||
- Create, accept, assign, status, notes, delete
|
||||
- Persisted in SQLite
|
||||
|
||||
## GPU matrix
|
||||
|
||||
- Live V100 cards from metrics sidecar
|
||||
- Shown in left rail + available to chat context
|
||||
|
||||
## Branding / chrome
|
||||
|
||||
- Dell logo → cockpit home
|
||||
- Ticker with pulse, power, alerts, visible count
|
||||
- Drawers: Chat, Ops, OpenManage AI iframe
|
||||
@@ -0,0 +1,46 @@
|
||||
# Security
|
||||
|
||||
Lab-oriented controls. This is **not** a hardened public multi-tenant SaaS.
|
||||
|
||||
## Secrets
|
||||
|
||||
| Secret | Location | Git |
|
||||
|--------|----------|-----|
|
||||
| OME password | `.env` | **Excluded** |
|
||||
| Open WebUI service password | `.env` | **Excluded** |
|
||||
| Ticket DB | `/data/ops.db` | **Excluded** |
|
||||
| SSH user passwords | Never stored server-side; transient WS auth only | N/A |
|
||||
|
||||
Use `.env.example` as a template with `CHANGE_ME` placeholders.
|
||||
|
||||
## Network exposure
|
||||
|
||||
- Cockpit has **no application auth** in the current lab build — rely on ATC network segmentation / VPN / reverse proxy if exposed beyond trusted LAN.
|
||||
- Prefer binding publish ports to trusted interfaces only in stricter environments.
|
||||
|
||||
## SSH bridge
|
||||
|
||||
- Destination host must match a **current fleet management IP**
|
||||
- Concurrency caps: 25 global, 3 per client IP
|
||||
- `known_hosts=None` for lab self-signed/changing keys — tighten for production
|
||||
- Idle timeout terminates abandoned sessions
|
||||
- Passwords are not logged; avoid verbose debug of auth payloads
|
||||
|
||||
## Chat / LLM
|
||||
|
||||
- Fleet context is sent to vLLM / Open WebUI — treat as sensitive operational data
|
||||
- Service account for Open WebUI should be least-privilege if possible
|
||||
|
||||
## Multi-user stability (related)
|
||||
|
||||
- Single worker process shares STATE safely for reads with asyncio
|
||||
- SSH sessions are isolated per WebSocket
|
||||
- OME poll uses short-lived API sessions and deletes them after fetch
|
||||
|
||||
## Recommendations for hardening (future)
|
||||
|
||||
1. Add OIDC / reverse-proxy auth in front of `:3090`
|
||||
2. Persist SSH host key policy / CA trust
|
||||
3. Audit log for SSH session start/stop (user, target, client IP)
|
||||
4. Encrypt ticket DB at rest if tickets contain sensitive notes
|
||||
5. Rotate lab service passwords regularly
|
||||
Reference in New Issue
Block a user