Skip to content

Latest commit

 

History

History
 
 

README.md

Snapd packaging

Snapd upstream project provides reference packaging for various distributions that are part of its CI process (Ubuntu, Debian, Fedora, openSUSE, Arch etc). The reference packaging is provided under the top level packaging directory in snapd source tree.

It is recommended to stay as close as possible to what is in the upstream repository. Snapd developers keep the packaging updated as new features or dependencies are introduced. At the same time, we are happy to accept patches and contributions related to packaging. If you find that the reference packaging is done incorrectly, or does not meet established conventions for your distribution, feel free to open a pull-request.

The guide focuses on packaging of snapd for use with a classic Linux distribution, such as Ubuntu, Fedora, Arch Linux, and not an immutable system like Ubuntu Core.

Dependencies

Majority of snapd is written in Go, but some smaller bits are written in C. See the go.mod file for the minimum required version of Go. While for building the C code any reasonably recent version of GCC or Clang will suffice.

Other high level build and runtime dependencies are:

  • Linux kernel >= 4.4 (or otherwise reasonably recent)
  • systemd
  • autotools, pkg-config
  • libc static
  • libudev
  • libseccomp
  • libcap
  • libapparmor (if using AppArmor)
  • libselinux (if using SELinux)
  • gnupg2
  • python3-docutils
  • squashfs

Source tarballs

Snapd release assets consist of 3 source tarballs:

  • snapd_<ver>.tar.xz (e.g. snapd_2.72.tar.xz) - a unified snapshot, which includes the snapd source tree plus all vendored Go dependencies
  • snapd_<ver>.no-vendor.tar.xz - snapshot without any Go dependencies
  • snapd_<ver>.only-vendor.tar.xz - snapshot of all Go dependencies only

Refer to the packaging policy of your distribution to decide which source tarball is appropriate for your use case.

Configuration and build

The build process of snapd is split in a couple of parts:

  • set snapd version
  • configure and build the C code
  • configure and build the Go code
  • generate any other data files

The build version is set by invoking mkversion.sh script like so:

./mkversion.sh <snapd-version>
# e.g. 2.72.1 with Arch build tag
./mkversion.sh 2.72.1-arch1

C

All of the C code is contained within cmd directory. It is configured and built using autotools. The high level process for building the code is:

cd cmd
autoreconf -i -f
./configure <options>

Most relevant configure options:

  • --enable-apparmor - enable AppArmor support
  • --enable-selinux - enable limited SELinux support
  • --libexecdir - set the location of where snapd internal tools are located, typically /usr/lib/snapd (or /usr/libexec/snapd)
  • --with-snap-mount-dir - expected snap mount directory, typically /var/lib/snapd/snap (or /snap)

Go

It is recommended to use packaging/snapd.mk helper for simplifying the build of Go code which will invoke go build with appropriate options and build tags.

The helper requires a bit of configuration, see openSUSE RPM spec for examples of usage. It expects to find a snapd.defines.mk configuration file within the build directory. The file itself it directly included by snapd.mk and so it must follow Make syntax. An example snippet which generates the configuration file, extracted from openSUSE RPM spec, is provided below:

# This file is generated by openSUSE's snapd.spec

###
# Directory variables.
###
# Desired installation prefix, usually /usr
prefix = %{_prefix}
# Desired installation path for system wide binaries, usually /usr/bin
bindir = %{_bindir}
# ...and /usr/sbin
sbindir = %{_sbindir}
# Desired location of snapd internal tools, one of /usr/lib/ or /usr/libexec/
libexecdir = %{_libexecdir}
# Location of manpages, typically /usr/share/man
mandir = %{_mandir}
# Location of data files, typically /usr/share
datadir = %{_datadir}
# Location of local state, typically /var/lib
localstatedir = %{_localstatedir}
# Location of shared state, typically /var
sharedstatedir = %{_sharedstatedir}
# Systemd system units directory, usually /usr/lib/systemd/system
unitdir = %{_unitdir}
# Build directory, depends on the build environment
builddir = %{_builddir}

###
# Build configuration
###
# Enable or disable Ubuntu Core specific pieces, 0|1
with_core_bits = 0
# Expect alternative snap mount directory, 0|1
with_alt_snap_mount_dir = 1
# Enable AppArmor support, 0|1
with_apparmor = 1
# Enable use of PIE when building static binaries, 0|1
# Ensure support in your distribution toolchain.
with_static_pie = $build_with_static_pie
# Use vendored dependencies, 0|1
with_vendor = 1
# Pass any additional flags to `go build`
EXTRA_GO_BUILD_FLAGS = -v -x
# Pass any additional flags for `go tool link` in go build invocation
EXTRA_GO_LDFLAGS = -compressdwarf=false
# Enable test keys
# NOTE this option is relevant only in builds for snapd CI
with_testkeys = 0

