Sunday, July 16, 2017


Packaging up a Go app as a snap


After building my first Python snap I was asked to try to build a Go snap.
There is a video about building Go snaps with snapcraft here so after watching it I gave Kurly a try. 

"Kurly is an alternative to the widely popular curl program and is designed to operate in a similar manner to curl, with select features. Notably, kurly is not aiming for feature parity, but common flags and mechanisms particularly within the HTTP(S) realm are to be expected.".

First of all I got familiar with the code and got it on my PC:

$ git clone https://github.com/davidjpeacock/kurly.git

I entered the kurly directory:

$ cd kurly

 I created a snap directory and entered it:

$ mkdir snap
$ cd snap
I created a snapcraft.yaml file with the go plugin (plugin: go):

name: kurly
version: master
summary: kurly is an alternative to the widely popular curl program.
description: |
                     kurly is designed to operate in a similar manner to curl, with select features. Notably, kurly is not aiming for feature parity, but common flags and mechanisms particularly within the HTTP(S) realm are to be expected.

confinement: devmode

apps:
  kurly:
     command: kurly

parts:
  kurly:
     source: .                                              
     plugin: go
     go-importpath: github.com/davidjpeacock/kurly

The go-importpath keyword is important and tells the checked out source to live within a certain path with 'GOPATH'. This is required to work with absolute imports and path checking.


I went back to the root of the project and launched the snapcraft command to build the snap:

$ cd ..
$ snapcraft

Once snapcraft has finished building you will find a kurly_master_amd64.snap file in the root directory of the project.

I installed the kurly snap in devmode to test it and see if worked well in non confined mode so that then I could run it in confined mode and add the plugs needed by the snap to work properly:

$ sudo snap install --dangerous --devmode kurly_master_amd64.snap


If you run:

$ snap list

you will see the kurly snap installed in devmode:

Name    Version  Rev   Developer  Notes
core    16-2     2312  canonical  -
kurly   master   x1               devmode

Now i tried kurly out a bit to see if it worked well, for instance:

$ kurly -v https://httpbin.org/ip
$  kurly -R -O -L http://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-8.7.1-amd64-netinst.iso

Ok fine, it worked so now I tried to install it in confined mode changing the snapcraft.yaml file accordingly (confinement: strict).

I ran snapcraft again and installed the snap:

$ snapcraft
$ sudo snap install --dangerous kurly_master_amd64.snap

You can see from  the snap list command that the app is installed not in devmode anymore:
$ snap list

Name    Version  Rev   Developer  Notes
core    16-2     2312  canonical  -
kurly   master   x2               -

I tried out kurly again and got some errors:

