ctfy.sdk.resources.nodes
client.nodes — the worker-node roster, for an admin bearer.
⚠️ Not public, and this file called it public for as long as the route
had no gate. GET /nodes answers the internal fleet — each node's own
address, its live load, its labels and its telemetry — so it is
require_admin on the platform. The name stays here rather than moving
under client.admin.nodes because moving it would break every caller to
restate a fact the server already enforces.
Operator node management (register / remove / patch / invites / health) lives
on ctfy.sdk.AdminClient under client.admin.nodes.
1"""``client.nodes`` — the worker-node roster, for an admin bearer. 2 3⚠️ **Not public, and this file called it public for as long as the route 4had no gate.** ``GET /nodes`` answers the internal fleet — each node's own 5address, its live load, its labels and its telemetry — so it is 6``require_admin`` on the platform. The name stays here rather than moving 7under ``client.admin.nodes`` because moving it would break every caller to 8restate a fact the server already enforces. 9 10Operator node management (register / remove / patch / invites / health) lives 11on :class:`ctfy.sdk.AdminClient` under ``client.admin.nodes``. 12""" 13 14from __future__ import annotations 15 16from collections.abc import Sequence 17 18from ctfy.sdk._helpers import PagedList, _extract_items, _raise_for_status 19from ctfy.sdk.base import BaseHttpClient 20from ctfy.server.models import ImageConsistencyRow, NodeInfo 21 22 23class NodesResource: 24 """Read of the worker-node roster. Needs an admin bearer.""" 25 26 def __init__(self, http: BaseHttpClient) -> None: 27 self._http = http 28 29 def list(self, offset: int = 0, limit: int = 50) -> PagedList[NodeInfo]: 30 resp = self._http.request("GET", "/nodes", params={"offset": offset, "limit": limit}) 31 _raise_for_status(resp) 32 return _extract_items(resp.json(), NodeInfo) 33 34 def image_consistency(self) -> Sequence[ImageConsistencyRow]: 35 """Tags more than one node holds and disagrees on the content of (#1716.4). 36 37 Empty means the fleet agrees; a row names the tag and which node 38 holds which digest. Needs an admin bearer, like :meth:`list`. 39 """ 40 resp = self._http.request("GET", "/nodes/image-consistency") 41 _raise_for_status(resp) 42 return [ImageConsistencyRow.model_validate(row) for row in resp.json()]
24class NodesResource: 25 """Read of the worker-node roster. Needs an admin bearer.""" 26 27 def __init__(self, http: BaseHttpClient) -> None: 28 self._http = http 29 30 def list(self, offset: int = 0, limit: int = 50) -> PagedList[NodeInfo]: 31 resp = self._http.request("GET", "/nodes", params={"offset": offset, "limit": limit}) 32 _raise_for_status(resp) 33 return _extract_items(resp.json(), NodeInfo) 34 35 def image_consistency(self) -> Sequence[ImageConsistencyRow]: 36 """Tags more than one node holds and disagrees on the content of (#1716.4). 37 38 Empty means the fleet agrees; a row names the tag and which node 39 holds which digest. Needs an admin bearer, like :meth:`list`. 40 """ 41 resp = self._http.request("GET", "/nodes/image-consistency") 42 _raise_for_status(resp) 43 return [ImageConsistencyRow.model_validate(row) for row in resp.json()]
Read of the worker-node roster. Needs an admin bearer.
35 def image_consistency(self) -> Sequence[ImageConsistencyRow]: 36 """Tags more than one node holds and disagrees on the content of (#1716.4). 37 38 Empty means the fleet agrees; a row names the tag and which node 39 holds which digest. Needs an admin bearer, like :meth:`list`. 40 """ 41 resp = self._http.request("GET", "/nodes/image-consistency") 42 _raise_for_status(resp) 43 return [ImageConsistencyRow.model_validate(row) for row in resp.json()]
Tags more than one node holds and disagrees on the content of (#1716.4).
Empty means the fleet agrees; a row names the tag and which node
holds which digest. Needs an admin bearer, like list().