State-scripts documentation: how to use them without Yocto

The documentation doesn’t really help to understand how to implement and include state scripts.
Question I have (and probably other newcomers will):

  • can state scripts be included in artifacts or they are a part of Mender client? (covered in docs)
  • how to design them? (covered in docs)
  • where to place them/how to include in the created artifact/image?
  • can they differ for different types of artifact/update-modules (e.g. rootfs vs single file) ?

Will be extremely thankful for any hints where to look at.

Regarding storage location, see https://docs.mender.io/2.0/artifacts/state-scripts#root-file-system-and-artifact-scripts for more details. Basically the “Root Filesystem” scripts go in /etc/Mender/scripts and the artifact scripts are added by the mender-artifact invocation. See ‘mender-artifact write module-image --help’ for more details.

The specifics for full-image versus partial updates can be found here: https://github.com/mendersoftware/mender/blob/2.0.0/Documentation/update-modules-v3-file-api.md

This is an ambiguous question. No, they can’t, in the sense that they are update module agnostic, they don’t care (and in fact, cannot find out) which type of update is in progress. This is intentional, since in the future, multiple updates may be supported inside one artifact.

But on the other hand, yes they can, in the sense that you can include any script you want in the artifact, and if you make a new artifact, with a different update type, you can include a different state script.

so no out-of-the-box way of adding state scripts to artifacts generated by mender-convert for now?

so no out-of-the-box way of adding state scripts to artifacts generated by mender-convert for now?

Correct, you will need to create a new Mender Artifact using mender-artifact and the ext4 image once the mender-convert process is completed.

One more question:
The naming of state scripts intended to be included in roofs is well documented.
But the naming requirements for scripts coming inside artifacts are confusing.

From one side, docs say it should follow the following format, same as ‘normal’ state scripts:

<STATE_NAME>_<ACTION>_<ORDERING_NUMBER>_<OPTIONAL_DESCRIPTION>

From the other hand, Mender Artifact file format spec shows example of state-scripts named as (using dots)

+---header.tar.gz (tar format)
  |    |
  |    +---header-info
  |    |
  |    +---scripts
  |    |    |
  |    |    +---State.Enter
  |    |    +---State.Leave
  |    |    +---State.Error
  |    |    `---<more scripts>

Another thing which is unclear (just a general case, not related to my use case) is whether Artifact-prefixed state scripts are only intended to be included in the artifacts or can be placed in rootfs (/etc/mender/scripts) as well?


My use case is simple and common: I need to copy saved wifi credentials (wpa_supplicant.conf file in case of raspbian) from old rootfs to new one when full image updates are performed to not loose connectivity after reboot (considering symlinking to /data/ is not an option). I saw retain-ssh-keys example, but as I plan to perform not only full-image updates, but also single file updates without changing rootfs partition, I don’t need to perform this script before every artifact install. That’s why I think such script should be included in Artifacts with full-os updates only. Is it the right path to follow?

@kacf might have some input on the naming inconsistencies.

Another thing which is unclear (just a general case, not related to my use case) is whether Artifact -prefixed state scripts are only intended to be included in the artifacts or can be placed in rootfs ( /etc/mender/scripts ) as well?

Artifact prefixed artifacts are only intended to be included in Artifacts and can not be placed in rootfs.

That’s why I think such script should be included in Artifacts with full-os updates only. Is it the right path to follow?

Yes, this looks like a good path for me.

Ok I will summarize info to potentially help others

can state scripts be included in artifacts or they are a part of Mender client?

Both. Client-side state scripts (those for states which are not prefixed with Artifact) are executed by the mender client regardless of the contents or type of the artifact it installs.

State scripts for states perfixed with Artifact are intended to be only included in the Artifact itself, thus may vary between Artifacts.

how to design them?

Some examples of client-side state scripts are in the mender client repo. Artifact state scripts may follow the same logic and should follow the same naming format, i.e.
<STATE_NAME>_<ACTION>_<ORDERING_NUMBER>_<OPTIONAL_DESCRIPTION>

retain-ssh-keys example may give an idea how to transfer files between old and new filesystems when performing full-rootfs updates, if storing persistent files in /data/ is not an option. Yet, IMHO this type of actions should rather be included in Artifact as ArtifactInstall_Enter_... script as such actions are only needed for full-os updates and not needed to be executed if you perform updates without swithing partitions (i.e. using update modules)

where to place state scripts/how to include in the created artifact/image?

Client state scripts should be placed in /etc/Mender/scripts of the new rootfs. To add them to an SD image, you can use Modifying disk images workflow from the docs.

To add client state scripts to a Mender artifact, you can use mender-artifact cp. Keep in mind it is a slow process and takes ~5 min per one file on ~300 MB Artifacts.

In addition, there’s no way of adding Artifact state scripts to already created Mender artifacts with mender-artifact. Thus if you use mender-convert workflow and need to include both clien and artifact state scripts, you can discard .mender file generated by mender-convert, mount .ext4 and copy all required client state scripts inside (as well as your mender.config, identity and inventory if needed), and then create mender Artifact from .ext4 yourself using mender-artifact write rootfs-image adding all your Artifact scripts by using --script, something like

mender-artifact --compression "lzma" write rootfs-image   \
   --file "$releaseName-mender.ext4"      \
   --device-type "raspberrypi3"           \
   --artifact-name "$releaseName-mender.mender"  \
   --script "$scriptsDir/ArtifactInstall_Enter_01_retain_wpa_supplicant" \ 
   --script "$scriptsDir/another_script"  

To verify that the scripts are added to the Artifact, you can open .mender as a .tar and check the contents of /header.tar.gz/scripts/

1 Like

From one side, docs say it should follow the following format, same as ‘normal’ state scripts:

From the other hand, Mender Artifact file format spec shows example of state-scripts named as (using dots)

Yeah, this is wrong/outdated. I have made some cleanups here.