Manage the OS package manager using Azure IoT and OSConfig

Important

Version 1.0.3 (published 28 June 2022) includes breaking changes to member names which may impact existing users. For more information, see: Member names transition from PascalCase to camelCase in version 1.0.3

Audience and scope

This article is designed to support people who provision or manage devices with Azure IoT. If that doesn't sound like you, consider taking a look at Audiences for OSConfig documentation.

This article is about getting package manager state and setting package manager desired state. For example:

Capability Use cases
Ensure package managers pull from your from your desired sources • Your operating policy is that device package managers should pull from a private package repository with approved versions of libraries and components
• You need devices to get packages from a specific vendor's repository
Inform package managers of desired packages • Your operating policy is that devices should have a specific package like "library-XYZ-v2"
• Your operating policy is that devices should have a specific dependency graph of packages
Compare devices' package
or sources lists
• Your operating policy is that deployed devices' installed package list should match a known good device

If you are here for reference information as opposed to interactive use case examples, you can skip ahead to the reference section.

Important

At this time, apt based distros including Debian and Ubuntu are in scope. If you would like to develop support for RPM based distros, see the extensibility documentation.

In an environment without apt (for example, building from source and running on a Red Hat family distro), you may see the following log messages indicating that the PackageManagerConfiguration module is not applicable.

  • In osconfig_pmc.log, lines including the following text:
    [ERROR] Cannot run on this platform, could not find required tool apt-get
  • In osconfig_pnp_agent.log, lines including the following text:
    [ERROR] PackageManagerConfiguration.state: MpiGet failed with 500

Use cases examples

These examples can serve as starting points for you to adapt for your unique environment.

Prerequisites to try the examples on live systems

If you are using this article for reference there are no pre-requisites. You can review the examples, copy property names, etc.

If you want to try the examples on live systems (recommended), follow these steps:

  1. Create a free Azure account or use an existing account

  2. Connect at least one OSConfig-enabled device to an IoT Hub

    Tip

    To easily create an IoT Hub with (virtual) devices attached, see Create an OSConfig (with Azure IoT) lab environment in 5 minutes

  3. Get ready to follow either the Azure portal instruction or the Azure CLI instructions in the examples:

If you prefer to use the Azure portal

  1. Sign in to your Azure portal and access your IoT Hub's Overview page Screenshot showing IoT Hub and devices from the Azure Portal

-OR- If you prefer to use Azure CLI

  1. RECOMMENDED: Use Azure Cloud Shell as your bash environment by signing in to your Azure Portal, then launching Azure Cloud Shell in bash mode Screen capture opening Cloud Shell from Azure Portal
  2. ALTERNATIVE: If you prefer to use your own bash environment rather than Cloud Shell, install the Azure CLI and sign-in
  3. Ensure the Azure IoT extension is ready by running az extension add --name azure-iot

Example 1. Specify desired package sources

This example demonstrates the Azure IoT workflow to ensure that devices use, as one of their package sources, the packages.microsoft.com prod channel for Ubuntu 18.04. You can adapt this example to use any package source. For example, a different distro/version's public repository, a particular vendor's repository, or a private repository that you curate.

The instructions are available in flavors for portal, CLI, specific device, and at-scale provisioning and management.

  1. From your IoT Hub's portal page, navigate to the OSConfig twin for the device you wish to manage, and add the following to the properties.desired section, followed by a comma to separate it from the next item in properties.desired.

    "PackageManagerConfiguration": {
       "desiredState": {
          "gpgKeys": {
             "pkgs-msft_key": "https://packages.microsoft.com/keys/microsoft.asc"
          },
          "sources": {
             "pkgs-msft_insiders-slow": "deb [arch=amd64,armhf,arm64 signed-by=pkgs-msft_key] https://packages.microsoft.com/ubuntu/18.04/prod insiders-slow main"
          },
          "packages": [
          ]
       }
    }
    
    

    Screen capture showing how to configure package manager configuration from Azure Portal

Example 1 was about defining a new package source. For reporting on the same, continue to Example 2.

Example 2. Report on package manager state and configuration

In this example we will report on:

  1. Which packages sources have been added
  2. Whether any devices are experiencing PackageManagerConfiguration errors

In Example 1 above, we added a desired PackageManagerConfiguration value to the OSConfig module twin of a specific device. We can now observe the results.

  1. Wait 1 minute (for network communications, device side activity, etc.) after having added the desired PackageManagerConfiguration in the example above

  2. In the same device's OSConfig module twin browse to properties, then reported, then PackageManagerConfiguration, then state.

  3. This will show the latest status of the package manager configuration.

    1. sourcesFileNames should reflect the two channels added
    2. executionStatus should be 2. For possible values, see: extensibility documentation

    Screen capture showing how to verify package manager configuration from Azure Portal

Reference information

Object model description

This section describes the twin properties and corresponding behaviors.

It is useful to understand that in Azure IoT there are two mental models or perspectives for describing twin contents.

  • Plain desired/reported perspective

    This is the core IoT Hub object model. It is used by IoT Hub Query service, IoT Hub Configurations service, az iot hub module-twin commands, and by the plain twin views in Azure Portal and IoT Explorer.

  • Digital Twin Definition Language (DTDL) enhanced perspective

    DTDL (with corresponding patterns including Azure IoT Plug and Play [PnP]) enables apps and services to anticipate, validate, and better contextualize twin content. This is used by the PnP views in IoT Explorer, by the Azure Digital Twins service, and potentially by your cloud solution when interacting with IoT Hub.

In most cases below, no distinction is needed. For example "gpgKeys" is called "gpgKeys" in either point-of-view.

