Writing a Snappy application

October 15 2015

So, having ingested all the information about Ubuntu Snappy Core, we can start developing our first application.

The platform

Ubuntu Snappy Core can currently be run on several platforms:

Fortunately, I have a Raspberry Pi 2 in a nice orange enclosure that I can use for my purposes. Orange Matchbox

Prerequisites

Before starting our favorite editor, we need to install some tools to develop a snappy application.

$ sudo add-apt-repository ppa:snappy-dev/tools
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install snappy-tools bzr

The code

I’ve put the code of this Snappy application on github, so ideally it should be easy to follow along.

The structure of a snappy application is rather simple.

├── Makefile
├── meta
│   ├── package.yaml
│   └── readme.md
├── README.md
└── src
    └── main.go

If we ignore the Makefile, and README.md, it’s just three files.

The code itself is simple - it’s a golang application, using an excellent go package to turn on and off lights on a piglow device over i2c.

The meta folder contains information describing the application: readme.md (it’s required) for humans and package.yaml for snappy.

name: blink
version: 1.0.0
vendor: Domas Monkus <domas.monkus@canonical.com>
services:
  - name: blinker
    description: blinker
    start: bin/blink

name, version and vendor are pretty much self-explanatory. services is a bit more interesting. A snappy application can either start a service or expose a binary (for other applications to use). Since I don’t want to have to ssh into my raspberry-pi to turn the blinking lights on, I’m going to expose a service that will automatically be started. There’s a lot more metadata that can be provided for a service (this is the absolute minimum) - please check out the documentation for more information.

Building and deploying

There’s two steps needed to create a snappy package in this case:

  1. Build the application binary.
  2. Create the snappy package.

To build the binary, we’re going to use go 1.5 cross-compilation capabilities (because raspberry pi2 is ARM):

$ env GOOS=linux GOARCH=arm go build -o bin/blink src/main.go

To build the snappy package, we’ll just run:

snappy build .

in the package directory.

After this is done, you should see a file blink_1.0.0_all.snap in the directory.

To deploy it, we’re going to run a command:

snappy-remote --url=ssh://[IP-ADDRESS-of-RPi2]:22 install blink_1.0.0_all.snap

Oh-oh

We built the executable, the package, sent it over to the raspberry pi, but the lights are not blinking!

Sad snappy

Well, that is because the application does not have access permissions to the i2c device. Fortunately, that’s easy to fix, we’ll just have to ssh into our orange matchbox:

$ ssh ubuntu@orangebox
...
$ sudo snappy hw-assign blink.sideload /dev/i2c-1

This will create a udev rule that adds access permissions to the cgroup specific to our application. The only downside is that the aplication has to be restarted for this to take effect. Yuck.

Let’s just do it:

$ ls /etc/systemd/system
blink_blinker_IDLRVAUReHSd.service [...]
$ sudo systemctl restart blink_blinker_IDLRVAUReHSd.service

it works!

Yay!

Update

My repository now contains a modified version of the snappy blinker, that changes the color based on the status of the juju master branch. Not completely useful yet, but not useless either.