$ kurly -v https://httpbin.org/ip
> GET /ip HTTP/1.1
> User-Agent [Kurly/1.0]
> Accept [*/*]
> Host [httpbin.org]
*Error: Unable to get URL; Get https://httpbin.org/ip: dial tcp: lookup httpbin.org: Temporary failure in name resolution

From the error I could understand that kurly needs the network plug (plugs: [network]) so I changed the snapcraft.yaml file so:

name: kurly
version: master
summary: kurly is an alternative to the widely popular curl program.
description: |
                     kurly is designed to operate in a similar manner to curl, with select features. Notably, kurly is not aiming for feature parity, but common flags and mechanisms particularly within the HTTP(S) realm are to be expected.

confinement: strict

apps:
  kurly:
     command: kurly
     plugs: [network]

parts:
  kurly:
     source: .
     plugin: go
     go-importpath: github.com/davidjpeacock/kurly


 I ran snapcraft and installed the kurly snap again:

$ snapcraft
$ sudo snap install --dangerous kurly_master_amd64.snap
But when I ran a kurly command for downloading a file I got another error:

$kurly -R -O -L http://cdimage.debian.org/debian-cd/current/amd64/iso-cd/debian-8.7.1-amd64-netinst.iso
*Error: Unable to create file 'debian-8.7.1-amd64-netinst.iso' for output
Kurly could not write the file to my home direcotry, so I added the home plug to the snapcraft.yaml file, ran snapcraft and installed the snap again.
This time kurly worked fine.

So here's the final snapcraft.yaml file ready for a PR in Git Hub:
 
name: kurly
version: master
summary: kurly is an alternative to the widely popular curl program.
description: |
                     kurly is designed to operate in a similar manner to curl, with select features. Notably, kurly is not aiming for feature parity, but common flags and mechanisms particularly within the HTTP(S) realm are to be expected.

confinement: strict

apps:
  kurly:
     command: kurly
     plugs: [network, home]

parts:
  kurly:
     source: .
     plugin: go
     go-importpath: github.com/davidjpeacock/kurly

That's it.
The Go snap is done!



 

Saturday, July 15, 2017


My first Snap 


I have been testing for Ubuntu for quite a while so I decided to change a bit and give packaging apps  a go, so here I am writing about how I managed to create my first Python Snap.

Snapcraft is new way to package apps and so I thought it would be nice to learn about it, so I went to the Snapcraft site https://snapcraft.io/ and found out, that with Snapcraft you can:
"Package any app for every Linux desktop, server, cloud or device, and deliver updates directly".

"A snap is a fancy zip file containing an application together with its dependencies, and a description of how it should safely run on your system, especially the different ways it should talk to other software.
Snaps are designed to be secure, sandboxed, containerised applications isolated from the underlying system and from other applications. Snaps allow the safe installation of apps from any vendor on mission critical devices and desktops."

So if you got an app that is too new for the Ubuntu archive, you can get it in the Snaps store and install it on Ubuntu or any other Linux distribution  that supports Snaps.

I started by getting in touch with the guys in the Snapcraft channel on Rocket chat:  https://rocket.ubuntu.com/channel/snapcraft that told me to how to start.

First of all I read the "Snap a Python App" tutorial and then applied what I learned to Lbryum a Lightweight lbrycrd client, a fork of the Electrum bitcoin client.

I couldn't believe how easy it was, I am not a developer but  I know how to code and I know a bit of Python.

First of all you need to get familiar with the code of the app you want to snap so I got Lbryum code from Git Hub:

$ sudo apt install git
$ git clone https://github.com/lbryio/lbryum.git


Once I got familiar with the code I installed Snapcraft:

 $ sudo apt install snapcraft

I generated a Snapcraft projet in the lbryum root directory with:

$ snapcraft init

If everything works, you will get this output:

Created snap/snapcraft.yaml.
Edit the file to your liking or run `snapcraft` to get started
 
Now if you check the content of the project's directory, it has been populated with  a "snap" folder containing the snapcraft.yaml file  that I modified  for creating the Lbryum app snap:


name: lbryum 
version: 'master'
summary: Lightweight lbrycrd client
description: |
        Lightweight lbrycrd client, a fork of the Electrum bitcoin client
grade: stable 
confinement: devmode 

apps:
  lbryum:
     command: lbryum
  parts:
  lbryum:
     source: . 
     plugin: python
      
Here is the documentation so you can find the meaning of the fields in the snapcraft.yaml file (the fields are quite self explanatory): 



To find out what plugs or parts your app needs, you need to run snapcraft and debug it until you find out all that's needed, so I tried to build it at this stage to make sure that I had the basic definition correct. 

I ran this command from the root of the lbryum-snap directory:

$ snapcraft prime

Obviously I had some errors  that made me make some changes to the snapcraft.yaml file. I found out that the app needs Python2 so I added "python-version: python2" and I specified to use the requirements.txt file of the Lbryum project for the packages needed during install (requirements: requirements.txt):
 
name: lbryum 
version: 'master'
summary: Lightweight lbrycrd client
description: |
        Lightweight lbrycrd client, a fork of the Electrum bitcoin client
grade: stable 
confinement: devmode 

apps:
  lbryum:
     command: lbryum
parts:
  lbryum:
     source: . 
     plugin: python
     requirements: requirements.txt
     python-version: python2
I  ran:

$ snapcraft clean 

and 
 
$snapcraft prime
 again.



Success!!!! :)

Ok, so now I tried the snap with:

$ sudo snap try --devmode prime/
$ lbryum daemon start
$ lbryum version
$ lbryum commands

played a bit around with it to see if the snap worked well.

Now before shipping the snap or opening a PR in Git Hub, we need to turn confinement on and see if the snap works or if it needs further changes to the snapcraft.yaml file.

So I changed the confinement from devmode to strict (confinement: strict) and then ran:

$ snapcraft

I got this output:

Skipping pull lbryum (already ran)
Skipping build lbryum (already ran)
Skipping stage lbryum (already ran)
Skipping prime lbryum (already ran)
Snapping 'lbryum' -                                                           
Snapped lbryum_master_amd64.snap
I installed the snap:

$ sudo snap install --dangerous lbryum_master_amd64.snap

When I ran lbryum I started getting a lot of errors that made me understand that lbryum needs to access the network for working so I added the network plug (plugs: [network]) : 
name: lbryum 
version: 'master'
summary: Lightweight lbrycrd client
description: |
        Lightweight lbrycrd client, a fork of the Electrum bitcoin client
grade: stable 
confinement: strict 

apps:
  lbryum:
     command: lbryum
     plugs: [network]
parts:
  lbryum:
     source: . 
     plugin: python
     requirements: requirements.txt
     python-version: python2
I ran:

$ snapcraft

again and installed the snap again:

$ sudo snap install --dangerous lbryum_master_amd64.snap
$ lbryum daemon start
$ lbryum version
$ lbryum commands

Works!

Fine, so I opened a PR on Git Hub proposing my snapcraft.yaml file so that they could use it for creating a Lbryum snap.



If you need to debug your snap for finding what is wrong there is also a debugging tool for debugging confined apps:

https://snapcraft.io/docs/build-snaps/debugging


Thats it. End of my first snap adventure :).