We are building a Yocto-based image, which comes with snapd preinstalled (fully confined). Now we need to include a few snaps in the rootfs. The easier way would be to just use snap download <snap_name>, however that won’t be possible because snapd is not available in our build environment. I am assuming we could get away with using curl/jq by calling a similar endpoint like https://search.apps.ubuntu.com/api/v1/package/firefox, however where do we get the .assert file ?
This may actually be part of a larger problem i.e. what to do once we have the snap downloaded, how do we install it on first boot (or during image build). Also, we are going to have our rootfs read-only, then how are subsequent updates going to work (bind-mount a rw location to /var/lib/snapd/snaps, but creating a mix of pre-seeded snaps and to-be-downloaded snaps would be a challenge)
As for first boot, I would suggest you look into seeding, which unfortunately is completely undocumented, but the following should help you started:
obtain a classic model assertion: snap known --remote model series=16 brand-id=generic model=generic-classic > classic.model
prepare the seed: snap prepare-image --classic --arch=<eg. amd64> classic.model $TARGET_DIR --snap foo --snap bar
This will fetch the classic model assertion and prepare a seed suitable for use with the target system. You just need to ensure that the $TARGET_DIR/var/lib/snapd structure is present in the target image. On startup snapd should locate the seed and preload the snaps.
Another alternative is to just build the snap binary and run it with snap download specifically, in fact we specifically support building just the snap binary on unsupported architectures i.e. macOS so that snaps and assertions can be downloaded this way (mainly to support snapcraft, but this is a valid use case as well I think).
I think someone should create a mirror, just for that i.e. publish snap binaries, which different scripts could just download and run for commands that don’t depend on the daemon.
Since I don’t necessarily need the .assert file independently, because “seeding” is the only thing that I need to do, I guess I’d have to find a way to use the snap CLI as @ijohnson suggested.
As expected the extracted snap file from snapd deb for arm64 didn’t work on the Yocto image because of having a different toolchain as compared to Ubuntu. So now I need to find a way to build the CLI tool only. @ijohnson any pointers towards that would be helpful.
to build the snap binary to be usable in this different toolchain environment you can compile the snap executable statically with the following steps on i.e. Ubuntu on arm64:
install Go however you choose (i.e. tarball from golang.org/dl or the snap)
install pkg-config gcc libseccomp-dev
setup GOPATH, i.e. GOPATH=$HOME/go; mkdir -p $GOPATH; PATH=$PATH:$GOPATH/bin
get the snapd sources, mkdir -p $GOPATH/src/github.com/snapcore; cd $GOPATH/src/github.com/snapcore; git clone https://github.com/snapcore/snapd
initialize vendor dependencies: cd $GOPATH/src/github.com/snapcore/snapd; ./get-deps.sh
build the snap command statically: go build -o snap-exe -buildmode=default -ldflags '-linkmode external -extldflags "-static"' -tags nomanagers,nosecboot ./cmd/snap, note this will complain about some things, but for usages of snap download it doesn’t much matter
Now you have a statically linked snap-exe which can be used on any Linux pretty much for at least snap download, though it may not work for other commands. You may even be able to cross compile this way, though I didn’t test that out. That would require more options when compiling.
What does your model assertion look like? It’s possible you are using an old style model assertion for UC16ish devices when you should be using one that is UC18ish and allows you to just use the snapd snap instead of the core snap.
One other question, does the “seeding” happen offline or does it require a working internet. I am thinking if I can set a somewhat “reasonable” date on our yocto image by default, will the seeding work even in the absence of internet ?
Tested, internet is not required, just need to have a “sane” time set.
What snaps are you seeding the device with? Do you have any snaps that specify base: core or specify no base at all? If so then you need to also seed the core snap onto the device.
We are seeding crossbarfx snap, which has base: core20. Any other snaps that we’ll ship will also have base: core20. We could obviously change our snap to base: core18 if needed.