JSON List cannot contain an object

mender-artifact will not allow JSON object within a list in the meta-data

I’m creating a custom update module. But ran into the restriction where the meta data file has a restriction "List cannot contain a JSON object.

The specific error I get both from the mender-artifact tool as well as the mender server UI when I try to upload the artifact is “Metadata: Invalid metadata section: compose: List cannot contain JSON object or list”. The “compose” key is an array of objects. That’s why this error is generated I guess. But I’m wondering why this restriction exists i.e. if I update the code to not have have the restriction what issues might I face?

It seems to be coming from this line of code.

// Copies JSON structures, with the additional restriction that lists cannot
// contain any object or list.
func jsonDeepCopy(src interface{}) (interface{}, error)

Example use-cases:
Creating a custom update module. We need to start/stop/update multiple services so was using an array objects where each object describes a service that we are updating.

Specification

Specification
Module name < custom >
Supports rollback < no >
Requires reboot < no >
Artifact generation script < yes>
Full system updater < no >
Source code < link >

It appears this restrictions was not documented, so I added it here.

The reason that the limitations exist is to facilitate the use of Augmented Artifacts, and specifically being able to filter JSON fields in a predictable way. See “filtering header fields” in Augmented Artifacts for more information about it. It is still not implemented, but it is planned in future versions of Mender, so we have to keep the restrictions in place for now.

I have a couple of suggestions for you:

  • If the list of keys in your object is small, and the same in every object, then I suggest splitting it across several lists, for example:

    {
        "list": [
            {
                "property1": "hi",
                "property2": "hello"
            },
            {
                "property1": "red",
                "property2": "blue"
            }
        ]
    }
    

    instead becomes

    {
        "property1": [
            "hi",
            "red"
        ],
        "property2": [
            "hello",
            "blue"
        ]
    }
    
  • If your structure is too advanced for that, or it is simply inconvenient, then I suggest instead to

    1. Use the Artifact generator script to put the JSON structure as a payload file instead
    2. Optionally, implement the Download state in your Update Module to make sure this JSON file is the first file and is read first, so that it still kind of acts as a header. If you do this you will have to read the other payload files too, if any.

Very good suggestion to just use a payload file. In metadata can just mention the payload file and pick that up. Thanks!