Device Configuration Management using Cumulocity

Thin-edge provides an operation plugin to manage device configurations using Cumulocity.

  • This management is bi-directional:
    • A device can be taken as reference, all the managed files being uploaded to the cloud and stored there as a configuration snapshot.
    • A configuration snapshot can be pushed from the cloud to any devices of the same type, i.e. supporting the same kind of configuration files.
  • With this operation plugin, the device owner defines the list of files (usually configuration files, but not necessarily), that will be managed from the cloud tenant.
  • Notably, the plugin configuration itself is managed from the cloud, meaning, the device owner can update from the cloud the list of files to be managed.
  • Cumulocity manages the configuration files accordingly to their type, a name that is chosen by the device owner to categorise each configuration. By default, the full path of a configuration file on the device is used as its type.
  • When files are downloaded from the cloud to the device, these files are stored in a temporary directory first. They are atomically moved to their target path, only after a fully successful download. The aim is to avoid breaking the system with half downloaded files.
  • When a downloaded file is copied to its target, the unix user, group and mod are preserved.
  • Once a snapshot has been downloaded from Cumulocity to the device, the plugin publishes a notification message on the local thin-edge MQTT bus. The device software has to subscribe to these messages if any action is required, say to check the content of file, to preprocess it or to restart a daemon.
  • In other words, the responsibilities of the plugin are:
    • to define the list of files under configuration management
    • to notify the cloud when this list is updated,
    • to upload these files to the cloud on demand,
    • to download the files pushed from the cloud,
    • to make sure that the target files are updated atomically after successful download,
    • to notify the device software when the configuration is updated.
  • By contrast, the plugin is not responsible for:
    • checking the uploaded files are well-formed,
    • restarting the configured processes.
  • A user-specific component, installed on the device, can implement more sophisticated configuration use-cases by:
    • listening for configuration updates on the local thin-edge MQTT bus,
    • restarting the appropriate processes when appropriate,
    • declaring intermediate files as the managed files, to have the opportunity to check or update their content before moving them to the actual targets.


Assuming the configuration plugin c8y_configuration_plugin has been installed in /usr/bin/c8y_configuration_plugin, two files must be added under /etc/tedge/operations/c8y/ to declare that this plugin supports two Cumulocity operations: uploading and downloading configuration files (which respective SmartRest2 codes are 526 and 524).

These two files can be created using the c8y_configuration_plugin --init option:

$ sudo c8y_configuration_plugin --init

$ ls -l /etc/tedge/operations/c8y/c8y_UploadConfigFile
-rw-r--r-- 1 tedge tedge 95 Mar 22 14:24 /etc/tedge/operations/c8y/c8y_UploadConfigFile
$ ls -l /etc/tedge/operations/c8y/c8y_DownloadConfigFile
-rw-r--r-- 1 tedge tedge 97 Mar 22 14:24 /etc/tedge/operations/c8y/c8y_DownloadConfigFile

The c8y_configuration_plugin has to be run as a daemon on the device, the latter being connected to Cumulocity.


The c8y_configuration_plugin configuration is stored by default under /etc/tedge/c8y/c8y-configuration-plugin.toml

This TOML file defines the list of files to be managed from the cloud tenant. Each configuration file is defined by a record with:

  • The full path to the file.
  • An optional configuration type. If not provided, the path is used as type.
  • Optional unix file ownership: user, group and octal mode.
    These are only used when a configuration file pushed from the cloud doesn't exist on the device. When a configuration file is already present on the device, this plugin never changes file ownership, ignoring these parameters.
$ cat /etc/tedge/c8y/c8y-configuration-plugin.toml
files = [
    { path = '/etc/tedge/tedge.toml', type = 'tedge.toml' },
    { path = '/etc/tedge/mosquitto-conf/c8y-bridge.conf' },
    { path = '/etc/tedge/mosquitto-conf/tedge-mosquitto.conf' },
    { path = '/etc/mosquitto/mosquitto.conf', type = 'mosquitto', user = 'mosquitto', group = 'mosquitto', mode = 0o644 }

Note that:

  • The file /etc/tedge/c8y/c8y-configuration-plugin.toml itself doesn't need to be listed. This is implied, so the list can always be configured from the cloud. The type for this self configuration file is c8y-configuration-plugin.
  • If the file /etc/tedge/c8y/c8y-configuration-plugin.toml is not found, empty, ill-formed or not-readable then only c8y-configuration-plugin.toml is managed from the cloud.
  • If the file /etc/tedge/c8y/c8y-configuration-plugin.toml is ill-formed or cannot be read then an error is logged, but the operation proceed as if the file were empty.

The behavior of the c8y_configuration_plugin is also controlled by the configuration of thin-edge:

  • tedge config get mqtt.bind_address: the address of the local MQTT bus.
  • tedge config get mqtt.port: the TCP port of the local MQTT bus.
  • tedge config get tmp.path: the directory where the files are updated before being copied atomically to their targets.


$ c8y_configuration_plugin --help
c8y_configuration_plugin 0.6.2
Thin-edge device configuration management for Cumulocity

    c8y_configuration_plugin [OPTIONS]

        --config-dir <CONFIG_DIR>      [default: /etc/tedge]
        --config-file <CONFIG_FILE>    [default: $CONFIG_DIR/c8y/c8y-configuration-plugin.toml]
        --debug                        Turn-on the debug log level
    -h, --help                         Print help information
    -i, --init                         Create supported operation files
    -V, --version                      Print version information

    On start, `c8y_configuration_plugin` notifies the cloud tenant of the managed configuration files,
    listed in the `CONFIG_FILE`, sending this list with a `119` on `c8y/s/us`.
    `c8y_configuration_plugin` subscribes then to `c8y/s/ds` listening for configuration operation
    requests (messages `524` and `526`).
    notifying the Cumulocity tenant of their progress (messages `501`, `502` and `503`).
    The thin-edge `CONFIG_DIR` is used to find where:
    * to store temporary files on download: `tedge config get tmp.path`,
    * to connect the MQTT bus: `tedge config get mqtt.port`.


The c8y_configuration_plugin reports progress and errors on its stderr.

  • All upload and download operation requests are logged, when received and when completed, with one line per file.
  • All changes to the list of managed file is logged, one line per change.
  • All errors are reported with the operation context (upload or download? which file?).


When a configuration file is successfully downloaded from the cloud, the c8y_configuration_plugin service notifies this update over MQTT.

  • The notification messages are published on the topic tedge/configuration_change/{type}, where {type} is the type of the configuration file that have been updated, for instance tedge/configuration_change/tedge.toml
  • Each message provides the path to the freshly updated file as in { "path": "/etc/tedge/tedge.toml" }.

Note that:

  • If no specific type has been assigned to a configuration file, then the path to this file is used as its type. Update notifications for that file are then published on the topic tedge/configuration_change/{path}, for instance tedge/configuration_change//etc/tedge/mosquitto-conf/c8y-bridge.conf.
  • Since the type of configuration file is used as an MQTT topic name, the characters # and + cannot be used in a type name. If such a character is used in a type name (or in the path of a configuration file without explicit type), then the whole plugin configuration /etc/tedge/c8y/c8y-configuration-plugin.toml is considered ill-formed.