From bc99c6f9825f3991b8b52bd027340ce505a07dda Mon Sep 17 00:00:00 2001 From: host Date: Mon, 3 Aug 2026 00:17:32 +0300 Subject: [PATCH] =?UTF-8?q?v2.1.1:=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=20discover=5Fapp?= =?UTF-8?q?=5Fendpoints()=20=D0=B4=D0=BB=D1=8F=20=D0=B4=D0=B8=D0=B0=D0=B3?= =?UTF-8?q?=D0=BD=D0=BE=D1=81=D1=82=D0=B8=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- truenas_tools.py | 81 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/truenas_tools.py b/truenas_tools.py index ac8b01a..906010b 100644 --- a/truenas_tools.py +++ b/truenas_tools.py @@ -1,17 +1,64 @@ -payload: Dict[str, Any] = {"catalog_name": catalog, "retrieve_all_trains": True} - if category: - payload["categories"] = [category] - # v2.1.1: расширенный список эндпоинтов — TrueNAS 25.10 имеет разные пути - # в зависимости от версии (chart/release/ — новые, catalog/ — старые) - endpoints = [ - "app/available", # новый (Electric Eel+) - "app.available", - "chart/release/names", # иногда используется - "chart.release.names", - "chart_release/names", - "catalog/items", # fallback - "catalog.items", - "catalog_items", - "app/available_apps", - "app/list_apps", - ] \ No newline at end of file +# ----------------------------------------------------------------- + # Каталоги и приложения (v2.1+) + # ----------------------------------------------------------------- + def discover_app_endpoints(self) -> str: + """ + Диагностический метод: проверяет разные эндпоинты API каталога приложений + и сообщает, какие из них реально работают на этой версии TrueNAS. + Полезно при обновлении truenas_tools.py или при ошибках в list_app_catalog. + """ + candidates_get = [ + "app/available", "app/available_apps", "app/list_apps", + "chart/release/names", "chart/release", "chart/release/list", + "catalog", "catalog?label=TRUENAS", "catalog/items", + "catalogs", "app/catalog", + ] + candidates_post = [ + ("app/available", {"catalog_name": "TRUENAS", "retrieve_all_trains": True}), + ("app/available", {}), + ("app.available", {"catalog_name": "TRUENAS"}), + ("chart/release/names", {"catalog_name": "TRUENAS"}), + ("chart.release.names", {}), + ("chart_release/names", {"catalog_name": "TRUENAS"}), + ("catalog/items", {"label": "TRUENAS"}), + ] + lines = ["🔍 ДИАГНОСТИКА ЭНДПОИНТОВ КАТАЛОГА", ""] + lines.append("=== GET ===") + for ep in candidates_get: + url = f"{self._base}/api/v2.0/{ep}" + try: + r = requests.get(url, headers=self._headers, timeout=self.valves.request_timeout, verify=self.valves.verify_ssl) + if r.status_code == 200: + body = r.text[:120].replace("\n", " ") + lines.append(f"✅ {ep:35s} HTTP 200 | {body}") + elif r.status_code == 404: + lines.append(f"❌ {ep:35s} HTTP 404") + elif r.status_code in (401, 403): + lines.append(f"🔑 {ep:35s} HTTP {r.status_code} (нет прав)") + else: + lines.append(f"⚠️ {ep:35s} HTTP {r.status_code}") + except Exception as e: + lines.append(f"💥 {ep:35s} ошибка: {type(e).__name__}") + lines.append("") + lines.append("=== POST ===") + for ep, payload in candidates_post: + url = f"{self._base}/api/v2.0/{ep}" + try: + r = requests.post(url, headers=self._headers, json=payload, timeout=self.valves.request_timeout, verify=self.valves.verify_ssl) + if r.status_code == 200: + body = r.text[:120].replace("\n", " ") + lines.append(f"✅ {ep:35s} HTTP 200 | {body}") + elif r.status_code == 404: + lines.append(f"❌ {ep:35s} HTTP 404") + elif r.status_code in (401, 403): + lines.append(f"🔑 {ep:35s} HTTP {r.status_code} (нет прав)") + else: + lines.append(f"⚠️ {ep:35s} HTTP {r.status_code}") + except Exception as e: + lines.append(f"💥 {ep:35s} ошибка: {type(e).__name__}") + lines.append("") + lines.append("ℹ️ Также можно посмотреть Swagger-документацию API:") + lines.append(f" {self._base}/api/docs/") + return "\n".join(lines) + + def list_catalogs(self) -> str: \ No newline at end of file