Learn snapcraft by example – multi-app client-server snap
by Igor Ljubuncic on 27 March 2020
Over the past few months, we published a number of articles showing how to snap desktop applications written in different languages – Rust, Java, C/C++, and others. In each one of these zero-to-hero guides, we went through a representative snapcraft.yaml file and highlighted the specific bits and pieces developers need to successfully build a snap.
Today, we want to diverge from this journey and focus on the server side of things. We will give you an overview of a snapcraft.yaml with two interesting components: a) it will have more than one application; typically, snaps come with one application inside b) it will have a simple background service, to which other applications can connect. Let’s have a look.
The basics
Here’s the relevant part of the snapcraft.yaml file:
apps:
borg:
command: bin/borg
daemon: simple
restart-condition: on-abnormal
plugs:
- home
- network
- network-bind
locutus:
command: bin/locutus
plugs:
- home
- network
What do we have here?
First, we declare the server part of the bundle – an application named borg. It is a simple daemon, and the restart condition will be “on-abnormal” – the service states are based on values returned from systemd.
Second, for the service to work, it needs to be able to bind to network ports, which is why we’re defining the network-bind interface. Please note that if your application needs to bind to a privileged port, you will need sudo to be able to make it run correctly. The use of snaps does not change the underlying security requirements.
We also define access to home (so that the service can read a configuration file, for instance), and network, so it can communicate over the network. This is necessary in addition to the bind declaration, unless your service is designed to only run and listen on localhost.
In the second part, we declare the client part of the bundle – an application that only needs access to the home directory (configuration files, certificates, etc.), and network. This way, you can run the component applications of this snap on various systems, in a classic client-server model.
How to invoke a multi-app snap?
The one question you may have is – with multiple apps inside a snap, how does the user run them? When the app name matches the snap name, e.g.: igor, you only need to run “igor” or “/snap/bin/igor”. Here, the invocation is slightly different. Let’s say the snap is called “picard”. In this case, for the server application, you would run:
picard.borg
Similarly, for the client application:
picard.locutus
Users can manually create aliases to work around this. Similarly, developers can request automatic aliases for their software from the Snap Store team, in cases where there is no obvious namespace clash. This can lead to a smoother, more streamlined user experience. In this example, borg will be mapped to picard.borg, and locutus will be mapped to picard.locutus.
Summary
We hope today’s guide sheds clarity on how to make somewhat more elaborate use cases with snaps, including multi-apps and client-server scenarios. Of course, creating the snapcraft.yaml is only part of the work, you also need to make sure that your software parts can communicate with one another, and do their job correctly. However, at least you have the snapcraft side of things covered.
If you have any comments, or perhaps requests on future articles that would help you snap your application (or a complex service), please join our forum for a discussion.
No Star Trek TNG references were aliased in the creation of this article.
Photo by Marlon Corona on Unsplash.