Update device_type for Yocto rootfs-image

Problem

Previously, we were using the beaglebone-yocto machine type in our Yocto build for both BeagleBone Green and BeagleBoneGreen Gateway boards. At some point we were forced to override the machine type and instead create a separate machine configuration for each of these boards. This was done using the MACHINE_OVERRIDES configuration variable so now we have bbg-beaglebone-yocto and bbgg-beaglebone-yocto machine types.

We then build our images using bitbake

bitbake mc:bbg-beaglebone-yocto:core-image-base
bitbake mc:bbgg-beaglebone-yocto:core-image-base

Then artifacts are generated for each

mender-artifact write rootfs-image \
  --artifact-name bbg-os \
  --device-type bbg-beaglebone-yocto \
  --file tmp/deploy/images/bbg-beaglebone-yocto/out.ext4

mender-artifact write rootfs-image \
  --artifact-name bbgg-os \
  --device-type bbgg-beaglebone-yocto \
  --file tmp/deploy/images/bbgg-beaglebone-yocto/out.ext4

The problem is that our artifacts were previously generated with the device-type of beaglebone-yocto but we want to update our devices with their machine-specific artifact.

Expected Outcome

What we need is some way to generate these new artifacts such that we can deploy bbg-beaglebone-yocto to a device that currently has the device type of beaglebone-yocto. This deployment should also update the device’s Device Type in Mender to reflect the device type of the artifact.

We have attempted to solve this problem by adding beaglebone-yocto as an additional --device-type when generating our new artifacts (see command below). This allows us to install the new rootfs-image to our device however it does not actually update the device-type of the device in Mender.

mender-artifact write rootfs-image \
  --artifact-name bbgg-os \
  --device-type bbgg-beaglebone-yocto \
  --device-type beaglebone-yocto \
  --file tmp/deploy/images/bbgg-beaglebone-yocto/out.ext4

The MENDER_DEVICE_TYPE variable in our Yocto configuration is reporting the correct new value so that shouldn’t be the issue. (Found this using bitbake -e)

/var/lib/mender/device_type on the device itself is also still reporting beaglebone-yocto instead of the new device type.

Is there any way to solve this problem without having to manually update /var/lib/mender/device_type on the boards after deploying the new rootfs-image artifact?

Hi @BGSD,

this is in fact a use case that I had on my personal wish list for some time, so took the opportunity to dig into it :slight_smile:

The easiest and most robust way is using the script update module. This is present by default on the device if you are using the generic Mender client installation. To be certain, check the device inventory, item update_modules.

In a nutshell, this enables you to run a mostly arbitrary script upon installation. I used this as the script file named change_device_type:

#!/bin/sh

echo -n "device_type=fancy_new_rpi4" > /data/mender/device_type

and created an artifact like this:

mender-artifact write module-image \
--type script \
--device-type raspberrypi4 \
-n fancy-new-rpi4 \
-f change_device_type \
-o change_device_type2.mender

After deployment, the device changed its type in the dashboard from raspberrypi4 to fancy_new_rpi4 :tada:

Take with a pinch of salt and test properly for your use case, but should be a neat solution.

Greetz,
Josef

I had to use a slightly different approach to your solution to get this to work for my use case.

Since we currently have a rootfs-image deployed to our board with the device_type=beaglebone-yocto, I needed to generate two different artifacts to get this to work.

So first off I have a recipe in my Yocto build for Mender update modules. The recipe looks like this:

recipes-update-modules
└── update-modules
    ├── files
    │   └── update-module
    └── update-modules_0.1.bb

update-modules_0.1.bb

RDEPENDS_${PN}_append = " bash"

SRC_URI = "file://update-module"

S = "${WORKDIR}"

FILES_${PN} += "\
    ${datadir}/mender/modules/v3/update-module \
"

do_install() {
    install -d ${D}${datadir}/mender/modules/v3
    install -m 0755 update-module ${D}${datadir}/mender/modules/v3
}

files/update-module handles updating our application files and does not change anything else in our OS.

