Skip to content
Zygmunt Krynicki edited this page Dec 7, 2016 · 15 revisions

Overview

The content interface is a way for two or more snaps to share something. Sharing happens at the filesystem level so anything that can be expressed as a file can be shared. This includes executables, libraries, data files but also sockets. Let's look at how this works in a few simple examples. At a very basic level, one directory, file or socket can be made to appear in a place where another snap can access it.

Examples

All of the examples below involve two snaps. One snap is offering some content (using a content slot) and the other snap is consuming that content (using a content plug). Let's call those snaps producer and consumer.

In all of the cases we see a small set of attributes defined on the particular interface. The producer declares which path can be read (using the read attribute) or written (using write). The consumer uses the target attribute to define where the content should show up at runtime. Both interfaces use the content attribute to describe the content. The content attribute must match on both sides for the connection to happen. Lastly you may notice that both read and write attributes use a list of paths. As of snapd 2.17 only one element may be listed there but this is a place for future expansion.

Sharing read-only snap content

Sharing an executable

producer/snapcraft.yaml

slots:
  content:
    content: executables
    read: 
      - $SNAP/bin

consumer/snapcraft.yaml

plugs:
  content:
    content: executables
    target: $SNAP/extra-bin

When the two interfaces are connected the consumer snap can invoke executables from $SNAP/extra-bin. The directory can be added to PATH in the wrapper script if desired. The directory can be inspected by any applications that wish to check if the extra executables are available (they can then fail gracefully).

Sharing a C-level library

TBD

Sharing writable data

Sharing writable files

TBD

Sharing UNIX sockets

producer/snapcraft.yaml

slots:
  content:
    content: socket-directory
    read: 
      - $SNAP_DATA/sockdir

consumer/snapcraft.yaml

plugs:
  content:
    content: socket-directory
    target: $SNAP/sockdir

When the two interfaces are connected the consumer snap can see the socket in $SNAP/sockdir. The directory is specifically present in $SNAP where it is easier to guarantee that it exists at the time the connection is established. The snap that wishes to create the socket should create $SNAP_DATA/sockdir early (e.g. in the configure hook) so that the connection can succeed in practice.

Technical background

The content interface is implemented with an interplay of two systems: apparmor and bind mounts. The apparmor sandbox by default allows writes to $SNAP_DATA and reads from $SNAP (overview of environment variables). We can take advantage of this by putting content from other location and make it appear to show up in $SNAP or $SNAP_DATA. We can now take data from one snap's $SNAP (e.g. from /snap/my-snap/1234/content and bind mount it to an empty directory in /snap/my-other-snap/4321/incoming-content). The same can be done for particular files if desired but it requires a pair of interfaces for each file and is more cumbersome.

Clone this wiki locally