Skip to content

ADU CLI Primer

Paymaun edited this page Aug 30, 2022 · 13 revisions

✨ Azure Device Update Command Line Interface (ADU CLI) ✨ - Preview

digimaun@host:~$ az iot device-update --help

Group
    az iot device-update : Device Update for IoT Hub is a service that enables you to deploy over-
    the-air updates (OTA) for your IoT devices.
        As organizations look to further enable productivity and operational efficiency, Internet of
        Things (IoT) solutions continue to be adopted at increasing rates. This makes it essential
        that the devices forming these solutions are built on a foundation of reliability and
        security and are easy to connect and manage at scale. Device Update for IoT Hub is an end-
        to-end platform that customers can use to publish, distribute, and manage over-the-air
        updates for everything from tiny sensors to gateway-level devices.
        To learn more about the Device Update for IoT Hub service visit
        https://docs.microsoft.com/en-us/azure/iot-hub-device-update/.
        This command group is in preview and under development. Reference and support levels:
        https://aka.ms/CLI_refstatus

Subgroups:
    account  : Device Update account management.
    device   : Device Update device management.
    instance : Device Update instance management.
    update   : Device Update update management.

To search AI knowledge base for examples, use: az find "az iot device-update"

Please let us know how we are doing: https://aka.ms/azureclihats

👉 The ADU CLI is intended & designed to be a complete Device Update experience. Anything the service supports that a user wants to do should be possible through the CLI.

Phase roadmap


  1. Full control plane support. [Available in azure-iot v0.16.0+]

  2. Full data plane support. [Available in azure-iot v0.17.0+]

  3. Import update manifest utilities [Generation, Stage].


Installation

Please start by reading the instructions written here. Remember that --help and --debug are your friends.

Download the latest in-work preview package encompassing both data-plane and control-plane. You can now install the latest azure-iot extension to enable the ADU command groups.

Bug bash package KPIs (may include 1 or more entries).

filename: azure_iot-255.200.3-py3-none-any.whl
extension: azure-iot
version: 255.200.3
SHA256: 20D35FAE583D869453F51CB0DC0F8BB6FB5821CD166BB3955ED43672AE26D4DF
MD5: 90BC61887CDEA858DDD51EB9AF89F28E

You can install directly from the above backing link URL or download the .whl package locally.

  • Ensure you have Azure CLI 2.30.0 or greater installed. Use az --version to check.
  • See existing Az CLI extension installations with az extension list
  • Remove any existing azure-iot installations if they exist via az extension remove --name azure-iot
  • Install the in-work preview package provided by these instructions via az extension add --source <URL or local file path to .whl> -y
  • After the install use az extension list again to verify the extension name & version.

Command Guide

🤖 If you have not already logged in, do so now by running az login. If you are using cloudshell make sure to run az login again to avoid a known issue.

🤖 Ensure your desired subscription is activated as default by running az account set --subscription '<name or Id of sub>'

🤖 The provided commands are meant as a starting point to get you going faster. In many cases commands include various options, switches and modes to support advanced usage scenarios.

🌟 We will now step through key scenarios of ADU and how to exercise them via CLI. The examples shown will have sample values rather than placeholders which are often seen in the --help docs.

Account Creation

[Optional] Create a resource group for the account (or use an existing one)

az group create --location westus2 --name MyDeviceUpdateRG

Minimum inputs, using the RG location for account location

az iot device-update account create -n test-adu-35d878a5c16248 -g MyDeviceUpdateRG

Specify a location

az iot device-update account create -n test-adu-35d878a5c16248 -g MyDeviceUpdateRG -l eastus2euap

Once your account is created you can view its properties at anytime

az iot device-update account show -n test-adu-35d878a5c16248

Instance Creation

[Optional] Provision a new IoT Hub (or use an existing one)

az iot hub create --name MyDeviceUpdateIoTHub -g MyDeviceUpdateRG

[Optional] Provision a new storage account for diagnostics (or use an existing one)