The helper is invoked like so:

make -f packaging/snapd.mk \
    SNAPD_DEFINES_DIR=$PWD \
    install  # or: build|check|clean|all

Where SNAPD_DEFINES_DIR is set to the path of the directory containing snapd.defines.mk file.

Other build artifacts

The top level data directory contains additional files that need to be configured and built. Those are systemd units, completion support, SELinux policy module, environment tweaks and similar. The build and installation is carried out like so, passing a number of overrides for the desired filesystem locations (snippet extracted from Fedora packaging):

pushd ./data
make BINDIR="%{_bindir}" LIBEXECDIR="%{_libexecdir}" DATADIR="%{_datadir}" \
     SYSTEMDSYSTEMUNITDIR="%{_unitdir}" \
     USE_CANONICAL_SNAP_MOUNT_DIR=false \
     USE_ALT_SNAP_MOUNT_DIR=true \
     SNAPD_ENVIRONMENT_FILE="%{_sysconfdir}/sysconfig/snapd"

# or
make install BINDIR=...
popd

It is essential to pass the same set of Make variable overrides during build and installation.

Notes on building

The following binaries are provided by the native host package, but need to be executed within the snap sandbox, and as such they need to be built statically:

  • snap-exec
  • snap-update-ns
  • snapctl
  • snapd-gdbserver-shim

The reference packaging contains relevant snippets for confirming that the binaries listed above are indeed built statically. Packagers are encouraged to copy the applicable snippets as needed.

Installation

snap-confine

The snap-confine binary is expected to have the file capabilities listed in cmd/snap-confine/snap-confine.v2-only.caps. set on it once the package has been installed.

The cmd/snap-confine/snap-confine.caps file lists the same set of capabilities, but additionally includes cap_setuid,cap_setgid, which is a workaround for kernel cgroup v1 issues and relevant only if expecting that the snapd package will be used within a container running on a host kernel that is booted with cgroup v1 support. Packaging is encouraged to not ship or otherwise use this file, unless deemed necessary for the use case.

Systemd units

The main systemd units are snapd.service, the snapd daemon, and snapd.socket, a socket unit which is responsible for creating the two sockets over which clients communicate with snapd: /run/snapd.sock (for snap command), and /run/snapd-snap.sock (for calls from within the sandbox using snapctl tool).

On systems with AppArmor enabled, snapd.apparmor.service needs to be installed as well. It is a dedicated unit which invokes snapd-apparmor internal tool, that is responsible for loading AppArmor profiles of installed snaps.

The table provides a summary of all systemd units that are relevant for classic distribution packaging:

Unit Kind Purpose
snapd.service system Main snapd service
snapd.socket system Snapd sockets unit, activates snapd.service
snapd.apparmor.service system Loads snap AppArmor profiles
snapd.mounts.target system Synchronization target right after snap mounts have completed
snapd.mounts-pre.target system Synchronization target for mounting snap units
snapd.seeded.service system Service waiting for snapd initialization to complete
snapd.session-agent.service user User session agent
snapd.session-agent.socket user User session socket for communication with snapd, activates the agent

It is recommended to enable at least snapd.socket and snapd.session-agent.socket units, however this should be done in accordance with a policy established by a given distribution.

Directories

The snapd daemon will create relevant state directories as needed (see the reference packaging for a list of actual locations), however some directories are expected to be created by the packaging, those are:

  • /usr/lib/snapd or /usr/libexec/snapd - snapd internal tools directory
  • /var/lib/snapd/snap or /snap - snap mount directory

Consult your distribution policies to decide which locations are appropriate.

Historically, the internal tools and snap mount directories needed to be hardcoded in snapd, however starting with 2.71, snapd will probe and use the locations created by distribution packaging.

Support for classic snaps (such as code editors, compilers etc.) requires /snap to be present, either as directory, or as a symbolic link pointing to /var/lib/snapd/snap. The users are free to create a symbolic link themselves and the packaging should account for that.

Support scripts

Snapd provides support scripts that can be used during package installation:

snap-mgmt

This script is expected to be invoked during package removal, in a pre-remove step, like so:

${libexecdir}/snapd/snap-mgmt --purge

Its purpose is to ensure that all snaps and their data is removed from system wide locations.

snap-mgmt-selinux

A support script which can be invoked from the snapd SELinux policy subpackage. Its purpose is to patch snap mount units to use a dedicated SELinux context for all snap mounts. The script is only relevant if there is possibility that the users, on a SELinux enabled system, may be updating from snapd older than 2.39.