Previously, if you wanted to distribute your application in Ubuntu or Debian, you had to package it as a deb. This was a rather long and tedious process that scared many people off. Snapcraft attempts to solve that problem. In this talk, Nathan Handler will demonstrate how you can convert an application to a Snap within mere minutes. The Snap can then be uploaded to the store where the rest of the world can discover and install it. Snapcraft comes with all of the tooling necessary to configure, build, and upload the Snap, greatly simplifying and speeding up the once challenging process. This talk will take the form of a step by step guide to taking an everyday application, preparing, builiding, and testing the snap, and then uploading it to the store. You will then be able to follow the same steps for thousands of other applications.
2. So here is who I am, my Twitter handle is also on
the bottom of each slide.
Before I get started, I want to note that while I am
an Ubuntu Developer, I am not employed by
Canonical or directly involved with any of the
development around Snaps
With that out of the way, I realize most of you could
care less about who I am, you are probably here
because you are interested in learning about Snaps
So let's get started
Who am I?
• Nathan Handler
• Ubuntu/Debian GNU/Linux Developer
• freenode IRC staff member
• nhandler@ubuntu.com / @nathanhandler
• Yelp Site Reliability Engineer
@NathanHandler 2
3. The Merriam-Webster Dictionary
defines a snap as a device that
fastens something by closing or
locking with a short, sharp sound
But while these snaps are extremely
useful, they are probably not the
type you are here to learn about
What is a Snap?
a device that fastens something by closing or locking with a short,
sharp sound
— Merriam-Webster Dic0onary
@NathanHandler 3
4. Searching for Snaps on
Google will return many results
for this ghostly service
But this is also probably not
the one you are here to learn
about
What is a Snap?
@NathanHandler 4
5. So what really is a Snap?
What is a Snap?
@NathanHandler 5
6. Today, we will look at an application called Wuzz.
Created by Adam Tauber (asciimoo)
asciimoo@gmail.com https://github.com/
asciimoo/wuzz
Interactive cli tool for HTTP inspection
Wuzz command line arguments are similar to
cURL's arguments, so it can be used to inspect/
modify requests copied from the browser's
network inspector with the "copy as cURL"
feature.
Wuzz
@NathanHandler 6
7. Rather than the classic method of
copying boilerplate configuration
from an existing project,
snapcraft init will give you a
simple starting point.
It does NOT try to be smart and fill
in the blanks like dh-make
$ snapcra) init
name: my-snap-name # you probably want to 'snapcraft register <name>'
version: '0.1' # just for humans, typically '1.2+git' or '1.3.2'
summary: Single-line elevator pitch for your amazing snap # 79 char long summary
description: |
This is my-snap's description. You have a paragraph or two to tell the
most important story about your snap. Keep it under 100 words though,
we live in tweetspace and your description wants to look good in the snap
store.
grade: devel # must be 'stable' to release into candidate/stable channels
confinement: devmode # use 'strict' once you have the right plugs and slots
parts:
my-part:
# See 'snapcraft plugins'
plugin: nil
@NathanHandler 7
8. The first thing we need to
specify is the name of our
snap
snapcra'.yaml
name: my-snap-name # you probably want to 'snapcraft register <name>'
version: '0.1' # just for humans, typically '1.2+git' or '1.3.2'
summary: Single-line elevator pitch for your amazing snap # 79 char long summary
description: |
This is my-snap's description. You have a paragraph or two to tell the
most important story about your snap. Keep it under 100 words though,
we live in tweetspace and your description wants to look good in the snap
store.
grade: devel # must be 'stable' to release into candidate/stable channels
confinement: devmode # use 'strict' once you have the right plugs and slots
parts:
my-part:
# See 'snapcraft plugins'
plugin: nil
@NathanHandler 8
9. We are going to name it the
same as the upstream
application, wuzz
snapcra'.yaml
name: wuzz
version: '0.1' # just for humans, typically '1.2+git' or '1.3.2'
summary: Single-line elevator pitch for your amazing snap # 79 char long summary
description: |
This is my-snap's description. You have a paragraph or two to tell the
most important story about your snap. Keep it under 100 words though,
we live in tweetspace and your description wants to look good in the snap
store.
grade: devel # must be 'stable' to release into candidate/stable channels
confinement: devmode # use 'strict' once you have the right plugs and slots
parts:
my-part:
# See 'snapcraft plugins'
plugin: nil
@NathanHandler 9
10. If you paid attention to the comment on the
previous slide, it said that we probably want to
register the name
This can be done with the snapcraft
register command
This is sort of like the Debian Intent To Package
(ITP) email
Since the upstream maintainer is currently not
interested in publishing his own snaps, I am
currently doing so on their behalf
$ snapcra) register wuzz
We always want to ensure that users get the software they expect
for a particular name.
If needed, we will rename snaps to ensure that a particular name
reflects the software most widely expected by our community.
For example, most people would expect ‘thunderbird’ to be published by
Mozilla. They would also expect to be able to get other snaps of
Thunderbird as 'thunderbird-$username'.
Would you say that MOST users will expect 'wuzz' to come from
you, and be the software you intend to publish there? [y/N]: y
Registering wuzz.
Congrats! You are now the publisher of 'wuzz'.
@NathanHandler 10
11. Next up is the version number.
As the comment says, this version
number if only for the benefit of humans
None of the automated tools care about it
It is NOT the same as a traditional Debian
version number
It is a freeform string, so values such as
master or latest are perfectly valid
snapcra'.yaml
name: wuzz
version: '0.1' # just for humans, typically '1.2+git' or '1.3.2'
summary: Single-line elevator pitch for your amazing snap # 79 char long summary
description: |
This is my-snap's description. You have a paragraph or two to tell the
most important story about your snap. Keep it under 100 words though,
we live in tweetspace and your description wants to look good in the snap
store.
grade: devel # must be 'stable' to release into candidate/stable channels
confinement: devmode # use 'strict' once you have the right plugs and slots
parts:
my-part:
# See 'snapcraft plugins'
plugin: nil
@NathanHandler 11
12. We are going to be packaging a
particular commit of wuzz
When doing this, I use the commit sha
with an iteration number at the end
The iteration is to allow me to call out
changes in the snap itself that don't
involve changes to the wuzz source
snapcra'.yaml
name: wuzz
version: 'dd696dc-1'
summary: Single-line elevator pitch for your amazing snap # 79 char long summary
description: |
This is my-snap's description. You have a paragraph or two to tell the
most important story about your snap. Keep it under 100 words though,
we live in tweetspace and your description wants to look good in the snap
store.
grade: devel # must be 'stable' to release into candidate/stable channels
confinement: devmode # use 'strict' once you have the right plugs and slots
parts:
my-part:
# See 'snapcraft plugins'
plugin: nil
@NathanHandler 12
13. The summary is similar to the short
description in traditional packaging
Typically, you want to think of the
summary as filling in the gap in:
wuzz is a <blank>
This summary shows up when
searching for snaps
snapcra'.yaml
name: wuzz
version: 'dd696dc-1'
summary: Single-line elevator pitch for your amazing snap # 79 char long summary
description: |
This is my-snap's description. You have a paragraph or two to tell the
most important story about your snap. Keep it under 100 words though,
we live in tweetspace and your description wants to look good in the snap
store.
grade: devel # must be 'stable' to release into candidate/stable channels
confinement: devmode # use 'strict' once you have the right plugs and slots
parts:
my-part:
# See 'snapcraft plugins'
plugin: nil
@NathanHandler 13
14. In this case, we will borrow
upstrem's short description
from Github
snapcra'.yaml
name: wuzz
version: 'dd696dc-1'
summary: interactive cli tool for HTTP inspection
description: |
This is my-snap's description. You have a paragraph or two to tell the
most important story about your snap. Keep it under 100 words though,
we live in tweetspace and your description wants to look good in the snap
store.
grade: devel # must be 'stable' to release into candidate/stable channels
confinement: devmode # use 'strict' once you have the right plugs and slots
parts:
my-part:
# See 'snapcraft plugins'
plugin: nil
@NathanHandler 14
15. This is the long description of the snap. It
is where you can go into a bit more detail
about what it is used for.
The pipe (|) has no special meaning for
snapcraft; it is part of the yaml spec and
means that a literal block of text will follow.
It allows us to have multi-line descriptions
that are nicely wrapped
snapcra'.yaml
name: wuzz
version: 'dd696dc-1'
summary: interactive cli tool for HTTP inspection
description: |
This is my-snap's description. You have a paragraph or two to tell the
most important story about your snap. Keep it under 100 words though,
we live in tweetspace and your description wants to look good in the snap
store.
grade: devel # must be 'stable' to release into candidate/stable channels
confinement: devmode # use 'strict' once you have the right plugs and slots
parts:
my-part:
# See 'snapcraft plugins'
plugin: nil
@NathanHandler 15
16. Once again, we borrow the not so
great description from upstream
If someone feels up to writing a
better description, they should
submit a pull request to upstream
and this snap
snapcra'.yaml
name: wuzz
version: 'dd696dc-1'
summary: interactive cli tool for HTTP inspection
description: |
Wuzz command line arguments are similar to cURL's arguments,
so it can be used to inspect/modify requests copies from the browser's
network inspector with the "copy as cURL" feature.
grade: devel # must be 'stable' to release into candidate/stable channels
confinement: devmode # use 'strict' once you have the right plugs and slots
parts:
my-part:
# See 'snapcraft plugins'
plugin: nil
@NathanHandler 16
17. The grade is a bit of a saftey check to
prevent you from uploading a potentially
buggy snap to the 'stable' channel
It can only have one of two values:
devel or stable
Only stable snaps can be released to
the candidate/stable channels
We will talk more about channels in a bit
snapcra'.yaml
name: wuzz
version: 'dd696dc-1'
summary: interactive cli tool for HTTP inspection
description: |
Wuzz command line arguments are similar to cURL's arguments,
so it can be used to inspect/modify requests copies from the browser's
network inspector with the "copy as cURL" feature.
grade: devel # must be 'stable' to release into candidate/stable channels
confinement: devmode # use 'strict' once you have the right plugs and slots
parts:
my-part:
# See 'snapcraft plugins'
plugin: nil
@NathanHandler 17
18. For now, we will leave it as
devel (as the snap is untested
and far from ready)
We will change this later on
snapcra'.yaml
name: wuzz
version: 'dd696dc-1'
summary: interactive cli tool for HTTP inspection
description: |
Wuzz command line arguments are similar to cURL's arguments,
so it can be used to inspect/modify requests copies from the browser's
network inspector with the "copy as cURL" feature.
grade: devel
confinement: devmode # use 'strict' once you have the right plugs and slots
parts:
my-part:
# See 'snapcraft plugins'
plugin: nil
@NathanHandler 18
19. confinement is a new concept for those used to
traditional deb packaging
By default, snaps use a 'strict' confinement which
grants RW access to the snap's own install space
Interfaces can be used to grant additional
permissions
devmode is same as strict but turns denials into
warnings in /var/log/syslog
classic is like traditional debs. / in snap is / on
filesystem. Manual review
snapcra'.yaml
name: wuzz
version: 'dd696dc-1'
summary: interactive cli tool for HTTP inspection
description: |
Wuzz command line arguments are similar to cURL's arguments,
so it can be used to inspect/modify requests copies from the browser's
network inspector with the "copy as cURL" feature.
grade: devel
confinement: devmode # use 'strict' once you have the right plugs and slots
parts:
my-part:
# See 'snapcraft plugins'
plugin: nil
@NathanHandler 19
20. Normally, you would iterate
with your snap in devmode,
but for for this simple snap, we
will use strict from the start
snapcra'.yaml
name: wuzz
version: 'dd696dc-1'
summary: interactive cli tool for HTTP inspection
description: |
Wuzz command line arguments are similar to cURL's arguments,
so it can be used to inspect/modify requests copies from the browser's
network inspector with the "copy as cURL" feature.
grade: strict
confinement: strict
parts:
my-part:
# See 'snapcraft plugins'
plugin: nil
@NathanHandler 20
21. The 'parts' section is the core
part of this file
It specifies where to find the
upstream application, what
format it is stored in, and how
to build it.
snapcra'.yaml
name: wuzz
version: 'dd696dc-1'
summary: interactive cli tool for HTTP inspection
description: |
Wuzz command line arguments are similar to cURL's arguments,
so it can be used to inspect/modify requests copies from the browser's
network inspector with the "copy as cURL" feature.
grade: strict
confinement: strict
parts:
my-part:
# See 'snapcraft plugins'
plugin: nil
@NathanHandler 21
22. In this case, wuzz is a golang
application that we are fetching from
a git repository hosted on github
As noted earlier, we want to pin this
build to a specific commit.
Ommitting the source-commit will
fetch 'master'. Tags can also be used.
snapcra'.yaml
name: wuzz
version: 'dd696dc-1'
summary: interactive cli tool for HTTP inspection
description: |
Wuzz command line arguments are similar to cURL's arguments,
so it can be used to inspect/modify requests copies from the browser's
network inspector with the "copy as cURL" feature.
grade: strict
confinement: strict
parts:
wuzz:
plugin: go
source: https://github.com/asciimoo/wuzz
source-type: git
source-commit: dd696dc6e014e08b6042a71dca600356eb3156c2
go-importpath: github.com/asciimoo/wuzz
@NathanHandler 22
23. We need to add one more section
that is not present in the template
While we could build the snap
without this part, it is necessary to
expose the 'wuzz' command to
the rest of the system to make it
easy to run.
snapcra'.yaml
apps:
wuzz:
command: wuzz
@NathanHandler 23
24. Final snapcraft.yaml
snapcra'.yaml
name: wuzz
version: 'dd696dc-1'
summary: interactive cli tool for HTTP inspection
description: |
Wuzz command line arguments are similar to cURL's arguments,
so it can be used to inspect/modify requests copies from the browser's
network inspector with the "copy as cURL" feature.
confinement: strict
grade: stable
apps:
wuzz:
command: wuzz
parts:
wuzz:
plugin: go
source: https://github.com/asciimoo/wuzz
source-type: git
source-commit: dd696dc6e014e08b6042a71dca600356eb3156c2
go-importpath: github.com/asciimoo/wuzz
@NathanHandler 24
25. pull, build, stage, prime, snap
Unfortunately, this will build
using your host system
Can lead to odd build failures
when it comes time to share
your snap or build it elsewhere
$ snapcra) snap
@NathanHandler 25
26. Traditional deb packaging requires setting
up a minimal build environment with a tool
such as pbuilder or sbuilder. Or some
people bypass this by always using a PPA
snapcraft provides a simple solution for
building your snap in a clean, minimal
environment that does not pull in cruft from
the host system
It uses an lxd container to do the build
$ snapcra) cleanbuild
@NathanHandler 26
27. You now have a shiny
new .snap file to play with.
The 'snap install' command
can be used to install it
$ sudo snap install *.snap
@NathanHandler 27
28. Hmm...That didn't work. Why
not? We just built our snap
locally, so there is no signature
Let's just bypass that check
for now.
error: cannot find signatures with
metadata for snap
"wuzzdd696dc-1amd64.snap"
@NathanHandler 28
29. Install the given snap file even if there are no
pre-acknowledged signatures for it, meaning
it was not verified and could be dangerous
This will allow us to install our freshly built
snap
Thanks to the apps definition we added
early, we will get a nice helpful 'wuzz'
command in our PATH that we can run
Let's give that a try
--dangerous
@NathanHandler 29
30. If we run wuzz, the application
does launch.
Uh, oh, what's that error
popping up?
Temporary failure in name resolu0on
@NathanHandler 30
31. It looks like we can't make any
web requests
Why would that be? Does
wuzz have a bug in it?
Response error: Get h-ps://
h-pbin.org/get: dial tcp: lookup
h-pbin.org: Temporary failure in
name resolu=on
@NathanHandler 31
32. It all goes back to us specifying
confinement: strict earlier
As a form of security, this places a number
of restrictions on the actions a snap can take
One of those restrictions is an inability to
make network connections
Wuzz would be pretty useless if it couldn't
make web requests.
Luckily, there is an easy solution.
confinement: strict
@NathanHandler 32
33. snaps have the ability to plug into
a number of interfaces.
In this case, we specify that we
want to plug into the network
interface, which allows us to access
the network as a client
Let's try running it again
Plugs / Interfaces
apps:
wuzz:
command: wuzz
plugs:
- network
@NathanHandler 33
35. I promised I would explain the concept of channels.
They aren't quite the same as Debian's unstable/stable/
testing concept
They don't represent different versions of Ubuntu or
anything like that
Instead, they are designed to be a representation of the
stability of the snap
* stable Tested, polished, appear in searches
* candidate Final testing of uploads before they migrate to
stable
* beta: Preview releases of semi-stable changes
* edge: Most recent, untested
Channels
• stable
• candidate
• beta
• edge
@NathanHandler 35
36. So how does the grade come into play?
We specified a grade of devel before.
Combined with our strict confinement,
that allows us to only upload to the
beta and edge channels
Since we want to target the stable
channel, we will need to set the grade
to stable as well
grade: devel or stable
confinement:
strict
confinement:
classic
confinement:
devmode
grade: stable all channels all channel beta and edge
only
grade: devel beta and edge
only
beta and edge
only
beta and edge
only
@NathanHandler 36
37. Our snap is now uploaded, but
it is not released into a
particular channel
This means users can't find/
install it
Let's fix that
Upload
$ snapcraft push wuzz_dd696dc-1_amd64.snap
Uploading wuzz_dd696dc-1_amd64.snap [====================] 100%
Processing ...
Ready to release!
Revision 1 of 'wuzz' created.
@NathanHandler 37
38. Release takes a few arguments.
First, the snap name. This is the name we registered in the snap
store at the start.
Notice that we are using a snap name rather than the path to
the snap file (since it is now uploaded)
Second is the revision number. As noted earlier, the version
number is just for humans.
Each time a new version of the snap is uploaded, the revision
number gets automatically incremented (starting at 1)
Finally, you specify the name of the channel to release the snap
into. Normally, you would probably work your way up from the
less stable channels, but for the sake of this presentation, we
will go straight to stable
snapcra' release wuzz 1 stable
@NathanHandler 38
40. Just like the application itself, your snap has source code.
This is often your snapcraft.yaml file and any other helper scripts that go with it.
Create a VCS repository somewhere (I'd recommend either Launchpad or Github)
Find some co-maintainers. Even for a simple snap, having more than one person
looking out for it is in everyone's best interest.
There have been a number of other sessions that have gone over the many benefits
that Continuous Integration/Deployment Pipelines provide
In our case, the pipeline will give us confidence that it is still possible to rebuild our snap
It is also very simple to setup these automated builds in Travis or for any github
repository with build.snapcraft.io. Launchpad also has support for doing continuous
builds of a hosted git repository
Once you have your snap being built continously, the last step is to adjust those builds
to automatically publish and release yoru snaps
I typically try to set my snaps to automatically build/release the latest commits to
'master' to the 'edge' channel
I still use a CI pipeline for testing my stable releases, but I manually test/update these
branches.
Next Steps
1. Share your snap source
2. Find some co-maintainers
3. Create a Con9nuous Integra9on/Deployment Pipeline to publish
your snap
4. Release your snap to mul9ple channels
@NathanHandler 40
41. Pay attention to those missing
Build-Dependencies
We would need to package
those applications as well if we
wanted to be able to build
wuzz
Comparison to Tradi.onal Packaging
$ dh-make-golang github.com/asciimoo/wuzz
Downloading "github.com/asciimoo/wuzz/..."
Determining upstream version number
Package version is "0.4.0+git20171018.6.92b4636"
Determining package type
Assuming you are packaging a program (because "github.com/asciimoo/wuzz" defines a main package), use -type to override
Determining dependencies
Build-Dependency "golang-github-x86kernel-htmlcolor-dev" is not yet available in Debian
Build-Dependency "golang-github-tidwall-gjson-dev" is not yet available in Debian
Build-Dependency "golang-github-alessio-shellescape-dev" is not yet available in Debian
Could not determine long description for "github.com/asciimoo/wuzz": unexpected HTTP status: got 403, want 200
Could not determine copyright for "github.com/asciimoo/wuzz": parsing time "" as "2006-01-02T15:04:05Z": cannot parse "" as "2006"
Could not determine author for "github.com/asciimoo/wuzz": parsing time "" as "2006-01-02T15:04:05Z": cannot parse "" as "2006"
Could not determine long description for "github.com/asciimoo/wuzz": unexpected HTTP status: got 403, want 200
Packaging successfully created in /home/nhandler/wuzz/wuzz
Resolve all TODOs in itp-wuzz.txt, then email it out:
sendmail -t < itp-wuzz.txt
Resolve all the TODOs in debian/, find them using:
grep -r TODO debian
To build the package, commit the packaging and use gbp buildpackage:
git add debian && git commit -a -m 'Initial packaging'
gbp buildpackage --git-pbuilder
To create the packaging git repository on alioth, use:
ssh git.debian.org "/git/pkg-go/setup-repository wuzz 'Packaging for wuzz'"
Once you are happy with your packaging, push it to alioth using:
git push git+ssh://git.debian.org/git/pkg-go/packages/wuzz.git --tags master pristine-tar upstream
@NathanHandler 41
42. It was quite nice of the script to generate this Intent to
Package email template for us
For those not familiar, the ITP is designed to inform
other Debian Developers that you plan to package
this application.
It helps avoid duplication of efforts and allows other
people to chime in with comments
I've helped quite a few people start packaging for
Debian over the years.
Trying to help them get a working sendmail is a
horrible task for both them and me.
Intent To Package
$ cat ./itp-wuzz.txt
From: "Nathan Handler" <nhandler@debian.org>
To: submit@bugs.debian.org
Subject: ITP: wuzz --
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
X-Debbugs-CC: debian-devel@lists.debian.org, pkg-go-maintainers@lists.alioth.debian.org
Package: wnpp
Severity: wishlist
Owner: Nathan Handler <nhandler@debian.org>
* Package name : wuzz
Version : 0.4.0+git20171018.6.92b4636-1
Upstream Author : TODO
* URL : https://github.com/asciimoo/wuzz
* License : TODO
Programming Lang: Go
Description :
TODO: long description
TODO: perhaps reasoning
@NathanHandler 42
43. The debian/rules file is where
traditional debian packages
specified how to build the
upstream source code
They have gotten a lot cleaner
and simpler over the years
cat debian/rules
#!/usr/bin/make -f
%:
dh $@ --buildsystem=golang --with=golang
@NathanHandler 43