From 5d1a0ee72becce39e36b5dc501b2f0c38e70d27c Mon Sep 17 00:00:00 2001 From: Rushabh Gosar Date: Wed, 7 Jan 2026 16:54:39 -0800 Subject: [PATCH] Initial commit --- .gitignore | 142 + AGENTS.full.md | 4206 +++++++++++++++++ AGENTS.md | 20 + README.md | 69 + docs/llamacpp-wrapper-notes.md | 60 + .../n8n-thesis-builder-checkpoint-20260104.md | 53 + llamaCpp.Wrapper.app/Dockerfile | 16 + llamaCpp.Wrapper.app/README.md | 134 + llamaCpp.Wrapper.app/__init__.py | 1 + llamaCpp.Wrapper.app/agents_config.json | 22 + llamaCpp.Wrapper.app/agents_parser.py | 119 + llamaCpp.Wrapper.app/api_app.py | 309 ++ llamaCpp.Wrapper.app/config.py | 214 + llamaCpp.Wrapper.app/docker_logs.py | 61 + llamaCpp.Wrapper.app/download_manager.py | 141 + llamaCpp.Wrapper.app/llamacpp_client.py | 52 + llamaCpp.Wrapper.app/logging_utils.py | 13 + llamaCpp.Wrapper.app/model_registry.py | 45 + llamaCpp.Wrapper.app/openai_translate.py | 140 + llamaCpp.Wrapper.app/restart.py | 51 + llamaCpp.Wrapper.app/run.py | 35 + llamaCpp.Wrapper.app/stream_transform.py | 102 + llamaCpp.Wrapper.app/truenas_middleware.py | 313 ++ llamaCpp.Wrapper.app/ui_app.py | 357 ++ llamaCpp.Wrapper.app/ui_static/app.js | 306 ++ llamaCpp.Wrapper.app/ui_static/index.html | 151 + llamaCpp.Wrapper.app/ui_static/styles.css | 337 ++ llamaCpp.Wrapper.app/warmup.py | 74 + llamacpp_remote_test.ps1 | 464 ++ llamacpp_set_command.ps1 | 117 + modelfiles/options-json-deepseek14b.Modelfile | 14 + modelfiles/options-json-llama31-70b.Modelfile | 14 + modelfiles/options-json-phi3mini.Modelfile | 14 + ollama_remote_test.ps1 | 561 +++ prompt_crwv.txt | 155 + query.sql | 1 + requirements.txt | 8 + scripts/deploy_truenas_wrapper.py | 116 + scripts/remote_wrapper_test.py | 162 + scripts/update_llamacpp_flags.ps1 | 29 + tests/conftest.py | 61 + tests/test_chat_completions.py | 77 + tests/test_embeddings.py | 14 + tests/test_models.py | 24 + tests/test_proxy.py | 12 + tests/test_remote_wrapper.py | 283 ++ tests/test_responses.py | 55 + tests/test_truenas_switch.py | 54 + tests/test_ui.py | 48 + tmp_channels_cols.sql | 1 + tmp_pref_type.sql | 1 + tmp_update_max_results.sql | 1 + trades_company_stock.txt | 56 + 53 files changed, 9885 insertions(+) create mode 100644 .gitignore create mode 100644 AGENTS.full.md create mode 100644 AGENTS.md create mode 100644 README.md create mode 100644 docs/llamacpp-wrapper-notes.md create mode 100644 docs/n8n-thesis-builder-checkpoint-20260104.md create mode 100644 llamaCpp.Wrapper.app/Dockerfile create mode 100644 llamaCpp.Wrapper.app/README.md create mode 100644 llamaCpp.Wrapper.app/__init__.py create mode 100644 llamaCpp.Wrapper.app/agents_config.json create mode 100644 llamaCpp.Wrapper.app/agents_parser.py create mode 100644 llamaCpp.Wrapper.app/api_app.py create mode 100644 llamaCpp.Wrapper.app/config.py create mode 100644 llamaCpp.Wrapper.app/docker_logs.py create mode 100644 llamaCpp.Wrapper.app/download_manager.py create mode 100644 llamaCpp.Wrapper.app/llamacpp_client.py create mode 100644 llamaCpp.Wrapper.app/logging_utils.py create mode 100644 llamaCpp.Wrapper.app/model_registry.py create mode 100644 llamaCpp.Wrapper.app/openai_translate.py create mode 100644 llamaCpp.Wrapper.app/restart.py create mode 100644 llamaCpp.Wrapper.app/run.py create mode 100644 llamaCpp.Wrapper.app/stream_transform.py create mode 100644 llamaCpp.Wrapper.app/truenas_middleware.py create mode 100644 llamaCpp.Wrapper.app/ui_app.py create mode 100644 llamaCpp.Wrapper.app/ui_static/app.js create mode 100644 llamaCpp.Wrapper.app/ui_static/index.html create mode 100644 llamaCpp.Wrapper.app/ui_static/styles.css create mode 100644 llamaCpp.Wrapper.app/warmup.py create mode 100644 llamacpp_remote_test.ps1 create mode 100644 llamacpp_set_command.ps1 create mode 100644 modelfiles/options-json-deepseek14b.Modelfile create mode 100644 modelfiles/options-json-llama31-70b.Modelfile create mode 100644 modelfiles/options-json-phi3mini.Modelfile create mode 100644 ollama_remote_test.ps1 create mode 100644 prompt_crwv.txt create mode 100644 query.sql create mode 100644 requirements.txt create mode 100644 scripts/deploy_truenas_wrapper.py create mode 100644 scripts/remote_wrapper_test.py create mode 100644 scripts/update_llamacpp_flags.ps1 create mode 100644 tests/conftest.py create mode 100644 tests/test_chat_completions.py create mode 100644 tests/test_embeddings.py create mode 100644 tests/test_models.py create mode 100644 tests/test_proxy.py create mode 100644 tests/test_remote_wrapper.py create mode 100644 tests/test_responses.py create mode 100644 tests/test_truenas_switch.py create mode 100644 tests/test_ui.py create mode 100644 tmp_channels_cols.sql create mode 100644 tmp_pref_type.sql create mode 100644 tmp_update_max_results.sql create mode 100644 trades_company_stock.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..70b73a6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,142 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# Project-specific +/inventory_raw/ +/llamacpp_runs_remote/ +/ollama_runs_remote/ +/reports/ +/tmp/ +*.log +/C:/Users/Rushabh/.gemini/tmp/bff31f86566324f77927540d72088ce62479fd0563c197318c9f0594af2e69ee/ + +# OS-generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db diff --git a/AGENTS.full.md b/AGENTS.full.md new file mode 100644 index 0000000..dc2b945 --- /dev/null +++ b/AGENTS.full.md @@ -0,0 +1,4206 @@ +# TrueNAS SCALE Inventory (snapshot 2025-12-29T05:44:45Z) + +All data captured via read-only SSH commands (port 55555) and middleware API calls. Sensitive values (private keys, tokens, passwords) are redacted in this document. + +Raw capture files live under `inventory_raw/` (JSON and text outputs). Patterns: +- `inventory_raw/*.json`, `inventory_raw/*.txt` +- `inventory_raw/apps/app.get_instance.*.json` +- `inventory_raw/vms/vm.get_instance.*.json`, `inventory_raw/vms/vm.status.*.json` + +Wrapper implementation notes live in `docs/llamacpp-wrapper-notes.md` (pointer only to avoid bloating this snapshot). +Latest wrapper/test status recorded there (updated 2026-01-03). + +## FAST ACCESS: SSH + N8N DB + WORKFLOWS (READ ME FIRST) +- SSH (passwordless): `ssh -p 55555 rushabh@192.168.1.2` (BatchMode=yes works) +- Sudo (passwordless): `sudo -n true` +- n8n Web: `https://n8n.rushg.me` +- n8n Postgres container: `ix-n8n-postgres-1` +- n8n DB creds: user `n8n`, db `n8n`, password `Rushabh%1` +- One-liner to list workflows (id | active | name): + `echo "SELECT id, name, active FROM workflow_entity ORDER BY name;" | sudo docker exec -i -e PGPASSWORD='Rushabh%1' ix-n8n-postgres-1 psql -U n8n -d n8n -At` +- One-liner to list workflows that call OpenAI (keyword scan in nodes JSON): + `echo "SELECT id, name FROM workflow_entity WHERE nodes::text ILIKE '%openai%' OR nodes::text ILIKE '%open ai%' OR nodes::text ILIKE '%n8n-nodes-base.openAi%' ORDER BY name;" | sudo docker exec -i -e PGPASSWORD='Rushabh%1' ix-n8n-postgres-1 psql -U n8n -d n8n -At` + +### N8N WORKFLOWS (CURRENT) +All workflows (id | active | name): +``` +dB_o7rs7QcudF-FJaZwdx|t|FinHub API Wrapper +jFQrmVTi878lN6RG|t|Get Charts +8buy3IDE2peQLJ69|f|iOS CRON +fU_HgWoc20u-izmg2Brbd|t|MarketData API +Df7V-4mxFWuxUll6hraFc|t|Morning Options Churn Routine +LuiBFxjVmrWcb1JE|f|My Sub-Workflow 1 +gBgDFMJdeDHBKzL93uBRx|f|My workflow +HEJkGpEDltw0H5Rr|f|New CRON +GkQha-893pV9sYXIlxTxb|t|Options Company Profile Fetch +mj5z8ngtyzoFWb5bUPAdK|f|Options recommendation Engine Core +ougUjs5yqz04rJ2G|t|Options recommendation Engine Core +uwtpkLrxabHGlus6|f|Options recommendation Engine Core LOCAL +Nupt4vBG82JKFoGc|f|Options recommendation Engine Core LOCAL +gfHA9unwjQFRVq5d|f|Options recommendation Engine Core LOCAL +k6MXB2baU0yAIfxR|f|Options recommendation news only SPX/NDX copy +ykD52Vc9BjKAesVa|f|Options recommendation news only SPX/NDX llama +ViE6R656qjGqoYAT|f|Options recommendation news only SPX/NDX MINIFIED -- OLLAMA +kFGxcx9nFoJ94La3|t|Options recommendations +jRlKyKvdObDKn73T|f|Options recommendation w/prices +TAPheNBccr59UElI|f|Options recommendation w/prices marketdata.app +DGmzcwJKXe1nPXHH|f|Options recommendation w/prices marketdata.app ollama +ac3jnrqAqTpntIId|t|Options recommendation w/prices w/customizable stock trigger +pl0N8AZtU2NZyF7x|f|Options recommendation w/prices yahoo +snky4enpUUhjnNE4|f|Selene - AI HomeAssistant +8jzylEikG32TfL0d|t|Selene V2 +lHEruCbA7GAqWHaf|t|Telegram stock trigger (stock 1m, 1h entry/exit) +xx-6b3eAQ8TpogCER0NXu|f|Timed Options Trigger +Sp8zKTB1Jr4nNZms|t|TrueNAS - SSH +2H0MCAcrVWxtiNxGkbY9-|f|Yahoo Company Profile +bYdl0I2JKX0nOKw5|t|YahooFinanceOptionsChain API +``` + +Workflows that call OpenAI (keyword scan in nodes JSON): +``` +mj5z8ngtyzoFWb5bUPAdK|Options recommendation Engine Core +ougUjs5yqz04rJ2G|Options recommendation Engine Core +Nupt4vBG82JKFoGc|Options recommendation Engine Core LOCAL +gfHA9unwjQFRVq5d|Options recommendation Engine Core LOCAL +k6MXB2baU0yAIfxR|Options recommendation news only SPX/NDX copy +ykD52Vc9BjKAesVa|Options recommendation news only SPX/NDX llama +ViE6R656qjGqoYAT|Options recommendation news only SPX/NDX MINIFIED -- OLLAMA +jRlKyKvdObDKn73T|Options recommendation w/prices +TAPheNBccr59UElI|Options recommendation w/prices marketdata.app +DGmzcwJKXe1nPXHH|Options recommendation w/prices marketdata.app ollama +ac3jnrqAqTpntIId|Options recommendation w/prices w/customizable stock trigger +pl0N8AZtU2NZyF7x|Options recommendation w/prices yahoo +snky4enpUUhjnNE4|Selene - AI HomeAssistant +lHEruCbA7GAqWHaf|Telegram stock trigger (stock 1m, 1h entry/exit) +2H0MCAcrVWxtiNxGkbY9-|Yahoo Company Profile +``` + +## System Settings > General +- Hostname: truenas +- TrueNAS version: TrueNAS-25.10.0.1 (system info: 25.10.0.1) +- Kernel/OS: Linux truenas 6.12.33-production+truenas #1 SMP PREEMPT_DYNAMIC Fri Nov 14 20:25:31 UTC 2025 x86_64 GNU/Linux +- OS release: PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"; NAME="Debian GNU/Linux"; VERSION_ID="12"; VERSION="12 (bookworm)"; VERSION_CODENAME=bookworm; ID=debian; HOME_URL="https://www.debian.org/"; SUPPORT_URL="https://www.debian.org/support"; BUG_REPORT_URL="https://bugs.debian.org/" +- Timezone: America/Los_Angeles +- Uptime: 0:55:46.075940 +- Boot time: 2025-12-29T01:59:20Z +- System manufacturer: Supermicro +- System product: Super Server +- System serial: 0123456789 +- Hardware model: AMD EPYC 7532 32-Core Processor +- ECC memory: True +- Physical memory bytes: 270086983680 +- UI address: ['0.0.0.0'] +- UI port: 80 +- UI allowlist: [] +- UI certificate: truenas_default (localhost) + - Valid: Fri Nov 28 15:44:06 2025 to Wed Dec 30 15:44:06 2026 + - Fingerprint: F4:AF:D9:AB:C4:07:E1:FE:2D:C9:CA:AA:0F:31:ED:2E:4F:7C:44:15 + - Paths: /etc/certificates/truenas_default.crt / /etc/certificates/truenas_default.key + +## System Settings > Advanced +- boot_scrub: 7 +- consolemenu: True +- serialconsole: True +- serialport: ttyS0 +- serialspeed: 9600 +- powerdaemon: False +- sysloglevel: F_INFO +- autotune: False +- debugkernel: False +- kdump_enabled: False +- fqdn_syslog: False + +## System Settings > Security +- FIPS enabled: False +- STIG enabled: False +- Password policy: min_length=None, min_age=None, max_age=None, history=None + +## System Settings > NTP +- 0.debian.pool.ntp.org (minpoll=6, maxpoll=10, iburst=True) +- 1.debian.pool.ntp.org (minpoll=6, maxpoll=10, iburst=True) +- 2.debian.pool.ntp.org (minpoll=6, maxpoll=10, iburst=True) + +## System Settings > System Dataset +- Pool: boot-pool +- Path: /var/db/system +- Dataset basename: boot-pool/.system + +## System Settings > UPS +- Mode: MASTER +- Identifier: ups +- Driver: +- Remote: :3493 + +## System Settings > Boot +- Boot environment list not captured (bootenv methods unavailable on this build). Use UI Boot Environments page if needed. + +## Network > Global Configuration +- IPv4 gateway: 192.168.1.1 +- IPv6 gateway: +- Nameservers: 8.8.8.8, 1.0.0.1, 1.1.1.1 +- Domains: [] +- HTTP proxy: + +## Network > Interfaces +- eno1: link_state=LINK_STATE_DOWN mtu=1500 mac=7c:c2:55:e8:6f:a0 +- eno2: link_state=LINK_STATE_DOWN mtu=1500 mac=7c:c2:55:e8:6f:a1 +- enxbe3af2b6059f: link_state=LINK_STATE_UNKNOWN mtu=1500 mac=be:3a:f2:b6:05:9f +- enp65s0: link_state=LINK_STATE_UP mtu=9000 mac=6c:b3:11:4d:2d:38 + - IPv4: 10.0.0.2/16 +- enp65s0d1: link_state=LINK_STATE_UP mtu=9000 mac=6c:b3:11:4d:2d:39 + - IPv4: 192.168.1.2/24 +- br0: link_state=LINK_STATE_UP mtu=9000 mac=9e:5e:88:92:b2:92 + +## Network > Routes and DNS (CLI capture) +See `inventory_raw/network.shell.txt` for `ip addr`, `ip route`, and `ss -tulpen` output. +Current `/etc/resolv.conf` snapshot: +```text +nameserver 8.8.8.8 +nameserver 1.0.0.1 +nameserver 1.1.1.1 +``` +Listening ports (`ss -tulpen`): +```text +Netid State Recv-Q Send-Q Local Address:Port Peer Address:PortProcess +udp UNCONN 0 0 0.0.0.0:53 0.0.0.0:* ino:30455 sk:1e001 cgroup:/system.slice/docker.service <-> +udp UNCONN 0 0 0.0.0.0:69 0.0.0.0:* ino:53993 sk:1e002 cgroup:/docker/31233e13a75657e56dcc1636825d0ebf1bbbf0cdeecac0aae42fa0315378f552 <-> +udp UNCONN 0 0 0.0.0.0:123 0.0.0.0:* ino:42609 sk:1e003 cgroup:/system.slice/chrony.service <-> +udp UNCONN 0 0 172.16.31.255:137 0.0.0.0:* ino:1184183 sk:1e004 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.31.1:137 0.0.0.0:* ino:1184182 sk:1e005 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.18.255:137 0.0.0.0:* ino:1184179 sk:1e006 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.18.1:137 0.0.0.0:* ino:1184178 sk:1e007 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.30.255:137 0.0.0.0:* ino:319339 sk:1e008 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.30.1:137 0.0.0.0:* ino:319338 sk:1e009 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.29.255:137 0.0.0.0:* ino:319335 sk:1e00a cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.29.1:137 0.0.0.0:* ino:319334 sk:1e00b cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.28.255:137 0.0.0.0:* ino:319331 sk:1e00c cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.28.1:137 0.0.0.0:* ino:319330 sk:1e00d cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.27.255:137 0.0.0.0:* ino:319327 sk:1e00e cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.27.1:137 0.0.0.0:* ino:319326 sk:1e00f cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.26.255:137 0.0.0.0:* ino:319323 sk:1e010 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.26.1:137 0.0.0.0:* ino:319322 sk:1e011 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.25.255:137 0.0.0.0:* ino:319319 sk:1e012 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.25.1:137 0.0.0.0:* ino:319318 sk:1e013 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.24.255:137 0.0.0.0:* ino:319315 sk:1e014 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.24.1:137 0.0.0.0:* ino:319314 sk:1e015 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.23.255:137 0.0.0.0:* ino:319311 sk:1e016 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.23.1:137 0.0.0.0:* ino:319310 sk:1e017 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.22.255:137 0.0.0.0:* ino:319307 sk:1e018 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.22.1:137 0.0.0.0:* ino:319306 sk:1e019 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.21.255:137 0.0.0.0:* ino:319303 sk:1e01a cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.21.1:137 0.0.0.0:* ino:319302 sk:1e01b cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.20.255:137 0.0.0.0:* ino:319299 sk:1e01c cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.20.1:137 0.0.0.0:* ino:319298 sk:1e01d cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.19.255:137 0.0.0.0:* ino:319295 sk:1e01e cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.19.1:137 0.0.0.0:* ino:319294 sk:1e01f cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.17.255:137 0.0.0.0:* ino:319287 sk:1e020 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.17.1:137 0.0.0.0:* ino:319286 sk:1e021 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.16.255:137 0.0.0.0:* ino:319283 sk:1e022 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.16.1:137 0.0.0.0:* ino:319282 sk:1e023 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.15.255:137 0.0.0.0:* ino:319279 sk:1e024 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.15.1:137 0.0.0.0:* ino:319278 sk:1e025 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.14.255:137 0.0.0.0:* ino:319275 sk:1e026 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.14.1:137 0.0.0.0:* ino:319274 sk:1e027 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.13.255:137 0.0.0.0:* ino:319271 sk:1e028 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.13.1:137 0.0.0.0:* ino:319270 sk:1e029 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.12.255:137 0.0.0.0:* ino:319267 sk:1e02a cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.12.1:137 0.0.0.0:* ino:319266 sk:1e02b cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.11.255:137 0.0.0.0:* ino:319263 sk:1e02c cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.11.1:137 0.0.0.0:* ino:319262 sk:1e02d cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.10.255:137 0.0.0.0:* ino:319259 sk:1e02e cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.10.1:137 0.0.0.0:* ino:319258 sk:1e02f cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.9.255:137 0.0.0.0:* ino:319255 sk:1e030 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.9.1:137 0.0.0.0:* ino:319254 sk:1e031 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.8.255:137 0.0.0.0:* ino:319251 sk:1e032 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.8.1:137 0.0.0.0:* ino:319250 sk:1e033 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.7.255:137 0.0.0.0:* ino:319247 sk:1e034 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.7.1:137 0.0.0.0:* ino:319246 sk:1e035 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.6.255:137 0.0.0.0:* ino:319243 sk:1e036 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.6.1:137 0.0.0.0:* ino:319242 sk:1e037 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.5.255:137 0.0.0.0:* ino:319239 sk:1e038 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.5.1:137 0.0.0.0:* ino:319238 sk:1e039 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.4.255:137 0.0.0.0:* ino:319235 sk:1e03a cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.4.1:137 0.0.0.0:* ino:319234 sk:1e03b cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.3.255:137 0.0.0.0:* ino:319231 sk:1e03c cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.3.1:137 0.0.0.0:* ino:319230 sk:1e03d cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.2.255:137 0.0.0.0:* ino:319227 sk:1e03e cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.2.1:137 0.0.0.0:* ino:319226 sk:1e03f cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.1.255:137 0.0.0.0:* ino:319223 sk:1e040 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.1.1:137 0.0.0.0:* ino:319222 sk:1e041 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.0.255:137 0.0.0.0:* ino:319219 sk:1e042 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.0.1:137 0.0.0.0:* ino:319218 sk:1e043 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 10.0.255.255:137 0.0.0.0:* ino:7880 sk:1e044 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 10.0.0.2:137 0.0.0.0:* ino:7879 sk:1e045 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 192.168.1.255:137 0.0.0.0:* ino:7876 sk:1e046 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 192.168.1.2:137 0.0.0.0:* ino:7875 sk:1e047 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 0.0.0.0:137 0.0.0.0:* ino:7860 sk:1e048 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.31.255:138 0.0.0.0:* ino:1184185 sk:1e049 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.31.1:138 0.0.0.0:* ino:1184184 sk:1e04a cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.18.255:138 0.0.0.0:* ino:1184181 sk:1e04b cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.18.1:138 0.0.0.0:* ino:1184180 sk:1e04c cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.30.255:138 0.0.0.0:* ino:319341 sk:1e04d cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.30.1:138 0.0.0.0:* ino:319340 sk:1e04e cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.29.255:138 0.0.0.0:* ino:319337 sk:1e04f cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.29.1:138 0.0.0.0:* ino:319336 sk:1e050 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.28.255:138 0.0.0.0:* ino:319333 sk:1e051 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.28.1:138 0.0.0.0:* ino:319332 sk:1e052 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.27.255:138 0.0.0.0:* ino:319329 sk:1e053 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.27.1:138 0.0.0.0:* ino:319328 sk:1e054 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.26.255:138 0.0.0.0:* ino:319325 sk:1e055 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.26.1:138 0.0.0.0:* ino:319324 sk:1e056 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.25.255:138 0.0.0.0:* ino:319321 sk:1e057 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.25.1:138 0.0.0.0:* ino:319320 sk:1e058 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.24.255:138 0.0.0.0:* ino:319317 sk:1e059 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.24.1:138 0.0.0.0:* ino:319316 sk:1e05a cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.23.255:138 0.0.0.0:* ino:319313 sk:1e05b cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.23.1:138 0.0.0.0:* ino:319312 sk:1e05c cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.22.255:138 0.0.0.0:* ino:319309 sk:1e05d cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.22.1:138 0.0.0.0:* ino:319308 sk:1e05e cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.21.255:138 0.0.0.0:* ino:319305 sk:1e05f cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.21.1:138 0.0.0.0:* ino:319304 sk:1e060 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.20.255:138 0.0.0.0:* ino:319301 sk:1e061 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.20.1:138 0.0.0.0:* ino:319300 sk:1e062 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.19.255:138 0.0.0.0:* ino:319297 sk:1e063 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.19.1:138 0.0.0.0:* ino:319296 sk:1e064 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.17.255:138 0.0.0.0:* ino:319289 sk:1e065 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.17.1:138 0.0.0.0:* ino:319288 sk:1e066 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.16.255:138 0.0.0.0:* ino:319285 sk:1e067 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.16.1:138 0.0.0.0:* ino:319284 sk:1e068 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.15.255:138 0.0.0.0:* ino:319281 sk:1e069 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.15.1:138 0.0.0.0:* ino:319280 sk:1e06a cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.14.255:138 0.0.0.0:* ino:319277 sk:1e06b cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.14.1:138 0.0.0.0:* ino:319276 sk:1e06c cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.13.255:138 0.0.0.0:* ino:319273 sk:1e06d cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.13.1:138 0.0.0.0:* ino:319272 sk:1e06e cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.12.255:138 0.0.0.0:* ino:319269 sk:1e06f cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.12.1:138 0.0.0.0:* ino:319268 sk:1e070 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.11.255:138 0.0.0.0:* ino:319265 sk:1e071 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.11.1:138 0.0.0.0:* ino:319264 sk:1e072 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.10.255:138 0.0.0.0:* ino:319261 sk:1e073 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.10.1:138 0.0.0.0:* ino:319260 sk:1e074 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.9.255:138 0.0.0.0:* ino:319257 sk:1e075 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.9.1:138 0.0.0.0:* ino:319256 sk:1e076 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.8.255:138 0.0.0.0:* ino:319253 sk:1e077 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.8.1:138 0.0.0.0:* ino:319252 sk:1e078 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.7.255:138 0.0.0.0:* ino:319249 sk:1e079 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.7.1:138 0.0.0.0:* ino:319248 sk:1e07a cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.6.255:138 0.0.0.0:* ino:319245 sk:1e07b cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.6.1:138 0.0.0.0:* ino:319244 sk:1e07c cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.5.255:138 0.0.0.0:* ino:319241 sk:1e07d cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.5.1:138 0.0.0.0:* ino:319240 sk:1e07e cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.4.255:138 0.0.0.0:* ino:319237 sk:1e07f cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.4.1:138 0.0.0.0:* ino:319236 sk:1e080 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.3.255:138 0.0.0.0:* ino:319233 sk:1e081 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.3.1:138 0.0.0.0:* ino:319232 sk:1e082 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.2.255:138 0.0.0.0:* ino:319229 sk:1e083 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.2.1:138 0.0.0.0:* ino:319228 sk:1e084 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.1.255:138 0.0.0.0:* ino:319225 sk:1e085 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.1.1:138 0.0.0.0:* ino:319224 sk:1e086 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.0.255:138 0.0.0.0:* ino:319221 sk:1e087 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 172.16.0.1:138 0.0.0.0:* ino:319220 sk:1e088 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 10.0.255.255:138 0.0.0.0:* ino:7882 sk:1e089 cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 10.0.0.2:138 0.0.0.0:* ino:7881 sk:1e08a cgroup:/system.slice/nmbd.service <-> +udp UNCONN 960 0 192.168.1.255:138 0.0.0.0:* ino:7878 sk:1e08b cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 192.168.1.2:138 0.0.0.0:* ino:7877 sk:1e08c cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 0.0.0.0:138 0.0.0.0:* ino:7861 sk:1e08d cgroup:/system.slice/nmbd.service <-> +udp UNCONN 0 0 127.0.0.1:323 0.0.0.0:* ino:42607 sk:1e08e cgroup:/system.slice/chrony.service <-> +udp UNCONN 0 0 192.168.1.2:3702 0.0.0.0:* uid:1 ino:21105 sk:1e08f cgroup:/system.slice/wsdd.service <-> +udp UNCONN 0 0 239.255.255.250:3702 0.0.0.0:* uid:1 ino:21103 sk:1e090 cgroup:/system.slice/wsdd.service <-> +udp UNCONN 0 0 10.0.0.2:3702 0.0.0.0:* uid:1 ino:43576 sk:1e091 cgroup:/system.slice/wsdd.service <-> +udp UNCONN 0 0 239.255.255.250:3702 0.0.0.0:* uid:1 ino:43574 sk:1e092 cgroup:/system.slice/wsdd.service <-> +udp UNCONN 0 0 0.0.0.0:5353 0.0.0.0:* uid:105 ino:4781 sk:1e093 cgroup:/system.slice/avahi-daemon.service <-> +udp UNCONN 0 0 0.0.0.0:43305 0.0.0.0:* uid:1 ino:21104 sk:1e094 cgroup:/system.slice/wsdd.service <-> +udp UNCONN 0 0 0.0.0.0:45203 0.0.0.0:* uid:105 ino:4782 sk:1e095 cgroup:/system.slice/avahi-daemon.service <-> +udp UNCONN 0 0 0.0.0.0:51413 0.0.0.0:* ino:13071 sk:1e096 cgroup:/system.slice/docker.service <-> +udp UNCONN 0 0 0.0.0.0:52050 0.0.0.0:* uid:1 ino:43575 sk:1e097 cgroup:/system.slice/wsdd.service <-> +udp UNCONN 0 0 [::]:53 [::]:* ino:30456 sk:1e098 cgroup:/system.slice/docker.service v6only:1 <-> +udp UNCONN 0 0 [::]:69 [::]:* ino:53994 sk:1e099 cgroup:/docker/31233e13a75657e56dcc1636825d0ebf1bbbf0cdeecac0aae42fa0315378f552 v6only:1 <-> +udp UNCONN 0 0 [::]:123 [::]:* ino:42610 sk:1e09a cgroup:/system.slice/chrony.service v6only:1 <-> +udp UNCONN 0 0 [::1]:323 [::]:* ino:42608 sk:1e09b cgroup:/system.slice/chrony.service v6only:1 <-> +udp UNCONN 0 0 [::]:51413 [::]:* ino:13072 sk:1e09c cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 0.0.0.0:30257 0.0.0.0:* ino:43760 sk:c001 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30233 0.0.0.0:* ino:89265 sk:c002 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30117 0.0.0.0:* ino:52210 sk:c003 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30116 0.0.0.0:* ino:30393 sk:c004 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30094 0.0.0.0:* ino:356427 sk:c005 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30109 0.0.0.0:* ino:36864 sk:c006 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30051 0.0.0.0:* ino:21267 sk:c007 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30048 0.0.0.0:* ino:84338 sk:c008 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30053 0.0.0.0:* ino:59189 sk:c009 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30063 0.0.0.0:* ino:17217 sk:c00a cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30070 0.0.0.0:* ino:50897 sk:c00b cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30068 0.0.0.0:* ino:91469 sk:c00c cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30022 0.0.0.0:* ino:45635 sk:c00d cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30021 0.0.0.0:* ino:33787 sk:c00e cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30020 0.0.0.0:* ino:26564 sk:c00f cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30024 0.0.0.0:* ino:26507 sk:c010 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30032 0.0.0.0:* ino:344507 sk:c011 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30040 0.0.0.0:* ino:1177170 sk:1e09d cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30009 0.0.0.0:* ino:13111 sk:c012 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30008 0.0.0.0:* ino:72092 sk:c013 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:30015 0.0.0.0:* ino:85592 sk:c014 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 511 0.0.0.0:31011 0.0.0.0:* users:(("nginx",pid=27291,fd=7),("nginx",pid=27289,fd=7),("nginx",pid=27288,fd=7),("nginx",pid=27287,fd=7)) ino:55128 sk:c015 cgroup:/docker/31233e13a75657e56dcc1636825d0ebf1bbbf0cdeecac0aae42fa0315378f552 <-> +tcp LISTEN 0 4096 0.0.0.0:31008 0.0.0.0:* ino:84603 sk:c016 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:31028 0.0.0.0:* ino:65265 sk:c017 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:31003 0.0.0.0:* ino:45671 sk:c018 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:32400 0.0.0.0:* ino:96457 sk:c019 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:20720 0.0.0.0:* ino:93262 sk:c01a cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:20489 0.0.0.0:* ino:116818 sk:c01b cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:20800 0.0.0.0:* ino:65258 sk:c01c cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 128 127.0.0.1:6000 0.0.0.0:* ino:49220 sk:1 cgroup:/system.slice/middlewared.service <-> +tcp LISTEN 0 4096 127.0.0.1:6999 0.0.0.0:* uid:999 ino:69818 sk:2 cgroup:/system.slice/netdata.service <-> +tcp LISTEN 0 4096 0.0.0.0:9091 0.0.0.0:* ino:55108 sk:c01d cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:9095 0.0.0.0:* ino:337985 sk:c01e cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:9092 0.0.0.0:* ino:6877 sk:c01f cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 5 192.168.1.2:5357 0.0.0.0:* uid:1 ino:21107 sk:c020 cgroup:/system.slice/wsdd.service <-> +tcp LISTEN 0 128 0.0.0.0:9777 0.0.0.0:* ino:45726 sk:c021 cgroup:/docker/6d3c444cf982929ddf356f0fc315feb5d6c2364ff948db9eef616adc86352695 <-> +tcp LISTEN 0 1 0.0.0.0:5900 0.0.0.0:* uid:986 ino:39816 sk:c022 cgroup:/machine.slice/machine-qemu\x2d1\x2d1HomeAssistant.scope/libvirt/emulator <-> +tcp LISTEN 0 1 0.0.0.0:5904 0.0.0.0:* uid:986 ino:100858 sk:c023 cgroup:/machine.slice/machine-qemu\x2d2\x2d6ubuntuServer.scope/libvirt/emulator <-> +tcp LISTEN 0 4096 0.0.0.0:8188 0.0.0.0:* ino:282563 sk:c024 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 0.0.0.0:8071 0.0.0.0:* ino:1175569 sk:1e09e cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 50 0.0.0.0:139 0.0.0.0:* ino:43684 sk:c025 cgroup:/system.slice/smbd.service <-> +tcp LISTEN 0 511 0.0.0.0:80 0.0.0.0:* ino:26063 sk:4 cgroup:/system.slice/nginx.service <-> +tcp LISTEN 0 4096 0.0.0.0:53 0.0.0.0:* ino:31476 sk:c026 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 511 0.0.0.0:443 0.0.0.0:* ino:26061 sk:5 cgroup:/system.slice/nginx.service <-> +tcp LISTEN 0 50 0.0.0.0:445 0.0.0.0:* ino:43683 sk:c027 cgroup:/system.slice/smbd.service <-> +tcp LISTEN 0 5 10.0.0.2:5357 0.0.0.0:* uid:1 ino:36568 sk:c028 cgroup:/system.slice/wsdd.service <-> +tcp LISTEN 0 128 127.0.0.1:55555 0.0.0.0:* ino:69790 sk:7 cgroup:/system.slice/ssh.service <-> +tcp LISTEN 0 128 192.168.1.2:55555 0.0.0.0:* ino:69788 sk:8 cgroup:/system.slice/ssh.service <-> +tcp LISTEN 0 4096 0.0.0.0:51413 0.0.0.0:* ino:33762 sk:c029 cgroup:/system.slice/docker.service <-> +tcp LISTEN 0 4096 [::]:30257 [::]:* ino:43761 sk:1e09f cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30233 [::]:* ino:89266 sk:1e0a0 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30117 [::]:* ino:52211 sk:1e0a1 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30116 [::]:* ino:30394 sk:1e0a2 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30094 [::]:* ino:356428 sk:1e0a3 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30109 [::]:* ino:101377 sk:1e0a4 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30051 [::]:* ino:21268 sk:1e0a5 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30048 [::]:* ino:84339 sk:1e0a6 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30053 [::]:* ino:59190 sk:1e0a7 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30063 [::]:* ino:17218 sk:1e0a8 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 *:30064 *:* uid:568 ino:128022 sk:1e0a9 cgroup:/docker/b92ea28ed6d0045c4c6c517113046ff6b7cc8879202fa25d8c98e8c0bdaacae9 v6only:0 <-> +tcp LISTEN 0 4096 [::]:30070 [::]:* ino:50898 sk:1e0aa cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30068 [::]:* ino:91470 sk:1e0ab cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30022 [::]:* ino:45636 sk:1e0ac cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30021 [::]:* ino:33788 sk:1e0ad cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30020 [::]:* ino:26565 sk:1e0ae cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30024 [::]:* ino:26508 sk:1e0af cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30032 [::]:* ino:344508 sk:1e0b0 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30040 [::]:* ino:1177171 sk:1e0b1 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30009 [::]:* ino:13112 sk:1e0b2 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30008 [::]:* ino:72093 sk:1e0b3 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:30015 [::]:* ino:85593 sk:1e0b4 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 511 *:31010 *:* users:(("node",pid=27232,fd=18)) uid:3000 ino:29423 sk:1e0b5 cgroup:/docker/31233e13a75657e56dcc1636825d0ebf1bbbf0cdeecac0aae42fa0315378f552 v6only:0 <-> +tcp LISTEN 0 4096 [::]:31008 [::]:* ino:84604 sk:1e0b6 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:31028 [::]:* ino:65266 sk:1e0b7 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:31003 [::]:* ino:45672 sk:1e0b8 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:32400 [::]:* ino:94585 sk:1e0b9 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 128 [fe80::6eb3:11ff:fe4d:2d39]%enp65s0d1:55555 [::]:* ino:69786 sk:1e0ba cgroup:/system.slice/ssh.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:20720 [::]:* ino:93263 sk:1e0bb cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:20489 [::]:* ino:116819 sk:1e0bc cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:20800 [::]:* ino:65259 sk:1e0bd cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:9091 [::]:* ino:55109 sk:1e0be cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:9095 [::]:* ino:337986 sk:1e0bf cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:9092 [::]:* ino:6878 sk:1e0c0 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:8188 [::]:* ino:282564 sk:1e0c1 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:8071 [::]:* ino:1175570 sk:1e0c2 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 50 [::]:139 [::]:* ino:43682 sk:1e0c3 cgroup:/system.slice/smbd.service v6only:1 <-> +tcp LISTEN 0 511 [::]:80 [::]:* ino:26064 sk:1e0c4 cgroup:/system.slice/nginx.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:53 [::]:* ino:31477 sk:1e0c5 cgroup:/system.slice/docker.service v6only:1 <-> +tcp LISTEN 0 511 [::]:443 [::]:* ino:26062 sk:1e0c6 cgroup:/system.slice/nginx.service v6only:1 <-> +tcp LISTEN 0 50 [::]:445 [::]:* ino:43681 sk:1e0c7 cgroup:/system.slice/smbd.service v6only:1 <-> +tcp LISTEN 0 4096 [::]:51413 [::]:* ino:33763 sk:1e0c8 cgroup:/system.slice/docker.service v6only:1 <-> +``` + +## System Settings > Services +- cifs: enabled=True state=RUNNING +- ssh: enabled=True state=RUNNING + +## Storage > Pools (ZFS) +zpool list: +```text +NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT +boot-pool 232G 10.2G 222G - - 16% 4% 1.00x ONLINE - +fast.storage.rushg.me 3.67T 1.52T 2.16T - - 21% 41% 1.00x ONLINE /mnt +storage.rushg.me 72.9T 56.8T 16.1T - - 18% 77% 1.00x ONLINE /mnt +``` +zpool status: +```text + pool: boot-pool + state: ONLINE + scan: scrub repaired 0B in 00:00:25 with 0 errors on Fri Dec 26 03:45:26 2025 +config: + + NAME STATE READ WRITE CKSUM + boot-pool ONLINE 0 0 0 + sda3 ONLINE 0 0 0 + +errors: No known data errors + + pool: fast.storage.rushg.me + state: ONLINE + scan: scrub repaired 0B in 00:13:45 with 0 errors on Sun Dec 28 18:18:24 2025 +config: + + NAME STATE READ WRITE CKSUM + fast.storage.rushg.me ONLINE 0 0 0 + mirror-0 ONLINE 0 0 0 + 63e35912-d8c0-4097-a4c3-138b2549bf44 ONLINE 0 0 0 + 29e12748-15b8-43d0-80b6-2555d812a6d8 ONLINE 0 0 0 + mirror-1 ONLINE 0 0 0 + d4e717d3-3f32-4685-89ff-1161bff9fc1e ONLINE 0 0 0 + a8addd66-401f-4cf1-b6d7-2b2da436871e ONLINE 0 0 0 + mirror-2 ONLINE 0 0 0 + b8167146-b705-490d-a41f-01aa541f70ec ONLINE 0 0 0 + e53a679c-019e-4a22-a9cf-a85ba03d0938 ONLINE 0 0 0 + +errors: No known data errors + + pool: storage.rushg.me + state: ONLINE + scan: scrub in progress since Sun Dec 28 18:04:41 2025 + 55.5T / 56.8T scanned at 11.0G/s, 4.41T / 56.8T issued at 895M/s + 0B repaired, 7.77% done, 17:03:00 to go +config: + + NAME STATE READ WRITE CKSUM + storage.rushg.me ONLINE 0 0 0 + raidz2-0 ONLINE 0 0 0 + d1b42f05-d1bd-4fb1-a422-56f2dff3a54c ONLINE 0 0 0 + e4dec5ae-f5d9-4166-9372-448d0bb74bdf ONLINE 0 0 0 + 5ce8d7ac-a3c8-4b9d-8990-3c073106fe27 ONLINE 0 0 0 + d9017701-8cc5-477e-9e9d-8e0dbc8476d3 ONLINE 0 0 0 + c4720694-87e5-4034-9347-b3fed0825458 ONLINE 0 0 0 + special + mirror-3 ONLINE 0 0 0 + 6bf4e54d-2143-40c8-9e0c-32e43281f096 ONLINE 0 0 0 + 95628859-3156-4698-823f-ef684d43fe5b ONLINE 0 0 0 + 35c1e81a-a99c-423f-9727-63316dfc61eb ONLINE 0 0 0 + logs + mirror-6 ONLINE 0 0 0 + 4485952d-687d-4879-9337-d978a7cb7f8b ONLINE 0 0 0 + 2b13a416-22e0-4764-82e6-6be2514f01e4 ONLINE 0 0 0 + cache + ff1d2bd9-b799-475a-86f6-ed4328ba5c7a ONLINE 0 0 0 + 348c7328-254a-47e9-8904-c9e7cb7bc2b2 ONLINE 0 0 0 + +errors: No known data errors +``` +- Pool errors cleared on 2025-12-29T03:34:20Z (fast.storage.rushg.me now reports no known data errors). +zfs list (filesystems and volumes): +```text +NAME USED AVAIL REFER MOUNTPOINT COMPRESS RECSIZE +boot-pool 10.2G 215G 96K none on 128K +boot-pool/.system 2.24G 215G 1.69G legacy on 128K +boot-pool/.system/configs-ae32c386e13840b2bf9c0083275e7941 2.91M 215G 2.91M legacy on 128K +boot-pool/.system/cores 37.4M 987M 37.4M legacy on 128K +boot-pool/.system/netdata-ae32c386e13840b2bf9c0083275e7941 516M 215G 516M legacy on 128K +boot-pool/.system/nfs 112K 215G 112K legacy on 128K +boot-pool/.system/samba4 504K 215G 504K legacy on 128K +boot-pool/.system/vm 216K 215G 216K legacy on 128K +boot-pool/ROOT 7.89G 215G 96K none on 128K +boot-pool/ROOT/25.10.0.1 7.89G 215G 104M legacy on 128K +boot-pool/ROOT/25.10.0.1/audit 4.70G 215G 4.70G /audit on 128K +boot-pool/ROOT/25.10.0.1/conf 7.38M 215G 7.38M /conf on 128K +boot-pool/ROOT/25.10.0.1/data 328K 215G 328K /data on 128K +boot-pool/ROOT/25.10.0.1/etc 7.89M 215G 6.71M /etc on 128K +boot-pool/ROOT/25.10.0.1/home 132K 215G 132K /home on 128K +boot-pool/ROOT/25.10.0.1/mnt 112K 215G 112K /mnt on 128K +boot-pool/ROOT/25.10.0.1/opt 4.65M 215G 4.65M /opt on 128K +boot-pool/ROOT/25.10.0.1/root 252K 215G 252K /root on 128K +boot-pool/ROOT/25.10.0.1/usr 2.82G 215G 2.82G /usr on 128K +boot-pool/ROOT/25.10.0.1/var 177M 215G 6.15M /var on 128K +boot-pool/ROOT/25.10.0.1/var/ca-certificates 96K 215G 96K /var/local/ca-certificates on 128K +boot-pool/ROOT/25.10.0.1/var/lib 32.8M 215G 30.3M /var/lib on 128K +boot-pool/ROOT/25.10.0.1/var/lib/incus 2.23M 215G 2.23M /var/lib/incus on 128K +boot-pool/ROOT/25.10.0.1/var/log 137M 215G 86.7M /var/log on 128K +boot-pool/ROOT/25.10.0.1/var/log/journal 50.8M 215G 50.8M /var/log/journal on 128K +boot-pool/grub 9.03M 215G 9.03M legacy on 128K +fast.storage.rushg.me 1.52T 2.04T 104K /mnt/fast.storage.rushg.me lz4 128K +fast.storage.rushg.me/.ix-virt 1.12M 2.04T 96K legacy lz4 128K +fast.storage.rushg.me/.ix-virt/buckets 96K 2.04T 96K legacy lz4 128K +fast.storage.rushg.me/.ix-virt/containers 96K 2.04T 96K legacy lz4 128K +fast.storage.rushg.me/.ix-virt/custom 96K 2.04T 96K legacy lz4 128K +fast.storage.rushg.me/.ix-virt/deleted 576K 2.04T 96K legacy lz4 128K +fast.storage.rushg.me/.ix-virt/deleted/buckets 96K 2.04T 96K legacy lz4 128K +fast.storage.rushg.me/.ix-virt/deleted/containers 96K 2.04T 96K legacy lz4 128K +fast.storage.rushg.me/.ix-virt/deleted/custom 96K 2.04T 96K legacy lz4 128K +fast.storage.rushg.me/.ix-virt/deleted/images 96K 2.04T 96K legacy lz4 128K +fast.storage.rushg.me/.ix-virt/deleted/virtual-machines 96K 2.04T 96K legacy lz4 128K +fast.storage.rushg.me/.ix-virt/images 96K 2.04T 96K legacy lz4 128K +fast.storage.rushg.me/.ix-virt/virtual-machines 96K 2.04T 96K legacy lz4 128K +fast.storage.rushg.me/datasets 1.20T 2.04T 188K /mnt/fast.storage.rushg.me/datasets gzip-9 128K +fast.storage.rushg.me/datasets/apps 1.08T 2.04T 36.1G /mnt/fast.storage.rushg.me/datasets/apps gzip-9 128K +fast.storage.rushg.me/datasets/apps/bichon 180K 2.04T 180K /mnt/fast.storage.rushg.me/datasets/apps/bichon gzip-9 128K +fast.storage.rushg.me/datasets/apps/comfyui 183G 2.04T 989M /mnt/fast.storage.rushg.me/datasets/apps/comfyui gzip-9 128K +fast.storage.rushg.me/datasets/apps/comfyui/input 4.27M 2.04T 4.27M /mnt/fast.storage.rushg.me/datasets/apps/comfyui/input gzip-9 128K +fast.storage.rushg.me/datasets/apps/comfyui/models 182G 2.04T 182G /mnt/fast.storage.rushg.me/datasets/apps/comfyui/models gzip-9 128K +fast.storage.rushg.me/datasets/apps/comfyui/output 214M 2.04T 214M /mnt/fast.storage.rushg.me/datasets/apps/comfyui/output gzip-9 128K +fast.storage.rushg.me/datasets/apps/filebrowser 528K 2.04T 108K /mnt/fast.storage.rushg.me/datasets/apps/filebrowser gzip-9 128K +fast.storage.rushg.me/datasets/apps/gitea 1.31G 2.04T 104K /mnt/fast.storage.rushg.me/datasets/apps/gitea gzip-9 128K +fast.storage.rushg.me/datasets/apps/gitea/config 100K 2.04T 100K /mnt/fast.storage.rushg.me/datasets/apps/gitea/config gzip-9 128K +fast.storage.rushg.me/datasets/apps/gitea/data 1.29G 2.04T 1.29G /mnt/fast.storage.rushg.me/datasets/apps/gitea/data gzip-9 128K +fast.storage.rushg.me/datasets/apps/gitea/postgres 16.0M 2.04T 10.8M /mnt/fast.storage.rushg.me/datasets/apps/gitea/postgres gzip-9 128K +fast.storage.rushg.me/datasets/apps/immich 722G 2.04T 112K /mnt/fast.storage.rushg.me/datasets/apps/immich gzip-9 128K +fast.storage.rushg.me/datasets/apps/immich/data 720G 2.04T 694G /mnt/fast.storage.rushg.me/datasets/apps/immich/data gzip-9 128K +fast.storage.rushg.me/datasets/apps/immich/mlcache 96K 2.04T 96K /mnt/fast.storage.rushg.me/datasets/apps/immich/mlcache gzip-9 128K +fast.storage.rushg.me/datasets/apps/immich/pgData 1.24G 2.04T 361M /mnt/fast.storage.rushg.me/datasets/apps/immich/pgData gzip-9 128K +fast.storage.rushg.me/datasets/apps/invidious-internal 715M 2.04T 96K /mnt/fast.storage.rushg.me/datasets/apps/invidious-internal gzip-9 128K +fast.storage.rushg.me/datasets/apps/invidious-internal/cache 96K 2.04T 96K /mnt/fast.storage.rushg.me/datasets/apps/invidious-internal/cache gzip-9 128K +fast.storage.rushg.me/datasets/apps/invidious-internal/config 212K 2.04T 100K /mnt/fast.storage.rushg.me/datasets/apps/invidious-internal/config gzip-9 128K +fast.storage.rushg.me/datasets/apps/invidious-internal/pgData 714M 2.04T 20.3M /mnt/fast.storage.rushg.me/datasets/apps/invidious-internal/pgData gzip-9 128K +fast.storage.rushg.me/datasets/apps/invidious-public 541M 2.04T 104K /mnt/fast.storage.rushg.me/datasets/apps/invidious-public gzip-9 128K +fast.storage.rushg.me/datasets/apps/invidious-public/cache 96K 2.04T 96K /mnt/fast.storage.rushg.me/datasets/apps/invidious-public/cache gzip-9 128K +fast.storage.rushg.me/datasets/apps/invidious-public/config 212K 2.04T 100K /mnt/fast.storage.rushg.me/datasets/apps/invidious-public/config gzip-9 128K +fast.storage.rushg.me/datasets/apps/invidious-public/pgData 540M 2.04T 20.1M /mnt/fast.storage.rushg.me/datasets/apps/invidious-public/pgData gzip-9 128K +fast.storage.rushg.me/datasets/apps/komga 63.5M 2.04T 11.2M /mnt/fast.storage.rushg.me/datasets/apps/komga gzip-9 128K +fast.storage.rushg.me/datasets/apps/llama-cpp.models 24.0G 2.04T 24.0G /mnt/fast.storage.rushg.me/datasets/apps/llama-cpp.models gzip-9 128K +fast.storage.rushg.me/datasets/apps/n8n 2.11G 2.04T 112K /mnt/fast.storage.rushg.me/datasets/apps/n8n gzip-9 128K +fast.storage.rushg.me/datasets/apps/n8n/data 298M 2.04T 196M /mnt/fast.storage.rushg.me/datasets/apps/n8n/data gzip-9 128K +fast.storage.rushg.me/datasets/apps/n8n/postgres-data 1.82G 2.04T 300M /mnt/fast.storage.rushg.me/datasets/apps/n8n/postgres-data gzip-9 128K +fast.storage.rushg.me/datasets/apps/netboot 1.74G 2.04T 104K /mnt/fast.storage.rushg.me/datasets/apps/netboot gzip-9 128K +fast.storage.rushg.me/datasets/apps/netboot/assets 1.73G 2.04T 1.73G /mnt/fast.storage.rushg.me/datasets/apps/netboot/assets gzip-9 128K +fast.storage.rushg.me/datasets/apps/netboot/config 8.91M 2.04T 7.11M /mnt/fast.storage.rushg.me/datasets/apps/netboot/config gzip-9 128K +fast.storage.rushg.me/datasets/apps/netdata 17.2G 2.04T 112K /mnt/fast.storage.rushg.me/datasets/apps/netdata gzip-9 128K +fast.storage.rushg.me/datasets/apps/netdata/cache 17.2G 2.04T 1.28G /mnt/fast.storage.rushg.me/datasets/apps/netdata/cache gzip-9 128K +fast.storage.rushg.me/datasets/apps/netdata/config 572K 2.04T 124K /mnt/fast.storage.rushg.me/datasets/apps/netdata/config gzip-9 128K +fast.storage.rushg.me/datasets/apps/netdata/lib 24.9M 2.04T 188K /mnt/fast.storage.rushg.me/datasets/apps/netdata/lib gzip-9 128K +fast.storage.rushg.me/datasets/apps/ollama.models 114G 2.04T 109G /mnt/fast.storage.rushg.me/datasets/apps/ollama.models gzip-9 128K +fast.storage.rushg.me/datasets/apps/openwebui 2.15G 2.04T 1.28G /mnt/fast.storage.rushg.me/datasets/apps/openwebui gzip-9 128K +fast.storage.rushg.me/datasets/apps/openwebui/data 867M 2.04T 867M /mnt/fast.storage.rushg.me/datasets/apps/openwebui/data gzip-9 128K +fast.storage.rushg.me/datasets/apps/organizr 266M 2.04T 199M /mnt/fast.storage.rushg.me/datasets/apps/organizr gzip-9 128K +fast.storage.rushg.me/datasets/apps/paperless 164M 2.04T 136K /mnt/fast.storage.rushg.me/datasets/apps/paperless gzip-9 128K +fast.storage.rushg.me/datasets/apps/paperless/consume 344K 2.04T 96K /mnt/fast.storage.rushg.me/datasets/apps/paperless/consume gzip-9 128K +fast.storage.rushg.me/datasets/apps/paperless/data 28.1M 2.04T 792K /mnt/fast.storage.rushg.me/datasets/apps/paperless/data gzip-9 128K +fast.storage.rushg.me/datasets/apps/paperless/media 5.07M 2.04T 4.75M /mnt/fast.storage.rushg.me/datasets/apps/paperless/media gzip-9 128K +fast.storage.rushg.me/datasets/apps/paperless/paperless-ai.data 452K 2.04T 164K /mnt/fast.storage.rushg.me/datasets/apps/paperless/paperless-ai.data gzip-9 128K +fast.storage.rushg.me/datasets/apps/paperless/postgres-data 130M 2.04T 16.5M /mnt/fast.storage.rushg.me/datasets/apps/paperless/postgres-data gzip-9 128K +fast.storage.rushg.me/datasets/apps/paperless/trash 344K 2.04T 96K /mnt/fast.storage.rushg.me/datasets/apps/paperless/trash gzip-9 128K +fast.storage.rushg.me/datasets/apps/pihole 1.10G 2.04T 104K /mnt/fast.storage.rushg.me/datasets/apps/pihole gzip-9 128K +fast.storage.rushg.me/datasets/apps/pihole/config 1.10G 2.04T 51.1M /mnt/fast.storage.rushg.me/datasets/apps/pihole/config gzip-9 128K +fast.storage.rushg.me/datasets/apps/pihole/dnsmasq 96K 2.04T 96K /mnt/fast.storage.rushg.me/datasets/apps/pihole/dnsmasq gzip-9 128K +fast.storage.rushg.me/datasets/apps/plex 4.22G 2.04T 96K /mnt/fast.storage.rushg.me/datasets/apps/plex gzip-9 128K +fast.storage.rushg.me/datasets/apps/plex/config 4.22G 2.04T 3.43G /mnt/fast.storage.rushg.me/datasets/apps/plex/config gzip-9 128K +fast.storage.rushg.me/datasets/apps/plex/data 96K 2.04T 96K /mnt/fast.storage.rushg.me/datasets/apps/plex/data gzip-9 128K +fast.storage.rushg.me/datasets/apps/qbittorrent 35.2M 2.04T 96K /mnt/fast.storage.rushg.me/datasets/apps/qbittorrent gzip-9 128K +fast.storage.rushg.me/datasets/apps/qbittorrent/config 35.1M 2.04T 3.75M /mnt/fast.storage.rushg.me/datasets/apps/qbittorrent/config gzip-9 128K +fast.storage.rushg.me/datasets/apps/retrom 305M 2.04T 96K /mnt/fast.storage.rushg.me/datasets/apps/retrom gzip-9 128K +fast.storage.rushg.me/datasets/apps/retrom/config 100K 2.04T 100K /mnt/fast.storage.rushg.me/datasets/apps/retrom/config gzip-9 128K +fast.storage.rushg.me/datasets/apps/retrom/data 305M 2.04T 305M /mnt/fast.storage.rushg.me/datasets/apps/retrom/data gzip-9 128K +fast.storage.rushg.me/datasets/apps/searxng 1.01M 2.04T 148K /mnt/fast.storage.rushg.me/datasets/apps/searxng gzip-9 128K +fast.storage.rushg.me/datasets/apps/trillium 59.7M 2.04T 4.74M /mnt/fast.storage.rushg.me/datasets/apps/trillium gzip-9 128K +fast.storage.rushg.me/datasets/apps/vaultwarden 17.8M 2.04T 96K /mnt/fast.storage.rushg.me/datasets/apps/vaultwarden gzip-9 128K +fast.storage.rushg.me/datasets/apps/vaultwarden/data 2.14M 2.04T 2.07M /mnt/fast.storage.rushg.me/datasets/apps/vaultwarden/data gzip-9 128K +fast.storage.rushg.me/datasets/apps/vaultwarden/postgres 15.6M 2.04T 13.0M /mnt/fast.storage.rushg.me/datasets/apps/vaultwarden/postgres gzip-9 128K +fast.storage.rushg.me/datasets/scripts 3.24M 2.04T 764K /mnt/fast.storage.rushg.me/datasets/scripts gzip-9 128K +fast.storage.rushg.me/datasets/vms 122G 2.04T 96K /mnt/fast.storage.rushg.me/datasets/vms gzip-9 128K +fast.storage.rushg.me/datasets/vms/homeassistant_ported 27.6G 2.04T 12.6G - gzip-9 - +fast.storage.rushg.me/datasets/vms/ubuntu 12.8G 2.04T 9.28G - gzip-9 - +fast.storage.rushg.me/datasets/vms/windowsAPIServer 81.1G 2.04T 47.2G - gzip-9 - +fast.storage.rushg.me/ix-apps 320G 2.04T 168K /mnt/.ix-apps lz4 128K +fast.storage.rushg.me/ix-apps/app_configs 61.0M 2.04T 44.3M /mnt/.ix-apps/app_configs lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts 6.28G 2.04T 152K /mnt/.ix-apps/app_mounts lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/gitea 12.2M 2.04T 96K /mnt/.ix-apps/app_mounts/gitea lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/gitea/postgres_data 12.1M 2.04T 12.0M /mnt/.ix-apps/app_mounts/gitea/postgres_data lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/invidious 12.7M 2.04T 104K /mnt/.ix-apps/app_mounts/invidious lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/invidious/companion_cache 96K 2.04T 96K /mnt/.ix-apps/app_mounts/invidious/companion_cache lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/invidious/config 140K 2.04T 100K /mnt/.ix-apps/app_mounts/invidious/config lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/invidious/postgres_data 12.3M 2.04T 12.3M /mnt/.ix-apps/app_mounts/invidious/postgres_data lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/open-webui 887M 2.04T 96K /mnt/.ix-apps/app_mounts/open-webui lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/open-webui/data 887M 2.04T 887M /mnt/.ix-apps/app_mounts/open-webui/data lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/paperless-ngx 15.8M 2.04T 112K /mnt/.ix-apps/app_mounts/paperless-ngx lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/paperless-ngx/consume 96K 2.04T 96K /mnt/.ix-apps/app_mounts/paperless-ngx/consume lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/paperless-ngx/data 208K 2.04T 184K /mnt/.ix-apps/app_mounts/paperless-ngx/data lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/paperless-ngx/media 120K 2.04T 120K /mnt/.ix-apps/app_mounts/paperless-ngx/media lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/paperless-ngx/postgres_data 15.2M 2.04T 15.2M /mnt/.ix-apps/app_mounts/paperless-ngx/postgres_data lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/paperless-ngx/trash 96K 2.04T 96K /mnt/.ix-apps/app_mounts/paperless-ngx/trash lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/photoprism 192K 2.04T 96K /mnt/.ix-apps/app_mounts/photoprism lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/photoprism/originals 96K 2.04T 96K /mnt/.ix-apps/app_mounts/photoprism/originals lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/portracker 244K 2.04T 96K /mnt/.ix-apps/app_mounts/portracker lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/portracker/data 148K 2.04T 100K /mnt/.ix-apps/app_mounts/portracker/data lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/searxng 420K 2.04T 96K /mnt/.ix-apps/app_mounts/searxng lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/searxng/config 324K 2.04T 160K /mnt/.ix-apps/app_mounts/searxng/config lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/steam-headless 5.36G 2.04T 104K /mnt/.ix-apps/app_mounts/steam-headless lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/steam-headless/games 104K 2.04T 104K /mnt/.ix-apps/app_mounts/steam-headless/games lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/steam-headless/home 5.36G 2.04T 4.03G /mnt/.ix-apps/app_mounts/steam-headless/home lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/steam-headless/pulse_socket 368K 2.04T 96K /mnt/.ix-apps/app_mounts/steam-headless/pulse_socket lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/steam-headless/x11_socket 800K 2.04T 148K /mnt/.ix-apps/app_mounts/steam-headless/x11_socket lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/vaultwarden 13.1M 2.04T 96K /mnt/.ix-apps/app_mounts/vaultwarden lz4 128K +fast.storage.rushg.me/ix-apps/app_mounts/vaultwarden/postgres_data 13.0M 2.04T 12.9M /mnt/.ix-apps/app_mounts/vaultwarden/postgres_data lz4 128K +fast.storage.rushg.me/ix-apps/docker 313G 2.04T 283G /mnt/.ix-apps/docker lz4 128K +fast.storage.rushg.me/ix-apps/truenas_catalog 768M 2.04T 250M /mnt/.ix-apps/truenas_catalog lz4 128K +fast.storage.rushg.me/rushabh 1.61M 2.04T 268K /mnt/fast.storage.rushg.me/rushabh lz4 128K +storage.rushg.me 37.9T 9.27T 167K /mnt/storage.rushg.me gzip-9 512K +storage.rushg.me/.system 322K 9.27T 120K legacy gzip-9 512K +storage.rushg.me/.system/vm 202K 9.27T 202K legacy gzip-9 512K +storage.rushg.me/apps 1019G 9.27T 163K /mnt/storage.rushg.me/apps gzip-9 512K +storage.rushg.me/apps/ddns 1.89M 9.27T 1.61M /mnt/storage.rushg.me/apps/ddns gzip-9 512K +storage.rushg.me/apps/gitea 3.14M 9.27T 2.94M /mnt/storage.rushg.me/apps/gitea gzip-9 512K +storage.rushg.me/apps/immich 462G 9.27T 2.78G /mnt/storage.rushg.me/apps/immich gzip-9 512K +storage.rushg.me/apps/immich/library 38.6G 9.27T 38.6G /mnt/storage.rushg.me/apps/immich/library gzip-9 512K +storage.rushg.me/apps/immich/pgData 1.74G 9.27T 1.23G /mnt/storage.rushg.me/apps/immich/pgData gzip-9 512K +storage.rushg.me/apps/immich/profile 402K 9.27T 121K /mnt/storage.rushg.me/apps/immich/profile gzip-9 512K +storage.rushg.me/apps/immich/thumbs 30.9G 9.27T 30.7G /mnt/storage.rushg.me/apps/immich/thumbs gzip-9 512K +storage.rushg.me/apps/immich/uploads 319G 9.27T 319G /mnt/storage.rushg.me/apps/immich/uploads gzip-9 512K +storage.rushg.me/apps/immich/video 66.2G 9.27T 66.2G /mnt/storage.rushg.me/apps/immich/video gzip-9 512K +storage.rushg.me/apps/jellyfin 1.64G 9.27T 102K /mnt/storage.rushg.me/apps/jellyfin gzip-9 512K +storage.rushg.me/apps/jellyfin/cache 3.89M 9.27T 3.89M /mnt/storage.rushg.me/apps/jellyfin/cache gzip-9 512K +storage.rushg.me/apps/jellyfin/config 1.64G 9.27T 1.64G /mnt/storage.rushg.me/apps/jellyfin/config gzip-9 512K +storage.rushg.me/apps/metube 26.4G 9.27T 22.4G /mnt/storage.rushg.me/apps/metube gzip-9 512K +storage.rushg.me/apps/photoprism 526G 9.27T 110K /mnt/storage.rushg.me/apps/photoprism gzip-9 512K +storage.rushg.me/apps/photoprism/originals 460G 9.27T 460G /mnt/storage.rushg.me/apps/photoprism/originals gzip-9 512K +storage.rushg.me/apps/photoprism/storage 65.7G 9.27T 44.8G /mnt/storage.rushg.me/apps/photoprism/storage gzip-9 512K +storage.rushg.me/apps/plex 1.92G 9.27T 1.92G /mnt/storage.rushg.me/apps/plex gzip-9 512K +storage.rushg.me/apps/vaultwarden 5.31M 9.27T 5.17M /mnt/storage.rushg.me/apps/vaultwarden gzip-9 512K +storage.rushg.me/backups 1.02T 9.27T 6.74G /mnt/storage.rushg.me/backups gzip-9 512K +storage.rushg.me/backups/windows 501G 9.27T 501G /mnt/storage.rushg.me/backups/windows gzip-9 512K +storage.rushg.me/backups/windowsv2 533G 9.27T 533G /mnt/storage.rushg.me/backups/windowsv2 gzip-9 512K +storage.rushg.me/data 32.9T 9.27T 1.09T /mnt/storage.rushg.me/data gzip-9 512K +storage.rushg.me/data/family 266K 9.27T 139K /mnt/storage.rushg.me/data/family gzip-9 512K +storage.rushg.me/data/family/trishala.cloud 127K 9.27T 127K /mnt/storage.rushg.me/data/family/trishala.cloud gzip-9 512K +storage.rushg.me/data/media 20.4T 9.27T 20.1T /mnt/storage.rushg.me/data/media gzip-9 512K +storage.rushg.me/data/mediaV2 3.92T 9.27T 3.90T /mnt/storage.rushg.me/data/mediaV2 gzip-9 512K +storage.rushg.me/data/mediaV2/downloaded 96K 9.27T 96K /mnt/storage.rushg.me/data/mediaV2/downloaded gzip-9 512K +storage.rushg.me/data/softwares 4.55T 9.27T 4.36T /mnt/storage.rushg.me/data/softwares gzip-9 512K +storage.rushg.me/data/z5 2.98T 9.27T 2.98T /mnt/storage.rushg.me/data/z5 gzip-9 512K +storage.rushg.me/fast-backup 841G 9.27T 261M /mnt/storage.rushg.me/fast-backup lz4 128K +storage.rushg.me/fast-backup/.ix-virt 178G 9.27T 120K /mnt/storage.rushg.me/fast-backup/.ix-virt lz4 128K +storage.rushg.me/fast-backup/.ix-virt/buckets 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/.ix-virt/buckets lz4 128K +storage.rushg.me/fast-backup/.ix-virt/containers 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/.ix-virt/containers lz4 128K +storage.rushg.me/fast-backup/.ix-virt/custom 178G 9.27T 96K /mnt/storage.rushg.me/fast-backup/.ix-virt/custom lz4 128K +storage.rushg.me/fast-backup/.ix-virt/custom/default_VisionRootVolume 32.1G 9.27T 32.1G - lz4 - +storage.rushg.me/fast-backup/.ix-virt/custom/default_Win10_22H2_English_x64v1.iso.iso 7.50G 9.27T 7.50G - lz4 - +storage.rushg.me/fast-backup/.ix-virt/custom/default_haos 16.8G 9.27T 7.34G - lz4 - +storage.rushg.me/fast-backup/.ix-virt/custom/default_windowsCopy 84.8G 9.27T 79.3G - lz4 - +storage.rushg.me/fast-backup/.ix-virt/custom/default_windowsPrivacy 37.2G 9.27T 37.2G - lz4 - +storage.rushg.me/fast-backup/.ix-virt/deleted 736K 9.27T 104K /mnt/storage.rushg.me/fast-backup/.ix-virt/deleted lz4 128K +storage.rushg.me/fast-backup/.ix-virt/deleted/buckets 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/.ix-virt/deleted/buckets lz4 128K +storage.rushg.me/fast-backup/.ix-virt/deleted/containers 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/.ix-virt/deleted/containers lz4 128K +storage.rushg.me/fast-backup/.ix-virt/deleted/custom 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/.ix-virt/deleted/custom lz4 128K +storage.rushg.me/fast-backup/.ix-virt/deleted/images 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/.ix-virt/deleted/images lz4 128K +storage.rushg.me/fast-backup/.ix-virt/deleted/virtual-machines 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/.ix-virt/deleted/virtual-machines lz4 128K +storage.rushg.me/fast-backup/.ix-virt/images 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/.ix-virt/images lz4 128K +storage.rushg.me/fast-backup/.ix-virt/virtual-machines 30.4M 9.27T 96K /mnt/storage.rushg.me/fast-backup/.ix-virt/virtual-machines lz4 128K +storage.rushg.me/fast-backup/.ix-virt/virtual-machines/homeassistant 8.88M 491M 8.30M /mnt/storage.rushg.me/fast-backup/.ix-virt/virtual-machines/homeassistant lz4 128K +storage.rushg.me/fast-backup/.ix-virt/virtual-machines/homeassistant.block 64K 9.27T 56K - lz4 - +storage.rushg.me/fast-backup/.ix-virt/virtual-machines/winPriv 6.13M 494M 5.96M /mnt/storage.rushg.me/fast-backup/.ix-virt/virtual-machines/winPriv lz4 128K +storage.rushg.me/fast-backup/.ix-virt/virtual-machines/winPriv.block 64K 9.27T 56K - lz4 - +storage.rushg.me/fast-backup/.ix-virt/virtual-machines/windows10VisionMonitorApplication 6.12M 494M 5.95M /mnt/storage.rushg.me/fast-backup/.ix-virt/virtual-machines/windows10VisionMonitorApplication lz4 128K +storage.rushg.me/fast-backup/.ix-virt/virtual-machines/windows10VisionMonitorApplication.block 64K 9.27T 56K - lz4 - +storage.rushg.me/fast-backup/.ix-virt/virtual-machines/windowsAPIServer 8.84M 491M 8.33M /mnt/storage.rushg.me/fast-backup/.ix-virt/virtual-machines/windowsAPIServer lz4 128K +storage.rushg.me/fast-backup/.ix-virt/virtual-machines/windowsAPIServer.block 64K 9.27T 56K - lz4 - +storage.rushg.me/fast-backup/.system 2.26G 9.27T 1.67G /mnt/storage.rushg.me/fast-backup/.system lz4 128K +storage.rushg.me/fast-backup/.system/configs-ae32c386e13840b2bf9c0083275e7941 23.3M 9.27T 23.3M /mnt/storage.rushg.me/fast-backup/.system/configs-ae32c386e13840b2bf9c0083275e7941 lz4 128K +storage.rushg.me/fast-backup/.system/cores 104K 1024M 96K /mnt/storage.rushg.me/fast-backup/.system/cores lz4 128K +storage.rushg.me/fast-backup/.system/netdata-ae32c386e13840b2bf9c0083275e7941 577M 9.27T 577M /mnt/storage.rushg.me/fast-backup/.system/netdata-ae32c386e13840b2bf9c0083275e7941 lz4 128K +storage.rushg.me/fast-backup/.system/nfs 120K 9.27T 112K /mnt/storage.rushg.me/fast-backup/.system/nfs lz4 128K +storage.rushg.me/fast-backup/.system/samba4 546K 9.27T 538K /mnt/storage.rushg.me/fast-backup/.system/samba4 lz4 128K +storage.rushg.me/fast-backup/.system/vm 119K 9.27T 111K /mnt/storage.rushg.me/fast-backup/.system/vm lz4 128K +storage.rushg.me/fast-backup/apps 120G 9.27T 120G /mnt/storage.rushg.me/fast-backup/apps lz4 128K +storage.rushg.me/fast-backup/apps/n8n 323M 9.27T 10.4M /mnt/storage.rushg.me/fast-backup/apps/n8n lz4 128K +storage.rushg.me/fast-backup/apps/n8n/data 206M 9.27T 197M /mnt/storage.rushg.me/fast-backup/apps/n8n/data lz4 128K +storage.rushg.me/fast-backup/apps/n8n/postgres-data 107M 9.27T 47.2M /mnt/storage.rushg.me/fast-backup/apps/n8n/postgres-data lz4 128K +storage.rushg.me/fast-backup/apps/nginx 73.0M 9.27T 28.0M /mnt/storage.rushg.me/fast-backup/apps/nginx lz4 128K +storage.rushg.me/fast-backup/apps/searxng 613K 9.27T 183K /mnt/storage.rushg.me/fast-backup/apps/searxng lz4 128K +storage.rushg.me/fast-backup/ix-applications 71.2G 9.27T 6.00M /mnt/storage.rushg.me/fast-backup/ix-applications lz4 128K +storage.rushg.me/fast-backup/ix-applications/catalogs 62.1M 9.27T 62.1M /mnt/storage.rushg.me/fast-backup/ix-applications/catalogs lz4 128K +storage.rushg.me/fast-backup/ix-applications/default_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/default_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/k3s 71.1G 9.27T 71.1G /mnt/storage.rushg.me/fast-backup/ix-applications/k3s lz4 128K +storage.rushg.me/fast-backup/ix-applications/k3s/kubelet 914K 9.27T 906K /mnt/storage.rushg.me/fast-backup/ix-applications/k3s/kubelet lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases 40.3M 9.27T 176K /mnt/storage.rushg.me/fast-backup/ix-applications/releases lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/audiobookshelf 2.63M 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/audiobookshelf lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/audiobookshelf/charts 2.19M 9.27T 2.18M /mnt/storage.rushg.me/fast-backup/ix-applications/releases/audiobookshelf/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/audiobookshelf/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/audiobookshelf/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/audiobookshelf/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/audiobookshelf/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/clamav 754K 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/clamav lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/clamav/charts 298K 9.27T 290K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/clamav/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/clamav/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/clamav/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/clamav/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/clamav/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/ddns-updater 3.93M 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/ddns-updater lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/ddns-updater/charts 3.49M 9.27T 3.49M /mnt/storage.rushg.me/fast-backup/ix-applications/releases/ddns-updater/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/ddns-updater/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/ddns-updater/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/ddns-updater/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/ddns-updater/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/filebrowser 762K 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/filebrowser lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/filebrowser/charts 306K 9.27T 298K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/filebrowser/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/filebrowser/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/filebrowser/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/filebrowser/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/filebrowser/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/firefly-iii 1.46M 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/firefly-iii lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/firefly-iii/charts 1.02M 9.27T 1.01M /mnt/storage.rushg.me/fast-backup/ix-applications/releases/firefly-iii/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/firefly-iii/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/firefly-iii/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/firefly-iii/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/firefly-iii/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/immich 2.84M 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/immich lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/immich/charts 2.41M 9.27T 2.33M /mnt/storage.rushg.me/fast-backup/ix-applications/releases/immich/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/immich/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/immich/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/immich/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/immich/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/invidiousv2 761K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/invidiousv2 lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/invidiousv2/charts 313K 9.27T 305K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/invidiousv2/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/invidiousv2/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/invidiousv2/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/invidiousv2/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/invidiousv2/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/jellyfin 1.65M 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/jellyfin lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/jellyfin/charts 1.21M 9.27T 1.21M /mnt/storage.rushg.me/fast-backup/ix-applications/releases/jellyfin/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/jellyfin/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/jellyfin/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/jellyfin/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/jellyfin/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/komga 955K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/komga lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/komga/charts 507K 9.27T 499K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/komga/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/komga/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/komga/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/komga/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/komga/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/linkding 782K 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/linkding lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/linkding/charts 326K 9.27T 318K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/linkding/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/linkding/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/linkding/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/linkding/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/linkding/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/metube 2.72M 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/metube lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/metube/charts 2.28M 9.27T 2.27M /mnt/storage.rushg.me/fast-backup/ix-applications/releases/metube/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/metube/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/metube/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/metube/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/metube/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/netbootxyz 1.08M 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/netbootxyz lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/netbootxyz/charts 658K 9.27T 650K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/netbootxyz/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/netbootxyz/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/netbootxyz/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/netbootxyz/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/netbootxyz/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/netdata 2.44M 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/netdata lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/netdata/charts 2.01M 9.27T 2.00M /mnt/storage.rushg.me/fast-backup/ix-applications/releases/netdata/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/netdata/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/netdata/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/netdata/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/netdata/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/nginx-proxy-manager 896K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/nginx-proxy-manager lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/nginx-proxy-manager/charts 448K 9.27T 440K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/nginx-proxy-manager/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/nginx-proxy-manager/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/nginx-proxy-manager/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/nginx-proxy-manager/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/nginx-proxy-manager/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/ollama 704K 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/ollama lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/ollama/charts 248K 9.27T 240K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/ollama/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/ollama/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/ollama/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/ollama/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/ollama/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/open-webui 696K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/open-webui lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/open-webui/charts 248K 9.27T 240K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/open-webui/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/open-webui/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/open-webui/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/open-webui/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/open-webui/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/organizr 725K 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/organizr lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/organizr/charts 269K 9.27T 261K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/organizr/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/organizr/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/organizr/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/organizr/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/organizr/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/paperless-ngx 1.90M 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/paperless-ngx lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/paperless-ngx/charts 1.47M 9.27T 1.46M /mnt/storage.rushg.me/fast-backup/ix-applications/releases/paperless-ngx/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/paperless-ngx/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/paperless-ngx/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/paperless-ngx/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/paperless-ngx/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/pihole 754K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/pihole lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/pihole/charts 306K 9.27T 298K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/pihole/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/pihole/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/pihole/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/pihole/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/pihole/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/plex 2.28M 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/plex lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/plex/charts 1.68M 9.27T 1.67M /mnt/storage.rushg.me/fast-backup/ix-applications/releases/plex/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/plex/volumes 440K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/plex/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/plex/volumes/ix_volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/plex/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/plex/volumes/ix_volumes/logs 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/plex/volumes/ix_volumes/logs lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/prowlarrv2 2.72M 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/prowlarrv2 lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/prowlarrv2/charts 2.28M 9.27T 2.27M /mnt/storage.rushg.me/fast-backup/ix-applications/releases/prowlarrv2/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/prowlarrv2/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/prowlarrv2/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/prowlarrv2/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/prowlarrv2/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/qbittorrent 1.92M 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/qbittorrent lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/qbittorrent/charts 1.31M 9.27T 1.31M /mnt/storage.rushg.me/fast-backup/ix-applications/releases/qbittorrent/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/qbittorrent/volumes 440K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/qbittorrent/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/qbittorrent/volumes/ix_volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/qbittorrent/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/qbittorrent/volumes/ix_volumes/downloads 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/qbittorrent/volumes/ix_volumes/downloads lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/searxng 1.74M 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/searxng lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/searxng/charts 1.29M 9.27T 1.28M /mnt/storage.rushg.me/fast-backup/ix-applications/releases/searxng/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/searxng/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/searxng/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/searxng/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/searxng/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/tautulli 1.29M 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/tautulli lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/tautulli/charts 866K 9.27T 858K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/tautulli/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/tautulli/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/tautulli/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/tautulli/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/tautulli/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/vaultwarden 1.75M 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/vaultwarden lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/vaultwarden/charts 1.31M 9.27T 1.30M /mnt/storage.rushg.me/fast-backup/ix-applications/releases/vaultwarden/charts lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/vaultwarden/volumes 272K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/vaultwarden/volumes lz4 128K +storage.rushg.me/fast-backup/ix-applications/releases/vaultwarden/volumes/ix_volumes 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-applications/releases/vaultwarden/volumes/ix_volumes lz4 128K +storage.rushg.me/fast-backup/ix-apps 469G 9.27T 302K /mnt/storage.rushg.me/fast-backup/ix-apps lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_configs 416M 9.27T 350M /mnt/storage.rushg.me/fast-backup/ix-apps/app_configs lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts 141G 9.27T 184K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/clamav 283M 9.27T 112K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/clamav lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/clamav/scan-dir 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/clamav/scan-dir lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/clamav/sig-db 283M 9.27T 283M /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/clamav/sig-db lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/ddns-updater1 2.06M 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/ddns-updater1 lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/ddns-updater1/data 1.95M 9.27T 1.94M /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/ddns-updater1/data lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/filebrowser 420K 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/filebrowser lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/filebrowser/config 308K 9.27T 111K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/filebrowser/config lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/immich 350M 9.27T 136K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/immich lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/immich/library 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/immich/library lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/immich/pgBackup 350M 9.27T 350M /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/immich/pgBackup lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/immich/profile 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/immich/profile lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/immich/thumbs 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/immich/thumbs lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/immich/uploads 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/immich/uploads lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/immich/video 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/immich/video lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/invidious-private 216K 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/invidious-private lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/invidious-private/companion_cache 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/invidious-private/companion_cache lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/invidious-public 216K 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/invidious-public lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/invidious-public/companion_cache 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/invidious-public/companion_cache lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/jellyfin 2.08G 9.27T 112K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/jellyfin lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/jellyfin/cache 18.5M 9.27T 18.2M /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/jellyfin/cache lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/jellyfin/config 2.06G 9.27T 1.96G /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/jellyfin/config lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/komga 13.1M 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/komga lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/komga/config 13.0M 9.27T 11.4M /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/komga/config lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/metube 216K 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/metube lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/metube/downloads 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/metube/downloads lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/netdata 1.97G 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/netdata lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/netdata/cache 1.97G 9.27T 1.09G /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/netdata/cache lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/netdata/config 405K 9.27T 141K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/netdata/config lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/netdata/lib 815K 9.27T 174K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/netdata/lib lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/nginx-proxy-manager 328K 9.27T 112K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/nginx-proxy-manager lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/nginx-proxy-manager/certs 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/nginx-proxy-manager/certs lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/nginx-proxy-manager/data 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/nginx-proxy-manager/data lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/ollama 98.1G 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/ollama lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/ollama/data 98.1G 9.27T 98.1G /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/ollama/data lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/pihole 1.21G 9.27T 112K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/pihole lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/pihole/config 1.21G 9.27T 1.21G /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/pihole/config lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/pihole/dnsmasq 134K 9.27T 126K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/pihole/dnsmasq lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/plex 37.0G 9.27T 120K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/plex lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/plex/config 37.0G 9.27T 37.0G /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/plex/config lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/plex/data 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/plex/data lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/plex/transcode 152K 9.27T 144K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/plex/transcode lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/plexv2 17.4M 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/plexv2 lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/plexv2/config 17.2M 9.27T 17.2M /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/plexv2/config lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/plexv2/data 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/plexv2/data lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/portainer 1.39M 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/portainer lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/portainer/data 1.29M 9.27T 1.28M /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/portainer/data lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/prowlarrv2 13.2M 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/prowlarrv2 lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/prowlarrv2/config 13.1M 9.27T 6.61M /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/prowlarrv2/config lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/qbittorrent 7.25M 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/qbittorrent lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/qbittorrent/config 7.14M 9.27T 4.33M /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/qbittorrent/config lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/rust-desk 245K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/rust-desk lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/rust-desk/data 141K 9.27T 133K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/rust-desk/data lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/scrutiny 12.9M 9.27T 112K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/scrutiny lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/scrutiny/config 744K 9.27T 110K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/scrutiny/config lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/scrutiny/influxdb 12.1M 9.27T 5.10M /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/scrutiny/influxdb lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/searxng 289K 9.27T 104K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/searxng lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/searxng/config 177K 9.27T 169K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/searxng/config lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/vaultwarden 23.7M 9.27T 112K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/vaultwarden lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/vaultwarden/data 104K 9.27T 96K /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/vaultwarden/data lz4 128K +storage.rushg.me/fast-backup/ix-apps/app_mounts/vaultwarden/pgData 23.5M 9.27T 22.1M /mnt/storage.rushg.me/fast-backup/ix-apps/app_mounts/vaultwarden/pgData lz4 128K +storage.rushg.me/fast-backup/ix-apps/docker 326G 9.27T 316G /mnt/storage.rushg.me/fast-backup/ix-apps/docker lz4 128K +storage.rushg.me/fast-backup/ix-apps/truenas_catalog 1.29G 9.27T 399M /mnt/storage.rushg.me/fast-backup/ix-apps/truenas_catalog lz4 128K +storage.rushg.me/fast-backupv2 2.20T 9.27T 104K /mnt/storage.rushg.me/fast-backupv2 lz4 512K +storage.rushg.me/fast-backupv2/.ix-virt 1.93G 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/.ix-virt lz4 512K +storage.rushg.me/fast-backupv2/.ix-virt/buckets 96K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/.ix-virt/buckets lz4 512K +storage.rushg.me/fast-backupv2/.ix-virt/containers 96K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/.ix-virt/containers lz4 512K +storage.rushg.me/fast-backupv2/.ix-virt/custom 96K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/.ix-virt/custom lz4 512K +storage.rushg.me/fast-backupv2/.ix-virt/deleted 576K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/.ix-virt/deleted lz4 512K +storage.rushg.me/fast-backupv2/.ix-virt/deleted/buckets 96K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/.ix-virt/deleted/buckets lz4 512K +storage.rushg.me/fast-backupv2/.ix-virt/deleted/containers 96K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/.ix-virt/deleted/containers lz4 512K +storage.rushg.me/fast-backupv2/.ix-virt/deleted/custom 96K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/.ix-virt/deleted/custom lz4 512K +storage.rushg.me/fast-backupv2/.ix-virt/deleted/images 96K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/.ix-virt/deleted/images lz4 512K +storage.rushg.me/fast-backupv2/.ix-virt/deleted/virtual-machines 96K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/.ix-virt/deleted/virtual-machines lz4 512K +storage.rushg.me/fast-backupv2/.ix-virt/images 1.93G 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/.ix-virt/images lz4 512K +storage.rushg.me/fast-backupv2/.ix-virt/images/48b9efb034aeb2e24e9f48519de3796080a097e251acce6b694680fba4fadd99 402M 9.27T 402M /mnt/storage.rushg.me/fast-backupv2/.ix-virt/images/48b9efb034aeb2e24e9f48519de3796080a097e251acce6b694680fba4fadd99 lz4 512K +storage.rushg.me/fast-backupv2/.ix-virt/images/52184386ae914de6bf575dc5f35dfc7745e9a0464eb4c49347e1cb390d775842 403M 9.27T 403M /mnt/storage.rushg.me/fast-backupv2/.ix-virt/images/52184386ae914de6bf575dc5f35dfc7745e9a0464eb4c49347e1cb390d775842 lz4 512K +storage.rushg.me/fast-backupv2/.ix-virt/images/5ca42d449023c3be1ebe8b581c9efe74592e1ff7da23b1d70cf35ead7a46d299 392M 9.27T 392M /mnt/storage.rushg.me/fast-backupv2/.ix-virt/images/5ca42d449023c3be1ebe8b581c9efe74592e1ff7da23b1d70cf35ead7a46d299 lz4 512K +storage.rushg.me/fast-backupv2/.ix-virt/images/81f913f33dacf1bcdb6a5d0d7467840eb199fab0cb3b91b17f38e20af9d55e15 385M 9.27T 385M /mnt/storage.rushg.me/fast-backupv2/.ix-virt/images/81f913f33dacf1bcdb6a5d0d7467840eb199fab0cb3b91b17f38e20af9d55e15 lz4 512K +storage.rushg.me/fast-backupv2/.ix-virt/images/fba08112bff23fb0f06f7612e8adabf965b609368872b0667c96e5c834da085d 395M 9.27T 395M /mnt/storage.rushg.me/fast-backupv2/.ix-virt/images/fba08112bff23fb0f06f7612e8adabf965b609368872b0667c96e5c834da085d lz4 512K +storage.rushg.me/fast-backupv2/.ix-virt/virtual-machines 96K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/.ix-virt/virtual-machines lz4 512K +storage.rushg.me/fast-backupv2/datasets 1.85T 9.27T 284K /mnt/storage.rushg.me/fast-backupv2/datasets gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps 1.63T 9.27T 36.2G /mnt/storage.rushg.me/fast-backupv2/datasets/apps gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/bichon 320K 9.27T 320K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/bichon gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/comfyui 185G 9.27T 1.04G /mnt/storage.rushg.me/fast-backupv2/datasets/apps/comfyui gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/comfyui/input 4.28M 9.27T 4.28M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/comfyui/input gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/comfyui/models 183G 9.27T 183G /mnt/storage.rushg.me/fast-backupv2/datasets/apps/comfyui/models gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/comfyui/output 215M 9.27T 215M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/comfyui/output gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/filebrowser 626K 9.27T 124K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/filebrowser gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/gatus 170K 9.27T 170K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/gatus gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/gitea 1.31G 9.27T 104K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/gitea gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/gitea/config 103K 9.27T 103K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/gitea/config gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/gitea/data 1.29G 9.27T 1.29G /mnt/storage.rushg.me/fast-backupv2/datasets/apps/gitea/data gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/gitea/postgres 21.0M 9.27T 13.7M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/gitea/postgres gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/immich 698G 9.27T 124K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/immich gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/immich/data 697G 9.27T 696G /mnt/storage.rushg.me/fast-backupv2/datasets/apps/immich/data gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/immich/mlcache 133K 9.27T 133K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/immich/mlcache gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/immich/pgData 1.20G 9.27T 419M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/immich/pgData gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/immich/postgres-data 137M 9.27T 137M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/immich/postgres-data gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/immichV3 580G 9.27T 104K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/immichV3 gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/immichV3/data 580G 9.27T 580G /mnt/storage.rushg.me/fast-backupv2/datasets/apps/immichV3/data gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/immichV3/postgres-data 13.2M 9.27T 13.2M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/immichV3/postgres-data gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/invidious-internal 839M 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/invidious-internal gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/invidious-internal/cache 96K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/invidious-internal/cache gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/invidious-internal/config 327K 9.27T 128K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/invidious-internal/config gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/invidious-internal/pgData 838M 9.27T 23.5M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/invidious-internal/pgData gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/invidious-public 645M 9.27T 185K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/invidious-public gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/invidious-public/cache 164K 9.27T 164K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/invidious-public/cache gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/invidious-public/config 370K 9.27T 171K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/invidious-public/config gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/invidious-public/pgData 644M 9.27T 23.7M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/invidious-public/pgData gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/komga 86.5M 9.27T 12.0M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/komga gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/llama-cpp.models 23.9G 9.27T 23.9G /mnt/storage.rushg.me/fast-backupv2/datasets/apps/llama-cpp.models gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/n8n 2.32G 9.27T 118K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/n8n gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/n8n/data 344M 9.27T 247M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/n8n/data gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/n8n/postgres-data 1.98G 9.27T 311M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/n8n/postgres-data gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/netboot 1.74G 9.27T 104K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/netboot gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/netboot/assets 1.73G 9.27T 1.73G /mnt/storage.rushg.me/fast-backupv2/datasets/apps/netboot/assets gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/netboot/config 11.2M 9.27T 8.85M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/netboot/config gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/netdata 17.9G 9.27T 112K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/netdata gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/netdata/cache 17.8G 9.27T 1.34G /mnt/storage.rushg.me/fast-backupv2/datasets/apps/netdata/cache gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/netdata/config 759K 9.27T 177K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/netdata/config gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/netdata/lib 38.3M 9.27T 224K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/netdata/lib gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/ollama.models 114G 9.27T 109G /mnt/storage.rushg.me/fast-backupv2/datasets/apps/ollama.models gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/openwebui 2.17G 9.27T 1.28G /mnt/storage.rushg.me/fast-backupv2/datasets/apps/openwebui gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/openwebui/data 867M 9.27T 867M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/openwebui/data gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/organizr 304M 9.27T 218M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/organizr gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/paperless 230M 9.27T 192K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/paperless gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/paperless-ai 241K 9.27T 241K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/paperless-ai gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/paperless/consume 466K 9.27T 139K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/paperless/consume gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/paperless/data 43.2M 9.27T 917K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/paperless/data gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/paperless/media 5.26M 9.27T 4.85M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/paperless/media gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/paperless/paperless-ai.data 769K 9.27T 279K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/paperless/paperless-ai.data gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/paperless/postgres-data 179M 9.27T 20.0M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/paperless/postgres-data gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/paperless/trash 466K 9.27T 139K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/paperless/trash gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/pihole 1.18G 9.27T 104K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/pihole gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/pihole/config 1.18G 9.27T 45.4M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/pihole/config gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/pihole/dnsmasq 96K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/pihole/dnsmasq gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/playwright 22.3M 9.27T 22.3M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/playwright gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/plex 4.47G 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/plex gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/plex/config 4.47G 9.27T 3.61G /mnt/storage.rushg.me/fast-backupv2/datasets/apps/plex/config gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/plex/data 96K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/plex/data gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/qbittorrent 52.5M 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/qbittorrent gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/qbittorrent/config 52.4M 9.27T 3.99M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/qbittorrent/config gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/retrom 308M 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/retrom gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/retrom/config 103K 9.27T 103K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/retrom/config gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/retrom/data 308M 9.27T 308M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/retrom/data gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/rustdesk 103K 9.27T 103K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/rustdesk gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/searxng 1.32M 9.27T 212K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/searxng gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/trillium 75.2M 9.27T 6.63M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/trillium gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/vaultwarden 21.1M 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/datasets/apps/vaultwarden gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/vaultwarden/data 2.41M 9.27T 2.33M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/vaultwarden/data gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/apps/vaultwarden/postgres 18.6M 9.27T 15.8M /mnt/storage.rushg.me/fast-backupv2/datasets/apps/vaultwarden/postgres gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/containers 96K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/datasets/containers gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/scripts 5.12M 9.27T 1.17M /mnt/storage.rushg.me/fast-backupv2/datasets/scripts gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/vms 227G 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/datasets/vms gzip-9 512K +storage.rushg.me/fast-backupv2/datasets/vms/homeassistant_ported 38.3G 9.27T 17.6G - gzip-9 - +storage.rushg.me/fast-backupv2/datasets/vms/ubuntu 19.1G 9.27T 13.6G - gzip-9 - +storage.rushg.me/fast-backupv2/datasets/vms/webserver_ubuntu 18.1G 9.27T 18.1G - gzip-9 - +storage.rushg.me/fast-backupv2/datasets/vms/windows11APIServer 40.0G 9.27T 40.0G - gzip-9 - +storage.rushg.me/fast-backupv2/datasets/vms/windowsAPIServer 112G 9.27T 66.9G - gzip-9 - +storage.rushg.me/fast-backupv2/ix-apps 348G 9.27T 184K /mnt/storage.rushg.me/fast-backupv2/ix-apps lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_configs 100M 9.27T 75.3M /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_configs lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts 8.28G 9.27T 239K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/anything-llm 319K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/anything-llm lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/anything-llm/data 223K 9.27T 223K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/anything-llm/data lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/bichon 504K 9.27T 170K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/bichon lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/bichon/data 334K 9.27T 334K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/bichon/data lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/clamav 283M 9.27T 104K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/clamav lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/clamav/scandir 96K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/clamav/scandir lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/clamav/sigdb 283M 9.27T 283M /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/clamav/sigdb lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/code-server 557K 9.27T 112K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/code-server lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/code-server/config 96K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/code-server/config lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/code-server/local 210K 9.27T 210K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/code-server/local lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/code-server/project 139K 9.27T 139K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/code-server/project lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/gitea 14.6M 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/gitea lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/gitea/postgres_data 14.5M 9.27T 14.5M /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/gitea/postgres_data lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/invidious 16.0M 9.27T 185K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/invidious lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/invidious/companion_cache 170K 9.27T 170K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/invidious/companion_cache lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/invidious/config 178K 9.27T 178K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/invidious/config lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/invidious/postgres_data 15.4M 9.27T 15.4M /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/invidious/postgres_data lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/next-explorer 347K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/next-explorer lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/next-explorer/config 251K 9.27T 251K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/next-explorer/config lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/open-webui 886M 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/open-webui lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/open-webui/data 886M 9.27T 886M /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/open-webui/data lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/paperless-ngx 20.0M 9.27T 199K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/paperless-ngx lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/paperless-ngx/consume 170K 9.27T 170K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/paperless-ngx/consume lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/paperless-ngx/data 327K 9.27T 327K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/paperless-ngx/data lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/paperless-ngx/media 213K 9.27T 213K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/paperless-ngx/media lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/paperless-ngx/postgres_data 18.9M 9.27T 18.9M /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/paperless-ngx/postgres_data lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/paperless-ngx/trash 170K 9.27T 170K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/paperless-ngx/trash lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/photoprism 279K 9.27T 121K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/photoprism lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/photoprism/originals 158K 9.27T 158K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/photoprism/originals lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/playwright 31.9M 9.27T 127K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/playwright lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/playwright/pwuser_home 31.8M 9.27T 31.8M /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/playwright/pwuser_home lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/portainer 258K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/portainer lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/portainer/data 162K 9.27T 162K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/portainer/data lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/portracker 199K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/portracker lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/portracker/data 103K 9.27T 103K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/portracker/data lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/qdirstat 560K 9.27T 121K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/qdirstat lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/qdirstat/storage_entry 440K 9.27T 440K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/qdirstat/storage_entry lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/searxng 343K 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/searxng lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/searxng/config 247K 9.27T 175K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/searxng/config lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headless 5.86G 9.27T 104K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headless lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headless/games 104K 9.27T 104K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headless/games lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headless/home 5.86G 9.27T 4.43G /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headless/home lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headless/pulse_socket 575K 9.27T 146K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headless/pulse_socket lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headless/x11_socket 1.26M 9.27T 232K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headless/x11_socket lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headlessv2 1.16G 9.27T 199K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headlessv2 lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headlessv2/games 172K 9.27T 172K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headlessv2/games lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headlessv2/home 1.16G 9.27T 1.16G /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headlessv2/home lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headlessv2/pulse_socket 170K 9.27T 170K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headlessv2/pulse_socket lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headlessv2/x11_socket 256K 9.27T 256K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/steam-headlessv2/x11_socket lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/tianji 17.0M 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/tianji lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/tianji/postgres_data 16.9M 9.27T 16.9M /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/tianji/postgres_data lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/vaultwarden 15.6M 9.27T 96K /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/vaultwarden lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/app_mounts/vaultwarden/postgres_data 15.5M 9.27T 15.5M /mnt/storage.rushg.me/fast-backupv2/ix-apps/app_mounts/vaultwarden/postgres_data lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/docker 339G 9.27T 308G /mnt/storage.rushg.me/fast-backupv2/ix-apps/docker lz4 512K +storage.rushg.me/fast-backupv2/ix-apps/truenas_catalog 866M 9.27T 443M /mnt/storage.rushg.me/fast-backupv2/ix-apps/truenas_catalog lz4 512K +storage.rushg.me/fast-backupv2/rushabh 2.55M 9.27T 361K /mnt/storage.rushg.me/fast-backupv2/rushabh lz4 512K +storage.rushg.me/ix-apps 377M 9.27T 112K /mnt/.ix-apps gzip-9 512K +storage.rushg.me/ix-apps/app_configs 96K 9.27T 96K /mnt/.ix-apps/app_configs gzip-9 512K +storage.rushg.me/ix-apps/app_mounts 96K 9.27T 96K /mnt/.ix-apps/app_mounts gzip-9 512K +storage.rushg.me/ix-apps/docker 491K 9.27T 491K /mnt/.ix-apps/docker gzip-9 512K +storage.rushg.me/ix-apps/truenas_catalog 376M 9.27T 376M /mnt/.ix-apps/truenas_catalog gzip-9 512K +``` + +## Storage > Datasets +Dataset summary (name type mountpoint used avail compression recordsize atime sync quota refquota reservation refreservation encrypted key_loaded): +```text +fast.storage.rushg.me FILESYSTEM /mnt/fast.storage.rushg.me 1.52 TiB 2.04 TiB LZ4 128K OFF STANDARD None None None None False False +fast.storage.rushg.me/datasets FILESYSTEM /mnt/fast.storage.rushg.me/datasets 1.2 TiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps 1.08 TiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/n8n FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/n8n 2.11 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/n8n/data FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/n8n/data 297.94 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/n8n/postgres-data FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/n8n/postgres-data 1.82 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/comfyui FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/comfyui 183.23 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/comfyui/input FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/comfyui/input 4.27 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/comfyui/output FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/comfyui/output 213.56 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/comfyui/models FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/comfyui/models 181.85 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/trillium FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/trillium 59.74 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/llama-cpp.models FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/llama-cpp.models 23.96 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/netdata FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/netdata 17.21 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/netdata/cache FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/netdata/cache 17.19 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/netdata/config FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/netdata/config 572 KiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/netdata/lib FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/netdata/lib 24.85 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/paperless FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/paperless 164.47 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/paperless/trash FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/paperless/trash 344 KiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/paperless/data FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/paperless/data 28.09 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/paperless/paperless-ai.data FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/paperless/paperless-ai.data 452 KiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/paperless/media FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/paperless/media 5.07 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/paperless/consume FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/paperless/consume 344 KiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/paperless/postgres-data FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/paperless/postgres-data 130.06 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/organizr FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/organizr 265.61 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/pihole FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/pihole 1.1 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/pihole/config FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/pihole/config 1.1 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/pihole/dnsmasq FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/pihole/dnsmasq 96 KiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/immich FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/immich 721.53 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/immich/data FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/immich/data 720.29 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/immich/mlcache FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/immich/mlcache 96 KiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/immich/pgData FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/immich/pgData 1.24 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/komga FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/komga 63.51 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/searxng FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/searxng 1.01 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/invidious-internal FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/invidious-internal 716.46 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/invidious-internal/pgData FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/invidious-internal/pgData 716.07 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/invidious-internal/config FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/invidious-internal/config 212 KiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/invidious-internal/cache FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/invidious-internal/cache 96 KiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/netboot FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/netboot 1.74 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/netboot/assets FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/netboot/assets 1.73 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/netboot/config FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/netboot/config 8.91 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/qbittorrent FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/qbittorrent 35.25 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/qbittorrent/config FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/qbittorrent/config 35.16 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/gitea FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/gitea 1.31 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/gitea/config FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/gitea/config 100 KiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/gitea/data FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/gitea/data 1.29 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/gitea/postgres FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/gitea/postgres 16.04 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/retrom FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/retrom 305.12 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/retrom/config FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/retrom/config 100 KiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/retrom/data FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/retrom/data 304.93 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/filebrowser FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/filebrowser 528 KiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/openwebui FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/openwebui 2.15 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/openwebui/data FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/openwebui/data 867.19 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/bichon FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/bichon 180 KiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/invidious-public FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/invidious-public 541.9 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/invidious-public/config FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/invidious-public/config 212 KiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/invidious-public/cache FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/invidious-public/cache 96 KiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/invidious-public/pgData FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/invidious-public/pgData 541.5 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/vaultwarden FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/vaultwarden 17.81 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/vaultwarden/postgres FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/vaultwarden/postgres 15.57 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/vaultwarden/data FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/vaultwarden/data 2.14 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/ollama.models FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/ollama.models 113.51 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/plex FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/plex 4.22 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/plex/data FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/plex/data 96 KiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/apps/plex/config FILESYSTEM /mnt/fast.storage.rushg.me/datasets/apps/plex/config 4.22 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/scripts FILESYSTEM /mnt/fast.storage.rushg.me/datasets/scripts 3.24 MiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/vms FILESYSTEM /mnt/fast.storage.rushg.me/datasets/vms 121.57 GiB 2.04 TiB GZIP-9 128K OFF DISABLED None None None None False False +fast.storage.rushg.me/datasets/vms/homeassistant_ported VOLUME None 27.59 GiB 2.04 TiB GZIP-9 DISABLED None None False False +fast.storage.rushg.me/datasets/vms/ubuntu VOLUME None 12.84 GiB 2.04 TiB GZIP-9 DISABLED None None False False +fast.storage.rushg.me/datasets/vms/windowsAPIServer VOLUME None 81.14 GiB 2.04 TiB GZIP-9 DISABLED None None False False +fast.storage.rushg.me/rushabh FILESYSTEM /mnt/fast.storage.rushg.me/rushabh 1.67 MiB 2.04 TiB LZ4 128K OFF STANDARD None None None None False False +storage.rushg.me FILESYSTEM /mnt/storage.rushg.me 37.93 TiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps FILESYSTEM /mnt/storage.rushg.me/apps 1018.52 GiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps/vaultwarden FILESYSTEM /mnt/storage.rushg.me/apps/vaultwarden 5.31 MiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps/metube FILESYSTEM /mnt/storage.rushg.me/apps/metube 26.43 GiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps/jellyfin FILESYSTEM /mnt/storage.rushg.me/apps/jellyfin 1.64 GiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps/jellyfin/cache FILESYSTEM /mnt/storage.rushg.me/apps/jellyfin/cache 3.89 MiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps/jellyfin/config FILESYSTEM /mnt/storage.rushg.me/apps/jellyfin/config 1.64 GiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps/plex FILESYSTEM /mnt/storage.rushg.me/apps/plex 1.92 GiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps/ddns FILESYSTEM /mnt/storage.rushg.me/apps/ddns 1.89 MiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps/photoprism FILESYSTEM /mnt/storage.rushg.me/apps/photoprism 526.09 GiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps/photoprism/storage FILESYSTEM /mnt/storage.rushg.me/apps/photoprism/storage 65.73 GiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps/photoprism/originals FILESYSTEM /mnt/storage.rushg.me/apps/photoprism/originals 460.36 GiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps/gitea FILESYSTEM /mnt/storage.rushg.me/apps/gitea 3.14 MiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps/immich FILESYSTEM /mnt/storage.rushg.me/apps/immich 462.43 GiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps/immich/video FILESYSTEM /mnt/storage.rushg.me/apps/immich/video 66.21 GiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps/immich/uploads FILESYSTEM /mnt/storage.rushg.me/apps/immich/uploads 319.12 GiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps/immich/pgData FILESYSTEM /mnt/storage.rushg.me/apps/immich/pgData 1.74 GiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps/immich/profile FILESYSTEM /mnt/storage.rushg.me/apps/immich/profile 401.62 KiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps/immich/thumbs FILESYSTEM /mnt/storage.rushg.me/apps/immich/thumbs 30.88 GiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/apps/immich/library FILESYSTEM /mnt/storage.rushg.me/apps/immich/library 38.59 GiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/fast-backupv2 FILESYSTEM /mnt/storage.rushg.me/fast-backupv2 2.2 TiB 9.27 TiB LZ4 512K OFF ALWAYS None None None None False False +storage.rushg.me/fast-backupv2/datasets FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets 1.85 TiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/containers FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/containers 96 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps 1.63 TiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/filebrowser FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/filebrowser 626.18 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/gatus FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/gatus 169.71 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/bichon FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/bichon 319.57 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/qbittorrent FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/qbittorrent 52.51 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/qbittorrent/config FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/qbittorrent/config 52.42 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/immichV3 FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/immichV3 579.66 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/immichV3/data FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/immichV3/data 579.65 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/immichV3/postgres-data FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/immichV3/postgres-data 13.19 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/invidious-public FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/invidious-public 645.01 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/invidious-public/cache FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/invidious-public/cache 164.23 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/invidious-public/config FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/invidious-public/config 370.18 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/invidious-public/pgData FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/invidious-public/pgData 644.31 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/invidious-internal FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/invidious-internal 838.67 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/invidious-internal/pgData FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/invidious-internal/pgData 838.16 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/invidious-internal/config FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/invidious-internal/config 326.76 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/invidious-internal/cache FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/invidious-internal/cache 96 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/netboot FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/netboot 1.74 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/netboot/config FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/netboot/config 11.17 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/netboot/assets FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/netboot/assets 1.73 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/paperless FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/paperless 229.7 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/paperless/media FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/paperless/media 5.26 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/paperless/data FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/paperless/data 43.23 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/paperless/postgres-data FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/paperless/postgres-data 179.36 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/paperless/paperless-ai.data FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/paperless/paperless-ai.data 768.77 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/paperless/consume FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/paperless/consume 466.09 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/paperless/trash FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/paperless/trash 466.09 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/vaultwarden FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/vaultwarden 21.08 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/vaultwarden/postgres FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/vaultwarden/postgres 18.58 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/vaultwarden/data FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/vaultwarden/data 2.41 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/gitea FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/gitea 1.31 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/gitea/postgres FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/gitea/postgres 20.98 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/gitea/config FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/gitea/config 103.1 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/gitea/data FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/gitea/data 1.29 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/playwright FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/playwright 22.31 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/plex FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/plex 4.47 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/plex/config FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/plex/config 4.47 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/plex/data FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/plex/data 96 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/paperless-ai FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/paperless-ai 240.64 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/retrom FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/retrom 308.05 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/retrom/config FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/retrom/config 103.1 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/retrom/data FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/retrom/data 307.85 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/trillium FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/trillium 75.16 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/netdata FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/netdata 17.85 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/netdata/config FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/netdata/config 759.23 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/netdata/lib FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/netdata/lib 38.27 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/netdata/cache FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/netdata/cache 17.82 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/komga FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/komga 86.46 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/llama-cpp.models FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/llama-cpp.models 23.94 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/pihole FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/pihole 1.18 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/pihole/config FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/pihole/config 1.18 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/pihole/dnsmasq FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/pihole/dnsmasq 96 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/immich FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/immich 698.46 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/immich/mlcache FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/immich/mlcache 133.22 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/immich/postgres-data FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/immich/postgres-data 137.43 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/immich/data FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/immich/data 697.13 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/immich/pgData FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/immich/pgData 1.2 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/ollama.models FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/ollama.models 113.88 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/searxng FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/searxng 1.32 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/openwebui FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/openwebui 2.17 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/openwebui/data FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/openwebui/data 867.42 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/rustdesk FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/rustdesk 103.1 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/comfyui FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/comfyui 184.51 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/comfyui/models FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/comfyui/models 182.97 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/comfyui/input FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/comfyui/input 4.28 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/comfyui/output FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/comfyui/output 214.8 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/organizr FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/organizr 303.86 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/n8n FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/n8n 2.32 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/n8n/postgres-data FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/n8n/postgres-data 1.98 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/apps/n8n/data FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/apps/n8n/data 343.98 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/vms FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/vms 227.45 GiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/datasets/vms/windows11APIServer VOLUME None 40.04 GiB 9.27 TiB GZIP-9 DISABLED None None False False +storage.rushg.me/fast-backupv2/datasets/vms/webserver_ubuntu VOLUME None 18.09 GiB 9.27 TiB GZIP-9 DISABLED None None False False +storage.rushg.me/fast-backupv2/datasets/vms/homeassistant_ported VOLUME None 38.31 GiB 9.27 TiB GZIP-9 DISABLED None None False False +storage.rushg.me/fast-backupv2/datasets/vms/ubuntu VOLUME None 19.08 GiB 9.27 TiB GZIP-9 DISABLED None None False False +storage.rushg.me/fast-backupv2/datasets/vms/windowsAPIServer VOLUME None 111.93 GiB 9.27 TiB GZIP-9 DISABLED None None False False +storage.rushg.me/fast-backupv2/datasets/scripts FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/datasets/scripts 5.12 MiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backupv2/rushabh FILESYSTEM /mnt/storage.rushg.me/fast-backupv2/rushabh 2.55 MiB 9.27 TiB LZ4 512K OFF ALWAYS None None None None False False +storage.rushg.me/backups FILESYSTEM /mnt/storage.rushg.me/backups 1.02 TiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/backups/windows FILESYSTEM /mnt/storage.rushg.me/backups/windows 501.16 GiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/backups/windowsv2 FILESYSTEM /mnt/storage.rushg.me/backups/windowsv2 532.55 GiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/data FILESYSTEM /mnt/storage.rushg.me/data 32.89 TiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/data/z5 FILESYSTEM /mnt/storage.rushg.me/data/z5 2.98 TiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/data/media FILESYSTEM /mnt/storage.rushg.me/data/media 20.35 TiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/data/softwares FILESYSTEM /mnt/storage.rushg.me/data/softwares 4.55 TiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/data/family FILESYSTEM /mnt/storage.rushg.me/data/family 266.44 KiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/data/family/trishala.cloud FILESYSTEM /mnt/storage.rushg.me/data/family/trishala.cloud 127.02 KiB 9.27 TiB GZIP-9 512K OFF ALWAYS None None None None False False +storage.rushg.me/data/mediaV2 FILESYSTEM /mnt/storage.rushg.me/data/mediaV2 3.92 TiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/data/mediaV2/downloaded FILESYSTEM /mnt/storage.rushg.me/data/mediaV2/downloaded 96 KiB 9.27 TiB GZIP-9 512K OFF DISABLED None None None None False False +storage.rushg.me/fast-backup FILESYSTEM /mnt/storage.rushg.me/fast-backup 840.9 GiB 9.27 TiB LZ4 128K OFF DISABLED None None None None False False +storage.rushg.me/fast-backup/apps FILESYSTEM /mnt/storage.rushg.me/fast-backup/apps 119.89 GiB 9.27 TiB LZ4 128K OFF DISABLED None None None None False False +storage.rushg.me/fast-backup/apps/searxng FILESYSTEM /mnt/storage.rushg.me/fast-backup/apps/searxng 613.05 KiB 9.27 TiB LZ4 128K OFF DISABLED None None None None False False +storage.rushg.me/fast-backup/apps/nginx FILESYSTEM /mnt/storage.rushg.me/fast-backup/apps/nginx 72.97 MiB 9.27 TiB LZ4 128K OFF DISABLED None None None None False False +storage.rushg.me/fast-backup/apps/n8n FILESYSTEM /mnt/storage.rushg.me/fast-backup/apps/n8n 323.39 MiB 9.27 TiB LZ4 128K OFF DISABLED None None None None False False +storage.rushg.me/fast-backup/apps/n8n/postgres-data FILESYSTEM /mnt/storage.rushg.me/fast-backup/apps/n8n/postgres-data 107.24 MiB 9.27 TiB LZ4 128K OFF DISABLED None None None None False False +storage.rushg.me/fast-backup/apps/n8n/data FILESYSTEM /mnt/storage.rushg.me/fast-backup/apps/n8n/data 205.7 MiB 9.27 TiB LZ4 128K OFF DISABLED None None None None False False +``` +Note: Full snapshot listing timed out during capture due to very large snapshot counts. See Alerts for snapshot count warning. + +## Storage > Disks +Disk inventory (devname model serial size_bytes type rotation pool): +```text +sdh ST16000NM000J-2TW103 ZR70WHDM 16000900661248 HDD 7200 None +sdg ST16000NM000J-2TW103 ZR70VAFG 16000900661248 HDD 7200 None +sdi ST16000NM000J-2TW103 ZRS0TD9D 16000900661248 HDD 7200 None +sdd SPCC_Solid_State_Disk 240275945121140 128035676160 SSD None None +sda Samsung_SSD_870_EVO_250GB S6PDNL0W606533W 250059350016 SSD None None +sdf SPCC_Solid_State_Disk AA000000000000008078 128035676160 SSD None None +sde SPCC_Solid_State_Disk AA000000000000008357 128035676160 SSD None None +sdc Samsung_SSD_870_EVO_500GB S6PXNM0T410022E 500107862016 SSD None None +sdb Samsung_SSD_850_PRO_512GB S250NX0H445783F 512110190592 SSD None None +sdk ST16000NM000J-2TW103 ZRS0TG44 16000900661248 HDD 7200 None +sdj ST16000NM001G-2KK103 ZL2JDCAA 16000900661248 HDD 7200 None +nvme6n1 Sabrent SB-RKT4P-1TB 48790469701392 1000204886016 SSD None None +nvme7n1 Seagate ZP1000GM30063 D3200KWZ 1000204886016 SSD None None +nvme0n1 Sabrent SB-2130-256 48803179100104 256060514304 SSD None None +nvme1n1 Sabrent SB-2130-256 48803179100121 256060514304 SSD None None +nvme3n1 Sabrent Rocket 4.0 Plus 7D89071A13B900012386 1000204886016 SSD None None +nvme4n1 XG7000-2TB 2280 9J40708003019 2048408248320 SSD None None +nvme5n1 XG7000-2TB 2280 9J40708003039 2048408248320 SSD None None +nvme2n1 Sabrent Rocket 4.0 Plus 44FE071A138F00011874 1000204886016 SSD None None +``` +SMART summary for `sde` (Storage > Disks): +- Device: SPCC Solid State Disk, 128 GB, serial AA000000000000008357, firmware VE0R840H. +- Health: PASSED; latest long self-test completed without error (life hours 14108). +- Key attributes: Reallocated_Sector_Ct=0; Reported_Uncorrect=9; Program_Fail_Count_Chip=9; Program_Fail_Cnt_Total=5345; UDMA_CRC_Error_Count=0; Temperature_Celsius=38C; Power_On_Hours=14108. +- Error log: ATA Error Count=8; UNC read error at LBA 0x00c57c80 (12942464). +- Allocation: `sde1` is `zfs_member` and is part of `storage.rushg.me` special vdev (mirror-3 with `sdd1`/`sdf1`) per `zpool status -L`. + +## Data Protection > Scrub Tasks +- Pool fast.storage.rushg.me: schedule={'minute': '00', 'hour': '00', 'dom': '*', 'month': '*', 'dow': '7'} enabled=True threshold=15 +- Pool storage.rushg.me: schedule={'minute': '00', 'hour': '00', 'dom': '*', 'month': '*', 'dow': '7'} enabled=True threshold=35 + +## Data Protection > Periodic Snapshot Tasks +- Dataset storage.rushg.me/apps: recursive=True schedule={'minute': '0', 'hour': '0', 'dom': '*', 'month': '*', 'dow': '*', 'begin': '00:00', 'end': '23:59'} lifetime=2 WEEK enabled=True last_snapshot=storage.rushg.me/apps@auto-2025-12-28_00-00 +- Dataset storage.rushg.me/data/z5: recursive=True schedule={'minute': '0', 'hour': '0', 'dom': '*', 'month': '*', 'dow': '*', 'begin': '00:00', 'end': '23:59'} lifetime=2 WEEK enabled=True last_snapshot=storage.rushg.me/data/z5@auto-2025-12-28_00-00 +- Dataset fast.storage.rushg.me: recursive=True schedule={'minute': '0', 'hour': '*', 'dom': '*', 'month': '*', 'dow': '*', 'begin': '00:00', 'end': '23:59'} lifetime=2 WEEK enabled=True last_snapshot=fast.storage.rushg.me@auto-2025-12-28_15-00 + +## Data Protection > Replication Tasks +- backup.rushg.me: direction=PUSH transport=SSH+NETCAT enabled=True remote=truenas_admin@192.168.1.82:22 + - source_datasets=['fast.storage.rushg.me', 'storage.rushg.me/apps', 'storage.rushg.me/data/z5'] target_dataset=backup.rushg.me/backup/truenas recursive=True auto=True + - last_state=FINISHED last_snapshot=fast.storage.rushg.me/rushabh@auto-2025-12-28_13-00 warnings=22 +- fast.storage.rushg.me - storage.rushg.me/fast-backupv2: direction=PUSH transport=LOCAL enabled=True remote= + - source_datasets=['fast.storage.rushg.me'] target_dataset=storage.rushg.me/fast-backupv2 recursive=True auto=True + - last_state=FINISHED last_snapshot=fast.storage.rushg.me/ix-apps/docker@auto-2025-12-28_15-00 warnings=21 + +## Data Protection > Cloud Sync Tasks +- Google Drive - /mnt/fast.storage.rushg.me/datasets/apps: direction=PUSH schedule={'minute': '0', 'hour': '*', 'dom': '*', 'month': '*', 'dow': '*'} enabled=True + - path=/mnt/fast.storage.rushg.me/datasets/apps include=['/pihole/**', '/rustdesk/**', '/searxng/**', '/vaultwarden/**', '/gitea/**'] exclude=[] + - last_state=FAILED logs=/var/log/jobs/125.log error_present=True + - credentials: REDACTED + +## Data Protection > Rsync Tasks +- No rsync tasks configured + +## Tasks > Cron Jobs +- ClamAV CRON Job: user=rushabh schedule={'minute': '0', 'hour': '0', 'dom': '*', 'month': '*', 'dow': '*'} enabled=False cmd=/mnt/fast.storage.rushg.me/rushabh/run_clamAV.sh + +## Tasks > Init/Shutdown Scripts +- rushg.me webserver: when=POSTINIT enabled=True type=COMMAND timeout=1 cmd=sleep 30 && cd /mnt/fast.storage.rushg.me/rushabh/rushabh/rushg.me && nohup python3 -m http.server 8081 > /dev/null 2>&1 & +- Lower FAN Speeds in a loop infinitely : when=PREINIT enabled=True type=COMMAND timeout=99999999999 cmd=ipmitool ... (REDACTED credentials) + +## Shares > SMB +- SMB config: netbiosname=truenas workgroup=WORKGROUP enable_smb1=False guest=nobody +- Share apps: path=/mnt/storage.rushg.me/apps enabled=True readonly=False purpose=DEFAULT_SHARE +- Share data: path=/mnt/storage.rushg.me/data enabled=True readonly=False purpose=DEFAULT_SHARE +- Share fast.datasets: path=/mnt/fast.storage.rushg.me/datasets enabled=True readonly=False purpose=DEFAULT_SHARE +- Share fast-backup.apps: path=/mnt/storage.rushg.me/fast-backup/apps enabled=True readonly=False purpose=DEFAULT_SHARE +- Share rushabh: path=/mnt/fast.storage.rushg.me/rushabh enabled=True readonly=False purpose=DEFAULT_SHARE +- Share scripts: path=/mnt/fast.storage.rushg.me/datasets/scripts enabled=True readonly=False purpose=DEFAULT_SHARE +- Share trishala.cloud: path=/mnt/storage.rushg.me/data/family/trishala.cloud enabled=True readonly=False purpose=DEFAULT_SHARE + +## Shares > NFS +- NFS config: servers=32 v4_krb=False allow_nonroot=False +- No NFS shares configured + +## Shares > iSCSI +- Targets: 0, Extents: 0, Portals: 0, Initiators: 0 + +## Apps > Settings +- Apps dataset: fast.storage.rushg.me/ix-apps (pool=fast.storage.rushg.me) +- NVIDIA support: True +- Image updates: True +- Docker status: RUNNING - Application(s) are currently running +- Apps available space: 2245534941184 +- Registries: 2 configured + +## Apps > Installed Applications +- Installed apps: 35 (RUNNING=30, STOPPED=3, DEPLOYING=2) +- Used host IPs: {'::': ['immich-recovery', 'llamacpp', 'vaultwarden', 'metube', 'ocrserver', 'comfyui3', 'plex', 'ollama', 'rushg-me', 'trilium-notes', 'searxng', 'n8n', 'open-webui', 'photoprism', 'qbittorrent', 'invidious-internal', 'paperless-ngx', 'rushg-llama-cpp-proxy-n8n', 'portracker', 'pihole', 'open-speed-test', 'netdata', 'nginx-proxy-manager', 'komga', 'it-tools', 'invidious', 'glances', 'gitea', 'filebrowser'], '0.0.0.0': ['immich-recovery', 'llamacpp', 'vaultwarden', 'metube', 'ocrserver', 'comfyui3', 'plex', 'ollama', 'rushg-me', 'trilium-notes', 'searxng', 'n8n', 'open-webui', 'photoprism', 'qbittorrent', 'invidious-internal', 'paperless-ngx', 'rushg-llama-cpp-proxy-n8n', 'portracker', 'pihole', 'open-speed-test', 'netdata', 'nginx-proxy-manager', 'komga', 'it-tools', 'invidious', 'glances', 'gitea', 'filebrowser']} +- Used host ports (list): [53, 8071, 8188, 9091, 9092, 9095, 20489, 20720, 20800, 30008, 30009, 30015, 30020, 30021, 30022, 30024, 30032, 30040, 30048, 30051, 30053, 30063, 30068, 30070, 30094, 30109, 30116, 30117, 30233, 30257, 31003, 31008, 31028, 32400, 51413] +- IX volumes: + - app=open-webui volume=data + - app=paperless-ngx volume=postgres_data + - app=paperless-ngx volume=media + - app=paperless-ngx volume=data + - app=paperless-ngx volume=consume + - app=paperless-ngx volume=trash + - app=gitea volume=postgres_data + - app=portracker volume=data + - app=photoprism volume=originals + - app=vaultwarden volume=postgres_data + - app=steam-headless volume=x11_socket + - app=steam-headless volume=home + - app=steam-headless volume=pulse_socket + - app=steam-headless volume=games + - app=invidious volume=postgres_data + - app=invidious volume=config + - app=invidious volume=companion_cache + - app=searxng volume=config + +### App: comfyui3 +- State: RUNNING | Version: 1.2.17 (app 1.2.15) | Train: stable | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:8188/'} +- Description: An application for deploying simple containers. +- Categories: ['custom'] +- Containers: + - comfyui3: image=yanwk/comfyui-boot:cu128-megapak state=running +- Port mappings: + - tcp 8188 -> 0.0.0.0:8188, :::8188 +- Volumes: + - /mnt/fast.storage.rushg.me/datasets/apps/comfyui/output -> /root/ComfyUI/output (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/comfyui -> /root (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/comfyui/models -> /root/ComfyUI/models (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/comfyui/input -> /root/ComfyUI/input (bind, ) +- Networks: + - ix-comfyui3_default (driver=bridge, subnets=['172.16.25.0/24', 'fdb7:86ec:b1dd:18::/64']) + +### App: dozzle +- State: RUNNING | Version: 1.0.74 (app v8.14.12) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:30064/'} +- Description: Realtime log viewer for docker containers. +- Categories: ['monitoring'] +- Containers: + - dozzle: image=amir20/dozzle:v8.14.12 state=running +- Volumes: + - /var/run/docker.sock -> /var/run/docker.sock (bind, ) + +### App: filebrowser +- State: RUNNING | Version: 1.3.54 (app v2.52.0) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:30051/'} +- Description: File Browser provides a file managing interface within a specified directory and it can be used to upload, delete, preview, rename and edit your files. +- Categories: ['storage'] +- Containers: + - filebrowser: image=filebrowser/filebrowser:v2.52.0 state=running + - init: image=filebrowser/filebrowser:v2.52.0 state=exited +- Port mappings: + - tcp 30051 -> 0.0.0.0:30051, :::30051 +- Volumes: + - /mnt/.ix-apps/docker/volumes/501c53f2af7824d5be184133210ad7652e4b03fcbbcd6a54f0466251e2a480e5/_data -> /database (volume, ) + - /mnt/fast.storage.rushg.me/datasets/apps/filebrowser -> /config (bind, ) + - /mnt/.ix-apps/docker/volumes/37535ebd5e41f682c0874e975ef3f591073c1988a250bdd81a977f5e7ce837ec/_data -> /database (volume, ) + - /mnt/storage.rushg.me -> /data/storage.rushg.me (bind, ) + - /mnt/fast.storage.rushg.me -> /data/fast.storage.rushg.me (bind, ) + - /mnt/.ix-apps/docker/volumes/e49a9e5835008d2207fd9a57076282e51ad849212ce0c194ae4add083a088097/_data -> /srv (volume, ) + - /mnt/.ix-apps/docker/volumes/3353d716ff7520c60ad068b01d87007fd3580f84efdcf63f4c61b7ab29f5ffc0/_data -> /srv (volume, ) +- Networks: + - ix-filebrowser_default (driver=bridge, subnets=['172.16.1.0/24', 'fdb7:86ec:b1dd::/64']) + +### App: gitea +- State: RUNNING | Version: 1.3.35 (app 1.25.3-rootless) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:30008/'} +- Description: Gitea - Git with a cup of tea +- Categories: ['productivity'] +- Containers: + - gitea: image=gitea/gitea:1.25.3-rootless state=running + - postgres: image=postgres:17.7-bookworm state=running + - postgres_upgrade: image=ixsystems/postgres-upgrade:1.1.4 state=exited + - permissions: image=ixsystems/container-utils:1.0.2 state=exited +- Port mappings: + - tcp 30008 -> 0.0.0.0:30008, :::30008 + - tcp 30009 -> 0.0.0.0:30009, :::30009 +- Volumes: + - /mnt/fast.storage.rushg.me/datasets/apps/gitea/data -> /var/lib/gitea (bind, ) + - /mnt/.ix-apps/docker/volumes/ix-gitea_tmp-gitea/_data -> /tmp/gitea (volume, rw) + - /mnt/fast.storage.rushg.me/datasets/apps/gitea/config -> /etc/gitea (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/gitea/postgres -> /var/lib/postgresql (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/gitea/postgres -> /mnt/permission/postgres_postgres_data (bind, ) + - /mnt/.ix-apps/docker/volumes/ix-gitea_tmp-gitea/_data -> /mnt/permission/tmp_gitea (volume, rw) + - /mnt/.ix-apps/docker/volumes/c11f573be672894150855ca14b39bca359cb3b32a6c74ddbd5d0630ec0018720/_data -> /var/lib/postgresql/data (volume, ) +- Networks: + - ix-gitea_default (driver=bridge, subnets=['172.16.2.0/24', 'fdb7:86ec:b1dd:1::/64']) + +### App: glances +- State: RUNNING | Version: 1.0.23 (app 4.3.0.8) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:30015/'} +- Description: Glances is a cross-platform system monitoring tool. +- Categories: ['monitoring'] +- Capabilities: ['DAC_OVERRIDE', 'FOWNER', 'SETGID', 'SETUID', 'SYS_PTRACE'] +- Containers: + - glances: image=nicolargo/glances:4.3.0.8 state=running +- Port mappings: + - tcp 30015 -> 0.0.0.0:30015, :::30015 +- Volumes: + - /etc/os-release -> /host/etc/os-release (bind, ) + - /sys -> /host/sys (bind, ) + - /var/run/docker.sock -> /var/run/docker.sock (bind, ) + - /proc -> /host/proc (bind, ) +- Networks: + - ix-glances_default (driver=bridge, subnets=['172.16.5.0/24', 'fdb7:86ec:b1dd:4::/64']) + +### App: immich-recovery +- State: RUNNING | Version: 1.11.4 (app v2.4.1) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:30040/'} +- Description: Immich is a self-hosted photo and video backup solution directly from your mobile phone. +- Categories: ['media'] +- Containers: + - server: image=ghcr.io/immich-app/immich-server:v2.4.1 state=running + - pgvecto: image=ghcr.io/immich-app/postgres:15-vectorchord0.5.3 state=running + - machine-learning: image=ghcr.io/immich-app/immich-machine-learning:v2.4.1-cuda state=running + - redis: image=valkey/valkey:9.0.1 state=running + - pgvecto_upgrade: image=ixsystems/postgres-upgrade:1.1.4 state=exited + - permissions: image=ixsystems/container-utils:1.0.2 state=exited +- Port mappings: + - tcp 30040 -> 0.0.0.0:30040, :::30040 +- Volumes: + - /mnt/.ix-apps/docker/volumes/24b5fd2c2e6bab2d39ef830a094608642c73517460ecfd250aaedf08583433df/_data -> /var/lib/postgresql/data (volume, ) + - /mnt/.ix-apps/docker/volumes/ix-immich-recovery_cli-temp-storage/_data -> /mnt/permission/-config (volume, rw) + - /mnt/.ix-apps/docker/volumes/ix-immich-recovery_redis-data/_data -> /mnt/permission/redis_redis_data (volume, rw) + - /mnt/storage.rushg.me/data/z5/Photos.DeDuped -> /import/rushabh (bind, ) + - /mnt/.ix-apps/docker/volumes/ix-immich-recovery_ml-cache/_data -> /mlcache (volume, rw) + - /mnt/.ix-apps/docker/volumes/ix-immich-recovery_cli-temp-storage/_data -> /.config (volume, rw) + - /mnt/fast.storage.rushg.me/datasets/apps/immich/data -> /data (bind, ) + - /mnt/.ix-apps/docker/volumes/ix-immich-recovery_redis-data/_data -> /data (volume, rw) + - /mnt/storage.rushg.me/data/z5/Aditi -> /import/aditi (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/immich/pgData -> /var/lib/postgresql (bind, ) + - /mnt/.ix-apps/docker/volumes/ix-immich-recovery_ml-cache/_data -> /mnt/permission/ml-cache (volume, rw) +- Networks: + - ix-immich-recovery_default (driver=bridge, subnets=['172.16.31.0/24', 'fdb7:86ec:b1dd:1e::/64']) + +### App: immich-rushabhperms +- State: STOPPED | Version: 1.11.4 (app v2.4.1) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:30041/'} +- Description: Immich is a self-hosted photo and video backup solution directly from your mobile phone. +- Categories: ['media'] + +### App: invidious +- State: RUNNING | Version: 1.4.25 (app 2.20250913.0) | Train: community | Custom: False | Upgrade available: False | Image updates: True +- Portals: {'Web UI': 'http://0.0.0.0:31008/'} +- Description: Invidious is an alternative front-end to YouTube +- Categories: ['media'] +- Containers: + - invidious: image=quay.io/invidious/invidious:2.20250913.0 state=running + - config: image=mikefarah/yq:4.50.1 state=exited + - db_seed_apply: image=postgres:17.7-bookworm state=exited + - postgres: image=postgres:17.7-bookworm state=running + - postgres_upgrade: image=ixsystems/postgres-upgrade:1.1.4 state=exited + - companion: image=quay.io/invidious/invidious-companion:latest state=running + - db_seed_fetch: image=alpine/git:v2.52.0 state=exited + - permissions: image=ixsystems/container-utils:1.0.2 state=exited +- Port mappings: + - tcp 31008 -> 0.0.0.0:31008, :::31008 +- Volumes: + - /mnt/fast.storage.rushg.me/datasets/apps/invidious-public/pgData -> /mnt/permission/postgres_postgres_data (bind, ) + - /mnt/.ix-apps/docker/volumes/ix-invidious_shared/_data -> /mnt/permission/shared (volume, rw) + - /mnt/.ix-apps/docker/volumes/ix-invidious_shared/_data -> /shared (volume, rw) + - /mnt/.ix-apps/docker/volumes/aae229a4285242265c6c45ebbdd067aed322284216280de48bda8248f6706689/_data -> /var/lib/postgresql/data (volume, ) + - /mnt/.ix-apps/docker/volumes/5a53df5979ef527a1d9c6244ae8817dbc17c51125b2b1d14d29443208ffb4e21/_data -> /git (volume, ) + - /mnt/fast.storage.rushg.me/datasets/apps/invidious-public/cache -> /var/tmp/youtubei.js (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/invidious-public/pgData -> /var/lib/postgresql (bind, ) + - /mnt/.ix-apps/docker/volumes/7a119b52a10f967d52fe12ac387d24af60f9da29c4a00a5ac3ffa5a453876cf8/_data -> /var/lib/postgresql/data (volume, ) + - /mnt/fast.storage.rushg.me/datasets/apps/invidious-public/config -> /config (bind, ) +- Networks: + - ix-invidious_default (driver=bridge, subnets=['172.16.3.0/24', 'fdb7:86ec:b1dd:2::/64']) + +### App: invidious-internal +- State: RUNNING | Version: 1.4.25 (app 2.20250913.0) | Train: community | Custom: False | Upgrade available: False | Image updates: True +- Portals: {'Web UI': 'http://0.0.0.0:31003/'} +- Description: Invidious is an alternative front-end to YouTube +- Categories: ['media'] +- Containers: + - invidious: image=quay.io/invidious/invidious:2.20250913.0 state=running + - config: image=mikefarah/yq:4.50.1 state=exited + - db_seed_apply: image=postgres:18.1-trixie state=exited + - postgres: image=postgres:18.1-trixie state=running + - companion: image=quay.io/invidious/invidious-companion:latest state=running + - postgres_upgrade: image=ixsystems/postgres-upgrade:1.1.4 state=exited + - db_seed_fetch: image=alpine/git:v2.52.0 state=exited + - permissions: image=ixsystems/container-utils:1.0.2 state=exited +- Port mappings: + - tcp 31003 -> 0.0.0.0:31003, :::31003 +- Volumes: + - /mnt/.ix-apps/docker/volumes/53d4248da37f9f274b8885b9ede6d7b2fa67014f925f8a510292819dd2c64394/_data -> /var/lib/postgresql (volume, ) + - /mnt/fast.storage.rushg.me/datasets/apps/invidious-internal/pgData -> /mnt/permission/postgres_postgres_data (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/invidious-internal/cache -> /var/tmp/youtubei.js (bind, ) + - /mnt/.ix-apps/docker/volumes/d347d7b175379c4779a26a6291ce7b767cd9361655ef02afd7a4fdd62b81f72d/_data -> /git (volume, ) + - /mnt/.ix-apps/docker/volumes/ix-invidious-internal_shared/_data -> /mnt/permission/shared (volume, rw) + - /mnt/fast.storage.rushg.me/datasets/apps/invidious-internal/pgData -> /var/lib/postgresql (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/invidious-internal/config -> /config (bind, ) + - /mnt/.ix-apps/docker/volumes/ix-invidious-internal_shared/_data -> /shared (volume, rw) +- Networks: + - ix-invidious-internal_default (driver=bridge, subnets=['172.16.7.0/24', 'fdb7:86ec:b1dd:6::/64']) + +### App: it-tools +- State: RUNNING | Version: 1.0.21 (app 2024.10.22-7ca5933) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:30063/'} +- Description: Collection of handy online tools for developers, with great UX. +- Categories: ['productivity'] +- Capabilities: ['CHOWN', 'DAC_OVERRIDE', 'FOWNER', 'NET_BIND_SERVICE', 'SETGID', 'SETUID'] +- Containers: + - it-tools: image=ghcr.io/corentinth/it-tools:2024.10.22-7ca5933 state=running +- Port mappings: + - tcp 80 -> 0.0.0.0:30063, :::30063 +- Networks: + - ix-it-tools_default (driver=bridge, subnets=['172.16.8.0/24', 'fdb7:86ec:b1dd:7::/64']) + +### App: komga +- State: RUNNING | Version: 1.3.23 (app 1.23.6) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:30048/'} +- Description: Komga is a free and open source comics/mangas server. +- Categories: ['media'] +- Containers: + - komga: image=gotson/komga:1.23.6 state=running +- Port mappings: + - tcp 30048 -> 0.0.0.0:30048, :::30048 +- Volumes: + - /mnt/fast.storage.rushg.me/datasets/apps/komga -> /config (bind, ) + - /mnt/storage.rushg.me/data/media/SoftwaresV2/Server/Server/eBooks -> /media (bind, ) + - /mnt/.ix-apps/docker/volumes/2e5830fc4a28f19757216c036a39fa6469b15018c912fd6c89252d8f517c7eb5/_data -> /tmp (volume, ) +- Networks: + - ix-komga_default (driver=bridge, subnets=['172.16.9.0/24', 'fdb7:86ec:b1dd:8::/64']) + +### App: llamacpp +- State: RUNNING | Version: 1.2.17 (app 1.2.15) | Train: stable | Custom: False | Upgrade available: True | Image updates: True +- Portals: {'Web UI': 'http://0.0.0.0:8071/'} +- Description: An application for deploying simple containers. +- Categories: ['custom'] +- Containers: + - llamacpp: image=ghcr.io/ggml-org/llama.cpp:server-cuda state=running +- Port mappings: + - tcp 8080 -> 0.0.0.0:8071, :::8071 +- Volumes: + - /mnt/fast.storage.rushg.me/datasets/apps/llama-cpp.models -> /models (bind, ) +- Models in /models: GPT-OSS, Meta-Llama-3-8B-Instruct.Q4_K_M.gguf, openassistant-llama2-13b-orca-8k-3319.Q5_K_M.gguf, Meta-Llama-3.1-8B-Instruct-Q4_K_M.gguf +- Networks: + - ix-llamacpp_default (driver=bridge, subnets=['172.16.18.0/24', 'fdb7:86ec:b1dd:11::/64']) + +### App: metube +- State: RUNNING | Version: 1.3.37 (app 2025.12.27) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:30094/'} +- Description: MeTube is a web GUI for youtube-dl (using the yt-dlp fork) with playlist support. +- Categories: ['media'] +- Containers: + - metube: image=alexta69/metube:2025.12.27 state=running +- Port mappings: + - tcp 30094 -> 0.0.0.0:30094, :::30094 +- Volumes: + - /mnt/storage.rushg.me/apps/metube -> /downloads (bind, ) +- Networks: + - ix-metube_default (driver=bridge, subnets=['172.16.10.0/24', 'fdb7:86ec:b1dd:9::/64']) + +### App: n8n +- State: RUNNING | Version: 1.6.96 (app 2.2.1) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:30109/'} +- Description: n8n is an extendable workflow automation tool. +- Categories: ['productivity'] +- Containers: + - n8n: image=n8nio/n8n:2.2.1 state=running + - postgres: image=postgres:17.7-bookworm state=running + - postgres_upgrade: image=ixsystems/postgres-upgrade:1.1.4 state=exited + - redis: image=valkey/valkey:9.0.1 state=running + - permissions: image=ixsystems/container-utils:1.0.2 state=exited +- Port mappings: + - tcp 30109 -> 0.0.0.0:30109, :::30109 +- Volumes: + - /mnt/.ix-apps/docker/volumes/ix-n8n_redis-data/_data -> /mnt/permission/redis_redis_data (volume, rw) + - /mnt/.ix-apps/docker/volumes/ix-n8n_redis-data/_data -> /data (volume, rw) + - /mnt/.ix-apps/docker/volumes/ix-n8n_tmp-n8n-npm-cache/_data -> /.cache (volume, rw) + - /mnt/fast.storage.rushg.me/datasets/scripts/models/n8n -> /.n8n-files (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/n8n/postgres-data -> /var/lib/postgresql (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/n8n/data -> /data (bind, ) + - /mnt/.ix-apps/docker/volumes/7a12f1f00edffee620c2565ca92d95c3856e2d5fe2bbdac3d143564f10ce4df0/_data -> /tmp (volume, z) + - /mnt/.ix-apps/docker/volumes/ix-n8n_tmp-n8n-npm-cache/_data -> /mnt/permission/tmp-n8n-npm-cache (volume, rw) + - /mnt/fast.storage.rushg.me/datasets/apps/n8n/postgres-data -> /mnt/permission/postgres_postgres_data (bind, ) + - /mnt/.ix-apps/docker/volumes/292cd1c8ed420f384b2622982f5b642a6c3b147bd383a211ca6acb0fb29466a5/_data -> /var/lib/postgresql/data (volume, ) +- Networks: + - ix-n8n_default (driver=bridge, subnets=['172.16.12.0/24', 'fdb7:86ec:b1dd:b::/64']) + +### App: netbootxyz +- State: RUNNING | Version: 1.2.14 (app 0.7.6-nbxyz4) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:31010/'} +- Description: netboot.xyz lets you PXE boot various operating system installers or utilities from a single tool over the network. +- Categories: ['networking'] +- Capabilities: ['CHOWN', 'DAC_OVERRIDE', 'FOWNER', 'KILL', 'NET_BIND_SERVICE', 'SETGID', 'SETUID', 'SYS_CHROOT'] +- Containers: + - netboot: image=ghcr.io/netbootxyz/netbootxyz:0.7.6-nbxyz4 state=running +- Volumes: + - /mnt/.ix-apps/docker/volumes/eb841807995b2554f8fed74d42b708d9dbdd6f38613cc5b0c698f30daf13cab5/_data -> /var/tmp/nginx (volume, z) + - /mnt/fast.storage.rushg.me/datasets/apps/netboot/assets -> /assets (bind, ) + - /mnt/.ix-apps/docker/volumes/02ed5a11571f341ed99208957f5a6a910ac8c0a9a8825a47b2ed8e65ccda9140/_data -> /var/log/nginx (volume, z) + - /mnt/fast.storage.rushg.me/datasets/apps/netboot/config -> /config (bind, ) + +### App: netdata +- State: RUNNING | Version: 1.3.29 (app v2.8.4) | Train: stable | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:20489/v3'} +- Description: Real-time performance monitoring, done right! +- Categories: ['monitoring'] +- Capabilities: ['CHOWN', 'DAC_OVERRIDE', 'FOWNER', 'SETGID', 'SETUID', 'SYS_PTRACE', 'SYS_RAWIO'] +- Containers: + - netdata: image=netdata/netdata:v2.8.4 state=running +- Port mappings: + - tcp 20489 -> 0.0.0.0:20489, :::20489 +- Volumes: + - /etc/os-release -> /host/etc/os-release (bind, ) + - /etc/passwd -> /host/etc/passwd (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/netdata/cache -> /var/cache/netdata (bind, ) + - /proc -> /host/proc (bind, ) + - /var/run/docker.sock -> /var/run/docker.sock (bind, ) + - /etc/group -> /host/etc/group (bind, ) + - /sys -> /host/sys (bind, ) + - /etc/hostname -> /host/etc/hostname (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/netdata/lib -> /var/lib/netdata (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/netdata/config -> /etc/netdata (bind, ) +- Networks: + - ix-netdata_default (driver=bridge, subnets=['172.16.14.0/24', 'fdb7:86ec:b1dd:d::/64']) + +### App: nginx-proxy-manager +- State: RUNNING | Version: 1.2.23 (app 2.13.5) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:30020/'} +- Description: Expose your services easily and securely +- Categories: ['networking'] +- Capabilities: ['CHOWN', 'DAC_OVERRIDE', 'FOWNER', 'SETGID', 'SETUID'] +- Containers: + - npm: image=jc21/nginx-proxy-manager:2.13.5 state=running +- Port mappings: + - tcp 443 -> 0.0.0.0:30022, :::30022 + - tcp 80 -> 0.0.0.0:30021, :::30021 + - tcp 81 -> 0.0.0.0:30020, :::30020 +- Volumes: + - /mnt/storage.rushg.me/fast-backup/apps/nginx -> /data (bind, ) + - /mnt/storage.rushg.me/fast-backup/apps/nginx -> /etc/letsencrypt (bind, ) +- Networks: + - ix-nginx-proxy-manager_default (driver=bridge, subnets=['172.16.13.0/24', 'fdb7:86ec:b1dd:c::/64']) + +### App: ocrserver +- State: RUNNING | Version: 1.2.17 (app 1.2.15) | Train: stable | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:9095/'} +- Description: An application for deploying simple containers. +- Categories: ['custom'] +- Containers: + - ocrserver: image=otiai10/ocrserver:latest state=running +- Port mappings: + - tcp 8080 -> 0.0.0.0:9095, :::9095 +- Networks: + - ix-ocrserver_default (driver=bridge, subnets=['172.16.15.0/24', 'fdb7:86ec:b1dd:e::/64']) + +### App: ollama +- State: RUNNING | Version: 1.1.47 (app 0.13.5) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Description: Get up and running with Llama 3.2, Mistral, Gemma 2, and other large language models. +- Categories: ['ai'] +- Containers: + - ollama: image=ollama/ollama:0.13.5 state=running +- Port mappings: + - tcp 30068 -> 0.0.0.0:30068, :::30068 +- Volumes: + - /mnt/fast.storage.rushg.me/datasets/apps/ollama.models -> /root/.ollama (bind, ) +- Networks: + - ix-ollama_default (driver=bridge, subnets=['172.16.16.0/24', 'fdb7:86ec:b1dd:f::/64']) + +### App: open-speed-test +- State: RUNNING | Version: 1.0.23 (app v2.0.6) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'HTTP': 'http://0.0.0.0:30116/', 'HTTPS': 'https://0.0.0.0:30117/'} +- Description: SpeedTest by OpenSpeedTest? is a Free and Open-Source HTML5 Network Performance Estimation Tool +- Categories: ['networking'] +- Containers: + - open-speed-test: image=openspeedtest/latest:v2.0.6 state=running +- Port mappings: + - tcp 30116 -> 0.0.0.0:30116, :::30116 + - tcp 30117 -> 0.0.0.0:30117, :::30117 +- Volumes: + - /mnt/.ix-apps/docker/volumes/1979716c954af6d6b5f87c4f6ab0acc9a7a610309fae64395db034f03d786a7b/_data -> /var/log/letsencrypt (volume, ) +- Networks: + - ix-open-speed-test_default (driver=bridge, subnets=['172.16.17.0/24', 'fdb7:86ec:b1dd:10::/64']) + +### App: open-webui +- State: RUNNING | Version: 1.1.44 (app 0.6.43) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:31028/'} +- Description: Open WebUI is an extensible, feature-rich, and user-friendly self-hosted WebUI designed to operate entirely offline. It supports various LLM runners, including Ollama and OpenAI-compatible APIs. +- Categories: ['ai'] +- Containers: + - open-webui: image=ghcr.io/open-webui/open-webui:0.6.43 state=running + - redis: image=valkey/valkey:9.0.1 state=running + - permissions: image=ixsystems/container-utils:1.0.2 state=exited +- Port mappings: + - tcp 31028 -> 0.0.0.0:31028, :::31028 +- Volumes: + - /mnt/fast.storage.rushg.me/datasets/apps/ollama.models -> /root/.ollama (bind, ) + - /mnt/.ix-apps/docker/volumes/ix-open-webui_redis_data/_data -> /mnt/permission/redis_redis_data (volume, rw) + - /mnt/fast.storage.rushg.me/datasets/apps/openwebui -> /app/backend/data (bind, ) + - /mnt/.ix-apps/docker/volumes/ix-open-webui_redis_data/_data -> /data (volume, rw) +- Networks: + - ix-open-webui_default (driver=bridge, subnets=['172.16.11.0/24', 'fdb7:86ec:b1dd:a::/64']) + +### App: options-train +- State: STOPPED | Version: 1.2.17 (app 1.2.15) | Train: stable | Custom: False | Upgrade available: False | Image updates: False +- Description: An application for deploying simple containers. +- Categories: ['custom'] + +### App: paperless-ngx +- State: RUNNING | Version: 1.3.58 (app 2.20.3) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:30070/'} +- Description: Paperless-ngx is a document management system that transforms your physical documents into a searchable online archive so you can keep, well, less paper. +- Categories: ['productivity'] +- Capabilities: ['CHOWN', 'DAC_OVERRIDE', 'FOWNER', 'SETGID', 'SETUID'] +- Containers: + - paperless: image=paperlessngx/paperless-ngx:2.20.3 state=running + - postgres: image=postgres:18.1-trixie state=running + - postgres_upgrade: image=ixsystems/postgres-upgrade:1.1.4 state=exited + - redis: image=valkey/valkey:9.0.1 state=running + - permissions: image=ixsystems/container-utils:1.0.2 state=exited + - tika: image=apache/tika:3.2.3.0-full state=running + - gotenberg: image=gotenberg/gotenberg:8.25.1 state=running +- Port mappings: + - tcp 30070 -> 0.0.0.0:30070, :::30070 +- Volumes: + - /mnt/.ix-apps/docker/volumes/7919b5a2cea1b7df778f2177bf8d4c42ea87a81335632c9d96fcf07291fb6c26/_data -> /usr/src/paperless/export (volume, ) + - /mnt/fast.storage.rushg.me/datasets/apps/paperless/consume -> /usr/src/paperless/consume (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/paperless/data -> /usr/src/paperless/data (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/paperless/trash -> /usr/src/paperless/trash (bind, ) + - /mnt/.ix-apps/docker/volumes/ix-paperless-ngx_redis-data/_data -> /mnt/permission/redis_redis_data (volume, rw) + - /mnt/fast.storage.rushg.me/datasets/apps/paperless/postgres-data -> /mnt/permission/postgres_postgres_data (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/paperless/postgres-data -> /var/lib/postgresql (bind, ) + - /mnt/.ix-apps/docker/volumes/ix-paperless-ngx_redis-data/_data -> /data (volume, rw) + - /mnt/fast.storage.rushg.me/datasets/apps/paperless/media -> /usr/src/paperless/media (bind, ) +- Networks: + - ix-paperless-ngx_default (driver=bridge, subnets=['172.16.6.0/24', 'fdb7:86ec:b1dd:5::/64']) + +### App: photoprism +- State: DEPLOYING | Version: 1.3.16 (app 251130) | Train: stable | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:20800/'} +- Description: AI-powered app for browsing, organizing & sharing your photo collection. +- Categories: ['media'] +- Capabilities: ['CHOWN', 'DAC_OVERRIDE', 'FOWNER', 'KILL', 'SETGID', 'SETUID'] +- Containers: + - photoprism: image=photoprism/photoprism:251130 state=starting + - permissions: image=ixsystems/container-utils:1.0.2 state=exited +- Port mappings: + - tcp 20800 -> 0.0.0.0:20800, :::20800 +- Volumes: + - /mnt/storage.rushg.me/apps/photoprism/storage -> /photoprism/storage (bind, ) + - /mnt/.ix-apps/app_mounts/photoprism/originals -> /mnt/permission/originals (bind, ) + - /mnt/.ix-apps/app_mounts/photoprism/originals -> /photoprism/originals (bind, ) + - /mnt/storage.rushg.me/apps/photoprism/originals -> /photoprism/import (bind, ) +- Networks: + - ix-photoprism_default (driver=bridge, subnets=['172.16.20.0/24', 'fdb7:86ec:b1dd:13::/64']) + +### App: pihole +- State: RUNNING | Version: 1.3.25 (app 2025.11.1) | Train: stable | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:20720/admin/'} +- Description: DNS and Ad-filtering for your network. +- Categories: ['networking'] +- Capabilities: ['CHOWN', 'DAC_OVERRIDE', 'FOWNER', 'KILL', 'NET_ADMIN', 'NET_BIND_SERVICE', 'NET_RAW', 'SETFCAP', 'SETGID', 'SETPCAP', 'SETUID', 'SYS_NICE', 'SYS_TIME'] +- Containers: + - pihole: image=pihole/pihole:2025.11.1 state=running +- Port mappings: + - tcp 20720 -> 0.0.0.0:20720, :::20720 + - tcp 53 -> 0.0.0.0:53, :::53 + - udp 53 -> 0.0.0.0:53, :::53 +- Volumes: + - /mnt/fast.storage.rushg.me/datasets/apps/pihole/dnsmasq -> /etc/dnsmasq.d (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/pihole/config -> /etc/pihole (bind, ) +- Networks: + - ix-pihole_default (driver=bridge, subnets=['172.16.21.0/24', 'fdb7:86ec:b1dd:14::/64']) + +### App: plex +- State: RUNNING | Version: 1.2.20 (app 1.42.2.10156-f737b826c) | Train: stable | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:32400/web'} +- Description: Plex is a media server that allows you to stream your media to any Plex client. +- Categories: ['media'] +- Capabilities: ['CHOWN', 'DAC_OVERRIDE', 'FOWNER', 'KILL', 'SETGID', 'SETUID'] +- Containers: + - plex: image=plexinc/pms-docker:plexpass state=running + - permissions: image=ixsystems/container-utils:1.0.2 state=exited +- Port mappings: + - tcp 32400 -> 0.0.0.0:32400, :::32400 +- Volumes: + - /mnt/.ix-apps/docker/volumes/ix-plex_plex-logs/_data -> /mnt/permission/logs (volume, rw) + - /mnt/fast.storage.rushg.me/datasets/apps/plex/config -> /config (bind, ) + - /mnt/.ix-apps/docker/volumes/ix-plex_plex-transcodes/_data -> /transcode (volume, rw) + - /mnt/.ix-apps/docker/volumes/ix-plex_plex-transcodes/_data -> /mnt/permission/transcode (volume, rw) + - /mnt/storage.rushg.me/data/media -> /media (bind, ) + - /mnt/.ix-apps/docker/volumes/ix-plex_plex-logs/_data -> /config/Library/Application Support/Plex Media Server/Logs (volume, rw) + - /mnt/fast.storage.rushg.me/datasets/apps/plex/data -> /data (bind, ) +- Networks: + - ix-plex_default (driver=bridge, subnets=['172.16.22.0/24', 'fdb7:86ec:b1dd:15::/64']) + +### App: portracker +- State: RUNNING | Version: 1.0.20 (app 1.2.2) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:30233/'} +- Description: A self-hosted, real-time port monitoring and discovery tool. +- Categories: ['monitoring'] +- Capabilities: ['NET_RAW', 'SYS_PTRACE'] +- Containers: + - portracker: image=mostafawahied/portracker:1.2.2 state=running +- Port mappings: + - tcp 30233 -> 0.0.0.0:30233, :::30233 +- Volumes: + - /mnt/.ix-apps/app_mounts/portracker/data -> /data (bind, ) + - /var/run/docker.sock -> /var/run/docker.sock (bind, ) +- Networks: + - ix-portracker_default (driver=bridge, subnets=['172.16.23.0/24', 'fdb7:86ec:b1dd:16::/64']) + +### App: qbittorrent +- State: DEPLOYING | Version: 1.2.19 (app 5.1.4) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:30024/'} +- Description: The qBittorrent project aims to provide an open-source software alternative to mTorrent. +- Categories: ['media'] +- Containers: + - qbittorrent: image=ghcr.io/home-operations/qbittorrent:5.1.4 state=starting +- Port mappings: + - tcp 30024 -> 0.0.0.0:30024, :::30024 + - tcp 51413 -> 0.0.0.0:51413, :::51413 + - udp 51413 -> 0.0.0.0:51413, :::51413 +- Volumes: + - /mnt/storage.rushg.me/data/mediaV2/downloaded -> /downloads (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/qbittorrent/config -> /config (bind, ) +- Networks: + - ix-qbittorrent_default (driver=bridge, subnets=['172.16.19.0/24', 'fdb7:86ec:b1dd:12::/64']) + +### App: rushg-llama-cpp-proxy-n8n +- State: RUNNING | Version: 1.2.17 (app 1.2.15) | Train: stable | Custom: False | Upgrade available: False | Image updates: False +- Description: An application for deploying simple containers. +- Categories: ['custom'] +- Containers: + - rushg-llama-cpp-proxy-n8n: image=rushabhtechie/rushg-llama-cpp-proxy-n8n:latest state=running +- Port mappings: + - tcp 8000 -> 0.0.0.0:9091, :::9091 +- Networks: + - ix-rushg-llama-cpp-proxy-n8n_default (driver=bridge, subnets=['172.16.26.0/24', 'fdb7:86ec:b1dd:19::/64']) + +### App: rushg-me +- State: RUNNING | Version: 1.2.17 (app 1.2.15) | Train: stable | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:9092/'} +- Description: An application for deploying simple containers. +- Categories: ['custom'] +- Containers: + - rushg-me: image=rushabhtechie/rushg-portfolio:latest state=running +- Port mappings: + - tcp 80 -> 0.0.0.0:9092, :::9092 +- Networks: + - ix-rushg-me_default (driver=bridge, subnets=['172.16.24.0/24', 'fdb7:86ec:b1dd:17::/64']) + +### App: rushg-yahoofinance-api +- State: RUNNING | Version: 1.2.17 (app 1.2.15) | Train: stable | Custom: False | Upgrade available: False | Image updates: False +- Description: An application for deploying simple containers. +- Categories: ['custom'] +- Containers: + - rushg-yahoofinance-api: image=rushabhtechie/yahoo-scraper:latest state=running +- Networks: + - ix-rushg-yahoofinance-api_default (driver=bridge, subnets=['172.16.28.0/24', 'fdb7:86ec:b1dd:1b::/64']) + +### App: searxng +- State: RUNNING | Version: 1.2.115 (app 2025.12.26-f95442310) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:30053/'} +- Description: SearXNG is a privacy-respecting, hackable metasearch engine +- Categories: ['productivity'] +- Capabilities: ['SETGID', 'SETUID'] +- Containers: + - searxng: image=searxng/searxng:2025.12.26-f95442310 state=running +- Port mappings: + - tcp 30053 -> 0.0.0.0:30053, :::30053 +- Volumes: + - /mnt/fast.storage.rushg.me/datasets/apps/searxng -> /etc/searxng (bind, ) + - /mnt/.ix-apps/docker/volumes/b3cbb8a4b6cd1fe692228d2466cd678dff3667264496e438a2eb364c2f743178/_data -> /var/cache/searxng (volume, ) +- Networks: + - ix-searxng_default (driver=bridge, subnets=['172.16.27.0/24', 'fdb7:86ec:b1dd:1a::/64']) + +### App: steam-headless +- State: STOPPED | Version: 1.0.24 (app debian) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:31100/'} +- Description: A Headless Steam Docker image supporting NVIDIA GPU and accessible via Web UI +- Categories: ['games'] +- Capabilities: ['AUDIT_WRITE', 'CHOWN', 'DAC_OVERRIDE', 'FOWNER', 'FSETID', 'KILL', 'MKNOD', 'NET_ADMIN', 'SETGID', 'SETUID', 'SYS_ADMIN', 'SYS_NICE', 'SYS_RESOURCE'] + +### App: trilium-notes +- State: RUNNING | Version: 1.0.16 (app v0.101.1) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Web UI': 'http://0.0.0.0:30257/'} +- Description: Trilium Notes is a free and open-source, cross-platform hierarchical note taking application with focus on building large personal knowledge bases. +- Categories: ['productivity'] +- Capabilities: ['CHOWN', 'DAC_OVERRIDE', 'FOWNER', 'SETGID', 'SETUID'] +- Containers: + - trilium: image=ghcr.io/triliumnext/trilium:v0.101.1 state=running +- Port mappings: + - tcp 30257 -> 0.0.0.0:30257, :::30257 +- Volumes: + - /mnt/fast.storage.rushg.me/datasets/apps/trillium -> /data (bind, ) +- Networks: + - ix-trilium-notes_default (driver=bridge, subnets=['172.16.30.0/24', 'fdb7:86ec:b1dd:1d::/64']) + +### App: vaultwarden +- State: RUNNING | Version: 1.3.27 (app 1.35.0) | Train: community | Custom: False | Upgrade available: False | Image updates: False +- Portals: {'Admin Portal': 'http://0.0.0.0:30032/admin', 'Web UI': 'http://0.0.0.0:30032/'} +- Description: Alternative implementation of the Bitwarden server API written in Rust and compatible with upstream Bitwarden clients. +- Categories: ['security'] +- Containers: + - vaultwarden: image=vaultwarden/server:1.35.0 state=running + - postgres: image=postgres:17.7-bookworm state=running + - postgres_upgrade: image=ixsystems/postgres-upgrade:1.1.4 state=exited + - permissions: image=ixsystems/container-utils:1.0.2 state=exited +- Port mappings: + - tcp 30032 -> 0.0.0.0:30032, :::30032 +- Volumes: + - /mnt/fast.storage.rushg.me/datasets/apps/vaultwarden/data -> /data (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/vaultwarden/postgres -> /mnt/permission/postgres_postgres_data (bind, ) + - /mnt/fast.storage.rushg.me/datasets/apps/vaultwarden/postgres -> /var/lib/postgresql (bind, ) + - /mnt/.ix-apps/docker/volumes/dc89a6bdc0a7f9c00f8dd8a6b3f95d817761cefb3d6b80e1058109a07c9cc498/_data -> /var/lib/postgresql/data (volume, ) +- Networks: + - ix-vaultwarden_default (driver=bridge, subnets=['172.16.29.0/24', 'fdb7:86ec:b1dd:1c::/64']) + +## Apps > Docker Runtime (CLI capture) +docker stats (resource usage at capture time): +```text +NAME CPU % MEM USAGE / LIMIT NET I/O BLOCK I/O PIDS +ix-immich-recovery-server-1 1.03% 358.5MiB / 64.55GiB 2.85MB / 3.92MB 0B / 0B 144 +ix-immich-recovery-pgvecto-1 0.63% 63.38MiB / 64.55GiB 202kB / 386kB 0B / 0B 12 +ix-immich-recovery-machine-learning-1 0.10% 247.8MiB / 64.55GiB 31.4kB / 21.1kB 0B / 0B 131 +ix-immich-recovery-redis-1 0.49% 17.97MiB / 64.55GiB 3.65MB / 1.99MB 0B / 0B 6 +ix-llamacpp-llamacpp-1 0.10% 5.342GiB / 251.5GiB 8.61kB / 1.47kB 4.9GB / 0B 71 +ix-vaultwarden-vaultwarden-1 0.00% 27.53MiB / 4GiB 146kB / 144kB 229kB / 0B 133 +ix-vaultwarden-postgres-1 0.00% 29.16MiB / 4GiB 154kB / 138kB 365kB / 0B 10 +ix-metube-metube-1 0.00% 54.54MiB / 4GiB 11.9kB / 1.61kB 0B / 0B 4 +ix-ocrserver-ocrserver-1 0.00% 11.88MiB / 4GiB 11.9kB / 1.61kB 22.3MB / 0B 6 +ix-comfyui3-comfyui3-1 0.21% 1.165GiB / 100GiB 6.29MB / 405kB 578MB / 0B 152 +ix-plex-plex-1 0.21% 109.5MiB / 40GiB 671kB / 294kB 76.2MB / 0B 45 +ix-ollama-ollama-1 0.00% 158.9MiB / 40GiB 11.9kB / 1.61kB 146MB / 0B 24 +ix-rushg-yahoofinance-api-rushg-yahoofinance-api-1 0.01% 43.3MiB / 2GiB 0B / 0B 54.8MB / 0B 1 +ix-rushg-me-rushg-me-1 0.01% 27.14MiB / 256MiB 131kB / 123kB 20.3MB / 0B 6 +ix-trilium-notes-trilium-1 0.00% 110.3MiB / 4GiB 11.9kB / 1.61kB 44.6MB / 0B 11 +ix-searxng-searxng-1 0.00% 183.9MiB / 4GiB 462kB / 89.3kB 42.3MB / 0B 17 +ix-n8n-n8n-1 0.10% 408.7MiB / 4GiB 2.41MB / 1.09MB 112MB / 0B 20 +ix-n8n-postgres-1 0.02% 40.62MiB / 4GiB 1.07MB / 2.33MB 26.7MB / 0B 7 +ix-n8n-redis-1 0.20% 16.67MiB / 4GiB 14.6kB / 1.61kB 0B / 0B 7 +ix-open-webui-open-webui-1 0.12% 765.2MiB / 251.5GiB 58.2kB / 53.3kB 341MB / 0B 194 +ix-open-webui-redis-1 0.21% 19.6MiB / 251.5GiB 62.7kB / 32.9kB 6.83MB / 0B 7 +ix-photoprism-photoprism-1 5.90% 263.3MiB / 4GiB 11.9kB / 1.61kB 377MB / 0B 10 +ix-qbittorrent-qbittorrent-1 0.06% 31.06MiB / 40GiB 3.97MB / 186kB 24.8MB / 0B 11 +ix-invidious-internal-invidious-1 0.01% 26.45MiB / 4GiB 9.52MB / 3.46MB 3.03MB / 0B 2 +ix-invidious-internal-postgres-1 0.01% 44.42MiB / 4GiB 2.93MB / 1.24MB 21.2MB / 0B 11 +ix-invidious-internal-companion-1 0.01% 577.8MiB / 4GiB 12.7MB / 633kB 47MB / 0B 21 +ix-paperless-ngx-paperless-1 0.14% 571.3MiB / 4GiB 1.15MB / 2.73MB 84.4MB / 0B 21 +ix-paperless-ngx-postgres-1 0.00% 33.16MiB / 4GiB 169kB / 220kB 2.39MB / 0B 11 +ix-paperless-ngx-redis-1 0.25% 17.45MiB / 4GiB 2.59MB / 917kB 28.7kB / 0B 7 +ix-paperless-ngx-tika-1 0.20% 307.3MiB / 4GiB 18.7kB / 1.68kB 70.7MB / 0B 114 +ix-paperless-ngx-gotenberg-1 0.03% 115.2MiB / 4GiB 18.2kB / 1.61kB 111MB / 0B 24 +ix-rushg-llama-cpp-proxy-n8n-rushg-llama-cpp-proxy-n8n-1 0.09% 47.78MiB / 1GiB 11.9kB / 1.68kB 16MB / 0B 5 +ix-portracker-portracker-1 0.00% 52.75MiB / 4GiB 11.9kB / 1.61kB 30.6MB / 0B 7 +ix-pihole-pihole-1 6.98% 233.3MiB / 4GiB 41.1MB / 168MB 62.8MB / 0B 17 +ix-open-speed-test-open-speed-test-1 0.00% 81.16MiB / 4GiB 11.9kB / 1.61kB 5.58MB / 0B 67 +ix-netdata-netdata-1 48.99% 1013MiB / 4GiB 131kB / 669kB 1.32GB / 0B 267 +ix-nginx-proxy-manager-npm-1 0.24% 212MiB / 4GiB 3.31MB / 2.69MB 99.6MB / 0B 87 +ix-netbootxyz-netboot-1 0.01% 82.12MiB / 4GiB 0B / 0B 49.2MB / 0B 14 +ix-komga-komga-1 0.09% 919.9MiB / 4GiB 11.9kB / 1.61kB 148MB / 0B 92 +ix-it-tools-it-tools-1 0.00% 49.08MiB / 4GiB 11.9kB / 1.61kB 5.22MB / 0B 65 +ix-invidious-invidious-1 0.01% 16.47MiB / 4GiB 8.03MB / 2.9MB 0B / 0B 2 +ix-glances-glances-1 1.76% 75.86MiB / 4GiB 11.9kB / 2.24kB 26.5MB / 0B 41 +ix-invidious-postgres-1 0.00% 28.23MiB / 4GiB 2.46MB / 1.13MB 3.51MB / 0B 8 +ix-gitea-gitea-1 0.03% 141.1MiB / 4GiB 561kB / 457kB 58.7MB / 0B 46 +ix-invidious-companion-1 0.01% 546MiB / 4GiB 12.7MB / 631kB 455kB / 0B 21 +ix-gitea-postgres-1 0.00% 30.06MiB / 4GiB 468kB / 549kB 2.23MB / 0B 8 +ix-filebrowser-filebrowser-1 0.00% 25.33MiB / 4GiB 11.9kB / 1.61kB 14.5MB / 0B 24 +ix-dozzle-dozzle-1 0.00% 47.39MiB / 4GiB 0B / 0B 21.7MB / 0B 33 +``` +docker networks: +```text +NETWORK ID NAME DRIVER SCOPE +f063f8091f22 bridge bridge local +90313c972301 host host local +5f5b6c11b64e ix-comfyui3_default bridge local +85246d1b071f ix-filebrowser_default bridge local +6a228a6ece0c ix-gitea_default bridge local +66d93dcd7fb8 ix-glances_default bridge local +e8a416d5ff38 ix-immich-recovery_default bridge local +184c17b679ff ix-invidious-internal_default bridge local +422385298a72 ix-invidious_default bridge local +be73cd117898 ix-it-tools_default bridge local +3ddb1c0ab0b2 ix-komga_default bridge local +c3e8bd9922e0 ix-llamacpp_default bridge local +40cffe89c78e ix-metube_default bridge local +b7096e8f4f91 ix-n8n_default bridge local +84e30fa37bdd ix-netdata_default bridge local +23af6780ce55 ix-nginx-proxy-manager_default bridge local +3abcd4af8d66 ix-ocrserver_default bridge local +6b33bfd94074 ix-ollama_default bridge local +c0313dc6a6a9 ix-open-speed-test_default bridge local +2138b854341a ix-open-webui_default bridge local +d76b25dd13ac ix-options-train_default bridge local +3eec2c5081b0 ix-paperless-ngx_default bridge local +5b6cd71cc4ce ix-photoprism_default bridge local +2fb7a8f9b1bb ix-pihole_default bridge local +7af16c94babb ix-plex_default bridge local +801715661e3e ix-portracker_default bridge local +f1d732fd2c52 ix-qbittorrent_default bridge local +92ecb49174e5 ix-rushg-llama-cpp-proxy-n8n_default bridge local +c26c0a6f6c71 ix-rushg-me_default bridge local +ac6a69b989d2 ix-rushg-yahoofinance-api_default bridge local +051296e5c6e4 ix-searxng_default bridge local +f315f0473410 ix-trilium-notes_default bridge local +d6ad522e0d74 ix-vaultwarden_default bridge local +7d4dd275bf37 none null local +``` +docker volumes: +```text +DRIVER VOLUME NAME +local 0a093777f43c7b7f1e7b5131217150a43623968019df675f136d66681a46c294 +local 0aab0a3e3c34a0573a2abe8b81b4bd5491766dd534901accf6db989a07a6ed73 +local 0b0739ca34925c87f124ab527273209f5cf9feb5e7061f4320a71ff616c30d73 +local 0c4d2f746592355ca82fc0677129e309438819e1aafa7124f939b3a7e28c205d +local 0dbff1f824bde6ab60055e9b6fd517f5a45ac074b55c9792a71a4cecddbdd25f +local 0e8cddba1835288884d5dfac7a5f7856c3fe3a159e1f7d7fcd82876324ea6772 +local 0e170671f3aa6c50fc769664b5aba26ee3f9ad8ea2c4564d7e9570e47bfb4d23 +local 1cd0c91f3606fcbea8a160a9fe71445ae593d78f100d0c951af40facbc15e0b5 +local 1f7edecd40e0a5e4306f9854a1b8bb4c7aace2f18a4607d4643d1ad0e6351b6b +local 1f38f35d7393939465a5ba07d51994ab3d5d5783b4c07e3012fe470d8690800a +local 2b5a9373bd24f24d35a0273079128bfebf5cbf6084e000ae37712fb52adcc10d +local 2b3518bc18cee445e5d53145fc04c0e9d4cf4d234211190961cb35033c89eebc +local 2ba79baf50ae068114bd2b4a6466b64d0e57dfbdd09ebb151696a7f1f53dceb8 +local 2d46060cc27c290166a47a0a3d28e9e688c83f9647b31e4a6265114d37e7d332 +local 2e5830fc4a28f19757216c036a39fa6469b15018c912fd6c89252d8f517c7eb5 +local 2ffb54dcdd0697796e765cc3c69b8de2494edf480c33769ae518573de6e26a00 +local 02b9f99c5749a75b8c1e36a046bc3a1cd80ad5a24ca7ae80e77b64c62ff79c31 +local 02ed5a11571f341ed99208957f5a6a910ac8c0a9a8825a47b2ed8e65ccda9140 +local 3a0e61f239a9726cd2ab7c71838902d2fb45a84c8a069871116d7652b881c728 +local 3a45d2ff486a242f4abca28c6c8acd68e6a77da93376588c2e14d68345288351 +local 3b49d4110a455d96e7069e00c6a5c4a3beaac4e781cf9b9296f9cd38bb06f3f0 +local 3c7c54dace26080b2c49603266822c823585a616bc629e7292ccbabf2f729fec +local 3c01354c1288e8b64b52b9ba30d5c963a67ad02effa52c118f0ca7e30976e5c0 +local 3cfecd9127295e6f3b86e3b150ab3836147f8788a2e4557cd04a6550c220b43c +local 3e4823235c1a495d53410a5615c3fdcc0759d951085d3185c264f798b03623df +local 3ff2b80487fd35b90a0b8bc18cea19fac184273f20488cb55a84ab5862faedb8 +local 03ad6369a322524651a3c0ab000a694bd11464bf05dc42ebadbe37cf14d598b1 +local 4a7f46aedb426db60be998792e3edef11ebec0f4197dde48d4f1cd0f0e455f7d +local 4a64d89ad812c1f3e3e7554560110bdba51adfde90b798dcb5c4c8fbe7a24553 +local 4c7d73b17641781d99b9d2c6e16f4d8b86955d17da4fd0bedc0cabf35f9d4c87 +local 4c7410b7255c47d7e9a7556d8181ed5d5eb64fdc0cc701a93bc4a4626c87c479 +local 4d0158aea9afc11781917f1f5ede2ad394b356625bc4099d9db484c139660f8f +local 4e7304b51c6e41daac21f262e29b5746dffda4fe4720cd7a5a7c1822b5d93958 +local 5a53df5979ef527a1d9c6244ae8817dbc17c51125b2b1d14d29443208ffb4e21 +local 5adb97f5247bb0228800e3483d9ac5b6ffe15a0abc5c29eee823edcbef6e3943 +local 5cab5c4448eb7670dc6c5d200fed605978a5ba8c62ec9bd43d690c8e4407c5ea +local 5e86b147f3bab9ac182bd0656a5283e5fb8a6ed6d1573c9c8e2c40c5a0bd2864 +local 5f4097304cd91f22ffb2cbf35cdfcf868fcb75b62f582396da78648ca2f435c2 +local 6a92ac9c4fd7f4caf3b77529990e74c1747cfaa0eed6ae3f613e96f92676659c +local 6b7f612b1a3424090023ed991d94b30f9442a8765684be896ac2b2bbe32901f6 +local 6bb58e9c53696dc5f8b30710879685399462c15beeee8e939135785a4c97df39 +local 06a5cc31a6ad63f43046d16ea88c5ff94575e2c0290d3475e949bd8c485d0ceb +local 7a12f1f00edffee620c2565ca92d95c3856e2d5fe2bbdac3d143564f10ce4df0 +local 7a119b52a10f967d52fe12ac387d24af60f9da29c4a00a5ac3ffa5a453876cf8 +local 7ae9ecf67f0866c6a1309d502118190da401bb26f15c64d7456e76fdd0ebd1be +local 7bc5a172e7b79d19129c6a6b9a019723302c159723c16cd2eadbaee169b96ad4 +local 7cb4260e258f8f4e0f37544f11f323c8f02e31555a55c2347f3ef3cbaa6c6785 +local 7cfc62a095502c98e525b09bebf2b9da88969e7cf77c44350c454d1088f34355 +local 7d83dd9b31f35921c784885aca10495d1d835489c5950080c1984dfbb3889ab1 +local 7e7289df8d511c6600ca4d4fd817091cdf628d70933081996c9914f7df0239ee +local 8a7997b8cc4f839002d356c43da39bb186f61fdf6f9037078fbf61b515cf3c80 +local 8b23449f0555faaba1c8cbbb109c0499338c04ed64b39f0789b12f95d64407fe +local 8dbd342963e6c41f604166d57aeab4cc0ebf19835d71fa631ba91b30d73a808f +local 8e3147a2a1330a67a2cd9e3dbd666a896d771850af4f081881ab6f96386f7aec +local 8f8620a409ce0f30c75bd0d98745365eaff444299a11ca24b963f5a47f4ec3bd +local 8ffe43dbe695428b5b7026588d1488b86936eeb04993efeaab303dd4f0e6fbda +local 9b1116ddbbb08dbcea58bfa94b8a42b44553755f6110f7ca72e464775a83eed4 +local 9cb332728217e378bd753bccd424226bc22b8beb02deedc50ef592a434c2bf5d +local 9d56ef5a28d7af079b0798274002ca1aa7839adf0cf5bf8015c6556b3ba9da79 +local 9e7c941434cf60d7d00f99322ed368194957693797bd136cc9c8306de1fa5cc9 +local 9e2184a2ea0fdb33a7de2d7eba3e210bafeb5e612f16e09e149ff559c1b10ebc +local 10e4bdc66665ee366902e3e02a8ccdb6e7f4ea0e90a4354054bf16f9b49b85c3 +local 12dd37d584e82db39138e949058c05d750732b6442aa7d4b42ef705c405ebf32 +local 16af23d4931945e02506be64d4ba3809c215811527ac3992fd7f0991d711234d +local 16d48b379f2df0f40c2edb9afe2db7bb59b1e23c9c45a369fd5c17c14e6877c7 +local 18d14a15fa526aad04685ee54c9eb92263579a25ac82641fb2de722474237d96 +local 20d84a5d536cc5153c22244408d50c6845747366d2a90d411f40185852891348 +local 021a9aff23681b8256095d0386b96c197540a2f08694d34ad7163f3bd1ce8db0 +local 24b5fd2c2e6bab2d39ef830a094608642c73517460ecfd250aaedf08583433df +local 26b52aa0ba3f892882ca5ded42624a704752dd9cf30c1a202eb64c2d25bf9b40 +local 26b338476e31b41d15cb21ae71557bb6063ae5566f8c3515173acc910fdb6c25 +local 27d9b8a5956d709b37583fd312447c477f50a614711098db34d211217368e8e4 +local 29e8d599d30b356cf9c4a9c4c99a43898a1266a59a0304ddc647a1b1cf15c08e +local 32b3c6fa47197e8dadc894ccc541eeb9e046fb0b2b67ad79d639e44225b5c870 +local 40eac2bf2f768f65e0f4b1540a0e343ce4e4a07405929fe447701fc5a6bf27b8 +local 42f56be205b7256e6526b955ee209c490e6fab41d241b3f73692ffb700c2f0ad +local 43e284ef05d3377381c24fac91c17e304b6d5a9a47bdfd05169d8861a3356f09 +local 44ee67d8e2f6d4a1b2278b41e674c072d8c700d09ff17a64288383365ce45ed8 +local 49dc5ecf1697121ba7b166916fa8fba632a2457869cc6d108fcc4f26a7d6378f +local 53d4248da37f9f274b8885b9ede6d7b2fa67014f925f8a510292819dd2c64394 +local 56bf5837d5aba32b9d3e183cf097133ef2be64995897968af6b522b862fa1af5 +local 61c1dd4e88f60d8b352e1cfd1f051d8694cbebf741e4aaca9c9f6ee2a63ae553 +local 61f7713fd4600c268aa9fdff1ad97023978e7f48e691e8a4bb63a38402a212f8 +local 70f5be97ddaee9ca004974e038d5a5c415f5e37a13070800ebedc6e7750ba92c +local 74b2f527828c263b153b631d82e8550fa545af27560e149a26030665bd5d1a2e +local 78b9ecf32a1a6798ef20b45d735343aa4a1f876f11268c435e5a11be5f08e75d +local 81ca524bb364cacec19921eaf3094ea6786e1c80fcbf91d20e56aeb5e5ca015e +local 83b89d537d5bbd44ffed5342c7ecf96bb5e28d901a651ee8513aeec5854de409 +local 84ac66f9a33a51784126f5f3113084c73b1b6923c7f1270caaab0d333a1967b7 +local 085d5a396a8095e1a98fa8c494dfbcac0ba8d1b563d580b9a6d54ff44b7e0dfe +local 87ad7f75ebcbbbe98f79dd15f8001e3155a34ba3d7ac87de93c1e22e3a847eff +local 99b689e215e9dab6c946211f2a1ce041b07bc68d90112f35f4f709241ccd81d5 +local 108d8fe64e16d36b274fecc039fdc57bf78f9a6a0315685012b1d5bdfe24ec05 +local 115a531b7ee064313c9fc93b59c3f90fa5fcdc90c71969cf01c02d0ed7de11a6 +local 183fab14b00b17a44867487485aefdb504bab1307e3c428203ec1fadd24a064d +local 239f0fafb8a7cbd23e944d779a3de9d2ff6bd23b58819e19a0adb44e181f1d5f +local 269afaacd13189e5b468113887d2d271d5e94a1f0bfb887fbb41b9d50008137d +local 292cd1c8ed420f384b2622982f5b642a6c3b147bd383a211ca6acb0fb29466a5 +local 430fe8b0f70f0e59633b0184b7788ac7b2d9571f7de91414be95359ee3c77983 +local 459c3bc67390a788385ec2a5958f97520f86431ecb3ed862a53828fb0b33ad96 +local 501c53f2af7824d5be184133210ad7652e4b03fcbbcd6a54f0466251e2a480e5 +local 506e2292f2eb693fc39213f73686348a556f030c8254476a71dc9fea955f1dd1 +local 543a1c5765991aacfde32a74cc955c2b396c0eb88c9da37f263240062db62462 +local 622e368e5c4ef3ca74214ee5155ca98290ad8d837a82cf5c673806532b461118 +local 692e9de64a2a00c1c0a1aa2155a46767ea6b2f5775fbd3b9cfdf2ec4d2e79348 +local 736fe853fd61b234d13e5b5ff534df79cbb89deb30c8f28f77cc23e7c2ac91e3 +local 777d279481b693fb4e12b991e5700322f9131a15e776fff9f57711daafbcf071 +local 785c7d85ee7ecad4ac669f450ad90d764d307ee91d37cbc2fa8bc82d673e9a68 +local 797c27fe1d60336deb2a8847927366a335bcf7a67521d986ed926903403af472 +local 844e97fe870285140fbe81fa4e9884ad25bd0e1839bfc7075b0b866443619ae3 +local 858b99113a297026d5cd6c490515487ec123c766aaf3e047c9ad8e75036028e7 +local 864a5b59820c2505c0790062c2cc2434f4bab963c7eb037b79e08d0af43c78d8 +local 971d52d071a24d3ec1b286ad3913eb003dd31fe376de2c6a22fc62f2409f832f +local 1034e8d1e01485ac22c51cd9375ec780789e5b8c2bdaeac3bec75eed2b774ff1 +local 1919baaf6c7d5e43ef9bca0491211582aee6710259cbec5ecdd39dc23eed00a8 +local 2934e733eac703219d5fe1bee14ce41be47610020adfc0c7735985af885b091e +local 3217d85532005c10a19ce77df674a991c76d9e177451a0be3e73fa881ea476cf +local 3353a41aea808138ab099dd6cfb87de13e259888f3ace1c3d8012f80ad2a68c1 +local 3353d716ff7520c60ad068b01d87007fd3580f84efdcf63f4c61b7ab29f5ffc0 +local 5339eb9dc6eec5f6de255191f610381e2e8cd3328afb36adee71bf846c10db5a +local 6675ffe31134497fca6eef0f83b9fdd33ae298b80526e58706d013c5755caf5e +local 7240aa7fcf4099ad4dee82b3415b34f8ae60d8f9618074341be2e62b8c178a33 +local 7919b5a2cea1b7df778f2177bf8d4c42ea87a81335632c9d96fcf07291fb6c26 +local 7929b341d8896f7350da166349a64f527e15170a6e4b62827546d839a6f248f6 +local 8304bc45e9b4fe499d3004c495b1528b881c7c06d1684c1a7aa02b9339be5468 +local 09516dd248bc701918bd42bdfae26b1b9f4a4748138bb71884dfeb300fb8c055 +local 14520e54e52030ad7c83816badc404a412a297b45e5ecfac6114aaec80dc6eac +local 15340c45d33c36f49c768ab98638319f65b4ba6347975801b153dbd21c131409 +local 37535ebd5e41f682c0874e975ef3f591073c1988a250bdd81a977f5e7ce837ec +local 41501d6e95f1b9efd8c053d737fb12677aabe7906648c06c1266e3f5b0ee4695 +local 43041e1cbc6297c5fe66a781f5f1872ae7f82a7dc5430bf0ed8c751425455e45 +local 55198c82f60a2e529a630b93a337391a4ea3fb195becb5fd3c7ef3b09d397f6a +local 58391a663e66fd8c3e3a5279760170f456c08548eb50eaae6d19912cf88df3b3 +local 68357be06932902d5f743cbc41d12fde6f3a071fa40e84757410103b27bba4ac +local 79815f5e39c9fe297a882ed490464b54c129225a55ac607e9cd08b1afa0542fb +local 87255a277cc4704c9a6167429b4d92b3c44e0ce30b8b7662724945a6cea564dc +local 89870cea507d93bd27a6044b8c99e8d64f282cc399125ffc6e10c8006d61179a +local 112781dbf7feae3d84390206b4995f0e474025d0750ef8668d3ba82ec7fbaed4 +local 192405b6b7e50de2da2020ac828d495ba5d00942f67002577f42ee39dd7a935e +local 375936ac84f17b8d7236846104fbeb80ca00ac73113bbadbb0845fd460610dd4 +local 413431df69fa3ad4fe0cefbcfcc2d53282366265d62cd351560b8521c32d1937 +local 522768d235b63049360fa75de835456ce53526815b531b03281e0dfa13c9961f +local 557357b25ae605c013dec7693aefdd4d145d296b0c3b9b3eadc772b1ab189612 +local 956567f23a03478de0efdf20acde6036ab415c9b8d2aa7e2a2d04dca2c279c68 +local 1979716c954af6d6b5f87c4f6ab0acc9a7a610309fae64395db034f03d786a7b +local 9378122a5a512249ef6a135f8e5231f1e747f1a5b86a6a578ac11108842dc13f +local 025809373ec35a76b2382ffdd41696d6039c05d948dad89805c9788d5bab24f2 +local 50209612dbbb505073790e8b5976699ea5c0c8a8435d73e55bc695c276e2b803 +local 62699500a5f82d4f69f0f23656a62de8c2431534ca6f8ff61505bf03bafa5d26 +local 91426594c1a0a64e9b654b54766788224ab3e9a9f594d7ea725b64b17bb6167e +local 990766571eeb917bbace765084b10d0b70045590d14474d5382169bbb41bd4ee +local 49425559633ee94f47cfe5ed128f77e8b4ff6e3a36687436a917bb4697ab666e +local 92814204659b667294d3bfbfcaee99f2d3a9e43bf2a6cc0a2864415aaf6a611e +local a9bf7a1ef3404f74b178ac0634c69b7596c9e422d88119ab7bf9687af866eda8 +local a30bb4b1aa1f7b81d9a6251bb7260e5ffc4b16a0f12b1a623c90fa59e47d8834 +local a033f0f1ba5df7211936db5835bd228d2f34b24719d8f4e967591b3537e6c4a7 +local a96b1f91c5748999db781d5df998dbb1a91980782fb43dc8ae140d98f89b1b51 +local a436c94dd43f1584d07ca0fbbb4ada34c13e302860eab8c7854e6ac026b31f33 +local a8104b53366179cd5e518b23efff803b36b30da8564021d36ea25522f795fed8 +local aae229a4285242265c6c45ebbdd067aed322284216280de48bda8248f6706689 +local ab2dbfddeea377e9a0e985671a99f14f6c181af447e8e9d27e0a84e8d9702c0e +local ac694aa889790ab72d74e0b03e02223f66033901ec7a8535dad3513dd1542b16 +local ad9501f66cb10e7dd176e60adacf4c3f629278b20f1d39ac0409c3810c0ce574 +local ae73cb0ce34cb08d3a938251c1a65a6b6810619dfcbc2f271b626204e682915a +local af90dacb912396778625accc60056f3f613c8248455927afcac602e740404702 +local af95d7d4da5cebed813953d7431f069631fc99f14dac2913c0c0098226c59c5d +local b0a1c240b32d49b169d20747d7c737178ca454231cc2be27101ebf8fd033903c +local b0fba1213377b4bc48cf3d729658baac74456f7fa6703605b2981f3ecd98c0e0 +local b3cbb8a4b6cd1fe692228d2466cd678dff3667264496e438a2eb364c2f743178 +local b09f34854edae02bc159c11b302bfea0038dc620ad58c7110451728da2f1ae30 +local b28c697655262b8c248e8d1bce4fd7b9515cf8520bef6900cabfa30e1e4d1030 +local b86f4cafffdd7ac7c4fe452cab854f1a2b896a01556505c65154341f55f61338 +local b006000acd1b8d183567a76ea52e2e60858b83ae48b69bb17bed21c644a76681 +local bc0df63c6ea041bdfaef7766bdc2ae6341aa2bc5cedd2efc1a51de2de21876bf +local bd98cc3f739d7b8ef541ce6b47939cb0332fa010d404d338792c8da72b899eee +local bd305b3b7d3930f8db3d680a24b22d058a591bf4fd771fb1426ac903e5ef2e7d +local bf2e94099154e243f3cdadd6d80ad52f17a1fa37fee73735e51e06630b8070c6 +local c9ceac744073680aee76d8e2e557496317812be938263e9311368dc90f97add2 +local c11f573be672894150855ca14b39bca359cb3b32a6c74ddbd5d0630ec0018720 +local c74fd70bdde9a77863ce56e696ae00c5a3ec5f3051e9dc7cb0fe06408da5eebd +local c506be4297518a708aba6cc36655dd6b0034433078ca9fe1e6602ea15d8ad9e7 +local c722fdf3b574cd95a37846edcf258bf5e28963e817a2ee3c88b4496b94833d8a +local c6362cc2e4aa4056a3ecff9d397548b6953b82d509b4ea59f490a1c2f4245b6c +local c39643efaa2b6d8b8db8f3cc34bba3bd18a76c4b4de5419f856f27ca51574e23 +local c641105dc19033a51569de89d171e282f5ae293bd62eba4c1d98e22cb3a36426 +local c760246fdf1c405af52325f8107db53df052ba5e1853c0fa7880077e1ab53898 +local cae9f7714d2921d5665e09f55540345d04f5ab27200bc310403b51360df29524 +local cc5e6aa6f5f89442396b10d8aaad38e454067b001fd2eb986dda912b1cb2d6cf +local cc267df27a50c3dc10b37157fcfaba1127be85efb8ac8ec57cb3c2e005f4fecc +local cd88e5e83c52a63320e6dce902cd2c4ab9f9ef4d0a2c78e8f689bdaf529b32dd +local cd410a9a5141744d52fe5aafaea4ca1f335c828097ae4739f53198a065637a38 +local ce127a368da0e688ec066fb27d5c792e2b54397a2ddf4eb6c0d70638e53829e3 +local cef0849a929ea2f5b262eff7f0f01b2efed450863e0f426e78ab0de84efab2c4 +local d0e3e3300e9f232eca6e305596b41c165b1ed63841960d77e630ad9bc8431e2b +local d3c4304d66972431f0664b41912677594959b1ef50b27531b604e49cf5b37179 +local d3e7c50cc9939e89841a573d07fc41638aaf585508a307681c33cf2bcde89879 +local d3f0d4562a29d11b89951bce6a27b34b00d1f32a0e28fff2856da717381b4aa5 +local d7d5d26d413bd05bc8dc009a31546dcc663e2075ab4d9625517ad67d573a54a9 +local d17b69de56b87ab0a8c18dcb96d1be66d78cc8fab9c7525dba51dda31069de2b +local d347d7b175379c4779a26a6291ce7b767cd9361655ef02afd7a4fdd62b81f72d +local d3120b11d58c7d6235fcc2614c299243eabf69930693a96d366d5409b687433c +local d8253b14346efe44b12b9e8ee5c300d7d41e29743a04b082917e19881e59e5d5 +local d9421a81c280dfcccb437dce683cb63dc6efb11a1b9526ed4e9adf3650df5c12 +local d2050654f661898e99ef417f2e51f7a919c24e523971a37c854226ce69cd162a +local d7361488b6751179cf4f668286002d1ebef18cfb696840a4fe2f26a66bef39b9 +local dc89a6bdc0a7f9c00f8dd8a6b3f95d817761cefb3d6b80e1058109a07c9cc498 +local dc41647d27e862bd71e32fa1c6471af68961f5e72d6e3c6607df14b8df33f29d +local dd846b0b99ce9c38e1084f0650cb5d4e04955e5226c5cde7f2c99b00eba89417 +local ddded6a4060597edcb52c8657c0ca5374b3339ee958edc7df068d074d8098eba +local dffdf51b172d4e36e4b2dbc5792f639b7b1f688be2c8f8b6c6ed05e98c12f1ec +local e00c9934e5e17c555ba6fab299063122c17e554b4ec69751deed335e42b046c0 +local e1bd360f34adc79c4fafb314b31bc7965f0945306447ec22b7ebd2b0bcac8be7 +local e4e8f8532f62626f554aeb2f7650b41b91d5504738ec3f59f60279ab4849865c +local e5e431dd8a5a5cfcdba2904559cc00050dbc96f575205a56089f898d89f1e7cb +local e18c2f6469b9f40f2f88d60c28053c30a75b2376bae4ce05185a6411108e6687 +local e33a28955f39bf389a382c8b3a81d0d1e44d586b9327eecb2cd341978bff9d52 +local e49a9e5835008d2207fd9a57076282e51ad849212ce0c194ae4add083a088097 +local e51ff5710266d6629f4a0799960a099c6d29545c6b328c0bc5502b3c93e243f0 +local e7079f5c8dd3c2933e3255812bb5027d92fc2fb06ce1fcd5237ec154e85b6193 +local e7087c615dc320c041fabf79562a60941ec92db77663d73608a61c6587732f4a +local e14648a1fe28f159474564000fe23b190280767be30d9c4f2779b0fd6179d61a +local e80894f2a3849f17c3c5e3cc9383c199e8ba4fb039cc16b0dcd7b863d5ccfc7d +local eb841807995b2554f8fed74d42b708d9dbdd6f38613cc5b0c698f30daf13cab5 +local ebb35e61c3d354855c9b88aefacc6f4690f454826243dbb03d6978288ea89562 +local eda917d8702cc42c20c3945c9f46905e58a8d48b80c0e3f98889d5e7d6c401a9 +local edbb6c97fff00d7746d0827673fbf738756e9146881311057ca2d7bd0f9dc027 +local f1ada2abb0f1b98995bdc399134c4e228a3d58c1734a527b2790be9683cadfd0 +local f3df2071afbbc83ef402def7578baaaf69a1706746202b8453be9283b3c626a7 +local f4f092523c6db1136cfd74b008c85b1397d08af7013c7da2defe04d9de2dfb5d +local f5c6eb9ac0c9437cf3366052aaf9f68f76b88636cc76056c4a4b9820363947c4 +local f8cb37061084e7aef9d87b48bf6cf3f92a08892198263c32d13983a3306b515d +local f16ae530dc44b757ac121ff5654f983a8fab5ead201d8da85e2001ee6c4ce5ee +local f21da5532255ccca3df87b87875cd48d03fb7f010067250689831e73d1ba7565 +local f53f44e5e995b0b4d943a6c1ed0b9efa13ece327a54ad1ad740039b4817570fd +local f361dd7c6a5e4def7d87aeebd1472921c4dbeed09a262ed2ea3d1b2ee0915e77 +local f544eb9eed6161d9b295d9e15fe984cc6b1b2c922357830b77303c3326aa6f79 +local f5503b62b5178222775cb1fe1d1c8f436715c043ac8f786f6fce5d92d8817295 +local f6593e10993aca660005af1492228bc5047abd42ce23a142523f3bb5c597ac22 +local f442163b22e547373bb57ed6c0d710c3fc096b73cec14e1a095aca35717b941f +local fbec9e5e1755def2cf027506d835d39a7d3097c9983458dc1ffede74c1aeb320 +local ff681499b5f2ba1796c3afefa9fab4d17257c45b97abfbf3e45025c2cd34def8 +local ffc4b9a4ef19c330fff22cdf465a4ca6f4b0a68fc94e785f362e9ca7649e2b4e +local ffc225fb3c1e173fb4b2723f764d7a4dc35066751f592d24e2fa43a5ded36896 +local ix-gitea_tmp-gitea +local ix-immich-recovery_cli-temp-storage +local ix-immich-recovery_ml-cache +local ix-immich-recovery_redis-data +local ix-immich-rushabhperms_ml-cache +local ix-immich-rushabhperms_redis-data +local ix-invidious-internal_shared +local ix-invidious_shared +local ix-n8n_redis-data +local ix-n8n_tmp-n8n-npm-cache +local ix-open-webui_redis_data +local ix-paperless-ngx_redis-data +local ix-plex_plex-logs +local ix-plex_plex-transcodes +``` + +## Virtualization > VMs +- VM HomeAssistant (id=1): state=RUNNING vcpus=1 memory_mib=8096 bootloader=UEFI autostart=True + - Devices: + - DISK: path=/dev/zvol/fast.storage.rushg.me/datasets/vms/homeassistant_ported type=VIRTIO iotype=THREADS serial=PI4XDP1C + - NIC: type=VIRTIO mac=00:a0:98:63:f4:45 attach=enp65s0 + - NIC: type=VIRTIO mac=00:a0:98:70:a3:9f attach=enp65s0d1 + - DISPLAY: type=VNC port=5900 bind=0.0.0.0 +- VM windows10APIServer (id=2): state=STOPPED vcpus=1 memory_mib=20480 bootloader=UEFI autostart=False + - Devices: + - DISK: path=/dev/zvol/fast.storage.rushg.me/datasets/vms/windowsAPIServer type=AHCI iotype=THREADS serial=orMolscx + - NIC: type=VIRTIO mac=00:a0:98:4f:f5:bf attach=enp65s0d1 + - DISPLAY: type=VNC port=5902 bind=0.0.0.0 +- VM ubuntuServer (id=6): state=RUNNING vcpus=2 memory_mib=4096 bootloader=UEFI autostart=True + - Devices: + - DISK: path=/dev/zvol/fast.storage.rushg.me/datasets/vms/ubuntu type=VIRTIO iotype=THREADS serial=sBC4x4Vb + - NIC: type=VIRTIO mac=00:a0:98:51:98:98 attach=enp65s0d1 + - DISPLAY: type=VNC port=5904 bind=0.0.0.0 + - PCI: pptdev=pci_0000_42_00_0 + - CDROM: path=/mnt/storage.rushg.me/data/softwares/Softwares/ubuntu-24.04.3-desktop-amd64.iso + +## Credentials > Users +User list (username uid full_name shell home builtin locked smb): +```text +root 0 root /usr/bin/zsh /root True False False +daemon 1 Owner of many system processes /usr/sbin/nologin /usr/sbin True False False +bin 2 Binaries Commands and Source /usr/sbin/nologin /bin True False False +games 5 Games pseudo-user /usr/sbin/nologin /usr/games True False False +news 9 News Subsystem /usr/sbin/nologin /var/spool/news True False False +man 6 Mister Man Pages /usr/sbin/nologin /var/cache/man True False False +sshd 111 Secure Shell Daemon /usr/sbin/nologin /var/empty True False False +proxy 13 Packet Filter pseudo-user /usr/sbin/nologin /bin True False False +uucp 10 UUCP pseudo-user /usr/sbin/nologin /var/spool/uucp True False False +nobody 65534 Unprivileged user /usr/sbin/nologin /var/empty True False False +avahi 105 avahi user /usr/sbin/nologin /var/empty True False False +messagebus 104 messagebus user /usr/sbin/nologin /var/empty True False False +ftp 121 /usr/sbin/nologin /var/empty True False False +ladvd 124 ladvd user /usr/sbin/nologin /var/empty True False False +webdav 666 WebDAV Anonymous User /usr/sbin/nologin /var/empty True False False +consul 108 Consul Daemon /usr/sbin/nologin /var/tmp/consul True False False +nslcd 110 Nslcd Daemon /usr/sbin/nologin /var/tmp/nslcd True False False +truenas_admin 950 Local Administrator /usr/bin/zsh /home/truenas_admin False False False +sys 3 sys /usr/sbin/nologin /dev True False False +sync 4 sync /bin/sync /bin True False False +lp 7 lp /usr/sbin/nologin /var/spool/lpd True False False +mail 8 mail /usr/sbin/nologin /var/mail True False False +www-data 33 www-data /usr/sbin/nologin /var/www True False False +backup 34 backup /usr/sbin/nologin /var/backups True False False +list 38 Mailing List Manager /usr/sbin/nologin /var/list True False False +irc 39 ircd /usr/sbin/nologin /run/ircd True False False +gnats 41 Gnats Bug-Reporting System (admin) /usr/sbin/nologin /var/lib/gnats True False False +_apt 100 /usr/sbin/nologin /var/empty True False False +systemd-timesync 101 systemd Time Synchronization /usr/sbin/nologin /run/systemd True False False +systemd-network 102 systemd Network Management /usr/sbin/nologin /run/systemd True False False +systemd-resolve 103 systemd Resolver /usr/sbin/nologin /run/systemd True False False +_rpc 106 /usr/sbin/nologin /run/rpcbind True False False +statd 107 /usr/sbin/nologin /var/lib/nfs True False False +nvpd 109 NVIDIA Persistence Daemon /usr/sbin/nologin /var/run/nvpd/ True False False +systemd-coredump 112 systemd Core Dumper /usr/sbin/nologin /run/systemd True False False +Debian-snmp 113 /bin/false /var/lib/snmp True False False +ntp 114 /usr/sbin/nologin /var/empty True False False +Debian-exim 115 /usr/sbin/nologin /var/spool/exim4 True False False +tftp 116 tftp daemon /usr/sbin/nologin /srv/tftp True False False +tcpdump 118 /usr/sbin/nologin /var/empty True False False +proftpd 120 /usr/sbin/nologin /run/proftpd True False False +nut 122 /usr/sbin/nologin /var/lib/nut True False False +dnsmasq 123 dnsmasq /usr/sbin/nologin /var/lib/misc True False False +nova 125 /bin/bash /var/lib/nova True False False +apps 568 Unprivileged Apps User /usr/sbin/nologin /var/empty True False False +libvirt-qemu 986 Libvirt Qemu /usr/sbin/nologin /var/lib/libvirt True False False +haproxy 126 /usr/sbin/nologin /var/lib/haproxy True False False +uuidd 127 /usr/sbin/nologin /run/uuidd True False False +ntpsec 128 /usr/sbin/nologin /var/empty True False False +tss 129 TPM software stack /bin/false /var/lib/tpm True False False +iperf3 130 /usr/sbin/nologin /var/empty True False False +_chrony 131 Chrony daemon /usr/sbin/nologin /var/lib/chrony True False False +polkitd 998 polkit /usr/sbin/nologin /var/empty True False False +netdata 999 /bin/sh /var/lib/netdata True False False +sssd 117 SSSD system user /usr/sbin/nologin /var/lib/sss True False False +rushabh 3000 Rushabh Gosar /usr/bin/zsh /mnt/fast.storage.rushg.me/rushabh/ False False True +truenas_container_unpriv_root 2147000001 Unprivileged root user for containers /usr/sbin/nologin /var/empty True True False +``` + +## Credentials > Groups +Group list (name gid builtin smb users_count): +```text +wheel 0 True False 1 +daemon 1 True False 1 +kmem 15 True False 0 +sys 3 True False 1 +tty 5 True False 0 +operator 37 True False 1 +mail 8 True False 1 +bin 2 True False 1 +news 9 True False 1 +man 12 True False 1 +games 60 True False 1 +ftp 14 True False 0 +staff 50 True False 0 +proxy 13 True False 1 +uucp 10 True False 1 +nogroup 65534 True False 8 +nobody 65534 True False 1 +avahi 112 True False 1 +messagebus 111 True False 1 +ladvd 127 True False 1 +webdav 666 True False 1 +consul 113 True False 1 +nslcd 115 True False 1 +builtin_administrators 544 True True 3 +truenas_readonly_administrators 951 True True 0 +truenas_sharing_administrators 952 True True 0 +truenas_admin 950 False False 1 +root 0 True False 0 +adm 4 True False 1 +disk 6 True False 0 +lp 7 True False 1 +dialout 20 True False 1 +fax 21 True False 0 +voice 22 True False 0 +cdrom 24 True False 0 +floppy 25 True False 0 +tape 26 True False 0 +sudo 27 True False 0 +audio 29 True False 0 +dip 30 True False 0 +www-data 33 True False 1 +backup 34 True False 1 +list 38 True False 1 +irc 39 True False 1 +src 40 True False 0 +gnats 41 True False 1 +shadow 42 True False 0 +utmp 43 True False 0 +video 44 True False 0 +sasl 45 True False 0 +plugdev 46 True False 0 +users 100 True False 0 +systemd-timesync 101 True False 1 +systemd-journal 102 True False 0 +systemd-network 103 True False 1 +systemd-resolve 104 True False 1 +input 105 True False 0 +kvm 106 True False 1 +render 107 True False 0 +crontab 108 True False 0 +netdev 109 True False 0 +ssh 110 True False 0 +nvpd 114 True False 1 +systemd-coredump 116 True False 1 +Debian-snmp 117 True False 1 +ssl-cert 118 True False 0 +ntp 119 True False 1 +Debian-exim 120 True False 1 +tftp 121 True False 1 +tcpdump 123 True False 1 +rdma 124 True False 0 +nut 126 True False 1 +libvirt 128 True False 0 +nova 129 True False 1 +builtin_users 545 True True 1 +builtin_guests 546 True True 0 +apps 568 True False 1 +docker 999 True False 0 +libvirt-qemu 986 True False 1 +haproxy 130 True False 1 +uuidd 131 True False 1 +i2c 132 True False 0 +sgx 133 True False 0 +_ssh 134 True False 0 +ntpsec 135 True False 1 +tss 136 True False 1 +iperf3 137 True False 1 +_chrony 138 True False 1 +polkitd 998 True False 1 +netdata 997 True False 1 +sssd 122 True False 1 +incus 996 True False 0 +incus-admin 995 True False 0 +rushabh 3000 False False 1 +``` + +## Credentials > Certificates +Certificates (name common type valid_from valid_until fingerprint path): +```text +truenas_default localhost CERTIFICATE Fri Nov 28 15:44:06 2025 Wed Dec 30 15:44:06 2026 F4:AF:D9:AB:C4:07:E1:FE:2D:C9:CA:AA:0F:31:ED:2E:4F:7C:44:15 /etc/certificates/truenas_default.crt +``` + +## Dashboard > Alerts +- CRITICAL: Pool fast.storage.rushg.me state is ONLINE: One or more devices has experienced an unrecoverable error. An attempt was made to correct the error. Applications are unaffected. +- ERROR: Cloud sync task "Google Drive - /mnt/fast.storage.rushg.me/datasets/apps" failed. +- WARNING: Your system has more snapshots (22258) than recommended (10000). Performance or functionality might degrade. +- WARNING: 9 uncorrectable errors reported for sde (AA000000000000008357). +- INFO: Replication "fast.storage.rushg.me - storage.rushg.me/fast-backupv2" succeeded. +- INFO: Replication "backup.rushg.me" succeeded. + +## System Logs (paths and recent capture) +Log directory listing (`/var/log`): +```text +total 20950 +-rw-r----- 1 root adm 1708745 Dec 28 19:02 daemon.log +-rw-r----- 1 root adm 3018392 Dec 28 19:02 syslog +-rw-r----- 1 root adm 3091422 Dec 28 19:02 auth.log +-rw-rw-r-- 1 root utmp 349440 Dec 28 19:02 wtmp +-rw-r----- 1 root adm 65298601 Dec 28 19:01 zettarepl.log +drwx------ 2 root root 7 Dec 28 19:00 jobs +-rw-r----- 1 root adm 223842 Dec 28 19:00 cron.log +-rw-r----- 1 root adm 5383081 Dec 28 18:57 kern.log +-rw-r----- 1 root adm 3661876 Dec 28 18:57 messages +-rw-r----- 1 root adm 2401887 Dec 28 18:56 middlewared.log +-rw-rw-r-- 1 root utmp 876292 Dec 28 18:15 lastlog +-rw-r----- 1 root adm 2323585 Dec 28 18:09 error +-rw-r----- 1 root adm 53074 Dec 28 18:04 docker_image.log +-rw-r----- 1 root adm 5990 Dec 28 18:02 user.log +-rw-r----- 1 root adm 240704 Dec 28 18:02 debug +-rw-r--r-- 1 root root 4676539 Dec 28 18:02 fallback-middlewared.log +drwxr-x--- 2 root adm 8 Dec 28 16:52 audit +drwxr-xr-x 2 root root 19 Dec 28 16:05 sysstat +-rw-r----- 1 root adm 16758524 Dec 28 16:05 daemon.log.1 +-rw-r----- 1 root adm 13861252 Dec 28 16:05 syslog.1 +drwx------ 2 root incus-admin 7 Dec 28 16:05 incus +-rw-r--r-- 1 root root 9795446 Dec 28 15:20 fallback-middlewared.log.1 +-rw-r----- 1 root adm 892004 Dec 24 00:00 syslog.2.gz +-rw-r----- 1 root adm 310703 Dec 23 22:49 app_lifecycle.log +-rw-r----- 1 root adm 884087 Dec 21 00:00 daemon.log.2.gz +-rw-rw---- 1 root utmp 384 Dec 18 14:31 btmp +drwxr-xr-x 2 root adm 8 Dec 15 00:00 nginx +-rw-r----- 1 root adm 1389782 Dec 15 00:00 syslog.3.gz +-rw-r----- 1 root adm 11636514 Dec 13 22:44 kern.log.1 +-rw-r----- 1 root adm 11404509 Dec 13 22:41 messages.1 +-rw-r----- 1 root adm 959265 Dec 13 00:00 daemon.log.3.gz +drwxr-s--- 2 netdata netdata 6 Dec 13 00:00 netdata +-rw-r----- 1 root adm 976 Dec 1 11:22 netdata_api.log +drwxr-xr-x 2 root root 7 Dec 1 00:00 apt +-rw-r--r-- 1 root root 0 Dec 1 00:00 dpkg.log +-rw-r--r-- 1 root root 0 Dec 1 00:00 alternatives.log +-rw-r--r-- 1 root root 34 Nov 30 20:13 clamav_scan.log +drwx--x--x 3 root root 3 Nov 29 16:40 swtpm +drwxr-xr-x 3 root root 17 Nov 28 16:50 samba4 +drwxr-x--- 2 _chrony _chrony 2 Nov 28 15:44 chrony +drwxr-sr-x+ 3 root systemd-journal 3 Nov 28 15:43 journal +-rw-r--r-- 1 root root 653866 Nov 14 13:50 dpkg.log.1 +-rw-r--r-- 1 root root 19059 Nov 14 13:48 alternatives.log.1 +drwxr-xr-x 2 root root 4 Nov 14 13:47 proftpd +drwxr-s--- 2 Debian-exim adm 2 Nov 14 13:47 exim4 +-rw-r--r-- 1 root root 605 Nov 14 13:46 fontconfig.log +drwxr-xr-x 3 root root 3 Nov 14 13:45 libvirt +drwxr-xr-x 5 root root 5 Nov 14 13:45 runit +-rw-r--r-- 1 root root 91460 Nov 14 13:44 bootstrap.log +lrwxrwxrwx 1 root root 39 Nov 14 13:43 README -> ../../usr/share/doc/systemd/README.logs +drwx------ 2 root root 2 Nov 14 13:43 private +-rw-r--r-- 1 root root 0 Nov 14 13:43 faillog +-rw-rw---- 1 root utmp 0 Nov 14 13:43 btmp.1 +drwxr-x--- 2 root root 2 Nov 14 13:19 sssd +drwxr-xr-x 2 root root 2 Nov 14 13:08 ctdb +drwxr-xr-x 2 root root 2 Nov 14 13:08 samba +-rw-r--r-- 1 daemon daemon 324 May 30 2025 wsdd.log +drwxr-xr-x 2 root root 2 Feb 24 2024 freeipmi +drwxr-xr-x 2 root root 2 Feb 24 2024 ipmiconsole +drwxr-xr-x 2 root root 2 Sep 26 2022 ipmctl +``` +Recent middlewared log excerpt (sanitized, last 30 lines captured): +```text +[2025/12/28 18:01:45] (INFO) SystemDatasetService.__post_mount_actions():575 - Successfully ran post mount action 'reporting.post_dataset_mount_action' endpoint for 'boot-pool/.system/netdata-ae32c386e13840b2bf9c0083275e7941' dataset +[2025/12/28 18:02:02] (DEBUG) PoolService.import_on_boot():486 - Finished calling pool.post_import +[2025/12/28 18:02:13] (DEBUG) middlewared._setup_periodic_tasks():428 - Setting up periodic task alert.flush_alerts to run every 3600 seconds +[2025/12/28 18:02:13] (DEBUG) middlewared._setup_periodic_tasks():428 - Setting up periodic task alert.process_alerts to run every 60 seconds +[2025/12/28 18:02:13] (DEBUG) middlewared._setup_periodic_tasks():428 - Setting up periodic task auditbackend._AuditBackendService__lifecycle_cleanup to run every 86400 seconds +[2025/12/28 18:02:13] (DEBUG) middlewared._setup_periodic_tasks():428 - Setting up periodic task certificate.renew_certs to run every 86400 seconds +[2025/12/28 18:02:13] (DEBUG) middlewared._setup_periodic_tasks():428 - Setting up periodic task docker.state.periodic_check to run every 86400 seconds +[2025/12/28 18:02:13] (DEBUG) middlewared._setup_periodic_tasks():428 - Setting up periodic task mail.send_mail_queue to run every 600 seconds +[2025/12/28 18:02:13] (DEBUG) middlewared._setup_periodic_tasks():428 - Setting up periodic task rate.limit.cache_clear to run every 600 seconds +[2025/12/28 18:02:13] (DEBUG) middlewared._setup_periodic_tasks():428 - Setting up periodic task service.check_deprecated_services to run every 3600 seconds +[2025/12/28 18:02:13] (DEBUG) middlewared._setup_periodic_tasks():428 - Setting up periodic task smb.sharesec.check_share_info_tdb to run every 3600 seconds +[2025/12/28 18:02:13] (DEBUG) middlewared._setup_periodic_tasks():428 - Setting up periodic task truecommand.health_check to run every 1800 seconds +[2025/12/28 18:02:13] (DEBUG) middlewared._setup_periodic_tasks():428 - Setting up periodic task vmware.delete_pending_snapshots to run every 10800.0 seconds +[2025/12/28 18:02:19] (DEBUG) InitShutdownScriptService.execute_init_tasks():176 - Timed out running COMMAND: 'sleep 30 && cd /mnt/fast.storage.rushg.me/rushabh/rushabh/rushg.me && nohup python3 -m http.server 8081 > /dev/null 2>&1 &' +[2025/12/28 18:02:22] (DEBUG) VirtGlobalService.setup_storage_pool():369 - Virt storage pool for fast.storage.rushg.me/.ix-virt already configured. +[2025/12/28 18:02:23] (ERROR) middlewared.wait_for_libvirtd():32 - Failed to setup libvirt @cee:{"TNLOG": {"exception": "Traceback (most recent call last):\n File \"/usr/lib/python3.11/asyncio/tasks.py\", line 500, in wait_for\n return fut.result()\n ^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/plugins/vm/lifecycle.py\", line 19, in libvirtd_started\n await middleware.call('service.start', 'libvirtd', {'ha_propagate': False})\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 1043, in call\n return await self._call(\n ^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 771, in _call\n return await methodobj(*prepared_call.args)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/api/base/decorator.py\", line 108, in wrapped\n result = await func(*args)\n ^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/plugins/service.py\", line 201, in start\n await self.middleware.call('service.notify_running', service)\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 1043, in call\n return await self._call(\n ^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 771, in _call\n return await methodobj(*prepared_call.args)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/plugins/service.py\", line 439, in notify_running\n svc = await self.middleware.call('service.query', [('service', '=', service)], {'get': True})\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 1043, in call\n return await self._call(\n ^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 771, in _call\n return await methodobj(*prepared_call.args)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/api/base/decorator.py\", line 108, in wrapped\n result = await func(*args)\n ^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/plugins/service.py\", line 112, in query\n return await self.middleware.call('datastore.query', 'services.services', filters, options | default_options)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 1043, in call\n return await self._call(\n ^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 771, in _call\n return await methodobj(*prepared_call.args)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/plugins/datastore/read.py\", line 149, in query\n result = await self.middleware.call(\"datastore.fetchall\", qs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 1043, in call\n return await self._call(\n ^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 782, in _call\n return await self.run_in_executor(prepared_call.executor, methodobj, *prepared_call.args)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 665, in run_in_executor\n return await loop.run_in_executor(pool, functools.partial(method, *args, **kwargs))\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nasyncio.exceptions.CancelledError\n\nThe above exception was the direct cause of the following exception:\n\nTraceback (most recent call last):\n File \"/usr/lib/python3/dist-packages/middlewared/plugins/vm/lifecycle.py\", line 26, in wait_for_libvirtd\n await asyncio.wait_for(self.middleware.create_task(libvirtd_started(self.middleware)), timeout=timeout)\n File \"/usr/lib/python3.11/asyncio/tasks.py\", line 502, in wait_for\n raise exceptions.TimeoutError() from exc\nTimeoutError", "type": "PYTHON_EXCEPTION", "time": "2025-12-29 02:02:23.614110"}} +[2025/12/28 18:04:24] (ERROR) middlewared.send():55 - Failed to JSON serialize server message: Object of type ValidationErrors is not JSON serializable @cee:{"TNLOG": {"exception": "Traceback (most recent call last):\n File \"/usr/lib/python3/dist-packages/middlewared/api/base/server/ws_handler/rpc.py\", line 53, in send\n data_ = json.dumps(data)\n ^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/truenas_api_client/ejson.py\", line 113, in dumps\n return json.dumps(obj, cls=JSONEncoder, **kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3.11/json/__init__.py\", line 238, in dumps\n **kw).encode(obj)\n ^^^^^^^^^^^\n File \"/usr/lib/python3.11/json/encoder.py\", line 200, in encode\n chunks = self.iterencode(o, _one_shot=True)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3.11/json/encoder.py\", line 258, in iterencode\n return _iterencode(o, 0)\n ^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/truenas_api_client/ejson.py\", line 61, in default\n return super(JSONEncoder, self).default(obj)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3.11/json/encoder.py\", line 180, in default\n raise TypeError(f'Object of type {o.__class__.__name__} '\nTypeError: Object of type ValidationErrors is not JSON serializable", "type": "PYTHON_EXCEPTION", "time": "2025-12-29 02:04:24.007228"}} +[2025/12/28 18:04:24] (ERROR) middlewared.send():55 - Failed to JSON serialize server message: Object of type ValidationErrors is not JSON serializable @cee:{"TNLOG": {"exception": "Traceback (most recent call last):\n File \"/usr/lib/python3/dist-packages/middlewared/api/base/server/ws_handler/rpc.py\", line 53, in send\n data_ = json.dumps(data)\n ^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/truenas_api_client/ejson.py\", line 113, in dumps\n return json.dumps(obj, cls=JSONEncoder, **kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3.11/json/__init__.py\", line 238, in dumps\n **kw).encode(obj)\n ^^^^^^^^^^^\n File \"/usr/lib/python3.11/json/encoder.py\", line 200, in encode\n chunks = self.iterencode(o, _one_shot=True)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3.11/json/encoder.py\", line 258, in iterencode\n return _iterencode(o, 0)\n ^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/truenas_api_client/ejson.py\", line 61, in default\n return super(JSONEncoder, self).default(obj)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3.11/json/encoder.py\", line 180, in default\n raise TypeError(f'Object of type {o.__class__.__name__} '\nTypeError: Object of type ValidationErrors is not JSON serializable", "type": "PYTHON_EXCEPTION", "time": "2025-12-29 02:04:24.567323"}} +[2025/12/28 18:04:29] (ERROR) middlewared.job.run():540 - Job > failed: CallError('You must provide an outgoing mailserver and mail server port when sending mail') +[2025/12/28 18:04:45] (ERROR) middlewared.send():55 - Failed to JSON serialize server message: Object of type ValidationErrors is not JSON serializable @cee:{"TNLOG": {"exception": "Traceback (most recent call last):\n File \"/usr/lib/python3/dist-packages/middlewared/api/base/server/ws_handler/rpc.py\", line 53, in send\n data_ = json.dumps(data)\n ^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/truenas_api_client/ejson.py\", line 113, in dumps\n return json.dumps(obj, cls=JSONEncoder, **kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3.11/json/__init__.py\", line 238, in dumps\n **kw).encode(obj)\n ^^^^^^^^^^^\n File \"/usr/lib/python3.11/json/encoder.py\", line 200, in encode\n chunks = self.iterencode(o, _one_shot=True)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3.11/json/encoder.py\", line 258, in iterencode\n return _iterencode(o, 0)\n ^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/truenas_api_client/ejson.py\", line 61, in default\n return super(JSONEncoder, self).default(obj)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3.11/json/encoder.py\", line 180, in default\n raise TypeError(f'Object of type {o.__class__.__name__} '\nTypeError: Object of type ValidationErrors is not JSON serializable", "type": "PYTHON_EXCEPTION", "time": "2025-12-29 02:04:45.505785"}} +[2025/12/28 18:04:46] (ERROR) middlewared.send():55 - Failed to JSON serialize server message: Object of type ValidationErrors is not JSON serializable @cee:{"TNLOG": {"exception": "Traceback (most recent call last):\n File \"/usr/lib/python3/dist-packages/middlewared/api/base/server/ws_handler/rpc.py\", line 53, in send\n data_ = json.dumps(data)\n ^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/truenas_api_client/ejson.py\", line 113, in dumps\n return json.dumps(obj, cls=JSONEncoder, **kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3.11/json/__init__.py\", line 238, in dumps\n **kw).encode(obj)\n ^^^^^^^^^^^\n File \"/usr/lib/python3.11/json/encoder.py\", line 200, in encode\n chunks = self.iterencode(o, _one_shot=True)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3.11/json/encoder.py\", line 258, in iterencode\n return _iterencode(o, 0)\n ^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/truenas_api_client/ejson.py\", line 61, in default\n return super(JSONEncoder, self).default(obj)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3.11/json/encoder.py\", line 180, in default\n raise TypeError(f'Object of type {o.__class__.__name__} '\nTypeError: Object of type ValidationErrors is not JSON serializable", "type": "PYTHON_EXCEPTION", "time": "2025-12-29 02:04:46.536879"}} +[2025/12/28 18:02:02] (INFO) worker.ddt_prefetch_pools():244 - Prefetching ddt table of 'storage.rushg.me' pool +[2025/12/28 18:02:02] (INFO) worker.ddt_prefetch_pools():244 - Prefetching ddt table of 'fast.storage.rushg.me' pool +[2025/12/28 18:04:47] (INFO) ZFSSnapshotService.create():195 - Snapshot taken: fast.storage.rushg.me/ix-apps/app_mounts/vaultwarden@1.3.26 +[2025/12/28 18:04:53] (DEBUG) middlewared.plugins.zettarepl._process_command_queue():254 - Running task +[2025/12/28 18:04:56] (DEBUG) middlewared.plugins.zettarepl._process_command_queue():254 - Running task +[2025/12/28 18:09:32] (ERROR) middlewared.job.run():540 - Job > failed: CallError("Checks: 11043 / 11043, 100%, Listed 32442\nTransferred: 37 / 37, 100%\nElapsed time: 4m40.3s\n\n2025/12/28 18:09:32 NOTICE: Failed to sync with 157 errors: last error was: googleapi: Error 403: The user's Drive storage quota has been exceeded., storageQuotaExceeded\n") +[2025/12/28 18:16:26] (ERROR) middlewared.process():90 - EventSource 'app.stats' run() failed @cee:{"TNLOG": {"exception": "Traceback (most recent call last):\n File \"/usr/lib/python3/dist-packages/docker/api/client.py\", line 275, in _raise_for_status\n response.raise_for_status()\n File \"/usr/lib/python3/dist-packages/requests/models.py\", line 1021, in raise_for_status\n raise HTTPError(http_error_msg, response=self)\nrequests.exceptions.HTTPError: 404 Client Error: Not Found for url: http+docker://localhost/v1.51/containers/1d7e14c452d7f9a259270881bf34913934363a20a95d377aae568b237d53f695/json\n\nThe above exception was the direct cause of the following exception:\n\nTraceback (most recent call last):\n File \"/usr/lib/python3/dist-packages/middlewared/event.py\", line 87, in process\n await self.run()\n File \"/usr/lib/python3/dist-packages/middlewared/event.py\", line 99, in run\n await self.middleware.run_in_thread(self.run_sync)\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 668, in run_in_thread\n return await self.run_in_executor(io_thread_pool_executor, method, *args, **kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 665, in run_in_executor\n return await loop.run_in_executor(pool, functools.partial(method, *args, **kwargs))\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3.11/concurrent/futures/thread.py\", line 58, in run\n result = self.fn(*self.args, **self.kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/plugins/apps/stats.py\", line 31, in run_sync\n project_stats = list_resources_stats_by_project()\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/plugins/apps/ix_apps/docker/stats.py\", line 25, in list_resources_stats_by_project\n return list_resources_stats_by_project_internal(project_name)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/plugins/apps/ix_apps/docker/stats.py\", line 36, in list_resources_stats_by_project_internal\n for container in client.containers.list(all=True, filters=label_filter, sparse=False):\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/docker/models/containers.py\", line 1018, in list\n containers.append(self.get(r['Id']))\n ^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/docker/models/containers.py\", line 954, in get\n resp = self.client.api.inspect_container(container_id)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/docker/utils/decorators.py\", line 19, in wrapped\n return f(self, resource_id, *args, **kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/docker/api/container.py\", line 793, in inspect_container\n return self._result(\n ^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/docker/api/client.py\", line 281, in _result\n self._raise_for_status(response)\n File \"/usr/lib/python3/dist-packages/docker/api/client.py\", line 277, in _raise_for_status\n raise create_api_error_from_http_exception(e) from e\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/docker/errors.py\", line 39, in create_api_error_from_http_exception\n raise cls(e, response=response, explanation=explanation) from e\ndocker.errors.NotFound: 404 Client Error for http+docker://localhost/v1.51/containers/1d7e14c452d7f9a259270881bf34913934363a20a95d377aae568b237d53f695/json: Not Found (\"No such container: 1d7e14c452d7f9a259270881bf34913934363a20a95d377aae568b237d53f695\")", "type": "PYTHON_EXCEPTION", "time": "2025-12-29 02:16:26.939182"}} +[2025/12/28 18:56:50] (WARNING) middlewared.process_method_call():394 - Exception while calling zfs.snapshot.query(*['[[],{" limit\\: 200}]']) @cee:{"TNLOG": {"exception": "concurrent.futures.process._RemoteTraceback: \n\"\"\"\nTraceback (most recent call last):\n File \"/usr/lib/python3.11/concurrent/futures/process.py\", line 261, in _process_worker\n r = call_item.fn(*call_item.args, **call_item.kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/worker.py\", line 115, in main_worker\n res = MIDDLEWARE._run(*call_args)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/worker.py\", line 48, in _run\n return self._call(name, serviceobj, methodobj, args, job=job)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/worker.py\", line 42, in _call\n return methodobj(*params)\n ^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/plugins/zfs_/snapshot.py\", line 62, in query\n filters_attrs = filter_getattrs(filters)\n ^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/utils/filter_list.py\", line 576, in filter_getattrs\n f = filters.copy()\n ^^^^^^^^^^^^\nAttributeError: 'str' object has no attribute 'copy'\n\"\"\"\n\nThe above exception was the direct cause of the following exception:\n\nTraceback (most recent call last):\n File \"/usr/lib/python3/dist-packages/middlewared/api/base/server/ws_handler/rpc.py\", line 360, in process_method_call\n result = await method.call(app, id_, params)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/api/base/server/method.py\", line 57, in call\n result = await self.middleware.call_with_audit(self.name, self.serviceobj, methodobj, params, app,\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 954, in call_with_audit\n result = await self._call(method, serviceobj, methodobj, params, app=app,\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 779, in _call\n return await self._call_worker(name, *prepared_call.args)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 785, in _call_worker\n return await self.run_in_proc(main_worker, name, args, job)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 681, in run_in_proc\n return await self.run_in_executor(self.__procpool, method, *args, **kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 665, in run_in_executor\n return await loop.run_in_executor(pool, functools.partial(method, *args, **kwargs))\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAttributeError: 'str' object has no attribute 'copy'", "type": "PYTHON_EXCEPTION", "time": "2025-12-29 02:56:50.473153"}} +[2025/12/28 18:56:56] (WARNING) middlewared.process_method_call():394 - Exception while calling zfs.snapshot.query(*[[], '{" limit\\: 200}']) @cee:{"TNLOG": {"exception": "concurrent.futures.process._RemoteTraceback: \n\"\"\"\nTraceback (most recent call last):\n File \"/usr/lib/python3.11/concurrent/futures/process.py\", line 261, in _process_worker\n r = call_item.fn(*call_item.args, **call_item.kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/worker.py\", line 115, in main_worker\n res = MIDDLEWARE._run(*call_args)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/worker.py\", line 48, in _run\n return self._call(name, serviceobj, methodobj, args, job=job)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/worker.py\", line 42, in _call\n return methodobj(*params)\n ^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/plugins/zfs_/snapshot.py\", line 63, in query\n extra = copy.deepcopy(options.get('extra', {}))\n ^^^^^^^^^^^\nAttributeError: 'str' object has no attribute 'get'\n\"\"\"\n\nThe above exception was the direct cause of the following exception:\n\nTraceback (most recent call last):\n File \"/usr/lib/python3/dist-packages/middlewared/api/base/server/ws_handler/rpc.py\", line 360, in process_method_call\n result = await method.call(app, id_, params)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/api/base/server/method.py\", line 57, in call\n result = await self.middleware.call_with_audit(self.name, self.serviceobj, methodobj, params, app,\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 954, in call_with_audit\n result = await self._call(method, serviceobj, methodobj, params, app=app,\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 779, in _call\n return await self._call_worker(name, *prepared_call.args)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 785, in _call_worker\n return await self.run_in_proc(main_worker, name, args, job)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 681, in run_in_proc\n return await self.run_in_executor(self.__procpool, method, *args, **kwargs)\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n File \"/usr/lib/python3/dist-packages/middlewared/main.py\", line 665, in run_in_executor\n return await loop.run_in_executor(pool, functools.partial(method, *args, **kwargs))\n ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nAttributeError: 'str' object has no attribute 'get'", "type": "PYTHON_EXCEPTION", "time": "2025-12-29 02:56:56.525579"}} +``` +Recent journalctl excerpt (sanitized, last 30 lines captured): +```text +Dec 28 19:02:13 truenas ed[1694]: pam_unix(middleware:session): session closed for user rushabh +Dec 28 19:02:15 truenas systemd-logind[12674]: New session 97 of user rushabh. +Dec 28 19:02:15 truenas systemd[1]: Started session-97.scope - Session 97 of User rushabh. +Dec 28 19:02:15 truenas sshd[300978]: pam_unix(sshd:session): session opened for user rushabh(uid=3000) by (uid=0) +Dec 28 19:02:15 truenas sshd[300978]: pam_env(sshd:session): deprecated reading of user environment enabled +Dec 28 19:02:15 truenas sshd[301032]: Received disconnect from 192.168.1.195 port 50839:11: disconnected by user +Dec 28 19:02:15 truenas sshd[301032]: Disconnected from user rushabh 192.168.1.195 port 50839 +Dec 28 19:02:15 truenas sshd[300978]: pam_unix(sshd:session): session closed for user rushabh +Dec 28 19:02:15 truenas systemd[1]: session-97.scope: Deactivated successfully. +Dec 28 19:02:15 truenas systemd-logind[12674]: Session 97 logged out. Waiting for processes to exit. +Dec 28 19:02:15 truenas systemd-logind[12674]: Removed session 97. +Dec 28 19:02:19 truenas systemd-logind[12674]: New session 98 of user rushabh. +Dec 28 19:02:19 truenas systemd[1]: Started session-98.scope - Session 98 of User rushabh. +Dec 28 19:02:19 truenas sshd[301466]: pam_unix(sshd:session): session opened for user rushabh(uid=3000) by (uid=0) +Dec 28 19:02:19 truenas sshd[301466]: pam_env(sshd:session): deprecated reading of user environment enabled +Dec 28 19:02:19 truenas sudo[301508]: @cee:{"sudo":{"accept":{"uuid":"0eb5ef49d5-4514-49b5-ffc2-f8a82bbcd7","server_time":{"seconds":1766977339,"nanoseconds":664496708,"iso8601":"20251229030219Z","localtime":"Dec 28 19:02:19"},"submit_time":{"seconds":1766977339,"nanoseconds":661864561,"iso8601":"20251229030219Z","localtime":"Dec 28 19:02:19"},"submituser":"rushabh","command":"/bin/tail","runuser":"root","runcwd":"/mnt/fast.storage.rushg.me/rushabh","submithost":"truenas.","submitcwd":"/mnt/fast.storage.rushg.me/rushabh","runuid":0,"columns":80,"lines":24,"runargv":["tail","-n","200","/var/log/middlewared.log"],"runenv":["PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin","LC_ALL=C.UTF-8","MAIL=/var/mail/root","LOGNAME=root","USER=root","HOME=/root","SHELL=/usr/bin/zsh","TERM=unknown","SUDO_COMMAND=/bin/tail -n 200 /var/log/middlewared.log","SUDO_USER=rushabh","SUDO_UID=3000","SUDO_GID=3000"]}}} +Dec 28 19:02:19 truenas sudo[301508]: pam_unix(sudo:session): session opened for user root(uid=0) by (uid=3000) +Dec 28 19:02:19 truenas sudo[301508]: pam_unix(sudo:session): session closed for user root +Dec 28 19:02:19 truenas sshd[301473]: Received disconnect from 192.168.1.195 port 50841:11: disconnected by user +Dec 28 19:02:19 truenas sshd[301473]: Disconnected from user rushabh 192.168.1.195 port 50841 +Dec 28 19:02:19 truenas sshd[301466]: pam_unix(sshd:session): session closed for user rushabh +Dec 28 19:02:19 truenas systemd[1]: session-98.scope: Deactivated successfully. +Dec 28 19:02:19 truenas systemd-logind[12674]: Session 98 logged out. Waiting for processes to exit. +Dec 28 19:02:19 truenas systemd-logind[12674]: Removed session 98. +Dec 28 19:02:23 truenas systemd-logind[12674]: New session 99 of user rushabh. +Dec 28 19:02:23 truenas systemd[1]: Started session-99.scope - Session 99 of User rushabh. +Dec 28 19:02:23 truenas sshd[301761]: pam_unix(sshd:session): session opened for user rushabh(uid=3000) by (uid=0) +Dec 28 19:02:23 truenas sshd[301761]: pam_env(sshd:session): deprecated reading of user environment enabled +Dec 28 19:02:23 truenas sudo[301792]: @cee:{"sudo":{"accept":{"uuid":"9dde8d7556-fd1e-4daf-dc2e-af43d999f2","server_time":{"seconds":1766977343,"nanoseconds":585866512,"iso8601":"20251229030223Z","localtime":"Dec 28 19:02:23"},"submit_time":{"seconds":1766977343,"nanoseconds":583411303,"iso8601":"20251229030223Z","localtime":"Dec 28 19:02:23"},"submituser":"rushabh","command":"/bin/journalctl","runuser":"root","runcwd":"/mnt/fast.storage.rushg.me/rushabh","submithost":"truenas.","submitcwd":"/mnt/fast.storage.rushg.me/rushabh","runuid":0,"columns":80,"lines":24,"runargv":["journalctl","-n","200","--no-pager"],"runenv":["PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin","LC_ALL=C.UTF-8","MAIL=/var/mail/root","LOGNAME=root","USER=root","HOME=/root","SHELL=/usr/bin/zsh","TERM=unknown","SUDO_COMMAND=/bin/journalctl -n 200 --no-pager","SUDO_USER=rushabh","SUDO_UID=3000","SUDO_GID=3000"]}}} +Dec 28 19:02:23 truenas sudo[301792]: pam_unix(sudo:session): session opened for user root(uid=0) by (uid=3000) +``` +Recent dmesg excerpt (sanitized, last 30 lines captured): +```text +[Sun Dec 28 18:57:42 2025] veth56c8970 (unregistering): left promiscuous mode +[Sun Dec 28 18:57:42 2025] br-5c6b1f2ae679: port 1(veth56c8970) entered disabled state +[Sun Dec 28 18:57:46 2025] br-e8a416d5ff38: port 1(veth3c7aeab) entered blocking state +[Sun Dec 28 18:57:46 2025] br-e8a416d5ff38: port 1(veth3c7aeab) entered disabled state +[Sun Dec 28 18:57:46 2025] veth3c7aeab: entered allmulticast mode +[Sun Dec 28 18:57:46 2025] veth3c7aeab: entered promiscuous mode +[Sun Dec 28 18:57:46 2025] br-e8a416d5ff38: port 2(vethefca9f8) entered blocking state +[Sun Dec 28 18:57:46 2025] br-e8a416d5ff38: port 2(vethefca9f8) entered disabled state +[Sun Dec 28 18:57:46 2025] vethefca9f8: entered allmulticast mode +[Sun Dec 28 18:57:46 2025] vethefca9f8: entered promiscuous mode +[Sun Dec 28 18:57:46 2025] eth0: renamed from veth2c5772b +[Sun Dec 28 18:57:46 2025] br-e8a416d5ff38: port 1(veth3c7aeab) entered blocking state +[Sun Dec 28 18:57:46 2025] br-e8a416d5ff38: port 1(veth3c7aeab) entered forwarding state +[Sun Dec 28 18:57:46 2025] eth0: renamed from veth114d0d4 +[Sun Dec 28 18:57:46 2025] br-e8a416d5ff38: port 2(vethefca9f8) entered blocking state +[Sun Dec 28 18:57:46 2025] br-e8a416d5ff38: port 2(vethefca9f8) entered forwarding state +[Sun Dec 28 18:57:48 2025] br-e8a416d5ff38: port 3(vethdae6c52) entered blocking state +[Sun Dec 28 18:57:48 2025] br-e8a416d5ff38: port 3(vethdae6c52) entered disabled state +[Sun Dec 28 18:57:48 2025] vethdae6c52: entered allmulticast mode +[Sun Dec 28 18:57:48 2025] vethdae6c52: entered promiscuous mode +[Sun Dec 28 18:57:48 2025] eth0: renamed from vethd5ced47 +[Sun Dec 28 18:57:48 2025] br-e8a416d5ff38: port 3(vethdae6c52) entered blocking state +[Sun Dec 28 18:57:48 2025] br-e8a416d5ff38: port 3(vethdae6c52) entered forwarding state +[Sun Dec 28 18:57:52 2025] br-e8a416d5ff38: port 4(veth7e8d198) entered blocking state +[Sun Dec 28 18:57:52 2025] br-e8a416d5ff38: port 4(veth7e8d198) entered disabled state +[Sun Dec 28 18:57:52 2025] veth7e8d198: entered allmulticast mode +[Sun Dec 28 18:57:52 2025] veth7e8d198: entered promiscuous mode +[Sun Dec 28 18:57:52 2025] eth0: renamed from vethe996706 +[Sun Dec 28 18:57:52 2025] br-e8a416d5ff38: port 4(veth7e8d198) entered blocking state +[Sun Dec 28 18:57:52 2025] br-e8a416d5ff38: port 4(veth7e8d198) entered forwarding state +``` + +## Hardware Inventory +- System: {'Manufacturer': 'Supermicro', 'Product Name': 'Super Server', 'Version': '0123456789', 'Serial Number': '0123456789', 'UUID': '87856000-8b34-11ef-8000-7cc255e86fa0'} +- Baseboard: {'Manufacturer': 'Supermicro', 'Product Name': 'H12SSL-I', 'Version': '1.10', 'Serial Number': 'WM24AS601045'} +- BIOS: {'Vendor': 'American Megatrends Inc.', 'Version': '3.0', 'Release Date': '07/22/2024', 'BIOS Revision': '5.14'} +- Chassis: {'Manufacturer': 'Supermicro', 'Type': 'Main Server Chassis', 'Version': '0123456789', 'Serial Number': '0123456789'} +- CPU: AMD EPYC 7532 32-Core Processor, sockets=1, cores_per_socket=32, threads_per_core=2, total_cpus=64 +Memory summary (`free -h`): +```text +total used free shared buff/cache available +Mem: 251Gi 120Gi 120Gi 505Mi 12Gi 130Gi +Swap: 0B 0B 0B +``` +Memory modules: +- DIMMA1 32 GB DDR4 2667 MT/s SK Hynix HMA84GR7AFR4N-VK 80AD01181111DE78BD +- DIMMB1 32 GB DDR4 2667 MT/s SK Hynix HMA84GR7AFR4N-VK 80AD01190452DD6FD2 +- DIMMC1 32 GB DDR4 2667 MT/s SK Hynix HMA84GR7AFR4N-VK 80AD01190452DD7059 +- DIMMD1 32 GB DDR4 2667 MT/s SK Hynix HMA84GR7AFR4N-VK 80AD01190452DD6F97 +- DIMME1 32 GB DDR4 2667 MT/s SK Hynix HMA84GR7AFR4N-VK 80AD01190452DD704C +- DIMMF1 32 GB DDR4 2667 MT/s SK Hynix HMA84GR7AFR4N-VK 80AD01182311F993ED +- DIMMG1 32 GB DDR4 2667 MT/s SK Hynix HMA84GR7AFR4N-VK 80AD011905124B25C8 +- DIMMH1 32 GB DDR4 2667 MT/s SK Hynix HMA84GR7AFR4N-VK 80AD01182211F72AD7 +PCI devices (`lspci -nn`): +```text +00:00.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Root Complex [1022:1480] +00:00.2 IOMMU [0806]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse IOMMU [1022:1481] +00:01.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +00:01.1 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge [1022:1483] +00:02.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +00:03.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +00:03.3 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge [1022:1483] +00:03.4 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge [1022:1483] +00:04.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +00:05.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +00:07.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +00:07.1 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Internal PCIe GPP Bridge 0 to bus[E:B] [1022:1484] +00:08.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +00:08.1 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Internal PCIe GPP Bridge 0 to bus[E:B] [1022:1484] +00:14.0 SMBus [0c05]: Advanced Micro Devices, Inc. [AMD] FCH SMBus Controller [1022:790b] (rev 61) +00:14.3 ISA bridge [0601]: Advanced Micro Devices, Inc. [AMD] FCH LPC Bridge [1022:790e] (rev 51) +00:18.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship Device 24; Function 0 [1022:1490] +00:18.1 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship Device 24; Function 1 [1022:1491] +00:18.2 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship Device 24; Function 2 [1022:1492] +00:18.3 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship Device 24; Function 3 [1022:1493] +00:18.4 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship Device 24; Function 4 [1022:1494] +00:18.5 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship Device 24; Function 5 [1022:1495] +00:18.6 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship Device 24; Function 6 [1022:1496] +00:18.7 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship Device 24; Function 7 [1022:1497] +01:00.0 VGA compatible controller [0300]: NVIDIA Corporation Device [10de:2d04] (rev a1) +01:00.1 Audio device [0403]: NVIDIA Corporation Device [10de:22eb] (rev a1) +02:00.0 Non-Volatile memory controller [0108]: Phison Electronics Corporation E18 PCIe4 NVMe Controller [1987:5018] (rev 01) +03:00.0 Non-Volatile memory controller [0108]: Seagate Technology PLC FireCuda 530 SSD [1bb1:5018] (rev 01) +04:00.0 Non-Essential Instrumentation [1300]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Function [1022:148a] +04:00.2 Encryption controller [1080]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PTDMA [1022:1498] +05:00.0 Non-Essential Instrumentation [1300]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Reserved SPP [1022:1485] +05:00.2 Encryption controller [1080]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PTDMA [1022:1498] +05:00.3 USB controller [0c03]: Advanced Micro Devices, Inc. [AMD] Starship USB 3.0 Host Controller [1022:148c] +40:00.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Root Complex [1022:1480] +40:00.2 IOMMU [0806]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse IOMMU [1022:1481] +40:01.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +40:02.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +40:03.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +40:03.1 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge [1022:1483] +40:03.3 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge [1022:1483] +40:03.4 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge [1022:1483] +40:03.5 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge [1022:1483] +40:03.6 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge [1022:1483] +40:04.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +40:05.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +40:07.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +40:07.1 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Internal PCIe GPP Bridge 0 to bus[E:B] [1022:1484] +40:08.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +40:08.1 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Internal PCIe GPP Bridge 0 to bus[E:B] [1022:1484] +40:08.2 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Internal PCIe GPP Bridge 0 to bus[E:B] [1022:1484] +40:08.3 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Internal PCIe GPP Bridge 0 to bus[E:B] [1022:1484] +41:00.0 Ethernet controller [0200]: Mellanox Technologies MT27500 Family [ConnectX-3] [15b3:1003] +42:00.0 USB controller [0c03]: ASMedia Technology Inc. ASM1042A USB 3.0 Host Controller [1b21:1142] +43:00.0 PCI bridge [0604]: ASPEED Technology, Inc. AST1150 PCI-to-PCI Bridge [1a03:1150] (rev 04) +44:00.0 VGA compatible controller [0300]: ASPEED Technology, Inc. ASPEED Graphics Family [1a03:2000] (rev 41) +45:00.0 USB controller [0c03]: ASMedia Technology Inc. ASM1042A USB 3.0 Host Controller [1b21:1142] +46:00.0 Ethernet controller [0200]: Broadcom Inc. and subsidiaries NetXtreme BCM5720 Gigabit Ethernet PCIe [14e4:165f] +46:00.1 Ethernet controller [0200]: Broadcom Inc. and subsidiaries NetXtreme BCM5720 Gigabit Ethernet PCIe [14e4:165f] +47:00.0 Non-Essential Instrumentation [1300]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Function [1022:148a] +47:00.2 Encryption controller [1080]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PTDMA [1022:1498] +48:00.0 Non-Essential Instrumentation [1300]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Reserved SPP [1022:1485] +48:00.1 Encryption controller [1080]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Cryptographic Coprocessor PSPCPP [1022:1486] +48:00.2 Encryption controller [1080]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PTDMA [1022:1498] +48:00.3 USB controller [0c03]: Advanced Micro Devices, Inc. [AMD] Starship USB 3.0 Host Controller [1022:148c] +49:00.0 SATA controller [0106]: Advanced Micro Devices, Inc. [AMD] FCH SATA Controller [AHCI mode] [1022:7901] (rev 51) +4a:00.0 SATA controller [0106]: Advanced Micro Devices, Inc. [AMD] FCH SATA Controller [AHCI mode] [1022:7901] (rev 51) +80:00.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Root Complex [1022:1480] +80:00.2 IOMMU [0806]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse IOMMU [1022:1481] +80:01.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +80:01.1 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge [1022:1483] +80:01.2 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge [1022:1483] +80:01.3 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge [1022:1483] +80:01.4 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge [1022:1483] +80:02.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +80:03.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +80:03.3 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge [1022:1483] +80:03.4 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge [1022:1483] +80:04.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +80:05.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +80:07.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +80:07.1 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Internal PCIe GPP Bridge 0 to bus[E:B] [1022:1484] +80:08.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +80:08.1 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Internal PCIe GPP Bridge 0 to bus[E:B] [1022:1484] +80:08.2 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Internal PCIe GPP Bridge 0 to bus[E:B] [1022:1484] +80:08.3 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Internal PCIe GPP Bridge 0 to bus[E:B] [1022:1484] +81:00.0 Non-Volatile memory controller [0108]: Phison Electronics Corporation PS5021-E21 PCIe4 NVMe Controller (DRAM-less) [1987:5021] (rev 01) +82:00.0 Non-Volatile memory controller [0108]: Phison Electronics Corporation PS5021-E21 PCIe4 NVMe Controller (DRAM-less) [1987:5021] (rev 01) +83:00.0 Non-Volatile memory controller [0108]: Phison Electronics Corporation E18 PCIe4 NVMe Controller [1987:5018] (rev 01) +84:00.0 Non-Volatile memory controller [0108]: Phison Electronics Corporation E18 PCIe4 NVMe Controller [1987:5018] (rev 01) +85:00.0 Non-Volatile memory controller [0108]: MAXIO Technology (Hangzhou) Ltd. NVMe SSD Controller MAP1602 (DRAM-less) [1e4b:1602] (rev 01) +86:00.0 Non-Volatile memory controller [0108]: MAXIO Technology (Hangzhou) Ltd. NVMe SSD Controller MAP1602 (DRAM-less) [1e4b:1602] (rev 01) +87:00.0 Non-Essential Instrumentation [1300]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Function [1022:148a] +87:00.2 Encryption controller [1080]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PTDMA [1022:1498] +88:00.0 Non-Essential Instrumentation [1300]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Reserved SPP [1022:1485] +88:00.2 Encryption controller [1080]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PTDMA [1022:1498] +89:00.0 SATA controller [0106]: Advanced Micro Devices, Inc. [AMD] FCH SATA Controller [AHCI mode] [1022:7901] (rev 51) +8a:00.0 SATA controller [0106]: Advanced Micro Devices, Inc. [AMD] FCH SATA Controller [AHCI mode] [1022:7901] (rev 51) +c0:00.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Root Complex [1022:1480] +c0:00.2 IOMMU [0806]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse IOMMU [1022:1481] +c0:01.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +c0:01.1 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse GPP Bridge [1022:1483] +c0:02.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +c0:03.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +c0:04.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +c0:05.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +c0:07.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +c0:07.1 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Internal PCIe GPP Bridge 0 to bus[E:B] [1022:1484] +c0:08.0 Host bridge [0600]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Host Bridge [1022:1482] +c0:08.1 PCI bridge [0604]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Internal PCIe GPP Bridge 0 to bus[E:B] [1022:1484] +c1:00.0 VGA compatible controller [0300]: NVIDIA Corporation Device [10de:2d04] (rev a1) +c1:00.1 Audio device [0403]: NVIDIA Corporation Device [10de:22eb] (rev a1) +c2:00.0 Non-Essential Instrumentation [1300]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PCIe Dummy Function [1022:148a] +c2:00.2 Encryption controller [1080]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PTDMA [1022:1498] +c3:00.0 Non-Essential Instrumentation [1300]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse Reserved SPP [1022:1485] +c3:00.2 Encryption controller [1080]: Advanced Micro Devices, Inc. [AMD] Starship/Matisse PTDMA [1022:1498] +``` +USB devices (`lsusb`): +```text +Bus 008 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub +Bus 007 Device 004: ID 0557:9241 ATEN International Co., Ltd SMCI HID KM +Bus 007 Device 003: ID 0b1f:03ee Insyde Software Corp. RNDIS/Ethernet Gadget +Bus 007 Device 002: ID 1d6b:0107 Linux Foundation USB Virtual Hub +Bus 007 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub +Bus 006 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub +Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub +Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub +Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub +``` +Block devices (`lsblk`): +```text +NAME SIZE TYPE MOUNTPOINT MODEL SERIAL +loop1 399.8M loop +sda 232.9G disk Samsung SSD 870 EVO 250GB S6PDNL0W606533W +??????sda1 1M part +??????sda2 512M part +??????sda3 232.4G part +sdb 476.9G disk Samsung SSD 850 PRO 512GB S250NX0H445783F +??????sdb1 474.9G part +sdc 465.8G disk Samsung SSD 870 EVO 500GB S6PXNM0T410022E +??????sdc1 463.8G part +sdd 119.2G disk SPCC Solid State Disk 240275945121140 +??????sdd1 119.2G part +sde 119.2G disk SPCC Solid State Disk AA000000000000008357 +??????sde1 119.2G part +sdf 119.2G disk SPCC Solid State Disk AA000000000000008078 +??????sdf1 119.2G part +sdg 14.6T disk ST16000NM000J-2TW103 ZR70VAFG +??????sdg1 14.6T part +sdh 14.6T disk ST16000NM000J-2TW103 ZR70WHDM +??????sdh1 14.6T part +sdi 14.6T disk ST16000NM000J-2TW103 ZRS0TD9D +??????sdi1 14.6T part +sdj 14.6T disk ST16000NM001G-2KK103 ZL2JDCAA +??????sdj1 14.6T part +sdk 14.6T disk ST16000NM000J-2TW103 ZRS0TG44 +??????sdk1 14.6T part +zd0 40G disk +zd16 40G disk +zd32 40G disk +zd48 40G disk +zd64 40G disk +zd80 40G disk +zd96 40G disk +zd112 40G disk +zd128 40G disk +zd144 40G disk +zd160 40G disk +zd176 40G disk +zd192 40G disk +zd208 40G disk +zd224 40G disk +zd240 40G disk +nvme1n1 238.5G disk Sabrent SB-2130-256 48803179100121 +??????nvme1n1p1 238.5G part +nvme0n1 238.5G disk Sabrent SB-2130-256 48803179100104 +??????nvme0n1p1 238.5G part +nvme5n1 1.9T disk XG7000-2TB 2280 9J40708003039 +??????nvme5n1p1 1.9T part +nvme4n1 1.9T disk XG7000-2TB 2280 9J40708003019 +??????nvme4n1p1 1.9T part +nvme6n1 931.5G disk Sabrent SB-RKT4P-1TB 48790469701392 +??????nvme6n1p1 929.5G part +nvme3n1 931.5G disk Sabrent Rocket 4.0 Plus 7D89071A13B900012386 +??????nvme3n1p1 929.5G part +nvme7n1 931.5G disk Seagate ZP1000GM30063 D3200KWZ +??????nvme7n1p1 929.5G part +nvme2n1 931.5G disk Sabrent Rocket 4.0 Plus 44FE071A138F00011874 +??????nvme2n1p1 929.5G part +zd256 40G disk +zd272 40G disk +zd288 40G disk +zd304 40G disk +zd320 40G disk +zd336 40G disk +zd352 40G disk +zd368 40G disk +zd384 40G disk +zd400 40G disk +zd416 40G disk +zd432 40G disk +zd448 40G disk +zd464 40G disk +zd480 40G disk +zd496 40G disk +zd512 40G disk +zd528 40G disk +zd544 40G disk +zd560 40G disk +zd576 40G disk +zd592 40G disk +zd608 40G disk +zd624 40G disk +zd640 40G disk +zd656 40G disk +zd672 40G disk +zd688 40G disk +zd704 40G disk +zd720 40G disk +zd736 40G disk +zd752 40G disk +zd768 40G disk +zd784 40G disk +zd800 40G disk +zd816 40G disk +zd832 40G disk +zd848 40G disk +zd864 40G disk +zd880 40G disk +zd896 40G disk +zd912 40G disk +zd928 40G disk +zd944 40G disk +zd960 40G disk +zd976 40G disk +zd992 40G disk +zd1008 40G disk +zd1024 40G disk +zd1040 40G disk +zd1056 40G disk +zd1072 40G disk +zd1088 40G disk +zd1104 40G disk +zd1120 40G disk +zd1136 40G disk +zd1152 40G disk +zd1168 40G disk +zd1184 40G disk +zd1200 40G disk +zd1216 40G disk +zd1232 40G disk +zd1248 40G disk +zd1264 40G disk +zd1280 40G disk +zd1296 40G disk +zd1312 40G disk +zd1328 40G disk +zd1344 40G disk +zd1360 40G disk +zd1376 40G disk +zd1392 40G disk +zd1408 40G disk +zd1424 40G disk +zd1440 40G disk +zd1456 40G disk +zd1472 40G disk +zd1488 40G disk +zd1504 40G disk +zd1520 40G disk +zd1536 40G disk +zd1552 40G disk +zd1568 40G disk +zd1584 40G disk +zd1600 40G disk +zd1616 40G disk +zd1632 40G disk +zd1648 40G disk +zd1664 40G disk +zd1680 40G disk +zd1696 40G disk +zd1712 40G disk +zd1728 40G disk +zd1744 40G disk +zd1760 40G disk +zd1776 40G disk +zd1792 40G disk +zd1808 40G disk +zd1824 40G disk +zd1840 40G disk +zd1856 40G disk +zd1872 40G disk +zd1888 40G disk +zd1904 40G disk +zd1920 40G disk +zd1936 40G disk +zd1952 40G disk +zd1968 40G disk +zd1984 40G disk +zd2000 40G disk +zd2016 40G disk +zd2032 40G disk +zd2048 40G disk +zd2064 40G disk +zd2080 40G disk +zd2096 40G disk +zd2112 40G disk +zd2128 40G disk +zd2144 40G disk +zd2160 40G disk +zd2176 40G disk +zd2192 40G disk +zd2208 40G disk +zd2224 40G disk +zd2240 40G disk +zd2256 40G disk +zd2272 40G disk +zd2288 40G disk +zd2304 40G disk +zd2320 40G disk +zd2336 40G disk +zd2352 40G disk +zd2368 40G disk +zd2384 40G disk +zd2400 40G disk +zd2416 40G disk +zd2432 40G disk +zd2448 40G disk +zd2464 40G disk +zd2480 40G disk +zd2496 40G disk +zd2512 40G disk +zd2528 40G disk +zd2544 40G disk +zd2560 40G disk +zd2576 40G disk +zd2592 40G disk +zd2608 40G disk +zd2624 40G disk +zd2640 40G disk +zd2656 40G disk +zd2672 40G disk +zd2688 40G disk +zd2704 40G disk +zd2720 40G disk +zd2736 40G disk +zd2752 40G disk +zd2768 40G disk +zd2784 40G disk +zd2800 40G disk +zd2816 40G disk +zd2832 40G disk +zd2848 40G disk +zd2864 40G disk +zd2880 40G disk +zd2896 40G disk +zd2912 40G disk +zd2928 40G disk +zd2944 40G disk +zd2960 40G disk +zd2976 40G disk +zd2992 40G disk +zd3008 40G disk +zd3024 40G disk +zd3040 40G disk +zd3056 40G disk +zd3072 40G disk +zd3088 40G disk +zd3104 40G disk +zd3120 40G disk +zd3136 40G disk +zd3152 40G disk +zd3168 40G disk +zd3184 40G disk +zd3200 40G disk +zd3216 40G disk +zd3232 40G disk +zd3248 40G disk +zd3264 40G disk +zd3280 40G disk +zd3296 40G disk +zd3312 40G disk +zd3328 40G disk +zd3344 40G disk +zd3360 40G disk +zd3376 40G disk +zd3392 40G disk +zd3408 40G disk +zd3424 40G disk +zd3440 40G disk +zd3456 40G disk +zd3472 40G disk +zd3488 40G disk +zd3504 40G disk +zd3520 40G disk +zd3536 40G disk +zd3552 40G disk +zd3568 40G disk +zd3584 40G disk +zd3600 40G disk +zd3616 40G disk +zd3632 40G disk +zd3648 40G disk +zd3664 40G disk +zd3680 40G disk +zd3696 40G disk +zd3712 40G disk +zd3728 40G disk +zd3744 40G disk +zd3760 40G disk +zd3776 40G disk +zd3792 40G disk +zd3808 40G disk +zd3824 40G disk +zd3840 40G disk +zd3856 40G disk +zd3872 40G disk +zd3888 40G disk +zd3904 40G disk +zd3920 40G disk +zd3936 40G disk +zd3952 40G disk +zd3968 40G disk +zd3984 40G disk +zd4000 40G disk +zd4016 40G disk +zd4032 40G disk +zd4048 40G disk +zd4064 40G disk +zd4080 40G disk +zd4096 40G disk +zd4112 40G disk +zd4128 40G disk +zd4144 40G disk +zd4160 40G disk +zd4176 40G disk +zd4192 40G disk +zd4208 40G disk +zd4224 40G disk +zd4240 40G disk +zd4256 40G disk +zd4272 40G disk +zd4288 40G disk +zd4304 40G disk +zd4320 40G disk +zd4336 40G disk +zd4352 40G disk +zd4368 40G disk +zd4384 40G disk +zd4400 40G disk +zd4416 40G disk +zd4432 40G disk +zd4448 40G disk +zd4464 40G disk +zd4480 40G disk +zd4496 40G disk +zd4512 40G disk +zd4528 40G disk +zd4544 40G disk +zd4560 40G disk +zd4576 40G disk +zd4592 40G disk +zd4608 40G disk +zd4624 40G disk +zd4640 40G disk +zd4656 40G disk +zd4672 40G disk +zd4688 40G disk +zd4704 40G disk +zd4720 40G disk +zd4736 40G disk +zd4752 40G disk +zd4768 40G disk +zd4784 40G disk +zd4800 40G disk +zd4816 40G disk +zd4832 40G disk +zd4848 40G disk +zd4864 40G disk +zd4880 400G disk +zd4896 40G disk +zd4912 40G disk +zd4928 40G disk +zd4944 40G disk +zd4960 40G disk +zd4976 40G disk +zd4992 40G disk +zd5008 40G disk +zd5024 40G disk +zd5040 40G disk +zd5056 40G disk +zd5072 40G disk +zd5088 40G disk +zd5104 40G disk +zd5120 40G disk +zd5136 40G disk +zd5152 40G disk +zd5168 40G disk +zd5184 40G disk +zd5200 40G disk +zd5216 500G disk +zd5232 40G disk +zd5248 40G disk +zd5264 40G disk +zd5280 40G disk +zd5296 40G disk +zd5312 40G disk +zd5328 40G disk +zd5344 40G disk +zd5360 40G disk +zd5376 40G disk +zd5392 40G disk +zd5408 40G disk +zd5424 400G disk +zd5440 400G disk +zd5456 400G disk +zd5472 400G disk +zd5488 400G disk +zd5504 400G disk +zd5520 400G disk +zd5536 400G disk +zd5552 400G disk +zd5568 400G disk +zd5584 400G disk +zd5600 400G disk +zd5616 400G disk +zd5632 400G disk +zd5648 400G disk +zd5664 400G disk +zd5680 400G disk +zd5696 400G disk +zd5712 400G disk +zd5728 400G disk +zd5744 400G disk +zd5776 400G disk +zd5792 400G disk +zd5808 400G disk +zd5824 400G disk +zd5840 400G disk +zd5856 400G disk +zd5872 400G disk +zd5888 400G disk +zd5904 400G disk +zd5920 400G disk +zd5936 400G disk +zd5952 400G disk +zd5968 400G disk +zd5984 400G disk +zd6000 400G disk +zd6016 400G disk +zd6032 400G disk +zd6048 400G disk +zd6064 400G disk +zd6080 400G disk +zd6112 400G disk +zd6128 400G disk +zd6144 400G disk +zd6160 400G disk +zd6176 400G disk +zd6192 400G disk +zd6208 400G disk +zd6224 400G disk +zd6240 400G disk +zd6256 400G disk +zd6272 400G disk +zd6288 400G disk +zd6304 400G disk +zd6320 400G disk +zd6336 400G disk +zd6352 400G disk +zd6368 400G disk +zd6384 400G disk +zd6400 400G disk +zd6416 400G disk +zd6432 400G disk +zd6448 400G disk +zd6464 400G disk +zd6480 400G disk +zd6496 400G disk +zd6512 400G disk +zd6528 400G disk +zd6544 400G disk +zd6560 400G disk +zd6576 400G disk +zd6592 400G disk +zd6608 400G disk +zd6624 400G disk +zd6640 400G disk +zd6656 400G disk +zd6672 400G disk +zd6688 400G disk +zd6704 400G disk +zd6720 400G disk +zd6736 400G disk +zd6752 400G disk +zd6768 400G disk +zd6784 400G disk +zd6800 400G disk +zd6816 400G disk +zd6848 400G disk +zd6864 400G disk +zd6880 400G disk +zd6896 400G disk +zd6912 400G disk +zd6928 400G disk +zd6944 400G disk +zd6960 400G disk +zd6976 400G disk +zd6992 400G disk +zd7008 400G disk +zd7024 400G disk +zd7040 400G disk +zd7056 400G disk +zd7072 400G disk +zd7088 400G disk +zd7104 400G disk +zd7120 400G disk +zd7136 400G disk +zd7152 400G disk +zd7168 400G disk +zd7184 400G disk +zd7200 400G disk +zd7216 400G disk +zd7232 400G disk +zd7248 400G disk +zd7264 400G disk +zd7280 400G disk +zd7296 400G disk +zd7312 400G disk +zd7328 400G disk +zd7344 400G disk +zd7360 400G disk +zd7376 400G disk +zd7392 400G disk +zd7408 400G disk +zd7424 400G disk +zd7440 400G disk +zd7456 400G disk +zd7472 400G disk +zd7488 400G disk +zd7504 400G disk +zd7520 400G disk +zd7536 400G disk +zd7552 400G disk +zd7568 400G disk +zd7584 400G disk +zd7600 400G disk +zd7616 400G disk +zd7632 400G disk +zd7648 400G disk +zd7664 400G disk +zd7680 400G disk +zd7696 400G disk +zd7712 400G disk +zd7728 400G disk +zd7744 400G disk +zd7760 400G disk +zd7776 400G disk +zd7792 400G disk +zd7808 400G disk +zd7824 400G disk +zd7840 400G disk +zd7856 400G disk +zd7872 400G disk +zd7888 400G disk +zd7904 400G disk +zd7920 400G disk +zd7936 400G disk +zd7952 400G disk +zd7968 400G disk +zd7984 400G disk +zd8000 400G disk +zd8016 400G disk +zd8032 400G disk +zd8048 400G disk +zd8064 400G disk +zd8080 400G disk +zd8096 400G disk +zd8112 400G disk +zd8128 400G disk +zd8144 400G disk +zd8160 400G disk +zd8176 400G disk +zd8192 400G disk +zd8208 400G disk +zd8224 400G disk +zd8240 400G disk +zd8256 400G disk +zd8272 400G disk +zd8288 400G disk +zd8304 400G disk +zd8320 400G disk +zd8336 400G disk +zd8352 400G disk +zd8368 400G disk +zd8384 400G disk +zd8400 400G disk +zd8416 400G disk +zd8432 400G disk +zd8448 500G disk +zd8464 500G disk +zd8480 500G disk +zd8496 500G disk +zd8512 500G disk +zd8528 500G disk +zd8544 500G disk +zd8560 500G disk +zd8576 500G disk +zd8592 500G disk +zd8608 500G disk +zd8624 500G disk +zd8640 500G disk +zd8656 500G disk +zd8672 500G disk +zd8688 500G disk +zd8704 500G disk +zd8720 500G disk +zd8736 500G disk +zd8752 500G disk +zd8768 500G disk +zd8784 500G disk +zd8800 500G disk +zd8816 500G disk +zd8832 500G disk +zd8848 500G disk +zd8864 500G disk +zd8880 500G disk +zd8896 500G disk +zd8912 500G disk +zd8928 500G disk +zd8944 500G disk +zd8960 500G disk +zd8976 500G disk +zd8992 500G disk +zd9008 500G disk +zd9024 500G disk +zd9040 500G disk +zd9056 500G disk +zd9072 500G disk +zd9088 500G disk +zd9104 500G disk +zd9136 500G disk +zd9168 500G disk +zd9184 500G disk +zd9200 500G disk +zd9216 500G disk +zd9232 500G disk +zd9248 500G disk +zd9264 500G disk +zd9280 500G disk +zd9296 500G disk +zd9312 500G disk +zd9328 500G disk +zd9344 500G disk +zd9360 500G disk +zd9376 500G disk +zd9392 500G disk +zd9408 500G disk +zd9424 500G disk +zd9440 500G disk +zd9456 500G disk +zd9472 500G disk +zd9488 500G disk +zd9504 500G disk +zd9520 500G disk +zd9536 500G disk +zd9552 500G disk +zd9568 100G disk +zd9584 100G disk +zd9600 40G disk +zd9632 40G disk +zd9648 40G disk +zd9664 40G disk +zd9680 40G disk +zd9696 40G disk +zd9712 40G disk +zd9728 40G disk +zd9744 40G disk +zd9760 40G disk +zd9776 40G disk +zd9792 40G disk +zd9808 40G disk +zd9824 40G disk +zd9840 40G disk +zd9856 40G disk +zd9872 40G disk +zd9888 40G disk +zd9904 40G disk +zd9920 40G disk +zd9936 40G disk +zd9952 40G disk +zd9968 40G disk +zd9984 40G disk +zd10000 40G disk +zd10016 40G disk +zd10032 40G disk +zd10048 40G disk +zd10064 40G disk +zd10080 40G disk +zd10096 40G disk +zd10112 40G disk +zd10128 40G disk +zd10144 40G disk +zd10160 40G disk +zd10176 40G disk +zd10192 40G disk +zd10208 40G disk +zd10224 40G disk +zd10240 40G disk +zd10256 40G disk +zd10272 40G disk +zd10288 40G disk +zd10304 40G disk +zd10320 40G disk +zd10336 40G disk +zd10352 40G disk +zd10368 40G disk +zd10384 40G disk +zd10400 40G disk +zd10416 40G disk +zd10432 40G disk +zd10448 40G disk +zd10464 40G disk +zd10480 40G disk +zd10496 40G disk +zd10512 40G disk +zd10528 40G disk +zd10544 40G disk +zd10560 40G disk +zd10576 40G disk +zd10592 40G disk +zd10608 40G disk +zd10624 40G disk +zd10640 40G disk +zd10656 40G disk +zd10672 40G disk +zd10688 40G disk +zd10704 40G disk +zd10720 40G disk +zd10736 40G disk +zd10752 40G disk +zd10768 40G disk +zd10784 40G disk +zd10800 40G disk +zd10816 40G disk +zd10832 40G disk +zd10848 40G disk +zd10864 40G disk +zd10880 40G disk +zd10896 40G disk +zd10912 40G disk +zd10928 40G disk +zd10944 40G disk +zd10960 40G disk +zd10976 40G disk +zd10992 40G disk +zd11008 40G disk +zd11024 40G disk +zd11040 40G disk +zd11056 40G disk +zd11072 40G disk +zd11088 40G disk +zd11104 40G disk +zd11120 40G disk +zd11136 40G disk +zd11152 40G disk +zd11168 40G disk +zd11184 40G disk +zd11200 40G disk +zd11216 40G disk +zd11232 40G disk +zd11248 40G disk +zd11264 40G disk +zd11280 40G disk +zd11296 40G disk +zd11312 40G disk +zd11328 40G disk +zd11344 40G disk +zd11360 40G disk +zd11376 40G disk +zd11392 40G disk +zd11408 40G disk +zd11424 40G disk +zd11440 40G disk +zd11456 40G disk +zd11472 40G disk +zd11488 40G disk +zd11504 40G disk +zd11520 40G disk +zd11536 40G disk +zd11552 40G disk +zd11568 40G disk +zd11584 40G disk +zd11600 40G disk +zd11616 40G disk +zd11632 40G disk +zd11648 40G disk +zd11664 40G disk +zd11680 40G disk +zd11696 40G disk +zd11712 40G disk +zd11728 40G disk +zd11744 40G disk +zd11760 40G disk +zd11776 40G disk +zd11792 40G disk +zd11808 40G disk +zd11824 40G disk +zd11840 40G disk +zd11856 40G disk +zd11872 40G disk +zd11888 40G disk +zd11904 40G disk +zd11920 40G disk +zd11936 40G disk +zd11952 40G disk +zd11968 40G disk +zd11984 40G disk +zd12000 40G disk +zd12016 40G disk +zd12032 40G disk +zd12048 40G disk +zd12064 40G disk +zd12080 40G disk +zd12096 40G disk +zd12112 40G disk +zd12128 40G disk +zd12144 40G disk +zd12160 40G disk +zd12176 40G disk +zd12192 40G disk +zd12208 40G disk +zd12224 40G disk +zd12240 40G disk +zd12256 40G disk +zd12272 40G disk +zd12288 40G disk +zd12304 40G disk +zd12320 40G disk +zd12336 40G disk +zd12352 40G disk +zd12368 40G disk +zd12384 40G disk +zd12400 40G disk +zd12416 40G disk +zd12432 40G disk +zd12448 40G disk +zd12464 40G disk +zd12480 40G disk +zd12496 40G disk +zd12512 40G disk +zd12528 40G disk +zd12544 40G disk +zd12560 40G disk +zd12576 40G disk +zd12592 40G disk +zd12608 40G disk +zd12624 40G disk +zd12640 40G disk +zd12656 40G disk +zd12672 40G disk +zd12688 40G disk +zd12704 40G disk +zd12720 40G disk +zd12736 40G disk +zd12752 40G disk +zd12768 40G disk +zd12784 40G disk +zd12800 40G disk +zd12816 40G disk +zd12832 40G disk +zd12848 40G disk +zd12864 40G disk +zd12880 40G disk +zd12896 40G disk +zd12928 40G disk +zd12944 40G disk +zd12960 40G disk +zd12976 40G disk +zd12992 40G disk +zd13008 40G disk +zd13024 40G disk +zd13040 40G disk +zd13056 40G disk +zd13072 40G disk +zd13088 40G disk +zd13104 40G disk +zd13120 40G disk +zd13136 40G disk +zd13152 40G disk +zd13168 40G disk +zd13184 40G disk +zd13200 40G disk +zd13216 40G disk +zd13232 40G disk +zd13248 40G disk +zd13264 40G disk +zd13280 40G disk +zd13296 40G disk +zd13312 40G disk +zd13328 40G disk +zd13344 40G disk +zd13360 40G disk +zd13376 40G disk +zd13392 40G disk +zd13408 40G disk +zd13424 40G disk +zd13440 40G disk +zd13456 40G disk +zd13472 40G disk +zd13488 40G disk +zd13504 40G disk +zd13520 40G disk +zd13552 40G disk +zd13568 40G disk +zd13584 40G disk +zd13600 40G disk +zd13616 40G disk +zd13632 40G disk +zd13648 40G disk +zd13664 40G disk +zd13680 40G disk +zd13696 40G disk +zd13712 40G disk +zd13728 40G disk +zd13744 40G disk +zd13760 40G disk +zd13776 40G disk +zd13792 40G disk +zd13808 40G disk +zd13824 40G disk +zd13840 40G disk +zd13856 40G disk +zd13872 40G disk +zd13888 40G disk +zd13904 40G disk +zd13920 40G disk +zd13936 40G disk +zd13952 40G disk +zd13968 40G disk +zd13984 40G disk +zd14000 40G disk +zd14016 40G disk +zd14032 40G disk +zd14048 40G disk +zd14064 40G disk +zd14080 40G disk +zd14096 40G disk +zd14112 40G disk +zd14128 40G disk +zd14144 40G disk +zd14160 40G disk +zd14176 40G disk +zd14192 40G disk +zd14208 40G disk +zd14224 40G disk +zd14240 40G disk +zd14256 40G disk +zd14272 40G disk +zd14288 40G disk +zd14304 40G disk +zd14320 40G disk +zd14336 40G disk +zd14352 40G disk +zd14368 40G disk +zd14384 40G disk +zd14400 40G disk +zd14416 40G disk +zd14432 40G disk +zd14448 40G disk +zd14464 40G disk +zd14480 40G disk +zd14496 40G disk +zd14512 40G disk +zd14528 40G disk +zd14544 40G disk +zd14560 40G disk +zd14576 40G disk +zd14592 40G disk +zd14608 40G disk +zd14624 40G disk +zd14640 40G disk +zd14656 40G disk +zd14672 40G disk +zd14688 40G disk +zd14704 40G disk +zd14720 40G disk +zd14736 40G disk +zd14752 40G disk +zd14768 40G disk +zd14784 40G disk +zd14800 40G disk +zd14816 40G disk +zd14832 40G disk +zd14848 40G disk +zd14864 40G disk +zd14880 40G disk +zd14896 40G disk +zd14912 40G disk +zd14928 40G disk +zd14944 40G disk +zd14960 40G disk +zd14976 40G disk +zd14992 40G disk +zd15008 40G disk +zd15024 400G disk +zd15040 400G disk +zd15056 400G disk +zd15072 400G disk +zd15088 400G disk +zd15104 400G disk +zd15120 400G disk +zd15136 400G disk +zd15152 400G disk +zd15168 400G disk +zd15184 400G disk +zd15200 400G disk +zd15216 400G disk +zd15232 400G disk +zd15248 400G disk +zd15264 400G disk +zd15280 400G disk +zd15296 400G disk +zd15312 400G disk +zd15328 400G disk +zd15344 400G disk +zd15360 400G disk +zd15376 400G disk +zd15392 400G disk +zd15408 400G disk +zd15424 400G disk +zd15440 400G disk +zd15456 400G disk +zd15472 400G disk +zd15488 400G disk +zd15504 400G disk +zd15520 400G disk +zd15536 400G disk +zd15552 400G disk +zd15568 400G disk +zd15584 400G disk +zd15600 400G disk +zd15616 400G disk +zd15632 400G disk +zd15648 400G disk +zd15664 400G disk +zd15680 400G disk +zd15696 400G disk +zd15712 400G disk +zd15744 400G disk +zd15760 400G disk +zd15776 400G disk +zd15792 400G disk +zd15808 400G disk +zd15824 400G disk +zd15840 400G disk +zd15856 400G disk +zd15872 400G disk +zd15888 400G disk +zd15904 400G disk +zd15920 400G disk +zd15936 400G disk +zd15952 400G disk +zd15968 400G disk +zd15984 400G disk +zd16000 400G disk +zd16016 400G disk +zd16048 400G disk +zd16064 400G disk +zd16080 400G disk +zd16096 400G disk +zd16112 400G disk +zd16128 400G disk +zd16144 400G disk +zd16160 400G disk +zd16176 400G disk +zd16192 400G disk +zd16208 400G disk +zd16224 400G disk +zd16240 400G disk +zd16256 400G disk +zd16272 400G disk +zd16288 400G disk +zd16304 400G disk +zd16320 400G disk +zd16336 400G disk +zd16352 400G disk +zd16368 400G disk +zd16384 400G disk +zd16400 400G disk +zd16416 400G disk +zd16432 400G disk +zd16448 400G disk +zd16464 400G disk +zd16480 400G disk +zd16496 400G disk +zd16512 400G disk +zd16528 400G disk +zd16544 400G disk +zd16560 400G disk +zd16576 400G disk +zd16592 400G disk +zd16608 400G disk +zd16624 400G disk +zd16640 400G disk +zd16656 400G disk +zd16672 400G disk +zd16688 400G disk +zd16704 400G disk +zd16720 400G disk +zd16736 400G disk +zd16752 400G disk +zd16768 400G disk +zd16784 400G disk +zd16800 400G disk +zd16816 400G disk +zd16832 400G disk +zd16848 400G disk +zd16864 400G disk +zd16880 400G disk +zd16896 400G disk +zd16912 400G disk +zd16928 400G disk +zd16944 400G disk +zd16960 400G disk +zd16976 400G disk +zd16992 400G disk +zd17008 400G disk +zd17024 400G disk +zd17040 400G disk +zd17056 400G disk +zd17072 400G disk +zd17088 400G disk +zd17104 400G disk +zd17120 400G disk +zd17136 400G disk +zd17152 400G disk +zd17168 400G disk +zd17184 400G disk +zd17200 400G disk +zd17216 400G disk +zd17232 400G disk +zd17248 400G disk +zd17264 400G disk +zd17280 400G disk +zd17296 400G disk +zd17312 400G disk +zd17328 400G disk +zd17344 400G disk +zd17360 400G disk +zd17376 400G disk +zd17392 400G disk +zd17408 400G disk +zd17424 400G disk +zd17440 400G disk +zd17456 400G disk +zd17472 400G disk +zd17488 400G disk +zd17504 400G disk +zd17520 400G disk +zd17536 400G disk +zd17552 400G disk +zd17568 400G disk +zd17584 400G disk +zd17600 400G disk +zd17616 400G disk +zd17632 400G disk +zd17648 400G disk +zd17664 400G disk +zd17680 400G disk +zd17696 400G disk +zd17712 400G disk +zd17728 400G disk +zd17744 400G disk +zd17760 400G disk +zd17776 400G disk +zd17792 400G disk +zd17808 400G disk +zd17824 400G disk +zd17840 400G disk +zd17856 400G disk +zd17872 400G disk +zd17888 400G disk +zd17904 400G disk +zd17920 400G disk +zd17936 400G disk +zd17952 400G disk +zd17968 400G disk +zd18000 400G disk +zd18016 400G disk +zd18032 400G disk +zd18048 500G disk +zd18064 500G disk +zd18080 500G disk +zd18096 500G disk +zd18112 500G disk +zd18128 500G disk +zd18144 500G disk +zd18160 500G disk +zd18176 500G disk +zd18192 500G disk +zd18208 500G disk +zd18224 500G disk +zd18240 500G disk +zd18256 500G disk +zd18288 500G disk +zd18304 500G disk +zd18320 500G disk +zd18336 500G disk +zd18352 500G disk +zd18384 500G disk +zd18400 500G disk +zd18416 500G disk +zd18432 500G disk +zd18448 500G disk +zd18464 500G disk +zd18480 500G disk +zd18496 500G disk +zd18512 500G disk +zd18528 500G disk +zd18544 500G disk +zd18560 500G disk +zd18576 500G disk +zd18592 500G disk +zd18608 500G disk +zd18624 500G disk +zd18640 500G disk +zd18656 500G disk +zd18672 500G disk +zd18688 500G disk +zd18704 500G disk +zd18720 500G disk +zd18736 500G disk +zd18752 500G disk +zd18768 500G disk +zd18784 500G disk +zd18800 500G disk +zd18816 500G disk +zd18832 500G disk +zd18848 500G disk +zd18864 500G disk +zd18880 500G disk +zd18896 500G disk +zd18912 500G disk +zd18928 500G disk +zd18944 500G disk +zd18960 500G disk +zd18976 500G disk +zd18992 500G disk +zd19008 500G disk +zd19024 500G disk +zd19040 500G disk +zd19056 500G disk +zd19072 500G disk +zd19088 500G disk +zd19104 500G disk +zd19120 500G disk +zd19136 100G disk +zd19152 500G disk +zd19168 500G disk +zd19184 40G disk +zd19200 5.7G disk +zd19216 10G disk +zd19232 10G disk +``` + +## Redactions +- UI certificate private key content removed (see `inventory_raw/system.general.config.json` and `inventory_raw/certificate.query.json` for metadata only). +- Cloud Sync credentials and tokens removed (Google Drive task). +- IPMI password removed from init script command. +- Replication SSH host keys and private key references not reproduced. + +## Ollama Experiment Log (2025-12-29 to 2025-12-30) + +### Environment +- Host: TrueNAS SCALE `truenas` at `192.168.1.2`, ollama service in container `ix-ollama-ollama-1`, API `http://192.168.1.2:30068`. +- GPUs: 2x NVIDIA RTX 5060 Ti, 16 GB each (per `nvidia-smi` in prior runs). +- Ollama env in app config: `OLLAMA_GPU_LAYERS=999`, `OLLAMA_SCHED_SPREAD=1`, `OLLAMA_FLASH_ATTENTION=1`, `OLLAMA_KV_CACHE_TYPE=q4_0`. +- Harness: `ollama_remote_test.ps1` + `prompt_crwv.txt`. Outputs: `ollama_runs_remote/` and aggregate CSV `ollama_runs_remote/all_runs.csv`. + +### Model Context Length Checks +- `deepseek-r1:14b`: 131072 +- `phi3:mini-128k`: 131072 +- `llama3.1:70b`: 131072 (but 500 errors at 131072 ctx in tests) +- `qwen2.5:32b-instruct`: 32768 +- `qwen2.5-14b-instruct-128k-q4km-dahara1`: 32768 +- `qwen2.5:14b-instruct`: 32768 +- `phi4:14b`: 16384 + +### Pull / Create Attempts +- `qwen2.5:32b-instruct` pull initially timed out while downloading (19 GB), later verified present in `ollama list`. +- `qwen2.5:32b-instruct-128k` and `dahara1/qwen2.5-32b-instruct-128k-q4km` tags not found. +- Custom Modelfiles created under `modelfiles/` and registered: + - `options-json-deepseek14b` from `deepseek-r1:14b` + - `options-json-phi3mini` from `phi3:mini-128k` + - `options-json-llama31-70b` from `llama3.1:70b` + +### Harness Changes +- Added deterministic decode options: `top_k`, `top_p`, `seed`, `repeat_penalty` in `ollama_remote_test.ps1`. +- Added Modelfile templates with strict JSON-only system prompt. +- GPU utilization parsing from `nvidia-smi -q` logs frequently reported 0 samples; `ollama ps` is the primary indicator of CPU/GPU split. + +### Attempts By Batch (from summary.json files) +Note: `batch_20251229_154716` contains only `run.log` (no `summary.json`). + +``` +batch model runs ok format +----- ----- ---- -- ------ +20251229_154736 gemma3:12b 2 0 +20251229_154736 gemma3:4b 2 0 +20251229_154736 gpt-oss:20b 2 0 +20251229_154736 llama3.1:latest 2 0 +20251229_154736 llama3.2:1b 2 0 +20251229_154736 llama3.2:3b 2 2 +20251229_154736 ministral-3:14b 2 0 +20251229_154736 rushg-optionstrader:latest 2 0 +20251229_154736 trained-options-model:latest 2 0 +20251229_160359 command-r:35b 2 0 +20251229_160359 deepseek-r1:14b 2 0 +20251229_160359 gemma3:12b 2 0 +20251229_160359 gemma3:4b 2 0 +20251229_160359 gpt-oss:20b 2 0 +20251229_160359 llama3.1:latest 2 0 +20251229_160359 llama3.2:1b 2 0 +20251229_160359 llama3.2:3b 2 2 +20251229_160359 ministral-3:14b 2 0 +20251229_160359 mistral-nemo:12b 2 0 +20251229_160359 phi3:mini-128k 2 0 +20251229_160359 rushg-optionstrader:latest 2 0 +20251229_160359 trained-options-model:latest 2 0 +20251229_163328 command-r:35b 2 0 +20251229_163328 deepseek-r1:14b 2 0 +20251229_163328 gemma3:12b 2 0 +20251229_163328 gemma3:4b 2 0 +20251229_163328 gpt-oss:20b 2 0 +20251229_163328 llama3.1:latest 2 0 +20251229_163328 llama3.2:1b 2 0 +20251229_163328 llama3.2:3b 2 2 +20251229_163328 ministral-3:14b 2 0 +20251229_163328 mistral-nemo:12b 2 0 +20251229_163328 phi3:mini-128k 2 0 +20251229_163328 rushg-optionstrader:latest 2 0 +20251229_163328 trained-options-model:latest 2 0 +20251229_175208_10runs_gpu llama3.2:3b 10 0 +20251229_180423_10runs_gpu_strict llama3.2:3b 10 0 +detjson_20251230 options-json-deepseek14b 5 0 json +detjson_20251230 options-json-llama31-70b 5 0 json +detjson_20251230 options-json-phi3mini 5 0 json +detjson_20251230 qwen2.5:32b-instruct 5 0 json +gpucheck_20251229_2015 deepseek-r1:14b 1 0 schema +gpuonly_20251229_2100 deepseek-r1:14b 10 0 schema +gpuonly_20251229_2100 ministral-3:14b 10 0 schema +gpuonly_20251229_2100 qwen2.5-14b-instruct-128k-q4km-dahara1 10 0 schema +gpuonly_20251229_2100 qwen2.5-7b-instruct-128k-q4km-dahara1 10 0 schema +gpuonly_20251229_2230 deepseek-r1:14b 1 0 schema +gpuonly_20251229_2230 ministral-3:14b 1 0 schema +gpuonly_20251229_2230 phi3:mini-128k 1 0 schema +gpuonly_20251229_2230 qwen2.5-14b-instruct-128k-q4km-dahara1 1 0 schema +gpuonly_20251229_2230 qwen2.5-7b-instruct-128k-q4km-dahara1 1 0 schema +gpuonly_20251229_2245 deepseek-r1:14b 2 0 schema +gpuonly_20251229_2245 ministral-3:14b 2 0 schema +gpuonly_20251229_2245 phi3:mini-128k 2 0 schema +gpuonly_20251229_2245 qwen2.5-14b-instruct-128k-q4km-dahara1 5 0 schema +gpuonly_20251229_2245 qwen2.5-7b-instruct-128k-q4km-dahara1 2 0 schema +schema_20251229_1845 deepseek-r1:14b 10 10 schema +schema_20251229_1845 ministral-3:14b 10 0 schema +schema_20251229_1845 qwen2.5-14b-instruct-128k-q4km-dahara1 10 0 schema +schema_20251229_1845 qwen2.5-7b-instruct-128k-q4km-dahara1 10 0 schema +schema_20251229_2005 deepseek-r1:14b 10 3 schema +``` + +### Aggregate Pass-Rate Graph (all attempts) +Counts are aggregated across all runs in `ollama_runs_remote/all_runs.csv` regardless of format. + +``` +model ok/total pass% graph +deepseek-r1:14b 15/38 39.5% ########............ +llama3.2:3b 6/26 23.1% #####............... +qwen2.5-14b-instruct-128k-q4km-dahara1 4/26 15.4% ###................. +qwen2.5-7b-instruct-128k-q4km-dahara1 0/23 0.0% .................... +phi3:mini-128k 0/7 0.0% .................... +mistral-nemo:12b 0/4 0.0% .................... +options-json-deepseek14b 0/5 0.0% .................... +qwen2.5:32b-instruct 0/5 0.0% .................... +options-json-phi3mini 0/5 0.0% .................... +options-json-llama31-70b 0/5 0.0% .................... +gpt-oss:20b 0/6 0.0% .................... +llama3.1:latest 0/6 0.0% .................... +gemma3:12b 0/6 0.0% .................... +gemma3:4b 0/6 0.0% .................... +llama3.2:1b 0/6 0.0% .................... +trained-options-model:latest 0/6 0.0% .................... +command-r:35b 0/4 0.0% .................... +ministral-3:14b 0/29 0.0% .................... +rushg-optionstrader:latest 0/6 0.0% .................... +``` + +### Observed Failure Patterns (most frequent) +- Invented expiries/strikes not in `liquidSet` (dominant failure mode). +- Structure/leg mismatches (e.g., straddle/strangle legs not 1 call + 1 put). +- Missing required top-level keys (e.g., `confidenceScore`). +- Invalid JSON or truncation (less frequent after increasing `num_predict`). +- `llama3.1:70b` returned HTTP 500 at 131072 ctx (likely OOM). + +### GPU Utilization Notes +- `ollama ps` shows CPU/GPU splits for some runs (e.g., `options-json-deepseek14b` reported `26%/74% CPU/GPU`). +- Several runs reported `100% GPU` in `ollama ps`. +- `nvidia-smi` log parsing currently yields `gpu0Used=false`/`gpu1Used=false` due to parser limitations; use `ollama ps` for now. + +### Llama.cpp Status (as of 2025-12-30) +- No llama.cpp server container found in `docker ps` or `docker ps -a`. +- The only related service is `ix-rushg-llama-cpp-proxy-n8n-rushg-llama-cpp-proxy-n8n-1`, which proxies to `UPSTREAM_BASE_URL=http://192.168.1.2:8071`. +- Host port `8071` is not listening (`ss -tulpen | grep 8071` returned nothing). +- Action needed: confirm where llama.cpp server should run (container name, port, or install instructions). + +### Llama.cpp Multi-GPU Fix (2026-01-03) +- Root cause: TrueNAS rendered compose exposed only one GPU to the `llamacpp` container. `NVIDIA_VISIBLE_DEVICES` and `deploy.resources.reservations.devices[0].device_ids` contained only `GPU-18f793cd-7d66-1415-c610-96c38ffc255d`. Also `user_config.yaml` had both PCI entries pointing at the same UUID. +- Updated TrueNAS app config to expose both GPUs: + - `/mnt/.ix-apps/app_configs/llamacpp/versions/1.2.17/user_config.yaml` + - `resources.gpus.use_all_gpus: true` + - `resources.gpus.nvidia_gpu_selection.0000:01:00.0.uuid = GPU-18f793cd-7d66-1415-c610-96c38ffc255d` + - `resources.gpus.nvidia_gpu_selection.0000:c1:00.0.uuid = GPU-471590af-4949-478f-740e-055f7ec34536` + - `/mnt/.ix-apps/app_configs/llamacpp/versions/1.2.17/templates/rendered/docker-compose.yaml` + - `services.llamacpp.environment.NVIDIA_VISIBLE_DEVICES = GPU-18f793cd-7d66-1415-c610-96c38ffc255d,GPU-471590af-4949-478f-740e-055f7ec34536` + - `services.llamacpp.deploy.resources.reservations.devices[0].device_ids = [UUID0, UUID1]` +- Applied update via `midclt call app.update llamacpp` with the modified compose (container restarted healthy). +- Verification: `docker logs ix-llamacpp-llamacpp-1` shows both CUDA devices initialized and KV/compute buffers split across CUDA0/CUDA1. + - Recheck after user report (2025-12-30): still only the proxy container is visible (`0.0.0.0:9091->8000/tcp`); no listening port 8071 found. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..16bcdcc --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,20 @@ +# AGENTS (compressed) + +This is the compact working context. For the full historical inventory and detailed snapshots, see `AGENTS.full.md` and `inventory_raw/`. + +## Access + basics +- SSH: `ssh -p 55555 rushabh@192.168.1.2` +- Sudo: `sudo -n true` +- TrueNAS UI: `http://192.168.1.2` + +## Full context pointers +- Full inventory snapshot and extra system details: `AGENTS.full.md` +- Raw captured data: `inventory_raw/` +- Documentation notes: `docs/*` +Projects + - n8n Thesis Builder checkpoint (2026-01-04): `docs/n8n-thesis-builder-checkpoint-20260104.md` + - llamaCpp wrapper: A Python-based OpenAI-compatible API wrapper and model manager for the TrueNAS llama.cpp app. + - Location: `llamaCpp.Wrapper.app/` + - API Port: `9093` + - UI Port: `9094` + - See the `README.md` inside the folder for full details. diff --git a/README.md b/README.md new file mode 100644 index 0000000..3ea198e --- /dev/null +++ b/README.md @@ -0,0 +1,69 @@ +# Codex TrueNAS Helper + +This project is a collection of scripts, configurations, and applications to manage and enhance a TrueNAS SCALE server, with a special focus on running and interacting with large language models (LLMs) like those powered by `llama.cpp` and `Ollama`. + +## Features + +* **`llama.cpp` Wrapper:** A sophisticated wrapper for the `llama.cpp` TrueNAS application that provides: + * An OpenAI-compatible API for chat completions and embeddings. + * A web-based UI for managing models (listing, downloading). + * The ability to hot-swap models without restarting the `llama.cpp` container by interacting with the TrueNAS API. +* **TrueNAS Inventory:** A snapshot of the TrueNAS server's configuration, including hardware, storage, networking, and running applications. +* **Automation Scripts:** A set of PowerShell and Python scripts for tasks like deploying the wrapper and testing remote endpoints. +* **LLM Integration:** Tools and configurations for working with various LLMs. + +## Directory Structure + +* `AGENTS.md` & `AGENTS.full.md`: These files contain detailed information and a complete inventory of the TrueNAS server's configuration. +* `llamaCpp.Wrapper.app/`: A Python-based application that wraps the `llama.cpp` TrueNAS app with an OpenAI-compatible API and a model management UI. +* `scripts/`: Contains various scripts for deployment, testing, and other tasks. +* `inventory_raw/`: Raw data dumps from the TrueNAS server, used to generate the inventory in `AGENTS.full.md`. +* `reports/`: Contains generated reports, test results, and other artifacts. +* `llamacpp_runs_remote/` & `ollama_runs_remote/`: Logs and results from running LLMs. +* `modelfiles/`: Modelfiles for different language models. +* `tests/`: Python tests for the `llamaCpp.Wrapper.app`. + +## `llamaCpp.Wrapper.app` + +This is the core component of the project. It's a Python application that acts as a proxy to the `llama.cpp` server running on TrueNAS, but with added features. + +### Running Locally + +1. Install the required Python packages: + ```bash + pip install -r llamaCpp.Wrapper.app/requirements.txt + ``` +2. Run the application: + ```bash + python -m llamaCpp.Wrapper.app.run + ``` + This will start two web servers: one for the API (default port 9093) and one for the UI (default port 9094). + +### Docker (TrueNAS) + +The wrapper can be run as a Docker container on TrueNAS. See the `llamaCpp.Wrapper.app/README.md` file for a detailed example of the `docker run` command. The wrapper needs to be configured with the appropriate environment variables to connect to the TrueNAS API and the `llama.cpp` container. + +### Model Hot-Swapping + +The wrapper can switch models in the `llama.cpp` server by updating the application's command via the TrueNAS API. This is a powerful feature that allows for dynamic model management without manual intervention. + +## Scripts + +* `deploy_truenas_wrapper.py`: A Python script to deploy the `llamaCpp.Wrapper.app` to TrueNAS. +* `remote_wrapper_test.py`: A Python script for testing the remote wrapper. +* `update_llamacpp_flags.ps1`: A PowerShell script to update the `llama.cpp` flags. +* `llamacpp_remote_test.ps1` & `ollama_remote_test.ps1`: PowerShell scripts for testing `llama.cpp` and `Ollama` remote endpoints. + +## Getting Started + +1. **Explore the Inventory:** Start by reading `AGENTS.md` and `AGENTS.full.md` to understand the TrueNAS server's configuration. +2. **Set up the Wrapper:** If you want to use the `llama.cpp` wrapper, follow the instructions in `llamaCpp.Wrapper.app/README.md` to run it either locally or as a Docker container on TrueNAS. +3. **Use the Scripts:** The scripts in the `scripts` directory can be used to automate various tasks. + +## Development + +The `llamaCpp.Wrapper.app` has a suite of tests located in the `tests/` directory. To run the tests, use `pytest`: + +```bash +pytest +``` diff --git a/docs/llamacpp-wrapper-notes.md b/docs/llamacpp-wrapper-notes.md new file mode 100644 index 0000000..9f1c9bc --- /dev/null +++ b/docs/llamacpp-wrapper-notes.md @@ -0,0 +1,60 @@ +# llama.cpp Wrapper Notes + +Last updated: 2026-01-04 + +## Purpose +OpenAI-compatible wrapper for the existing `llamacpp` app with a model manager UI, +model switching, and parameter management via TrueNAS middleware. + +## Deployed Image +- `rushabhtechie/llamacpp-wrapper-rushg-d:20260104-112221` + +## Ports (current) +- API (pinned): `http://192.168.1.2:9093` +- UI (pinned): `http://192.168.1.2:9094` +- llama.cpp native: `http://192.168.1.2:8071` + +## Key Behaviors +- Model switching uses TrueNAS middleware `app.update` to update `--model`. +- `--device` flag is explicitly removed because it crashes llama.cpp on this host. +- UI shows active model and supports switching with verification prompt. +- UI auto-refreshes on download progress and on llama.cpp model changes (SSE). +- UI allows editing llama.cpp command parameters (ctx-size, temp, top-k/p, etc.). +- UI supports dark theme toggle (persisted in localStorage). +- UI streams llama.cpp logs via Docker socket fallback when TrueNAS log APIs are unavailable. + +## Tools Support (n8n/OpenWebUI) +- Incoming `tools` in flat format (`{type,name,parameters}`) are normalized to + OpenAI format (`{type:"function", function:{...}}`) before proxying to llama.cpp. +- Legacy `functions` payloads are normalized into `tools`. +- `tool_choice` is normalized to OpenAI format as well. +- `return_format=json` is supported (falls back to JSON-only system prompt if llama.cpp rejects `response_format`). + +## Model Resolution +- Exact string match only (with optional explicit alias mapping). +- Requests that do not exactly match a listed model return `404`. + +## Parameters UI +- Endpoint: `GET /ui/api/llamacpp-config` (active model + params + extra args) +- Endpoint: `POST /ui/api/llamacpp-config` (updates command flags + extra args) + +## Model Switch UI +- Endpoint: `POST /ui/api/switch-model` with `{ "model_id": "..." }` +- Verifies switch by sending a minimal prompt. + +## Tests +- Remote functional tests: `tests/test_remote_wrapper.py` (chat/responses/tools/JSON mode, model switch, logs, multi-GPU flags). +- UI checks: `tests/test_ui.py` (UI elements, assets, theme toggle wiring). +- Run with env vars: + - `WRAPPER_BASE=http://192.168.1.2:9093` + - `UI_BASE=http://192.168.1.2:9094` + - `TRUENAS_WS_URL=wss://192.168.1.2/websocket` + - `TRUENAS_API_KEY=...` + - `MODEL_REQUEST=` + +## Runtime Validation (2026-01-04) +- Fixed llama.cpp init failure by enabling `--flash-attn on` (required with KV cache quantization). +- Confirmed TinyLlama loads and answers prompts with `return_format=json`. +- Switched via UI to `Qwen2.5-7B-Instruct-Q4_K_M.gguf` and validated prompt success. +- Expect transient `503 Loading model` during warmup; retry after load completes. + - Verified `yarn-llama-2-13b-64k.Q4_K_M.gguf` model switch from wrapper and a tool-enabled chat request completes after load (took ~107s). diff --git a/docs/n8n-thesis-builder-checkpoint-20260104.md b/docs/n8n-thesis-builder-checkpoint-20260104.md new file mode 100644 index 0000000..90953f4 --- /dev/null +++ b/docs/n8n-thesis-builder-checkpoint-20260104.md @@ -0,0 +1,53 @@ +# n8n Thesis Builder Debug Checkpoint (2026-01-04) + +## Summary +- Workflow: `Options recommendation Engine Core LOCAL v2` (id `Nupt4vBG82JKFoGc`). +- Primary issue: `AI - Thesis Builder` returns garbled output even when workflow succeeds. +- Confirmed execution with garbled output: execution `7890` (status `success`). + +## What changed in the workflow +Only this workflow was modified: +- `Code in JavaScript9` now pulls `symbol` from `Code7` (trigger) instead of AI output. +- `HTTP Request13` query forced to the stock symbol to avoid NewsAPI query-length errors. +- `Trim Thesis Data` node inserted between `Aggregate2` -> `AI - Thesis Builder`. +- `AI - Thesis Builder` prompt simplified to only: symbol, price, news, technicals. +- `Code10` now caps news items and string length. + +## Last successful run details (execution 7890) +- `AI - Thesis Builder` output is garbled (example `symbol` and `thesis` fields full of junk tokens). +- `AI - Technicals Auditor` output looks valid JSON (see sample below). +- `Aggregate2` payload size ~6.7KB; `news` ~859 chars; `tech` ~1231 chars; `thesis_prompt` ~4448 chars. +- Garbling persists despite trimming input size; likely model/wrapper settings or response format handling. + +### Sample `AI - Thesis Builder` output (garbled) +- symbol: `6097ig5ear18etymac3ofy4ppystugamp2llcashackicset0ovagates-hstt.20t*6fthm--offate9noptooth(2ccods+5ing, or 7ACYntat?9ur);8ot1ut` +- thesis: (junk tokens, mostly non-words) +- confidence: `0` + +### Sample `AI - Technicals Auditor` output (valid JSON) +``` +{ + "output": { + "timeframes": [ + { "interval": "1m", "valid": true, "features": { "trend": "BEARISH" } }, + { "interval": "5m", "valid": true, "features": { "trend": "BEARISH" } }, + { "interval": "15m", "valid": true, "features": { "trend": "BEARISH" } }, + { "interval": "1h", "valid": true, "features": { "trend": "BULLISH" } } + ], + "optionsRegime": { "priceRegime": "TRENDING", "volRegime": "EXPANDING", "nearTermSensitivity": "HIGH" }, + "dataQualityScore": 0.5, + "error": "INSUFFICIENT_DATA" + } +} +``` + +## Open issues +- Thesis Builder garbling persists even with small prompt; likely model/wrapper output issue. +- Need to confirm whether llama.cpp wrapper is corrupting output or model is misconfigured for JSON-only output. + +## Useful commands +- Last runs: + `SELECT id, status, finished, "startedAt" FROM execution_entity WHERE "workflowId"='Nupt4vBG82JKFoGc' ORDER BY "startedAt" DESC LIMIT 5;` +- Export workflow: + `sudo docker exec ix-n8n-n8n-1 n8n export:workflow --id Nupt4vBG82JKFoGc --output /tmp/n8n_local_v2.json` + diff --git a/llamaCpp.Wrapper.app/Dockerfile b/llamaCpp.Wrapper.app/Dockerfile new file mode 100644 index 0000000..ce8ab15 --- /dev/null +++ b/llamaCpp.Wrapper.app/Dockerfile @@ -0,0 +1,16 @@ +FROM python:3.11-slim + +ENV PYTHONDONTWRITEBYTECODE=1 \ + PYTHONUNBUFFERED=1 + +WORKDIR /app + +COPY requirements.txt /app/requirements.txt +RUN pip install --no-cache-dir -r /app/requirements.txt + +COPY app /app/app +COPY trades_company_stock.txt /app/trades_company_stock.txt + +EXPOSE 8000 8001 + +CMD ["python", "-m", "app.run"] diff --git a/llamaCpp.Wrapper.app/README.md b/llamaCpp.Wrapper.app/README.md new file mode 100644 index 0000000..99f7ecd --- /dev/null +++ b/llamaCpp.Wrapper.app/README.md @@ -0,0 +1,134 @@ +# llama.cpp OpenAI-Compatible Wrapper + +This project wraps the existing llama.cpp TrueNAS app with OpenAI-compatible endpoints and a model management UI. +The wrapper reads deployment details from `AGENTS.md` (build-time) into `app/agents_config.json`. + +## Current Agents-Derived Details + +- llama.cpp image: `ghcr.io/ggml-org/llama.cpp:server-cuda` +- Host port: `8071` -> container port `8080` +- Model mount: `/mnt/fast.storage.rushg.me/datasets/apps/llama-cpp.models` -> `/models` +- Network: `ix-llamacpp_default` +- Container name: `ix-llamacpp-llamacpp-1` +- GPUs: 2x NVIDIA RTX 5060 Ti (from AGENTS snapshot) + +Regenerate the derived config after updating `AGENTS.md`: + +```bash +python app/agents_parser.py --agents AGENTS.md --out app/agents_config.json +``` + +## Running Locally + +```bash +python -m venv .venv +. .venv/bin/activate +pip install -r requirements.txt +python -m app.run +``` + +Defaults: +- API: `PORT_A=9093` +- UI: `PORT_B=9094` +- Base URL: `LLAMACPP_BASE_URL` (defaults to container name or localhost based on agents config) +- Model dir: `MODEL_DIR=/models` + +## Docker (TrueNAS) + +Example (join existing llama.cpp network and mount models): + +```bash +docker run --rm -p 9093:9093 -p 9094:9094 \ + --network ix-llamacpp_default \ + -v /mnt/fast.storage.rushg.me/datasets/apps/llama-cpp.models:/models \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -e LLAMACPP_RESTART_METHOD=docker \ + -e LLAMACPP_RESTART_COMMAND=ix-llamacpp-llamacpp-1 \ + -e LLAMACPP_TARGET_CONTAINER=ix-llamacpp-llamacpp-1 \ + -e TRUENAS_WS_URL=ws://192.168.1.2/websocket \ + -e TRUENAS_API_KEY=YOUR_KEY \ + -e TRUENAS_API_USER=YOUR_USER \ + -e TRUENAS_APP_NAME=llamacpp \ + -e LLAMACPP_BASE_URL=http://ix-llamacpp-llamacpp-1:8080 \ + -e PORT_A=9093 -e PORT_B=9094 \ + llama-cpp-openai-wrapper:latest +``` + +## Model Hot-Swap / Restart Hooks + +This wrapper does not modify llama.cpp by default. To enable hot-swap/restart for new models or model selection, +provide one of the restart methods below: + +- `LLAMACPP_RESTART_METHOD=http` +- `LLAMACPP_RESTART_URL=http://host-or-helper/restart` + +or + +- `LLAMACPP_RESTART_METHOD=shell` +- `LLAMACPP_RESTART_COMMAND="/usr/local/bin/your-restart-script --arg"` + +or (requires mounting docker socket) + +- `LLAMACPP_RESTART_METHOD=docker` +- `LLAMACPP_RESTART_COMMAND=ix-llamacpp-llamacpp-1` + +## Model switching via TrueNAS middleware (P0) + +Provide TrueNAS API credentials so the wrapper can update the llama.cpp app command when a new model is selected: + +``` +TRUENAS_WS_URL=ws://192.168.1.2/websocket +TRUENAS_API_KEY=YOUR_KEY +TRUENAS_API_USER=YOUR_USER +TRUENAS_APP_NAME=llamacpp +TRUENAS_VERIFY_SSL=false +``` + +The wrapper preserves existing flags in the compose command and only updates `--model`, while optionally adding +missing GPU split flags from `LLAMACPP_*` if not already set. + +Optional arguments passed to restart handlers: + +``` +LLAMACPP_DEVICES=0,1 +LLAMACPP_TENSOR_SPLIT=0.5,0.5 +LLAMACPP_SPLIT_MODE=layer +LLAMACPP_N_GPU_LAYERS=999 +LLAMACPP_CTX_SIZE=8192 +LLAMACPP_BATCH_SIZE=1024 +LLAMACPP_UBATCH_SIZE=256 +LLAMACPP_CACHE_TYPE_K=q4_0 +LLAMACPP_CACHE_TYPE_V=q4_0 +LLAMACPP_FLASH_ATTN=on +``` + +You can also pass arbitrary llama.cpp flags (space-separated) via: + +``` +LLAMACPP_EXTRA_ARGS="--mlock --no-mmap --rope-scaling linear" +``` + +## Model Manager UI + +Open `http://HOST:PORT_B/`. + +Features: +- List existing models +- Download models via URL +- Live progress + cancel + +## Testing + +Tests are parameterized with 100+ cases per endpoint. + +```bash +pytest -q +``` + +## llama.cpp flags reference + +Scraped from upstream docs into `reports/llamacpp_docs.md` and `reports/llamacpp_flags.txt`. + +``` +pwsh scripts/update_llamacpp_flags.ps1 +``` diff --git a/llamaCpp.Wrapper.app/__init__.py b/llamaCpp.Wrapper.app/__init__.py new file mode 100644 index 0000000..e02abfc --- /dev/null +++ b/llamaCpp.Wrapper.app/__init__.py @@ -0,0 +1 @@ + diff --git a/llamaCpp.Wrapper.app/agents_config.json b/llamaCpp.Wrapper.app/agents_config.json new file mode 100644 index 0000000..e30afa7 --- /dev/null +++ b/llamaCpp.Wrapper.app/agents_config.json @@ -0,0 +1,22 @@ +{ + "image": "ghcr.io/ggml-org/llama.cpp:server-cuda", + "container_name": "ix-llamacpp-llamacpp-1", + "host_port": 8071, + "container_port": 8080, + "web_ui_url": "http://0.0.0.0:8071/", + "model_host_path": "/mnt/fast.storage.rushg.me/datasets/apps/llama-cpp.models", + "model_container_path": "/models", + "models": [ + "GPT-OSS", + "Meta-Llama-3-8B-Instruct.Q4_K_M.gguf", + "openassistant-llama2-13b-orca-8k-3319.Q5_K_M.gguf", + "Meta-Llama-3.1-8B-Instruct-Q4_K_M.gguf" + ], + "network": "ix-llamacpp_default", + "subnets": [ + "172.16.18.0/24", + "fdb7:86ec:b1dd:11::/64" + ], + "gpu_count": 2, + "gpu_name": "NVIDIA RTX 5060 Ti, 16 GB each (per `nvidia-smi` in prior runs)." +} \ No newline at end of file diff --git a/llamaCpp.Wrapper.app/agents_parser.py b/llamaCpp.Wrapper.app/agents_parser.py new file mode 100644 index 0000000..9154f0b --- /dev/null +++ b/llamaCpp.Wrapper.app/agents_parser.py @@ -0,0 +1,119 @@ +import json +import re +from dataclasses import dataclass, asdict +from pathlib import Path +from typing import List, Optional + +APP_HEADER_RE = re.compile(r"^### App: (?P.+?)\s*$") +IMAGE_RE = re.compile(r"image=(?P[^\s]+)") +PORT_MAP_RE = re.compile(r"- tcp (?P\d+) -> (?P\d+|0\.0\.0\.0:(?P\d+))") +PORT_LINE_RE = re.compile(r"- tcp (?P\d+) -> (?P[^:]+):(?P\d+)") +VOLUME_RE = re.compile(r"- (?P/[^\s]+) -> (?P/[^\s]+)") +NETWORK_RE = re.compile(r"- (?Pix-[^\s]+)_default") +SUBNET_RE = re.compile(r"subnets=\[(?P[^\]]+)\]") +MODELS_RE = re.compile(r"Models in /models: (?P.+)$") +PORTAL_RE = re.compile(r"Portals: \{\'Web UI\': \'(?P[^\']+)\'\}") +GPU_RE = re.compile(r"GPUs:\s*(?P\d+)x\s*(?P.+)$") +CONTAINER_NAME_RE = re.compile(r"^(?Pix-llamacpp-[^\s]+)") + +@dataclass +class LlamacppConfig: + image: Optional[str] = None + container_name: Optional[str] = None + host_port: Optional[int] = None + container_port: Optional[int] = None + web_ui_url: Optional[str] = None + model_host_path: Optional[str] = None + model_container_path: Optional[str] = None + models: List[str] = None + network: Optional[str] = None + subnets: List[str] = None + gpu_count: Optional[int] = None + gpu_name: Optional[str] = None + + +def _find_section(lines: List[str], app_name: str) -> List[str]: + start = None + for i, line in enumerate(lines): + m = APP_HEADER_RE.match(line.strip()) + if m and m.group("name") == app_name: + start = i + break + if start is None: + return [] + for j in range(start + 1, len(lines)): + if APP_HEADER_RE.match(lines[j].strip()): + return lines[start:j] + return lines[start:] + + +def parse_agents(path: Path) -> LlamacppConfig: + text = path.read_text(encoding="utf-8", errors="ignore") + lines = text.splitlines() + section = _find_section(lines, "llamacpp") + cfg = LlamacppConfig(models=[], subnets=[]) + + for line in section: + if cfg.image is None: + m = IMAGE_RE.search(line) + if m: + cfg.image = m.group("image") + if cfg.web_ui_url is None: + m = PORTAL_RE.search(line) + if m: + cfg.web_ui_url = m.group("url") + if cfg.container_port is None or cfg.host_port is None: + m = PORT_LINE_RE.search(line) + if m: + cfg.container_port = int(m.group("container")) + cfg.host_port = int(m.group("host")) + if cfg.model_host_path is None or cfg.model_container_path is None: + m = VOLUME_RE.search(line) + if m and "/models" in m.group("container"): + cfg.model_host_path = m.group("host") + cfg.model_container_path = m.group("container") + if cfg.network is None: + m = NETWORK_RE.search(line) + if m: + cfg.network = f"{m.group('name')}_default" + if "subnets=" in line: + m = SUBNET_RE.search(line) + if m: + subnets_raw = m.group("subnets") + subnets = [s.strip().strip("'") for s in subnets_raw.split(",")] + cfg.subnets.extend([s for s in subnets if s]) + if "Models in /models:" in line: + m = MODELS_RE.search(line) + if m: + models_raw = m.group("models") + cfg.models = [s.strip() for s in models_raw.split(",") if s.strip()] + + for line in lines: + if cfg.gpu_count is None: + m = GPU_RE.search(line) + if m: + cfg.gpu_count = int(m.group("count")) + cfg.gpu_name = m.group("name").strip() + if cfg.container_name is None: + m = CONTAINER_NAME_RE.match(line.strip()) + if m: + cfg.container_name = m.group("name") + + return cfg + + +def main() -> None: + import argparse + parser = argparse.ArgumentParser() + parser.add_argument("--agents", default="AGENTS.md") + parser.add_argument("--out", default="app/agents_config.json") + args = parser.parse_args() + + cfg = parse_agents(Path(args.agents)) + out_path = Path(args.out) + out_path.parent.mkdir(parents=True, exist_ok=True) + out_path.write_text(json.dumps(asdict(cfg), indent=2), encoding="utf-8") + + +if __name__ == "__main__": + main() diff --git a/llamaCpp.Wrapper.app/api_app.py b/llamaCpp.Wrapper.app/api_app.py new file mode 100644 index 0000000..30afc5a --- /dev/null +++ b/llamaCpp.Wrapper.app/api_app.py @@ -0,0 +1,309 @@ +import asyncio +import logging +import time +from pathlib import Path +from typing import Any, Dict + +from fastapi import APIRouter, FastAPI, HTTPException, Request, Response +from fastapi.responses import JSONResponse, StreamingResponse +import httpx + +from app.config import load_config +from app.llamacpp_client import proxy_json, proxy_raw, proxy_stream +from app.logging_utils import configure_logging +from app.model_registry import find_model, resolve_model, scan_models +from app.openai_translate import responses_to_chat_payload, chat_to_responses, normalize_chat_payload +from app.restart import RestartPlan, trigger_restart +from app.stream_transform import stream_chat_to_responses +from app.truenas_middleware import TrueNASConfig, get_active_model_id, switch_model +from app.warmup import resolve_warmup_prompt, run_warmup_with_retry + + +configure_logging() +log = logging.getLogger("api_app") + + +def _model_list_payload(model_dir: str) -> Dict[str, Any]: + data = [] + for model in scan_models(model_dir): + data.append({ + "id": model.model_id, + "object": "model", + "created": model.created, + "owned_by": "llama.cpp", + }) + return {"object": "list", "data": data} + + +def _requires_json_mode(payload: Dict[str, Any]) -> bool: + response_format = payload.get("response_format") + if isinstance(response_format, dict) and response_format.get("type") == "json_object": + return True + if payload.get("return_format") == "json": + return True + return False + + +def _apply_json_fallback(payload: Dict[str, Any]) -> Dict[str, Any]: + payload = dict(payload) + payload.pop("response_format", None) + payload.pop("return_format", None) + messages = payload.get("messages") + if isinstance(messages, list): + system_msg = {"role": "system", "content": "Respond only with a valid JSON object."} + if not messages or messages[0].get("role") != "system": + payload["messages"] = [system_msg, *messages] + else: + payload["messages"] = [system_msg, *messages[1:]] + return payload + + +async def _proxy_json_with_retry( + base_url: str, + path: str, + method: str, + headers: Dict[str, str], + payload: Dict[str, Any], + timeout_s: float, + delay_s: float = 3.0, +) -> httpx.Response: + deadline = time.time() + timeout_s + attempt = 0 + last_exc: Exception | None = None + while time.time() < deadline: + attempt += 1 + try: + resp = await proxy_json(base_url, path, method, headers, payload, timeout_s) + if resp.status_code == 503: + try: + data = resp.json() + except Exception: + data = {} + message = "" + if isinstance(data, dict): + err = data.get("error") + if isinstance(err, dict): + message = str(err.get("message") or "") + else: + message = str(data.get("message") or "") + if "loading model" in message.lower(): + log.warning("llama.cpp still loading model, retrying (attempt %s)", attempt) + await asyncio.sleep(delay_s) + continue + return resp + except httpx.RequestError as exc: + last_exc = exc + log.warning("Proxy request failed (attempt %s): %s", attempt, exc) + await asyncio.sleep(delay_s) + if last_exc: + raise last_exc + raise RuntimeError("proxy retry deadline exceeded") + + +async def _get_active_model_from_truenas(cfg: TrueNASConfig) -> str: + try: + return await get_active_model_id(cfg) + except Exception as exc: + log.warning("Failed to read active model from TrueNAS config: %s", exc) + return "" + + +async def _wait_for_active_model(cfg: TrueNASConfig, model_id: str, timeout_s: float) -> None: + deadline = asyncio.get_event_loop().time() + timeout_s + while asyncio.get_event_loop().time() < deadline: + active = await _get_active_model_from_truenas(cfg) + if active == model_id: + return + await asyncio.sleep(2) + raise RuntimeError(f"active model did not switch to {model_id}") + + +async def _ensure_model_loaded(model_id: str, model_dir: str) -> str: + cfg = load_config() + model = resolve_model(model_dir, model_id, cfg.model_aliases) + if not model: + log.warning("Requested model not found: %s", model_id) + raise HTTPException(status_code=404, detail="model not found") + if model.model_id != model_id: + log.info("Resolved model alias %s -> %s", model_id, model.model_id) + + truenas_cfg = None + if cfg.truenas_ws_url and cfg.truenas_api_key: + truenas_cfg = TrueNASConfig( + ws_url=cfg.truenas_ws_url, + api_key=cfg.truenas_api_key, + api_user=cfg.truenas_api_user, + app_name=cfg.truenas_app_name, + verify_ssl=cfg.truenas_verify_ssl, + ) + active_id = await _get_active_model_from_truenas(truenas_cfg) + if active_id and active_id == model.model_id: + return model.model_id + + if truenas_cfg: + log.info("Switching model via API model=%s args=%s extra_args=%s", model.model_id, cfg.llamacpp_args, cfg.llamacpp_extra_args) + try: + model_path = str((Path(cfg.model_container_dir) / model.model_id)) + await switch_model( + truenas_cfg, + model_path, + cfg.llamacpp_args, + cfg.llamacpp_extra_args, + ) + await _wait_for_active_model(truenas_cfg, model.model_id, cfg.switch_timeout_s) + except Exception as exc: + log.exception("TrueNAS model switch failed") + raise HTTPException(status_code=500, detail=f"model switch failed: {exc}") + warmup_prompt = resolve_warmup_prompt(None, cfg.warmup_prompt_path) + log.info("Running warmup prompt after model switch: model=%s prompt_len=%s", model.model_id, len(warmup_prompt)) + await run_warmup_with_retry(cfg.base_url, model.model_id, warmup_prompt, timeout_s=cfg.switch_timeout_s) + return model.model_id + + plan = RestartPlan( + method=cfg.restart_method, + command=cfg.restart_command, + url=cfg.restart_url, + allowed_container=cfg.allowed_container, + ) + log.info("Triggering restart for model=%s method=%s", model.model_id, cfg.restart_method) + payload = { + "model_id": model.model_id, + "model_path": str(Path(cfg.model_container_dir) / model.model_id), + "gpu_count": cfg.gpu_count_runtime or cfg.agents.gpu_count, + "llamacpp_args": cfg.llamacpp_args, + "llamacpp_extra_args": cfg.llamacpp_extra_args, + } + await trigger_restart(plan, payload=payload) + warmup_prompt = resolve_warmup_prompt(None, cfg.warmup_prompt_path) + log.info("Running warmup prompt after restart: model=%s prompt_len=%s", model.model_id, len(warmup_prompt)) + await run_warmup_with_retry(cfg.base_url, model.model_id, warmup_prompt, timeout_s=cfg.switch_timeout_s) + return model.model_id + + +def create_api_app() -> FastAPI: + cfg = load_config() + app = FastAPI(title="llama.cpp OpenAI Wrapper", version="0.1.0") + router = APIRouter() + + @app.middleware("http") + async def log_requests(request: Request, call_next): + log.info("Request %s %s", request.method, request.url.path) + return await call_next(request) + + @app.exception_handler(Exception) + async def unhandled_exception_handler(request: Request, exc: Exception) -> JSONResponse: + log.exception("Unhandled error") + return JSONResponse(status_code=500, content={"detail": str(exc)}) + + @router.get("/health") + async def health() -> Dict[str, Any]: + return { + "status": "ok", + "base_url": cfg.base_url, + "model_dir": cfg.model_dir, + "agents": { + "image": cfg.agents.image, + "container_name": cfg.agents.container_name, + "network": cfg.agents.network, + "gpu_count": cfg.agents.gpu_count, + }, + "gpu_count_runtime": cfg.gpu_count_runtime, + } + + @router.get("/v1/models") + async def list_models() -> Dict[str, Any]: + log.info("Listing models") + return _model_list_payload(cfg.model_dir) + + @router.get("/v1/models/{model_id}") + async def get_model(model_id: str) -> Dict[str, Any]: + log.info("Get model %s", model_id) + model = resolve_model(cfg.model_dir, model_id, cfg.model_aliases) or find_model(cfg.model_dir, model_id) + if not model: + raise HTTPException(status_code=404, detail="model not found") + return { + "id": model.model_id, + "object": "model", + "created": model.created, + "owned_by": "llama.cpp", + } + + @router.post("/v1/chat/completions") + async def chat_completions(request: Request) -> Response: + payload = await request.json() + payload = normalize_chat_payload(payload) + model_id = payload.get("model") + log.info("Chat completions model=%s stream=%s", model_id, bool(payload.get("stream"))) + if model_id: + resolved = await _ensure_model_loaded(model_id, cfg.model_dir) + payload["model"] = resolved + stream = bool(payload.get("stream")) + if stream and _requires_json_mode(payload): + payload = _apply_json_fallback(payload) + if stream: + streamer = proxy_stream(cfg.base_url, "/v1/chat/completions", "POST", dict(request.headers), payload, cfg.proxy_timeout_s) + return StreamingResponse(streamer, media_type="text/event-stream") + resp = await _proxy_json_with_retry(cfg.base_url, "/v1/chat/completions", "POST", dict(request.headers), payload, cfg.proxy_timeout_s) + if resp.status_code >= 500 and _requires_json_mode(payload): + log.info("Retrying chat completion with JSON fallback prompt") + fallback_payload = _apply_json_fallback(payload) + resp = await _proxy_json_with_retry(cfg.base_url, "/v1/chat/completions", "POST", dict(request.headers), fallback_payload, cfg.proxy_timeout_s) + try: + return JSONResponse(status_code=resp.status_code, content=resp.json()) + except Exception: + return Response( + status_code=resp.status_code, + content=resp.content, + media_type=resp.headers.get("content-type"), + ) + + @router.post("/v1/responses") + async def responses(request: Request) -> Response: + payload = await request.json() + chat_payload, model_id = responses_to_chat_payload(payload) + log.info("Responses model=%s stream=%s", model_id, bool(chat_payload.get("stream"))) + if model_id: + resolved = await _ensure_model_loaded(model_id, cfg.model_dir) + chat_payload["model"] = resolved + stream = bool(chat_payload.get("stream")) + if stream and _requires_json_mode(chat_payload): + chat_payload = _apply_json_fallback(chat_payload) + if stream: + streamer = stream_chat_to_responses( + cfg.base_url, + dict(request.headers), + chat_payload, + cfg.proxy_timeout_s, + ) + return StreamingResponse(streamer, media_type="text/event-stream") + resp = await _proxy_json_with_retry(cfg.base_url, "/v1/chat/completions", "POST", dict(request.headers), chat_payload, cfg.proxy_timeout_s) + if resp.status_code >= 500 and _requires_json_mode(chat_payload): + log.info("Retrying responses with JSON fallback prompt") + fallback_payload = _apply_json_fallback(chat_payload) + resp = await _proxy_json_with_retry(cfg.base_url, "/v1/chat/completions", "POST", dict(request.headers), fallback_payload, cfg.proxy_timeout_s) + resp.raise_for_status() + return JSONResponse(status_code=200, content=chat_to_responses(resp.json(), model_id)) + + @router.post("/v1/embeddings") + async def embeddings(request: Request) -> Response: + payload = await request.json() + log.info("Embeddings") + resp = await _proxy_json_with_retry(cfg.base_url, "/v1/embeddings", "POST", dict(request.headers), payload, cfg.proxy_timeout_s) + try: + return JSONResponse(status_code=resp.status_code, content=resp.json()) + except Exception: + return Response( + status_code=resp.status_code, + content=resp.content, + media_type=resp.headers.get("content-type"), + ) + + @router.api_route("/proxy/llamacpp/{path:path}", methods=["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"]) + async def passthrough(path: str, request: Request) -> Response: + body = await request.body() + resp = await proxy_raw(cfg.base_url, f"/{path}", request.method, dict(request.headers), body, cfg.proxy_timeout_s) + return Response(status_code=resp.status_code, content=resp.content, headers=dict(resp.headers)) + + app.include_router(router) + return app + diff --git a/llamaCpp.Wrapper.app/config.py b/llamaCpp.Wrapper.app/config.py new file mode 100644 index 0000000..eaeda2e --- /dev/null +++ b/llamaCpp.Wrapper.app/config.py @@ -0,0 +1,214 @@ +import json +import os +from dataclasses import dataclass +from pathlib import Path +from typing import Dict, List, Optional + + +@dataclass +class AgentsRuntime: + image: Optional[str] + container_name: Optional[str] + host_port: Optional[int] + container_port: Optional[int] + web_ui_url: Optional[str] + model_host_path: Optional[str] + model_container_path: Optional[str] + models: List[str] + network: Optional[str] + subnets: List[str] + gpu_count: Optional[int] + gpu_name: Optional[str] + + +@dataclass +class AppConfig: + api_port: int + ui_port: int + base_url: str + model_dir: str + model_container_dir: str + download_dir: str + download_max_concurrent: int + download_allowlist: List[str] + restart_method: str + restart_command: Optional[str] + restart_url: Optional[str] + reload_on_new_model: bool + proxy_timeout_s: float + switch_timeout_s: float + gpu_count_runtime: Optional[int] + llamacpp_args: Dict[str, str] + llamacpp_extra_args: str + truenas_api_key: Optional[str] + truenas_api_user: Optional[str] + truenas_app_name: str + truenas_ws_url: Optional[str] + truenas_verify_ssl: bool + allowed_container: Optional[str] + warmup_prompt_path: str + llamacpp_container_name: Optional[str] + model_aliases: Dict[str, str] + agents: AgentsRuntime + + +def _load_agents_config(path: Path) -> AgentsRuntime: + if not path.exists(): + return AgentsRuntime( + image=None, + container_name=None, + host_port=None, + container_port=None, + web_ui_url=None, + model_host_path=None, + model_container_path=None, + models=[], + network=None, + subnets=[], + gpu_count=None, + gpu_name=None, + ) + raw = json.loads(path.read_text(encoding="utf-8")) + return AgentsRuntime( + image=raw.get("image"), + container_name=raw.get("container_name"), + host_port=raw.get("host_port"), + container_port=raw.get("container_port"), + web_ui_url=raw.get("web_ui_url"), + model_host_path=raw.get("model_host_path"), + model_container_path=raw.get("model_container_path"), + models=raw.get("models") or [], + network=raw.get("network"), + subnets=raw.get("subnets") or [], + gpu_count=raw.get("gpu_count"), + gpu_name=raw.get("gpu_name"), + ) + + +def _infer_gpu_count_runtime() -> Optional[int]: + visible = os.getenv("CUDA_VISIBLE_DEVICES") or os.getenv("NVIDIA_VISIBLE_DEVICES") + if visible and visible not in {"all", "void"}: + parts = [p.strip() for p in visible.split(",") if p.strip()] + if parts: + return len(parts) + return None + + +def _default_base_url(agents: AgentsRuntime) -> str: + if agents.container_name and agents.container_port: + return f"http://{agents.container_name}:{agents.container_port}" + if agents.host_port: + return f"http://127.0.0.1:{agents.host_port}" + return "http://127.0.0.1:8080" + + +def load_config() -> AppConfig: + agents_path = Path(os.getenv("AGENTS_CONFIG_PATH", "app/agents_config.json")) + agents = _load_agents_config(agents_path) + + api_port = int(os.getenv("PORT_A", "9093")) + ui_port = int(os.getenv("PORT_B", "9094")) + + base_url = os.getenv("LLAMACPP_BASE_URL") or _default_base_url(agents) + model_dir = os.getenv("MODEL_DIR") or agents.model_container_path or "/models" + model_container_dir = os.getenv("MODEL_CONTAINER_DIR") or model_dir + + download_dir = os.getenv("MODEL_DOWNLOAD_DIR") or model_dir + download_max = int(os.getenv("MODEL_DOWNLOAD_MAX_CONCURRENT", "2")) + + allowlist_raw = os.getenv("MODEL_DOWNLOAD_ALLOWLIST", "") + allowlist = [item.strip() for item in allowlist_raw.split(",") if item.strip()] + + restart_method = os.getenv("LLAMACPP_RESTART_METHOD", "none").lower() + restart_command = os.getenv("LLAMACPP_RESTART_COMMAND") + restart_url = os.getenv("LLAMACPP_RESTART_URL") + + reload_on_new_model = os.getenv("RELOAD_ON_NEW_MODEL", "false").lower() in {"1", "true", "yes"} + proxy_timeout_s = float(os.getenv("LLAMACPP_PROXY_TIMEOUT_S", "600")) + switch_timeout_s = float(os.getenv("LLAMACPP_SWITCH_TIMEOUT_S", "300")) + + gpu_count_runtime = _infer_gpu_count_runtime() + + llamacpp_args = {} + args_map = { + "LLAMACPP_TENSOR_SPLIT": "tensor_split", + "LLAMACPP_SPLIT_MODE": "split_mode", + "LLAMACPP_N_GPU_LAYERS": "n_gpu_layers", + "LLAMACPP_CTX_SIZE": "ctx_size", + "LLAMACPP_BATCH_SIZE": "batch_size", + "LLAMACPP_UBATCH_SIZE": "ubatch_size", + "LLAMACPP_CACHE_TYPE_K": "cache_type_k", + "LLAMACPP_CACHE_TYPE_V": "cache_type_v", + "LLAMACPP_FLASH_ATTN": "flash_attn", + } + for env_key, arg_key in args_map.items(): + value = os.getenv(env_key) + if value is not None and value != "": + llamacpp_args[arg_key] = value + llamacpp_extra_args = os.getenv("LLAMACPP_EXTRA_ARGS", "") + + truenas_api_key = os.getenv("TRUENAS_API_KEY") + truenas_api_user = os.getenv("TRUENAS_API_USER") + truenas_app_name = os.getenv("TRUENAS_APP_NAME", "llamacpp") + truenas_ws_url = os.getenv("TRUENAS_WS_URL") + truenas_api_url = os.getenv("TRUENAS_API_URL") + if not truenas_ws_url and truenas_api_url: + if truenas_api_url.startswith("https://"): + truenas_ws_url = "wss://" + truenas_api_url[len("https://") :].rstrip("/") + "/websocket" + elif truenas_api_url.startswith("http://"): + truenas_ws_url = "ws://" + truenas_api_url[len("http://") :].rstrip("/") + "/websocket" + truenas_verify_ssl = os.getenv("TRUENAS_VERIFY_SSL", "false").lower() in {"1", "true", "yes"} + allowed_container = os.getenv("LLAMACPP_TARGET_CONTAINER") or agents.container_name + llamacpp_container_name = os.getenv("LLAMACPP_CONTAINER_NAME") or agents.container_name + warmup_prompt_path = os.getenv("WARMUP_PROMPT_PATH", str(Path("trades_company_stock.txt").resolve())) + if truenas_ws_url and (":" in model_container_dir[:3] or "\\" in model_container_dir): + model_container_dir = os.getenv("MODEL_CONTAINER_DIR") or "/models" + aliases_raw = os.getenv("MODEL_ALIASES", "") + model_aliases: Dict[str, str] = {} + if aliases_raw: + try: + model_aliases = json.loads(aliases_raw) + except json.JSONDecodeError: + for item in aliases_raw.split(","): + if "=" in item: + key, value = item.split("=", 1) + model_aliases[key.strip()] = value.strip() + + gpu_count = gpu_count_runtime or agents.gpu_count + if gpu_count and gpu_count >= 2: + if "tensor_split" not in llamacpp_args: + ratio = 1.0 / float(gpu_count) + split = ",".join([f"{ratio:.2f}"] * gpu_count) + llamacpp_args["tensor_split"] = split + if "split_mode" not in llamacpp_args: + llamacpp_args["split_mode"] = "layer" + + return AppConfig( + api_port=api_port, + ui_port=ui_port, + base_url=base_url, + model_dir=model_dir, + model_container_dir=model_container_dir, + download_dir=download_dir, + download_max_concurrent=download_max, + download_allowlist=allowlist, + restart_method=restart_method, + restart_command=restart_command, + restart_url=restart_url, + reload_on_new_model=reload_on_new_model, + proxy_timeout_s=proxy_timeout_s, + switch_timeout_s=switch_timeout_s, + gpu_count_runtime=gpu_count_runtime, + llamacpp_args=llamacpp_args, + llamacpp_extra_args=llamacpp_extra_args, + truenas_api_key=truenas_api_key, + truenas_api_user=truenas_api_user, + truenas_app_name=truenas_app_name, + truenas_ws_url=truenas_ws_url, + truenas_verify_ssl=truenas_verify_ssl, + allowed_container=allowed_container, + warmup_prompt_path=warmup_prompt_path, + llamacpp_container_name=llamacpp_container_name, + model_aliases=model_aliases, + agents=agents, + ) diff --git a/llamaCpp.Wrapper.app/docker_logs.py b/llamaCpp.Wrapper.app/docker_logs.py new file mode 100644 index 0000000..bf50ca9 --- /dev/null +++ b/llamaCpp.Wrapper.app/docker_logs.py @@ -0,0 +1,61 @@ +import json +import logging +import os +from typing import Optional + +import httpx + + +log = logging.getLogger("docker_logs") + + +def _docker_transport() -> httpx.AsyncHTTPTransport: + sock_path = os.getenv("DOCKER_SOCK", "/var/run/docker.sock") + return httpx.AsyncHTTPTransport(uds=sock_path) + + +async def _docker_get(path: str, params: Optional[dict] = None) -> httpx.Response: + timeout = httpx.Timeout(10.0, read=10.0) + async with httpx.AsyncClient(transport=_docker_transport(), base_url="http://docker", timeout=timeout) as client: + resp = await client.get(path, params=params) + resp.raise_for_status() + return resp + + +def _decode_docker_stream(data: bytes) -> str: + if not data: + return "" + out = bytearray() + idx = 0 + while idx + 8 <= len(data): + stream_type = data[idx] + size = int.from_bytes(data[idx + 4: idx + 8], "big") + idx += 8 + if idx + size > len(data): + break + chunk = data[idx: idx + size] + idx += size + if stream_type in (1, 2): + out.extend(chunk) + else: + out.extend(chunk) + if out: + return out.decode("utf-8", errors="replace") + return data.decode("utf-8", errors="replace") + + +async def docker_container_logs(container_name: str, tail_lines: int = 200) -> str: + filters = json.dumps({"name": [container_name]}) + resp = await _docker_get("/containers/json", params={"filters": filters}) + containers = resp.json() or [] + if not containers: + log.info("No docker container found for name=%s", container_name) + return "" + container_id = containers[0].get("Id") + if not container_id: + return "" + resp = await _docker_get( + f"/containers/{container_id}/logs", + params={"stdout": 1, "stderr": 1, "tail": tail_lines}, + ) + return _decode_docker_stream(resp.content) diff --git a/llamaCpp.Wrapper.app/download_manager.py b/llamaCpp.Wrapper.app/download_manager.py new file mode 100644 index 0000000..d61921c --- /dev/null +++ b/llamaCpp.Wrapper.app/download_manager.py @@ -0,0 +1,141 @@ +import asyncio +import fnmatch +import logging +import os +import time +import uuid +from dataclasses import asdict, dataclass, field +from pathlib import Path +from typing import Dict, Optional + +import httpx + +from app.config import AppConfig +from app.logging_utils import configure_logging +from app.restart import RestartPlan, trigger_restart + +configure_logging() +log = logging.getLogger("download_manager") + + +@dataclass +class DownloadStatus: + download_id: str + url: str + filename: str + status: str + bytes_total: Optional[int] = None + bytes_downloaded: int = 0 + started_at: float = field(default_factory=time.time) + finished_at: Optional[float] = None + error: Optional[str] = None + + +class DownloadManager: + def __init__(self, cfg: AppConfig, broadcaster=None) -> None: + self.cfg = cfg + self._downloads: Dict[str, DownloadStatus] = {} + self._tasks: Dict[str, asyncio.Task] = {} + self._semaphore = asyncio.Semaphore(cfg.download_max_concurrent) + self._broadcaster = broadcaster + + async def _emit(self, payload: dict) -> None: + if self._broadcaster: + await self._broadcaster.publish(payload) + + def list_downloads(self) -> Dict[str, dict]: + return {k: asdict(v) for k, v in self._downloads.items()} + + def get(self, download_id: str) -> Optional[DownloadStatus]: + return self._downloads.get(download_id) + + def _is_allowed(self, url: str) -> bool: + if not self.cfg.download_allowlist: + return True + return any(fnmatch.fnmatch(url, pattern) for pattern in self.cfg.download_allowlist) + + async def start(self, url: str, filename: Optional[str] = None) -> DownloadStatus: + if not self._is_allowed(url): + raise ValueError("url not allowed by allowlist") + if not filename: + filename = os.path.basename(url.split("?")[0]) or f"model-{uuid.uuid4().hex}.gguf" + log.info("Download requested url=%s filename=%s", url, filename) + download_id = uuid.uuid4().hex + status = DownloadStatus(download_id=download_id, url=url, filename=filename, status="queued") + self._downloads[download_id] = status + task = asyncio.create_task(self._run_download(status)) + self._tasks[download_id] = task + await self._emit({"type": "download_status", "download": asdict(status)}) + return status + + async def cancel(self, download_id: str) -> bool: + task = self._tasks.get(download_id) + if task: + task.cancel() + status = self._downloads.get(download_id) + if status: + log.info("Download cancelled id=%s filename=%s", download_id, status.filename) + await self._emit({"type": "download_status", "download": asdict(status)}) + return True + return False + + async def _run_download(self, status: DownloadStatus) -> None: + status.status = "downloading" + base = Path(self.cfg.download_dir) + base.mkdir(parents=True, exist_ok=True) + tmp_path = base / f".{status.filename}.partial" + final_path = base / status.filename + last_emit = 0.0 + + try: + async with self._semaphore: + async with httpx.AsyncClient(timeout=None, follow_redirects=True) as client: + async with client.stream("GET", status.url) as resp: + resp.raise_for_status() + length = resp.headers.get("content-length") + if length: + status.bytes_total = int(length) + with tmp_path.open("wb") as f: + async for chunk in resp.aiter_bytes(): + if chunk: + f.write(chunk) + status.bytes_downloaded += len(chunk) + now = time.time() + if now - last_emit >= 1: + last_emit = now + await self._emit({"type": "download_progress", "download": asdict(status)}) + if tmp_path.exists(): + tmp_path.replace(final_path) + status.status = "completed" + status.finished_at = time.time() + log.info("Download completed id=%s filename=%s", status.download_id, status.filename) + await self._emit({"type": "download_completed", "download": asdict(status)}) + if self.cfg.reload_on_new_model: + plan = RestartPlan( + method=self.cfg.restart_method, + command=self.cfg.restart_command, + url=self.cfg.restart_url, + allowed_container=self.cfg.allowed_container, + ) + await trigger_restart( + plan, + payload={ + "reason": "new_model", + "model_id": status.filename, + "llamacpp_args": self.cfg.llamacpp_args, + "llamacpp_extra_args": self.cfg.llamacpp_extra_args, + }, + ) + except asyncio.CancelledError: + status.status = "cancelled" + if tmp_path.exists(): + tmp_path.unlink(missing_ok=True) + log.info("Download cancelled id=%s filename=%s", status.download_id, status.filename) + await self._emit({"type": "download_cancelled", "download": asdict(status)}) + except Exception as exc: + status.status = "error" + status.error = str(exc) + if tmp_path.exists(): + tmp_path.unlink(missing_ok=True) + log.info("Download error id=%s filename=%s error=%s", status.download_id, status.filename, exc) + await self._emit({"type": "download_error", "download": asdict(status)}) diff --git a/llamaCpp.Wrapper.app/llamacpp_client.py b/llamaCpp.Wrapper.app/llamacpp_client.py new file mode 100644 index 0000000..38da9fa --- /dev/null +++ b/llamaCpp.Wrapper.app/llamacpp_client.py @@ -0,0 +1,52 @@ +import logging +from typing import AsyncIterator, Dict, Optional + +import httpx + + +log = logging.getLogger("llamacpp_client") + + +def _filter_headers(headers: Dict[str, str]) -> Dict[str, str]: + drop = {"host", "content-length"} + return {k: v for k, v in headers.items() if k.lower() not in drop} + + +async def proxy_json( + base_url: str, + path: str, + method: str, + headers: Dict[str, str], + payload: Optional[dict], + timeout_s: float, +) -> httpx.Response: + async with httpx.AsyncClient(base_url=base_url, timeout=timeout_s) as client: + return await client.request(method, path, headers=_filter_headers(headers), json=payload) + + +async def proxy_raw( + base_url: str, + path: str, + method: str, + headers: Dict[str, str], + body: Optional[bytes], + timeout_s: float, +) -> httpx.Response: + async with httpx.AsyncClient(base_url=base_url, timeout=timeout_s) as client: + return await client.request(method, path, headers=_filter_headers(headers), content=body) + + +async def proxy_stream( + base_url: str, + path: str, + method: str, + headers: Dict[str, str], + payload: Optional[dict], + timeout_s: float, +) -> AsyncIterator[bytes]: + async with httpx.AsyncClient(base_url=base_url, timeout=timeout_s) as client: + async with client.stream(method, path, headers=_filter_headers(headers), json=payload) as resp: + resp.raise_for_status() + async for chunk in resp.aiter_bytes(): + if chunk: + yield chunk diff --git a/llamaCpp.Wrapper.app/logging_utils.py b/llamaCpp.Wrapper.app/logging_utils.py new file mode 100644 index 0000000..9e1234b --- /dev/null +++ b/llamaCpp.Wrapper.app/logging_utils.py @@ -0,0 +1,13 @@ +import logging +import os + + +def configure_logging() -> None: + if logging.getLogger().handlers: + return + level_name = os.getenv("LOG_LEVEL", "INFO").upper() + level = getattr(logging, level_name, logging.INFO) + logging.basicConfig( + level=level, + format="%(asctime)s %(levelname)s %(name)s: %(message)s", + ) diff --git a/llamaCpp.Wrapper.app/model_registry.py b/llamaCpp.Wrapper.app/model_registry.py new file mode 100644 index 0000000..9deb2f4 --- /dev/null +++ b/llamaCpp.Wrapper.app/model_registry.py @@ -0,0 +1,45 @@ +import time +from dataclasses import dataclass +from pathlib import Path +from typing import Dict, List, Optional + + +@dataclass +class ModelInfo: + model_id: str + created: int + size: int + path: Path + + +def scan_models(model_dir: str) -> List[ModelInfo]: + base = Path(model_dir) + if not base.exists(): + return [] + models: List[ModelInfo] = [] + now = int(time.time()) + for entry in base.iterdir(): + if entry.name.endswith(".partial"): + continue + if entry.is_file(): + size = entry.stat().st_size + models.append(ModelInfo(model_id=entry.name, created=now, size=size, path=entry)) + elif entry.is_dir(): + models.append(ModelInfo(model_id=entry.name, created=now, size=0, path=entry)) + models.sort(key=lambda m: m.model_id.lower()) + return models + + +def find_model(model_dir: str, model_id: str) -> Optional[ModelInfo]: + for model in scan_models(model_dir): + if model.model_id == model_id: + return model + return None + + +def resolve_model(model_dir: str, requested: str, aliases: Dict[str, str]) -> Optional[ModelInfo]: + if not requested: + return None + if requested in aliases: + requested = aliases[requested] + return find_model(model_dir, requested) diff --git a/llamaCpp.Wrapper.app/openai_translate.py b/llamaCpp.Wrapper.app/openai_translate.py new file mode 100644 index 0000000..4b8793e --- /dev/null +++ b/llamaCpp.Wrapper.app/openai_translate.py @@ -0,0 +1,140 @@ +import time +import uuid +from typing import Any, Dict, List, Tuple + + +def _messages_from_input(input_value: Any) -> List[Dict[str, Any]]: + if isinstance(input_value, str): + return [{"role": "user", "content": input_value}] + if isinstance(input_value, list): + messages: List[Dict[str, Any]] = [] + for item in input_value: + if isinstance(item, str): + messages.append({"role": "user", "content": item}) + elif isinstance(item, dict): + role = item.get("role") or "user" + content = item.get("content") or item.get("text") or "" + if item.get("type") == "input_image": + content = [{"type": "image_url", "image_url": {"url": item.get("image_url", "")}}] + messages.append({"role": role, "content": content}) + return messages + return [{"role": "user", "content": str(input_value)}] + + +def _normalize_tools(tools: Any) -> Any: + if not isinstance(tools, list): + return tools + normalized = [] + for tool in tools: + if not isinstance(tool, dict): + normalized.append(tool) + continue + if "function" in tool: + normalized.append(tool) + continue + if tool.get("type") == "function" and ("name" in tool or "parameters" in tool or "description" in tool): + function = { + "name": tool.get("name"), + "parameters": tool.get("parameters"), + "description": tool.get("description"), + } + function = {k: v for k, v in function.items() if v is not None} + normalized.append({"type": "function", "function": function}) + continue + normalized.append(tool) + return normalized + + +def _normalize_tool_choice(tool_choice: Any) -> Any: + if not isinstance(tool_choice, dict): + return tool_choice + if "function" in tool_choice: + return tool_choice + if tool_choice.get("type") == "function" and "name" in tool_choice: + return {"type": "function", "function": {"name": tool_choice.get("name")}} + return tool_choice + + +def normalize_chat_payload(payload: Dict[str, Any]) -> Dict[str, Any]: + if "return_format" in payload and "response_format" not in payload: + if payload["return_format"] == "json": + payload["response_format"] = {"type": "json_object"} + if "functions" in payload and "tools" not in payload: + functions = payload.get("functions") + if isinstance(functions, list): + tools = [] + for func in functions: + if isinstance(func, dict): + tools.append({"type": "function", "function": func}) + if tools: + payload["tools"] = tools + payload.pop("functions", None) + if "tools" in payload: + payload["tools"] = _normalize_tools(payload.get("tools")) + if "tool_choice" in payload: + payload["tool_choice"] = _normalize_tool_choice(payload.get("tool_choice")) + return payload + + +def responses_to_chat_payload(payload: Dict[str, Any]) -> Tuple[Dict[str, Any], str]: + model = payload.get("model") or "unknown" + messages = _messages_from_input(payload.get("input", "")) + + chat_payload: Dict[str, Any] = { + "model": model, + "messages": messages, + } + + passthrough_keys = [ + "temperature", + "top_p", + "max_output_tokens", + "stream", + "tools", + "tool_choice", + "response_format", + "return_format", + "frequency_penalty", + "presence_penalty", + "seed", + "stop", + ] + + for key in passthrough_keys: + if key in payload: + if key == "max_output_tokens": + chat_payload["max_tokens"] = payload[key] + elif key == "return_format" and payload[key] == "json": + chat_payload["response_format"] = {"type": "json_object"} + else: + chat_payload[key] = payload[key] + + return normalize_chat_payload(chat_payload), model + + +def chat_to_responses(chat: Dict[str, Any], model: str) -> Dict[str, Any]: + response_id = f"resp_{uuid.uuid4().hex}" + created = int(time.time()) + content = "" + if chat.get("choices"): + choice = chat["choices"][0] + message = choice.get("message") or {} + content = message.get("content") or "" + + return { + "id": response_id, + "object": "response", + "created": created, + "model": model, + "output": [ + { + "id": f"msg_{uuid.uuid4().hex}", + "type": "message", + "role": "assistant", + "content": [ + {"type": "output_text", "text": content} + ], + } + ], + "usage": chat.get("usage", {}), + } diff --git a/llamaCpp.Wrapper.app/restart.py b/llamaCpp.Wrapper.app/restart.py new file mode 100644 index 0000000..e0d3675 --- /dev/null +++ b/llamaCpp.Wrapper.app/restart.py @@ -0,0 +1,51 @@ +import asyncio +import logging +import shlex +from dataclasses import dataclass +from typing import Optional + +import httpx + + +log = logging.getLogger("llamacpp_restart") + + +@dataclass +class RestartPlan: + method: str + command: Optional[str] + url: Optional[str] + allowed_container: Optional[str] = None + + +async def trigger_restart(plan: RestartPlan, payload: Optional[dict] = None) -> None: + if plan.method == "none": + log.warning("Restart requested but restart method is none") + return + if plan.method == "http": + if not plan.url: + raise RuntimeError("restart url is required for http method") + async with httpx.AsyncClient(timeout=60) as client: + resp = await client.post(plan.url, json=payload or {}) + resp.raise_for_status() + return + if plan.method == "docker": + if not plan.command: + raise RuntimeError("restart command must include container id or name for docker method") + if plan.allowed_container and plan.command != plan.allowed_container: + raise RuntimeError("docker restart command not allowed for non-target container") + async with httpx.AsyncClient(transport=httpx.AsyncHTTPTransport(uds="/var/run/docker.sock"), timeout=30) as client: + resp = await client.post(f"http://docker/containers/{plan.command}/restart") + resp.raise_for_status() + return + if plan.method == "shell": + if not plan.command: + raise RuntimeError("restart command is required for shell method") + cmd = plan.command + args = shlex.split(cmd) + proc = await asyncio.create_subprocess_exec(*args) + code = await proc.wait() + if code != 0: + raise RuntimeError(f"restart command failed with exit code {code}") + return + raise RuntimeError(f"unknown restart method {plan.method}") diff --git a/llamaCpp.Wrapper.app/run.py b/llamaCpp.Wrapper.app/run.py new file mode 100644 index 0000000..71a40fa --- /dev/null +++ b/llamaCpp.Wrapper.app/run.py @@ -0,0 +1,35 @@ +import os +import signal +import subprocess +import sys + +from app.config import load_config + + +def main() -> None: + cfg = load_config() + python = sys.executable + + api_cmd = [python, "-m", "uvicorn", "app.api_app:create_api_app", "--factory", "--host", "0.0.0.0", "--port", str(cfg.api_port)] + ui_cmd = [python, "-m", "uvicorn", "app.ui_app:create_ui_app", "--factory", "--host", "0.0.0.0", "--port", str(cfg.ui_port)] + + procs = [subprocess.Popen(api_cmd)] + if cfg.ui_port != cfg.api_port: + procs.append(subprocess.Popen(ui_cmd)) + + def shutdown(_sig, _frame): + for proc in procs: + proc.terminate() + for proc in procs: + proc.wait(timeout=10) + sys.exit(0) + + signal.signal(signal.SIGTERM, shutdown) + signal.signal(signal.SIGINT, shutdown) + + for proc in procs: + proc.wait() + + +if __name__ == "__main__": + main() diff --git a/llamaCpp.Wrapper.app/stream_transform.py b/llamaCpp.Wrapper.app/stream_transform.py new file mode 100644 index 0000000..a2a6253 --- /dev/null +++ b/llamaCpp.Wrapper.app/stream_transform.py @@ -0,0 +1,102 @@ +import json +import time +import uuid +from typing import Any, AsyncIterator, Dict + +import httpx + + +def _sse_event(event: str, data: Dict[str, Any]) -> bytes: + payload = json.dumps(data, separators=(",", ":")) + return f"event: {event}\ndata: {payload}\n\n".encode("utf-8") + +def _filter_headers(headers: Dict[str, str]) -> Dict[str, str]: + drop = {"host", "content-length"} + return {k: v for k, v in headers.items() if k.lower() not in drop} + + +async def stream_chat_to_responses( + base_url: str, + headers: Dict[str, str], + payload: Dict[str, Any], + timeout_s: float, +) -> AsyncIterator[bytes]: + response_id = f"resp_{uuid.uuid4().hex}" + created = int(time.time()) + model = payload.get("model") or "unknown" + msg_id = f"msg_{uuid.uuid4().hex}" + output_text = "" + + response_stub = { + "id": response_id, + "object": "response", + "created": created, + "model": model, + "output": [ + { + "id": msg_id, + "type": "message", + "role": "assistant", + "content": [ + {"type": "output_text", "text": ""} + ], + } + ], + } + + yield _sse_event("response.created", {"type": "response.created", "response": response_stub}) + + async with httpx.AsyncClient(base_url=base_url, timeout=timeout_s) as client: + async with client.stream( + "POST", + "/v1/chat/completions", + headers=_filter_headers(headers), + json=payload, + ) as resp: + resp.raise_for_status() + buffer = "" + async for chunk in resp.aiter_text(): + buffer += chunk + while "\n\n" in buffer: + block, buffer = buffer.split("\n\n", 1) + lines = [line for line in block.splitlines() if line.startswith("data:")] + if not lines: + continue + data_str = "\n".join(line[len("data:"):].strip() for line in lines) + if data_str == "[DONE]": + continue + try: + data = json.loads(data_str) + except json.JSONDecodeError: + continue + choices = data.get("choices") or [] + if not choices: + continue + delta = choices[0].get("delta") or {} + text_delta = delta.get("content") + if text_delta: + output_text += text_delta + yield _sse_event( + "response.output_text.delta", + { + "type": "response.output_text.delta", + "delta": text_delta, + "item_id": msg_id, + "output_index": 0, + "content_index": 0, + }, + ) + + yield _sse_event( + "response.output_text.done", + { + "type": "response.output_text.done", + "text": output_text, + "item_id": msg_id, + "output_index": 0, + "content_index": 0, + }, + ) + + response_stub["output"][0]["content"][0]["text"] = output_text + yield _sse_event("response.completed", {"type": "response.completed", "response": response_stub}) diff --git a/llamaCpp.Wrapper.app/truenas_middleware.py b/llamaCpp.Wrapper.app/truenas_middleware.py new file mode 100644 index 0000000..3430c96 --- /dev/null +++ b/llamaCpp.Wrapper.app/truenas_middleware.py @@ -0,0 +1,313 @@ +import json +import logging +import shlex +import ssl +from dataclasses import dataclass +from pathlib import Path +from typing import Any, Dict, Optional + +import websockets +import yaml + + +log = logging.getLogger("truenas_middleware") + + +@dataclass +class TrueNASConfig: + ws_url: str + api_key: str + api_user: Optional[str] + app_name: str + verify_ssl: bool = False + + +def _parse_compose(raw: Any) -> Dict[str, Any]: + if isinstance(raw, dict): + return raw + if isinstance(raw, str): + text = raw.strip() + try: + return json.loads(text) + except json.JSONDecodeError: + return yaml.safe_load(text) + raise ValueError("Unsupported compose payload") + + +def _command_to_list(command: Any) -> list: + if isinstance(command, list): + return command + if isinstance(command, str): + return shlex.split(command) + return [] + + +def _extract_command(config: Dict[str, Any], service_name: str = "llamacpp") -> list: + if config.get("custom_compose_config") or config.get("custom_compose_config_string"): + compose = _parse_compose(config.get("custom_compose_config") or config.get("custom_compose_config_string") or {}) + services = compose.get("services") or {} + svc = services.get(service_name) or {} + return _command_to_list(svc.get("command")) + return _command_to_list(config.get("command")) + + +def _model_id_from_command(cmd: list) -> Optional[str]: + if "--model" in cmd: + idx = cmd.index("--model") + if idx + 1 < len(cmd): + return Path(cmd[idx + 1]).name + return None + + +def _set_arg(cmd: list, flag: str, value: Optional[str]) -> list: + if value is None: + return cmd + if flag in cmd: + idx = cmd.index(flag) + if idx + 1 < len(cmd): + cmd[idx + 1] = value + else: + cmd.append(value) + return cmd + cmd.extend([flag, value]) + return cmd + + +def _merge_args(cmd: list, args: Dict[str, str]) -> list: + flag_map = { + "device": "--device", + "tensor_split": "--tensor-split", + "split_mode": "--split-mode", + "n_gpu_layers": "--n-gpu-layers", + "ctx_size": "--ctx-size", + "batch_size": "--batch-size", + "ubatch_size": "--ubatch-size", + "cache_type_k": "--cache-type-k", + "cache_type_v": "--cache-type-v", + "flash_attn": "--flash-attn", + } + for key, value in args.items(): + flag = flag_map.get(key) + if flag: + if flag in cmd: + continue + _set_arg(cmd, flag, value) + return cmd + + +def _merge_extra_args(cmd: list, extra: str) -> list: + if not extra: + return cmd + extra_list = shlex.split(extra) + filtered: list[str] = [] + skip_next = False + for item in extra_list: + if skip_next: + skip_next = False + continue + if item in {"--device", "-dev"}: + log.warning("Dropping --device from extra args to avoid llama.cpp device errors.") + skip_next = True + continue + filtered.append(item) + for flag in filtered: + if flag not in cmd: + cmd.append(flag) + return cmd + + +def _update_model_command(command: Any, model_path: str, args: Dict[str, str], extra: str) -> list: + cmd = _command_to_list(command) + if "--device" in cmd: + idx = cmd.index("--device") + del cmd[idx: idx + 2] + cmd = _set_arg(cmd, "--model", model_path) + cmd = _merge_args(cmd, args) + cmd = _merge_extra_args(cmd, extra) + return cmd + + +def _replace_flags(cmd: list, flags: Dict[str, Optional[str]], extra: str) -> list: + result = list(cmd) + for flag in flags.keys(): + while flag in result: + idx = result.index(flag) + del result[idx: idx + 2] + if "--device" in result: + idx = result.index("--device") + del result[idx: idx + 2] + for flag, value in flags.items(): + if value is not None and value != "": + result = _set_arg(result, flag, value) + result = _merge_extra_args(result, extra) + return result + + +async def get_app_config(cfg: TrueNASConfig) -> Dict[str, Any]: + config = await _rpc_call(cfg, "app.config", [cfg.app_name]) + if not isinstance(config, dict): + raise RuntimeError("app.config returned unsupported payload") + return config + + +async def get_app_command(cfg: TrueNASConfig, service_name: str = "llamacpp") -> list: + config = await get_app_config(cfg) + return _extract_command(config, service_name=service_name) + + +async def get_active_model_id(cfg: TrueNASConfig, service_name: str = "llamacpp") -> str: + config = await get_app_config(cfg) + cmd = _extract_command(config, service_name=service_name) + return _model_id_from_command(cmd) or "" + + +async def get_app_logs( + cfg: TrueNASConfig, + tail_lines: int = 200, + service_name: str = "llamacpp", +) -> str: + tail_payloads = [ + {"tail": tail_lines}, + {"tail_lines": tail_lines}, + {"tail": str(tail_lines)}, + ] + for payload in tail_payloads: + try: + result = await _rpc_call(cfg, "app.container_logs", [cfg.app_name, service_name, payload]) + if isinstance(result, str): + return result + except Exception as exc: + log.debug("app.container_logs failed (%s): %s", payload, exc) + for payload in tail_payloads: + try: + result = await _rpc_call(cfg, "app.logs", [cfg.app_name, payload]) + if isinstance(result, str): + return result + except Exception as exc: + log.debug("app.logs failed (%s): %s", payload, exc) + return "" + + +async def update_app_command( + cfg: TrueNASConfig, + command: list, + service_name: str = "llamacpp", +) -> None: + config = await _rpc_call(cfg, "app.config", [cfg.app_name]) + if not isinstance(config, dict): + raise RuntimeError("app.config returned unsupported payload") + if config.get("custom_compose_config") or config.get("custom_compose_config_string"): + compose = _parse_compose(config.get("custom_compose_config") or config.get("custom_compose_config_string") or {}) + services = compose.get("services") or {} + if service_name not in services: + raise RuntimeError(f"service {service_name} not found in compose") + svc = services[service_name] + svc["command"] = command + await _rpc_call(cfg, "app.update", [cfg.app_name, {"custom_compose_config": compose}]) + return + config["command"] = command + await _rpc_call(cfg, "app.update", [cfg.app_name, {"values": config}]) + + +async def update_command_flags( + cfg: TrueNASConfig, + flags: Dict[str, Optional[str]], + extra: str, + service_name: str = "llamacpp", +) -> None: + config = await _rpc_call(cfg, "app.config", [cfg.app_name]) + if not isinstance(config, dict): + raise RuntimeError("app.config returned unsupported payload") + if config.get("custom_compose_config") or config.get("custom_compose_config_string"): + compose = _parse_compose(config.get("custom_compose_config") or config.get("custom_compose_config_string") or {}) + services = compose.get("services") or {} + if service_name not in services: + raise RuntimeError(f"service {service_name} not found in compose") + svc = services[service_name] + cmd = svc.get("command") + svc["command"] = _replace_flags(_command_to_list(cmd), flags, extra) + await _rpc_call(cfg, "app.update", [cfg.app_name, {"custom_compose_config": compose}]) + return + cmd = _replace_flags(_command_to_list(config.get("command")), flags, extra) + config["command"] = cmd + await _rpc_call(cfg, "app.update", [cfg.app_name, {"values": config}]) + + +async def _rpc_call(cfg: TrueNASConfig, method: str, params: Optional[list] = None) -> Any: + ssl_ctx = None + if cfg.ws_url.startswith("wss://") and not cfg.verify_ssl: + ssl_ctx = ssl.create_default_context() + ssl_ctx.check_hostname = False + ssl_ctx.verify_mode = ssl.CERT_NONE + + async with websockets.connect(cfg.ws_url, ssl=ssl_ctx) as ws: + await ws.send(json.dumps({"msg": "connect", "version": "1", "support": ["1"]})) + connected = json.loads(await ws.recv()) + if connected.get("msg") != "connected": + raise RuntimeError("failed to connect to TrueNAS websocket") + + await ws.send( + json.dumps({"id": 1, "msg": "method", "method": "auth.login_with_api_key", "params": [cfg.api_key]}) + ) + auth_resp = json.loads(await ws.recv()) + if not auth_resp.get("result"): + if not cfg.api_user: + raise RuntimeError("API key rejected and TRUENAS_API_USER not set") + await ws.send( + json.dumps( + { + "id": 2, + "msg": "method", + "method": "auth.login_ex", + "params": [ + { + "mechanism": "API_KEY_PLAIN", + "username": cfg.api_user, + "api_key": cfg.api_key, + } + ], + } + ) + ) + auth_ex = json.loads(await ws.recv()) + if auth_ex.get("result", {}).get("response_type") != "SUCCESS": + raise RuntimeError("API key authentication failed") + + req_id = 3 + await ws.send(json.dumps({"id": req_id, "msg": "method", "method": method, "params": params or []})) + while True: + raw = json.loads(await ws.recv()) + if raw.get("id") != req_id: + continue + if raw.get("msg") == "error": + raise RuntimeError(raw.get("error")) + return raw.get("result") + + +async def switch_model( + cfg: TrueNASConfig, + model_path: str, + args: Dict[str, str], + extra: str, + service_name: str = "llamacpp", +) -> None: + config = await _rpc_call(cfg, "app.config", [cfg.app_name]) + if config.get("custom_compose_config") or config.get("custom_compose_config_string"): + compose = _parse_compose(config.get("custom_compose_config") or config.get("custom_compose_config_string") or {}) + services = compose.get("services") or {} + if service_name not in services: + raise RuntimeError(f"service {service_name} not found in compose") + svc = services[service_name] + cmd = svc.get("command") + svc["command"] = _update_model_command(cmd, model_path, args, extra) + await _rpc_call(cfg, "app.update", [cfg.app_name, {"custom_compose_config": compose}]) + log.info("Requested model switch to %s via TrueNAS middleware (custom app)", model_path) + return + + if not isinstance(config, dict): + raise RuntimeError("app.config returned unsupported payload") + + cmd = config.get("command") + config["command"] = _update_model_command(cmd, model_path, args, extra) + await _rpc_call(cfg, "app.update", [cfg.app_name, {"values": config}]) + log.info("Requested model switch to %s via TrueNAS middleware (catalog app)", model_path) diff --git a/llamaCpp.Wrapper.app/ui_app.py b/llamaCpp.Wrapper.app/ui_app.py new file mode 100644 index 0000000..dbac33b --- /dev/null +++ b/llamaCpp.Wrapper.app/ui_app.py @@ -0,0 +1,357 @@ +import asyncio +import json +import logging +from pathlib import Path +from typing import Any, Dict, Optional + +import httpx +from fastapi import FastAPI, HTTPException, Request +from fastapi.responses import FileResponse, HTMLResponse, JSONResponse, StreamingResponse + +from app.config import load_config +from app.docker_logs import docker_container_logs +from app.download_manager import DownloadManager +from app.logging_utils import configure_logging +from app.model_registry import scan_models +from app.truenas_middleware import ( + TrueNASConfig, + get_active_model_id, + get_app_command, + get_app_logs, + switch_model, + update_command_flags, +) +from app.warmup import resolve_warmup_prompt, run_warmup_with_retry + + +configure_logging() +log = logging.getLogger("ui_app") + + +class EventBroadcaster: + def __init__(self) -> None: + self._queues: set[asyncio.Queue] = set() + + def connect(self) -> asyncio.Queue: + queue: asyncio.Queue = asyncio.Queue() + self._queues.add(queue) + return queue + + def disconnect(self, queue: asyncio.Queue) -> None: + self._queues.discard(queue) + + async def publish(self, payload: dict) -> None: + for queue in list(self._queues): + queue.put_nowait(payload) + + +def _static_path() -> Path: + return Path(__file__).parent / "ui_static" + + +async def _fetch_active_model(truenas_cfg: Optional[TrueNASConfig]) -> Optional[str]: + if not truenas_cfg: + return None + try: + return await get_active_model_id(truenas_cfg) + except Exception as exc: + log.warning("Failed to read active model from TrueNAS config: %s", exc) + return None + + +def _model_list(model_dir: str, active_model: Optional[str]) -> Dict[str, Any]: + data = [] + for model in scan_models(model_dir): + data.append({ + "id": model.model_id, + "size": model.size, + "active": model.model_id == active_model, + }) + return {"models": data, "active_model": active_model} + + +def create_ui_app() -> FastAPI: + cfg = load_config() + app = FastAPI(title="llama.cpp Model Manager", version="0.1.0") + broadcaster = EventBroadcaster() + manager = DownloadManager(cfg, broadcaster=broadcaster) + truenas_cfg = None + if cfg.truenas_ws_url and cfg.truenas_api_key: + truenas_cfg = TrueNASConfig( + ws_url=cfg.truenas_ws_url, + api_key=cfg.truenas_api_key, + api_user=cfg.truenas_api_user, + app_name=cfg.truenas_app_name, + verify_ssl=cfg.truenas_verify_ssl, + ) + + async def monitor_active_model() -> None: + last_model = None + while True: + current = await _fetch_active_model(truenas_cfg) + if current and current != last_model: + last_model = current + await broadcaster.publish({"type": "active_model", "model_id": current}) + await asyncio.sleep(3) + + async def _fetch_logs() -> str: + logs = "" + if truenas_cfg: + try: + logs = await asyncio.wait_for(get_app_logs(truenas_cfg, tail_lines=200), timeout=5) + except asyncio.TimeoutError: + logs = "" + if not logs and cfg.llamacpp_container_name: + try: + logs = await asyncio.wait_for( + docker_container_logs(cfg.llamacpp_container_name, tail_lines=200), + timeout=10, + ) + except asyncio.TimeoutError: + logs = "" + return logs + + @app.on_event("startup") + async def start_tasks() -> None: + asyncio.create_task(monitor_active_model()) + + @app.middleware("http") + async def log_requests(request: Request, call_next): + log.info("UI request %s %s", request.method, request.url.path) + return await call_next(request) + + @app.get("/health") + async def health() -> Dict[str, Any]: + return {"status": "ok", "model_dir": cfg.model_dir} + + @app.get("/") + async def index() -> HTMLResponse: + return FileResponse(_static_path() / "index.html") + + @app.get("/ui/styles.css") + async def styles() -> FileResponse: + return FileResponse(_static_path() / "styles.css") + + @app.get("/ui/app.js") + async def app_js() -> FileResponse: + return FileResponse(_static_path() / "app.js") + + @app.get("/ui/api/models") + async def list_models() -> JSONResponse: + active_model = await _fetch_active_model(truenas_cfg) + log.info("UI list models active=%s", active_model) + return JSONResponse(_model_list(cfg.model_dir, active_model)) + + @app.get("/ui/api/downloads") + async def list_downloads() -> JSONResponse: + log.info("UI list downloads") + return JSONResponse({"downloads": manager.list_downloads()}) + + @app.post("/ui/api/downloads") + async def start_download(request: Request) -> JSONResponse: + payload = await request.json() + url = payload.get("url") + filename = payload.get("filename") + log.info("UI download start url=%s filename=%s", url, filename) + if not url: + raise HTTPException(status_code=400, detail="url is required") + try: + status = await manager.start(url, filename=filename) + except ValueError as exc: + raise HTTPException(status_code=403, detail=str(exc)) + return JSONResponse({"download": status.__dict__}) + + @app.delete("/ui/api/downloads/{download_id}") + async def cancel_download(download_id: str) -> JSONResponse: + log.info("UI download cancel id=%s", download_id) + ok = await manager.cancel(download_id) + if not ok: + raise HTTPException(status_code=404, detail="download not found") + return JSONResponse({"status": "cancelled"}) + + @app.get("/ui/api/events") + async def events() -> StreamingResponse: + queue = broadcaster.connect() + + async def event_stream(): + try: + while True: + payload = await queue.get() + data = json.dumps(payload, separators=(",", ":")) + yield f"data: {data}\n\n".encode("utf-8") + finally: + broadcaster.disconnect(queue) + + return StreamingResponse(event_stream(), media_type="text/event-stream") + + @app.post("/ui/api/switch-model") + async def switch_model_ui(request: Request) -> JSONResponse: + payload = await request.json() + model_id = payload.get("model_id") + warmup_override = payload.get("warmup_prompt") or "" + if not model_id: + raise HTTPException(status_code=400, detail="model_id is required") + + model_path = Path(cfg.model_dir) / model_id + if not model_path.exists(): + raise HTTPException(status_code=404, detail="model not found") + + if not truenas_cfg: + raise HTTPException(status_code=500, detail="TrueNAS credentials not configured") + + try: + container_model_path = str(Path(cfg.model_container_dir) / model_id) + await switch_model(truenas_cfg, container_model_path, cfg.llamacpp_args, cfg.llamacpp_extra_args) + except Exception as exc: + await broadcaster.publish({"type": "model_switch_failed", "model_id": model_id, "error": str(exc)}) + raise HTTPException(status_code=500, detail=f"model switch failed: {exc}") + + warmup_prompt = resolve_warmup_prompt(warmup_override, cfg.warmup_prompt_path) + log.info("UI warmup after switch model=%s prompt_len=%s", model_id, len(warmup_prompt)) + try: + await run_warmup_with_retry(cfg.base_url, model_id, warmup_prompt, timeout_s=cfg.switch_timeout_s) + except Exception as exc: + await broadcaster.publish({"type": "model_switch_failed", "model_id": model_id, "error": str(exc)}) + raise HTTPException(status_code=500, detail=f"model switch warmup failed: {exc}") + + try: + async with httpx.AsyncClient(base_url=cfg.base_url, timeout=120) as client: + resp = await client.post( + "/v1/chat/completions", + json={ + "model": model_id, + "messages": [{"role": "user", "content": "ok"}], + "max_tokens": 4, + "temperature": 0, + }, + ) + resp.raise_for_status() + except Exception as exc: + await broadcaster.publish({"type": "model_switch_failed", "model_id": model_id, "error": str(exc)}) + raise HTTPException(status_code=500, detail=f"model switch verification failed: {exc}") + + await broadcaster.publish({"type": "model_switched", "model_id": model_id}) + log.info("UI model switched model=%s", model_id) + return JSONResponse({"status": "ok", "model_id": model_id}) + + @app.get("/ui/api/llamacpp-config") + async def get_llamacpp_config() -> JSONResponse: + active_model = await _fetch_active_model(truenas_cfg) + log.info("UI get llama.cpp config active=%s", active_model) + params: Dict[str, Optional[str]] = {} + command_raw = [] + if truenas_cfg: + command_raw = await get_app_command(truenas_cfg) + flag_map = { + "--ctx-size": "ctx_size", + "--n-gpu-layers": "n_gpu_layers", + "--tensor-split": "tensor_split", + "--split-mode": "split_mode", + "--cache-type-k": "cache_type_k", + "--cache-type-v": "cache_type_v", + "--flash-attn": "flash_attn", + "--temp": "temp", + "--top-k": "top_k", + "--top-p": "top_p", + "--repeat-penalty": "repeat_penalty", + "--repeat-last-n": "repeat_last_n", + "--frequency-penalty": "frequency_penalty", + "--presence-penalty": "presence_penalty", + } + if isinstance(command_raw, list): + for flag, key in flag_map.items(): + if flag in command_raw: + idx = command_raw.index(flag) + if idx + 1 < len(command_raw): + params[key] = command_raw[idx + 1] + known_flags = set(flag_map.keys()) | {"--model"} + extra = [] + if isinstance(command_raw, list): + skip_next = False + for item in command_raw: + if skip_next: + skip_next = False + continue + if item in known_flags: + skip_next = True + continue + extra.append(item) + return JSONResponse( + { + "active_model": active_model, + "params": params, + "extra_args": " ".join(extra), + } + ) + + @app.post("/ui/api/llamacpp-config") + async def update_llamacpp_config(request: Request) -> JSONResponse: + payload = await request.json() + params = payload.get("params") or {} + extra_args = payload.get("extra_args") or "" + warmup_override = payload.get("warmup_prompt") or "" + log.info("UI save llama.cpp config params=%s extra_args=%s", params, extra_args) + if not truenas_cfg: + raise HTTPException(status_code=500, detail="TrueNAS credentials not configured") + flags = { + "--ctx-size": params.get("ctx_size"), + "--n-gpu-layers": params.get("n_gpu_layers"), + "--tensor-split": params.get("tensor_split"), + "--split-mode": params.get("split_mode"), + "--cache-type-k": params.get("cache_type_k"), + "--cache-type-v": params.get("cache_type_v"), + "--flash-attn": params.get("flash_attn"), + "--temp": params.get("temp"), + "--top-k": params.get("top_k"), + "--top-p": params.get("top_p"), + "--repeat-penalty": params.get("repeat_penalty"), + "--repeat-last-n": params.get("repeat_last_n"), + "--frequency-penalty": params.get("frequency_penalty"), + "--presence-penalty": params.get("presence_penalty"), + } + try: + await update_command_flags(truenas_cfg, flags, extra_args) + except Exception as exc: + log.exception("UI update llama.cpp config failed") + raise HTTPException(status_code=500, detail=f"config update failed: {exc}") + active_model = await _fetch_active_model(truenas_cfg) + if active_model: + warmup_prompt = resolve_warmup_prompt(warmup_override, cfg.warmup_prompt_path) + log.info("UI warmup after config update model=%s prompt_len=%s", active_model, len(warmup_prompt)) + try: + await run_warmup_with_retry(cfg.base_url, active_model, warmup_prompt, timeout_s=cfg.switch_timeout_s) + except Exception as exc: + raise HTTPException(status_code=500, detail=f"config warmup failed: {exc}") + await broadcaster.publish({"type": "llamacpp_config_updated"}) + return JSONResponse({"status": "ok"}) + + @app.get("/ui/api/llamacpp-logs") + async def get_llamacpp_logs() -> JSONResponse: + logs = await _fetch_logs() + return JSONResponse({"logs": logs}) + + @app.get("/ui/api/llamacpp-logs/stream") + async def stream_llamacpp_logs() -> StreamingResponse: + async def event_stream(): + last_lines: list[str] = [] + while True: + logs = await _fetch_logs() + lines = logs.splitlines() + if last_lines: + last_tail = last_lines[-1] + idx = -1 + for i in range(len(lines) - 1, -1, -1): + if lines[i] == last_tail: + idx = i + break + if idx >= 0: + lines = lines[idx + 1 :] + if lines: + last_lines = (last_lines + lines)[-200:] + data = json.dumps({"type": "logs", "lines": lines}, separators=(",", ":")) + yield f"data: {data}\n\n".encode("utf-8") + await asyncio.sleep(2) + + return StreamingResponse(event_stream(), media_type="text/event-stream") + + return app diff --git a/llamaCpp.Wrapper.app/ui_static/app.js b/llamaCpp.Wrapper.app/ui_static/app.js new file mode 100644 index 0000000..f3da04a --- /dev/null +++ b/llamaCpp.Wrapper.app/ui_static/app.js @@ -0,0 +1,306 @@ +const modelsList = document.getElementById("models-list"); +const downloadsList = document.getElementById("downloads-list"); +const refreshModels = document.getElementById("refresh-models"); +const refreshDownloads = document.getElementById("refresh-downloads"); +const form = document.getElementById("download-form"); +const errorEl = document.getElementById("download-error"); +const statusEl = document.getElementById("switch-status"); +const configStatusEl = document.getElementById("config-status"); +const configForm = document.getElementById("config-form"); +const refreshConfig = document.getElementById("refresh-config"); +const warmupPromptEl = document.getElementById("warmup-prompt"); +const refreshLogs = document.getElementById("refresh-logs"); +const logsOutput = document.getElementById("logs-output"); +const logsStatus = document.getElementById("logs-status"); +const themeToggle = document.getElementById("theme-toggle"); + +const applyTheme = (theme) => { + document.documentElement.setAttribute("data-theme", theme); + themeToggle.textContent = theme === "dark" ? "Light" : "Dark"; + themeToggle.setAttribute("aria-pressed", theme === "dark" ? "true" : "false"); +}; + +const savedTheme = localStorage.getItem("theme") || "light"; +applyTheme(savedTheme); +themeToggle.addEventListener("click", () => { + const next = document.documentElement.getAttribute("data-theme") === "dark" ? "light" : "dark"; + localStorage.setItem("theme", next); + applyTheme(next); +}); + +const cfgFields = { + ctx_size: document.getElementById("cfg-ctx-size"), + n_gpu_layers: document.getElementById("cfg-n-gpu-layers"), + tensor_split: document.getElementById("cfg-tensor-split"), + split_mode: document.getElementById("cfg-split-mode"), + cache_type_k: document.getElementById("cfg-cache-type-k"), + cache_type_v: document.getElementById("cfg-cache-type-v"), + flash_attn: document.getElementById("cfg-flash-attn"), + temp: document.getElementById("cfg-temp"), + top_k: document.getElementById("cfg-top-k"), + top_p: document.getElementById("cfg-top-p"), + repeat_penalty: document.getElementById("cfg-repeat-penalty"), + repeat_last_n: document.getElementById("cfg-repeat-last-n"), + frequency_penalty: document.getElementById("cfg-frequency-penalty"), + presence_penalty: document.getElementById("cfg-presence-penalty"), +}; +const extraArgsEl = document.getElementById("cfg-extra-args"); + +const fmtBytes = (bytes) => { + if (!bytes && bytes !== 0) return "-"; + const units = ["B", "KB", "MB", "GB", "TB"]; + let idx = 0; + let value = bytes; + while (value >= 1024 && idx < units.length - 1) { + value /= 1024; + idx += 1; + } + return `${value.toFixed(1)} ${units[idx]}`; +}; + +const setStatus = (message, type) => { + statusEl.textContent = message || ""; + statusEl.className = "status"; + if (type) { + statusEl.classList.add(type); + } +}; + +const setConfigStatus = (message, type) => { + configStatusEl.textContent = message || ""; + configStatusEl.className = "status"; + if (type) { + configStatusEl.classList.add(type); + } +}; + +async function loadModels() { + const res = await fetch("/ui/api/models"); + const data = await res.json(); + modelsList.innerHTML = ""; + const activeModel = data.active_model; + data.models.forEach((model) => { + const li = document.createElement("li"); + if (model.active) { + li.classList.add("active"); + } + const row = document.createElement("div"); + row.className = "model-row"; + + const name = document.createElement("span"); + name.textContent = `${model.id} (${fmtBytes(model.size)})`; + + const actions = document.createElement("div"); + if (model.active) { + const badge = document.createElement("span"); + badge.className = "badge"; + badge.textContent = "Active"; + actions.appendChild(badge); + } else { + const button = document.createElement("button"); + button.className = "ghost"; + button.textContent = "Switch"; + button.onclick = async () => { + setStatus(`Switching to ${model.id}...`); + const warmupPrompt = warmupPromptEl.value.trim(); + const res = await fetch("/ui/api/switch-model", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ model_id: model.id, warmup_prompt: warmupPrompt }), + }); + const payload = await res.json(); + if (!res.ok) { + setStatus(payload.detail || "Switch failed.", "error"); + return; + } + warmupPromptEl.value = ""; + setStatus(`Active model: ${model.id}`, "ok"); + await loadModels(); + }; + actions.appendChild(button); + } + + row.appendChild(name); + row.appendChild(actions); + li.appendChild(row); + modelsList.appendChild(li); + }); + if (activeModel) { + setStatus(`Active model: ${activeModel}`, "ok"); + } +} + +async function loadDownloads() { + const res = await fetch("/ui/api/downloads"); + const data = await res.json(); + downloadsList.innerHTML = ""; + const entries = Object.values(data.downloads || {}); + if (!entries.length) { + downloadsList.innerHTML = "

No active downloads.

"; + return; + } + entries.forEach((download) => { + const card = document.createElement("div"); + card.className = "download-card"; + + const title = document.createElement("strong"); + title.textContent = download.filename; + + const meta = document.createElement("div"); + const percent = download.bytes_total + ? Math.round((download.bytes_downloaded / download.bytes_total) * 100) + : 0; + meta.textContent = `${download.status} · ${fmtBytes(download.bytes_downloaded)} / ${fmtBytes(download.bytes_total)}`; + + const progress = document.createElement("div"); + progress.className = "progress"; + const bar = document.createElement("span"); + bar.style.width = `${Math.min(percent, 100)}%`; + progress.appendChild(bar); + + const actions = document.createElement("div"); + if (download.status === "downloading" || download.status === "queued") { + const cancel = document.createElement("button"); + cancel.className = "ghost"; + cancel.textContent = "Cancel"; + cancel.onclick = async () => { + await fetch(`/ui/api/downloads/${download.download_id}`, { method: "DELETE" }); + await loadDownloads(); + }; + actions.appendChild(cancel); + } + + card.appendChild(title); + card.appendChild(meta); + card.appendChild(progress); + card.appendChild(actions); + downloadsList.appendChild(card); + }); +} + +async function loadConfig() { + const res = await fetch("/ui/api/llamacpp-config"); + const data = await res.json(); + Object.entries(cfgFields).forEach(([key, el]) => { + el.value = data.params?.[key] || ""; + }); + extraArgsEl.value = data.extra_args || ""; + if (data.active_model) { + setConfigStatus(`Active model: ${data.active_model}`, "ok"); + } +} + +async function loadLogs() { + const res = await fetch("/ui/api/llamacpp-logs"); + if (!res.ok) { + logsStatus.textContent = "Unavailable"; + return; + } + const data = await res.json(); + logsOutput.textContent = data.logs || ""; + logsStatus.textContent = data.logs ? "Snapshot" : "Empty"; +} + +form.addEventListener("submit", async (event) => { + event.preventDefault(); + errorEl.textContent = ""; + const url = document.getElementById("model-url").value.trim(); + const filename = document.getElementById("model-filename").value.trim(); + if (!url) { + errorEl.textContent = "URL is required."; + return; + } + const payload = { url }; + if (filename) payload.filename = filename; + const res = await fetch("/ui/api/downloads", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify(payload), + }); + if (!res.ok) { + const err = await res.json(); + errorEl.textContent = err.detail || "Failed to start download."; + return; + } + document.getElementById("model-url").value = ""; + document.getElementById("model-filename").value = ""; + await loadDownloads(); +}); + +configForm.addEventListener("submit", async (event) => { + event.preventDefault(); + setConfigStatus("Applying parameters..."); + const params = {}; + Object.entries(cfgFields).forEach(([key, el]) => { + if (el.value.trim()) { + params[key] = el.value.trim(); + } + }); + const warmupPrompt = warmupPromptEl.value.trim(); + const res = await fetch("/ui/api/llamacpp-config", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ params, extra_args: extraArgsEl.value.trim(), warmup_prompt: warmupPrompt }), + }); + const payload = await res.json(); + if (!res.ok) { + setConfigStatus(payload.detail || "Update failed.", "error"); + return; + } + setConfigStatus("Parameters updated.", "ok"); + warmupPromptEl.value = ""; +}); + +refreshModels.addEventListener("click", loadModels); +refreshDownloads.addEventListener("click", loadDownloads); +refreshConfig.addEventListener("click", loadConfig); +refreshLogs.addEventListener("click", loadLogs); + +loadModels(); +loadDownloads(); +loadConfig(); +loadLogs(); + +const eventSource = new EventSource("/ui/api/events"); +eventSource.onmessage = async (event) => { + const payload = JSON.parse(event.data); + if (payload.type === "download_progress" || payload.type === "download_completed" || payload.type === "download_status") { + await loadDownloads(); + } + if (payload.type === "active_model") { + await loadModels(); + await loadConfig(); + } + if (payload.type === "model_switched") { + setStatus(`Active model: ${payload.model_id}`, "ok"); + await loadModels(); + await loadConfig(); + } + if (payload.type === "model_switch_failed") { + setStatus(payload.error || "Model switch failed.", "error"); + } + if (payload.type === "llamacpp_config_updated") { + await loadConfig(); + } +}; + +const logsSource = new EventSource("/ui/api/llamacpp-logs/stream"); +logsSource.onopen = () => { + logsStatus.textContent = "Streaming"; +}; +logsSource.onmessage = (event) => { + const payload = JSON.parse(event.data); + if (payload.type !== "logs") { + return; + } + const lines = payload.lines || []; + if (!lines.length) return; + const current = logsOutput.textContent.split("\n").filter((line) => line.length); + const merged = current.concat(lines).slice(-400); + logsOutput.textContent = merged.join("\n"); + logsOutput.scrollTop = logsOutput.scrollHeight; + logsStatus.textContent = "Streaming"; +}; +logsSource.onerror = () => { + logsStatus.textContent = "Disconnected"; +}; diff --git a/llamaCpp.Wrapper.app/ui_static/index.html b/llamaCpp.Wrapper.app/ui_static/index.html new file mode 100644 index 0000000..7218106 --- /dev/null +++ b/llamaCpp.Wrapper.app/ui_static/index.html @@ -0,0 +1,151 @@ + + + + + + llama.cpp Model Manager + + + +
+
+
+

llama.cpp wrapper

+

Model Manager

+

Curate models, tune runtime parameters, and keep llama.cpp responsive.

+
+
+ +
+

Quick Add

+
+ + + +

+
+
+
+
+ +
+
+
+
+

Models

+ +
+
+ +
    +
    + +
    +
    +

    Downloads

    + +
    +
    +
    +
    + +
    +
    +
    +

    Runtime Parameters

    + +
    +
    +
    + + + + + + + + + + + + + + + + +
    +
    +
    +
    + +
    +
    +
    +

    llama.cpp Logs

    +

    Live tail from the llama.cpp container.

    +
    +
    + Idle + +
    +
    +
    
    +      
    +
    + + + diff --git a/llamaCpp.Wrapper.app/ui_static/styles.css b/llamaCpp.Wrapper.app/ui_static/styles.css new file mode 100644 index 0000000..6939140 --- /dev/null +++ b/llamaCpp.Wrapper.app/ui_static/styles.css @@ -0,0 +1,337 @@ +:root { + --bg: #f5f6f8; + --panel: #ffffff; + --panel-muted: #f2f3f6; + --text: #111318; + --muted: #5b6472; + --border: rgba(17, 19, 24, 0.08); + --accent: #0a84ff; + --accent-ink: #005ad6; + --shadow: 0 20px 60px rgba(17, 19, 24, 0.08); +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + font-family: "SF Pro Text", "SF Pro Display", "Helvetica Neue", "Segoe UI", sans-serif; + background: radial-gradient(circle at top, #ffffff 0%, var(--bg) 60%); + color: var(--text); +} + +.page { + max-width: 1200px; + margin: 0 auto; + padding: 48px 28px 72px; +} + +.topbar { + display: grid; + grid-template-columns: minmax(240px, 1.2fr) minmax(280px, 0.8fr); + gap: 32px; + align-items: stretch; + margin-bottom: 36px; +} + +.header-actions { + display: grid; + gap: 16px; + justify-items: end; +} + +.header-actions .quick-actions { + width: 100%; +} + +.header-actions #theme-toggle { + justify-self: end; +} + +.brand h1 { + font-size: clamp(2.2rem, 4vw, 3.2rem); + letter-spacing: -0.02em; +} + +.eyebrow { + text-transform: uppercase; + letter-spacing: 0.2em; + font-size: 0.68rem; + color: var(--muted); +} + +.lede { + margin-top: 12px; + font-size: 1rem; + color: var(--muted); +} + +.lede.small { + font-size: 0.85rem; +} + +.card { + background: var(--panel); + padding: 22px; + border-radius: 22px; + border: 1px solid var(--border); + box-shadow: var(--shadow); +} + +.quick-actions h2 { + margin-bottom: 14px; + font-size: 1.1rem; +} + +.layout { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); + gap: 24px; +} + +.column { + display: grid; + gap: 24px; +} + +.logs-panel { + margin-top: 28px; +} + +.card-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-bottom: 16px; +} + +.card-header h3 { + font-size: 1.1rem; +} + +.log-actions { + display: flex; + align-items: center; + gap: 12px; +} + +form { + display: grid; + gap: 12px; +} + +label { + display: grid; + gap: 6px; + font-size: 0.85rem; + color: var(--muted); +} + +input, +textarea, +button { + font: inherit; +} + +input, +textarea { + padding: 10px 12px; + border-radius: 12px; + border: 1px solid var(--border); + background: #fff; +} + +button { + border: none; + padding: 10px 16px; + border-radius: 12px; + background: var(--accent); + color: #fff; + font-weight: 600; + cursor: pointer; + transition: transform 0.2s ease, background 0.2s ease; +} + +button:hover { + transform: translateY(-1px); + background: var(--accent-ink); +} + +button.ghost { + background: transparent; + color: var(--accent); + border: 1px solid rgba(10, 132, 255, 0.4); + padding: 8px 12px; +} + +.list { + list-style: none; + padding: 0; + margin: 0; + display: grid; + gap: 10px; +} + +.list li { + padding: 12px; + border-radius: 14px; + background: var(--panel-muted); + border: 1px solid var(--border); + font-family: "SF Mono", "JetBrains Mono", "Menlo", monospace; + font-size: 0.85rem; +} + +.list li.active { + border-color: rgba(10, 132, 255, 0.4); + background: #eef5ff; +} + +.model-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; +} + +.badge { + display: inline-block; + padding: 4px 8px; + border-radius: 999px; + background: var(--accent); + color: #fff; + font-size: 0.7rem; + font-weight: 600; +} + +.badge.muted { + background: rgba(17, 19, 24, 0.1); + color: var(--muted); +} + +.status { + margin-bottom: 12px; + font-size: 0.9rem; + color: var(--muted); +} + +.status.ok { + color: #1a7f37; +} + +.status.error { + color: #b02a14; +} + +.downloads { + display: grid; + gap: 12px; +} + +.download-card { + border-radius: 16px; + border: 1px solid var(--border); + padding: 12px; + background: #f7f8fb; +} + +.download-card strong { + display: block; + font-size: 0.9rem; + margin-bottom: 6px; +} + +.progress { + height: 8px; + border-radius: 999px; + background: #dfe3ea; + overflow: hidden; + margin: 8px 0; +} + +.progress > span { + display: block; + height: 100%; + background: var(--accent); + width: 0; +} + +.error { + color: #b02a14; + font-size: 0.85rem; +} + +.config-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); + gap: 14px; +} + +.config-wide { + grid-column: 1 / -1; +} + +textarea { + padding: 10px 12px; + border-radius: 12px; + border: 1px solid var(--border); + font-family: "SF Mono", "JetBrains Mono", "Menlo", monospace; + font-size: 0.85rem; + resize: vertical; +} + +.log-output { + background: #0f141b; + color: #dbe6f3; + padding: 16px; + border-radius: 16px; + min-height: 260px; + max-height: 420px; + overflow: auto; + font-size: 12px; + line-height: 1.6; + white-space: pre-wrap; +} + +[data-theme="dark"] { + --bg: #0b0d12; + --panel: #141824; + --panel-muted: #1b2132; + --text: #f1f4f9; + --muted: #a5afc2; + --border: rgba(241, 244, 249, 0.1); + --accent: #4aa3ff; + --accent-ink: #1f7ae0; + --shadow: 0 20px 60px rgba(0, 0, 0, 0.4); +} + +[data-theme="dark"] body { + background: radial-gradient(circle at top, #131826 0%, var(--bg) 60%); +} + +[data-theme="dark"] .download-card { + background: #121826; +} + +[data-theme="dark"] .progress { + background: #2a3349; +} + +[data-theme="dark"] .log-output { + background: #080b12; + color: #d8e4f3; +} + +@media (max-width: 900px) { + .topbar { + grid-template-columns: 1fr; + } +} + +@media (max-width: 640px) { + .page { + padding: 32px 16px 48px; + } +} diff --git a/llamaCpp.Wrapper.app/warmup.py b/llamaCpp.Wrapper.app/warmup.py new file mode 100644 index 0000000..ffc8da6 --- /dev/null +++ b/llamaCpp.Wrapper.app/warmup.py @@ -0,0 +1,74 @@ +import asyncio +import logging +import time +from pathlib import Path + +import httpx + + +log = logging.getLogger("llamacpp_warmup") + + +def _is_loading_error(response: httpx.Response) -> bool: + if response.status_code != 503: + return False + try: + payload = response.json() + except Exception: + return False + message = "" + if isinstance(payload, dict): + error = payload.get("error") + if isinstance(error, dict): + message = str(error.get("message") or "") + else: + message = str(payload.get("message") or "") + return "loading model" in message.lower() + + +def resolve_warmup_prompt(override: str | None, fallback_path: str) -> str: + if override: + prompt = override.strip() + if prompt: + return prompt + try: + prompt = Path(fallback_path).read_text(encoding="utf-8").strip() + if prompt: + return prompt + except Exception as exc: + log.warning("Failed to read warmup prompt from %s: %s", fallback_path, exc) + return "ok" + + +async def run_warmup(base_url: str, model_id: str, prompt: str, timeout_s: float) -> None: + payload = { + "model": model_id, + "messages": [{"role": "user", "content": prompt}], + "max_tokens": 8, + "temperature": 0, + } + async with httpx.AsyncClient(base_url=base_url, timeout=timeout_s) as client: + resp = await client.post("/v1/chat/completions", json=payload) + if resp.status_code == 503 and _is_loading_error(resp): + raise RuntimeError("llama.cpp still loading model") + resp.raise_for_status() + + +async def run_warmup_with_retry( + base_url: str, + model_id: str, + prompt: str, + timeout_s: float, + interval_s: float = 3.0, +) -> None: + deadline = time.time() + timeout_s + last_exc: Exception | None = None + while time.time() < deadline: + try: + await run_warmup(base_url, model_id, prompt, timeout_s=timeout_s) + return + except Exception as exc: + last_exc = exc + await asyncio.sleep(interval_s) + if last_exc: + raise last_exc diff --git a/llamacpp_remote_test.ps1 b/llamacpp_remote_test.ps1 new file mode 100644 index 0000000..af089ee --- /dev/null +++ b/llamacpp_remote_test.ps1 @@ -0,0 +1,464 @@ +param( + [Parameter(Mandatory = $true)][string]$Model, + [string]$BaseUrl = "http://192.168.1.2:8071", + [string]$PromptPath = "prompt_crwv.txt", + [int]$Runs = 3, + [int]$MaxTokens = 2000, + [int]$NumCtx = 131072, + [int]$TopK = 1, + [double]$TopP = 1.0, + [int]$Seed = 42, + [double]$RepeatPenalty = 1.05, + [double]$Temperature = 0, + [string]$JsonSchema = "", + [int]$TimeoutSec = 1800, + [string]$BatchId, + [switch]$EnableGpuMonitor = $true, + [string]$SshExe = "$env:SystemRoot\\System32\\OpenSSH\\ssh.exe", + [string]$SshUser = "rushabh", + [string]$SshHost = "192.168.1.2", + [int]$SshPort = 55555, + [int]$GpuMonitorIntervalSec = 1, + [int]$GpuMonitorSeconds = 120 +) + +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" + +function Normalize-Strike([object]$value) { + if ($null -eq $value) { return $null } + if ($value -is [double] -or $value -is [float] -or $value -is [int] -or $value -is [long]) { + return ([double]$value).ToString("0.################", [System.Globalization.CultureInfo]::InvariantCulture) + } + return ($value.ToString().Trim()) +} + +function Get-AllowedLegs([string]$promptText) { + $pattern = 'Options Chain\s*```\s*(\[[\s\S]*?\])\s*```' + $match = [regex]::Match($promptText, $pattern, [System.Text.RegularExpressions.RegexOptions]::Singleline) + if (-not $match.Success) { + throw "Options Chain JSON block not found in prompt." + } + $chains = $match.Groups[1].Value | ConvertFrom-Json + $allowedExpiry = @{} + $allowedLegs = @{} + foreach ($exp in $chains) { + $expiry = [string]$exp.expiry + if ([string]::IsNullOrWhiteSpace($expiry)) { continue } + $allowedExpiry[$expiry] = $true + foreach ($leg in $exp.liquidSet) { + if ($null -eq $leg) { continue } + if ($leg.liquid -ne $true) { continue } + $side = [string]$leg.side + $strikeNorm = Normalize-Strike $leg.strike + if (-not [string]::IsNullOrWhiteSpace($side) -and $strikeNorm) { + $key = "$expiry|$side|$strikeNorm" + $allowedLegs[$key] = $true + } + } + } + return @{ AllowedExpiry = $allowedExpiry; AllowedLegs = $allowedLegs } +} + +function Test-TradeSchema($obj, $allowedExpiry, $allowedLegs) { + $errors = New-Object System.Collections.Generic.List[string] + + $requiredTop = @("selectedExpiry", "expiryRationale", "strategyBias", "recommendedTrades", "whyOthersRejected", "confidenceScore") + foreach ($key in $requiredTop) { + if (-not ($obj.PSObject.Properties.Name -contains $key)) { + $errors.Add("Missing top-level key: $key") + } + } + + if ($obj.strategyBias -and ($obj.strategyBias -notin @("DIRECTIONAL","VOLATILITY","NEUTRAL","NO_TRADE"))) { + $errors.Add("Invalid strategyBias: $($obj.strategyBias)") + } + + if (-not [string]::IsNullOrWhiteSpace([string]$obj.selectedExpiry)) { + if (-not $allowedExpiry.ContainsKey([string]$obj.selectedExpiry)) { + $errors.Add("selectedExpiry not in provided expiries: $($obj.selectedExpiry)") + } + } else { + $errors.Add("selectedExpiry is missing or empty") + } + + if ($obj.confidenceScore -ne $null) { + if (-not ($obj.confidenceScore -is [double] -or $obj.confidenceScore -is [int])) { + $errors.Add("confidenceScore is not numeric") + } elseif ($obj.confidenceScore -lt 0 -or $obj.confidenceScore -gt 100) { + $errors.Add("confidenceScore out of range 0-100") + } + } + + if ($obj.recommendedTrades -eq $null) { + $errors.Add("recommendedTrades is null") + } elseif (-not ($obj.recommendedTrades -is [System.Collections.IEnumerable])) { + $errors.Add("recommendedTrades is not an array") + } + + if ($obj.strategyBias -eq "NO_TRADE") { + if ($obj.recommendedTrades -and $obj.recommendedTrades.Count -gt 0) { + $errors.Add("strategyBias is NO_TRADE but recommendedTrades is not empty") + } + } else { + if (-not $obj.recommendedTrades -or $obj.recommendedTrades.Count -lt 1 -or $obj.recommendedTrades.Count -gt 3) { + $errors.Add("recommendedTrades must contain 1-3 trades") + } + } + + if ($obj.whyOthersRejected -ne $null -and -not ($obj.whyOthersRejected -is [System.Collections.IEnumerable])) { + $errors.Add("whyOthersRejected is not an array") + } + + if ($obj.recommendedTrades) { + foreach ($trade in $obj.recommendedTrades) { + $tradeRequired = @("name","structure","legs","greekProfile","maxRisk","maxReward","thesisAlignment","invalidation") + foreach ($tkey in $tradeRequired) { + if (-not ($trade.PSObject.Properties.Name -contains $tkey)) { + $errors.Add("Trade missing key: $tkey") + } + } + + if ([string]::IsNullOrWhiteSpace([string]$trade.name)) { $errors.Add("Trade name is empty") } + if ([string]::IsNullOrWhiteSpace([string]$trade.structure)) { $errors.Add("Trade structure is empty") } + if ([string]::IsNullOrWhiteSpace([string]$trade.thesisAlignment)) { $errors.Add("Trade thesisAlignment is empty") } + if ([string]::IsNullOrWhiteSpace([string]$trade.invalidation)) { $errors.Add("Trade invalidation is empty") } + if ($trade.maxRisk -eq $null -or [string]::IsNullOrWhiteSpace([string]$trade.maxRisk)) { $errors.Add("Trade maxRisk is empty") } + if ($trade.maxReward -eq $null -or [string]::IsNullOrWhiteSpace([string]$trade.maxReward)) { $errors.Add("Trade maxReward is empty") } + if ($trade.maxRisk -is [double] -or $trade.maxRisk -is [int]) { + if ($trade.maxRisk -le 0) { $errors.Add("Trade maxRisk must be > 0") } + } + if ($trade.maxReward -is [double] -or $trade.maxReward -is [int]) { + if ($trade.maxReward -le 0) { $errors.Add("Trade maxReward must be > 0") } + } + + if (-not $trade.legs -or -not ($trade.legs -is [System.Collections.IEnumerable])) { + $errors.Add("Trade legs missing or not an array") + continue + } + + $legs = @($trade.legs) + + $hasBuy = $false + $hasSell = $false + foreach ($leg in $trade.legs) { + $side = ([string]$leg.side).ToLowerInvariant() + $action = ([string]$leg.action).ToLowerInvariant() + $expiry = [string]$leg.expiry + $strikeNorm = Normalize-Strike $leg.strike + + if ($side -notin @("call","put")) { $errors.Add("Invalid leg side: $side") } + if ($action -notin @("buy","sell")) { $errors.Add("Invalid leg action: $action") } + if (-not $allowedExpiry.ContainsKey($expiry)) { $errors.Add("Leg expiry not allowed: $expiry") } + if (-not $strikeNorm) { $errors.Add("Leg strike missing") } else { + $key = "$expiry|$side|$strikeNorm" + if (-not $allowedLegs.ContainsKey($key)) { + $errors.Add("Leg not in liquid set: $key") + } + } + + if ($action -eq "buy") { $hasBuy = $true } + if ($action -eq "sell") { $hasSell = $true } + } + + if ($obj.selectedExpiry -and $legs) { + foreach ($leg in $legs) { + if ([string]$leg.expiry -ne [string]$obj.selectedExpiry) { + $errors.Add("Leg expiry does not match selectedExpiry: $($leg.expiry)") + } + } + } + + if ($hasSell -and -not $hasBuy) { + $errors.Add("Naked short detected: trade has sell leg(s) with no buy leg") + } + + if ($trade.greekProfile) { + $gp = $trade.greekProfile + $gpRequired = @("deltaBias","gammaExposure","thetaExposure","vegaExposure") + foreach ($gkey in $gpRequired) { + if (-not ($gp.PSObject.Properties.Name -contains $gkey)) { + $errors.Add("Missing greekProfile.$gkey") + } + } + if ($gp.deltaBias -and ($gp.deltaBias -notin @("POS","NEG","NEUTRAL"))) { $errors.Add("Invalid deltaBias") } + if ($gp.gammaExposure -and ($gp.gammaExposure -notin @("HIGH","MED","LOW"))) { $errors.Add("Invalid gammaExposure") } + if ($gp.thetaExposure -and ($gp.thetaExposure -notin @("POS","NEG","LOW"))) { $errors.Add("Invalid thetaExposure") } + if ($gp.vegaExposure -and ($gp.vegaExposure -notin @("HIGH","MED","LOW"))) { $errors.Add("Invalid vegaExposure") } + + if (-not $hasSell -and $gp.thetaExposure -eq "POS") { + $errors.Add("ThetaExposure POS on all-long legs") + } + } else { + $errors.Add("Missing greekProfile") + } + + $structure = ([string]$trade.structure).ToLowerInvariant() + $tradeName = ([string]$trade.name).ToLowerInvariant() + $isStraddle = $structure -match "straddle" -or $tradeName -match "straddle" + $isStrangle = $structure -match "strangle" -or $tradeName -match "strangle" + $isCallDebit = ($structure -match "call") -and ($structure -match "debit") -and ($structure -match "spread") + $isPutDebit = ($structure -match "put") -and ($structure -match "debit") -and ($structure -match "spread") + + if ($isStraddle -or $isStrangle) { + if ($legs.Count -ne 2) { $errors.Add("Straddle/Strangle must have exactly 2 legs") } + $callLegs = $legs | Where-Object { $_.side -eq "call" } + $putLegs = $legs | Where-Object { $_.side -eq "put" } + if ($callLegs.Count -ne 1 -or $putLegs.Count -ne 1) { $errors.Add("Straddle/Strangle must have 1 call and 1 put") } + if ($callLegs.Count -eq 1 -and $putLegs.Count -eq 1) { + $callStrike = Normalize-Strike $callLegs[0].strike + $putStrike = Normalize-Strike $putLegs[0].strike + if ($isStraddle -and $callStrike -ne $putStrike) { $errors.Add("Straddle strikes must match") } + if ($isStrangle) { + try { + if ([double]$callStrike -le [double]$putStrike) { $errors.Add("Strangle call strike must be above put strike") } + } catch { + $errors.Add("Strangle strike comparison failed") + } + } + if ($callLegs[0].action -ne "buy" -or $putLegs[0].action -ne "buy") { + $errors.Add("Straddle/Strangle must be long (buy) legs") + } + } + if ($trade.greekProfile -and $trade.greekProfile.deltaBias -and $trade.greekProfile.deltaBias -ne "NEUTRAL") { + $errors.Add("DeltaBias must be NEUTRAL for straddle/strangle") + } + } + + if ($isCallDebit) { + $callLegs = $legs | Where-Object { $_.side -eq "call" } + if ($callLegs.Count -ne 2) { $errors.Add("Call debit spread must have 2 call legs") } + $buy = $callLegs | Where-Object { $_.action -eq "buy" } + $sell = $callLegs | Where-Object { $_.action -eq "sell" } + if ($buy.Count -ne 1 -or $sell.Count -ne 1) { $errors.Add("Call debit spread must have 1 buy and 1 sell") } + if ($buy.Count -eq 1 -and $sell.Count -eq 1) { + try { + if ([double](Normalize-Strike $buy[0].strike) -ge [double](Normalize-Strike $sell[0].strike)) { + $errors.Add("Call debit spread buy strike must be below sell strike") + } + } catch { + $errors.Add("Call debit spread strike comparison failed") + } + } + } + + if ($isPutDebit) { + $putLegs = $legs | Where-Object { $_.side -eq "put" } + if ($putLegs.Count -ne 2) { $errors.Add("Put debit spread must have 2 put legs") } + $buy = $putLegs | Where-Object { $_.action -eq "buy" } + $sell = $putLegs | Where-Object { $_.action -eq "sell" } + if ($buy.Count -ne 1 -or $sell.Count -ne 1) { $errors.Add("Put debit spread must have 1 buy and 1 sell") } + if ($buy.Count -eq 1 -and $sell.Count -eq 1) { + try { + if ([double](Normalize-Strike $buy[0].strike) -le [double](Normalize-Strike $sell[0].strike)) { + $errors.Add("Put debit spread buy strike must be above sell strike") + } + } catch { + $errors.Add("Put debit spread strike comparison failed") + } + } + } + } + } + + return $errors +} + +function Parse-GpuLog { + param([string]$Path) + $summary = [ordered]@{ gpu0Used = $false; gpu1Used = $false; samples = 0; error = $null } + if (-not (Test-Path $Path)) { + $summary.error = "gpu log missing" + return $summary + } + $lines = Get-Content -Path $Path + $currentIndex = -1 + $gpuIndex = -1 + $inUtilBlock = $false + foreach ($line in $lines) { + if ($line -match '^Timestamp') { + $gpuIndex = -1 + $currentIndex = -1 + $inUtilBlock = $false + continue + } + if ($line -match '^GPU\\s+[0-9A-Fa-f:.]+$') { + $gpuIndex += 1 + $currentIndex = $gpuIndex + $inUtilBlock = $false + continue + } + if ($line -match '^\\s*Utilization\\s*$') { + $inUtilBlock = $true + continue + } + if ($inUtilBlock -and $line -match '^\\s*GPU\\s*:\\s*([0-9]+)\\s*%') { + $util = [int]$Matches[1] + if ($currentIndex -eq 0 -and $util -gt 0) { $summary.gpu0Used = $true } + if ($currentIndex -eq 1 -and $util -gt 0) { $summary.gpu1Used = $true } + $summary.samples += 1 + } + } + return $summary +} + +$prompt = [string](Get-Content -Raw -Path $PromptPath) +$allowed = Get-AllowedLegs -promptText $prompt +$allowedExpiry = $allowed.AllowedExpiry +$allowedLegs = $allowed.AllowedLegs + +if ([string]::IsNullOrWhiteSpace($BatchId)) { + $BatchId = (Get-Date).ToString("yyyyMMdd_HHmmss") +} + +$outBase = Join-Path -Path (Get-Location) -ChildPath "llamacpp_runs_remote" +if (-not (Test-Path $outBase)) { New-Item -ItemType Directory -Path $outBase | Out-Null } + +$safeModel = $Model -replace '[\\/:*?"<>|]', '_' +$batchDir = Join-Path -Path $outBase -ChildPath ("batch_{0}" -f $BatchId) +if (-not (Test-Path $batchDir)) { New-Item -ItemType Directory -Path $batchDir | Out-Null } + +$outDir = Join-Path -Path $batchDir -ChildPath $safeModel +if (-not (Test-Path $outDir)) { New-Item -ItemType Directory -Path $outDir | Out-Null } + +$summary = [ordered]@{ + model = $Model + baseUrl = $BaseUrl + batchId = $BatchId + params = [ordered]@{ + temperature = $Temperature + top_k = $TopK + top_p = $TopP + seed = $Seed + repeat_penalty = $RepeatPenalty + max_tokens = $MaxTokens + num_ctx = $NumCtx + } + gpuMonitor = [ordered]@{ + enabled = [bool]$EnableGpuMonitor + sshHost = $SshHost + sshPort = $SshPort + intervalSec = $GpuMonitorIntervalSec + durationSec = $GpuMonitorSeconds + } + modelMeta = $null + runs = @() +} + +if (-not [string]::IsNullOrWhiteSpace($JsonSchema)) { + try { + $schemaObject = $JsonSchema | ConvertFrom-Json + } catch { + throw "JsonSchema is not valid JSON: $($_.Exception.Message)" + } +} + +try { + $modelsResponse = Invoke-RestMethod -Uri "$BaseUrl/v1/models" -TimeoutSec 30 + $meta = $modelsResponse.data | Where-Object { $_.id -eq $Model } | Select-Object -First 1 + if ($meta) { $summary.modelMeta = $meta.meta } +} catch { + $summary.modelMeta = @{ error = $_.Exception.Message } +} + +for ($i = 1; $i -le $Runs; $i++) { + Write-Host "Running $Model (run $i/$Runs)" + + $runResult = [ordered]@{ run = $i; ok = $false; errors = @() } + $gpuJob = $null + $gpuLogPath = $null + + if ($EnableGpuMonitor) { + $samples = [math]::Max(5, [int]([math]::Ceiling($GpuMonitorSeconds / [double]$GpuMonitorIntervalSec))) + $gpuLogPath = Join-Path $outDir ("gpu_run{0}.csv" -f $i) + $sshTarget = "{0}@{1}" -f $SshUser, $SshHost + $gpuJob = Start-Job -ScriptBlock { + param($sshExe, $target, $port, $samples, $interval, $logPath) + for ($s = 1; $s -le $samples; $s++) { + Add-Content -Path $logPath -Value ("=== SAMPLE {0} {1}" -f $s, (Get-Date).ToString('s')) + try { + $out = & $sshExe -p $port $target "nvidia-smi -q -d UTILIZATION" + Add-Content -Path $logPath -Value $out + } catch { + Add-Content -Path $logPath -Value ("GPU monitor error: $($_.Exception.Message)") + } + Start-Sleep -Seconds $interval + } + } -ArgumentList $SshExe, $sshTarget, $SshPort, $samples, $GpuMonitorIntervalSec, $gpuLogPath + Start-Sleep -Seconds 1 + } + + $body = @{ + model = $Model + messages = @(@{ role = "user"; content = $prompt }) + temperature = $Temperature + top_k = $TopK + top_p = $TopP + seed = $Seed + repeat_penalty = $RepeatPenalty + max_tokens = $MaxTokens + } + + if ($schemaObject) { + $body.response_format = @{ + type = "json_schema" + json_schema = @{ + name = "trade_schema" + schema = $schemaObject + strict = $true + } + } + } + + $body = $body | ConvertTo-Json -Depth 12 + + try { + $resp = Invoke-RestMethod -Uri "$BaseUrl/v1/chat/completions" -Method Post -Body $body -ContentType "application/json" -TimeoutSec $TimeoutSec + } catch { + $runResult.errors = @("API error: $($_.Exception.Message)") + $summary.runs += $runResult + if ($gpuJob) { Stop-Job -Job $gpuJob | Out-Null } + continue + } finally { + if ($gpuJob) { + Wait-Job -Job $gpuJob -Timeout 5 | Out-Null + if ($gpuJob.State -eq "Running") { Stop-Job -Job $gpuJob | Out-Null } + Remove-Job -Job $gpuJob | Out-Null + } + } + + $raw = [string]$resp.choices[0].message.content + + $jsonPath = Join-Path $outDir ("run{0}.json" -f $i) + Set-Content -Path $jsonPath -Value $raw -Encoding ASCII + + try { + $parsed = $raw | ConvertFrom-Json + $errors = Test-TradeSchema -obj $parsed -allowedExpiry $allowedExpiry -allowedLegs $allowedLegs + if ($errors.Count -eq 0) { + $runResult.ok = $true + } else { + $runResult.errors = $errors + } + } catch { + $runResult.errors = @("Invalid JSON: $($_.Exception.Message)") + } + + if ($gpuLogPath) { + $runResult.gpuLog = $gpuLogPath + $runResult.gpuUsage = Parse-GpuLog -Path $gpuLogPath + } + if ($resp.timings) { + $runResult.timings = $resp.timings + } + if ($resp.usage) { + $runResult.usage = $resp.usage + } + + $summary.runs += $runResult +} + +$summaryPath = Join-Path $outDir "summary.json" +$summary | ConvertTo-Json -Depth 6 | Set-Content -Path $summaryPath -Encoding ASCII + +$summary | ConvertTo-Json -Depth 6 diff --git a/llamacpp_set_command.ps1 b/llamacpp_set_command.ps1 new file mode 100644 index 0000000..82b514a --- /dev/null +++ b/llamacpp_set_command.ps1 @@ -0,0 +1,117 @@ +param( + [Parameter(Mandatory = $true)][string]$ModelPath, + [Parameter(Mandatory = $true)][int]$CtxSize, + [int]$BatchSize = 1024, + [int]$UBatchSize = 256, + [string]$TensorSplit = "0.5,0.5", + [string]$Devices = "0,1", + [int]$GpuLayers = 999, + [string]$CacheTypeK = "q4_0", + [string]$CacheTypeV = "q4_0", + [string]$GrammarFile = "", + [string]$JsonSchema = "", + [string]$BaseUrl = "http://192.168.1.2:8071", + [int]$TimeoutSec = 600, + [string]$SshExe = "$env:SystemRoot\\System32\\OpenSSH\\ssh.exe", + [string]$SshUser = "rushabh", + [string]$SshHost = "192.168.1.2", + [int]$SshPort = 55555 +) + +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" + +$commandArgs = @( + "--model", $ModelPath, + "--ctx-size", $CtxSize.ToString(), + "--n-gpu-layers", $GpuLayers.ToString(), + "--split-mode", "layer", + "--tensor-split", $TensorSplit, + "--batch-size", $BatchSize.ToString(), + "--ubatch-size", $UBatchSize.ToString(), + "--cache-type-k", $CacheTypeK, + "--cache-type-v", $CacheTypeV, + "--flash-attn", "on" +) + +if (-not [string]::IsNullOrWhiteSpace($Devices)) { + $commandArgs = @("--device", $Devices) + $commandArgs +} + +if (-not [string]::IsNullOrWhiteSpace($GrammarFile)) { + $commandArgs += @("--grammar-file", $GrammarFile) +} + +if (-not [string]::IsNullOrWhiteSpace($JsonSchema)) { + $commandArgs += @("--json-schema", $JsonSchema) +} + +$argJson = $commandArgs | ConvertTo-Json -Compress + +$py = @" +import json +path = r"/mnt/.ix-apps/app_configs/llamacpp/versions/1.2.17/user_config.yaml" +new_cmd = json.loads(r'''$argJson''') +lines = open(path, "r", encoding="utf-8").read().splitlines() +out = [] +in_cmd = False +def yaml_quote(value): + text = str(value) + return "'" + text.replace("'", "''") + "'" +for line in lines: + if line.startswith('"command":'): + out.append('"command":') + for arg in new_cmd: + out.append(f"- {yaml_quote(arg)}") + in_cmd = True + continue + if in_cmd: + if line.startswith('"') and not line.startswith('"command":'): + in_cmd = False + out.append(line) + else: + continue + else: + out.append(line) +if in_cmd: + pass +open(path, "w", encoding="utf-8").write("\n".join(out) + "\n") +"@ + +$py | & $SshExe -p $SshPort "$SshUser@$SshHost" "sudo -n python3 -" + +$pyCompose = @" +import json, yaml, subprocess +compose_path = "/mnt/.ix-apps/app_configs/llamacpp/versions/1.2.17/templates/rendered/docker-compose.yaml" +user_config_path = "/mnt/.ix-apps/app_configs/llamacpp/versions/1.2.17/user_config.yaml" +with open(compose_path, "r", encoding="utf-8") as f: + compose = json.load(f) +with open(user_config_path, "r", encoding="utf-8") as f: + config = yaml.safe_load(f) +command = config.get("command") +if not command: + raise SystemExit("command list missing from user_config") +svc = compose["services"]["llamacpp"] +svc["command"] = command +with open(compose_path, "w", encoding="utf-8") as f: + json.dump(compose, f) +payload = {"custom_compose_config": compose} +subprocess.run(["midclt", "call", "app.update", "llamacpp", json.dumps(payload)], check=True) +"@ + +$pyCompose | & $SshExe -p $SshPort "$SshUser@$SshHost" "sudo -n python3 -" | Out-Null + +$start = Get-Date +while ((Get-Date) - $start -lt [TimeSpan]::FromSeconds($TimeoutSec)) { + try { + $resp = Invoke-RestMethod -Uri "$BaseUrl/health" -TimeoutSec 10 + if ($resp.status -eq "ok") { + Write-Host "llamacpp healthy at $BaseUrl" + exit 0 + } + } catch { + Start-Sleep -Seconds 5 + } +} + +throw "Timed out waiting for llama.cpp server at $BaseUrl" diff --git a/modelfiles/options-json-deepseek14b.Modelfile b/modelfiles/options-json-deepseek14b.Modelfile new file mode 100644 index 0000000..9efb7c2 --- /dev/null +++ b/modelfiles/options-json-deepseek14b.Modelfile @@ -0,0 +1,14 @@ +FROM deepseek-r1:14b +SYSTEM """ +You are a senior quantitative options trader specializing in index and ETF options. +Return ONLY a single valid JSON object that matches the exact schema described in the user prompt. +No markdown, no code fences, no commentary, no extra keys, no trailing text. +Use ONLY strikes/expiries from the provided options chain; do NOT invent data. +If no trade qualifies, set "strategyBias" to "NO_TRADE" and "recommendedTrades" to []. +Begin output with { and end with }. +""" +PARAMETER temperature 0 +PARAMETER top_k 1 +PARAMETER top_p 1 +PARAMETER repeat_penalty 1.05 +PARAMETER seed 42 diff --git a/modelfiles/options-json-llama31-70b.Modelfile b/modelfiles/options-json-llama31-70b.Modelfile new file mode 100644 index 0000000..e435d5a --- /dev/null +++ b/modelfiles/options-json-llama31-70b.Modelfile @@ -0,0 +1,14 @@ +FROM llama3.1:70b +SYSTEM """ +You are a senior quantitative options trader specializing in index and ETF options. +Return ONLY a single valid JSON object that matches the exact schema described in the user prompt. +No markdown, no code fences, no commentary, no extra keys, no trailing text. +Use ONLY strikes/expiries from the provided options chain; do NOT invent data. +If no trade qualifies, set "strategyBias" to "NO_TRADE" and "recommendedTrades" to []. +Begin output with { and end with }. +""" +PARAMETER temperature 0 +PARAMETER top_k 1 +PARAMETER top_p 1 +PARAMETER repeat_penalty 1.05 +PARAMETER seed 42 diff --git a/modelfiles/options-json-phi3mini.Modelfile b/modelfiles/options-json-phi3mini.Modelfile new file mode 100644 index 0000000..c1c7509 --- /dev/null +++ b/modelfiles/options-json-phi3mini.Modelfile @@ -0,0 +1,14 @@ +FROM phi3:mini-128k +SYSTEM """ +You are a senior quantitative options trader specializing in index and ETF options. +Return ONLY a single valid JSON object that matches the exact schema described in the user prompt. +No markdown, no code fences, no commentary, no extra keys, no trailing text. +Use ONLY strikes/expiries from the provided options chain; do NOT invent data. +If no trade qualifies, set "strategyBias" to "NO_TRADE" and "recommendedTrades" to []. +Begin output with { and end with }. +""" +PARAMETER temperature 0 +PARAMETER top_k 1 +PARAMETER top_p 1 +PARAMETER repeat_penalty 1.05 +PARAMETER seed 42 diff --git a/ollama_remote_test.ps1 b/ollama_remote_test.ps1 new file mode 100644 index 0000000..fea07e1 --- /dev/null +++ b/ollama_remote_test.ps1 @@ -0,0 +1,561 @@ +param( + [Parameter(Mandatory = $true)][string]$Model, + [string]$BaseUrl = "http://192.168.1.2:30068", + [string]$PromptPath = "prompt_crwv.txt", + [int]$Runs = 3, + [int]$NumPredict = 1200, + [int]$NumCtx = 131072, + [int]$NumBatch = 0, + [int]$NumGpuLayers = 0, + [int]$TimeoutSec = 900, + [int]$TopK = 1, + [double]$TopP = 1.0, + [int]$Seed = 42, + [double]$RepeatPenalty = 1.05, + [string]$BatchId, + [switch]$UseSchemaFormat = $false, + [switch]$EnableGpuMonitor = $true, + [string]$SshExe = "$env:SystemRoot\\System32\\OpenSSH\\ssh.exe", + [switch]$CheckProcessor = $true, + [string]$SshUser = "rushabh", + [string]$SshHost = "192.168.1.2", + [int]$SshPort = 55555, + [int]$GpuMonitorIntervalSec = 1, + [int]$GpuMonitorSeconds = 120 +) + +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" + +function Normalize-Strike([object]$value) { + if ($null -eq $value) { return $null } + if ($value -is [double] -or $value -is [float] -or $value -is [int] -or $value -is [long]) { + return ([double]$value).ToString("0.################", [System.Globalization.CultureInfo]::InvariantCulture) + } + return ($value.ToString().Trim()) +} + +function Get-AllowedLegs([string]$promptText) { + $pattern = 'Options Chain\s*```\s*(\[[\s\S]*?\])\s*```' + $match = [regex]::Match($promptText, $pattern, [System.Text.RegularExpressions.RegexOptions]::Singleline) + if (-not $match.Success) { + throw "Options Chain JSON block not found in prompt." + } + $chains = $match.Groups[1].Value | ConvertFrom-Json + $allowedExpiry = @{} + $allowedLegs = @{} + foreach ($exp in $chains) { + $expiry = [string]$exp.expiry + if ([string]::IsNullOrWhiteSpace($expiry)) { continue } + $allowedExpiry[$expiry] = $true + foreach ($leg in $exp.liquidSet) { + if ($null -eq $leg) { continue } + if ($leg.liquid -ne $true) { continue } + $side = [string]$leg.side + $strikeNorm = Normalize-Strike $leg.strike + if (-not [string]::IsNullOrWhiteSpace($side) -and $strikeNorm) { + $key = "$expiry|$side|$strikeNorm" + $allowedLegs[$key] = $true + } + } + } + return @{ AllowedExpiry = $allowedExpiry; AllowedLegs = $allowedLegs } +} + +function Test-TradeSchema($obj, $allowedExpiry, $allowedLegs) { + $errors = New-Object System.Collections.Generic.List[string] + + $requiredTop = @("selectedExpiry", "expiryRationale", "strategyBias", "recommendedTrades", "whyOthersRejected", "confidenceScore") + foreach ($key in $requiredTop) { + if (-not ($obj.PSObject.Properties.Name -contains $key)) { + $errors.Add("Missing top-level key: $key") + } + } + + if ($obj.strategyBias -and ($obj.strategyBias -notin @("DIRECTIONAL","VOLATILITY","NEUTRAL","NO_TRADE"))) { + $errors.Add("Invalid strategyBias: $($obj.strategyBias)") + } + + if (-not [string]::IsNullOrWhiteSpace([string]$obj.selectedExpiry)) { + if (-not $allowedExpiry.ContainsKey([string]$obj.selectedExpiry)) { + $errors.Add("selectedExpiry not in provided expiries: $($obj.selectedExpiry)") + } + } else { + $errors.Add("selectedExpiry is missing or empty") + } + + if ($obj.confidenceScore -ne $null) { + if (-not ($obj.confidenceScore -is [double] -or $obj.confidenceScore -is [int])) { + $errors.Add("confidenceScore is not numeric") + } elseif ($obj.confidenceScore -lt 0 -or $obj.confidenceScore -gt 100) { + $errors.Add("confidenceScore out of range 0-100") + } + } + + if ($obj.recommendedTrades -eq $null) { + $errors.Add("recommendedTrades is null") + } elseif (-not ($obj.recommendedTrades -is [System.Collections.IEnumerable])) { + $errors.Add("recommendedTrades is not an array") + } + + if ($obj.strategyBias -eq "NO_TRADE") { + if ($obj.recommendedTrades -and $obj.recommendedTrades.Count -gt 0) { + $errors.Add("strategyBias is NO_TRADE but recommendedTrades is not empty") + } + } else { + if (-not $obj.recommendedTrades -or $obj.recommendedTrades.Count -lt 1 -or $obj.recommendedTrades.Count -gt 3) { + $errors.Add("recommendedTrades must contain 1-3 trades") + } + } + + if ($obj.whyOthersRejected -ne $null -and -not ($obj.whyOthersRejected -is [System.Collections.IEnumerable])) { + $errors.Add("whyOthersRejected is not an array") + } + + if ($obj.recommendedTrades) { + foreach ($trade in $obj.recommendedTrades) { + $tradeRequired = @("name","structure","legs","greekProfile","maxRisk","maxReward","thesisAlignment","invalidation") + foreach ($tkey in $tradeRequired) { + if (-not ($trade.PSObject.Properties.Name -contains $tkey)) { + $errors.Add("Trade missing key: $tkey") + } + } + + if ([string]::IsNullOrWhiteSpace([string]$trade.name)) { $errors.Add("Trade name is empty") } + if ([string]::IsNullOrWhiteSpace([string]$trade.structure)) { $errors.Add("Trade structure is empty") } + if ([string]::IsNullOrWhiteSpace([string]$trade.thesisAlignment)) { $errors.Add("Trade thesisAlignment is empty") } + if ([string]::IsNullOrWhiteSpace([string]$trade.invalidation)) { $errors.Add("Trade invalidation is empty") } + if ($trade.maxRisk -eq $null -or [string]::IsNullOrWhiteSpace([string]$trade.maxRisk)) { $errors.Add("Trade maxRisk is empty") } + if ($trade.maxReward -eq $null -or [string]::IsNullOrWhiteSpace([string]$trade.maxReward)) { $errors.Add("Trade maxReward is empty") } + if ($trade.maxRisk -is [double] -or $trade.maxRisk -is [int]) { + if ($trade.maxRisk -le 0) { $errors.Add("Trade maxRisk must be > 0") } + } + if ($trade.maxReward -is [double] -or $trade.maxReward -is [int]) { + if ($trade.maxReward -le 0) { $errors.Add("Trade maxReward must be > 0") } + } + + if (-not $trade.legs -or -not ($trade.legs -is [System.Collections.IEnumerable])) { + $errors.Add("Trade legs missing or not an array") + continue + } + + $legs = @($trade.legs) + + $hasBuy = $false + $hasSell = $false + foreach ($leg in $trade.legs) { + $side = ([string]$leg.side).ToLowerInvariant() + $action = ([string]$leg.action).ToLowerInvariant() + $expiry = [string]$leg.expiry + $strikeNorm = Normalize-Strike $leg.strike + + if ($side -notin @("call","put")) { $errors.Add("Invalid leg side: $side") } + if ($action -notin @("buy","sell")) { $errors.Add("Invalid leg action: $action") } + if (-not $allowedExpiry.ContainsKey($expiry)) { $errors.Add("Leg expiry not allowed: $expiry") } + if (-not $strikeNorm) { $errors.Add("Leg strike missing") } else { + $key = "$expiry|$side|$strikeNorm" + if (-not $allowedLegs.ContainsKey($key)) { + $errors.Add("Leg not in liquid set: $key") + } + } + + if ($action -eq "buy") { $hasBuy = $true } + if ($action -eq "sell") { $hasSell = $true } + } + + if ($obj.selectedExpiry -and $legs) { + foreach ($leg in $legs) { + if ([string]$leg.expiry -ne [string]$obj.selectedExpiry) { + $errors.Add("Leg expiry does not match selectedExpiry: $($leg.expiry)") + } + } + } + + if ($hasSell -and -not $hasBuy) { + $errors.Add("Naked short detected: trade has sell leg(s) with no buy leg") + } + + if ($trade.greekProfile) { + $gp = $trade.greekProfile + $gpRequired = @("deltaBias","gammaExposure","thetaExposure","vegaExposure") + foreach ($gkey in $gpRequired) { + if (-not ($gp.PSObject.Properties.Name -contains $gkey)) { + $errors.Add("Missing greekProfile.$gkey") + } + } + if ($gp.deltaBias -and ($gp.deltaBias -notin @("POS","NEG","NEUTRAL"))) { $errors.Add("Invalid deltaBias") } + if ($gp.gammaExposure -and ($gp.gammaExposure -notin @("HIGH","MED","LOW"))) { $errors.Add("Invalid gammaExposure") } + if ($gp.thetaExposure -and ($gp.thetaExposure -notin @("POS","NEG","LOW"))) { $errors.Add("Invalid thetaExposure") } + if ($gp.vegaExposure -and ($gp.vegaExposure -notin @("HIGH","MED","LOW"))) { $errors.Add("Invalid vegaExposure") } + + if (-not $hasSell -and $gp.thetaExposure -eq "POS") { + $errors.Add("ThetaExposure POS on all-long legs") + } + } else { + $errors.Add("Missing greekProfile") + } + + $structure = ([string]$trade.structure).ToLowerInvariant() + $tradeName = ([string]$trade.name).ToLowerInvariant() + $isStraddle = $structure -match "straddle" -or $tradeName -match "straddle" + $isStrangle = $structure -match "strangle" -or $tradeName -match "strangle" + $isCallDebit = ($structure -match "call") -and ($structure -match "debit") -and ($structure -match "spread") + $isPutDebit = ($structure -match "put") -and ($structure -match "debit") -and ($structure -match "spread") + + if ($isStraddle -or $isStrangle) { + if ($legs.Count -ne 2) { $errors.Add("Straddle/Strangle must have exactly 2 legs") } + $callLegs = $legs | Where-Object { $_.side -eq "call" } + $putLegs = $legs | Where-Object { $_.side -eq "put" } + if ($callLegs.Count -ne 1 -or $putLegs.Count -ne 1) { $errors.Add("Straddle/Strangle must have 1 call and 1 put") } + if ($callLegs.Count -eq 1 -and $putLegs.Count -eq 1) { + $callStrike = Normalize-Strike $callLegs[0].strike + $putStrike = Normalize-Strike $putLegs[0].strike + if ($isStraddle -and $callStrike -ne $putStrike) { $errors.Add("Straddle strikes must match") } + if ($isStrangle) { + try { + if ([double]$callStrike -le [double]$putStrike) { $errors.Add("Strangle call strike must be above put strike") } + } catch { + $errors.Add("Strangle strike comparison failed") + } + } + if ($callLegs[0].action -ne "buy" -or $putLegs[0].action -ne "buy") { + $errors.Add("Straddle/Strangle must be long (buy) legs") + } + } + if ($trade.greekProfile -and $trade.greekProfile.deltaBias -and $trade.greekProfile.deltaBias -ne "NEUTRAL") { + $errors.Add("DeltaBias must be NEUTRAL for straddle/strangle") + } + } + + if ($isCallDebit) { + $callLegs = $legs | Where-Object { $_.side -eq "call" } + if ($callLegs.Count -ne 2) { $errors.Add("Call debit spread must have 2 call legs") } + $buy = $callLegs | Where-Object { $_.action -eq "buy" } + $sell = $callLegs | Where-Object { $_.action -eq "sell" } + if ($buy.Count -ne 1 -or $sell.Count -ne 1) { $errors.Add("Call debit spread must have 1 buy and 1 sell") } + if ($buy.Count -eq 1 -and $sell.Count -eq 1) { + try { + if ([double](Normalize-Strike $buy[0].strike) -ge [double](Normalize-Strike $sell[0].strike)) { + $errors.Add("Call debit spread buy strike must be below sell strike") + } + } catch { + $errors.Add("Call debit spread strike comparison failed") + } + } + } + + if ($isPutDebit) { + $putLegs = $legs | Where-Object { $_.side -eq "put" } + if ($putLegs.Count -ne 2) { $errors.Add("Put debit spread must have 2 put legs") } + $buy = $putLegs | Where-Object { $_.action -eq "buy" } + $sell = $putLegs | Where-Object { $_.action -eq "sell" } + if ($buy.Count -ne 1 -or $sell.Count -ne 1) { $errors.Add("Put debit spread must have 1 buy and 1 sell") } + if ($buy.Count -eq 1 -and $sell.Count -eq 1) { + try { + if ([double](Normalize-Strike $buy[0].strike) -le [double](Normalize-Strike $sell[0].strike)) { + $errors.Add("Put debit spread buy strike must be above sell strike") + } + } catch { + $errors.Add("Put debit spread strike comparison failed") + } + } + } + } + } + + return $errors +} + +function Parse-GpuLog { + param([string]$Path) + $summary = [ordered]@{ gpu0Used = $false; gpu1Used = $false; samples = 0; error = $null } + if (-not (Test-Path $Path)) { + $summary.error = "gpu log missing" + return $summary + } + $lines = Get-Content -Path $Path + $currentIndex = -1 + $gpuIndex = -1 + $inGpuUtilSamples = $false + $inUtilBlock = $false + foreach ($line in $lines) { + if ($line -match '^Timestamp') { + $gpuIndex = -1 + $currentIndex = -1 + $inGpuUtilSamples = $false + $inUtilBlock = $false + continue + } + if ($line -match '^GPU\\s+[0-9A-Fa-f:.]+$') { + $gpuIndex += 1 + $currentIndex = $gpuIndex + $inGpuUtilSamples = $false + $inUtilBlock = $false + continue + } + if ($line -match '^\\s*Utilization\\s*$') { + $inUtilBlock = $true + continue + } + if ($line -match '^\\s*GPU Utilization Samples') { + $inGpuUtilSamples = $true + $inUtilBlock = $false + continue + } + if ($line -match '^\\s*(Memory|ENC|DEC) Utilization Samples') { + $inGpuUtilSamples = $false + $inUtilBlock = $false + continue + } + if ($inUtilBlock -and $line -match '^\\s*GPU\\s*:\\s*([0-9]+)\\s*%') { + $util = [int]$Matches[1] + if ($currentIndex -eq 0 -and $util -gt 0) { $summary.gpu0Used = $true } + if ($currentIndex -eq 1 -and $util -gt 0) { $summary.gpu1Used = $true } + $summary.samples += 1 + continue + } + if ($inGpuUtilSamples -and $line -match '^\\s*Max\\s*:\\s*([0-9]+)\\s*%') { + $util = [int]$Matches[1] + if ($currentIndex -eq 0 -and $util -gt 0) { $summary.gpu0Used = $true } + if ($currentIndex -eq 1 -and $util -gt 0) { $summary.gpu1Used = $true } + $summary.samples += 1 + } + } + return $summary +} + +function Get-ProcessorShare { + param( + [string]$SshExePath, + [string]$Target, + [int]$Port, + [string]$ModelName + ) + $result = [ordered]@{ cpuPct = $null; gpuPct = $null; raw = $null; error = $null } + try { + $out = & $SshExePath -p $Port $Target "sudo -n docker exec ix-ollama-ollama-1 ollama ps" + $line = $out | Select-String -SimpleMatch $ModelName | Select-Object -First 1 + if ($null -eq $line) { + $result.error = "model not found in ollama ps" + return $result + } + $raw = $line.ToString().Trim() + $result.raw = $raw + if ($raw -match '([0-9]+)%\\/([0-9]+)%\\s+CPU\\/GPU') { + $result.cpuPct = [int]$Matches[1] + $result.gpuPct = [int]$Matches[2] + } elseif ($raw -match '([0-9]+)%\\s+GPU') { + $result.cpuPct = 0 + $result.gpuPct = [int]$Matches[1] + } else { + $result.error = "CPU/GPU split not parsed" + } + } catch { + $result.error = $_.Exception.Message + } + return $result +} + +$prompt = [string](Get-Content -Raw -Path $PromptPath) +$allowed = Get-AllowedLegs -promptText $prompt +$allowedExpiry = $allowed.AllowedExpiry +$allowedLegs = $allowed.AllowedLegs + +if ([string]::IsNullOrWhiteSpace($BatchId)) { + $BatchId = (Get-Date).ToString("yyyyMMdd_HHmmss") +} + +$outBase = Join-Path -Path (Get-Location) -ChildPath "ollama_runs_remote" +if (-not (Test-Path $outBase)) { New-Item -ItemType Directory -Path $outBase | Out-Null } + +$safeModel = $Model -replace '[\\/:*?"<>|]', '_' +$batchDir = Join-Path -Path $outBase -ChildPath ("batch_{0}" -f $BatchId) +if (-not (Test-Path $batchDir)) { New-Item -ItemType Directory -Path $batchDir | Out-Null } + +$outDir = Join-Path -Path $batchDir -ChildPath $safeModel +if (-not (Test-Path $outDir)) { New-Item -ItemType Directory -Path $outDir | Out-Null } + +$summary = [ordered]@{ + model = $Model + baseUrl = $BaseUrl + formatMode = $(if ($UseSchemaFormat) { "schema" } else { "json" }) + batchId = $BatchId + gpuMonitor = [ordered]@{ + enabled = [bool]$EnableGpuMonitor + sshHost = $SshHost + sshPort = $SshPort + intervalSec = $GpuMonitorIntervalSec + durationSec = $GpuMonitorSeconds + } + runs = @() +} + +for ($i = 1; $i -le $Runs; $i++) { + Write-Host "Running $Model (run $i/$Runs)" + + $runResult = [ordered]@{ run = $i; ok = $false; errors = @() } + $gpuJob = $null + $gpuLogPath = $null + + if ($EnableGpuMonitor) { + $samples = [math]::Max(5, [int]([math]::Ceiling($GpuMonitorSeconds / [double]$GpuMonitorIntervalSec))) + $gpuLogPath = Join-Path $outDir ("gpu_run{0}.csv" -f $i) + $sshTarget = "{0}@{1}" -f $SshUser, $SshHost + $gpuJob = Start-Job -ScriptBlock { + param($sshExe, $target, $port, $samples, $interval, $logPath) + for ($s = 1; $s -le $samples; $s++) { + Add-Content -Path $logPath -Value ("=== SAMPLE {0} {1}" -f $s, (Get-Date).ToString('s')) + try { + $out = & $sshExe -p $port $target "nvidia-smi -q -d UTILIZATION" + Add-Content -Path $logPath -Value $out + } catch { + Add-Content -Path $logPath -Value ("GPU monitor error: $($_.Exception.Message)") + } + Start-Sleep -Seconds $interval + } + } -ArgumentList $SshExe, $sshTarget, $SshPort, $samples, $GpuMonitorIntervalSec, $gpuLogPath + Start-Sleep -Seconds 1 + } + + $format = "json" + if ($UseSchemaFormat) { + $format = @{ + type = "object" + additionalProperties = $false + required = @("selectedExpiry","expiryRationale","strategyBias","recommendedTrades","whyOthersRejected","confidenceScore") + properties = @{ + selectedExpiry = @{ type = "string"; minLength = 1 } + expiryRationale = @{ type = "string"; minLength = 1 } + strategyBias = @{ type = "string"; enum = @("DIRECTIONAL","VOLATILITY","NEUTRAL","NO_TRADE") } + recommendedTrades = @{ + type = "array" + minItems = 0 + maxItems = 3 + items = @{ + type = "object" + additionalProperties = $false + required = @("name","structure","legs","greekProfile","maxRisk","maxReward","thesisAlignment","invalidation") + properties = @{ + name = @{ type = "string"; minLength = 1 } + structure = @{ type = "string"; minLength = 1 } + legs = @{ + type = "array" + minItems = 1 + maxItems = 4 + items = @{ + type = "object" + additionalProperties = $false + required = @("side","action","strike","expiry") + properties = @{ + side = @{ type = "string"; enum = @("call","put") } + action = @{ type = "string"; enum = @("buy","sell") } + strike = @{ type = @("number","string") } + expiry = @{ type = "string"; minLength = 1 } + } + } + } + greekProfile = @{ + type = "object" + additionalProperties = $false + required = @("deltaBias","gammaExposure","thetaExposure","vegaExposure") + properties = @{ + deltaBias = @{ type = "string"; enum = @("POS","NEG","NEUTRAL") } + gammaExposure = @{ type = "string"; enum = @("HIGH","MED","LOW") } + thetaExposure = @{ type = "string"; enum = @("POS","NEG","LOW") } + vegaExposure = @{ type = "string"; enum = @("HIGH","MED","LOW") } + } + } + maxRisk = @{ anyOf = @(@{ type = "string"; minLength = 1 }, @{ type = "number" }) } + maxReward = @{ anyOf = @(@{ type = "string"; minLength = 1 }, @{ type = "number" }) } + thesisAlignment = @{ type = "string"; minLength = 1 } + invalidation = @{ type = "string"; minLength = 1 } + managementNotes = @{ type = "string" } + } + } + } + whyOthersRejected = @{ + type = "array" + items = @{ type = "string" } + } + confidenceScore = @{ type = "number"; minimum = 0; maximum = 100 } + } + } + } + + $options = @{ + temperature = 0 + top_k = $TopK + top_p = $TopP + seed = $Seed + repeat_penalty = $RepeatPenalty + num_ctx = $NumCtx + num_predict = $NumPredict + } + if ($NumBatch -gt 0) { + $options.num_batch = $NumBatch + } + if ($NumGpuLayers -gt 0) { + $options.num_gpu_layers = $NumGpuLayers + } + + $body = @{ + model = $Model + prompt = $prompt + format = $format + stream = $false + options = $options + } | ConvertTo-Json -Depth 10 + + try { + $resp = Invoke-RestMethod -Uri "$BaseUrl/api/generate" -Method Post -Body $body -ContentType "application/json" -TimeoutSec $TimeoutSec + } catch { + $runResult.errors = @("API error: $($_.Exception.Message)") + $summary.runs += $runResult + if ($gpuJob) { Stop-Job -Job $gpuJob | Out-Null } + continue + } finally { + if ($gpuJob) { + Wait-Job -Job $gpuJob -Timeout 5 | Out-Null + if ($gpuJob.State -eq "Running") { Stop-Job -Job $gpuJob | Out-Null } + Remove-Job -Job $gpuJob | Out-Null + } + } + + $raw = [string]$resp.response + + $jsonPath = Join-Path $outDir ("run{0}.json" -f $i) + Set-Content -Path $jsonPath -Value $raw -Encoding ASCII + + try { + $parsed = $raw | ConvertFrom-Json + $errors = Test-TradeSchema -obj $parsed -allowedExpiry $allowedExpiry -allowedLegs $allowedLegs + if ($errors.Count -eq 0) { + $runResult.ok = $true + } else { + $runResult.errors = $errors + } + } catch { + $runResult.errors = @("Invalid JSON: $($_.Exception.Message)") + } + + if ($gpuLogPath) { + $runResult.gpuLog = $gpuLogPath + $runResult.gpuUsage = Parse-GpuLog -Path $gpuLogPath + } + + if ($CheckProcessor) { + $sshTarget = "{0}@{1}" -f $SshUser, $SshHost + $proc = Get-ProcessorShare -SshExePath $SshExe -Target $sshTarget -Port $SshPort -ModelName $Model + $runResult.processor = $proc + if ($proc.cpuPct -ne $null) { + $runResult.gpuOnly = ($proc.cpuPct -eq 0) + } + } + + $summary.runs += $runResult +} + +$summaryPath = Join-Path $outDir "summary.json" +$summary | ConvertTo-Json -Depth 6 | Set-Content -Path $summaryPath -Encoding ASCII + +$summary | ConvertTo-Json -Depth 6 diff --git a/prompt_crwv.txt b/prompt_crwv.txt new file mode 100644 index 0000000..32082ec --- /dev/null +++ b/prompt_crwv.txt @@ -0,0 +1,155 @@ +You are a **senior quantitative options trader** with decades of experience trading **index and ETF options across regimes**, specializing in **volatility, structure selection, and risk asymmetry**. +You are decisive, skeptical, and profit-focused. + +You are given: +- A **validated market thesis** (multi-timeframe technicals, regime, volatility context, news impact). +- **Pre-processed options chains** for **three expiries (short / medium / extended)** with: + - Liquidity-filtered contracts + - ATM and delta anchors + - Delta ladders + - Liquid execution sets +- All pricing, greeks, spreads, and liquidity metrics required for execution-quality decisions. + +Assume: +- Data is correct and cleaned. +- You **must not re-analyze technicals or news** - the thesis is authoritative. +- Your job is **to convert thesis + surface into executable options trades**. + +--- + +## OBJECTIVE + +Select **the best expiry and structure** and propose **1-3 high-quality options trades** that: +- Align with the stated **market bias and regime** +- Exploit **volatility characteristics** (gamma vs theta vs vega) +- Are **liquid, fillable, and risk-defined** +- Have **clear invalidation logic** + +If no trade offers a favorable risk/reward, you must explicitly say **NO TRADE** and explain why. + +--- + +## HOW TO THINK (MANDATORY) + +Think slowly and critically: + +### 1. Compare expiries +- Which expiry best matches: + - Directional confidence vs uncertainty + - Volatility expansion vs decay + - Time needed for thesis to play out +- Reject expiries with: + - Poor liquidity density + - Misaligned vega/theta exposure + - Overpaying for time or vol + +### 2. Choose strategy class +- Examples: + - Directional debit (calls/puts, verticals) + - Volatility plays (straddles, strangles) + - Defined-risk premium selling (only if regime supports it) +- Explicitly justify **why this structure fits the thesis better than alternatives**. + +### 3. Select strikes from provided data +- Use: + - ATM anchor + - Delta ladder + - LiquidSet +- Prefer: + - Tight spreads + - Meaningful volume & OI + - Greeks that express the thesis (gamma, vega, theta balance) + +### 4. Risk discipline +- Every trade must include: + - Max risk + - What must go right + - What breaks the trade + +## TOOLS +You may call MarketData API to get options chain ladder for a specified expiration date. You choose the expiration date. Use this tool to identify opportunities in expirations not already provided. +--- + +## HARD CONSTRAINTS + +- Do NOT invent strikes, expiries, or prices. +- Do NOT suggest illiquid contracts. +- Do NOT recommend naked risk. +- Do NOT hedge unless justified. +- Do NOT repeat raw data back. + +--- + +## REQUIRED OUTPUT FORMAT (STRICT) + +Return **only valid JSON** in the following shape: + +```json +{ + "selectedExpiry": "YYYY-MM-DD", + "expiryRationale": "Why this expiry dominates the others given thesis + vol + liquidity", + "strategyBias": "DIRECTIONAL | VOLATILITY | NEUTRAL | NO_TRADE", + "recommendedTrades": [ + { + "name": "Short descriptive name", + "structure": "e.g. Long Call, Call Debit Spread, Long Strangle", + "legs": [ + { + "side": "call|put", + "action": "buy|sell", + "strike": 0, + "expiry": "YYYY-MM-DD" + } + ], + "greekProfile": { + "deltaBias": "POS|NEG|NEUTRAL", + "gammaExposure": "HIGH|MED|LOW", + "thetaExposure": "POS|NEG|LOW", + "vegaExposure": "HIGH|MED|LOW" + }, + "maxRisk": "Defined numeric or qualitative", + "maxReward": "Defined numeric or qualitative", + "thesisAlignment": "Exactly how this trade expresses the thesis", + "invalidation": "Clear condition where trade is wrong", + "managementNotes": "Optional: scale, take-profit, time stop" + } + ], + "whyOthersRejected": [ + "Why other expiries or strategy types were inferior" + ], + "confidenceScore": 0 +} +``` + +--- + +## FINAL NOTE + +You are **not optimizing for cleverness**. +You are optimizing for **repeatable profitability under uncertainty**. + +If conditions are marginal, say **NO TRADE** with conviction. + +Think like capital is scarce. + Asset Value: +76.42 + +Asset Name: +CRWV + + +52 Week High: +187 + +Options Chain +``` +[{"expiry":"2026-01-02","underlyingPrice":76.42,"usableContracts":56,"liquidContracts":21,"anchors":{"atm":{"side":"call","strike":77,"bid":2.45,"ask":2.59,"mid":2.52,"spreadPct":0.05555555555555543,"volume":1743,"openInterest":222,"iv":0.7269,"inTheMoney":false,"greeks":{"delta":0.4746,"gamma":0.0549,"theta":-0.2336,"vega":0.0397},"liquid":true},"call25":{"side":"call","strike":81,"bid":1.05,"ask":1.12,"mid":1.085,"spreadPct":0.06451612903225812,"volume":363,"openInterest":517,"iv":0.6997,"inTheMoney":false,"greeks":{"delta":0.2669,"gamma":0.0471,"theta":-0.1849,"vega":0.0328},"liquid":true},"put25":{"side":"put","strike":72,"bid":1.05,"ask":1.14,"mid":1.095,"spreadPct":0.08219178082191768,"volume":800,"openInterest":404,"iv":0.6936,"inTheMoney":false,"greeks":{"delta":-0.2524,"gamma":0.0461,"theta":-0.1743,"vega":0.0319},"liquid":true}},"ladder":{"calls":{"d10":{"side":"call","strike":86,"bid":0.32,"ask":0.36,"mid":0.33999999999999997,"spreadPct":0.11764705882352937,"volume":1920,"openInterest":803,"iv":0.7094,"inTheMoney":false,"greeks":{"delta":0.1045,"gamma":0.0256,"theta":-0.103,"vega":0.0181},"liquid":false},"d15":{"side":"call","strike":84,"bid":0.5,"ask":0.58,"mid":0.54,"spreadPct":0.14814814814814806,"volume":266,"openInterest":399,"iv":0.7001,"inTheMoney":false,"greeks":{"delta":0.1543,"gamma":0.034,"theta":-0.1335,"vega":0.0237},"liquid":false},"d25":{"side":"call","strike":81,"bid":1.05,"ask":1.12,"mid":1.085,"spreadPct":0.06451612903225812,"volume":363,"openInterest":517,"iv":0.6997,"inTheMoney":false,"greeks":{"delta":0.2669,"gamma":0.0471,"theta":-0.1849,"vega":0.0328},"liquid":true},"d35":{"side":"call","strike":79,"bid":1.63,"ask":1.72,"mid":1.6749999999999998,"spreadPct":0.053731343283582145,"volume":843,"openInterest":276,"iv":0.7066,"inTheMoney":false,"greeks":{"delta":0.365,"gamma":0.0533,"theta":-0.2139,"vega":0.0375},"liquid":true},"d50":{"side":"call","strike":77,"bid":2.45,"ask":2.59,"mid":2.52,"spreadPct":0.05555555555555543,"volume":1743,"openInterest":222,"iv":0.7269,"inTheMoney":false,"greeks":{"delta":0.4746,"gamma":0.0549,"theta":-0.2336,"vega":0.0397},"liquid":true}},"puts":{"d10":{"side":"put","strike":67,"bid":0.33,"ask":0.41,"mid":0.37,"spreadPct":0.21621621621621612,"volume":215,"openInterest":389,"iv":0.7837,"inTheMoney":false,"greeks":{"delta":-0.0964,"gamma":0.0219,"theta":-0.1058,"vega":0.0171},"liquid":false},"d15":{"side":"put","strike":69,"bid":0.51,"ask":0.6,"mid":0.5549999999999999,"spreadPct":0.16216216216216212,"volume":330,"openInterest":1024,"iv":0.737,"inTheMoney":false,"greeks":{"delta":-0.1414,"gamma":0.0305,"theta":-0.1303,"vega":0.0224},"liquid":false},"d25":{"side":"put","strike":72,"bid":1.05,"ask":1.14,"mid":1.095,"spreadPct":0.08219178082191768,"volume":800,"openInterest":404,"iv":0.6936,"inTheMoney":false,"greeks":{"delta":-0.2524,"gamma":0.0461,"theta":-0.1743,"vega":0.0319},"liquid":true},"d35":{"side":"put","strike":74,"bid":1.64,"ask":1.78,"mid":1.71,"spreadPct":0.08187134502923984,"volume":1629,"openInterest":285,"iv":0.6784,"inTheMoney":false,"greeks":{"delta":-0.355,"gamma":0.055,"theta":-0.1982,"vega":0.0372},"liquid":true},"d50":{"side":"put","strike":76,"bid":2.45,"ask":2.6,"mid":2.5250000000000004,"spreadPct":0.05940594059405936,"volume":1611,"openInterest":1707,"iv":0.6584,"inTheMoney":false,"greeks":{"delta":-0.4715,"gamma":0.0606,"theta":-0.2047,"vega":0.0397},"liquid":true}}},"liquidSet":[{"side":"call","strike":76,"bid":2.94,"ask":3.05,"mid":2.995,"spreadPct":0.03672787979966607,"volume":631,"openInterest":468,"iv":0.7298,"inTheMoney":true,"greeks":{"delta":0.5293,"gamma":0.0546,"theta":-0.2347,"vega":0.0397},"liquid":true},{"side":"call","strike":80,"bid":1.31,"ask":1.4,"mid":1.355,"spreadPct":0.06642066420664196,"volume":2467,"openInterest":1896,"iv":0.7028,"inTheMoney":false,"greeks":{"delta":0.3141,"gamma":0.0506,"theta":-0.2006,"vega":0.0354},"liquid":true},{"side":"call","strike":77,"bid":2.45,"ask":2.59,"mid":2.52,"spreadPct":0.05555555555555543,"volume":1743,"openInterest":222,"iv":0.7269,"inTheMoney":false,"greeks":{"delta":0.4746,"gamma":0.0549,"theta":-0.2336,"vega":0.0397},"liquid":true},{"side":"call","strike":79,"bid":1.63,"ask":1.72,"mid":1.6749999999999998,"spreadPct":0.053731343283582145,"volume":843,"openInterest":276,"iv":0.7066,"inTheMoney":false,"greeks":{"delta":0.365,"gamma":0.0533,"theta":-0.2139,"vega":0.0375},"liquid":true},{"side":"call","strike":78,"bid":2.01,"ask":2.12,"mid":2.065,"spreadPct":0.053268765133172066,"volume":837,"openInterest":139,"iv":0.7154,"inTheMoney":false,"greeks":{"delta":0.4192,"gamma":0.0547,"theta":-0.2253,"vega":0.039},"liquid":true},{"side":"call","strike":71,"bid":6.2,"ask":6.45,"mid":6.325,"spreadPct":0.039525691699604744,"volume":110,"openInterest":246,"iv":0.7963,"inTheMoney":true,"greeks":{"delta":0.7666,"gamma":0.0385,"theta":-0.1991,"vega":0.0306},"liquid":true},{"side":"put","strike":75,"bid":2.03,"ask":2.16,"mid":2.0949999999999998,"spreadPct":0.06205250596658728,"volume":6880,"openInterest":2217,"iv":0.67,"inTheMoney":false,"greeks":{"delta":-0.4119,"gamma":0.0582,"theta":-0.2042,"vega":0.0388},"liquid":true},{"side":"put","strike":80,"bid":4.75,"ask":5,"mid":4.875,"spreadPct":0.05128205128205128,"volume":1599,"openInterest":1115,"iv":0.619,"inTheMoney":true,"greeks":{"delta":-0.7127,"gamma":0.0552,"theta":-0.1621,"vega":0.034},"liquid":true},{"side":"put","strike":76,"bid":2.45,"ask":2.6,"mid":2.5250000000000004,"spreadPct":0.05940594059405936,"volume":1611,"openInterest":1707,"iv":0.6584,"inTheMoney":false,"greeks":{"delta":-0.4715,"gamma":0.0606,"theta":-0.2047,"vega":0.0397},"liquid":true},{"side":"put","strike":79,"bid":4.1,"ask":4.3,"mid":4.199999999999999,"spreadPct":0.04761904761904767,"volume":564,"openInterest":367,"iv":0.6295,"inTheMoney":true,"greeks":{"delta":-0.6548,"gamma":0.0587,"theta":-0.1793,"vega":0.0368},"liquid":true},{"side":"put","strike":81,"bid":5.4,"ask":5.85,"mid":5.625,"spreadPct":0.07999999999999988,"volume":1154,"openInterest":1273,"iv":0.6147,"inTheMoney":true,"greeks":{"delta":-0.7643,"gamma":0.0502,"theta":-0.1443,"vega":0.0307},"liquid":true},{"side":"put","strike":77,"bid":2.97,"ask":3.2,"mid":3.085,"spreadPct":0.07455429497568881,"volume":952,"openInterest":476,"iv":0.6645,"inTheMoney":true,"greeks":{"delta":-0.5312,"gamma":0.06,"theta":-0.2061,"vega":0.0397},"liquid":true}]}, +{"expiry":"2026-01-09","underlyingPrice":76.42,"usableContracts":85,"liquidContracts":24,"anchors":{"atm":{"side":"put","strike":77,"bid":4.6,"ask":4.95,"mid":4.775,"spreadPct":0.07329842931937183,"volume":121,"openInterest":186,"iv":0.7535,"inTheMoney":true,"greeks":{"delta":-0.4891,"gamma":0.0354,"theta":-0.1564,"vega":0.0597},"liquid":true},"call25":{"side":"call","strike":85,"bid":1.6,"ask":1.72,"mid":1.6600000000000001,"spreadPct":0.07228915662650595,"volume":134,"openInterest":526,"iv":0.7558,"inTheMoney":false,"greeks":{"delta":0.2611,"gamma":0.0288,"theta":-0.133,"vega":0.0486},"liquid":true},"put25":{"side":"put","strike":70,"bid":1.9,"ask":2.09,"mid":1.9949999999999999,"spreadPct":0.09523809523809522,"volume":228,"openInterest":803,"iv":0.7904,"inTheMoney":false,"greeks":{"delta":-0.2582,"gamma":0.0273,"theta":-0.1344,"vega":0.0483},"liquid":true}},"ladder":{"calls":{"d10":{"side":"call","strike":96,"bid":0.29,"ask":0.79,"mid":0.54,"spreadPct":0.9259259259259258,"volume":16,"openInterest":88,"iv":0.8418,"inTheMoney":false,"greeks":{"delta":0.0973,"gamma":0.0137,"theta":-0.0781,"vega":0.0257},"liquid":false},"d15":{"side":"call","strike":90,"bid":0.65,"ask":1.03,"mid":0.8400000000000001,"spreadPct":0.45238095238095233,"volume":826,"openInterest":1611,"iv":0.7559,"inTheMoney":false,"greeks":{"delta":0.1524,"gamma":0.0208,"theta":-0.0962,"vega":0.0353},"liquid":false},"d25":{"side":"call","strike":85,"bid":1.6,"ask":1.72,"mid":1.6600000000000001,"spreadPct":0.07228915662650595,"volume":134,"openInterest":526,"iv":0.7558,"inTheMoney":false,"greeks":{"delta":0.2611,"gamma":0.0288,"theta":-0.133,"vega":0.0486},"liquid":true},"d35":{"side":"call","strike":82,"bid":2.25,"ask":2.55,"mid":2.4,"spreadPct":0.12499999999999993,"volume":61,"openInterest":200,"iv":0.7527,"inTheMoney":false,"greeks":{"delta":0.3447,"gamma":0.0327,"theta":-0.1504,"vega":0.0551},"liquid":true},"d50":{"side":"call","strike":77,"bid":4.1,"ask":4.5,"mid":4.3,"spreadPct":0.09302325581395357,"volume":164,"openInterest":116,"iv":0.7619,"inTheMoney":false,"greeks":{"delta":0.5115,"gamma":0.035,"theta":-0.1657,"vega":0.0596},"liquid":true}},"puts":{"d10":{"side":"put","strike":64,"bid":0.32,"ask":1.01,"mid":0.665,"spreadPct":1.0375939849624058,"volume":26,"openInterest":147,"iv":0.7887,"inTheMoney":false,"greeks":{"delta":-0.1093,"gamma":0.0159,"theta":-0.078,"vega":0.028},"liquid":false},"d15":{"side":"put","strike":66,"bid":0.67,"ask":1.26,"mid":0.9650000000000001,"spreadPct":0.6113989637305699,"volume":83,"openInterest":105,"iv":0.7802,"inTheMoney":false,"greeks":{"delta":-0.1491,"gamma":0.0199,"theta":-0.0956,"vega":0.0347},"liquid":false},"d25":{"side":"put","strike":70,"bid":1.9,"ask":2.09,"mid":1.9949999999999999,"spreadPct":0.09523809523809522,"volume":228,"openInterest":803,"iv":0.7904,"inTheMoney":false,"greeks":{"delta":-0.2582,"gamma":0.0273,"theta":-0.1344,"vega":0.0483},"liquid":true},"d35":{"side":"put","strike":73,"bid":2.83,"ask":3.1,"mid":2.965,"spreadPct":0.09106239460370996,"volume":235,"openInterest":109,"iv":0.7705,"inTheMoney":false,"greeks":{"delta":-0.3507,"gamma":0.0322,"theta":-0.1497,"vega":0.0554},"liquid":true},"d50":{"side":"put","strike":77,"bid":4.6,"ask":4.95,"mid":4.775,"spreadPct":0.07329842931937183,"volume":121,"openInterest":186,"iv":0.7535,"inTheMoney":true,"greeks":{"delta":-0.4891,"gamma":0.0354,"theta":-0.1564,"vega":0.0597},"liquid":true}}},"liquidSet":[{"side":"call","strike":80,"bid":3,"ask":3.15,"mid":3.075,"spreadPct":0.048780487804878016,"volume":183,"openInterest":674,"iv":0.7583,"inTheMoney":false,"greeks":{"delta":0.4093,"gamma":0.0343,"theta":-0.1601,"vega":0.0581},"liquid":true},{"side":"call","strike":85,"bid":1.6,"ask":1.72,"mid":1.6600000000000001,"spreadPct":0.07228915662650595,"volume":134,"openInterest":526,"iv":0.7558,"inTheMoney":false,"greeks":{"delta":0.2611,"gamma":0.0288,"theta":-0.133,"vega":0.0486},"liquid":true},{"side":"call","strike":83,"bid":2.05,"ask":2.22,"mid":2.135,"spreadPct":0.07962529274004702,"volume":89,"openInterest":176,"iv":0.755,"inTheMoney":false,"greeks":{"delta":0.3157,"gamma":0.0315,"theta":-0.1456,"vega":0.0532},"liquid":true},{"side":"call","strike":86,"bid":1.39,"ask":1.51,"mid":1.45,"spreadPct":0.08275862068965525,"volume":90,"openInterest":202,"iv":0.7544,"inTheMoney":false,"greeks":{"delta":0.2356,"gamma":0.0273,"theta":-0.1256,"vega":0.046},"liquid":true},{"side":"call","strike":77,"bid":4.1,"ask":4.5,"mid":4.3,"spreadPct":0.09302325581395357,"volume":164,"openInterest":116,"iv":0.7619,"inTheMoney":false,"greeks":{"delta":0.5115,"gamma":0.035,"theta":-0.1657,"vega":0.0596},"liquid":true},{"side":"call","strike":81,"bid":2.56,"ask":2.8,"mid":2.6799999999999997,"spreadPct":0.08955223880597007,"volume":47,"openInterest":236,"iv":0.748,"inTheMoney":false,"greeks":{"delta":0.3748,"gamma":0.0339,"theta":-0.154,"vega":0.0567},"liquid":true},{"side":"put","strike":75,"bid":3.7,"ask":3.95,"mid":3.825,"spreadPct":0.06535947712418301,"volume":568,"openInterest":729,"iv":0.7662,"inTheMoney":false,"greeks":{"delta":-0.4189,"gamma":0.0341,"theta":-0.1564,"vega":0.0584},"liquid":true},{"side":"put","strike":81,"bid":7.05,"ask":7.3,"mid":7.175,"spreadPct":0.03484320557491289,"volume":124,"openInterest":171,"iv":0.7437,"inTheMoney":true,"greeks":{"delta":-0.6263,"gamma":0.0341,"theta":-0.1451,"vega":0.0567},"liquid":true},{"side":"put","strike":70,"bid":1.9,"ask":2.09,"mid":1.9949999999999999,"spreadPct":0.09523809523809522,"volume":228,"openInterest":803,"iv":0.7904,"inTheMoney":false,"greeks":{"delta":-0.2582,"gamma":0.0273,"theta":-0.1344,"vega":0.0483},"liquid":true},{"side":"put","strike":76,"bid":4.1,"ask":4.45,"mid":4.275,"spreadPct":0.08187134502923989,"volume":208,"openInterest":234,"iv":0.7586,"inTheMoney":false,"greeks":{"delta":-0.4538,"gamma":0.0349,"theta":-0.1568,"vega":0.0593},"liquid":true},{"side":"put","strike":77,"bid":4.6,"ask":4.95,"mid":4.775,"spreadPct":0.07329842931937183,"volume":121,"openInterest":186,"iv":0.7535,"inTheMoney":true,"greeks":{"delta":-0.4891,"gamma":0.0354,"theta":-0.1564,"vega":0.0597},"liquid":true},{"side":"put","strike":73,"bid":2.83,"ask":3.1,"mid":2.965,"spreadPct":0.09106239460370996,"volume":235,"openInterest":109,"iv":0.7705,"inTheMoney":false,"greeks":{"delta":-0.3507,"gamma":0.0322,"theta":-0.1497,"vega":0.0554},"liquid":true}]}, +{"expiry":"2026-01-16","underlyingPrice":76.42,"usableContracts":82,"liquidContracts":37,"anchors":{"atm":{"side":"call","strike":78,"bid":4.95,"ask":5.45,"mid":5.2,"spreadPct":0.09615384615384615,"volume":275,"openInterest":19,"iv":0.8017,"inTheMoney":false,"greeks":{"delta":0.4988,"gamma":0.0272,"theta":-0.1427,"vega":0.0731},"liquid":true},"call25":{"side":"call","strike":88,"bid":1.82,"ask":2.21,"mid":2.015,"spreadPct":0.19354838709677413,"volume":18,"openInterest":38,"iv":0.7798,"inTheMoney":false,"greeks":{"delta":0.2568,"gamma":0.0226,"theta":-0.1113,"vega":0.059},"liquid":false},"put25":{"side":"put","strike":67.5,"bid":2.15,"ask":2.37,"mid":2.26,"spreadPct":0.09734513274336293,"volume":219,"openInterest":3915,"iv":0.8255,"inTheMoney":false,"greeks":{"delta":-0.2318,"gamma":0.0202,"theta":-0.1079,"vega":0.0559},"liquid":true}},"ladder":{"calls":{"d10":{"side":"call","strike":100,"bid":0.57,"ask":0.64,"mid":0.605,"spreadPct":0.11570247933884308,"volume":2090,"openInterest":38143,"iv":0.7952,"inTheMoney":false,"greeks":{"delta":0.0956,"gamma":0.0117,"theta":-0.0595,"vega":0.0311},"liquid":false},"d15":{"side":"call","strike":95,"bid":0.95,"ask":1.01,"mid":0.98,"spreadPct":0.06122448979591842,"volume":1145,"openInterest":5413,"iv":0.7814,"inTheMoney":false,"greeks":{"delta":0.1446,"gamma":0.0159,"theta":-0.0785,"vega":0.0417},"liquid":false},"d25":{"side":"call","strike":88,"bid":1.82,"ask":2.21,"mid":2.015,"spreadPct":0.19354838709677413,"volume":18,"openInterest":38,"iv":0.7798,"inTheMoney":false,"greeks":{"delta":0.2568,"gamma":0.0226,"theta":-0.1113,"vega":0.059},"liquid":false},"d35":{"side":"call","strike":84,"bid":2.73,"ask":3.65,"mid":3.19,"spreadPct":0.2884012539184953,"volume":8,"openInterest":29,"iv":0.8135,"inTheMoney":false,"greeks":{"delta":0.352,"gamma":0.0249,"theta":-0.134,"vega":0.068},"liquid":false},"d50":{"side":"call","strike":78,"bid":4.95,"ask":5.45,"mid":5.2,"spreadPct":0.09615384615384615,"volume":275,"openInterest":19,"iv":0.8017,"inTheMoney":false,"greeks":{"delta":0.4988,"gamma":0.0272,"theta":-0.1427,"vega":0.0731},"liquid":true}},"puts":{"d10":{"side":"put","strike":60,"bid":0.8,"ask":0.93,"mid":0.865,"spreadPct":0.15028901734104047,"volume":215,"openInterest":9981,"iv":0.8759,"inTheMoney":false,"greeks":{"delta":-0.1033,"gamma":0.0112,"theta":-0.0678,"vega":0.0329},"liquid":false},"d15":{"side":"put","strike":62.5,"bid":1.16,"ask":1.3,"mid":1.23,"spreadPct":0.11382113821138222,"volume":142,"openInterest":4191,"iv":0.8614,"inTheMoney":false,"greeks":{"delta":-0.1394,"gamma":0.0141,"theta":-0.0822,"vega":0.0406},"liquid":true},"d25":{"side":"put","strike":67.5,"bid":2.15,"ask":2.37,"mid":2.26,"spreadPct":0.09734513274336293,"volume":219,"openInterest":3915,"iv":0.8255,"inTheMoney":false,"greeks":{"delta":-0.2318,"gamma":0.0202,"theta":-0.1079,"vega":0.0559},"liquid":true},"d35":{"side":"put","strike":72.5,"bid":3.75,"ask":4,"mid":3.875,"spreadPct":0.06451612903225806,"volume":60,"openInterest":7514,"iv":0.7966,"inTheMoney":false,"greeks":{"delta":-0.3526,"gamma":0.0255,"theta":-0.126,"vega":0.068},"liquid":true},"d50":{"side":"put","strike":78,"bid":6.4,"ask":6.7,"mid":6.550000000000001,"spreadPct":0.04580152671755722,"volume":38,"openInterest":99,"iv":0.7853,"inTheMoney":true,"greeks":{"delta":-0.5028,"gamma":0.0277,"theta":-0.1323,"vega":0.0731},"liquid":false}}},"liquidSet":[{"side":"call","strike":90,"bid":1.65,"ask":1.71,"mid":1.68,"spreadPct":0.03571428571428575,"volume":530,"openInterest":7539,"iv":0.7857,"inTheMoney":false,"greeks":{"delta":0.2218,"gamma":0.0207,"theta":-0.1034,"vega":0.0545},"liquid":true},{"side":"call","strike":80,"bid":4.25,"ask":4.5,"mid":4.375,"spreadPct":0.05714285714285714,"volume":522,"openInterest":9961,"iv":0.7972,"inTheMoney":false,"greeks":{"delta":0.4457,"gamma":0.0271,"theta":-0.1403,"vega":0.0724},"liquid":true},{"side":"call","strike":85,"bid":2.6,"ask":2.83,"mid":2.715,"spreadPct":0.08471454880294658,"volume":836,"openInterest":4629,"iv":0.7827,"inTheMoney":false,"greeks":{"delta":0.3208,"gamma":0.025,"theta":-0.1243,"vega":0.0656},"liquid":true},{"side":"call","strike":77.5,"bid":5.2,"ask":5.45,"mid":5.325,"spreadPct":0.046948356807511735,"volume":129,"openInterest":1386,"iv":0.7895,"inTheMoney":false,"greeks":{"delta":0.5112,"gamma":0.0276,"theta":-0.1406,"vega":0.0731},"liquid":true},{"side":"call","strike":75,"bid":6.4,"ask":6.75,"mid":6.575,"spreadPct":0.05323193916349804,"volume":124,"openInterest":2595,"iv":0.8004,"inTheMoney":true,"greeks":{"delta":0.5796,"gamma":0.0267,"theta":-0.1402,"vega":0.0716},"liquid":true},{"side":"call","strike":65,"bid":12.55,"ask":13.5,"mid":13.025,"spreadPct":0.07293666026871395,"volume":231,"openInterest":3596,"iv":0.8091,"inTheMoney":true,"greeks":{"delta":0.8259,"gamma":0.0173,"theta":-0.0956,"vega":0.0471},"liquid":true},{"side":"put","strike":75,"bid":4.85,"ask":5.15,"mid":5,"spreadPct":0.060000000000000143,"volume":1076,"openInterest":4255,"iv":0.7931,"inTheMoney":false,"greeks":{"delta":-0.4203,"gamma":0.0269,"theta":-0.1316,"vega":0.0716},"liquid":true},{"side":"put","strike":82.5,"bid":9.2,"ask":9.45,"mid":9.325,"spreadPct":0.02680965147453083,"volume":103,"openInterest":1313,"iv":0.7744,"inTheMoney":true,"greeks":{"delta":-0.6224,"gamma":0.0268,"theta":-0.1228,"vega":0.0696},"liquid":true},{"side":"put","strike":70,"bid":2.87,"ask":3.1,"mid":2.9850000000000003,"spreadPct":0.07705192629815744,"volume":1191,"openInterest":11970,"iv":0.8101,"inTheMoney":false,"greeks":{"delta":-0.2891,"gamma":0.023,"theta":-0.1183,"vega":0.0626},"liquid":true},{"side":"put","strike":65,"bid":1.59,"ask":1.7,"mid":1.645,"spreadPct":0.06686930091185403,"volume":283,"openInterest":14078,"iv":0.835,"inTheMoney":false,"greeks":{"delta":-0.18,"gamma":0.0172,"theta":-0.0941,"vega":0.0481},"liquid":true},{"side":"put","strike":80,"bid":7.55,"ask":8.1,"mid":7.824999999999999,"spreadPct":0.07028753993610222,"volume":237,"openInterest":9133,"iv":0.7949,"inTheMoney":true,"greeks":{"delta":-0.5547,"gamma":0.0271,"theta":-0.1321,"vega":0.0724},"liquid":true},{"side":"put","strike":85,"bid":10.8,"ask":11.6,"mid":11.2,"spreadPct":0.07142857142857134,"volume":360,"openInterest":2822,"iv":0.7871,"inTheMoney":true,"greeks":{"delta":-0.6779,"gamma":0.0249,"theta":-0.117,"vega":0.0657},"liquid":true}]}, +{"expiry":"2026-01-23","underlyingPrice":76.42,"usableContracts":96,"liquidContracts":11,"anchors":{"atm":{"side":"put","strike":79,"bid":7.7,"ask":10.4,"mid":9.05,"spreadPct":0.2983425414364641,"volume":6,"openInterest":16,"iv":0.9105,"inTheMoney":true,"greeks":{"delta":-0.4989,"gamma":0.0207,"theta":-0.1326,"vega":0.0844},"liquid":false},"call25":{"side":"call","strike":91,"bid":1.83,"ask":2.65,"mid":2.24,"spreadPct":0.3660714285714285,"volume":6,"openInterest":56,"iv":0.7921,"inTheMoney":false,"greeks":{"delta":0.2493,"gamma":0.0189,"theta":-0.0966,"vega":0.0671},"liquid":false},"put25":{"side":"put","strike":68,"bid":2.84,"ask":3.15,"mid":2.995,"spreadPct":0.10350584307178633,"volume":22,"openInterest":91,"iv":0.8036,"inTheMoney":false,"greeks":{"delta":-0.2594,"gamma":0.0191,"theta":-0.0961,"vega":0.0685},"liquid":false}},"ladder":{"calls":{"d10":{"side":"call","strike":105,"bid":0.65,"ask":0.77,"mid":0.71,"spreadPct":0.16901408450704225,"volume":12,"openInterest":221,"iv":0.8069,"inTheMoney":false,"greeks":{"delta":0.0967,"gamma":0.01,"theta":-0.0528,"vega":0.0362},"liquid":false},"d15":{"side":"call","strike":99,"bid":0.96,"ask":1.4,"mid":1.18,"spreadPct":0.37288135593220334,"volume":2,"openInterest":22,"iv":0.8024,"inTheMoney":false,"greeks":{"delta":0.1481,"gamma":0.0136,"theta":-0.0711,"vega":0.0489},"liquid":false},"d25":{"side":"call","strike":91,"bid":1.83,"ask":2.65,"mid":2.24,"spreadPct":0.3660714285714285,"volume":6,"openInterest":56,"iv":0.7921,"inTheMoney":false,"greeks":{"delta":0.2493,"gamma":0.0189,"theta":-0.0966,"vega":0.0671},"liquid":false},"d35":{"side":"call","strike":85,"bid":3.4,"ask":3.7,"mid":3.55,"spreadPct":0.08450704225352121,"volume":468,"openInterest":942,"iv":0.7838,"inTheMoney":false,"greeks":{"delta":0.3549,"gamma":0.0225,"theta":-0.1125,"vega":0.0787},"liquid":true},"d50":{"side":"call","strike":78,"bid":4,"ask":6.8,"mid":5.4,"spreadPct":0.5185185185185185,"volume":6,"openInterest":58,"iv":0.7154,"inTheMoney":false,"greeks":{"delta":0.5025,"gamma":0.0264,"theta":-0.111,"vega":0.0844},"liquid":false}},"puts":{"d10":{"side":"put","strike":58,"bid":0.59,"ask":1.25,"mid":0.9199999999999999,"spreadPct":0.7173913043478262,"volume":27,"openInterest":2,"iv":0.8529,"inTheMoney":false,"greeks":{"delta":-0.0978,"gamma":0.0096,"theta":-0.0548,"vega":0.0365},"liquid":false},"d15":{"side":"put","strike":62,"bid":1,"ask":1.8,"mid":1.4,"spreadPct":0.5714285714285715,"volume":22,"openInterest":17,"iv":0.804,"inTheMoney":false,"greeks":{"delta":-0.1446,"gamma":0.0134,"theta":-0.0679,"vega":0.0481},"liquid":false},"d25":{"side":"put","strike":68,"bid":2.84,"ask":3.15,"mid":2.995,"spreadPct":0.10350584307178633,"volume":22,"openInterest":91,"iv":0.8036,"inTheMoney":false,"greeks":{"delta":-0.2594,"gamma":0.0191,"theta":-0.0961,"vega":0.0685},"liquid":false},"d35":{"side":"put","strike":72,"bid":4.3,"ask":4.75,"mid":4.525,"spreadPct":0.09944751381215473,"volume":16,"openInterest":94,"iv":0.8029,"inTheMoney":false,"greeks":{"delta":-0.3488,"gamma":0.0218,"theta":-0.1092,"vega":0.0783},"liquid":false},"d50":{"side":"put","strike":79,"bid":7.7,"ask":10.4,"mid":9.05,"spreadPct":0.2983425414364641,"volume":6,"openInterest":16,"iv":0.9105,"inTheMoney":true,"greeks":{"delta":-0.4989,"gamma":0.0207,"theta":-0.1326,"vega":0.0844},"liquid":false}}},"liquidSet":[{"side":"call","strike":85,"bid":3.4,"ask":3.7,"mid":3.55,"spreadPct":0.08450704225352121,"volume":468,"openInterest":942,"iv":0.7838,"inTheMoney":false,"greeks":{"delta":0.3549,"gamma":0.0225,"theta":-0.1125,"vega":0.0787},"liquid":true},{"side":"call","strike":83,"bid":4.05,"ask":4.3,"mid":4.175,"spreadPct":0.059880239520958084,"volume":624,"openInterest":92,"iv":0.7879,"inTheMoney":false,"greeks":{"delta":0.3975,"gamma":0.0231,"theta":-0.1173,"vega":0.0816},"liquid":true},{"side":"call","strike":80,"bid":5.05,"ask":5.4,"mid":5.225,"spreadPct":0.06698564593301445,"volume":81,"openInterest":238,"iv":0.7894,"inTheMoney":false,"greeks":{"delta":0.4639,"gamma":0.0238,"theta":-0.1214,"vega":0.084},"liquid":true},{"side":"call","strike":90,"bid":2.3,"ask":2.55,"mid":2.425,"spreadPct":0.10309278350515465,"volume":58,"openInterest":687,"iv":0.7911,"inTheMoney":false,"greeks":{"delta":0.2652,"gamma":0.0196,"theta":-0.0997,"vega":0.0693},"liquid":true},{"side":"call","strike":88,"bid":2.6,"ask":3.15,"mid":2.875,"spreadPct":0.1913043478260869,"volume":12,"openInterest":1234,"iv":0.7945,"inTheMoney":false,"greeks":{"delta":0.3009,"gamma":0.0207,"theta":-0.1065,"vega":0.0737},"liquid":true},{"side":"call","strike":75,"bid":7.2,"ask":7.85,"mid":7.525,"spreadPct":0.08637873754152817,"volume":2,"openInterest":154,"iv":0.8049,"inTheMoney":true,"greeks":{"delta":0.5812,"gamma":0.0229,"theta":-0.1224,"vega":0.0826},"liquid":true},{"side":"put","strike":80,"bid":8.35,"ask":8.8,"mid":8.575,"spreadPct":0.0524781341107873,"volume":35,"openInterest":393,"iv":0.782,"inTheMoney":true,"greeks":{"delta":-0.5373,"gamma":0.024,"theta":-0.1125,"vega":0.084},"liquid":true},{"side":"put","strike":75,"bid":5.55,"ask":5.95,"mid":5.75,"spreadPct":0.0695652173913044,"volume":78,"openInterest":217,"iv":0.7807,"inTheMoney":false,"greeks":{"delta":-0.419,"gamma":0.0237,"theta":-0.1115,"vega":0.0826},"liquid":true},{"side":"put","strike":70,"bid":3.5,"ask":3.8,"mid":3.65,"spreadPct":0.08219178082191776,"volume":75,"openInterest":337,"iv":0.7949,"inTheMoney":false,"greeks":{"delta":-0.3022,"gamma":0.0208,"theta":-0.1021,"vega":0.0738},"liquid":true},{"side":"put","strike":65,"bid":1.97,"ask":2.25,"mid":2.11,"spreadPct":0.13270142180094788,"volume":50,"openInterest":713,"iv":0.8062,"inTheMoney":false,"greeks":{"delta":-0.1988,"gamma":0.0164,"theta":-0.0833,"vega":0.059},"liquid":true}]}, +{"expiry":"2026-01-30","underlyingPrice":76.42,"usableContracts":97,"liquidContracts":7,"anchors":{"atm":{"side":"call","strike":79,"bid":4.4,"ask":8.7,"mid":6.55,"spreadPct":0.6564885496183205,"volume":11,"openInterest":44,"iv":0.803,"inTheMoney":false,"greeks":{"delta":0.5008,"gamma":0.021,"theta":-0.1113,"vega":0.0944},"liquid":false},"call25":{"side":"call","strike":94,"bid":1.12,"ask":4.3,"mid":2.71,"spreadPct":1.173431734317343,"volume":2,"openInterest":38,"iv":0.8413,"inTheMoney":false,"greeks":{"delta":0.2566,"gamma":0.0162,"theta":-0.0932,"vega":0.0762},"liquid":false},"put25":{"side":"put","strike":67,"bid":2.84,"ask":3.5,"mid":3.17,"spreadPct":0.20820189274447953,"volume":3,"openInterest":38,"iv":0.7879,"inTheMoney":false,"greeks":{"delta":-0.2506,"gamma":0.0171,"theta":-0.0825,"vega":0.0753},"liquid":false}},"ladder":{"calls":{"d10":{"side":"call","strike":105,"bid":1.08,"ask":1.58,"mid":1.33,"spreadPct":0.37593984962406013,"volume":43,"openInterest":307,"iv":0.8516,"inTheMoney":false,"greeks":{"delta":0.144,"gamma":0.0113,"theta":-0.0662,"vega":0.0537},"liquid":false},"d15":{"side":"call","strike":105,"bid":1.08,"ask":1.58,"mid":1.33,"spreadPct":0.37593984962406013,"volume":43,"openInterest":307,"iv":0.8516,"inTheMoney":false,"greeks":{"delta":0.144,"gamma":0.0113,"theta":-0.0662,"vega":0.0537},"liquid":false},"d25":{"side":"call","strike":94,"bid":1.12,"ask":4.3,"mid":2.71,"spreadPct":1.173431734317343,"volume":2,"openInterest":38,"iv":0.8413,"inTheMoney":false,"greeks":{"delta":0.2566,"gamma":0.0162,"theta":-0.0932,"vega":0.0762},"liquid":false},"d35":{"side":"call","strike":87,"bid":2.1,"ask":6.05,"mid":4.075,"spreadPct":0.969325153374233,"volume":9,"openInterest":76,"iv":0.8204,"inTheMoney":false,"greeks":{"delta":0.3547,"gamma":0.0192,"theta":-0.1054,"vega":0.088},"liquid":false},"d50":{"side":"call","strike":79,"bid":4.4,"ask":8.7,"mid":6.55,"spreadPct":0.6564885496183205,"volume":11,"openInterest":44,"iv":0.803,"inTheMoney":false,"greeks":{"delta":0.5008,"gamma":0.021,"theta":-0.1113,"vega":0.0944},"liquid":false}},"puts":{"d10":{"side":"put","strike":56,"bid":0.47,"ask":1.82,"mid":1.145,"spreadPct":1.1790393013100438,"volume":13,"openInterest":11,"iv":0.8918,"inTheMoney":false,"greeks":{"delta":-0.1014,"gamma":0.0084,"theta":-0.0525,"vega":0.0419},"liquid":false},"d15":{"side":"put","strike":60,"bid":1.47,"ask":1.81,"mid":1.6400000000000001,"spreadPct":0.20731707317073175,"volume":191,"openInterest":187,"iv":0.842,"inTheMoney":false,"greeks":{"delta":-0.1426,"gamma":0.0113,"theta":-0.0629,"vega":0.0533},"liquid":false},"d25":{"side":"put","strike":67,"bid":2.84,"ask":3.5,"mid":3.17,"spreadPct":0.20820189274447953,"volume":3,"openInterest":38,"iv":0.7879,"inTheMoney":false,"greeks":{"delta":-0.2506,"gamma":0.0171,"theta":-0.0825,"vega":0.0753},"liquid":false},"d35":{"side":"put","strike":72,"bid":4.45,"ask":5.7,"mid":5.075,"spreadPct":0.24630541871921183,"volume":81,"openInterest":136,"iv":0.7833,"inTheMoney":false,"greeks":{"delta":-0.3526,"gamma":0.0201,"theta":-0.0952,"vega":0.0878},"liquid":false},"d50":{"side":"put","strike":79,"bid":7.3,"ask":11.3,"mid":9.3,"spreadPct":0.4301075268817205,"volume":2,"openInterest":20,"iv":0.8442,"inTheMoney":true,"greeks":{"delta":-0.4943,"gamma":0.02,"theta":-0.1092,"vega":0.0943},"liquid":false}}},"liquidSet":[{"side":"call","strike":85,"bid":4.35,"ask":5,"mid":4.675,"spreadPct":0.1390374331550803,"volume":65,"openInterest":10564,"iv":0.8249,"inTheMoney":false,"greeks":{"delta":0.3905,"gamma":0.0197,"theta":-0.1094,"vega":0.0908},"liquid":true},{"side":"call","strike":90,"bid":2.9,"ask":3.4,"mid":3.15,"spreadPct":0.15873015873015872,"volume":197,"openInterest":293,"iv":0.7967,"inTheMoney":false,"greeks":{"delta":0.2986,"gamma":0.0184,"theta":-0.0953,"vega":0.0821},"liquid":true},{"side":"call","strike":77,"bid":6.8,"ask":7.8,"mid":7.3,"spreadPct":0.136986301369863,"volume":130,"openInterest":87,"iv":0.7932,"inTheMoney":false,"greeks":{"delta":0.5411,"gamma":0.0212,"theta":-0.1097,"vega":0.0938},"liquid":true},{"side":"call","strike":80,"bid":5.95,"ask":7.2,"mid":6.575,"spreadPct":0.19011406844106463,"volume":82,"openInterest":153,"iv":0.8472,"inTheMoney":false,"greeks":{"delta":0.4869,"gamma":0.0199,"theta":-0.1171,"vega":0.0943},"liquid":true},{"side":"put","strike":70,"bid":4.25,"ask":4.6,"mid":4.425,"spreadPct":0.07909604519774004,"volume":126,"openInterest":4189,"iv":0.8065,"inTheMoney":false,"greeks":{"delta":-0.313,"gamma":0.0186,"theta":-0.0938,"vega":0.0838},"liquid":true},{"side":"put","strike":75,"bid":6.45,"ask":7,"mid":6.725,"spreadPct":0.08178438661710034,"volume":170,"openInterest":216,"iv":0.8067,"inTheMoney":false,"greeks":{"delta":-0.4164,"gamma":0.0205,"theta":-0.1026,"vega":0.0923},"liquid":true},{"side":"put","strike":80,"bid":8.5,"ask":10.3,"mid":9.4,"spreadPct":0.19148936170212774,"volume":28,"openInterest":329,"iv":0.7907,"inTheMoney":true,"greeks":{"delta":-0.5213,"gamma":0.0213,"theta":-0.1016,"vega":0.0942},"liquid":true}]}, +{"expiry":"2026-02-06","underlyingPrice":76.42,"usableContracts":73,"liquidContracts":0,"anchors":{"atm":{"side":"put","strike":80,"bid":8.4,"ask":12.5,"mid":10.45,"spreadPct":0.3923444976076555,"volume":1,"openInterest":0,"iv":0.8267,"inTheMoney":true,"greeks":{"delta":-0.5043,"gamma":0.0186,"theta":-0.0969,"vega":0.1033},"liquid":false},"call25":{"side":"call","strike":100,"bid":2.2,"ask":2.49,"mid":2.345,"spreadPct":0.12366737739872069,"volume":11,"openInterest":0,"iv":0.8408,"inTheMoney":false,"greeks":{"delta":0.2153,"gamma":0.0134,"theta":-0.0772,"vega":0.0757},"liquid":false},"put25":{"side":"put","strike":65,"bid":2.92,"ask":3.7,"mid":3.31,"spreadPct":0.23564954682779463,"volume":18,"openInterest":0,"iv":0.8197,"inTheMoney":false,"greeks":{"delta":-0.2316,"gamma":0.0144,"theta":-0.075,"vega":0.079},"liquid":false}},"ladder":{"calls":{"d10":{"side":"call","strike":110,"bid":0.02,"ask":2.21,"mid":1.115,"spreadPct":1.9641255605381165,"volume":0,"openInterest":0,"iv":0.8118,"inTheMoney":false,"greeks":{"delta":0.1205,"gamma":0.0095,"theta":-0.051,"vega":0.052},"liquid":false},"d15":{"side":"call","strike":105,"bid":0.79,"ask":2.36,"mid":1.575,"spreadPct":0.9968253968253967,"volume":12,"openInterest":0,"iv":0.8165,"inTheMoney":false,"greeks":{"delta":0.1596,"gamma":0.0115,"theta":-0.0622,"vega":0.0629},"liquid":false},"d25":{"side":"call","strike":100,"bid":2.2,"ask":2.49,"mid":2.345,"spreadPct":0.12366737739872069,"volume":11,"openInterest":0,"iv":0.8408,"inTheMoney":false,"greeks":{"delta":0.2153,"gamma":0.0134,"theta":-0.0772,"vega":0.0757},"liquid":false},"d35":{"side":"call","strike":90,"bid":3.35,"ask":5.15,"mid":4.25,"spreadPct":0.42352941176470593,"volume":10,"openInterest":0,"iv":0.8447,"inTheMoney":false,"greeks":{"delta":0.3389,"gamma":0.0167,"theta":-0.0974,"vega":0.0948},"liquid":false},"d50":{"side":"call","strike":79,"bid":5.55,"ask":8.9,"mid":7.225,"spreadPct":0.46366782006920426,"volume":2,"openInterest":0,"iv":0.7962,"inTheMoney":false,"greeks":{"delta":0.5099,"gamma":0.0193,"theta":-0.101,"vega":0.1033},"liquid":false}},"puts":{"d10":{"side":"put","strike":55,"bid":0.86,"ask":1.55,"mid":1.205,"spreadPct":0.5726141078838174,"volume":18,"openInterest":0,"iv":0.8635,"inTheMoney":false,"greeks":{"delta":-0.1001,"gamma":0.0078,"theta":-0.0459,"vega":0.0455},"liquid":false},"d15":{"side":"put","strike":60,"bid":1.86,"ask":2.3,"mid":2.08,"spreadPct":0.2115384615384614,"volume":13,"openInterest":0,"iv":0.8428,"inTheMoney":false,"greeks":{"delta":-0.1584,"gamma":0.0111,"theta":-0.0614,"vega":0.0626},"liquid":false},"d25":{"side":"put","strike":65,"bid":2.92,"ask":3.7,"mid":3.31,"spreadPct":0.23564954682779463,"volume":18,"openInterest":0,"iv":0.8197,"inTheMoney":false,"greeks":{"delta":-0.2316,"gamma":0.0144,"theta":-0.075,"vega":0.079},"liquid":false},"d35":{"side":"put","strike":72,"bid":4.35,"ask":8.15,"mid":6.25,"spreadPct":0.6080000000000001,"volume":0,"openInterest":0,"iv":0.8391,"inTheMoney":false,"greeks":{"delta":-0.358,"gamma":0.0172,"theta":-0.0934,"vega":0.0967},"liquid":false},"d50":{"side":"put","strike":80,"bid":8.4,"ask":12.5,"mid":10.45,"spreadPct":0.3923444976076555,"volume":1,"openInterest":0,"iv":0.8267,"inTheMoney":true,"greeks":{"delta":-0.5043,"gamma":0.0186,"theta":-0.0969,"vega":0.1033},"liquid":false}}},"liquidSet":[{"side":"call","strike":50,"bid":25.4,"ask":29.4,"mid":27.4,"spreadPct":0.14598540145985403,"volume":0,"openInterest":0,"iv":0.9439,"inTheMoney":true,"greeks":{"delta":0.9326,"gamma":0.0053,"theta":-0.0422,"vega":0.0338},"liquid":false},{"side":"call","strike":55,"bid":20.95,"ask":24.95,"mid":22.95,"spreadPct":0.17429193899782136,"volume":2,"openInterest":0,"iv":0.8958,"inTheMoney":true,"greeks":{"delta":0.8936,"gamma":0.0079,"theta":-0.0551,"vega":0.0476},"liquid":false},{"side":"call","strike":60,"bid":16.85,"ask":20.85,"mid":18.85,"spreadPct":0.21220159151193632,"volume":0,"openInterest":0,"iv":0.8673,"inTheMoney":true,"greeks":{"delta":0.8367,"gamma":0.011,"theta":-0.0703,"vega":0.0639},"liquid":false},{"side":"call","strike":65,"bid":13.1,"ask":17.15,"mid":15.125,"spreadPct":0.2677685950413222,"volume":0,"openInterest":0,"iv":0.8423,"inTheMoney":true,"greeks":{"delta":0.7647,"gamma":0.0141,"theta":-0.0841,"vega":0.0797},"liquid":false},{"side":"call","strike":68,"bid":11.95,"ask":15.15,"mid":13.55,"spreadPct":0.2361623616236163,"volume":0,"openInterest":0,"iv":0.88,"inTheMoney":true,"greeks":{"delta":0.7095,"gamma":0.015,"theta":-0.0969,"vega":0.0887},"liquid":false},{"side":"call","strike":69,"bid":10.5,"ask":14.55,"mid":12.525,"spreadPct":0.3233532934131737,"volume":0,"openInterest":0,"iv":0.8319,"inTheMoney":true,"greeks":{"delta":0.6968,"gamma":0.0162,"theta":-0.0936,"vega":0.0905},"liquid":false},{"side":"put","strike":40,"bid":0.1,"ask":3.05,"mid":1.575,"spreadPct":1.8730158730158728,"volume":0,"openInterest":0,"iv":1.5809,"inTheMoney":false,"greeks":{"delta":-0.0692,"gamma":0.0032,"theta":-0.0642,"vega":0.0345},"liquid":false},{"side":"put","strike":50,"bid":0.36,"ask":1.35,"mid":0.855,"spreadPct":1.1578947368421053,"volume":5,"openInterest":0,"iv":0.9526,"inTheMoney":false,"greeks":{"delta":-0.0688,"gamma":0.0054,"theta":-0.0383,"vega":0.0343},"liquid":false},{"side":"put","strike":55,"bid":0.86,"ask":1.55,"mid":1.205,"spreadPct":0.5726141078838174,"volume":18,"openInterest":0,"iv":0.8635,"inTheMoney":false,"greeks":{"delta":-0.1001,"gamma":0.0078,"theta":-0.0459,"vega":0.0455},"liquid":false},{"side":"put","strike":60,"bid":1.86,"ask":2.3,"mid":2.08,"spreadPct":0.2115384615384614,"volume":13,"openInterest":0,"iv":0.8428,"inTheMoney":false,"greeks":{"delta":-0.1584,"gamma":0.0111,"theta":-0.0614,"vega":0.0626},"liquid":false},{"side":"put","strike":65,"bid":2.92,"ask":3.7,"mid":3.31,"spreadPct":0.23564954682779463,"volume":18,"openInterest":0,"iv":0.8197,"inTheMoney":false,"greeks":{"delta":-0.2316,"gamma":0.0144,"theta":-0.075,"vega":0.079},"liquid":false},{"side":"put","strike":68,"bid":4.25,"ask":5.4,"mid":4.825,"spreadPct":0.23834196891191717,"volume":2,"openInterest":0,"iv":0.8714,"inTheMoney":false,"greeks":{"delta":-0.2897,"gamma":0.0152,"theta":-0.0893,"vega":0.0886},"liquid":false}]}] +``` + +Thesis +[{"output":{"symbol":"CRWV","thesis":"CRWV (CoreWeave Inc., AI cloud infrastructure provider in Technology sector with peers SNOW/NET/MDB/APLD, recent IPO 2025-03-28; from tool Finnhub profile/peers) at 76.42 is ~59% off 52w high of 187 amid elevated volume (14M shares; from provided), operating in MIXED priceRegime with EXPANDING volRegime and HIGH nearTermSensitivity (from provided optionsRegime/technicals). Higher TFs confirm bearish control (1h/1d trend=BEARISH) while 15m is oversold near lower BB (rsiZone=OVERSOLD, bbPos=0.1688, vwapDiffPct=-27%; from provided technicals), with cross-TF conflicts (RSI neutral vs oversold; trend/momentum mismatches; from provided crossTimeframeFlags) fostering intraday volatility over clean direction. Fundamentals highlight persistent insider selling pressure (heavy 'S' transactions by McBee Brannin, Intrator, Venturo, Magnetar across Sep-Dec at $64-140+; from tool Finnhub insider-transactions), suggesting supply overhang and weak conviction amid AI hype cooldown. Provided news remains macro/politics/non-specific (e.g., FOMC minutes, Trump/Bolsonaro/Ukraine; from provided news), downweighting as low-conviction without company catalysts. Regime + conflicts prioritize vol capture; bearish swing bias from trend/drawdown/insiders trumps short-term bounce potential for resilient positioning. Profit protection favors convexity in high-sensitivity setup over premium selling amid ongoing supply risks.","marketBias":{"intraday":"VOLATILE","swing_1_5d":"BEARISH"},"confidence":65,"regime":{"priceRegime":"MIXED","volRegime":"EXPANDING","nearTermSensitivity":"HIGH"},"keyDrivers":[{"driver":"Expanding vol regime + high sensitivity (large moves expected)","weight":"HIGH","evidence":["from provided optionsRegime: volRegime=EXPANDING, nearTermSensitivity=HIGH","from provided technicals: bbWidthPct wide (1h=34%,1d=36.5%), atrPct elevated (1h=5.1%,1d=8.8%)"]},{"driver":"Bearish higher TF trend + extreme drawdown","weight":"HIGH","evidence":["from provided technicals: 1h/1d trend=BEARISH","from provided: price=76.42 vs 52wH=187 (~59% off)"]},{"driver":"Short-term oversold for potential snapback","weight":"HIGH","evidence":["from provided technicals: 15m rsiZone=OVERSOLD, bbPos=0.1688, vwapDiffPct=-0.270129"]},{"driver":"Heavy insider/institutional selling overhang","weight":"HIGH","evidence":["from tool Finnhub insider-transactions: numerous large 'S' sales (e.g., McBee/Intrator/Venturo/Magnetar in Dec 2025 at ~$65-87)"]},{"driver":"TF conflicts promote chop/volatility","weight":"MED","evidence":["from provided crossTimeframeFlags: RSI conflicts (1m/5m NEUTRAL vs 15m OVERSOLD), trend/momentum disagreements"]},{"driver":"Macro event risk (FOMC low-weight)","weight":"LOW","evidence":["from provided news: 'December FOMC minutes, housing data'"]}],"notableConflicts":[{"conflict":"15m OVERSOLD/BULLISH trend/NEG mom vs 1m/5m BEARISH/POS mom (whipsaw risk)","impact":"SWITCH_TO_VOLATILE"},{"conflict":"RSI divergence short vs longer TFs (NEUTRAL)","impact":"DOWNGRADES_CONFIDENCE"}],"optionsImplications":{"premiumBias":"BUY_PREMIUM","why":["EXPANDING vol + HIGH sensitivity risks blowups for premium sellers (from optionsRegime)","Oversold extremes + conflicts heighten reversal/continuation convexity needs (from technicals/crossFlags)"]},"invalidationSignals":["15m RSI normalizes (to NEUTRAL) + price reclaims VWAP meaningfully (from technicals)","Vol contracts: bbWidthPct/atrPct drop sharply on 1h/1d (from technicals)","1h/1d trend flips BULLISH (from technicals)","CRWV catalyst (earnings/SEC/contract) overrides technicals/insiders (absent in news/tools)"]}}] diff --git a/query.sql b/query.sql new file mode 100644 index 0000000..529d3e3 --- /dev/null +++ b/query.sql @@ -0,0 +1 @@ +SELECT p.title, p.privacy FROM playlists p JOIN users u ON p.author = u.email WHERE u.email = 'rushabh'; \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..6154214 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,8 @@ +fastapi==0.115.6 +uvicorn==0.30.6 +httpx==0.27.2 +pytest==8.3.3 +respx==0.21.1 +pytest-asyncio==0.24.0 +PyYAML==6.0.3 +websockets==12.0 diff --git a/scripts/deploy_truenas_wrapper.py b/scripts/deploy_truenas_wrapper.py new file mode 100644 index 0000000..96ab9b8 --- /dev/null +++ b/scripts/deploy_truenas_wrapper.py @@ -0,0 +1,116 @@ +import argparse +import asyncio +import json +import ssl +from typing import Any, Dict, List, Optional + +import websockets + + +async def _rpc_call(ws_url: str, api_key: str, method: str, params: Optional[list] = None, verify_ssl: bool = False) -> Any: + ssl_ctx = None + if ws_url.startswith("wss://") and not verify_ssl: + ssl_ctx = ssl.create_default_context() + ssl_ctx.check_hostname = False + ssl_ctx.verify_mode = ssl.CERT_NONE + + async with websockets.connect(ws_url, ssl=ssl_ctx) as ws: + await ws.send(json.dumps({"msg": "connect", "version": "1", "support": ["1"]})) + connected = json.loads(await ws.recv()) + if connected.get("msg") != "connected": + raise RuntimeError("failed to connect to TrueNAS websocket") + + await ws.send(json.dumps({"id": 1, "msg": "method", "method": "auth.login_with_api_key", "params": [api_key]})) + auth_resp = json.loads(await ws.recv()) + if not auth_resp.get("result"): + raise RuntimeError("API key authentication failed") + + req_id = 2 + await ws.send(json.dumps({"id": req_id, "msg": "method", "method": method, "params": params or []})) + while True: + raw = json.loads(await ws.recv()) + if raw.get("id") != req_id: + continue + if raw.get("msg") == "error": + raise RuntimeError(raw.get("error")) + return raw.get("result") + + +async def main() -> None: + parser = argparse.ArgumentParser() + parser.add_argument("--ws-url", required=True) + parser.add_argument("--api-key", required=True) + parser.add_argument("--api-user") + parser.add_argument("--app-name", required=True) + parser.add_argument("--image", required=True) + parser.add_argument("--model-host-path", required=True) + parser.add_argument("--llamacpp-base-url", required=True) + parser.add_argument("--network", required=True) + parser.add_argument("--api-port", type=int, default=9091) + parser.add_argument("--ui-port", type=int, default=9092) + parser.add_argument("--verify-ssl", action="store_true") + args = parser.parse_args() + + api_port = args.api_port + ui_port = args.ui_port + + env = { + "PORT_A": str(api_port), + "PORT_B": str(ui_port), + "LLAMACPP_BASE_URL": args.llamacpp_base_url, + "MODEL_DIR": "/models", + "TRUENAS_WS_URL": args.ws_url, + "TRUENAS_API_KEY": args.api_key, + "TRUENAS_APP_NAME": "llamacpp", + "TRUENAS_VERIFY_SSL": "false", + } + if args.api_user: + env["TRUENAS_API_USER"] = args.api_user + + compose = { + "services": { + "wrapper": { + "image": args.image, + "restart": "unless-stopped", + "ports": [ + f"{api_port}:{api_port}", + f"{ui_port}:{ui_port}", + ], + "environment": env, + "volumes": [ + f"{args.model_host_path}:/models", + "/var/run/docker.sock:/var/run/docker.sock", + ], + "networks": ["llamacpp_net"], + } + }, + "networks": { + "llamacpp_net": {"external": True, "name": args.network} + }, + } + + create_payload = { + "custom_app": True, + "app_name": args.app_name, + "custom_compose_config": compose, + } + + existing = await _rpc_call(args.ws_url, args.api_key, "app.query", [[["id", "=", args.app_name]]], args.verify_ssl) + if existing: + result = await _rpc_call( + args.ws_url, + args.api_key, + "app.update", + [args.app_name, {"custom_compose_config": compose}], + args.verify_ssl, + ) + action = "updated" + else: + result = await _rpc_call(args.ws_url, args.api_key, "app.create", [create_payload], args.verify_ssl) + action = "created" + + print(json.dumps({"action": action, "api_port": api_port, "ui_port": ui_port, "result": result}, indent=2)) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/scripts/remote_wrapper_test.py b/scripts/remote_wrapper_test.py new file mode 100644 index 0000000..518126f --- /dev/null +++ b/scripts/remote_wrapper_test.py @@ -0,0 +1,162 @@ +import json +import os +import time +from datetime import datetime + +import requests + +BASE = os.getenv("WRAPPER_BASE", "http://192.168.1.2:9000") +UPSTREAM = os.getenv("LLAMACPP_BASE", "http://192.168.1.2:8071") +RUNS = int(os.getenv("RUNS", "100")) +MAX_TOKENS = int(os.getenv("MAX_TOKENS", "4")) +TIMEOUT = int(os.getenv("REQ_TIMEOUT", "300")) + + +def _now(): + return datetime.utcnow().isoformat() + "Z" + + +def _get_loaded_model_id(): + deadline = time.time() + 600 + last_error = None + while time.time() < deadline: + try: + resp = requests.get(UPSTREAM + "/v1/models", timeout=30) + resp.raise_for_status() + data = resp.json().get("data") or [] + if data: + return data[0].get("id") + last_error = "no models reported by upstream" + except Exception as exc: + last_error = str(exc) + time.sleep(5) + raise RuntimeError(f"upstream not ready: {last_error}") + + +def _stream_ok(resp): + got_data = False + got_done = False + for line in resp.iter_lines(decode_unicode=True): + if not line: + continue + if line.startswith("data:"): + got_data = True + if line.strip() == "data: [DONE]": + got_done = True + break + return got_data, got_done + + +def run_suite(model_id, idx): + results = {} + + # Models + r = requests.get(BASE + "/v1/models", timeout=30) + results["models"] = r.status_code + + r = requests.get(BASE + f"/v1/models/{model_id}", timeout=30) + results["model_get"] = r.status_code + + # Chat completions non-stream + payload = { + "model": model_id, + "messages": [{"role": "user", "content": f"Run {idx}: say ok."}], + "max_tokens": MAX_TOKENS, + "temperature": (idx % 5) / 10.0, + } + r = requests.post(BASE + "/v1/chat/completions", json=payload, timeout=TIMEOUT) + results["chat"] = r.status_code + + # Chat completions stream + payload_stream = dict(payload) + payload_stream["stream"] = True + r = requests.post(BASE + "/v1/chat/completions", json=payload_stream, stream=True, timeout=TIMEOUT) + ok_data, ok_done = _stream_ok(r) + results["chat_stream"] = r.status_code + results["chat_stream_ok"] = ok_data and ok_done + + # Responses non-stream + payload_resp = { + "model": model_id, + "input": f"Run {idx}: say ok.", + "max_output_tokens": MAX_TOKENS, + } + r = requests.post(BASE + "/v1/responses", json=payload_resp, timeout=TIMEOUT) + results["responses"] = r.status_code + + # Responses stream + payload_resp_stream = { + "model": model_id, + "input": f"Run {idx}: say ok.", + "stream": True, + } + r = requests.post(BASE + "/v1/responses", json=payload_resp_stream, stream=True, timeout=TIMEOUT) + ok_data, ok_done = _stream_ok(r) + results["responses_stream"] = r.status_code + results["responses_stream_ok"] = ok_data and ok_done + + # Embeddings (best effort) + payload_emb = {"model": model_id, "input": f"Run {idx}"} + r = requests.post(BASE + "/v1/embeddings", json=payload_emb, timeout=TIMEOUT) + results["embeddings"] = r.status_code + + # Proxy + r = requests.post(BASE + "/proxy/llamacpp/v1/chat/completions", json=payload, timeout=TIMEOUT) + results["proxy"] = r.status_code + + return results + + +def main(): + summary = { + "started_at": _now(), + "base": BASE, + "upstream": UPSTREAM, + "runs": RUNS, + "max_tokens": MAX_TOKENS, + "results": [], + } + + model_id = _get_loaded_model_id() + summary["model_id"] = model_id + + for i in range(1, RUNS + 1): + start = time.time() + try: + results = run_suite(model_id, i) + ok = all( + results.get(key) == 200 + for key in ("models", "model_get", "chat", "chat_stream", "responses", "responses_stream", "proxy") + ) + stream_ok = results.get("chat_stream_ok") and results.get("responses_stream_ok") + summary["results"].append({ + "run": i, + "ok": ok and stream_ok, + "stream_ok": stream_ok, + "status": results, + "elapsed_s": round(time.time() - start, 2), + }) + except Exception as exc: + summary["results"].append({ + "run": i, + "ok": False, + "stream_ok": False, + "error": str(exc), + "elapsed_s": round(time.time() - start, 2), + }) + print(f"Run {i}/{RUNS} done") + + summary["finished_at"] = _now() + + os.makedirs("reports", exist_ok=True) + out_path = os.path.join("reports", "remote_wrapper_test.json") + with open(out_path, "w", encoding="utf-8") as f: + json.dump(summary, f, indent=2) + + # Print a compact summary + ok_count = sum(1 for r in summary["results"] if r.get("ok")) + print(f"OK {ok_count}/{RUNS}") + + +if __name__ == "__main__": + main() diff --git a/scripts/update_llamacpp_flags.ps1 b/scripts/update_llamacpp_flags.ps1 new file mode 100644 index 0000000..666816e --- /dev/null +++ b/scripts/update_llamacpp_flags.ps1 @@ -0,0 +1,29 @@ +param( + [string]$OutDocs = "reports\\llamacpp_docs.md", + [string]$OutFlags = "reports\\llamacpp_flags.txt" +) + +$urls = @( + "https://raw.githubusercontent.com/ggerganov/llama.cpp/master/examples/server/README.md", + "https://raw.githubusercontent.com/ggerganov/llama.cpp/master/examples/server/README-llama-server.md", + "https://raw.githubusercontent.com/ggerganov/llama.cpp/master/README.md" +) + +$out = @() +foreach ($u in $urls) { + try { + $content = Invoke-WebRequest -Uri $u -UseBasicParsing -TimeoutSec 30 + $out += "# Source: $u" + $out += $content.Content + } catch { + $out += "# Source: $u" + $out += "(failed to fetch)" + } +} + +$out | Set-Content -Encoding UTF8 $OutDocs + +$docs = Get-Content $OutDocs -Raw +$flags = [regex]::Matches($docs, "--[a-zA-Z0-9\\-]+") | ForEach-Object { $_.Value } +$flags = $flags | Sort-Object -Unique +$flags | Set-Content -Encoding UTF8 $OutFlags diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..978c788 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,61 @@ +import json +import os +from pathlib import Path + +import pytest +from fastapi.testclient import TestClient +import respx + +from app.api_app import create_api_app +from app.ui_app import create_ui_app + + +@pytest.fixture() +def agents_config(tmp_path: Path) -> Path: + data = { + "image": "ghcr.io/ggml-org/llama.cpp:server-cuda", + "container_name": "ix-llamacpp-llamacpp-1", + "host_port": 8071, + "container_port": 8080, + "web_ui_url": "http://0.0.0.0:8071/", + "model_host_path": str(tmp_path), + "model_container_path": str(tmp_path), + "models": [], + "network": "ix-llamacpp_default", + "subnets": ["172.16.18.0/24"], + "gpu_count": 2, + "gpu_name": "NVIDIA RTX 5060 Ti", + } + path = tmp_path / "agents_config.json" + path.write_text(json.dumps(data), encoding="utf-8") + return path + + +@pytest.fixture() +def model_dir(tmp_path: Path) -> Path: + (tmp_path / "model-a.gguf").write_text("x", encoding="utf-8") + (tmp_path / "model-b.gguf").write_text("y", encoding="utf-8") + return tmp_path + + +@pytest.fixture() +def api_client(monkeypatch: pytest.MonkeyPatch, agents_config: Path, model_dir: Path): + monkeypatch.setenv("AGENTS_CONFIG_PATH", str(agents_config)) + monkeypatch.setenv("MODEL_DIR", str(model_dir)) + monkeypatch.setenv("LLAMACPP_BASE_URL", "http://llama.test") + app = create_api_app() + return TestClient(app) + + +@pytest.fixture() +def ui_client(monkeypatch: pytest.MonkeyPatch, agents_config: Path, model_dir: Path): + monkeypatch.setenv("AGENTS_CONFIG_PATH", str(agents_config)) + monkeypatch.setenv("MODEL_DIR", str(model_dir)) + app = create_ui_app() + return TestClient(app) + + +@pytest.fixture() +def respx_mock(): + with respx.mock(assert_all_called=False) as mock: + yield mock diff --git a/tests/test_chat_completions.py b/tests/test_chat_completions.py new file mode 100644 index 0000000..e92af3f --- /dev/null +++ b/tests/test_chat_completions.py @@ -0,0 +1,77 @@ +import json +import pytest +import httpx + + +@pytest.mark.parametrize("case", list(range(120))) +def test_chat_completions_non_stream(api_client, respx_mock, case): + respx_mock.get("http://llama.test/v1/models").mock( + return_value=httpx.Response(200, json={"data": [{"id": "model-a.gguf"}]}) + ) + respx_mock.post("http://llama.test/v1/chat/completions").mock( + return_value=httpx.Response(200, json={"id": f"chatcmpl-{case}", "choices": [{"message": {"content": "ok"}}]}) + ) + + payload = { + "model": "model-a.gguf", + "messages": [{"role": "user", "content": f"hello {case}"}], + "temperature": (case % 10) / 10, + } + resp = api_client.post("/v1/chat/completions", json=payload) + assert resp.status_code == 200 + data = resp.json() + assert data["choices"][0]["message"]["content"] == "ok" + + +@pytest.mark.parametrize("case", list(range(120))) +def test_chat_completions_stream(api_client, respx_mock, case): + respx_mock.get("http://llama.test/v1/models").mock( + return_value=httpx.Response(200, json={"data": [{"id": "model-a.gguf"}]}) + ) + + def stream_response(request): + content = b"data: {\"id\": \"chunk\"}\n\n" + return httpx.Response(200, content=content, headers={"Content-Type": "text/event-stream"}) + + respx_mock.post("http://llama.test/v1/chat/completions").mock(side_effect=stream_response) + + payload = { + "model": "model-a.gguf", + "messages": [{"role": "user", "content": f"hello {case}"}], + "stream": True, + } + with api_client.stream("POST", "/v1/chat/completions", json=payload) as resp: + assert resp.status_code == 200 + body = b"".join(resp.iter_bytes()) + assert b"data:" in body + + +def test_chat_completions_tools_normalize(api_client, respx_mock): + respx_mock.get("http://llama.test/v1/models").mock( + return_value=httpx.Response(200, json={"data": [{"id": "model-a.gguf"}]}) + ) + + def handler(request): + data = request.json() + tools = data.get("tools") or [] + assert tools + assert tools[0].get("function", {}).get("name") == "format_final_json_response" + return httpx.Response(200, json={"id": "chatcmpl-tools", "choices": [{"message": {"content": "ok"}}]}) + + respx_mock.post("http://llama.test/v1/chat/completions").mock(side_effect=handler) + + payload = { + "model": "model-a.gguf", + "messages": [{"role": "user", "content": "hello"}], + "tools": [ + { + "type": "function", + "name": "format_final_json_response", + "parameters": {"type": "object"}, + } + ], + "tool_choice": {"type": "function", "name": "format_final_json_response"}, + } + + resp = api_client.post("/v1/chat/completions", json=payload) + assert resp.status_code == 200 diff --git a/tests/test_embeddings.py b/tests/test_embeddings.py new file mode 100644 index 0000000..e7a240e --- /dev/null +++ b/tests/test_embeddings.py @@ -0,0 +1,14 @@ +import pytest +import httpx + + +@pytest.mark.parametrize("case", list(range(120))) +def test_embeddings(api_client, respx_mock, case): + respx_mock.post("http://llama.test/v1/embeddings").mock( + return_value=httpx.Response(200, json={"data": [{"embedding": [0.1, 0.2]}]}) + ) + payload = {"model": "model-a.gguf", "input": f"text-{case}"} + resp = api_client.post("/v1/embeddings", json=payload) + assert resp.status_code == 200 + data = resp.json() + assert "data" in data diff --git a/tests/test_models.py b/tests/test_models.py new file mode 100644 index 0000000..9a114cf --- /dev/null +++ b/tests/test_models.py @@ -0,0 +1,24 @@ +import pytest + + +@pytest.mark.parametrize("case", list(range(120))) +def test_list_models_cases(api_client, case): + resp = api_client.get("/v1/models", headers={"x-case": str(case)}) + assert resp.status_code == 200 + payload = resp.json() + assert payload["object"] == "list" + assert isinstance(payload["data"], list) + + +@pytest.mark.parametrize("model_id", [f"model-a.gguf" for _ in range(120)]) +def test_get_model_ok(api_client, model_id): + resp = api_client.get(f"/v1/models/{model_id}") + assert resp.status_code == 200 + payload = resp.json() + assert payload["id"] == model_id + + +@pytest.mark.parametrize("model_id", [f"missing-{i}" for i in range(120)]) +def test_get_model_not_found(api_client, model_id): + resp = api_client.get(f"/v1/models/{model_id}") + assert resp.status_code == 404 diff --git a/tests/test_proxy.py b/tests/test_proxy.py new file mode 100644 index 0000000..4ca3f7f --- /dev/null +++ b/tests/test_proxy.py @@ -0,0 +1,12 @@ +import pytest +import httpx + + +@pytest.mark.parametrize("case", list(range(120))) +def test_proxy_passthrough(api_client, respx_mock, case): + respx_mock.post("http://llama.test/test/path").mock( + return_value=httpx.Response(200, content=f"ok-{case}".encode()) + ) + resp = api_client.post("/proxy/llamacpp/test/path", content=b"hello") + assert resp.status_code == 200 + assert resp.content.startswith(b"ok-") diff --git a/tests/test_remote_wrapper.py b/tests/test_remote_wrapper.py new file mode 100644 index 0000000..177c20e --- /dev/null +++ b/tests/test_remote_wrapper.py @@ -0,0 +1,283 @@ +import asyncio +import json +import os +import ssl +import time +from typing import Dict, List + +import pytest +import requests +import websockets + +WRAPPER_BASE = os.getenv("WRAPPER_BASE", "http://192.168.1.2:9093") +UI_BASE = os.getenv("UI_BASE", "http://192.168.1.2:9094") +TRUENAS_WS_URL = os.getenv("TRUENAS_WS_URL", "wss://192.168.1.2/websocket") +TRUENAS_API_KEY = os.getenv("TRUENAS_API_KEY", "") +TRUENAS_APP_NAME = os.getenv("TRUENAS_APP_NAME", "llamacpp") +MODEL_REQUEST = os.getenv("MODEL_REQUEST", "") + + +async def _rpc_call(method: str, params: List | None = None): + if not TRUENAS_API_KEY: + pytest.skip("TRUENAS_API_KEY not set") + ssl_ctx = ssl.create_default_context() + ssl_ctx.check_hostname = False + ssl_ctx.verify_mode = ssl.CERT_NONE + async with websockets.connect(TRUENAS_WS_URL, ssl=ssl_ctx) as ws: + await ws.send(json.dumps({"msg": "connect", "version": "1", "support": ["1"]})) + connected = json.loads(await ws.recv()) + if connected.get("msg") != "connected": + raise RuntimeError("failed to connect") + await ws.send(json.dumps({"id": 1, "msg": "method", "method": "auth.login_with_api_key", "params": [TRUENAS_API_KEY]})) + auth = json.loads(await ws.recv()) + if not auth.get("result"): + raise RuntimeError("auth failed") + await ws.send(json.dumps({"id": 2, "msg": "method", "method": method, "params": params or []})) + while True: + raw = json.loads(await ws.recv()) + if raw.get("id") != 2: + continue + if raw.get("msg") == "error": + raise RuntimeError(raw.get("error")) + return raw.get("result") + + +def _get_models() -> List[str]: + _wait_for_http(WRAPPER_BASE + "/health") + resp = requests.get(WRAPPER_BASE + "/v1/models", timeout=30) + resp.raise_for_status() + data = resp.json().get("data") or [] + return [m.get("id") for m in data if m.get("id")] + + +def _assert_chat_ok(resp_json: Dict) -> str: + choices = resp_json.get("choices") or [] + assert choices, "no choices" + message = choices[0].get("message") or {} + text = message.get("content") or "" + assert text.strip(), "empty content" + return text + + +def _wait_for_http(url: str, timeout_s: float = 90) -> None: + deadline = time.time() + timeout_s + last_err = None + while time.time() < deadline: + try: + resp = requests.get(url, timeout=5) + if resp.status_code == 200: + return + last_err = f"status {resp.status_code}" + except Exception as exc: + last_err = str(exc) + time.sleep(2) + raise RuntimeError(f"service not ready: {url} ({last_err})") + + +def _post_with_retry(url: str, payload: Dict, timeout_s: float = 300, retries: int = 6, delay_s: float = 5.0): + last = None + for _ in range(retries): + try: + resp = requests.post(url, json=payload, timeout=timeout_s) + if resp.status_code == 200: + return resp + last = resp + except requests.exceptions.RequestException as exc: + last = exc + time.sleep(delay_s) + if isinstance(last, Exception): + raise last + return last + + +@pytest.mark.asyncio +async def test_active_model_and_multi_gpu_flags(): + cfg = await _rpc_call("app.config", [TRUENAS_APP_NAME]) + command = cfg.get("command") or [] + assert "--model" in command + assert "--tensor-split" in command + split_idx = command.index("--tensor-split") + 1 + split = command[split_idx] + assert "," in split, f"tensor-split missing commas: {split}" + assert "--split-mode" in command + + +def test_models_listed(): + models = _get_models() + assert models, "no models discovered" + + +def test_chat_completions_switch_and_prompts(): + models = _get_models() + assert models, "no models" + if MODEL_REQUEST: + assert MODEL_REQUEST in models, f"MODEL_REQUEST not found: {MODEL_REQUEST}" + model_id = MODEL_REQUEST + else: + model_id = models[0] + payload = { + "model": model_id, + "messages": [{"role": "user", "content": "Say OK."}], + "max_tokens": 12, + "temperature": 0, + } + for _ in range(3): + resp = _post_with_retry(WRAPPER_BASE + "/v1/chat/completions", payload) + assert resp.status_code == 200 + _assert_chat_ok(resp.json()) + + +def test_tools_flat_format(): + models = _get_models() + assert models, "no models" + if MODEL_REQUEST: + assert MODEL_REQUEST in models, f"MODEL_REQUEST not found: {MODEL_REQUEST}" + model_id = MODEL_REQUEST + else: + model_id = models[0] + payload = { + "model": model_id, + "messages": [{"role": "user", "content": "Say OK and do not call tools."}], + "tools": [ + { + "type": "function", + "name": "format_final_json_response", + "description": "format output", + "parameters": { + "type": "object", + "properties": {"ok": {"type": "boolean"}}, + "required": ["ok"], + }, + } + ], + "max_tokens": 12, + } + resp = _post_with_retry(WRAPPER_BASE + "/v1/chat/completions", payload) + assert resp.status_code == 200 + _assert_chat_ok(resp.json()) + + +def test_functions_payload_normalized(): + models = _get_models() + assert models, "no models" + if MODEL_REQUEST: + assert MODEL_REQUEST in models, f"MODEL_REQUEST not found: {MODEL_REQUEST}" + model_id = MODEL_REQUEST + else: + model_id = models[0] + payload = { + "model": model_id, + "messages": [{"role": "user", "content": "Say OK and do not call tools."}], + "functions": [ + { + "name": "format_final_json_response", + "description": "format output", + "parameters": { + "type": "object", + "properties": {"ok": {"type": "boolean"}}, + "required": ["ok"], + }, + } + ], + "max_tokens": 12, + } + resp = _post_with_retry(WRAPPER_BASE + "/v1/chat/completions", payload) + assert resp.status_code == 200 + _assert_chat_ok(resp.json()) + + +def test_return_format_json(): + models = _get_models() + assert models, "no models" + if MODEL_REQUEST: + assert MODEL_REQUEST in models, f"MODEL_REQUEST not found: {MODEL_REQUEST}" + model_id = MODEL_REQUEST + else: + model_id = models[0] + payload = { + "model": model_id, + "messages": [{"role": "user", "content": "Return JSON with key ok true."}], + "return_format": "json", + "max_tokens": 32, + "temperature": 0, + } + resp = _post_with_retry(WRAPPER_BASE + "/v1/chat/completions", payload) + assert resp.status_code == 200 + text = _assert_chat_ok(resp.json()) + parsed = json.loads(text) + assert isinstance(parsed, dict) + + +def test_responses_endpoint(): + models = _get_models() + assert models, "no models" + if MODEL_REQUEST: + assert MODEL_REQUEST in models, f"MODEL_REQUEST not found: {MODEL_REQUEST}" + model_id = MODEL_REQUEST + else: + model_id = models[0] + payload = { + "model": model_id, + "input": "Say OK.", + "max_output_tokens": 16, + } + resp = _post_with_retry(WRAPPER_BASE + "/v1/responses", payload) + assert resp.status_code == 200 + output = resp.json().get("output") or [] + assert output, "responses output empty" + content = output[0].get("content") or [] + text = content[0].get("text") if content else "" + assert text and text.strip() + + +@pytest.mark.asyncio +async def test_model_switch_applied_to_truenas(): + models = _get_models() + assert models, "no models" + target = MODEL_REQUEST or models[0] + assert target in models, f"MODEL_REQUEST not found: {target}" + resp = requests.post(UI_BASE + "/ui/api/switch-model", json={"model_id": target, "warmup_prompt": "warmup"}, timeout=600) + assert resp.status_code == 200 + cfg = await _rpc_call("app.config", [TRUENAS_APP_NAME]) + command = cfg.get("command") or [] + assert "--model" in command + model_path = command[command.index("--model") + 1] + assert model_path.endswith(target) + + +def test_invalid_model_rejected(): + models = _get_models() + assert models, "no models" + payload = { + "model": "modelx-q8:4b", + "messages": [{"role": "user", "content": "Say OK."}], + "max_tokens": 8, + "temperature": 0, + } + resp = requests.post(WRAPPER_BASE + "/v1/chat/completions", json=payload, timeout=60) + assert resp.status_code == 404 + + +def test_llamacpp_logs_streaming(): + logs = "" + for _ in range(5): + try: + resp = requests.get(UI_BASE + "/ui/api/llamacpp-logs", timeout=10) + if resp.status_code == 200: + logs = resp.json().get("logs") or "" + if logs.strip(): + break + except requests.exceptions.ReadTimeout: + pass + time.sleep(2) + assert logs.strip(), "no logs returned" + + # Force a log line before streaming. + try: + requests.get(WRAPPER_BASE + "/proxy/llamacpp/health", timeout=5) + except Exception: + pass + + # Stream endpoint may not emit immediately, so validate that the endpoint responds. + with requests.get(UI_BASE + "/ui/api/llamacpp-logs/stream", stream=True, timeout=(5, 5)) as resp: + assert resp.status_code == 200 diff --git a/tests/test_responses.py b/tests/test_responses.py new file mode 100644 index 0000000..79a0109 --- /dev/null +++ b/tests/test_responses.py @@ -0,0 +1,55 @@ +import json +import pytest +import httpx + + +@pytest.mark.parametrize("case", list(range(120))) +def test_responses_non_stream(api_client, respx_mock, case): + respx_mock.get("http://llama.test/v1/models").mock( + return_value=httpx.Response(200, json={"data": [{"id": "model-a.gguf"}]}) + ) + respx_mock.post("http://llama.test/v1/chat/completions").mock( + return_value=httpx.Response(200, json={"choices": [{"message": {"content": f"reply-{case}"}}]}) + ) + + payload = { + "model": "model-a.gguf", + "input": f"prompt-{case}", + "max_output_tokens": 32, + } + resp = api_client.post("/v1/responses", json=payload) + assert resp.status_code == 200 + data = resp.json() + assert data["object"] == "response" + assert data["output"][0]["content"][0]["text"].startswith("reply-") + + +@pytest.mark.parametrize("case", list(range(120))) +def test_responses_stream(api_client, respx_mock, case): + respx_mock.get("http://llama.test/v1/models").mock( + return_value=httpx.Response(200, json={"data": [{"id": "model-a.gguf"}]}) + ) + + def stream_response(request): + payload = { + "id": "chunk", + "object": "chat.completion.chunk", + "choices": [{"delta": {"content": f"hi-{case}"}, "index": 0, "finish_reason": None}], + } + content = f"data: {json.dumps(payload)}\n\n".encode() + content += b"data: [DONE]\n\n" + return httpx.Response(200, content=content, headers={"Content-Type": "text/event-stream"}) + + respx_mock.post("http://llama.test/v1/chat/completions").mock(side_effect=stream_response) + + payload = { + "model": "model-a.gguf", + "input": f"prompt-{case}", + "stream": True, + } + with api_client.stream("POST", "/v1/responses", json=payload) as resp: + assert resp.status_code == 200 + body = b"".join(resp.iter_bytes()) + assert b"event: response.created" in body + assert b"event: response.output_text.delta" in body + assert b"event: response.completed" in body diff --git a/tests/test_truenas_switch.py b/tests/test_truenas_switch.py new file mode 100644 index 0000000..2efebea --- /dev/null +++ b/tests/test_truenas_switch.py @@ -0,0 +1,54 @@ +import json +import pytest + +from app.truenas_middleware import TrueNASConfig, switch_model + + +@pytest.mark.asyncio +@pytest.mark.parametrize("case", list(range(120))) +async def test_switch_model_updates_command(monkeypatch, case): + compose = { + "services": { + "llamacpp": { + "command": [ + "--model", + "/models/old.gguf", + "--ctx-size", + "2048", + ] + } + } + } + + captured = {} + + async def fake_rpc_call(cfg, method, params=None): + if method == "app.config": + return {"custom_compose_config": compose} + if method == "app.update": + captured["payload"] = params[1] + return {"state": "RUNNING"} + raise AssertionError(f"unexpected method {method}") + + monkeypatch.setattr("app.truenas_middleware._rpc_call", fake_rpc_call) + + cfg = TrueNASConfig( + ws_url="ws://truenas.test/websocket", + api_key="key", + api_user=None, + app_name="llamacpp", + verify_ssl=False, + ) + + await switch_model( + cfg, + f"/models/new-{case}.gguf", + {"n_gpu_layers": "999"}, + "--flash-attn on", + ) + + assert "custom_compose_config" in captured["payload"] + cmd = captured["payload"]["custom_compose_config"]["services"]["llamacpp"]["command"] + assert "--model" in cmd + idx = cmd.index("--model") + assert cmd[idx + 1].endswith(f"new-{case}.gguf") diff --git a/tests/test_ui.py b/tests/test_ui.py new file mode 100644 index 0000000..59a970d --- /dev/null +++ b/tests/test_ui.py @@ -0,0 +1,48 @@ +import json +import os +import time + +import pytest +import requests + +UI_BASE = os.getenv("UI_BASE", "http://192.168.1.2:9094") + +def _wait_for_http(url: str, timeout_s: float = 90) -> None: + deadline = time.time() + timeout_s + last_err = None + while time.time() < deadline: + try: + resp = requests.get(url, timeout=5) + if resp.status_code == 200: + return + last_err = f"status {resp.status_code}" + except Exception as exc: + last_err = str(exc) + time.sleep(2) + raise RuntimeError(f"service not ready: {url} ({last_err})") + + +def test_ui_index_contains_expected_elements(): + _wait_for_http(UI_BASE + "/health") + resp = requests.get(UI_BASE + "/", timeout=30) + assert resp.status_code == 200 + html = resp.text + assert "Model Manager" in html + assert "id=\"download-form\"" in html + assert "id=\"models-list\"" in html + assert "id=\"logs-output\"" in html + assert "id=\"theme-toggle\"" in html + + +def test_ui_assets_available(): + resp = requests.get(UI_BASE + "/ui/styles.css", timeout=30) + assert resp.status_code == 200 + css = resp.text + assert "data-theme" in css + + resp = requests.get(UI_BASE + "/ui/app.js", timeout=30) + assert resp.status_code == 200 + js = resp.text + assert "themeToggle" in js + assert "localStorage" in js + assert "logs-output" in js diff --git a/tmp_channels_cols.sql b/tmp_channels_cols.sql new file mode 100644 index 0000000..6253ee6 --- /dev/null +++ b/tmp_channels_cols.sql @@ -0,0 +1 @@ +SELECT column_name, data_type FROM information_schema.columns WHERE table_name='channels' ORDER BY ordinal_position; diff --git a/tmp_pref_type.sql b/tmp_pref_type.sql new file mode 100644 index 0000000..7b841f7 --- /dev/null +++ b/tmp_pref_type.sql @@ -0,0 +1 @@ +SELECT data_type FROM information_schema.columns WHERE table_name='users' AND column_name='preferences'; diff --git a/tmp_update_max_results.sql b/tmp_update_max_results.sql new file mode 100644 index 0000000..0140c3a --- /dev/null +++ b/tmp_update_max_results.sql @@ -0,0 +1 @@ +UPDATE users SET preferences = (jsonb_set(preferences::jsonb, '{max_results}', '200'::jsonb, true))::text WHERE email='rushabh'; diff --git a/trades_company_stock.txt b/trades_company_stock.txt new file mode 100644 index 0000000..46fac35 --- /dev/null +++ b/trades_company_stock.txt @@ -0,0 +1,56 @@ +You are a senior quantitative options trader (index/ETF options across regimes; also liquid single-name options and macro-sensitive metal ETFs), specializing in volatility, structure selection, and risk asymmetry. Decisive, skeptical, profit-focused. + +You are given: +- A validated market thesis (authoritative): multi-timeframe technicals, regime, volatility context, news impact. +- Pre-processed options chains for three expiries (short / medium / extended) with liquidity-filtered contracts, ATM/delta anchors, delta ladders, and a liquid execution set. +- All pricing, greeks, spreads, and liquidity metrics required for execution-quality decisions. + +Assume: +- Data is correct and cleaned. +- You must NOT re-analyze technicals or news; the thesis is authoritative. +- Your job is to convert thesis + surface into executable options trades. + +Objective: +- Select the best expiry and propose 1–3 high-quality options trades that align with thesis bias/regime, exploit volatility characteristics (gamma/theta/vega fit), are liquid/fillable/risk-defined, and include clear invalidation logic. +- If no trade offers favorable risk/reward: strategyBias=NO_TRADE and explain why. + +How to decide: +1) Compare expiries: match time-to-playout vs confidence/uncertainty; match vol regime (expansion vs decay); reject poor liquidity density; reject misaligned vega/theta; avoid overpaying for time/vol. +2) Choose structure class (explicitly justify vs alternatives): directional debit (single/vertical), volatility (straddle/strangle), defined-risk premium selling only if the regime supports it. +3) Select strikes ONLY from provided data (ATM anchor, delta ladder, liquidSet). Prefer tight spreads, meaningful volume & OI, and greeks that express the thesis. +4) Risk discipline: every trade must include max risk, what must go right, and what breaks the trade (invalidation). + +Optional tools (use only when they materially improve decision quality; otherwise do not call): +- MarketData – Options Chain (expiry-specific): only if provided expiries do not sufficiently match the thesis horizon, or liquidity/skew is materially better in a nearby expiry not already supplied. Choose an explicit expiry date. Use returned data only for strike selection and liquidity validation. Do not re-fetch already provided expiries unless validating anomalies. +- Fear & Greed Index (FGI): only for index/ETF/macro-sensitive underlyings (e.g., SPX, NDX, IWM, SLV). Contextual only (risk appetite / convexity vs tempered), not a primary signal. + +Hard constraints: +- Do NOT invent strikes, expiries, or prices. +- Do NOT suggest illiquid contracts. +- Do NOT recommend naked risk. +- Do NOT hedge unless justified. +- Do NOT repeat raw data back. + +Return ONLY valid JSON in exactly this shape: +{ + "selectedExpiry": "YYYY-MM-DD", + "expiryRationale": "Why this expiry dominates the others given thesis + vol + liquidity", + "strategyBias": "DIRECTIONAL|VOLATILITY|NEUTRAL|NO_TRADE", + "recommendedTrades": [ + { + "name": "Short descriptive name", + "structure": "e.g. Long Call, Call Debit Spread, Long Strangle", + "legs": [{"side":"call|put","action":"buy|sell","strike":0,"expiry":"YYYY-MM-DD"}], + "greekProfile": {"deltaBias":"POS|NEG|NEUTRAL","gammaExposure":"HIGH|MED|LOW","thetaExposure":"POS|NEG|LOW","vegaExposure":"HIGH|MED|LOW"}, + "maxRisk": "Defined numeric or qualitative", + "maxReward": "Defined numeric or qualitative", + "thesisAlignment": "Exactly how this trade expresses the thesis", + "invalidation": "Clear condition where trade is wrong", + "managementNotes": "Optional: scale, take-profit, time stop" + } + ], + "whyOthersRejected": ["Why other expiries or strategy types were inferior"], + "confidenceScore": 0 +} + +Final note: optimize for repeatable profitability under uncertainty. If conditions are marginal, say NO_TRADE with conviction.