Seeding snaps not downloaded from store

We have a Yocto-based image, that has snapd and ships a bunch of snaps by default. Currently all snaps that we ship are downloaded from the Snap store by running

snap prepare-image --classic --arch=arm64 classic.model . --snap snapd

This works fine if we are pulling snaps from the snap store, but we want to be able to ship a snap that we built locally, something that we currently don’t publish to the snap store.

How can I achieve that ?

Did you try simply specifying a local path with --snap? the help for snap prepare-image claims this is supported.

snap prepare-image --classic --arch=arm64 classic.model . --snap /path/to/yoursecretsnap_1_amd64.snap
$ snap prepare-image --help
  snap prepare-image [prepare-image-OPTIONS] <model-assertion> <target-dir>

The prepare-image command performs some of the steps necessary for
creating device images.

For core images it is not invoked directly but usually via

For preparing classic images it supports a --classic mode

[prepare-image command options]
      --classic                      Enable classic mode to prepare a classic model image
      --arch=                        Specify an architecture for snaps for --classic when the model does not
      --channel=                     The channel to use
      --snap=<snap>[=<channel>]      Include the given snap from the store or a local file and/or specify the channel to track for the given snap

[prepare-image command arguments]
  <model-assertion>:                 The model assertion name
  <target-dir>:                      The target directory

Thanks for the reply @roadmr

You are right, that seemed to have just worked.

So I now have another question, how can I “trick” snapd to automatically connect interfaces for snaps that I ship from files instead of downloading from store ?

For example I have a locally built snap that I “seed” into our image and want it to connect to the camera interface, how may I achieve that ?

The thing that controls how interfaces are auto-connected is a snap-declaration assertion. The assertion is signed by the store - so if your snap does not exist in the store, you will not have an assertion and auto connection at snap install time will not work.

Clearly, snapd only trusts the store’s private key (snapd has the corresponding public key to verify assertions) so signing the assertion yourself is unfeasible as well.

One thing you could do if you are using a gadget snap, is to use that to set up connections at image build / first boot time, rather than at install time. Someone from the snapd team might be able to confirm, I think this might allow you to connect without needing the assertion.

Look at the “connections” section in the gadget snap specification here : Gadget snaps

1 Like

Can anyone from the snapd team please comment on that ?

the connections in he gadget.yaml require a snap id … so i suspect that wont work without involving the store (which generates the id on upload)

So I guess the other solution for us would be to create an external service, that takes care of the connections on first boot.

I do believe that allowing the image builders to have that “permission” would be a cool addition to snapd.

all these “permissions” come by default with a brand store :slight_smile: … you are simply hacking around the product that pays for the free snap infrastructure here :wink:

1 Like

I need to talk this up with the “decision makers” in our team. I think we had a call with the Canonical sales team a while ago about this. IIRC the “X$ per device per year” model wouldn’t scale well for us (but I was not in that call).