Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ 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}[/...]]`. <br/>
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 to which the deployment is assigned.
To reference a child device behind a see-thru gateway the format is `{gatewayName}/{childName}`. <br/>
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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
@@ -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 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 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:

Expand All @@ -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

Expand Down Expand Up @@ -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. |
Expand Down Expand Up @@ -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:
deviceId:
id:
metadata:
name:
namespace:
targetName:
spec:
applicationId:
deploymentProfile:
Expand Down Expand Up @@ -406,15 +406,15 @@ 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 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' %}
```

### 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 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' %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,22 @@ 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 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 name.
* MUST NOT contain more than one `/` separator.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this changing the original requirements? Or was this the intention all along?

Was the original intention to allow only two levels: gateway -> child? Or was the intention to allow multiple nested gateways: gateway -> child -> child?

The way the capabilities endpoint was defined in the SUP seemed to indicate that more than two levels were desired:

@julienduquesnay-se - thoughts?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@phil-abb

Good note to highlight, as I'm trying to round out the Ids we use and the rules around them.

Investigating the original SUP, the id parameter is described:

In case of a device behind a gateway, it takes the form of a path with the id of the parent gateway and the id of the child device, i.e., "{device-id}/{device-id}". The top-level {device-id} must be unique for a given {clientId}, and the children {device-id} must be unique for a given parent {device-id

Additionally, all the examples in the SUP are only Parent/Child. No reference of Parent/Child/Child.

IMO, what hops occur from Gateway to Child that the capabiltiies or deployment specs are associated with are not relevant/useful for the WFM.

* 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).


## API Definition
The REST API is defined via the OpenAPI Specification:
Expand All @@ -30,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 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 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 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:

Expand Down Expand Up @@ -61,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"
}
```

Expand Down
Loading
Loading