From 504b892c08aa0c86f36a09f875a961a218ca710b Mon Sep 17 00:00:00 2001 From: Armand Craig Date: Fri, 11 Sep 2026 12:38:30 -0400 Subject: [PATCH 1/3] Initial commit of changes - to be refined. Signed-off-by: Armand Craig --- .../desired-state.linkml.yaml | 10 ++-- .../examples/valid/DesiredState-001.yaml | 2 +- .../examples/valid/DesiredState-002.yaml | 2 +- .../examples/valid/gateway-autonomous.yaml | 2 +- .../examples/valid/gateway-directed.yaml | 2 +- .../resources/index.md.jinja2 | 8 +-- .../api-requirements-and-security.md | 17 +++++- .../deployment-status.md | 60 ++++++++++++++++--- .../device-capabilities.md | 26 ++++---- .../workload-management-api-1.0.0-rc.2.yaml | 54 ++++++++--------- system-design/specification/problem-types.md | 14 ++--- 11 files changed, 127 insertions(+), 70 deletions(-) diff --git a/src/specification/margo-management-interface/desired-state.linkml.yaml b/src/specification/margo-management-interface/desired-state.linkml.yaml index dba9dee2..3b898cb2 100644 --- a/src/specification/margo-management-interface/desired-state.linkml.yaml +++ b/src/specification/margo-management-interface/desired-state.linkml.yaml @@ -59,12 +59,12 @@ classes: required: true range: string rank: 20 - deviceId: + targetName: description: >- - The id of the device, with hierarchy if applicable, to which the deployment is assigned. - To reference a child-device the format is `{device-id}[/{device-id}[/...]]`.
- To request the gateway to choose the child-device, use `*` for the last segment in the hierarchy (i.e. `{device-id}[/{device-id}/...]/*`). - If the gateway is not capable of autonomously selecting a child-device, it MUST send back a deployment status with error `103 - Autonomous placement not supported` when `*` is used. + The name of the target, with hierarchy if applicable, to which the deployment is assigned. + To reference a child device behind a see-thru gateway the format is `{target-name}[/{target-name}[/...]]`.
+ To request the gateway to choose the child device, use `*` for the last segment in the hierarchy (i.e. `{target-name}[/{target-name}/...]/*`). + If the gateway is not capable of autonomously selecting a child device, it MUST send back a deployment status with error `103 - Autonomous placement not supported` when `*` is used. required: true pattern: '^[A-Za-z0-9._~-]+(\/[A-Za-z0-9._~-]+)*(\/\*)?$' rank: 30 diff --git a/src/specification/margo-management-interface/resources/examples/valid/DesiredState-001.yaml b/src/specification/margo-management-interface/resources/examples/valid/DesiredState-001.yaml index b3eaa0d7..9db0bfcc 100644 --- a/src/specification/margo-management-interface/resources/examples/valid/DesiredState-001.yaml +++ b/src/specification/margo-management-interface/resources/examples/valid/DesiredState-001.yaml @@ -2,7 +2,7 @@ id: a3e2f5dc-912e-494f-8395-52cf3769bc06 metadata: name: com-northstartida-digitron-orchestrator-deployment namespace: margo-poc - deviceId: edge-01 + targetName: edge-01 spec: applicationId: com-northstartida-digitron-orchestrator deploymentProfile: diff --git a/src/specification/margo-management-interface/resources/examples/valid/DesiredState-002.yaml b/src/specification/margo-management-interface/resources/examples/valid/DesiredState-002.yaml index 0c3ee23d..04e701a1 100644 --- a/src/specification/margo-management-interface/resources/examples/valid/DesiredState-002.yaml +++ b/src/specification/margo-management-interface/resources/examples/valid/DesiredState-002.yaml @@ -2,7 +2,7 @@ id: ad9b614e-8912-45f4-a523-372358765def metadata: name: com-northstartida-digitron-orchestrator-deployment namespace: margo-poc - deviceId: edge-01 + targetName: edge-01 spec: applicationId: com-northstartida-digitron-orchestrator deploymentProfile: diff --git a/src/specification/margo-management-interface/resources/examples/valid/gateway-autonomous.yaml b/src/specification/margo-management-interface/resources/examples/valid/gateway-autonomous.yaml index 167d9e4a..1a68d52f 100644 --- a/src/specification/margo-management-interface/resources/examples/valid/gateway-autonomous.yaml +++ b/src/specification/margo-management-interface/resources/examples/valid/gateway-autonomous.yaml @@ -2,7 +2,7 @@ id: ad9b614e-8912-45f4-a523-372358765def metadata: name: com-northstartida-digitron-orchestrator-deployment namespace: margo-poc - deviceId: gateway-01/* + targetName: gateway-01/* spec: applicationId: com-northstartida-digitron-orchestrator deploymentProfile: diff --git a/src/specification/margo-management-interface/resources/examples/valid/gateway-directed.yaml b/src/specification/margo-management-interface/resources/examples/valid/gateway-directed.yaml index 7df45132..54bf8f36 100644 --- a/src/specification/margo-management-interface/resources/examples/valid/gateway-directed.yaml +++ b/src/specification/margo-management-interface/resources/examples/valid/gateway-directed.yaml @@ -2,7 +2,7 @@ id: ad9b614e-8912-45f4-a523-372358765def metadata: name: com-northstartida-digitron-orchestrator-deployment namespace: margo-poc - deviceId: gateway-01/edge-01 + targetName: gateway-01/edge-01 spec: applicationId: com-northstartida-digitron-orchestrator deploymentProfile: diff --git a/src/specification/margo-management-interface/resources/index.md.jinja2 b/src/specification/margo-management-interface/resources/index.md.jinja2 index c9c6a74c..b1ab41af 100644 --- a/src/specification/margo-management-interface/resources/index.md.jinja2 +++ b/src/specification/margo-management-interface/resources/index.md.jinja2 @@ -5,7 +5,7 @@ In order for the Workload Fleet Manager (WFM) to manage workloads on an Edge Com The Desired State defines *what* workloads (applications) should run on the device and *how* they should be configured. It is distributed using a lightweight, pull-based HTTP API that allows devices to stay synchronized with the WFM. -At the center of this process is the State Manifest, a JSON document that lists all workloads assigned to the authenticated client. The manifest is scoped to the client, not to a single device: a client that fronts several devices, such as a see-thru gateway with child devices, retrieves one manifest covering all of them. Each workload is represented by an [`ApplicationDeployment`](#applicationdeployment-yaml-definition) YAML - a self-contained object defining configuration, components, and parameters for that workload - and names its target device in its `metadata.deviceId` attribute. +At the center of this process is the State Manifest, a JSON document that lists all workloads assigned to the authenticated client. The manifest is scoped to the client, not to a single device: a client that fronts several devices, such as a see-thru gateway with child devices, retrieves one manifest covering all of them. Each workload is represented by an [`ApplicationDeployment`](#applicationdeployment-yaml-definition) YAML - a self-contained object defining configuration, components, and parameters for that workload - and names its deployment target in its `metadata.targetName` attribute. The manifest includes two complementary ways for the client to obtain the same `ApplicationDeployment` YAMLs: @@ -269,7 +269,7 @@ id: metadata: name: namespace: - deviceId: + targetName: spec: applicationId: deploymentProfile: @@ -406,7 +406,7 @@ These enumerations are used as vocabularies for attribute values of the `Applica ### Example: Gateway Directed Deployment Specification -In this example, an application is deployed to a specific child device through a see-thru gateway. The gateway determines the target device for deployment from the value of the `deviceId` attribute of the `ApplicationDeployment` specification. +In this example, an application is deployed to a specific child device through a see-thru gateway. The gateway determines the target device for deployment from the value of the `targetName` attribute of the `ApplicationDeployment` specification. ```yaml {% include 'examples/valid/gateway-directed.yaml' %} @@ -414,7 +414,7 @@ In this example, an application is deployed to a specific child device through a ### Example: Gateway Autonomous Deployment Specification -In this example, an application is deployed to a child device with the see-thru gateway deciding which device to use. The gateway is told to choose the device by using `*` in the `deviceId` attribute of the `ApplicationDeployment` specification. +In this example, an application is deployed to a child device with the see-thru gateway deciding which device to use. The gateway is told to choose the device by using `*` in the `targetName` attribute of the `ApplicationDeployment` specification. ```yaml {% include 'examples/valid/gateway-autonomous.yaml' %} diff --git a/system-design/specification/margo-management-interface/api-requirements-and-security.md b/system-design/specification/margo-management-interface/api-requirements-and-security.md index 6b5ca268..308dc451 100644 --- a/system-design/specification/margo-management-interface/api-requirements-and-security.md +++ b/system-design/specification/margo-management-interface/api-requirements-and-security.md @@ -13,6 +13,19 @@ Below is a breakdown of the two major categories these requirements fall under: Identity and authentication for the Management Interface are provided by the [Margo Identity and Authorization Framework](../identity/identity-framework.md) and the [WFM Identity Profile](../identity/wfm-identity-profile.md). A WFM Client and a WFM are each provisioned with an X.509-SVID before any Management Interface call is made. +## Target Names + +`targetName` is the WFM Client-reported name of a deployment target. It identifies the device, gateway, or child device path a WFM uses for capability reporting, desired state assignment, and deployment status correlation. Every Management Interface surface that names a deployment target uses `targetName`. + +A `targetName`: + +* MUST be stable for the lifetime of the target relationship. +* MUST consist only of unreserved characters as specified in [RFC3986](https://www.rfc-editor.org/rfc/rfc3986#section-2.3) in each path segment. +* MAY contain `/` separators to represent a see-thru [gateway](../../concepts/gateways/gateways.md) hierarchy, in the form `{name}[/{name}[/{name}...]]`. +* MAY use `*` as the final path segment only where this specification explicitly allows gateway-selected placement. +* MUST be treated as opaque by the WFM except where this specification defines gateway path interpretation. + +A `targetName` is a name, not a universally unique device identifier. Margo reserves the term `deviceId` for a universally unique device identifier assigned by a Device Fleet Manager or another authoritative inventory system, and does not use it on the Management Interface targeting surface. ## API Definition The REST API is defined via the OpenAPI Specification: @@ -30,9 +43,9 @@ Authentication is mutual TLS per the MIAF [TLS requirements](../identity/tls-req The caller identity for every request is the authenticated WFM Client SPIFFE ID; the request itself does not carry it. A WFM derives the caller from the SPIFFE ID, not from any identifier in the request path or body. -Every Management Interface endpoint is scoped to the authenticated caller. A WFM determines from the caller's identity which devices that client is responsible for and which deployments are assigned to them. Where a request path carries a resource identifier, for example `{deviceId}` or `{digest}`, the WFM looks that identifier up only among the resources in the caller's scope. A WFM MUST NOT expose or mutate a resource outside the caller's scope. +Every Management Interface endpoint is scoped to the authenticated caller. A WFM determines from the caller's identity which deployment targets that client is responsible for and which deployments are assigned to them. Where a request path carries a resource identifier, for example `{targetName}` or `{digest}`, the WFM looks that identifier up only among the resources in the caller's scope. A WFM MUST NOT expose or mutate a resource outside the caller's scope. -A `deviceId` is not a global name: it identifies a device only within the scope of one WFM Client. The binding between a `deviceId` and the caller's identity is established by the client itself, when it first reports capabilities for that device (see [Device Capabilities](../margo-management-interface/device-capabilities.md)), and every later reference to that `deviceId` is resolved within the reporting client's scope. Because the scope is derived from the authenticated SPIFFE ID, a client cannot register, read, or mutate a device in another client's scope: two clients reporting the same `deviceId` string address two unrelated device records. A WFM MAY additionally constrain, by local policy, which `deviceId`s a given client is allowed to report; such policy is deployment-specific and out of scope for this specification. +A `targetName` is not a global name: it identifies a deployment target only within the scope of one WFM Client. The binding between a `targetName` and the caller's identity is established by the client itself, when it first reports capabilities for that target (see [Device Capabilities](../margo-management-interface/device-capabilities.md)), and every later reference to that `targetName` is resolved within the reporting client's scope. Because the scope is derived from the authenticated SPIFFE ID, a client cannot register, read, or mutate a target in another client's scope: two clients reporting the same `targetName` string address two unrelated target records. A WFM MAY additionally constrain, by local policy, which `targetName`s a given client is allowed to report; such policy is deployment-specific and out of scope for this specification. The WFM authorizes each request using local policy keyed on the authenticated WFM Client identity, and MAY deny a request from a still-valid credential, per [Authorization](../identity/wfm-identity-profile.md#authorization). When a WFM denies a request by local policy (for example, a retired client relationship), it SHOULD respond `403 Forbidden` with an [RFC 9457](https://datatracker.ietf.org/doc/html/rfc9457) Problem Details body (`Content-Type: application/problem+json`) using the `wfm-client-relationship-retired` type: diff --git a/system-design/specification/margo-management-interface/deployment-status.md b/system-design/specification/margo-management-interface/deployment-status.md index 921ee4f4..d39a31b3 100644 --- a/system-design/specification/margo-management-interface/deployment-status.md +++ b/system-design/specification/margo-management-interface/deployment-status.md @@ -32,7 +32,7 @@ POST /api/v1/deployments/{deploymentId}/status | Fields | Type | Required? | Description | |-----------------|-----------------|-----------------|-----------------| | deploymentId | string | Y | The unique identifier UUID of the deployment specification. Needs to be assigned by the Workload Fleet Management Software. | -| deviceId | string | N* | Id of the device hosting the deployment. Includes the full device hierarchy if applicable.
* This attribute is required when reporting on behalf of a child-device. | +| targetName | string | Y | Name of the target hosting the deployment. Includes the full gateway hierarchy if applicable. See [Target Names](./api-requirements-and-security.md#target-names). | | adoptedManifestVersion | number | Y | The [manifestVersion](./desired-state.md#endpoints---state-manifest) of the most recent state manifest the WFM client has adopted for this deployment. See the [Adopted Manifest Version](#adopted-manifest-version) section below.| | status | []status | Y | Element that defines overall deployment status. See the [Status Attributes](#status-attributes) section below.| | components | []components | Y | Element that defines the individual component's deployment status. See the [Component Attributes](#component-attributes) section below.| @@ -59,10 +59,10 @@ POST /api/v1/deployments/{deploymentId}/status | Fields | Type | Required? | Description | |-----------------|-----------------|-----------------|-----------------| | code | string | Y | Associated error code following a component failure during installation. | -| source | string | Y | Identifies the source of the error. It is set to the device id, with its full hierarchy if applicable, of the device generating the error, or to the component name of the component generating the error. | +| source | string | Y | Identifies the source of the error. It is set to the `targetName`, with its full hierarchy if applicable, of the target generating the error, or to the component name of the component generating the error. | | message | string | Y | Associated error message that provides further details to the WFM about the error that was encountered. | -When the error is generated by a see-thru [gateway](../../concepts/gateways/gateways.md), the source attribute of the error structure MUST be set to the gateway device id, with its full hierarchy if applicable. +When the error is generated by a see-thru [gateway](../../concepts/gateways/gateways.md), the source attribute of the error structure MUST be set to the gateway's `targetName`, with its full hierarchy if applicable. When the error is not generated by a see-thru gateway, the source of the `status.error` attribute MUST be set to the name of the deployment as defined in the `metadata.name` attribute of the application deployment manifest. @@ -74,11 +74,11 @@ When the error is not generated by a see-thru gateway, the source of the `compon | Error Code | Message | Source | Description | |------------|-------------|-------------|-------------| -| 101 | Unknown child device ID | Id of the gateway | The gateway cannot identify the child device with the given ID. | -| 102 | Child device unreachable | Id of the gateway | The gateway cannot establish a connection with the child device. | -| 103 | Autonomous placement not supported | Id of the gateway | The gateway is not capable of autonomously selecting the child-device for the deployment. | +| 101 | Unknown child device | `targetName` of the gateway | The gateway cannot identify the child device with the given name. | +| 102 | Child device unreachable | `targetName` of the gateway | The gateway cannot establish a connection with the child device. | +| 103 | Autonomous placement not supported | `targetName` of the gateway | The gateway is not capable of autonomously selecting the child-device for the deployment. | -When the error used is a reserved code for a gateway-generated error, the `source` attribute MUST be set to the id of the gateway, with its full hierarchy if applicable. +When the error used is a reserved code for a gateway-generated error, the `source` attribute MUST be set to the `targetName` of the gateway, with its full hierarchy if applicable. #### Adopted Manifest Version @@ -97,7 +97,7 @@ The attribute is present in every status report. A client learns of a deployment ```json { "deploymentId": "a3e2f5dc-912e-494f-8395-52cf3769bc06", - "deviceId": "plant-alfa-zone1-edge01", + "targetName": "plant-alfa-zone1-edge01", "adoptedManifestVersion": 7, "status": { "state": "pending", @@ -128,4 +128,48 @@ The attribute is present in every status report. A client learns of a deployment } ] } +``` + +## Example See-thru Gateway Deployment Status Manifest Request + +A see-thru gateway reporting status for a workload it hosts itself names its own target: + +```json +{ + "deploymentId": "a3e2f5dc-912e-494f-8395-52cf3769bc06", + "targetName": "gateway1", + "adoptedManifestVersion": 7, + "status": { + "state": "pending" + }, + "components": [ + { + "name": "digitron-orchestrator", + "state": "pending" + }, + { + "name": "database-services", + "state": "pending" + } + ] +} +``` + +A see-thru gateway reporting status on behalf of a child device names the child target using the full gateway path: + +```json +{ + "deploymentId": "b4f3a6ed-102f-405f-9a86-63df487abc17", + "targetName": "gateway1/deviceA", + "adoptedManifestVersion": 7, + "status": { + "state": "installed" + }, + "components": [ + { + "name": "digitron-orchestrator", + "state": "installed" + } + ] +} ``` \ No newline at end of file diff --git a/system-design/specification/margo-management-interface/device-capabilities.md b/system-design/specification/margo-management-interface/device-capabilities.md index 132e39cf..c3ad9939 100644 --- a/system-design/specification/margo-management-interface/device-capabilities.md +++ b/system-design/specification/margo-management-interface/device-capabilities.md @@ -9,15 +9,15 @@ To ensure the WFM is kept up to date, the device's client MUST send updated capa ## Route and HTTP Methods ```https -PUT /api/v1/capabilities/{deviceId} -DELETE /api/v1/capabilities/{deviceId} +PUT /api/v1/capabilities/{targetName} +DELETE /api/v1/capabilities/{targetName} ``` ### Route Parameters |Parameter | Type | Required? | Description| |----------|------|-----------|------------| -| {deviceId} | string | Y | The unique identifier of the device reporting the capabilities.
It must have the following format: "{id}[/{id}[/{id}...]]". The top-level `id` is required and must include only unreserved characters as specified in [RFC3986](https://www.rfc-editor.org/rfc/rfc3986#section-2.3). If reporting capabilties for a child device, the subsequent `id`s are required and must include only unreserved characters as specified in [RFC3986](https://www.rfc-editor.org/rfc/rfc3986#section-2.3).
Using multiple ids in the endpoint does not register multiple devices in a single request, but indicates a hierarchy of devices, with a parent/child relationship. | +| {targetName} | string | Y | The name of the target whose capabilities are being reported or deleted. See [Target Names](./api-requirements-and-security.md#target-names).
It must have the following format: "{name}[/{name}[/{name}...]]". The top-level `name` is required and must include only unreserved characters as specified in [RFC3986](https://www.rfc-editor.org/rfc/rfc3986#section-2.3). If reporting capabilties for a child device, the subsequent `name`s are required and must include only unreserved characters as specified in [RFC3986](https://www.rfc-editor.org/rfc/rfc3986#section-2.3).
Using multiple names in the endpoint does not register multiple devices in a single request, but indicates a hierarchy of devices, with a parent/child relationship. | ### Response Codes @@ -28,7 +28,7 @@ DELETE /api/v1/capabilities/{deviceId} | 204 No Content | The device capabilities document was deleted successfully. | | 400 Bad Request | PUT: Malformed request body. | | 403 Forbidden | The request is not authorized by the WFM's local policy (for example, the client relationship has been retired; see [Authorization](../identity/wfm-identity-profile.md#authorization)). | -| 404 Not Found | PUT: No gateway was found for the given child-device `deviceId` (see [Gateways considerations](#gateways-considerations) for more details).
DELETE: No device with the given `deviceId` was found for the client. | +| 404 Not Found | PUT: No gateway was found for the given child-device `targetName` (see [Gateways considerations](#gateways-considerations) for more details).
DELETE: No device with the given `targetName` was found for the client. | | 422 Unprocessable Content | Request body includes a semantic error. | ## Request Body Attributes @@ -43,7 +43,7 @@ DELETE /api/v1/capabilities/{deviceId} | Field | Type | Required? | Description | |-----------------|-----------------|-----------------|-----------------| -| id | string | Y | Unique deviceID assigned to the device via the Device Owner. It must include only unreserved characters as specified in [RFC3986](https://www.rfc-editor.org/rfc/rfc3986#section-2.3) plus the path separator (i.e. '/'). In case of a device behind a gateway, the id field takes the form of a path with the id of the parent gateway, the id of the child device, and the ids of any intermediate devices, i.e., "{gatewayId}/[{intermediateDeviceId/.../]{deviceId}". | +| targetName | string | Y | The name of the target whose capabilities are described. It MUST match the `{targetName}` route parameter. It must include only unreserved characters as specified in [RFC3986](https://www.rfc-editor.org/rfc/rfc3986#section-2.3) plus the path separator (i.e. '/'). In case of a device behind a see-thru gateway, the value takes the form of a path with the name of the parent gateway, the names of any intermediate devices, and the name of the child device, i.e., "{gatewayName}/[{intermediateName}/.../]{childName}". See [Target Names](./api-requirements-and-security.md#target-names). | | vendor | string | Y | Defines the device vendor.| | modelNumber | string | Y | Defines the model number of the device.| | serialNumber | string | Y | Defines the serial number of the device.| @@ -56,7 +56,7 @@ DELETE /api/v1/capabilities/{deviceId} | supportedRuntimes | []SupportedRuntime | Y* | Supported workload runtimes present on the device. See the [SupportedRuntime](#supportedruntime) definition for all permissible values. A device that is capable of hosting workloads MUST report at least one entry.| | supportedDeploymentTypes | []SupportedDeploymentType | Y* | The deployment profile types the device can receive and process locally. See the [SupportedDeploymentType](#supporteddeploymenttype) definition for all permissible values. A device that is capable of hosting workloads MUST report at least one entry.| -> Note: \* A see-thru gateway not hosting workloads itself MUST omit these fields. The WFM infers such a device is non-hosting from the absence of these capabilities, and infers a gateway relationship from the parent/child `deviceId` hierarchy. +> Note: \* A see-thru gateway not hosting workloads itself MUST omit these fields. The WFM infers such a device is non-hosting from the absence of these capabilities, and infers a gateway relationship from the parent/child `targetName` hierarchy. ### CPU Attributes CPU element defining the device's CPU characteristics. @@ -140,7 +140,7 @@ These enumerations are used as vocabularies for attribute values of the `DeviceC ```json { "properties": { - "id": "northstarida.xtapro.k8s.edge", + "targetName": "northstarida.xtapro.k8s.edge", "vendor": "Northstar Industrial Devices", "modelNumber": "332ANZE1-N1", "serialNumber": "PF45343-AA", @@ -192,14 +192,14 @@ A device may represent, and aggregate the capabilities of, multiple child-device WFM clients may connect one or more child-devices to the WFM while allowing the WFM to see each device behind it as an individual device with its own capabilities. This type of client is referred to as a **see-thru gateway**. -A see-thru gateway uses the same `DeviceCapabilitiesManifest` schema as any other device — from a payload perspective it is an ordinary device that also reports the devices behind it. Its conformance rules are relaxed, though: unlike non-gateway device, a see-thru gateway is not required to host workloads and need not report workload-hosting capabilities. The WFM infers the gateway relationship from the parent/child `deviceId` hierarchy, which is typically most evident when the gateway reports no workload-hosting capabilities. +A see-thru gateway uses the same `DeviceCapabilitiesManifest` schema as any other device — from a payload perspective it is an ordinary device that also reports the devices behind it. Its conformance rules are relaxed, though: unlike non-gateway device, a see-thru gateway is not required to host workloads and need not report workload-hosting capabilities. The WFM infers the gateway relationship from the parent/child `targetName` hierarchy, which is typically most evident when the gateway reports no workload-hosting capabilities. **How a see-thru gateway reports capabilities** A see-thru gateway MUST report its own capabilities and the capabilities of each device it connects to the WFM: 1. Call the `device capabilities` endpoint once for the gateway itself, then once for each device behind it. -2. Encode the hierarchy in the `deviceId` as a parent/child path. For example, a gateway `gateway1` with two child-devices calls the endpoint three times, with `deviceId`s `gateway1`, `gateway1/deviceA`, and `gateway1/deviceB`. +2. Encode the hierarchy in the `targetName` as a parent/child path. For example, a gateway `gateway1` with two child-devices calls the endpoint three times, with `targetName`s `gateway1`, `gateway1/deviceA`, and `gateway1/deviceB`. 3. Report the gateway's own manifest **before** any child manifest. If the WFM receives a child manifest first, it MUST reject the request with a `404 Not Found` response code. **What the gateway reports about itself** @@ -221,7 +221,7 @@ Hosting is neither required of nor forbidden for a see-thru gateway: it reports ```json { "properties": { - "id": "gateway1", + "targetName": "gateway1", "vendor": "Gateway Vendor", "modelNumber": "GW-1000", "serialNumber": "GW12345678" @@ -237,7 +237,7 @@ Hosting is neither required of nor forbidden for a see-thru gateway: it reports ```json { "properties": { - "id": "gateway1", + "targetName": "gateway1", "vendor": "Gateway Vendor", "modelNumber": "GW-1000", "serialNumber": "GW12345678", @@ -274,7 +274,7 @@ Hosting is neither required of nor forbidden for a see-thru gateway: it reports ```json { "properties": { - "id": "gateway1/deviceA", + "targetName": "gateway1/deviceA", "vendor": "Device A Vendor", "modelNumber": "DA-2000", "serialNumber": "DA12345678", @@ -316,7 +316,7 @@ Hosting is neither required of nor forbidden for a see-thru gateway: it reports ```json { "properties": { - "id": "gateway1/path1/deviceA", + "targetName": "gateway1/path1/deviceA", "vendor": "Device A Vendor", "modelNumber": "DA-1000", "serialNumber": "DA12345678", diff --git a/system-design/specification/margo-management-interface/workload-management-api-1.0.0-rc.2.yaml b/system-design/specification/margo-management-interface/workload-management-api-1.0.0-rc.2.yaml index 7fc2cd80..ed93ce7e 100644 --- a/system-design/specification/margo-management-interface/workload-management-api-1.0.0-rc.2.yaml +++ b/system-design/specification/margo-management-interface/workload-management-api-1.0.0-rc.2.yaml @@ -21,15 +21,15 @@ security: - mTLS: [] paths: - /api/v1/capabilities/{deviceId}: + /api/v1/capabilities/{targetName}: put: summary: Report or update device capabilities parameters: - - name: deviceId + - name: targetName in: path required: true schema: - $ref: '#/components/schemas/DeviceId' + $ref: '#/components/schemas/TargetName' requestBody: required: true content: @@ -54,7 +54,7 @@ paths: schema: $ref: '#/components/schemas/ProblemDetail' '404': - description: No gateway was found for the given child-device deviceId. + description: No gateway was found for the given child-device targetName. content: application/problem+json: schema: @@ -68,11 +68,11 @@ paths: delete: summary: Remove device (Unregister) parameters: - - name: deviceId + - name: targetName in: path required: true schema: - $ref: '#/components/schemas/DeviceId' + $ref: '#/components/schemas/TargetName' responses: '204': description: Device capabilities removed successfully @@ -83,7 +83,7 @@ paths: schema: $ref: '#/components/schemas/ProblemDetail' '404': - description: No device with the given deviceId was found for the client. + description: No device with the given targetName was found for the client. content: application/problem+json: schema: @@ -354,7 +354,7 @@ components: detail: type: string description: Human-readable explanation specific to this occurrence of the problem. - example: No gateway was found for the given child-device deviceId. + example: No gateway was found for the given child-device targetName. instance: type: string format: uri-reference @@ -492,16 +492,16 @@ components: properties: properties: type: object - required: [id, vendor, modelNumber, serialNumber] + required: [targetName, vendor, modelNumber, serialNumber] # Only identity fields are required. A device that hosts workloads reports cpus, memory, # storage, peripherals, interfaces, otelCollector (true), supportedRuntimes (>=1), and # supportedDeploymentTypes (>=1). A device that does not host workloads (e.g. a see-thru # gateway that only relays the devices behind it) omits those fields. # The WFM infers it is non-hosting from their absence and infers a - # gateway from the parent/child deviceId hierarchy. + # gateway from the parent/child targetName hierarchy. properties: - id: - $ref: '#/components/schemas/DeviceId' + targetName: + $ref: '#/components/schemas/TargetName' vendor: type: string modelNumber: @@ -564,16 +564,16 @@ components: - type: array items: type: number - DeviceId: - # format: "{id}[/{id}[/{id}...]]" - # Top-level id is required and must include only unreserved characters as specified in RFC3986. - # Subsequent ids are only used when referencing child devices, and must include only unreserved characters as specified in RFC3986 when present. + TargetName: + # format: "{name}[/{name}[/{name}...]]" + # Top-level name is required and must include only unreserved characters as specified in RFC3986. + # Subsequent names are only used when referencing child devices behind a see-thru gateway, and must include only unreserved characters as specified in RFC3986 when present. type: string pattern: '^[A-Za-z0-9._~-]+(\/[A-Za-z0-9._~-]+)*$' - DeviceId_with_asterisk: - # format: "{id}[/{id}[/{id}...]/*]" - # Top-level id is required and must include only unreserved characters as specified in RFC3986. - # Subsequent ids are only used when referencing child devices, and must include only unreserved characters as specified in RFC3986 when present. + TargetName_with_asterisk: + # format: "{name}[/{name}[/{name}...]/*]" + # Top-level name is required and must include only unreserved characters as specified in RFC3986. + # Subsequent names are only used when referencing child devices behind a see-thru gateway, and must include only unreserved characters as specified in RFC3986 when present. type: string pattern: '^[A-Za-z0-9._~-]+(\/[A-Za-z0-9._~-]+)*(\/\*)?$' @@ -598,12 +598,12 @@ components: DeploymentStatusManifest: type: object - required: [deploymentId, adoptedManifestVersion, status, components] + required: [deploymentId, targetName, adoptedManifestVersion, status, components] properties: deploymentId: type: string - deviceId: - $ref: '#/components/schemas/DeviceId' + targetName: + $ref: '#/components/schemas/TargetName' adoptedManifestVersion: $ref: '#/components/schemas/ManifestVersion' status: @@ -663,7 +663,7 @@ components: $ref: '#/components/schemas/appDeploymentSpec' appDeploymentMetadata: type: object - required: [annotations, name, namespace, deviceId] + required: [annotations, name, namespace, targetName] properties: name: type: string @@ -671,9 +671,9 @@ components: namespace: type: string description: Namespace of the resource - deviceId: - $ref: '#/components/schemas/DeviceId_with_asterisk' - description: Device ID of the target device for the deployment + targetName: + $ref: '#/components/schemas/TargetName_with_asterisk' + description: Name of the target the deployment is assigned to labels: type: object additionalProperties: { type: string } diff --git a/system-design/specification/problem-types.md b/system-design/specification/problem-types.md index 1353eec6..e774c666 100644 --- a/system-design/specification/problem-types.md +++ b/system-design/specification/problem-types.md @@ -13,8 +13,8 @@ These values are used in the `type` field of RFC 9457 `application/problem+json` | [#invalid-request](#invalid-request) | 400 | Malformed request body. | | [#semantic-error](#semantic-error) | 422 | Request body includes a semantic error. | | [#not-authorized](#not-authorized) | 403 | The request is not authorized by the WFM's local policy (for example, the client relationship has been retired). | -| [#gateway-not-found](#gateway-not-found) | 404 | No gateway was found for the given child-device deviceId. | -| [#device-not-found](#device-not-found) | 404 | No device with the given deviceId was found for the client. | +| [#gateway-not-found](#gateway-not-found) | 404 | No gateway was found for the given child-device targetName. | +| [#device-not-found](#device-not-found) | 404 | No device with the given targetName was found for the client. | | [#invalid-bundle](#invalid-bundle) | 404 | Bundle not found for the given digest. | | [#deployment-not-found](#deployment-not-found) | 404 | Deployment not found for the given digest. | | [#discovery-document-not-found](#discovery-document-not-found) | 404 | Trust domain discovery document not available. | @@ -149,16 +149,16 @@ This problem type identifies requests that are denied by the WFM's local authori - **Type URI:** `https://docs.margo.org/specification/problem-types#gateway-not-found` - **HTTP status:** 404 Not Found -- **Summary:** No gateway was found for the given child-device deviceId. +- **Summary:** No gateway was found for the given child-device targetName. -This problem type indicates that the server cannot find a gateway for the child-device identified by the `deviceId` path parameter. This applies when a child `deviceId` is used and no parent gateway is registered for it. +This problem type indicates that the server cannot find a gateway for the child-device identified by the `targetName` path parameter. This applies when a child `targetName` is used and no parent gateway is registered for it. ```json { "type": "https://docs.margo.org/specification/problem-types#gateway-not-found", "title": "Gateway not found", "status": 404, - "detail": "No gateway was found for the given child-device deviceId.", + "detail": "No gateway was found for the given child-device targetName.", "instance": "/api/v1/capabilities/gateway-1/child-device-2" } ``` @@ -169,7 +169,7 @@ This problem type indicates that the server cannot find a gateway for the child- - **Type URI:** `https://docs.margo.org/specification/problem-types#device-not-found` - **HTTP status:** 404 Not Found -- **Summary:** No device with the given deviceId was found for the client. +- **Summary:** No device with the given targetName was found for the client. This problem type is returned when a DELETE request references a device that does not exist for the authenticated client. @@ -178,7 +178,7 @@ This problem type is returned when a DELETE request references a device that doe "type": "https://docs.margo.org/specification/problem-types#device-not-found", "title": "Device Not Found", "status": 404, - "detail": "No device with the given deviceId was found for the client.", + "detail": "No device with the given targetName was found for the client.", "instance": "/api/v1/capabilities/device-1" } ``` From a8911cbc9909208797d1cc5c3b2a034d96d9066f Mon Sep 17 00:00:00 2001 From: Armand Craig Date: Thu, 17 Sep 2026 15:11:45 -0400 Subject: [PATCH 2/3] Removal of white space. Signed-off-by: Armand Craig --- .../resources/index.md.jinja2 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/specification/margo-management-interface/resources/index.md.jinja2 b/src/specification/margo-management-interface/resources/index.md.jinja2 index b1ab41af..902bb3d6 100644 --- a/src/specification/margo-management-interface/resources/index.md.jinja2 +++ b/src/specification/margo-management-interface/resources/index.md.jinja2 @@ -265,11 +265,11 @@ This section defines the structure and YAML schema of an `ApplicationDeployment` {% if schema.description %}{{ schema.description }}{% endif %} ```yaml -id: -metadata: - name: - namespace: - targetName: +id: +metadata: + name: + namespace: + targetName: spec: applicationId: deploymentProfile: @@ -414,7 +414,7 @@ In this example, an application is deployed to a specific child device through a ### Example: Gateway Autonomous Deployment Specification -In this example, an application is deployed to a child device with the see-thru gateway deciding which device to use. The gateway is told to choose the device by using `*` in the `targetName` attribute of the `ApplicationDeployment` specification. +In this example, an application is deployed to a child device with the see-thru gateway deciding which device to use. The gateway is told to choose the device by using `*` in the `targetName` attribute of the `ApplicationDeployment` specification. ```yaml {% include 'examples/valid/gateway-autonomous.yaml' %} From fe2a2eda7c3bc2078788356f4b8c9cec4d761e4f Mon Sep 17 00:00:00 2001 From: Armand Craig Date: Tue, 22 Sep 2026 16:26:29 -0400 Subject: [PATCH 3/3] Addressed various comments, but now in a rabbit hole I need to work through with a counterpart :) Signed-off-by: Armand Craig --- .../desired-state.linkml.yaml | 8 +-- .../resources/index.md.jinja2 | 16 ++--- .../api-requirements-and-security.md | 21 ++++--- .../deployment-status.md | 10 +-- .../device-capabilities.md | 63 ++++--------------- .../workload-management-api-1.0.0-rc.3.yaml | 30 ++++----- system-design/specification/problem-types.md | 32 +++++----- 7 files changed, 74 insertions(+), 106 deletions(-) diff --git a/src/specification/margo-management-interface/desired-state.linkml.yaml b/src/specification/margo-management-interface/desired-state.linkml.yaml index 3b898cb2..c27c8fa5 100644 --- a/src/specification/margo-management-interface/desired-state.linkml.yaml +++ b/src/specification/margo-management-interface/desired-state.linkml.yaml @@ -61,12 +61,12 @@ classes: rank: 20 targetName: description: >- - The name of the target, with hierarchy if applicable, to which the deployment is assigned. - To reference a child device behind a see-thru gateway the format is `{target-name}[/{target-name}[/...]]`.
- To request the gateway to choose the child device, use `*` for the last segment in the hierarchy (i.e. `{target-name}[/{target-name}/...]/*`). + The name of the target to which the deployment is assigned. + To reference a child device behind a see-thru gateway the format is `{gatewayName}/{childName}`.
+ To request the gateway to choose the child device, use `*` in place of the child name (i.e. `{gatewayName}/*`). If the gateway is not capable of autonomously selecting a child device, it MUST send back a deployment status with error `103 - Autonomous placement not supported` when `*` is used. required: true - pattern: '^[A-Za-z0-9._~-]+(\/[A-Za-z0-9._~-]+)*(\/\*)?$' + pattern: '^[A-Za-z0-9._~-]+(\/([A-Za-z0-9._~-]+|\*))?$' rank: 30 Spec: description: Specification details of the desired state. diff --git a/src/specification/margo-management-interface/resources/index.md.jinja2 b/src/specification/margo-management-interface/resources/index.md.jinja2 index 902bb3d6..7cc14ac7 100644 --- a/src/specification/margo-management-interface/resources/index.md.jinja2 +++ b/src/specification/margo-management-interface/resources/index.md.jinja2 @@ -1,11 +1,11 @@ # Desired State -In order for the Workload Fleet Manager (WFM) to manage workloads on an Edge Compute Device, the device's Workload Fleet Management Client must periodically retrieve its desired workload configuration - referred to as the Desired State - from the WFM. +In order for the Workload Fleet Manager (WFM) to manage workloads on a compute target, the target's Workload Fleet Management Client must periodically retrieve its desired workload configuration - referred to as the Desired State - from the WFM. -The Desired State defines *what* workloads (applications) should run on the device and *how* they should be configured. -It is distributed using a lightweight, pull-based HTTP API that allows devices to stay synchronized with the WFM. +The Desired State defines *what* workloads (applications) should run on the target and *how* they should be configured. +It is distributed using a lightweight, pull-based HTTP API that allows clients to stay synchronized with the WFM. -At the center of this process is the State Manifest, a JSON document that lists all workloads assigned to the authenticated client. The manifest is scoped to the client, not to a single device: a client that fronts several devices, such as a see-thru gateway with child devices, retrieves one manifest covering all of them. Each workload is represented by an [`ApplicationDeployment`](#applicationdeployment-yaml-definition) YAML - a self-contained object defining configuration, components, and parameters for that workload - and names its deployment target in its `metadata.targetName` attribute. +At the center of this process is the State Manifest, a JSON document that lists all workloads assigned to the authenticated client. The manifest is scoped to the client, not to a single target: a client that fronts several targets, such as a see-thru gateway with child targets, retrieves one manifest covering all of them. Each workload is represented by an [`ApplicationDeployment`](#applicationdeployment-yaml-definition) YAML - a self-contained object defining configuration, components, and parameters for that workload - and names its target in its `metadata.targetName` attribute. The manifest includes two complementary ways for the client to obtain the same `ApplicationDeployment` YAMLs: @@ -25,7 +25,7 @@ For every change in deployment state - including installation, updates, removals ## Endpoints: State Manifest -This section defines the API endpoint used by a client to retrieve the State Manifest from the Workload Fleet Manager, representing the complete desired workload configuration assigned to the client and the devices it is responsible for. +This section defines the API endpoint used by a client to retrieve the State Manifest from the Workload Fleet Manager, representing the complete desired workload configuration assigned to the client and the targets it is responsible for. ### Route and HTTP Methods @@ -73,7 +73,7 @@ GET /api/v1/deployments | Field | Type | Required? | Description | | ----- | ---- | --------- | ----------- | -| `manifestVersion` | number | Y | Monotonically increasing unsigned 64-bit integer in the inclusive range `[1, 2^64-1]`. Each new manifest for the same client MUST have a strictly greater value than the previous, forming a single sequence per client that spans all devices the client is responsible for. The first manifest for a given client MUST use the value 1. | +| `manifestVersion` | number | Y | Monotonically increasing unsigned 64-bit integer in the inclusive range `[1, 2^64-1]`. Each new manifest for the same client MUST have a strictly greater value than the previous, forming a single sequence per client that spans all targets the client is responsible for. The first manifest for a given client MUST use the value 1. | | `bundle` | object | Y | Describes an archive containing all referenced `ApplicationDeployment` YAMLs. If there are zero deployments (i.e., the `deployments` array is empty), this field MUST be present with the value `null`. An empty archive MUST NOT be served. | | `bundle.mediaType` | string | Y | MUST be `application/vnd.margo.bundle.v1+tar+gzip`, which denotes a gzip-compressed tar archive (commonly delivered as a .tar.gz) whose root contains one or more `ApplicationDeployment` YAML files. Servers MUST set the HTTP `Content-Type` to this media type. The archive MUST contain exactly the set of YAML files referenced by `deployments`. | | `bundle.digest` | string | Y | Digest of the bundle archive. MUST equal the digest computed over the exact sequence of bytes in the [bundle endpoint's](#endpoints-deployment-bundle) HTTP `200 OK` response body. See [Protocol: Digest](#protocol-digest) for further details. | @@ -406,7 +406,7 @@ These enumerations are used as vocabularies for attribute values of the `Applica ### Example: Gateway Directed Deployment Specification -In this example, an application is deployed to a specific child device through a see-thru gateway. The gateway determines the target device for deployment from the value of the `targetName` attribute of the `ApplicationDeployment` specification. +In this example, an application is deployed to a specific child target through a see-thru gateway. The gateway determines the target for deployment from the value of the `targetName` attribute of the `ApplicationDeployment` specification. ```yaml {% include 'examples/valid/gateway-directed.yaml' %} @@ -414,7 +414,7 @@ In this example, an application is deployed to a specific child device through a ### Example: Gateway Autonomous Deployment Specification -In this example, an application is deployed to a child device with the see-thru gateway deciding which device to use. The gateway is told to choose the device by using `*` in the `targetName` attribute of the `ApplicationDeployment` specification. +In this example, an application is deployed to a child target with the see-thru gateway deciding which one to use. The gateway is told to choose the target by using `*` in the `targetName` attribute of the `ApplicationDeployment` specification. ```yaml {% include 'examples/valid/gateway-autonomous.yaml' %} diff --git a/system-design/specification/margo-management-interface/api-requirements-and-security.md b/system-design/specification/margo-management-interface/api-requirements-and-security.md index 1ca27e93..51d1149b 100644 --- a/system-design/specification/margo-management-interface/api-requirements-and-security.md +++ b/system-design/specification/margo-management-interface/api-requirements-and-security.md @@ -15,17 +15,20 @@ Identity and authentication for the Management Interface are provided by the [Ma ## Target Names -`targetName` is the WFM Client-reported name of a deployment target. It identifies the device, gateway, or child device path a WFM uses for capability reporting, desired state assignment, and deployment status correlation. Every Management Interface surface that names a deployment target uses `targetName`. +`targetName` is the WFM Client-reported name of a target: the identifier a WFM uses for capability reporting, desired state assignment, and deployment status correlation. Every Management Interface surface that names a target uses `targetName`. A **compute target** is a target that hosts workloads. A see-thru gateway is a target that relays others, and may be a compute target as well. + +A `targetName` takes one of two forms: a single name for a target the WFM Client connects directly, or `{gatewayName}/{childName}` for a target behind a see-thru gateway. A `targetName`: * MUST be stable for the lifetime of the target relationship. -* MUST consist only of unreserved characters as specified in [RFC3986](https://www.rfc-editor.org/rfc/rfc3986#section-2.3) in each path segment. -* MAY contain `/` separators to represent a see-thru [gateway](../../concepts/gateways/gateways.md) hierarchy, in the form `{name}[/{name}[/{name}...]]`. -* MAY use `*` as the final path segment only where this specification explicitly allows gateway-selected placement. -* MUST be treated as opaque by the WFM except where this specification defines gateway path interpretation. +* MUST consist only of unreserved characters as specified in [RFC3986](https://www.rfc-editor.org/rfc/rfc3986#section-2.3) in each name. +* MUST NOT contain more than one `/` separator. +* MAY use `*` in place of `{childName}` only where this specification explicitly allows gateway-selected placement. +* MUST be treated as opaque by the WFM apart from the split into `{gatewayName}` and `{childName}`. + +A see-thru gateway that reaches its targets through further internal tiers MUST present each one to the WFM as a single `{childName}` directly under its own name. The internal topology is private to the gateway: the WFM never observes it, and the gateway is responsible for keeping each `{childName}` unique within its own scope. See [See-thru gateways](./device-capabilities.md#see-thru-gateways). -A `targetName` is a name, not a universally unique device identifier. Margo reserves the term `deviceId` for a universally unique device identifier assigned by a Device Fleet Manager or another authoritative inventory system, and does not use it on the Management Interface targeting surface. ## API Definition The REST API is defined via the OpenAPI Specification: @@ -43,9 +46,9 @@ Authentication is mutual TLS per the MIAF [TLS requirements](../identity/tls-req The caller identity for every request is the authenticated WFM Client SPIFFE ID; the request itself does not carry it. A WFM derives the caller from the SPIFFE ID, not from any identifier in the request path or body. -Every Management Interface endpoint is scoped to the authenticated caller. A WFM determines from the caller's identity which deployment targets that client is responsible for and which deployments are assigned to them. Where a request path carries a resource identifier, for example `{targetName}` or `{digest}`, the WFM looks that identifier up only among the resources in the caller's scope. A WFM MUST NOT expose or mutate a resource outside the caller's scope. +Every Management Interface endpoint is scoped to the authenticated caller. A WFM determines from the caller's identity which targets that client is responsible for and which deployments are assigned to them. Where a request path carries a resource identifier, for example `{targetName}` or `{digest}`, the WFM looks that identifier up only among the resources in the caller's scope. A WFM MUST NOT expose or mutate a resource outside the caller's scope. -A `targetName` is not a global name: it identifies a deployment target only within the scope of one WFM Client. The binding between a `targetName` and the caller's identity is established by the client itself, when it first reports capabilities for that target (see [Device Capabilities](../margo-management-interface/device-capabilities.md)), and every later reference to that `targetName` is resolved within the reporting client's scope. Because the scope is derived from the authenticated SPIFFE ID, a client cannot register, read, or mutate a target in another client's scope: two clients reporting the same `targetName` string address two unrelated target records. A WFM MAY additionally constrain, by local policy, which `targetName`s a given client is allowed to report; such policy is deployment-specific and out of scope for this specification. +A `targetName` is not a global name: it identifies a target only within the scope of one WFM Client. The binding between a `targetName` and the caller's identity is established by the client itself, when it first reports capabilities for that target (see [Device Capabilities](../margo-management-interface/device-capabilities.md)), and every later reference to that `targetName` is resolved within the reporting client's scope. Because the scope is derived from the authenticated SPIFFE ID, a client cannot register, read, or mutate a target in another client's scope: two clients reporting the same `targetName` string address two unrelated target records. A WFM MAY additionally constrain, by local policy, which `targetName`s a given client is allowed to report; such policy is deployment-specific and out of scope for this specification. The WFM authorizes each request using local policy keyed on the authenticated WFM Client identity, and MAY deny a request from a still-valid credential, per [Authorization](../identity/wfm-identity-profile.md#authorization). When a WFM denies a request by local policy (for example, a retired client relationship), it SHOULD respond `403 Forbidden` with an [RFC 9457](https://datatracker.ietf.org/doc/html/rfc9457) Problem Details body (`Content-Type: application/problem+json`) using the `wfm-client-relationship-retired` type: @@ -74,7 +77,7 @@ The standard error response structure is: "title": "Invalid Request", "status": 400, "detail": "Malformed request body.", - "instance": "/api/v1/capabilities/device-1" + "instance": "/api/v1/capabilities/target-1" } ``` diff --git a/system-design/specification/margo-management-interface/deployment-status.md b/system-design/specification/margo-management-interface/deployment-status.md index d39a31b3..66e64add 100644 --- a/system-design/specification/margo-management-interface/deployment-status.md +++ b/system-design/specification/margo-management-interface/deployment-status.md @@ -32,7 +32,7 @@ POST /api/v1/deployments/{deploymentId}/status | Fields | Type | Required? | Description | |-----------------|-----------------|-----------------|-----------------| | deploymentId | string | Y | The unique identifier UUID of the deployment specification. Needs to be assigned by the Workload Fleet Management Software. | -| targetName | string | Y | Name of the target hosting the deployment. Includes the full gateway hierarchy if applicable. See [Target Names](./api-requirements-and-security.md#target-names). | +| targetName | string | Y | Name of the target hosting the deployment. Includes the gateway name when the target sits behind a see-thru gateway. See [Target Names](./api-requirements-and-security.md#target-names). | | adoptedManifestVersion | number | Y | The [manifestVersion](./desired-state.md#endpoints---state-manifest) of the most recent state manifest the WFM client has adopted for this deployment. See the [Adopted Manifest Version](#adopted-manifest-version) section below.| | status | []status | Y | Element that defines overall deployment status. See the [Status Attributes](#status-attributes) section below.| | components | []components | Y | Element that defines the individual component's deployment status. See the [Component Attributes](#component-attributes) section below.| @@ -59,10 +59,10 @@ POST /api/v1/deployments/{deploymentId}/status | Fields | Type | Required? | Description | |-----------------|-----------------|-----------------|-----------------| | code | string | Y | Associated error code following a component failure during installation. | -| source | string | Y | Identifies the source of the error. It is set to the `targetName`, with its full hierarchy if applicable, of the target generating the error, or to the component name of the component generating the error. | +| source | string | Y | Identifies the source of the error. It is set to the `targetName` of the target generating the error, or to the component name of the component generating the error. | | message | string | Y | Associated error message that provides further details to the WFM about the error that was encountered. | -When the error is generated by a see-thru [gateway](../../concepts/gateways/gateways.md), the source attribute of the error structure MUST be set to the gateway's `targetName`, with its full hierarchy if applicable. +When the error is generated by a see-thru [gateway](./device-capabilities.md#see-thru-gateways), the source attribute of the error structure MUST be set to the gateway's `targetName`. When the error is not generated by a see-thru gateway, the source of the `status.error` attribute MUST be set to the name of the deployment as defined in the `metadata.name` attribute of the application deployment manifest. @@ -76,9 +76,9 @@ When the error is not generated by a see-thru gateway, the source of the `compon |------------|-------------|-------------|-------------| | 101 | Unknown child device | `targetName` of the gateway | The gateway cannot identify the child device with the given name. | | 102 | Child device unreachable | `targetName` of the gateway | The gateway cannot establish a connection with the child device. | -| 103 | Autonomous placement not supported | `targetName` of the gateway | The gateway is not capable of autonomously selecting the child-device for the deployment. | +| 103 | Autonomous placement not supported | `targetName` of the gateway | The gateway is not capable of autonomously selecting the child target for the deployment. | -When the error used is a reserved code for a gateway-generated error, the `source` attribute MUST be set to the `targetName` of the gateway, with its full hierarchy if applicable. +When the error used is a reserved code for a gateway-generated error, the `source` attribute MUST be set to the `targetName` of the gateway. #### Adopted Manifest Version diff --git a/system-design/specification/margo-management-interface/device-capabilities.md b/system-design/specification/margo-management-interface/device-capabilities.md index c3ad9939..9c714462 100644 --- a/system-design/specification/margo-management-interface/device-capabilities.md +++ b/system-design/specification/margo-management-interface/device-capabilities.md @@ -17,7 +17,7 @@ DELETE /api/v1/capabilities/{targetName} |Parameter | Type | Required? | Description| |----------|------|-----------|------------| -| {targetName} | string | Y | The name of the target whose capabilities are being reported or deleted. See [Target Names](./api-requirements-and-security.md#target-names).
It must have the following format: "{name}[/{name}[/{name}...]]". The top-level `name` is required and must include only unreserved characters as specified in [RFC3986](https://www.rfc-editor.org/rfc/rfc3986#section-2.3). If reporting capabilties for a child device, the subsequent `name`s are required and must include only unreserved characters as specified in [RFC3986](https://www.rfc-editor.org/rfc/rfc3986#section-2.3).
Using multiple names in the endpoint does not register multiple devices in a single request, but indicates a hierarchy of devices, with a parent/child relationship. | +| {targetName} | string | Y | The name of the target whose capabilities are being reported or deleted. See [Target Names](./api-requirements-and-security.md#target-names).
It must be a single name for a target the client connects directly, or "{gatewayName}/{childName}" for a target behind a see-thru gateway. Each name is required and must include only unreserved characters as specified in [RFC3986](https://www.rfc-editor.org/rfc/rfc3986#section-2.3).
A `targetName` has at most two names. Using two names in the endpoint does not register two targets in a single request, but indicates a parent/child relationship between a see-thru gateway and one target behind it. | ### Response Codes @@ -28,8 +28,8 @@ DELETE /api/v1/capabilities/{targetName} | 204 No Content | The device capabilities document was deleted successfully. | | 400 Bad Request | PUT: Malformed request body. | | 403 Forbidden | The request is not authorized by the WFM's local policy (for example, the client relationship has been retired; see [Authorization](../identity/wfm-identity-profile.md#authorization)). | -| 404 Not Found | PUT: No gateway was found for the given child-device `targetName` (see [Gateways considerations](#gateways-considerations) for more details).
DELETE: No device with the given `targetName` was found for the client. | -| 422 Unprocessable Content | Request body includes a semantic error. | +| 404 Not Found | PUT: No gateway was registered under the `{gatewayName}` of the given child `targetName` (see [Gateways considerations](#gateways-considerations) for more details).
DELETE: No target with the given `targetName` was found for the client. | +| 422 Unprocessable Content | Request body includes a semantic error, for example `properties.targetName` does not match the `{targetName}` route parameter. | ## Request Body Attributes @@ -43,7 +43,7 @@ DELETE /api/v1/capabilities/{targetName} | Field | Type | Required? | Description | |-----------------|-----------------|-----------------|-----------------| -| targetName | string | Y | The name of the target whose capabilities are described. It MUST match the `{targetName}` route parameter. It must include only unreserved characters as specified in [RFC3986](https://www.rfc-editor.org/rfc/rfc3986#section-2.3) plus the path separator (i.e. '/'). In case of a device behind a see-thru gateway, the value takes the form of a path with the name of the parent gateway, the names of any intermediate devices, and the name of the child device, i.e., "{gatewayName}/[{intermediateName}/.../]{childName}". See [Target Names](./api-requirements-and-security.md#target-names). | +| targetName | string | Y | The name of the target whose capabilities are described. It MUST match the `{targetName}` route parameter exactly, comparing case-sensitively; a WFM MUST reject a mismatch with `422 Unprocessable Content` and MUST NOT create or update a target from either value. It must include only unreserved characters as specified in [RFC3986](https://www.rfc-editor.org/rfc/rfc3986#section-2.3) plus the path separator (i.e. '/'). In case of a target behind a see-thru gateway, the value takes the form of the name of the parent gateway followed by the name of the child target, i.e., "{gatewayName}/{childName}". See [Target Names](./api-requirements-and-security.md#target-names). | | vendor | string | Y | Defines the device vendor.| | modelNumber | string | Y | Defines the model number of the device.| | serialNumber | string | Y | Defines the serial number of the device.| @@ -56,7 +56,7 @@ DELETE /api/v1/capabilities/{targetName} | supportedRuntimes | []SupportedRuntime | Y* | Supported workload runtimes present on the device. See the [SupportedRuntime](#supportedruntime) definition for all permissible values. A device that is capable of hosting workloads MUST report at least one entry.| | supportedDeploymentTypes | []SupportedDeploymentType | Y* | The deployment profile types the device can receive and process locally. See the [SupportedDeploymentType](#supporteddeploymenttype) definition for all permissible values. A device that is capable of hosting workloads MUST report at least one entry.| -> Note: \* A see-thru gateway not hosting workloads itself MUST omit these fields. The WFM infers such a device is non-hosting from the absence of these capabilities, and infers a gateway relationship from the parent/child `targetName` hierarchy. +> Note: \* A see-thru gateway not hosting workloads itself MUST omit these fields. The WFM infers such a device is non-hosting from the absence of these capabilities, and infers a gateway relationship from the parent/child `targetName`. ### CPU Attributes CPU element defining the device's CPU characteristics. @@ -184,22 +184,22 @@ These enumerations are used as vocabularies for attribute values of the `DeviceC ### Opaque gateways -A device may represent, and aggregate the capabilities of, multiple child-devices behind it and report itself as a single Margo device to the WFM. This type of device is referred to as an opaque gateway. Opaque gateways report the combined capabilities of all the devices they connect to the WFM as a single `DeviceCapabilitiesManifest`. Because the child-devices are not individually visible to the WFM, an opaque gateway is seen as a single device and reports the aggregated resource fields, `supportedRuntimes`, and `supportedDeploymentTypes` of the devices behind it. +A target may represent, and aggregate the capabilities of, multiple compute resources behind it and report itself to the WFM as a single target. This type of target is referred to as an opaque gateway. Opaque gateways report the combined capabilities of everything they connect to the WFM as a single `DeviceCapabilitiesManifest`. Because the resources behind them are not individually visible to the WFM, an opaque gateway is seen as a single target and reports the aggregated resource fields, `supportedRuntimes`, and `supportedDeploymentTypes` of the resources behind it. -> Example: An opaque gateway has two child-devices. Each child-device has an ARM64 processor with 2 cores, 5 GB of memory, 32 GB of storage, and 1 ethernet interface. The gateway will report capabilities of 2 CPUs (arm64) with 2 cores each, 10 GB of memory, 64 GB of storage, and 2 ethernet interfaces. Since the gateway can deploy compose applications on its child-devices it will report `supportedDeploymentTypes: ["compose"]`. +> Example: An opaque gateway has two compute resources behind it. Each has an ARM64 processor with 2 cores, 5 GB of memory, 32 GB of storage, and 1 ethernet interface. The gateway will report capabilities of 2 CPUs (arm64) with 2 cores each, 10 GB of memory, 64 GB of storage, and 2 ethernet interfaces. Since the gateway can deploy compose applications on the resources behind it, it will report `supportedDeploymentTypes: ["compose"]`. ### See-thru gateways -WFM clients may connect one or more child-devices to the WFM while allowing the WFM to see each device behind it as an individual device with its own capabilities. This type of client is referred to as a **see-thru gateway**. +WFM clients may connect one or more child targets to the WFM while allowing the WFM to see each one behind it as an individual target with its own capabilities. This type of client is referred to as a **see-thru gateway**. -A see-thru gateway uses the same `DeviceCapabilitiesManifest` schema as any other device — from a payload perspective it is an ordinary device that also reports the devices behind it. Its conformance rules are relaxed, though: unlike non-gateway device, a see-thru gateway is not required to host workloads and need not report workload-hosting capabilities. The WFM infers the gateway relationship from the parent/child `targetName` hierarchy, which is typically most evident when the gateway reports no workload-hosting capabilities. +A see-thru gateway uses the same `DeviceCapabilitiesManifest` schema as any other target — from a payload perspective it is an ordinary target that also reports the targets behind it. Its conformance rules are relaxed, though: unlike a non-gateway target, a see-thru gateway is not required to host workloads and need not report workload-hosting capabilities. The WFM infers the gateway relationship from the parent/child `targetName`, which is typically most evident when the gateway reports no workload-hosting capabilities. **How a see-thru gateway reports capabilities** -A see-thru gateway MUST report its own capabilities and the capabilities of each device it connects to the WFM: +A see-thru gateway MUST report its own capabilities and the capabilities of each target it connects to the WFM: -1. Call the `device capabilities` endpoint once for the gateway itself, then once for each device behind it. -2. Encode the hierarchy in the `targetName` as a parent/child path. For example, a gateway `gateway1` with two child-devices calls the endpoint three times, with `targetName`s `gateway1`, `gateway1/deviceA`, and `gateway1/deviceB`. +1. Call the `device capabilities` endpoint once for the gateway itself, then once for each target behind it. +2. Encode the relationship in the `targetName` as `{gatewayName}/{childName}`. For example, a gateway `gateway1` with two child targets calls the endpoint three times, with `targetName`s `gateway1`, `gateway1/deviceA`, and `gateway1/deviceB`. 3. Report the gateway's own manifest **before** any child manifest. If the WFM receives a child manifest first, it MUST reject the request with a `404 Not Found` response code. **What the gateway reports about itself** @@ -207,7 +207,7 @@ A see-thru gateway MUST report its own capabilities and the capabilities of each | If the gateway... | Then its own manifest MUST... | | --- | --- | | does **not** host workloads | contain only the required identity fields — omit the workload-hosting fields (`cpus`, `memory`, `storage`, `peripherals`, `interfaces`, `supportedRuntimes`, `supportedDeploymentTypes`), and omit `otelCollector` | -| **also** hosts workloads | report the workload-hosting fields like any hosting device, including at least one entry in both `supportedRuntimes` and `supportedDeploymentTypes` | +| **also** hosts workloads | report the workload-hosting fields like any hosting target, including at least one entry in both `supportedRuntimes` and `supportedDeploymentTypes` | Hosting is neither required of nor forbidden for a see-thru gateway: it reports the workload-hosting fields when it hosts workloads, and omits them when it does not. @@ -308,43 +308,6 @@ Hosting is neither required of nor forbidden for a see-thru gateway: it reports } ``` -* See-thru gateway reporting the capabilities of a child device with deeper hierarchy to the WFM: - - ``` - PUT /api/v1/capabilities/gateway1/path1/deviceA - ``` - ```json - { - "properties": { - "targetName": "gateway1/path1/deviceA", - "vendor": "Device A Vendor", - "modelNumber": "DA-1000", - "serialNumber": "DA12345678", - "cpus": [ - { - "cores": 2, - "architecture": "arm64" - } - ], - "memory": "6 Gi", - "storage": "30 Gi", - "peripherals": [], - "interfaces": [ - { - "type": "ethernet" - } - ], - "otelCollector": true, - "supportedRuntimes": [ - "oci" - ], - "supportedDeploymentTypes": [ - "compose" - ] - } - } - ``` - * See-thru gateway informing the WFM that a child device is no longer available: ``` diff --git a/system-design/specification/margo-management-interface/workload-management-api-1.0.0-rc.3.yaml b/system-design/specification/margo-management-interface/workload-management-api-1.0.0-rc.3.yaml index 47968b76..0943c0a3 100644 --- a/system-design/specification/margo-management-interface/workload-management-api-1.0.0-rc.3.yaml +++ b/system-design/specification/margo-management-interface/workload-management-api-1.0.0-rc.3.yaml @@ -54,13 +54,15 @@ paths: schema: $ref: '#/components/schemas/ProblemDetail' '404': - description: No gateway was found for the given child-device targetName. + description: No gateway was found for the given child targetName. content: application/problem+json: schema: $ref: '#/components/schemas/ProblemDetail' '422': - description: Request body includes a semantic error. + description: >- + Request body includes a semantic error, for example properties.targetName does not match + the targetName route parameter. content: application/problem+json: schema: @@ -83,7 +85,7 @@ paths: schema: $ref: '#/components/schemas/ProblemDetail' '404': - description: No device with the given targetName was found for the client. + description: No target with the given targetName was found for the client. content: application/problem+json: schema: @@ -354,12 +356,12 @@ components: detail: type: string description: Human-readable explanation specific to this occurrence of the problem. - example: No gateway was found for the given child-device targetName. + example: No gateway was found for the given child targetName. instance: type: string format: uri-reference description: URI reference identifying the specific occurrence of the problem. - example: /api/v1/capabilities/gateway-1/child-device-2 + example: /api/v1/capabilities/gateway-1/child-2 retryable: type: boolean description: > @@ -498,7 +500,7 @@ components: # supportedDeploymentTypes (>=1). A device that does not host workloads (e.g. a see-thru # gateway that only relays the devices behind it) omits those fields. # The WFM infers it is non-hosting from their absence and infers a - # gateway from the parent/child targetName hierarchy. + # gateway from the parent/child targetName. properties: targetName: $ref: '#/components/schemas/TargetName' @@ -565,17 +567,17 @@ components: items: type: number TargetName: - # format: "{name}[/{name}[/{name}...]]" - # Top-level name is required and must include only unreserved characters as specified in RFC3986. - # Subsequent names are only used when referencing child devices behind a see-thru gateway, and must include only unreserved characters as specified in RFC3986 when present. + # format: a single name, or "{gatewayName}/{childName}" + # Each name is required and must include only unreserved characters as specified in RFC3986. + # The two-name form is only used when referencing a child target behind a see-thru gateway. type: string - pattern: '^[A-Za-z0-9._~-]+(\/[A-Za-z0-9._~-]+)*$' + pattern: '^[A-Za-z0-9._~-]+(\/[A-Za-z0-9._~-]+)?$' TargetName_with_asterisk: - # format: "{name}[/{name}[/{name}...]/*]" - # Top-level name is required and must include only unreserved characters as specified in RFC3986. - # Subsequent names are only used when referencing child devices behind a see-thru gateway, and must include only unreserved characters as specified in RFC3986 when present. + # format: a single name, "{gatewayName}/{childName}", or "{gatewayName}/*" + # Each name is required and must include only unreserved characters as specified in RFC3986. + # "*" in place of the child name requests gateway-selected placement behind the named see-thru gateway. type: string - pattern: '^[A-Za-z0-9._~-]+(\/[A-Za-z0-9._~-]+)*(\/\*)?$' + pattern: '^[A-Za-z0-9._~-]+(\/([A-Za-z0-9._~-]+|\*))?$' ComponentStatus: type: object diff --git a/system-design/specification/problem-types.md b/system-design/specification/problem-types.md index e774c666..144f272b 100644 --- a/system-design/specification/problem-types.md +++ b/system-design/specification/problem-types.md @@ -13,8 +13,8 @@ These values are used in the `type` field of RFC 9457 `application/problem+json` | [#invalid-request](#invalid-request) | 400 | Malformed request body. | | [#semantic-error](#semantic-error) | 422 | Request body includes a semantic error. | | [#not-authorized](#not-authorized) | 403 | The request is not authorized by the WFM's local policy (for example, the client relationship has been retired). | -| [#gateway-not-found](#gateway-not-found) | 404 | No gateway was found for the given child-device targetName. | -| [#device-not-found](#device-not-found) | 404 | No device with the given targetName was found for the client. | +| [#gateway-not-found](#gateway-not-found) | 404 | No gateway was found for the given child targetName. | +| [#target-not-found](#target-not-found) | 404 | No target with the given targetName was found for the client. | | [#invalid-bundle](#invalid-bundle) | 404 | Bundle not found for the given digest. | | [#deployment-not-found](#deployment-not-found) | 404 | Deployment not found for the given digest. | | [#discovery-document-not-found](#discovery-document-not-found) | 404 | Trust domain discovery document not available. | @@ -93,7 +93,7 @@ This problem type indicates that the server rejected the request because the req "title": "Invalid Request", "status": 400, "detail": "Malformed request body.", - "instance": "/api/v1/capabilities/device-1" + "instance": "/api/v1/capabilities/target-1" } ``` @@ -113,7 +113,7 @@ This problem type is returned when the request body is syntactically valid but c "title": "Semantic Error", "status": 422, "detail": "Request body includes a semantic error.", - "instance": "/api/v1/capabilities/device-1", + "instance": "/api/v1/capabilities/target-1", "errors": [ { "field": "properties.supportedRuntimes", @@ -149,37 +149,37 @@ This problem type identifies requests that are denied by the WFM's local authori - **Type URI:** `https://docs.margo.org/specification/problem-types#gateway-not-found` - **HTTP status:** 404 Not Found -- **Summary:** No gateway was found for the given child-device targetName. +- **Summary:** No gateway was found for the given child targetName. -This problem type indicates that the server cannot find a gateway for the child-device identified by the `targetName` path parameter. This applies when a child `targetName` is used and no parent gateway is registered for it. +This problem type indicates that the server cannot find a gateway for the child target identified by the `targetName` path parameter. This applies when a child `targetName` is used and no parent gateway is registered for it. ```json { "type": "https://docs.margo.org/specification/problem-types#gateway-not-found", "title": "Gateway not found", "status": 404, - "detail": "No gateway was found for the given child-device targetName.", - "instance": "/api/v1/capabilities/gateway-1/child-device-2" + "detail": "No gateway was found for the given child targetName.", + "instance": "/api/v1/capabilities/gateway-1/child-2" } ``` --- -## device-not-found +## target-not-found -- **Type URI:** `https://docs.margo.org/specification/problem-types#device-not-found` +- **Type URI:** `https://docs.margo.org/specification/problem-types#target-not-found` - **HTTP status:** 404 Not Found -- **Summary:** No device with the given targetName was found for the client. +- **Summary:** No target with the given targetName was found for the client. -This problem type is returned when a DELETE request references a device that does not exist for the authenticated client. +This problem type is returned when a DELETE request references a target that does not exist for the authenticated client. ```json { - "type": "https://docs.margo.org/specification/problem-types#device-not-found", - "title": "Device Not Found", + "type": "https://docs.margo.org/specification/problem-types#target-not-found", + "title": "Target Not Found", "status": 404, - "detail": "No device with the given targetName was found for the client.", - "instance": "/api/v1/capabilities/device-1" + "detail": "No target with the given targetName was found for the client.", + "instance": "/api/v1/capabilities/target-1" } ```