Configure a snap: using a content snap
When a robotics application is snapped, one might want to use it on multiple different robots.
Reusing the same snap means that we must be able to configure the snap to the specificity of a robot once installed on it.
For the rest of this guide, we will refer to the snap distributing the configuration as the configuration snap, and the one running the teleoperation application as the application snap.
We present in this guide the steps to distribute configurations with a separate, dedicated configuration snap and use it to distribute configuration files to another application snap.
Our application snap will get its configuration, not from the snapped package but from a configuration snap. This allows us to use the same snap on multiple devices with different configurations, as well as updating the configuration without having to update the application snap.
For this how-to-guide, we use the example ubuntu-robotics/snap_configuration.
The repository consists of the snapcraft.yaml
file from which the snap is built, as well as a launcher script.
The repository contains a standard snap package providing the key_teleop application from the teleop_tool ROS 2 package. The goal here is to be able to configure the application using content-sharing, thus without having to update the application snap. The key_teleop
node can be configured for its forward_rate, backward_rate and rotational_rate parameters. These are the parameters we will be configuring from the configuration snap.
Requirements
This how-to-guide is assuming that we are familiar with robotics snaps. Please refer to our tutorials to learn more about robotics snaps.
An up and running Ubuntu (minimum 20.04) with snapcraft installed is also required.
Configuration snap
In addition to an application snap containing our teleoperation, we will also distribute an independent configuration snap, only responsible for configuring our application. The configuration snap will simply contain the YAML file and make it available for the application snap via a content interface.
Create the configuration snap
The first step is to create a snap to distribute our configuration file.
Let’s create a new directory for the configuration snap:
mkdir snap
And then we can create the file snap/snapcraft.yaml with the following content:
name: my-configuration-snap
base: core22
version: '0.1'
summary: A snap to configure them all
description: |
This snap is sharing a configuration via content-sharing.
This way, my-ros2-teleop-test is getting configured.
grade: devel
confinement: strict
parts:
configuration:
plugin: dump
source: snap/local/
organize:
'*.yaml': etc/
The snap only contains one part, dumping local YAML files inside the snap. There is no application defined, since we don’t need one.
Define the configuration
Now let’s create the configuration file that our snap will be sharing.
First, we create a directory:
mkdir snap/local
We then create the file snap/local/up-to-date-config.yaml
containing:
key_teleop:
ros__parameters:
forward_rate : 1.234 # our custom value
This configuration file only overwrites one value from the default one. This is the configuration that our application snap will use.
Declare the content slot
The configuration snap needs now to define the content interface. On the configuration snap side, we declare the slot
part of the interface. Please refer to the online documentation for the explanation of slots and plugs.
We modify the snapcraft.yaml
to declare the content slot:
grade: devel
confinement: strict
+slots:
+ configuration:
+ interface: content
+ source:
+ read:
+ - $SNAP/etc
The configuration is placed in $SNAP/etc
here since etc/
is a standard directory for system configurations on Linux, but we could have used another directory such as $SNAP/teleop_config
.
The configuration snap is now completed, we can build it and install it:
snapcraft
sudo snap install my-configuration_*.snap --dangerous
Our configuration snap is installed and ready to provide configurations!
Application snap
At the beginning of this guide, we introduced the ubuntu-robotics/snap_configuration. We start from this snap and modify it so that it uses our shared configuration.
First, we clone the repository:
git clone https://github.com/ubuntu-robotics/snap_configuration.git
This repository already contains a snap package for the key_teleop
package. There is a launcher script in snap/local/teleop_launcher.bash
and the snap/snapcraft.yaml
.
Declare the content plug
The configuration snap is exposing a content slot containing the configuration. To access this configuration, we must declare the content plug
.
Let’s add the plug to the snapcraft.yaml
:
grade: devel
confinement: strict
+plugs:
+ configuration:
+ interface: content
+ target: $SNAP/configuration
Additionally, we must declare that our application is using this plug
:
command: bin/teleop_launcher.bash
-plugs: [network, network-bind]
+plugs: [network, network-bind, configuration]
Our application has now enough privilege to access the shared YAML file.
Before rebuilding our snap, we still need to actually use this file in our launcher.
Let’s see how to do that.
Use the content shared configuration
Even if we can access the shared configuration file, our launcher is still using the default configuration.
We will modify the launcher to make sure the shared configuration file is present and load it.
We modify the file snap/teleop_launcher.bash
as follows:
#!/usr/bin/bash
+CONFIG_FILE_PATH="$SNAP/configuration/etc/up-to-date-config.yaml"
+if [[ -f $CONFIG_FILE_PATH ]]; then
-ros2 run key_teleop key_teleop --ros-args --params-file $CONFIG_FILE_PATH
+ ros2 run key_teleop key_teleop --ros-args --params-file $CONFIG_FILE_PATH
+else
+ echo "No configuration found!"
+ exit 1
+fi
As we can see, the content shared was entirely mounted in our target location.
Our application is now loading the YAML from our configuration snap!
Ensure content-interface connection between snaps
The content interface is auto-connect only when connecting two snaps from the same publisher, in other cases we really should verify the connection of the plug before launching our application.
Again, we modify our snap/teleop_launcher.yaml
and prepend the following:
#!/usr/bin/bash
+if ! snapctl is-connected configuration; then
+ >&2 echo "Plug 'configuration' isn't connected, \
+ please run: snap connect ${SNAP_NAME}:configuration PROVIDER_SNAP:configuration"
+ exit 1
+fi
CONFIG_FILE_PATH="$SNAP/configuration/etc/up-to-date-config.yaml"
This way, the error message will be clear to the user in case the plug is not connected.
We are now ready to test, we can build and install the application snap:
snapcraft
sudo snap install my-ros2-teleop-test_*.snap --dangerous
We are now all set!
Test the snaps together
Both snaps are now installed. It’s time to make sure everything works fine.
We can verify the connections state of our application snap with:
$ snap connections my-ros2-teleop-test
Interface Plug Slot Notes
content my-ros2-teleop-test:configuration - -
network my-ros2-teleop-test:network :network -
network-bind my-ros2-teleop-test:network-bind :network-bind -
Since the content interface is not connected, we can manually connect it with the following command:
sudo snap connect my-ros2-teleop-test:configuration my-configuration-snap:configuration
We can now launch the application with:
my-ros2-teleop-test
By pressing the “up” arrow, we can observe that the value from our configuration snap (1.234) is used!
With the application snap properly using the YAML provided by our configuration snap, we can now update the configuration easily and independently of the application snap.
We can use the same application snap on multiple robots and provide a different configuration snap to different robots. We can also ship many configuration files in the configurations snap serving multiple application snaps!
We can find the complete example of this how-to-guide (application and configuration snap) on the branch howto/content_sharing_configuration_snap of the repository.