Go (golang) app as snap (for Kiosk use)

We build custom web apps in Go as kiosks for our customers, usually deployed on Kubuntu with Ansible for ease of configuration as a kiosk (hide desktop etc).

We’ve just become aware Ubuntu Core & Ubuntu Frame, which fits our use case much better. However, where our app works as a service normally, I am struggling to package it up as a snap - I’ve googled through the documentation, and am finding it sparse or limited, despite us being a pretty simple use case.

Our current service based app architecture is:

/opt/experience <- service binary (go)
/opt/ui-files/ <- bundled HTML/JS files served by service
/opt/config/ <- app configuration files

We use private repos for our apps (and some deps), which seems like a challenge for the go plugin to handle, so have bypassed that step for now in favour of keeping our original build process and resulting tar.gz which contains:

/experience/server <- service binary
/experience/ui-files/ <- bundled web app

with config files just in the root of the CI process to be copied


I can’t seem to get the basics working to start debugging the process. Current snapcraft file looks like:

name: kiosk-experience
base: core22
version: "test"
summary: A Summary
description: |
      Interactive Kiosk

confinement: devmode
grade: stable

    source: ./ansible/files/experience/experience-release-v0.57.tar.gz
    plugin: dump
    # organize: 
    #   experience/server: bin/server

    command: experience/server
      - network

Which results in som e lint warnings (for a future question…!):

Lint warnings:                                                                                                                                                                                                                                                                
- library: experience: missing dependency 'libMagickCore-6.Q16.so.6'. (https://snapcraft.io/docs/linters-library)                                                                                                                                                             
- library: experience: missing dependency 'libMagickWand-6.Q16.so.6'. (https://snapcraft.io/docs/linters-library)                                                                                                                                                             
- library: experience: missing dependency 'libasound.so.2'. (https://snapcraft.io/docs/linters-library)          

But what seems more important:

Cannot pack snap file: Command '['snap', 'pack', '--filename', '1421-malibu_test_amd64.snap', '--compression', 'xz', PosixPath('/root/prime'), PosixPath('/root/project')]' returned non-zero exit status 1. (2023/07/05 07:48:18.418754 container.go:215: in snap "kiosk-experience": path "experience/server" does not exist
2023/07/05 07:48:18.418801 container.go:215: in snap "kiosk-experience": path "experience" does not exist
error: cannot pack "/root/prime": snap is unusable due to missing files)                        
Failed to execute pack in instance.

I’m keen to get my head around this process, or understand if this is not the right thing to be doing, but don’t seem to have found the right examples to learn from. The app needs to access webcam, USB and printers on the host device - all of which I think is possible. The snap needs to override the UI and server parts on new release, but leave the config alone in a place we can edit using ansible.

Any pointers would be great.

lets start with the linter warnings… to fulfill the requirements you can use the apt-file command to find the matching debs for these libraries:

$ apt-file search libMagickCore-6.Q16.so.6
libmagickcore-6.q16-6: /usr/lib/x86_64-linux-gnu/libMagickCore-6.Q16.so.6
libmagickcore-6.q16-6: /usr/lib/x86_64-linux-gnu/libMagickCore-6.Q16.so.6.0.0
$ apt-file search libMagickWand-6.Q16.so.6
libmagickwand-6.q16-6: /usr/lib/x86_64-linux-gnu/libMagickWand-6.Q16.so.6
libmagickwand-6.q16-6: /usr/lib/x86_64-linux-gnu/libMagickWand-6.Q16.so.6.0.0
$ apt-file search libasound.so.2
libasound2: /usr/lib/x86_64-linux-gnu/libasound.so.2
libasound2: /usr/lib/x86_64-linux-gnu/libasound.so.2.0.0
liboss4-salsa-asound2: /usr/lib/x86_64-linux-gnu/libasound.so.2

with that info you can now craft your stage-packages: list for the kiosk-experience: part… like:

      - libmagickcore-6.q16-6
      - libmagickwand-6.q16-6
      - libasound2

that should quieten the linter and your snap should now bundle the required libs …

the packing error indicates that your experience dir does not end up in the prime directory properly … run snapcraft with --debug, that should give you a shell inside the build container, then inspect the parts/kiosk-experience/install dirs and the prime/ dir as well … the process here is:

  • pull the tarball from the location source: defines and unpack it to parts/<partname>/src
  • move content of <partname>/src/ to <partname>/install/
  • move content of <partname>/install/ into the toplevel stage/ directory
  • at the end move content from stage/ to prime/

your build log should show what snapcraft is doing here (you might need to set --verbosity=debug in your snapcraft call to get more output though) and via the shell in the environment after the build fails, you should be able to inspect the respective dirs and where things get lost.

Thank you for the response. I’m getting somewhere!

That all makes sense - the linter warnings have changed to: Lint warnings:

- library: libfftw3_omp.so.3: unused library 'usr/lib/x86_64-linux-gnu/libfftw3_omp.so.3.5.8'. (https://snapcraft.io/docs/linters-library)                                                                                                                                    
- library: libfftw3_threads.so.3: unused library 'usr/lib/x86_64-linux-gnu/libfftw3_threads.so.3.5.8'. (https://snapcraft.io/docs/linters-library)                                                                                                                            
- library: libicuio.so.70: unused library 'usr/lib/x86_64-linux-gnu/libicuio.so.70.1'. (https://snapcraft.io/docs/linters-library)                                                                                                                                            
- library: libicutest.so.70: unused library 'usr/lib/x86_64-linux-gnu/libicutest.so.70.1'. (https://snapcraft.io/docs/linters-library) 

The --debug flag was what I needed to start understanding what’s happening inside, it was a case of incorrect filenames on my part. That now creates a snap!

A couple of questions:

  • How/where would I now move the UI-dist folder (and replace on snap updates - it goes hand in hand with the binary)?
  • Where would I copy the config files(which need to persist on updates etc)?
  • Where would files created by the app end up?

I think the last two points are understanding where the working directory / persistent storage lives.