Wednesday, April 20, 2016

Snappy, snapcraft and interfaces

This is the first of a series of articles about snappy, specifically focusing on snappy interfaces.

Interfaces are an essential part of snappy. They are the mechanism which allows snaps to reach beyond the default space they are given, to interact with other parts of the system, with other snaps, with the network, with the desktop and more.

Before we begin we should define some terminology. I will do my best to use the right terms each time. During the development of snappy 2.0 series we tried various different terms for what is now known as snappy interfaces. If you've been following the development release for the past few months you may still remember some of the older terms and that can add to the confusion as to what interfaces are. Let's set this straight now:

Snap is the new package format. Snaps hold one or more applications.
App is a runnable executable exposed by a snap. There are command line apps, desktop apps and background apps (aka daemon/service).
Interface is the mechanism with which two snaps can interact with each other. The type of interaction is defined by the interface name. Interfaces can allow snaps to communicate, share particular resources or access particular hardware.
Plug is the consumer part of an interface. Plugs can be connected to slots. Most snaps will define one or more plugs.
Slot is the producer or provider part of an interface. Slots are what plugs connect to. Many slots come directly from the OS snap. Most snaps will not define any slots.

Don't worry if the interface/plug/slot part is still confusing. Let's explore a single example today and see how plugs and slots play a part of the experience. For this purpose I've created a snap with the links text mode web browser.

The entire snapcraft.yaml file for this snap is reproduced below:

name: links
version: 2.12-1
summary: Web browser running in text mode
description: |
    Links is a text mode WWW browser, similar to Lynx. It displays tables,
    frames, downloads on background, uses HTTP/1.1 keepalive connections.
        command: links
        plugs: [network, network-bind]
        plugin: nil
            - links

If you are not familiar with snapcraft I would recommend taking a quick look at the introduction to snapcraft. Even if you haven't used snapcraft yet the content is somewhat self-explanatory. The snap "links" contains one app, "links", which runs the command "links". The snap is comprised of just one part, "links", which is using the "nil" (do nothing extra) plugin to put the "links" Debian package into the stage directory from which our snap is created.

All that this does it puts pre-packaged links executable into a snap. No compiling required!

In Ubuntu, Debian and many other distributions, applications started by a particular user run with the privileges of that user. In other words *every* application that you install from outside of the official repository has complete and unrestricted access to all of your personal files. To your photos. To your browser history. To your saved passwords. To your ssh and gpg keys. Each application you ever installed from a PPA also has complete access to your kernel and to all the other applications. Wow, that's a lot of responsibility. This is why in Ubuntu the trust is put on the Debian / Ubuntu repository. Trustworthy people review the software that is placed there to ensure it doesn't have any nasty code inside.

So why did we have use the two plugs in the snapcraft.yaml above? Because snappy is different. Similarly to how your phone may work, snaps don't get unrestricted access to all of your hardware and personal data.

Recall that snappy runs all apps in a confined sandbox. This is the same technology we use on the Ubuntu phone and tablet. I won't go into details as to how this snadbox works but suffice it to say that apps don't have access to the network or to your personal files default. To give links access to the internet we have to use snappy interfaces.

So what are those interfaces? The network interface allows applications to access the network as a client. This is clearly what links wants to do, it wants to have access to the internet. The network-bind interface allows applications to access the network as a server. Why does links need this? Because apparently it has an option to bind to particular local IP address. It's somewhat unfortunate but we cannot avoid it without patching this feature out of links. Let's not do that today. This is exactly what the statement "plugs: [network, network-bind]" above does.

Please recall that interfaces have two sides, the plug side and the slot side. The plugs are meant for consumer. The slots are meant for producers (or providers). So who's providing network and network-bind on our system? The OS does.

The OS snap, ubuntu-core, has a slot of type network (many plugs will be named after the interface name but those names are independent). When the snap links was installed snappy automatically connected the plug network from the snap links to the slot network from the snap ubuntu-core. The same thing happened for network-bind. Both the network and the network-bind interfaces are designed to automatically-connect to the slots on the OS snap.

You can see that this is true by running the command "snap interfaces" which shows all plugs, slots and their connections.

zyga@zyga-thinkpad-w510:~$ snap interfaces
Slot                 Plug
:firewall-control    -
:home                -
:locale-control      -
:log-observe         -
:mount-observe       -
:network             links
:network-bind        links
:network-control     -
:network-observe     -
:opengl              -
:snapd-control       -
:system-observe      -
:timeserver-control  -
:timezone-control    -
:unity7              -
:x11                 -

Let's have a look at the output. There are two columns, one for slots and one for plugs. In general each plug and slot is displayed as snap:plug or snap:slot but as you can see above there are a number of abbreviations that make the output less repetitive. The Slot column doesn't display the name of the OS snap (ubuntu-core). The Plug column doesn't display the plug name if it is the same as interface name (here it just displays the snap name twice).

Had both of those abbreviations been turned off the relevant portion of the output would look something like this:

zyga@zyga-thinkpad-w510:~$ snap interfaces
Slot                            Plug
ubuntu-core:network             links:network
ubuntu-core:network-bind        links:network-bind

You can install this example snap on your system (make sure to run up-to-date Ubuntu 16.04 on an amd64 architecture) by running "sudo snap install links". After that it should just work, you should be able to run links and browse the web in all of its plain-text glory.

In the next article I will explore connections. Show you how you can disconnect, connect and what happens when you do that.

If you have any questions please leave them as comments below.