跳至主要内容

Upload and Deploy an AI Model

Overview

Authenticate each request with a WEDA bearer token that grants access to the target organization and devices. Obtain one through the standard SSO flow or as an M2M Client Credential.

The workflow has two parts:

  • Upload — create the model, register an edition, upload the binary, and wait for hash verification
  • Deploy — push the verified edition to target devices and confirm the result

Upload Flow

StepCallResult
1. Create modelPOST /api/v1/orgs/{orgId}/ai-models — body { modelName }201modelId. If the name already exists, 409 — list existing models and reuse the modelId
2. Register editionPOST /api/v1/orgs/{orgId}/ai-models/{modelId}/editions — body { edition, fileName, fileSize, fileHash }201uploadId, tusEndpoint
3. Create upload session (TUS)POST /api/v1/orgs/{orgId}/ai-models/{modelId}/editions/{edition}/uploads — headers Tus-Resumable: 1.0.0, Upload-Length: {fileSize}, Upload-Metadata: uploadId {base64(uploadId)}201 + Location header containing the upload resource URL
4. Upload binary (TUS PATCH)Send PATCH to the complete URL returned in the Location header — headers Tus-Resumable: 1.0.0, Upload-Offset: 0, Content-Type: application/offset+octet-stream, body = file bytes204; object stored, Upload-Offset equals fileSize
5. Check verification statusGET /api/v1/orgs/{orgId}/ai-models/{modelId}/editions/{edition}/uploads/{uploadId}/statusPending → Uploading → Verifying → Uploaded. WEDA Core re-hashes the file server-side; a mismatch sets VerifyFailed and deletes the object
備註

Upload-Metadata in step 3 carries the registered uploadId returned from step 2, base64-encoded. For subsequent HEAD and PATCH requests, use the complete upload resource URL from the Location header without parsing or reconstructing it. Continue to use the registered uploadId when polling the upload status. The edition is identified throughout by the edition string you chose in step 2 (e.g. 1.0.3), not by a numeric ID.

Poll step 5 until the status reaches Uploaded before deploying.

Resuming an Interrupted Upload

If the upload connection drops mid-transfer, query the current offset before resuming:

CallResult
Get current upload offsetHEAD to the same upload resource URL from the Location header — returns Upload-Offset and Upload-Length

Resume by sending the remaining bytes in a subsequent PATCH with Upload-Offset set to the value returned by HEAD.

Upload Requirements

  • Complete the upload within 12 hours after registering the edition.
  • The maximum file size is 50 GiB.
  • Provide fileHash as a 64-character lowercase SHA-256 hexadecimal string.
  • Supply fileName, fileSize, and fileHash together. Omitting all three creates an empty edition in Pending status without starting an upload.

Deploy Flow

StepCallResult
6. DeployPOST /api/v1/orgs/{orgId}/ai-models/{modelId}/editions/{edition}:deploy — body { targets[] }202{ modelDeploymentId, status: "IN_PROGRESS" }, each target at state: "SENT". The deployment is queued and delivered once the device is reachable
備註

The deploy verb lives under /ai-models/ — there is no separate /models/ route.

The Deploy Body — Apply Pipeline

Each target device carries a tasks[] entry describing a four-phase action pipeline: preCmdvalidateCmdapplyCmdpostCmd. Every hook is an { action, params } pair drawn from a closed enum — WEDA Core never sends arbitrary shell commands to the device.

The tasks array is optional. If you omit it, WEDA still downloads the verified file to the device's Secured Volume, but it does not run additional lifecycle actions against a container or service. Omitting an individual hook (e.g. no preCmd key) has the same effect as setting it to NOOP for that stage — the stage is skipped without failing.

Common configuration — verify the file's signature, then atomically swap it in and restart the container:

{
"targets": [
{
"deviceIdList": ["000c29e353e9"],
"tasks": [
{
"preCmd": { "action": "CHECK_DISK_USAGE", "params": { "maxUsagePercent": "95" } },
"validateCmd": { "action": "SIGNATURE_VERIFY", "params": { "publicKeyHex": "...", "signatureHex": "..." } },
"applyCmd": { "action": "ATOMIC_SWAP_AND_RESTART_CONTAINER", "params": { "containerName": "container1" } },
"postCmd": { "action": "HEALTH_CHECK_FILE_EXISTS", "params": {} }
}
]
}
]
}
HookRecommended actionWhy
validateCmdSIGNATURE_VERIFYConfirms the file's authenticity before it's swapped in — see Verifying File Signatures below
applyCmdATOMIC_SWAP_AND_RESTART_CONTAINERSwaps the file into place and restarts the target container so it picks up the new version
important