So then I tried adding a new update module like you described named update-device-type then updated the update-modules_0.1.bb file to include this new script in the SRC_URI, the FILES_${PN} and the do_install() sections.

I then generated an artifact using this new update module as follows:

mender-artifact write module-image \
    --type update-device-type \
    -n test_update_device_type \
    -t beaglebone-yocto \
    -f bbgg.ext4 \
    -o test_update_device_type.mender

However when I went to deploy this module-image artifact to my device, it failed to deploy due to the /usr/share/mender/modules/v3/update-module file not existing on the current image.

So to work around this issue, I had to take the following approach.

  1. Created three scripts in the recipes-update-modules recipe.
    • device-type-bbg-beaglebone-yocto
    • device-type-bbgg-beaglebone-yocto
    • device-type-beaglebone-yocto

    These scripts just echo their respective device_type into /data/mender/device_type.

  2. Changed permissions on each of the scripts to make them executable.
    chmod +x recipes-update-modules/update-modules/files/device-type*
    
  3. Added each of these scripts to the update-modules_0.1.bb file as described previously.
    RDEPENDS_${PN}_append = " bash"
      
    SRC_URI = "\
        file://update-module \
        file://device-type-bbg-beaglebone-yocto \
        file://device-type-bbgg-beaglebone-yocto \
        file://device-type-beaglebone-yocto \
    "
      
    S = "${WORKDIR}"
      
    FILES_${PN} += "\
        ${datadir}/mender/modules/v3/update-module \
        ${datadir}/mender/modules/v3/device-type-bbg-beaglebone-yocto \
        ${datadir}/mender/modules/v3/device-type-bbgg-beaglebone-yocto \
        ${datadir}/mender/modules/v3/device-type-beaglebone-yocto \
    "
      
    do_install() {
        install -d ${D}${datadir}/mender/modules/v3
        install -m 0755 update-module ${D}${datadir}/mender/modules/v3
        install -m 0755 device-type-bbg-beaglebone-yocto ${D}${datadir}/mender/modules/v3
        install -m 0755 device-type-bbgg-beaglebone-yocto ${D}${datadir}/mender/modules/v3
        install -m 0755 device-type-beaglebone-yocto ${D}${datadir}/mender/modules/v3
    

    Looking back, I wonder if I even needed to do step #2 since I am installing these files with 0755 in the do_install() section here. Not really sure…

  4. Build my base images.
    bitbake mc:bbg-beaglebone-yocto:core-image-base
    bitbake mc:bbgg-beaglebone-yocto:core-image-base
    
  5. Generate the rootfs-image artifacts for each device.
    mender-artifact write rootfs-image \
      -n device-type-upgrade:bbg-part-1-of-2 \
      -t beaglebone-yocto \
      -t bbg-beaglebone-yocto \
      -f core-image-base-bbg-beaglebone-yocto.ext4 \
      -o device-type-upgrade-bbg-part-1-of-2.mender \
    

    Same command repeated but replaced bbg with bbgg

  6. Generate the module-image artifacts for each device.
    mender-artifact write module-image \
      -T device-type-bbg-beaglebone-yocto \
      -n device-type-upgrade:bbg-part-2-of-2 \
      -t beaglebone-yocto \
      -f core-image-base-bbg-beaglebone-yocto.ext4 \
      -o device-type-upgrade-bbg-part-2-of-2.mender
    

    Same command repeated but replaced bbg with bbgg

  7. Upload artifacts to Mender.
  8. Deploy part 1 of artifacts to respective boards.
    • Board will now have the Mender module update scripts in /usr/share/mender/modules/v3
    • At this point /data/mender/device_type is still beaglebone-yocto.
  9. Deploy part 2 of artifacts to respective boards.
    • This update actually runs the module update scripts to change /data/mender/device_type.

At this point I can now deploy the new rootfs-image artifacts using the new device types.

I feel like I may have overcomplicated much of this process so if there is anything that you think I did wrong then let me know.

I also notice that mender-artifact write rootfs-image has a parameter --script used to specify a “state script” however I haven’t looked into those at all so I don’t know how they differ from module update scripts.