Files
2026-05-12 11:04:17 +02:00

82 lines
2.9 KiB
Python

"""Plesk REST API Client.
Nutzt den CLI-Wrapper /api/v2/cli/{utility}/call. Vorteile:
- mappt 1:1 auf `plesk bin mail`
- stabil über Plesk-Versionen hinweg
- Fehlertexte sind die gleichen wie auf der Shell.
"""
from typing import Optional
import requests
import urllib3
class PleskError(Exception):
pass
class PleskClient:
def __init__(self, host: str, *, api_key: Optional[str] = None,
user: Optional[str] = None, password: Optional[str] = None,
port: int = 8443, verify: bool = True):
if not host:
raise PleskError("Plesk-Host ist leer")
self.base = f"https://{host}:{port}"
self.session = requests.Session()
self.session.verify = verify
if not verify:
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
if api_key:
self.session.headers["X-API-Key"] = api_key
elif user and password:
self.session.auth = (user, password)
else:
raise PleskError(
"Plesk: Weder API-Key noch User/Passwort gesetzt. "
"Siehe README → Plesk-API-Key per SSH erzeugen."
)
self.session.headers["Content-Type"] = "application/json"
self.session.headers["Accept"] = "application/json"
def close(self) -> None:
try:
self.session.close()
except Exception:
pass
def _cli(self, utility: str, params: list) -> dict:
url = f"{self.base}/api/v2/cli/{utility}/call"
try:
r = self.session.post(url, json={"params": params}, timeout=30)
except requests.RequestException as e:
raise PleskError(f"Plesk Verbindung fehlgeschlagen: {e}")
if r.status_code == 401:
raise PleskError("Plesk: Authentifizierung fehlgeschlagen (API-Key/Login prüfen)")
if not r.ok:
raise PleskError(f"Plesk HTTP {r.status_code}: {r.text[:300]}")
try:
data = r.json()
except ValueError:
raise PleskError(f"Plesk: ungültige Antwort: {r.text[:300]}")
if data.get("code", 0) != 0:
err = (data.get("stderr") or data.get("stdout") or "").strip()
raise PleskError(f"Plesk CLI exit {data.get('code')}: {err}")
return data
def mail_exists(self, email: str) -> bool:
try:
self._cli("mail", ["--info", email])
return True
except PleskError as e:
msg = str(e).lower()
if "does not exist" in msg or "not found" in msg or "unknown mailname" in msg:
return False
raise
def create_mail(self, email: str, password: str) -> None:
# plesk bin mail --create user@dom -passwd 'pw' -mailbox true
self._cli("mail", [
"--create", email,
"-passwd", password,
"-mailbox", "true",
])