When you use an action that operates on a container, such as ATOMIC_SWAP_AND_RESTART_CONTAINER, applyCmd.params.containerName must match a container that is already running on the device. The action does not create or mount the container. The container must already have the Secured Volume mounted; see Make Your Container Read the Model.

An unrecognized action is rejected with ERR_UNKNOWN_ACTION.

All available actions and parameters

Each hook operates at a different point in the file's lifecycle — validateCmd runs against the working path (downloaded, not yet moved into place); applyCmd and postCmd run against the final path (after the atomic move). Using an action at the wrong stage fails because the path it expects doesn't exist yet.

ActionStageParams (✅ required)Behavior
BACKUP_CURRENTpreCmdsourcePath ✅, backupSuffix (default .bak)Copies a backup; succeeds as a no-op if the source doesn't exist
STOP_CONTAINERpreCmdcontainerNameRuns docker stop; the name is checked against a character allowlist
CLEAN_STAGINGpreCmdstagingDir ✅ (.. not allowed)Recursively deletes the staging directory
CHECK_DISK_USAGEpreCmdmaxUsagePercent ✅ (0 < x ≤ 100)Fails if root filesystem usage exceeds the threshold
FILE_SIZE_VERIFYvalidateCmdnoneCompares against the edition's fileSize metadata; without it, just checks the file is non-empty
CHECKSUM_VERIFYvalidateCmdexpectedChecksum ✅ (hex), algorithm (sha256 default or sha512)Streaming hash comparison
SIGNATURE_VERIFYvalidateCmdpublicKeyHex/publicKeyPath ✅, signatureHex/signaturePathEd25519 signature verification — see Verifying File Signatures
ATOMIC_SWAPapplyCmdnoneConfirms the file landed at its final path
ATOMIC_SWAP_AND_RESTART_CONTAINERapplyCmdcontainerNameConfirms the swap, then docker restart. A restart failure is non-fatal — the file is already deployed; a warning is logged and nothing is rolled back
RENAME_AND_RELOAD_SERVICEapplyCmdserviceNamesystemctl reload (the host needs the service and permission to reload it)
HEALTH_CHECK_FILE_EXISTSpostCmdnoneConfirms the file exists
HEALTH_CHECK_HTTPpostCmdurl ✅, timeoutSeconds (default 10)Expects a 2xx response
HEALTH_CHECK_TCPpostCmdhost + port ✅, timeoutSeconds (default 5)TCP connection test
HEALTH_CHECK_PROCESSpostCmdprocessNameChecks the process exists (exact name match)

Verifying File Signatures

WEDA Core does not generate, store, or manage model signatures — signing is entirely bring your own (BYO). Supply the public key and signature in the deploy request's validateCmd.params (publicKeyHex/signatureHex, or the *Path variants pointing to files already on the device); WEDA passes them through to the device unchanged.

Verification is a pure Ed25519 check over the file's SHA-512 digest:

d := sha512.Sum512(fileBytes)      // device computes SHA-512 of the downloaded file
sig := ed25519.Sign(priv, d[:]) // pure Ed25519 signature over the digest
// params: publicKeyHex = hex(pub), signatureHex = hex(sig)

publicKeyHex is 32 bytes and signatureHex is 64 bytes, both hex-encoded.

備註

Key management — who holds the signing private key, whether a signature is tracked alongside an edition, and how the public key reaches the device — is not yet a formalized WEDA feature. Today, your own deployment pipeline is responsible for generating the signature and supplying it with each deploy request.

Check Deployment Result

Two read endpoints confirm a deployment — query by device, or by model edition. Both return a paged envelope.

