Rename Installation to Instance
Follows the portal: the noun is "instance" everywhere the app says it — UI strings, CLI output, error details, docs and comments. The wire keys (`instance_id`, `instance_token`) and the hub route this calls move with it. An existing cloud.json is adopted rather than refused: without the key alias the dataclass fails to parse, which the caller swallows and reads as "never enrolled" instead of "reconnect". `instance_key` on a node type becomes `target_key`. It means the outside thing a node points at, which is a different sense of the word, and keeping both would put two meanings of "instance" in one codebase. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015YrQnKV3bnQd4K342y8tKj
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
"""The link this installation opens to its portal.
|
||||
"""The link this instance opens to its portal.
|
||||
|
||||
Same shape as the remote-worker agent, with the direction of the favour
|
||||
reversed: there, a GPU box dials the engine so the engine can give it work;
|
||||
@@ -50,7 +50,7 @@ MAX_WS_MESSAGE = 1024 * 1024
|
||||
#: Only the versioned API is served over the tunnel. The MCP mount and the
|
||||
#: OAuth endpoints live outside it and stay local-only.
|
||||
ALLOWED_PREFIX = "/api/v1/"
|
||||
#: Proxied calls, and bridged streams, this installation will run at once.
|
||||
#: Proxied calls, and bridged streams, this instance will run at once.
|
||||
#: Neither dict was bounded, and an id the hub reused silently dropped the
|
||||
#: reference to a task that was still running.
|
||||
MAX_IN_FLIGHT = 256
|
||||
@@ -76,7 +76,7 @@ async def watch_enrolment(app: FastAPI) -> None:
|
||||
"""Notice an enrolment that happened outside this process.
|
||||
|
||||
``fluksio enroll`` writes the config against the database directly, with no
|
||||
idea whether an engine is running — so without this, pairing an installation
|
||||
idea whether an engine is running — so without this, pairing an instance
|
||||
that is already serving would take a restart to come into effect. Enrolling
|
||||
through the API starts the link itself and this sees a task already there.
|
||||
"""
|
||||
@@ -124,7 +124,7 @@ class CloudConnector:
|
||||
# this process does: enrolment may have named a container.
|
||||
"issuer": config.issuer if config else None,
|
||||
"portal_account": config.portal_account if config else None,
|
||||
"installation_id": config.installation_id if config else None,
|
||||
"instance_id": config.instance_id if config else None,
|
||||
"last_error": self._last_error,
|
||||
"connected_since": self._connected_since,
|
||||
}
|
||||
@@ -165,7 +165,7 @@ class CloudConnector:
|
||||
|
||||
delay = BASE_BACKOFF_S if attached else min(MAX_BACKOFF_S, delay * 2)
|
||||
# Jittered, so a portal coming back up is not met by every
|
||||
# installation it serves in the same instant.
|
||||
# instance it serves in the same instant.
|
||||
wait = delay * (0.75 + random.random() * 0.5)
|
||||
logger.info("Reconnecting to the portal in %.0fs", wait)
|
||||
await asyncio.sleep(wait)
|
||||
@@ -197,9 +197,7 @@ class CloudConnector:
|
||||
self._connected = True
|
||||
self._connected_since = time.time()
|
||||
self._last_error = None
|
||||
logger.info(
|
||||
"Attached to the portal as installation %s", config.installation_id
|
||||
)
|
||||
logger.info("Attached to the portal as instance %s", config.instance_id)
|
||||
|
||||
keepalive = asyncio.create_task(self._keepalive(socket, config))
|
||||
try:
|
||||
@@ -270,7 +268,7 @@ class CloudConnector:
|
||||
|
||||
@staticmethod
|
||||
def _local_account(session: Any, config: cloud_config.CloudConfig) -> Any:
|
||||
"""The account this installation acts as, or the one that now stands for it.
|
||||
"""The account this instance acts as, or the one that now stands for it.
|
||||
|
||||
``local_user_id`` names whoever redeemed the claim code. A database
|
||||
restored from a backup, or rebuilt under an enrolment that outlived it,
|
||||
@@ -301,7 +299,7 @@ class CloudConnector:
|
||||
)
|
||||
if len(superusers) != 1:
|
||||
logger.warning(
|
||||
"The account this installation enrolled as is gone, and there "
|
||||
"The account this instance enrolled as is gone, and there "
|
||||
"%s to adopt unambiguously — enrol again from Settings.",
|
||||
"is no superuser" if not superusers else "are several superusers",
|
||||
)
|
||||
@@ -309,7 +307,7 @@ class CloudConnector:
|
||||
adopted = superusers[0]
|
||||
cloud_config.save(replace(config, local_user_id=str(adopted.id)))
|
||||
logger.warning(
|
||||
"The account this installation enrolled as is gone; acting as %s instead",
|
||||
"The account this instance enrolled as is gone; acting as %s instead",
|
||||
adopted.email,
|
||||
)
|
||||
return adopted
|
||||
@@ -334,14 +332,14 @@ class CloudConnector:
|
||||
async def _health_summary(
|
||||
self, config: cloud_config.CloudConfig
|
||||
) -> dict[str, Any] | None:
|
||||
"""This installation's own health, as the dashboard reads it.
|
||||
"""This instance's own health, as the dashboard reads it.
|
||||
|
||||
Fetched through the same in-process transport as everything else, with
|
||||
a short-lived local token: the observability API is authenticated, and
|
||||
this process is entitled to mint one for the enrolling user.
|
||||
|
||||
``failures_24h`` is added here rather than by ``/summary``: it is the
|
||||
portal's tile and nothing on this installation reads it, and summing
|
||||
portal's tile and nothing on this instance reads it, and summing
|
||||
the same rollups over the same window the app's own Home tile sums
|
||||
keeps the two from drifting apart the way they already did once.
|
||||
"""
|
||||
@@ -376,7 +374,7 @@ class CloudConnector:
|
||||
def _client(self) -> httpx.AsyncClient:
|
||||
return httpx.AsyncClient(
|
||||
transport=httpx.ASGITransport(app=self._app),
|
||||
base_url="http://installation.local",
|
||||
base_url="http://instance.local",
|
||||
timeout=httpx.Timeout(300.0, connect=5.0),
|
||||
)
|
||||
|
||||
@@ -404,7 +402,7 @@ class CloudConnector:
|
||||
try:
|
||||
if not path.startswith(ALLOWED_PREFIX):
|
||||
# Defence in depth: the hub only ever forwards API paths, and
|
||||
# an installation that trusted anything else would be an SSRF
|
||||
# an instance that trusted anything else would be an SSRF
|
||||
# gadget aimed at its own process.
|
||||
await socket.send(
|
||||
_dump({"op": "err", "id": call_id, "message": "path not allowed"})
|
||||
|
||||
Reference in New Issue
Block a user