The content interface

content allows sharing code and data with other snaps.

Auto-connect: no unless connecting to snaps from the same publisher.
Attributes:

  • read (slot): read-only paths from providing snap to expose to the consuming snap
  • write (slot): read-write paths from providing snap to expose to the consuming snap
  • content (slot): reference to plug side of connection. Defaults to local slot name
  • default-provider (plug): name and slot of preferred providing snap (<SNAP>:<SLOT>)
  • target (plug): path in consuming snap to find providing snap’s files
  • content (plug): reference to slot side of connection. Defaults to local plug name

This is a snap interface. See Interface management and Supported interfaces for further details on how interfaces are used.

Read, write and target can start with either $SNAP, $SNAP_DATA or $SNAP_COMMON to refer to the designated directory. The content attribute specified of the consuming snap (plug) must have a content attribute match in the providing snap (slot).

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:
  _slot_name_:
    content: executables
    read: 
      - $SNAP/bin

consumer/snapcraft.yaml

plugs:
  _plug_name_:
    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

producer/snapcraft.yaml

slots:
  lib0-1604:
    content: lib0-1604
    read: 
      - $SNAP/lib

consumer/snapcraft.yaml

plugs:
  lib0-1604:
    content: lib0-1604
    target: $SNAP/extra-libs

When the two interfaces are connected the consumer snap can link to libraries from $SNAP/extra-libs. The directory can be added to LD_LIBRARY_PATH in the wrapper script if desired. While the name of the interface and the value for the content attribute can be anything, it is good practice (and required when sharing content between snap publishers) to follow the form nameAPI-BUILDENV as a reminder to consumers of the API level and build tools used. In the above, the API ‘0’ is used and ‘1604’ is used to denote it was built using the Ubuntu 16.04 LTS toolchain and libraries. API and BUILDENV can be anything that is meaningful to the provider and consumers. For example, the gnome content snap uses gnome-3-26-1604 to denote the full GNOME 3.26 platform libraries and supporting files built on Ubuntu 16.04 LTS.

Default provider

A content plug can optionally specify a default provider snap.

consumer/snapcraft.yaml

plugs:
  lib0-1604:
    content: lib0-1604
    target: $SNAP/extra-libs
    default-provider: lib01604

The default-provider attribute can be set to the name of a snap offering a corresponding content slot. When installing the consumer snapd starting with 2.32 should install the default provider snap if there is not yet any snap in the system providing a matching slot. On installation auto-connection then will also make sure that the consumer is connected to the slot from this snap.

For example a snap consuming the gnome content snap for GNOME 3.26 can set default-provider to gnome-3-26-1604.

Sharing writable data

Sharing writable data can be used to share data files or … UNIX sockets for a simple form of IPC among a group of snaps. In subsequent releases of snapd it may become easier to share a subdirectory that is automatically created but this is not supported yet. It is recommended to share all of $SNAP_DATA or $SNAP_COMMON for now.

Sharing writable files

Note that this only works since snapd 2.19.1

producer/snapcraft.yaml

slots:
  _slot_name_:
    content: writable-data
    write: 
      - $SNAP_DATA

consumer/snapcraft.yaml

plugs:
  _plug_name_:
    content: writable-data
    target: $SNAP_DATA

Sharing UNIX sockets

Note that this only works since snapd 2.19.1

TBD: Links to example snaps using this.

producer/snapcraft.yaml

slots:
  _slot_name_:
    content: socket-directory
    write: 
      - $SNAP_DATA

consumer/snapcraft.yaml

plugs:
  _plug_name_:
    content: socket-directory
    target: $SNAP_DATA

When the two interfaces are connected the consumer snap can see the socket in $SNAP_DATA.

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|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.

Last updated a month ago. Help improve this document in the forum.