OperationCallDescription
By deviceGET /api/v1/devices/{deviceId}/ai-models?maxResultCount=10&skipCount=0Per-device deployment records; each walks to the terminal state: DEPLOYED
By model editionGET /api/v1/orgs/{orgId}/ai-models/{modelId}/editions/{edition}/deployments?maxResultCount=10&skipCount=0One item per target device, with deviceId, state, edgeFilePath, deploymentStartTime, lastTransitionTime
{
"items": [
{
"modelDeploymentId": "d642d71e-0cbd-40db-a649-99cdb68def2d",
"modelName": "defect-detector",
"edition": "1.0.3",
"deviceId": "000c29e353e9",
"edgeFilePath": "/ai-models/defect-detector/1.0.3/model.bin",
"state": "DEPLOYED"
}
],
"skipCount": 0,
"maxResultCount": 10,
"totalCount": 1,
"totalPages": 1
}

What Happens on the Device

Once the deployment instruction reaches the device, the on-device agent (dmagent) takes over automatically:

  1. Signal receiveddmagent picks up the pending deployment
  2. Download — pulls the file via the File Transfer Service, verifying CRC32 per chunk
  3. Verify & store — checks the whole-file SHA-256 and moves it into the encrypted secured volume
  4. Apply pipeline — runs the preCmd → validateCmd → applyCmd → postCmd sequence against the target container

Internally, a deployment walks a finer edge-side stage sequence before reaching DEPLOYED:

SENT → SERVERFILEPATH_OBTAINED → EDGERECEIVED → MODEL_STORAGE_CHECKED
→ CAPACITY_CHECKED → DOWNLOADED → VALIDATED → DEPLOYED

A REJECTED status carries a rejection reason identifying which stage failed.

Deployment Statuses

The deployment-level status summarizes the result across all target devices:

StatusMeaning
IN_PROGRESSAt least one target device is still processing the deployment.
COMPLETEDEvery target device reached DEPLOYED.
PARTIAL_FAILEDSome target devices reached DEPLOYED, while others were rejected.
FAILEDAll target devices were rejected.

Each target device reports its own state:

StateMeaning
SENTWEDA Core accepted and dispatched the deployment request.
SERVERFILEPATH_OBTAINEDThe device resolved the source file location.
EDGERECEIVEDThe device received the deployment instruction.
MODEL_STORAGE_CHECKEDThe device verified that model storage is available.
CAPACITY_CHECKEDThe device confirmed that sufficient storage capacity is available.
DOWNLOADEDThe device downloaded the model file.
VALIDATEDThe downloaded file passed the configured validation.
DEPLOYEDThe model file was placed in its active location successfully.
REJECTEDThe device rejected the deployment. Inspect the rejection reason for details.
DELETEDThe deployed file was removed from the device.

Device Offline Behavior

Issuing a deployment never checks whether the target device is online — a request to an offline device is accepted the same as any other. The deployment is queued and will apply automatically when the device reconnects. While the device is unreachable, its state remains SENT.

Deployments do not time out while a device is offline — they remain pending indefinitely until the device reconnects.

Constraints

  • After an edition's file passes upload verification, its file content cannot be replaced. Descriptive metadata can still be updated. Re-registering the same (modelName, edition) pair with another file returns 409 Conflict.
  • An edition with VerifyFailed status cannot be deployed
  • You can deploy only to devices that belong to an organization you are authorized to manage. The deployment ACL fields allowedContainers and allowedSubnets separately control access to the deployed file on the device.
  • A deployment reaches DEPLOYED once the device is reachable and applies it; while offline, it remains queued indefinitely — see Device Offline Behavior

Teardown

StepCallResult
Remove from deviceDELETE /api/v1/devices/{deviceId}/ai-models/{modelId}/editions/{edition}202 — the removal is queued and applied once the device is reachable
Remove from all deployed devicesDELETE /api/v1/orgs/{orgId}/ai-models/{modelId}/editions/{edition}/deployments202 — requests removal from every device that received the edition
Delete the modelDELETE /api/v1/orgs/{orgId}/ai-models/{modelId}Hard delete — permanently removes the model, all its editions, uploads, and stored files from WEDA Core

Removing an edition from devices and deleting the cloud model are independent operations — neither requires the other, and there is no ordering constraint between them:

  • You do not need to remove an edition from its devices before deleting the model from WEDA Core
  • A device's online/offline status has no effect on whether the cloud model can be deleted
  • Deleting the cloud model does not touch files already deployed to a device's Secured Volume — those remain in place until separately removed via Remove from device
  • Because deletion is a hard delete, a (modelName, edition) pair can be reused immediately after the original model is deleted — the name is not reserved by a soft-deleted record

Last updated on Jul-17, 2026 | Version 1.1.0