feat(host-agent): add Console task submission with Host self-submission client
Adds a CSRF-protected task submission form to the local Console Tasks page
This commit is contained in:
@@ -38,6 +38,21 @@ class StaleLeaseError(HostAgentAPIError):
|
||||
pass
|
||||
|
||||
|
||||
class HostTaskSubmissionUnknownError(RuntimeError):
|
||||
"""Raised when a Host self-submission request's Cloud outcome is uncertain.
|
||||
|
||||
This is distinct from :class:`HostAgentAPIError` because the request may
|
||||
have reached the control plane but the response was lost, the server
|
||||
returned a 5xx, or the success payload was malformed. Retrying would
|
||||
duplicate the create, so the caller must treat the task as unknown and
|
||||
surface that to the operator.
|
||||
"""
|
||||
|
||||
def __init__(self, reason: str) -> None:
|
||||
super().__init__(f"host task submission outcome is unknown: {reason}")
|
||||
self.reason = reason
|
||||
|
||||
|
||||
class HostAgentEnrollmentClient:
|
||||
def __init__(
|
||||
self,
|
||||
@@ -172,16 +187,37 @@ class HostAgentClient:
|
||||
goal: str,
|
||||
device_id: str | None = None,
|
||||
) -> HostTaskSubmissionResponse:
|
||||
response = await self._request(
|
||||
"POST",
|
||||
f"/internal/v1/hosts/{self.config.host_id}/tasks",
|
||||
json={
|
||||
"host_id": self.config.host_id,
|
||||
"goal": goal,
|
||||
"device_id": device_id,
|
||||
},
|
||||
)
|
||||
return HostTaskSubmissionResponse.model_validate(response.json())
|
||||
try:
|
||||
response = await self._client.request(
|
||||
"POST",
|
||||
f"/internal/v1/hosts/{self.config.host_id}/tasks",
|
||||
json={
|
||||
"host_id": self.config.host_id,
|
||||
"goal": goal,
|
||||
"device_id": device_id,
|
||||
},
|
||||
headers={"Authorization": f"Bearer {self.config.token}"},
|
||||
)
|
||||
except httpx.TransportError as exc:
|
||||
raise HostTaskSubmissionUnknownError(str(exc)) from exc
|
||||
if response.status_code >= 500:
|
||||
raise HostTaskSubmissionUnknownError(
|
||||
f"control plane returned status {response.status_code}"
|
||||
)
|
||||
if not response.is_success:
|
||||
_raise_api_error(response, stale_lease=False)
|
||||
try:
|
||||
payload = response.json()
|
||||
except ValueError as exc:
|
||||
raise HostTaskSubmissionUnknownError(
|
||||
"control plane returned malformed success payload"
|
||||
) from exc
|
||||
try:
|
||||
return HostTaskSubmissionResponse.model_validate(payload)
|
||||
except Exception as exc:
|
||||
raise HostTaskSubmissionUnknownError(
|
||||
"control plane returned malformed success payload"
|
||||
) from exc
|
||||
|
||||
async def claim(self) -> AssignmentModel | None:
|
||||
response = await self._request(
|
||||
|
||||
Reference in New Issue
Block a user