добрыйхостинг

База знаний API

API: готовые примеры

Скрипты на bash, Python и Node.js: перезагрузка по тегу, экспорт метрик, мониторинг доступности, cron.

4 мин чтения · раздел «API»

Во всех примерах токен берётся из переменной окружения DOBRY_TOKEN.

bash: перезагрузить все серверы с тегом vpn

#!/usr/bin/env bash
set -euo pipefail
API=https://panel.dobry.host/api
H="Authorization: Bearer $DOBRY_TOKEN"
for id in $(curl -sf "$API/servers" -H "$H" | jq -r '.servers[] | select(.tags | index("vpn")) | .id'); do
  key="cron-$(date +%Y%m%d%H)-$id"
  curl -sf -X POST "$API/servers/$id/actions" -H "$H" -H "Content-Type: application/json" \
    -d "{\"action\":\"reboot\",\"idempotency_key\":\"$key\"}" | jq -c '{id: .operation.id, status: .operation.status}'
done

Ключ cron-ГГГГММДДЧЧ-id гарантирует, что при повторном запуске в тот же час сервер не перезагрузится второй раз.

Python: клиент с обработкой ошибок и лимитов

import os, time, requests

class Dobry:
    def __init__(self, token=None, base="https://panel.dobry.host/api"):
        self.s = requests.Session()
        self.s.headers["Authorization"] = "Bearer " + (token or os.environ["DOBRY_TOKEN"])
        self.base = base

    def call(self, method, path, **kw):
        for attempt in range(3):
            r = self.s.request(method, self.base + path, timeout=20, **kw)
            if r.status_code == 429:            # лимит 120/мин — подождать
                time.sleep(5 * (attempt + 1)); continue
            data = r.json()
            if not data.get("ok"):
                raise RuntimeError(f"{data['error']['code']}: {data['error']['message']}")
            return data
        raise RuntimeError("rate limit")

    def servers(self):
        return self.call("GET", "/servers")["servers"]

    def action(self, sid, action, key):
        return self.call("POST", f"/servers/{sid}/actions", json={"action": action, "idempotency_key": key})["operation"]

    def metrics(self, sid, rng="24h"):
        return self.call("GET", f"/servers/{sid}/metrics", params={"range": rng})["metrics"]

api = Dobry()
for s in api.servers():
    m = api.metrics(s["id"], "1h")
    last = m["points"][-1] if m["points"] else None
    print(s["name"], s["ip"], "cpu:", last["cpu"] if last else "нет агента")

Python: экспорт метрик за сутки в CSV

import csv
api = Dobry()
with open("metrics.csv", "w", newline="") as f:
    w = csv.writer(f); w.writerow(["server", "time", "cpu", "mem_gb", "disk_gb", "rx_mbit", "tx_mbit"])
    for s in api.servers():
        for p in api.metrics(s["id"], "24h")["points"]:
            w.writerow([s["name"], p["time"], p["cpu"], p["memory"], p["disk"], p["rx"], p["tx"]])

Python: продлить нельзя, но напомнить себе — можно

import time
api = Dobry()
soon = [s for s in api.servers() if 0 < s["paid_until"] - time.time() < 3 * 86400 and not s["auto_renew"]]
for s in soon:
    print(f"⚠️ {s['name']} истекает {time.strftime('%d.%m', time.localtime(s['paid_until']))} — продлите в кабинете")

Node.js: перезагрузка, если сервер не отвечает

const API = "https://panel.dobry.host/api";
const H = { Authorization: "Bearer " + process.env.DOBRY_TOKEN, "Content-Type": "application/json" };
const api = (path, init = {}) => fetch(API + path, { ...init, headers: H }).then((r) => r.json());

const { servers } = await api("/servers/sparklines");
for (const [id, s] of Object.entries(servers)) {
  if (s.status !== "down") continue;               // агент молчит > 4 минут
  const key = `watchdog-${id}-${Math.floor(Date.now() / 3600000)}`;  // не чаще раза в час
  const r = await api(`/servers/${id}/actions`, { method: "POST", body: JSON.stringify({ action: "reboot", idempotency_key: key }) });
  console.log(id, r.ok ? r.operation.status : r.error.message);
}

Grafana / Prometheus

Простейший экспортёр — cron раз в минуту пишет sparklines в textfile-коллектор node_exporter:

curl -sf https://panel.dobry.host/api/servers/sparklines -H "Authorization: Bearer $DOBRY_TOKEN" \
 | jq -r '.servers | to_entries[] | "dobry_cpu{server=\"\(.key)\"} \(.value.cpu[-1] // 0)\ndobry_up{server=\"\(.key)\"} \(if .value.status=="up" then 1 else 0 end)"' \
 > /var/lib/node_exporter/textfile/dobry.prom.$$ && mv /var/lib/node_exporter/textfile/dobry.prom.$$ /var/lib/node_exporter/textfile/dobry.prom

Что учесть

  • После reboot/shutdown живой статус в карточке меняется через 10–30 с — не опрашивайте чаще.
  • needs_review — не ошибка и не успех: проверьте live.status через минуту.
  • Токен с правом power держите отдельно от токена мониторинга (read) и ограничьте по IP.
  • Если скрипт работает с сервера, который выдан вам другом, права ограничены тем, что разрешил владелец (shared.perms).

Смотрите также