az storage account create -n deviceupdatestorage -g MyDeviceUpdateRG`

Create an instance on the account. The IoT Hub can exist in any subscription, just provide an explicit --subscription for the respective show command if your target hub is in a different subscription compared to the default activated one.

az iot device-update instance create -n test-adu-35d878a5c16248 -i myinstance1 --iothub-ids $(az iot hub show -n MyDeviceUpdateIoTHub --subscription 1c9af29c-c73a-44a9-bbc4-2aafc5c3f1e1 --query id -o tsv)

Create an instance with diagnostics enabled. The storage account can exist in any subscription, just provide an explicit --subscription for the respective show command if your target storage account is in a different subscription compared to the default activated one.

az iot device-update instance create -n test-adu-35d878a5c16248 -i myinstance1 --iothub-ids $(az iot hub show -n MyDeviceUpdateIoTHub --subscription 1c9af29c-c73a-44a9-bbc4-2aafc5c3f1e1 --query id -o tsv) --enable-diagnostics --diagnostic-storage-id $(az storage account show -n deviceupdatestorage -o tsv --query id)

Once your instance is created you can view its properties at anytime

az iot device-update instance show -n test-adu-35d878a5c16248 -i myinstance1

The rest of this document will focus on data-plane, but you can checkout the ADU infra/control-plane reference docs at anytime here.

❗ Role assignment for data plane access

Assigning a privileged role to the target principal needing data-plane access is a requirement.

az role assignment create --role 'Device Update Administrator' --assignee '[email protected]' --scope $(az iot device-update account show -n test-adu-35d878a5c16248 -o tsv --query id)

It will take some time for the role assignment to propagate. Usually less than a couple minutes but it can take longer. You can try running az login again to force a refresh of your auth token.

Importing and managing updates

Preparing an update

Before importing via ADU CLI, the update artifacts need to be staged in a storage container.

  • Create the storage container

    az storage container create --name myupdatecontainer --account-name deviceupdatestorage --only-show-errors
    
  • Upload update artifacts (manifest and related files). Run this step 1 or more times.

    az storage blob upload -f 'local/path/to/update/artifact' -c myupdatecontainer --name artifact_blobname --account-name deviceupdatestorage --only-show-errors
    
  • Generate SAS URI for blob artifacts. Run this step 1 or more times.

    az storage blob generate-sas -c myupdatecontainer --name artifact_blobname --account-name deviceupdatestorage --permissions r --expiry 2022-07-24T00:00:00Z --https-only --full-uri -o tsv --only-show-errors
    

    It is highly recommended that the output SAS URI's from the above command get assigned as shell or environment variables. This allows easier escaping and re-use.

    Powershell example

    $UPDATE_MANIFEST_SAS_URI=$(az storage blob generate-sas -c myupdatecontainer --name artifact_blobname --account-name deviceupdatestorage --permissions r --expiry 2022-07-24T00:00:00Z --https-only --full-uri -o tsv --only-show-errors)
    

    Bash example

    UPDATE_MANIFEST_SAS_URI=$(az storage blob generate-sas -c myupdatecontainer --name artifact_blobname --account-name deviceupdatestorage --permissions r --expiry 2022-07-24T00:00:00Z --https-only --full-uri -o tsv --only-show-errors)
    

Simple update

For an update with no reference steps like this sample v5 schema one, the az iot device-update update import command supports importing on a single execution.

{
  "updateId": {
    "provider": "digimaun",
    "name": "adutest",
    "version": "1.0.0.0"
  },
  "compatibility": [{
    "deviceManufacturer": "Contoso",
    "deviceModel": "Vacuum"
  }],
  "instructions": {
    "steps": [{
      "type": "inline",
      "handler": "microsoft/swupdate:1",
      "files": [
        "file1.dat"
      ]
    }]
  },
  "files": [{
    "filename": "file1.dat",
    "sizeInBytes": 11,
    "hashes": {
      "sha256": "TkeCZpi7RjD7RFEBAGL62/hdYUJ8vfrtetDyPyOb7Yk="
    },
    "mimeType": "application/octet-stream",
    "relatedFiles": [{
      "filename": "file2.dat",
      "sizeInBytes": 8,
      "hashes": {
        "sha256": "HLeyIbet2hz0xHJLMjaTlFgEgMhKuDV5XWCKxZqhMAI="
      },
      "properties": {
        "microsoft.sourceFileHashAlgorithm": "sha256",
        "microsoft.sourceFileHash": "YmFYwnEUddq2nZsBAn5v7gCRKdHx+TUntMz5tLwU+24="
      }
    }],
    "downloadHandler": {
      "id": "microsoft/delta:1"
    }
  }],
  "createdDateTime": "2022-04-22T00:02:41.2100526Z",
  "manifestVersion": "5.0"
}

Here is an example on importing the above update after preparation steps. These samples assume the SAS URI environment variable guidance was followed. Note --file can be used 1 or more times.

Powershell

az iot device-update update import -n test-adu-35d878a5c16248 -i myinstance1 --friendly-name digicontosovac --url "`"$UPDATE_MANIFEST_SAS_URI`"" --file filename=file1.dat url="`"$FILE1DAT_SAS_URI`"" --file filename=file2.dat url="`"$FILE2DAT_SAS_URI`""

Bash

az iot device-update update import -n test-adu-35d878a5c16248 -i myinstance1 --friendly-name digicontosovac --url "$UPDATE_MANIFEST_SAS_URI" --file filename=file1.dat url="$FILE1DAT_SAS_URI" --file filename=file2.dat url="$FILE2DAT_SAS_URI"

Update with reference steps

For an update with reference steps like the following sample, the az iot device-update update import command supports deferred import until next execution via --defer. Using --defer will cache the import request payload that would have gone to Azure then exit. The next usage of the update import command without --defer will combine all prior cached payloads with the current one before sending to Azure. You are able to view & purge cache content via az cache commands.

parent.importmanifest.json

{
  "updateId": {
    "provider": "Microsoft",
    "name": "Surface",
    "version": "1.5"
  },
  "isDeployable": true,
  "compatibility": [
    {
      "deviceModel": "Surface",
      "deviceManufacturer": "Microsoft"
    }
  ],
  "instructions": {
    "steps": [
      {
        "type": "inline",
        "description": "Pre-install script",
        "handler": "microsoft/script:1",
        "files": [ "create-adu-import-manifest.sh" ],
        "handlerProperties": { "arguments": "--pre" }
      },
      {
        "type": "reference",
        "description": "Microphone Firmware",
        "updateId": {
          "provider": "Microsoft",
          "name": "Microphone",
          "version": "1.3"
        }
      },
      {
        "type": "reference",
        "description": "Speaker Firmware",
        "updateId": {
          "provider": "Microsoft",
          "name": "Speaker",
          "version": "1.3"
        }
      },
      {
        "type": "inline",
        "description": "Post-install script",
        "handler": "microsoft/script:1",
        "files": [ "create-adu-import-manifest.sh" ],
        "handlerProperties": { "arguments": "--post" }
      }
    ]
  },
  "files": [
    {
      "filename": "create-adu-import-manifest.sh",
      "sizeInBytes": 7,
      "hashes": { "sha256": "5S8yHqFy+9gFvedPP7o5CnMOmOUTxcN6PEBeR4CmbRo=" }
    }
  ],
  "createdDateTime": "2021-11-10T01:30:04.8978755Z",
  "manifestVersion": "4.0"
}

leaf1.importmanifest.json

{
  "updateId": {
    "provider": "Microsoft",
    "name": "Microphone",
    "version": "1.3"
  },
  "isDeployable": false,
  "compatibility": [
    {
      "deviceModel": "Microphone",
      "deviceManufacturer": "Microsoft"
    }
  ],
  "instructions": {
    "steps": [
      {
        "type": "inline",
        "handler": "microsoft/swupdate:1",
        "files": [ "README.md" ]
      }
    ]
  },
  "files": [
    {
      "filename": "README.md",
      "sizeInBytes": 6,
      "hashes": { "sha256": "YX6mQiDPV6sXCpihV/5uTxAMinOR/gBwf8m0XTolmJg=" }
    }
  ],
  "createdDateTime": "2021-11-10T01:30:04.8795262Z",
  "manifestVersion": "4.0"
}

leaf2.importmanifest.json

{
  "updateId": {
    "provider": "Microsoft",
    "name": "Speaker",
    "version": "1.3"
  },
  "isDeployable": false,
  "compatibility": [
    {
      "deviceModel": "Speaker",
      "deviceManufacturer": "Microsoft"
    }
  ],
  "instructions": {
    "steps": [
      {
        "type": "inline",
        "handler": "microsoft/swupdate:1",
        "files": [ "README.md" ]
      }
    ]
  },
  "files": [
    {
      "filename": "README.md",
      "sizeInBytes": 6,
      "hashes": { "sha256": "YX6mQiDPV6sXCpihV/5uTxAMinOR/gBwf8m0XTolmJg=" }
    }
  ],
  "createdDateTime": "2021-11-10T01:30:04.8847323Z",
  "manifestVersion": "4.0"
}

Here is an example on importing the above update after preparation steps. These samples assume the SAS URI environment variable guidance was followed. Note usage of --defer does not depend on any order or relationship between update nodes.

Powershell

  • Defer import for one update node and store the request payload in local cache

    az iot device-update update import -n test-adu-35d878a5c16248 -i myinstance1 --friendly-name surface_parent --url "`"$surface15_root`"" --file 
    filename=create-adu-import-manifest.sh url="`"$script_file`"" --defer
    
  • Defer import for another update node and store the request payload in local cache

    az iot device-update update import -n test-adu-35d878a5c16248 -i myinstance1 --friendly-name surface_leaf1 --url "`"$surface15_leaf1`"" --file 
    filename=README.md url="`"$readme_file`"" --defer
    
  • Combine cached payloads and submit to Azure (as no --defer is provided)

    az iot device-update update import -n test-adu-35d878a5c16248 -i myinstance1 --friendly-name surface_leaf2 --url "`"$surface15_leaf2`"" --file 
    filename=README.md url="`"$readme_file`""
    

Remember you are able to view and purge local cache entities via az cache commands.

Viewing imported updates

You can see all your imported updates at a glance with az iot device-update update list and table output.

az iot device-update update list -n test-adu-35d878a5c16248 -i myinstance1 -o table

UpdateProvider    UpdateName    UpdateVersion    FriendlyName    IsDeployable    ManifestVersion    ImportedDateTime
----------------  ------------  ---------------  --------------  --------------  -----------------  --------------------------------
digimaun          adutest       2.0.0.0          test_update     True            5.0                2022-06-29T23:08:13.534344+00:00
digimaun          adutest       1.0.0.2          init_update     True            5.0                2022-06-29T02:19:51.396379+00:00

The az iot device-update update list has a lot of options. Use --help to see them all. Here are a few variations.

# List only update providers
az iot device-update update list test-adu-35d878a5c16248 -i myinstance1 --by-provider

# List with service side filter 
az iot device-update update list test-adu-35d878a5c16248 -i myinstance1 --filter "friendlyName eq 'init_1'"

# List with service side free search expression
az iot device-update update list test-adu-35d878a5c16248 -i myinstance1 --search "libcurl4-doc"

See details of a specific update

az iot device-update update show -n test-adu-35d878a5c16248 -i myinstance1 --update-provider digimaun --update-name adutest --update-version 1.0.0.2 

List files of a specific update

az iot device-update update file list -n test-adu-35d878a5c16248 -i myinstance1 --up digimaun --un adutest --uv 1.0.0.2

Show details of a file for a specific update

az iot device-update update file show -n test-adu-35d878a5c16248 -i myinstance1 --up digimaun --un adutest --uv 1.0.0.2 --ufid fc221eb1cea23218c 

Delete a specific update

az iot device-update update delete -n test-adu-35d878a5c16248 -i myinstance1 --update-provider digimaun --update-name adutest --update-version 1.0.0.2 

Importing and managing devices

To import ADU aware device and module identities from the linked IoT Hub instance run the following

az iot device-update device import -n test-adu-35d878a5c16248 -i myinstance1

After importing, you can list device identities (with an optional filter)

az iot device-update device list -n test-adu-35d878a5c16248 -i myinstance1

az iot device-update device list -n test-adu-35d878a5c16248 -i myinstance1 --filter "groupId eq 'MyGroup'"

To see the details of a device identity (where the identity is d0).

az iot device-update device show -n test-adu-35d878a5c16248 -i myinstance1 -d d0

To see at a glance compliance for the instance

az iot device-update device compliance show -n test-adu-35d878a5c16248 -i myinstance1

To list instance device health you can run the device health list command. This is a list operation where filter is required by design.

az iot device-update device health list -n test-adu-35d878a5c16248 -i myinstance1 --filter "state eq 'Healthy'"

Managing Device Groups and Classes

❗ Make sure you import ADU-enabled devices before exercising this section.

Device Groups

List all instance device groups (with optional --order-by)

az iot device-update device group list -n test-adu-35d878a5c16248 -i myinstance1

az iot device-update device group list -n test-adu-35d878a5c16248 -i myinstance1 --order-by deviceCount

Show details of a target device group. This command supports multiple flags to modify the operation and see different views of a group. The flags include --update-compliance and --best-updates.

az iot device-update device group show -n test-adu-35d878a5c16248 -i myinstance1 --group-id MyGroup

az iot device-update device group show -n test-adu-35d878a5c16248 -i myinstance1 --group-id MyGroup --update-compliance

az iot device-update device group show -n test-adu-35d878a5c16248 -i myinstance1 --group-id MyGroup --best-updates

Delete a group via

az iot device-update device group delete -n test-adu-35d878a5c16248 -i myinstance1 --group-id MyGroup

The delete group operation can be used if there is no need for the group or need to retain history for it. If a device is ever connected again for a group after the group was deleted it will be automatically re-created with no history.

Device Classes

The ADU CLI simplifies concepts by combining device class and device class subgroup management into a single command group az iot device-update device class. When a command exposes an optional --group-id parameter, not providing it means the operation is against an instance device class. If --group-id/--gid is provided the command operates on the device class subgroup.

List device classes. If listing by --group-id an optional compatProperties --filter can be provided.

# List instance classes
az iot device-update device class list -n test-adu-35d878a5c16248 -i myinstance1

# List group classes aka device class subgroup
az iot device-update device class list -n test-adu-35d878a5c16248 -i myinstance1 --gid MyGroup

# List group classes with compatProperties filter
az iot device-update device class list -n test-adu-35d878a5c16248 -i myinstance1 --gid MyGroup --filter "compatProperties/manufacturer eq 'Contoso'"

Show the details of a device class or device class subgroup. This command supports multiple flags to modify the operation and see different views of a class. When used in conjunction with --group-id the flags --update-compliance and --best-update can be used.

az iot device-update device class show -n test-adu-35d878a5c16248 -i myinstance1 --class-id cdad9d100395aba0a920525b4fe6ac24c6c7ad44

az iot device-update device class show -n test-adu-35d878a5c16248 -i myinstance1 --class-id cdad9d100395aba0a920525b4fe6ac24c6c7ad44 --installable-updates

az iot device-update device class show -n test-adu-35d878a5c16248 -i myinstance1 --class-id cdad9d100395aba0a920525b4fe6ac24c6c7ad44 --gid MyGroup --best-update

az iot device-update device class show -n test-adu-35d878a5c16248 -i myinstance1 --class-id cdad9d100395aba0a920525b4fe6ac24c6c7ad44 --gid MyGroup --update-compliance

You can patch update a device class, where currently only --friendly-name is supported.

az iot device-update device class update -n test-adu-35d878a5c16248 -i myinstance1 --class-id cdad9d100395aba0a920525b4fe6ac24c6c7ad44 --friendly-name "EU-region"

Delete a device class or device class subgroup via

az iot device-update device class delete -n test-adu-35d878a5c16248 -i myinstance1 --class-id cdad9d100395aba0a920525b4fe6ac24c6c7ad44

az iot device-update device class delete -n test-adu-35d878a5c16248 -i myinstance1 --class-id cdad9d100395aba0a920525b4fe6ac24c6c7ad44 --group-id MyGroup

If all device class subgroups for a target device class are deleted then the device class itself can also be deleted to remove the records from the system and to stop checking the compatibility of the device class with new updates. If a device is ever reconnected its device class will be re-created if it does not exist.

Diagnostic Logs

❗ This section of operations requires imported devices/modules and diagnostic storage enabled at the account level.

Create a diagnostic log collection with the following command. Note --agent-id can be used 1 or more times where it expects input in the form of key=value pairs where deviceId is a required key and moduleId is optional.

az iot device-update device log collect -n test-adu-35d878a5c16248 -i myinstance1 --lcid mycollection --agent-id deviceId=d0 --description "Test collection"

List existing log collections via

az iot device-update device log list -n test-adu-35d878a5c16248 -i myinstance1

Show a basic or detailed view of an existing log collection

az iot device-update device log show -n test-adu-35d878a5c16248 -i myinstance1 --lcid mycollection

az iot device-update device log show -n test-adu-35d878a5c16248 -i myinstance1 --lcid mycollection --detailed

Managing deployments

❗ This section of operations requires imported devices and compatible updates.

Basic deployment creation

az iot device-update device deployment create -n test-adu-35d878a5c16248 -i myinstance1 --group-id MyGroup --deployment-id mydeployment1002 --update-provider digimaun --update-name adutest --update-version 1.0.0.2`

