Snap Packaging

Democratising Wireless Innovation
Jump to navigation Jump to search

Snaps are a containerization system that makes it easy to package and distribute a complete set of dependencies and files needed for an application.

Snaps offer both security through signing and validation, as well as confinement rules between applications and the rest of the system. With a little upfront work from a developer, any application can be snapped, and uploaded to a store to share with millions.

As an example, several snaps are now available on the LimeNet store for the Lime Suite GUI, Pothos GUI, GQRX, and GNURadio companion.

Creating a snap

At its most basic, a snap is described a single text file named "snapcraft.yaml". In practice, a few other files usually accompany the .yaml file, such as icons, desktop launchers, and scripts for setting up environment variables. Its also possible to include source code as well, although my preference is to to fetch the various sources from a repository like GitHub.

To start with, we are going to need an Ubuntu PC with "snapcraft" and "snapd" installed. Snapcraft is a command line tool used for building snaps. It will also automatically download any additional dependencies needed by the snap. So all you will need from this point on is a text editor.

sudo apt-get install snapcraft snapd

Yaml structure

In short, a "snapcraft.yaml" lists all of the dependencies needed to build and package an application, and all of the relevant executables and binaries that will be used. This can include GUI applications, server daemons, bash scripts, python, and more. Here is a real-world example that packages LimeSuite along with SoapySDR:

name: limesuite-example
version: 2016.09
summary: LimeSuite Example
description: Example package with LimeSuite
confinement: strict
apps:
    SoapySDRUtil:
        command: SoapySDRUtil
        plugs: [home]
    LimeUtil:
        command: LimeUtil
        plugs: [home]
parts:
    soapysdr:
        plugin: cmake
        source: https://github.com/pothosware/SoapySDR.git
    limesuite:
        plugin: cmake
        source: https://github.com/myriadrf/LimeSuite.git
        after: [soapysdr]
        build-packages:
            - libsqlite3-dev
            - libi2c-dev
            - libusb-1.0-0-dev

Notes

  • after allows us to order dependencies. SoapySDR must be built first in this case.
  • build-packages specifies a list of dependencies that are found in the apt repository.
  • plugs are part of the security features of snaps, but more on that in another section.
  • Read more about the snapcraft yaml syntax
  • Read more about the syntax for snapcraft parts

Building the snap

To build the snap, simply open a terminal and cd into the directory containing "snapcraft.yaml". Now run:

>>> snapcraft

After some time compiling, you should see a few build directories and a .snap file:

>>> ls
limesuite-example_2016.09_amd64.snap  parts  prime  setup  snapcraft.yaml  stage

Installing the snap

Now use the snap command to install the new .snap package:

sudo snap install --force-dangerous limesuite-example_2016.09_amd64.snap

Don't worry about the "--force-dangerous" part, that's just because the snap command does not know that the file is from a trusted source, even though you had just compiled it. The snap should now be installed -- but where did it go?

>>> ls /snap/limesuite-example/
 current x1

The "x1" directory contains the snap that you just installed. Look inside, you will see all of the various dependencies and installed files. Subsequent installs of limesuite-example would create an x2, x3, etc directory so you can always roll back to a previous version. And "current" is a symlink to the latest version of the snap that you just installed. In this case its just a symlink to the x1 directory.

You will be able to find the commands specified in the "app" section under the /snap/bin/ directory. Executables take the form "package.command". So in this case expect two executables named "limesuite-example.SoapySDRUtil" and "limesuite-example.LimeUtil". This may seem cumbersome, but it avoids name collisions with other snaps that may have overlapping applications. Also note that /snap/bin/ is in the PATH by default, so one only needs to type "package.command" at the prompt.

Advanced topics

To help shed some more light on snaps and how they work, I will try to cover some other aspects that came up during packaging and development.

Security model

An installed snap does not simply get free-run of your system. Every command is confined by AppArmor which gives restrictive access based on a profile. To access the user's home directory, graphics, network, devices, and other restricted elements; each app entry also specifies a list of interfaces in the plugs. See the complete interfaces list for existing options. In the limesuite-example, we specified plugs: [home] because LimeSuite uses the home directory to store calibration data.

Graphical applications

Snapcraft can also package graphical apps with a few extra additions to the .yaml file. Here is an example for GQRX. Note that not all of the yaml file is shown:

apps:
    gqrx:
        command: desktop-launch gqrx
        plugs: [network, x11, pulseaudio, opengl, home]
