Unit contract v1: JSON Schemas
These are the schemas of contract v1, draft 2020-12, copied verbatim from the files the agent embeds and validates against. Each is also served as a file under /contract/units/v1/. The $id URLs are the canonical identifiers.
POST /accepting request body
A JSON boolean (the literal true or false). An empty body means true. The signals ready, idle, busy and shutdown take no body. The same text is the content of the file signals/accepting.
Raw file: accepting-request.schema.json
Code{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://zaroz.cloud/contract/units/v1/accepting-request.schema.json", "title": "POST /accepting request body", "description": "A JSON boolean (the literal true or false). An empty body means true. The signals ready, idle, busy and shutdown take no body. The same text is the content of the file signals/accepting.", "type": "boolean" }
/zaroz/allocation.json
null while the unit is not allocated. When allocated, user-data.json already holds the allocation's user_data.
Raw file: allocation.schema.json
Code{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://zaroz.cloud/contract/units/v1/allocation.schema.json", "title": "/zaroz/allocation.json", "description": "null while the unit is not allocated. When allocated, user-data.json already holds the allocation's user_data.", "oneOf": [ { "type": "null" }, { "type": "object", "required": [ "id", "allocated_at", "generation" ], "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 128 }, "allocated_at": { "type": "string", "format": "date-time" }, "generation": { "type": "integer" } } } ] }
/zaroz/contract.json
Which contract the files in this directory follow. Read it first.
Raw file: contract.schema.json
Code{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://zaroz.cloud/contract/units/v1/contract.schema.json", "title": "/zaroz/contract.json", "description": "Which contract the files in this directory follow. Read it first.", "type": "object", "required": [ "version", "agent_version" ], "properties": { "version": { "const": 1, "description": "Contract major version. Within a major, changes are additive only." }, "agent_version": { "type": "string", "minLength": 1 } } }
Error response of the signal socket
Code{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://zaroz.cloud/contract/units/v1/error.schema.json", "title": "Error response of the signal socket", "type": "object", "required": [ "error" ], "properties": { "error": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "string", "description": "Stable machine-readable code, for example unknown_signal, invalid_body, invalid_wait, not_ready, body_too_large." }, "message": { "type": "string" } } } } }
Unit event envelope
One event of the units event log, as returned by the events route and delivered to webhooks. Consumers must ignore unknown fields and unknown event types.
Code{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://zaroz.cloud/contract/units/v1/event.schema.json", "title": "Unit event envelope", "description": "One event of the units event log, as returned by the events route and delivered to webhooks. Consumers must ignore unknown fields and unknown event types.", "type": "object", "required": [ "seq", "id", "type", "contract_version", "occurred_at", "service_instance_id", "unit", "data" ], "properties": { "seq": { "type": "integer", "minimum": 0, "description": "Gapless and strictly increasing per Workload, from 1. Only the delivery-only webhook.ping may carry 0 (the cursor of a webhook that has delivered nothing yet)." }, "id": { "type": "string", "pattern": "^evt_[0-9a-fA-F-]{32,36}$" }, "type": { "type": "string", "minLength": 1 }, "contract_version": { "const": 1 }, "occurred_at": { "type": "string", "format": "date-time" }, "service_instance_id": { "type": "string", "minLength": 1 }, "unit": { "oneOf": [ { "type": "null" }, { "type": "object", "required": [ "id", "key", "labels" ], "properties": { "id": { "type": "string", "minLength": 1 }, "key": { "type": "string", "minLength": 1, "maxLength": 40 }, "labels": { "type": "object", "additionalProperties": { "type": "string" } } } } ] }, "data": { "type": "object" } }, "allOf": [ { "if": { "properties": { "type": { "const": "webhook.ping" } }, "required": [ "type" ] }, "else": { "properties": { "seq": { "minimum": 1 } } } }, { "if": { "properties": { "type": { "const": "unit.exited" } }, "required": [ "type" ] }, "then": { "properties": { "data": { "type": "object", "required": [ "code", "restarted" ], "properties": { "code": { "type": "integer" }, "restarted": { "type": "boolean" } } } } } }, { "if": { "properties": { "type": { "enum": [ "unit.failed", "unit.destroyed" ] } }, "required": [ "type" ] }, "then": { "properties": { "data": { "type": "object", "required": [ "reason" ], "properties": { "reason": { "type": "string" } } } } } }, { "if": { "properties": { "type": { "const": "units.scaled" } }, "required": [ "type" ] }, "then": { "properties": { "unit": { "type": "null" }, "data": { "type": "object", "required": [ "from", "to", "reason" ], "properties": { "from": { "type": "integer", "minimum": 0 }, "to": { "type": "integer", "minimum": 0 }, "reason": { "type": "string" } } } } } }, { "if": { "properties": { "type": { "enum": [ "unit.ready", "unit.allocated" ] } }, "required": [ "type" ] }, "then": { "properties": { "unit": { "type": "object" }, "data": { "type": "object", "required": [ "private_name" ], "properties": { "private_name": { "type": "string" }, "public_endpoints": { "type": "array" } } } } } }, { "if": { "properties": { "type": { "enum": [ "unit.created", "unit.starting", "unit.accepting", "unit.not_accepting", "unit.allocation_delivered", "unit.allocation_undelivered", "unit.idle", "unit.busy", "unit.draining", "unit.stopped" ] } }, "required": [ "type" ] }, "then": { "properties": { "unit": { "type": "object" } } } } ] }
Response of POST /<signal>
Raw file: signal-response.schema.json
Code{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://zaroz.cloud/contract/units/v1/signal-response.schema.json", "title": "Response of POST /<signal>", "type": "object", "required": [ "ok", "signal", "changed" ], "properties": { "ok": { "const": true }, "signal": { "enum": [ "ready", "accepting", "idle", "busy", "shutdown" ] }, "changed": { "type": "boolean", "description": "false when the signal repeated the current state and was coalesced." } } }
/zaroz/state.json
Whether the unit is being drained. A draining unit has already left the load-balanced set; finish up and exit before the pod's termination grace ends.
Code{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://zaroz.cloud/contract/units/v1/state.schema.json", "title": "/zaroz/state.json", "description": "Whether the unit is being drained. A draining unit has already left the load-balanced set; finish up and exit before the pod's termination grace ends.", "oneOf": [ { "type": "object", "required": [ "draining" ], "properties": { "draining": { "const": false } } }, { "type": "object", "required": [ "draining", "reason" ], "properties": { "draining": { "const": true }, "reason": { "enum": [ "stop", "destroy", "replace", "scale_down" ] } } } ] }
UnitSignal (units.zaroz.cloud/v1) spec
Written by the kernel, read by the agent. The agent ignores unknown fields and refuses a spec that fails validation, keeping the previous contract.
Raw file: unit-signal-spec.schema.json
Code{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://zaroz.cloud/contract/units/v1/unit-signal-spec.schema.json", "title": "UnitSignal (units.zaroz.cloud/v1) spec", "description": "Written by the kernel, read by the agent. The agent ignores unknown fields and refuses a spec that fails validation, keeping the previous contract.", "type": "object", "required": [ "unitId", "key", "contractVersion", "generation" ], "properties": { "unitId": { "type": "string", "minLength": 1, "maxLength": 128 }, "key": { "type": "string", "minLength": 1, "maxLength": 40, "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$" }, "labels": { "type": "object", "maxProperties": 16, "propertyNames": { "minLength": 1, "maxLength": 32, "pattern": "^[a-z0-9]([a-z0-9_.-]*[a-z0-9])?$" }, "additionalProperties": { "type": "string", "maxLength": 64 } }, "userData": { "description": "Any JSON value, null for none." }, "allocation": { "oneOf": [ { "type": "null" }, { "type": "object", "required": [ "id", "generation" ], "properties": { "id": { "type": "string", "minLength": 1, "maxLength": 128 }, "generation": { "type": "integer" }, "allocatedAt": { "type": "string", "format": "date-time", "description": "Optional; the agent stamps the time it first saw the allocation when absent." } } } ] }, "draining": { "oneOf": [ { "const": false }, { "enum": [ "stop", "destroy", "replace", "scale_down" ] } ], "description": "false, or the reason." }, "contractVersion": { "const": 1 }, "generation": { "type": "integer", "minimum": 0, "description": "Bump on every change; the agent acknowledges it in status.observedGeneration after the files are written." }, "publicEndpoints": { "type": "array", "description": "Optional override of the pod's ZAROZ_PUBLIC_ENDPOINTS, for an address assigned after pod creation.", "items": { "type": "object", "required": [ "protocols", "internal_port", "address" ], "properties": { "protocols": { "type": "array", "items": { "type": "string" } }, "internal_port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "address": { "type": "string" } } } } } }
UnitSignal (units.zaroz.cloud/v1) status
Written by the agent through the status subresource only, coalesced to at most 5 patches per second. Every field is always present (null, not absent) because the agent patches with a JSON merge patch.
Raw file: unit-signal-status.schema.json
Code{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://zaroz.cloud/contract/units/v1/unit-signal-status.schema.json", "title": "UnitSignal (units.zaroz.cloud/v1) status", "description": "Written by the agent through the status subresource only, coalesced to at most 5 patches per second. Every field is always present (null, not absent) because the agent patches with a JSON merge patch.", "type": "object", "required": [ "observedGeneration", "agentVersion", "signalledReady", "accepting", "activity", "activitySince", "shutdownRequestedAt", "allocationAck", "seq" ], "properties": { "observedGeneration": { "type": "integer" }, "agentVersion": { "type": "string" }, "signalledReady": { "oneOf": [ { "type": "null" }, { "type": "string", "format": "date-time" } ] }, "accepting": { "type": "boolean" }, "activity": { "oneOf": [ { "type": "null" }, { "enum": [ "idle", "busy" ] } ] }, "activitySince": { "oneOf": [ { "type": "null" }, { "type": "string", "format": "date-time" } ] }, "shutdownRequestedAt": { "oneOf": [ { "type": "null" }, { "type": "string", "format": "date-time" } ] }, "allocationAck": { "oneOf": [ { "type": "null" }, { "type": "string" } ], "description": "Id of the allocation whose files are written, null when none." }, "seq": { "type": "integer", "minimum": 0, "description": "Monotonic per agent start." } } }
/zaroz/unit.json
Who this unit is. Labels update live; every other field is fixed for the life of the pod. Ignore fields you do not know.
Code{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://zaroz.cloud/contract/units/v1/unit.schema.json", "title": "/zaroz/unit.json", "description": "Who this unit is. Labels update live; every other field is fixed for the life of the pod. Ignore fields you do not know.", "type": "object", "required": [ "contract_version", "unit_id", "key", "labels", "origin", "workload", "project_id", "region", "private_name", "public_endpoints", "incarnation", "started_at" ], "properties": { "contract_version": { "const": 1 }, "unit_id": { "type": "string", "minLength": 1, "maxLength": 128 }, "key": { "type": "string", "minLength": 1, "maxLength": 40, "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$" }, "labels": { "type": "object", "maxProperties": 16, "propertyNames": { "minLength": 1, "maxLength": 32, "pattern": "^[a-z0-9]([a-z0-9_.-]*[a-z0-9])?$" }, "additionalProperties": { "type": "string", "maxLength": 64 } }, "origin": { "type": "string", "minLength": 1, "description": "How the unit came to exist (for example policy, code, warm)." }, "workload": { "type": "object", "required": [ "id", "slug" ], "properties": { "id": { "type": "string", "minLength": 1 }, "slug": { "type": "string", "minLength": 1 } } }, "project_id": { "type": "string", "minLength": 1 }, "region": { "type": "string", "minLength": 1 }, "private_name": { "type": "string", "minLength": 1, "description": "<key>.<workload>, resolvable from the project's other units." }, "public_endpoints": { "type": "array", "items": { "type": "object", "required": [ "protocols", "internal_port", "address" ], "properties": { "protocols": { "type": "array", "items": { "type": "string" } }, "internal_port": { "type": "integer", "minimum": 1, "maximum": 65535 }, "address": { "type": "string" } } } }, "incarnation": { "type": "integer", "minimum": 0 }, "started_at": { "type": "string", "format": "date-time" } } }
/zaroz/user-data.json
The customer's JSON value for this unit, or null. At most 64 KiB serialized compactly and nested at most 32 deep (enforced before it is delivered); any JSON value otherwise.
Raw file: user-data.schema.json
Code{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://zaroz.cloud/contract/units/v1/user-data.schema.json", "title": "/zaroz/user-data.json", "description": "The customer's JSON value for this unit, or null. At most 64 KiB serialized compactly and nested at most 32 deep (enforced before it is delivered); any JSON value otherwise." }