Create deployment with a cloud-initiated rollback policy. Requires an update to rollback to.

az iot device-update device deployment create -n test-adu-35d878a5c16248 -i myinstance1 --group-id MyGroup --deployment-id mydeployment1002 --update-provider digimaun --update-name adutest --update-version 1.0.0.2 --failed-count 10 --failed-percentage 20 --rollback-update-provider digimaun --rollback-update-name adutest --rollback-update-version 1.0.0.0`

List instance deployments by device group or class subgroup

az iot device-update device deployment list -n test-adu-35d878a5c16248 -i myinstance1 --group-id MyGroup

az iot device-update device deployment list -n test-adu-35d878a5c16248 -i myinstance1 --group-id MyGroup --class-id cdad9d100395aba0a920525b4fe6ac24c6c7ad44

Show the details of a deployment by device group or class subgroup including status which details a breakdown of how many devices in the deployment are in progress, completed, or failed.

# By group

az iot device-update device deployment show -n test-adu-35d878a5c16248 -i myinstance1 --gid MyGroup --deployment-id mydeployment1002

az iot device-update device deployment show -n test-adu-35d878a5c16248 -i myinstance1 --gid MyGroup --deployment-id mydeployment1002 --status

# By class subgroup

az iot device-update device deployment show -n test-adu-35d878a5c16248 -i myinstance1 --gid MyGroup --cid cdad9d100395aba0a920525b4fe6ac24c6c7ad44 --deployment-id mydeployment1002

az iot device-update device deployment show -n test-adu-35d878a5c16248 -i myinstance1 --gid MyGroup --cid cdad9d100395aba0a920525b4fe6ac24c6c7ad44 --deployment-id mydeployment1002 --status

List devices in a device class subgroup deployment along with their state. Useful for getting a list of failed devices. This command supports an optional filter.

az iot device-update device deployment list-devices -n test-adu-35d878a5c16248 -i myinstance1 --gid MyGroup --class-id cdad9d100395aba0a920525b4fe6ac24c6c7ad44 --deployment-id mydeployment1002

# With filter

az iot device-update device deployment list-devices -n test-adu-35d878a5c16248 -i myinstance1 --gid MyGroup --class-id cdad9d100395aba0a920525b4fe6ac24c6c7ad44 --deployment-id mydeployment1002 --filter "deviceId eq 'd0' and deviceState eq 'InProgress'"

Retry a device class subgroup deployment

az iot device-update device deployment retry -n test-adu-35d878a5c16248 -i myinstance1 --gid MyGroup --deployment-id mydeployment1002 --cid cdad9d100395aba0a920525b4fe6ac24c6c7ad44

Cancel a device class subgroup deployment

az iot device-update device deployment cancel -n test-adu-35d878a5c16248 -i myinstance1 --gid MyGroup --deployment-id mydeployment1002 --cid cdad9d100395aba0a920525b4fe6ac24c6c7ad44

Delete a deployment by device group or class subgroup

az iot device-update device deployment delete -n test-adu-35d878a5c16248 -i myinstance1 --gid MyGroup --deployment-id mydeployment1002

az iot device-update device deployment delete -n test-adu-35d878a5c16248 -i myinstance1 --gid MyGroup --deployment-id mydeployment1002 --cid cdad9d100395aba0a920525b4fe6ac24c6c7ad44

Known Issues

Using data-plane commands on cloudshell without running az login again will net an MSI provider 400 error. This is because cloudshell needs to explicitly allow the ADU JWT audience Id.