In certain cases, a distinction may be helpful. For example the Path values given below. In those cases, the plain desired/reported description is given first, followed by a DTDL enhanced perspective in parenthesis.

desiredState (input from admin)
  • Path: properties.desired.PackageManagerConfiguration.desiredState (DTDL: PackageManagerConfiguration component --> desiredState writable property)

  • Description: Input from admin; enables addition of package sources and packages to devices

  • Members

    Name Type Notes
    sources map of sourceName: sourceDescriptor pairs (strings) For each pair in the dictionary:
    sourceName is an admin specified identifier, for example: *my-source-foo*
    sourceDescriptor is a source definition string in the format used by the package manager; for example: deb [arch=amd64,armhf,arm64 signed-by=my-repo-key] https://packages.microsoft.com/ubuntu/18.04/prod focal main
    • Inside sourceDescriptor the value passed to signed-by= should be the name of a key from gpgKeys (described below); for example: signed-by=my-source-foo-key
    • When adding or modifying a source, a file in sources.list.d will be populated (overwriting existing file if present) with the source descriptor
    • To specify that devices should not use a particular source (assuming it was previously defined in sources.list.d, not elsewhere on the system), include a pair like "my-source-bar": ""; If a file named my-source-bar.list exists in sources.list.d it will be removed
    • If you no longer need a should not use directive (for example, my-source-bar is no longer relevant after some time), you can remove it from the desired twin by changing the value from "my-source-bar": "" to "my-source-bar": null
    gpgKeys map of key-name: uri pairs (strings) Used to inform the package
    manager of repository public keys;
    For each pair in the dictionary:
    key-name is an admin specified identifier; for example: my-repo-foo-key, which is referred to from signed-by in sources
    uri is the location of a repo's public key; for example: https://packages.microsoft.com/keys/microsoft.asc
    • The key is added as a file to /usr/share/keyrings/; Note that to ensure the applicability of the key is scoped, this non-apt-specific path is used; apt will only apply that key to sources which are explicitly associated to it (via signed-by
    • To remove a key file from /usr/share/keyrings set key-name to match the file name (without extension), and set uri to ""
    packages array of package identifiers (strings) • Instructs package manager to ensure these packages are installed
    • Analogous to apt install <package names> on Debian
    • Additive (non-destructive) in nature; for example an empty list means "do nothing" (not "uninstall all packages on the system")
  • Example payload (as seen in twin's properties.desired section of an IoT Hub twin)

    "PackageManagerConfiguration": {
        "desiredState": {
           "gpgKeys": {
              "pkgs-msft_key": "https://packages.microsoft.com/keys/microsoft.asc"
           },
           "sources": {
              "pkgs-msft_insiders-slow": "deb [arch=amd64,armhf,arm64 signed-by=pkgs-msft_key] https://packages.microsoft.com/ubuntu/18.04/prod insiders-slow main"
           },
           "packages": [
              "cowsay"
           ]
        }
    }
    
state
  • Path: properties.reported.PackageManagerConfiguration.state (DTDL perspective: PackageManagerConfiguration component --> state read-only property)

  • Description: PackageManagerConfiguration state as reported by the device

  • Members

    Name Type Notes
    packagesFingerprint string • Opaque fingerprint for the list of all installed packages on the device (not limited to packages referenced in desiredState.packages)
    • Used for comparing large numbers of devices to a known-good device
    packages array of package identifiers (strings) • Name and status (version or "failed") of the admin-specified packages from desiredState.packages
    • If a package has been installed successfully, the name is followed by the installed version number
    • If a package could not be installed, the name is followed by "failed"
    sourcesFingerprint string • Opaque fingerprint of package sources used by the device
    • Used for comparing large numbers of devices to a known-good device
    sourcesFilenames array of file names (strings) • List of package sources (as file names, for example my-repo.list) which have been added to the package manager via /etc/apt/sources.list.d (on Debian)
    • Includes any sources present, regardless of whether they were added via desiredState.sources
    executionState int • Overall success/failure state
    • Nominal values are 0 (initial state, no desiredState has been specified) or 2 (succeeded)
    • For other values, see: extensibility documentation
    executionSubstate int • For possible values, see: extensibility documentation
    executionSubstateDetails string • Additional information for troubleshooting
  • Example payload (as seen in twin's properties.reported section)

    "PackageManagerConfiguration": {
        "state": {
           "packagesFingerprint": "9e7a85de3d067474e3621d7e1618f6ac0e2e8fc6cb9d60ee92af9927294114d3",
           "packages": [
              "cowsay=3.03+dfsg2-7"
           ],
           "executionState": 2,
           "executionSubstate": 0,
           "executionSubstateDetails": "",
           "sourcesFingerprint": "64b7de49c2be4ef2c180e4a978300fbb7b8a743a89e4038ba7ac6a91c31b625f",
           "sourcesFilenames": [
              "pkgs-msft_insiders-slow.list"
           ]
        }
    }
    
desiredState (reported; acknowledgement from device)
  • Path: properties.reported.PackageManagerConfiguration.desiredState (DTDL perspective: PackageManagerConfiguration component --> ACK portion of desiredState writeable property)

  • Description: This additional reported element is an acknowledgement from the device; for admin tools and reporting it supplements state-- enabling the admin toolchain to determine whether device has yet received the admin intent captured in the admin-writable/desired desiredState

  • Members

    Name Type Notes
    value object • Should mirror properties.desired.PackageManagerConfiguration.desiredState
    ac int • Indicates success (value 200) or failure (value 400) of the device receiving and processing desiredState from the admin

Next steps

For an overview of OSConfig scenarios and capabilities, see:

For specific practical examples, see: