Plasma in a Snap?

…why not!

Shortly before FOSDEM, Aleix Pol asked if I had ever put Plasma in a Snap. While I was a bit perplexed by the notion itself, I also found this a rather interesting idea.

So, the past couple of weeks I spent a bit of time here and there on trying to see if it is possible.

img_20170220_154814

It is!

But let’s start in the beginning. Snap is one of the Linux bundle formats that are currently very much en-vogue. Basically, whatever is necessary to run an application is put into a self-contained archive from which the application then gets run. The motivation is to isolate application building and delivery from the operating system building and delivery. Or in short, you do not depend on your Linux distribution to provide a package, as long as the distribution can run the middleware for the specific bundle format you can get a bundle from the source author and it will run. As an added bonus these bundles usually also get confined. That means that whatever is inside can’t access system files or other programs unless permission for this was given in some form or fashion.

Putting Plasma, KDE’s award-winning desktop workspace, in a snap is interesting for all the same reasons it is interesting for applications. Distributing binary builds would be less of a hassle, testing is more accessible and confinement in various ways can lessen the impact of security issues in the confined software.

With the snap format specifically Plasma has two challenges:

  1. The snapped software is mounted in a changing path that is different from the installation directory.
  2. Confining Plasma is a bit tricky because of how many actors are involved in a Plasma session and some of them needing far-reaching access to system services.

As it turns out problem 1, in particular, is biting Plasma fairly hard. Not exactly a great surprise, after all, relocating (i.e. changing paths of) an installed Plasma isn’t exactly something we’ve done in the past. In fact, it goes further than that as ultimately Plasma’s dependencies need to be relocatable as well, which for example Xwayland is not.

But let’s talk about the snapping itself first. For the purposes of this proof of concept, I simply recycled KDE neon‘s deb builds. Snapcraft, the build tool for snaps, has built-in support for installing debs into a snap, so that is a great timesaver to get things off the ground as it were. Additionally, I used the Plasma Wayland stack instead of the X11 stack. Confinement makes lots more sense with Wayland compared to X11.

Relocatability

Relocatability is a tricky topic. A lot of times one compiles fixed paths into the binary because it is easy to do and it is somewhat secure. Notably, depending on the specific environment at the time of invocation one could be tricked into executing a malicious binary in $PATH instead of the desired one. Explicitly specifying the path is a well-understood safeguard against this sort of problem. Unfortunately, it also means that you cannot move your installed tree anywhere but where it was installed. The relocatable and safe solution is slightly more involved in terms of code as you need to resolve what you want to invoke relative from your location, it being more code and also not exactly trivial to get right is why often times one opts to simply hard-compile paths. This is a problem in terms of packing things into a relocatable snap though. I had to apply a whole bunch of hacks to either resolve binaries from PATH or resolve their location relative. None of these are particularly useful patches but here ya go.

Session

Once all relocatability issues were out of the way I finally had an actual Plasma session. Weeeh!

Confinement

Confining Plasma as a whole is fairly straightforward, albeit a bit of a drag since it’s basically a matter of figuring out what is or isn’t required to make things fly. A lot of logouts and logins is what it takes. Fortunately, snaps have a built-in mechanism to expose DBus session services offered by them. A full blown Plasma session has an enormous amount of services it offers on DBus, from the general purpose notification service to the special interest Plasma Activity service. Being able to expose them efficiently is a great help in tweaking confinement.

Not everything is about DBus though! Sometimes a snap needs to talk with a system service, and obviously, a workspace as powerful as Plasma would need to talk to a bunch of them. Doing advanced access control needs to be done in snapd (the thing that manages installed snaps). Snapd’s interfaces control what is and is not allowed for a snap. To get Plasma to start and work with confinement a bunch of holes need to be poked in the confinement that are outside the scope of existing interface. KWin, in particular, is taking the role of a fairly central service in the Plasma Wayland world, so it needs far-reaching access so it can do its job. Unfortunately, interfaces currently can only be built with snapd’s source tree itself. I made an example interface which covers most of the relevant core services but unless you build a snapd this won’t be particularly easy to try 😉

Summary

All in all, Plasma is easily bundled up once one gets relocatability problems out of the way. And thanks to the confinement control snap and snapd offer, it is also perfectly possible to restrict the workspace through confinement.

I did not at all touch on integration issues however. Running the workspace from a confined bundle is all nice and dandy but not very useful since Plasma won’t have any applications it can launch as they either live on the system or in other snaps. A confined Plasma would know about neither right now.

There is also the lingering question of whether confining like this makes sense at all. Putting all of Plasma into the same snap means this one snap will need lots of permissions and interaction with the host system. At the same time it also means that keeping confinement profiles up to date would be a continuous feat as there are so many things offered and used by this one snap.

One day perhaps we’ll see this in production quality. Certainly not today 🙂

mascot_konqi-app-dev

KDE Applications in Ubuntu Snap Store

Following the recent addition of easy DBus service snapping in the snap binary bundle format, I am happy to say that we now have some of our KDE Applications in the Ubuntu 16.04 Snap Store.

screenshot_ubuntults_2017-01-30_153533

To use them you need to first manually install the kde-frameworks-5 snap. Once you have it installed you can install the applications. Currently we have available:

  • ktuberling – The most awesome game ever!
  • kbruch – Learn how to do fractions (I almost failed at first exercise :O)
  • katomic – Fun and education in one
  • kblocks – Tetris-like game
  • kmplot – Plotting mathematical functions
  • kgeography – An education application for learning states/countries/capitals
  • kollision – Casual ball game
  • kruler – A screen ruler to measure pixel distance on your screen

The Ubuntu 16.04 software center comes with Snap store support built in, so you can simply search for the application and should find a snap version for installation. As we are still working on stabilizing Snap support in Plasma’s Discover, for now, you have to resort to a terminal to test the snaps on KDE neon.

To get started using the command line interface of snap you can do the following:

sudo snap install kde-frameworks-5
sudo snap install kblocks

All currently available snaps are auto generated. For some technical background check out my earlier blog post on snapping KDE applications. In the near future I hope to get manually maintained snaps also built automatically. Also from-git delivery to the edge channel is very much a desired feature still. Stay tuned.

Snapping KDE Applications

This is largely based on a presentation I gave a couple of weeks ago. If you are too lazy to read, go watch it instead 😉

For 20 years KDE has been building free software for the world. As part of this endeavor, we created a collection of libraries to assist in high-quality C++ software development as well as building highly integrated graphic applications on any operating system. We call them the KDE Frameworks.

With the recent advance of software bundling systems such as Snapcraft and Flatpak, KDE software maintainers are however a bit on the spot. As our software is building on such a vast collection of frameworks and supporting technology, the individual size of a distributable application can be quite abysmal.

When we tried to package our calculator KCalc as a snap bundle, we found that even a relatively simple application like this, makes for a good 70 MiB snap to be in a working state (most of this is the graphical stack required by our underlying C++ framework, Qt).
Since then a lot of effort was put into devising a system that would allow us to more efficiently deal with this. We now have a reasonably suitable solution on the table.

The KDE Frameworks 5 content snap.

A content snap is a special bundle meant to be mounted into other bundles for the purpose of sharing its content. This allows us to share a common core of libraries and other content across all applications, making the individual applications just as big as they need to be. KCalc is only 312 KiB without translations.

The best thing is that beside some boilerplate definitions, the snapcraft.yaml file defining how to snap the application is like a regular snapcraft file.

Let’s look at how this works by example of KAlgebra, a calculator and mathematical function plotter:

Any snapcraft.yaml has some global attributes we’ll want to set for the snap

name: kalgebra
version: 16.08.2
summary: ((TBD))
description: ((TBD))
confinement: strict
grade: devel

We’ll want to define an application as well. This essentially allows snapd to expose and invoke our application properly. For the purpose of content sharing we will use a special start wrapper called kf5-launch that allows us to use the content shared Qt and KDE Frameworks. Except for the actual application/binary name this is fairly boilerplate stuff you can use for pretty much all KDE applications.

apps:
  kalgebra:
    command: kf5-launch kalgebra
    plugs:
      - kde-frameworks-5-plug # content share itself
      - home # give us a dir in the user home
      - x11 # we run with xcb Qt platform for now
      - opengl # Qt/QML uses opengl
      - network # gethotnewstuff needs network IO
      - network-bind # gethotnewstuff needs network IO
      - unity7 # notifications
      - pulseaudio # sound notifications

To access the KDE Frameworks 5 content share we’ll then want to define a plug our application can use to access the content. This is always the same for all applications.

plugs:
  kde-frameworks-5-plug:
    interface: content
    content: kde-frameworks-5-all
    default-provider: kde-frameworks-5
    target: kf5

Once we got all that out of the way we can move on to actually defining the parts that make up our snap. For the most part parts are build instructions for the application and its dependencies. With content shares there are two boilerplate parts you want to define.

The development tarball is essentially a fully built kde frameworks tree including development headers and cmake configs. The tarball is packed by the same tech that builds the actual content share, so this allows you to build against the correct versions of the latest share.

  kde-frameworks-5-dev:
    plugin: dump
    snap: [-*]
    source: http://build.neon.kde.org/job/kde-frameworks-5-release_amd64.snap/lastSuccessfulBuild/artifact/kde-frameworks-5-dev_amd64.tar.xz

The environment rigging provide the kf5-launch script we previously saw in the application’s definition, we’ll use it to execute the application within a suitable environment. It also gives us the directory for the content share mount point.

  kde-frameworks-5-env:
    plugin: dump
    snap: [kf5-launch, kf5]
    source: http://github.com/apachelogger/kf5-snap-env.git

Lastly, we’ll need the actual application part, which simply instructs that it will need the dev part to be staged first and then builds the tarball with boilerplate cmake config flags.

  kalgebra:
    after: [kde-frameworks-5-dev]
    plugin: cmake
    source: http://download.kde.org/stable/applications/16.08.2/src/kalgebra-16.08.2.tar.xz
    configflags:
      - "-DKDE_INSTALL_USE_QT_SYS_PATHS=ON"
      - "-DCMAKE_INSTALL_PREFIX=/usr"
      - "-DCMAKE_BUILD_TYPE=Release"
      - "-DENABLE_TESTING=OFF"
      - "-DBUILD_TESTING=OFF"
      - "-DKDE_SKIP_TEST_SETTINGS=ON"

Putting it all together we get a fairly standard snapcraft.yaml with some additional boilerplate definitions to wire it up with the content share. Please note that the content share is using KDE neon’s Qt and KDE Frameworks builds, so, if you want to try this and need additional build-packages or stage-packages to build a part you’ll want to make sure that KDE neon’s User Edition archive is present in the build environments sources.list deb http://archive.neon.kde.org/user xenial main. This is going to get a more accessible centralized solution for all of KDE soon™.

name: kalgebra
version: 16.08.2
summary: ((TBD))
description: ((TBD))
confinement: strict
grade: devel

apps:
  kalgebra:
    command: kf5-launch kalgebra
    plugs:
      - kde-frameworks-5-plug # content share itself
      - home # give us a dir in the user home
      - x11 # we run with xcb Qt platform for now
      - opengl # Qt/QML uses opengl
      - network # gethotnewstuff needs network IO
      - network-bind # gethotnewstuff needs network IO
      - unity7 # notifications
      - pulseaudio # sound notifications

plugs:
  kde-frameworks-5-plug:
    interface: content
    content: kde-frameworks-5-all
    default-provider: kde-frameworks-5
    target: kf5

parts:
  kde-frameworks-5-dev:
    plugin: dump
    snap: [-*]
    source: http://build.neon.kde.org/job/kde-frameworks-5-release_amd64.snap/lastSuccessfulBuild/artifact/kde-frameworks-5-dev_amd64.tar.xz
  kde-frameworks-5-env:
    plugin: dump
    snap: [kf5-launch, kf5]
    source: http://github.com/apachelogger/kf5-snap-env.git
  kalgebra:
    after: [kde-frameworks-5-dev]
    plugin: cmake
    source: http://download.kde.org/stable/applications/16.08.2/src/kalgebra-16.08.2.tar.xz
    configflags:
      - "-DKDE_INSTALL_USE_QT_SYS_PATHS=ON"
      - "-DCMAKE_INSTALL_PREFIX=/usr"
      - "-DCMAKE_BUILD_TYPE=Release"
      - "-DENABLE_TESTING=OFF"
      - "-DBUILD_TESTING=OFF"
      - "-DKDE_SKIP_TEST_SETTINGS=ON"

Now to install this we’ll need the content snap itself. Here is the content snap. To install it a command like sudo snap install --force-dangerous kde-frameworks-5_*_amd64.snap should get you going. Once that is done one can install the kalgebra snap. If you are a KDE developer and want to publish your snap on the store get in touch with me so we can get you set up.

The kde-frameworks-5 content snap is also available in the edge channel of the Ubuntu store. You can try the games kblocks and ktuberling like so:

sudo snap install --edge kde-frameworks-5
sudo snap install --edge --devmode kblocks
sudo snap install --edge --devmode ktuberling

If you want to be part of making the world a better place, or would like a KDE-themed postcard, please consider donating a penny or two to KDE

postcard04