parts:
    gqrx:
        plugin: cmake
        source: https://github.com/csete/gqrx.git
        build-packages: [qtbase5-dev]
        after: [grosmosdr, desktop-qt5]
  • The command uses desktop-launch before the actual executable
  • The plugs also include x11 and opengl for graphics access
  • Notice the use of desktop-qt5 for the after dependencies
    • There is a similar "desktop-gtk" for gtk-based apps

In addition, snaps can package menu launchers in setup/gui/app-name.desktop. The .desktop files follow the freedesktop.org specification and will appear in the menu of the window management environment like Unity or KDE.

Environment variables

Since snaps get installed to an arbitrary directory and have pretty strict access rules, its important to let your application know where its installed (so it can find resources) and where it can store its configuration files. Fortunately, a myriad of SNAP_ environment variables are set before executing the application just for this purpose.

However, most applications are not already looking for "SNAP_" environment variables but often specify their own. For example, SoapySDR uses SOAPY_SDR_ROOT to locate the installation directory, which it needs to locate its plugin modules. In this case, and many others, I found it necessary to create a simple adaptor script to set expected variables based on the SNAP_ variable names. Example:

#!/bin/sh
export SOAPY_SDR_ROOT=$SNAP
export APPDATA=$SNAP_USER_COMMON
export GRC_BLOCKS_PATH=$SNAP/share/gnuradio/grc/blocks
export VOLK_CONFIGPATH=$SNAP_USER_COMMON

This script is then installed by the snapcraft.yaml and called in the command right before the actual executable.

Snaps for LimeSDR

Snaps for Lime Suite GUI, Pothos GUI, GQRX, and GNURadio companion have been uploaded to the LimeNET store. In this section we will cover installing snaps from the store and using them with the LimeSDR. The source code used to build all of these snaps can be found in the myriadrf snapcraft sandbox. Anyone should be able to clone, build, modify these snaps, or take them as an example to package other applications altogether.

Setup Udev rules

Until hotplugging capabilities are added to snaps, its necessary to create udev rules for the LimeSDR. The udev rules consist of a simple one-line file that gives user (non-root) access to the LimeSDR. Run the following command to create a udev rule for the LimeSDR:

wget https://raw.githubusercontent.com/myriadrf/LimeSuite/master/udev-rules/64-limesuite.rules
sudo mv 64-limesuite.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules

The LimeNET store

To download and install snaps from the LimeNET store, we must set the store ID in the environment variables and restart the snapd service. The snap command line tool should be able to locate and install the new snap-based applications after this step.

#set the UBUNTU_STORE_ID in /etc/environment
>>> sudo edit /etc/environment
#add this line: UBUNTU_STORE_ID=LimeNET

And now restart the snapd service:

>>> sudo service snapd restart

The LimeNET store should now be accessible:

>>> snap find lime

Name            Version     Developer  Notes  Summary
limesdr-grc     3.7.10.1.0  goq        -      LimeSuite + GRC
limesdr-pothos  0.4.1.0     goq        -      LimeSuite + Pothos apps
limesdr-gqrx    2.6.1       goq        -      LimeSuite + GQRX
limesuite       16.8.23.0   goq        -      LimeSuite GUI and command line utils

Installing LimeSuite

Now the first application be installed. Lets install the "limesuite" snap. This snap contains the hardware support GUI for the LimeSDR and a helpful command line application LimeUtil. First install the "limesuite" snap with the following command:

sudo snap install --devmode limesuite

Now its possible to see how snaps get installed on the system:

>>> ls /snap/bin/limesuite.*
/snap/bin/limesuite.LimeSuiteGUI  /snap/bin/limesuite.LimeUtil

>>> ls -l /snap/limesuite/
total 0
drwxr-xr-x 10 root root 211 Oct  7 10:48 2
lrwxrwxrwx  1 root root   1 Oct 19 22:07 current -> 2

Running the applications:

Graphical apps like the LimeSuiteGUI can also be found in the menu of your window manager (KDE pictured):

And command line apps lime LimeUtil can be run if properly prefixed with the snap name:

>>>limesuite.LimeUtil --find
  * [USB 3.0 (LimeSDR-USB), media=USB, module=STREAM, addr=241:1204]

Notes about devmode

Without the hotplugging capabilities, which are still in development, AppArmor will block LimeSuite and libusb from communicating with the LimeSDR. Fortunately, we have a quick work around. Snaps can be installed with the "--devmode" option. This bypasses the security profile and can also be used to make development easier to experiment with snaps without considering the plugs and interfaces. But we should have a complete solution to this in the near future.

Installing GQRX

Now lets install the LimeSDR snap this GQRX. This snap includes LimeSuite, SoapySDR, and GQRX:

sudo snap install --devmode limesdr-gqrx

Since GQRX is a graphical application, it can also be launched from the menu: