Feeding cloud-init data to snapd

It feels a bit error prone to refresh before we even attempt to setup the device the first time, instead of establishing a common path which is always the one tested. We cannot avoid supporting the other path, in which the device first sets up and then refreshes, because that can always happen if the refresh doesn’t work for whatever reason (e.g. not fast enough to take precedence, or device is offline).

Not sure lazy classic registration plays a role here. If the device has a gadget, it has snaps in use and should attempt to refresh, so it’s not lazy anymore, right? Or has that changed?

In either case, these questions are a hint that perhaps this is getting too complex for such a simple problem. Your suggestion 2 is also nice, and simpler. We might support a yaml configuration file in a well known place that is loaded when snapd is starting, assuming it’s owned by root and with permission bits restrictive enough.

We might either do it at seed time only, or if we want to make it more generic we can request the file to be written in a location controlled by snapd, and we remove the file after the options are loaded, ensuring the authoritative place to remain inside snapd proper, which avoids user options from being overwritten if they are changed via the usual means.

no, that has not changed, if there’s a gadget is not lazy even on classic. But as I mentioned, I remember we had discussions to possibly change that and keep laziness on classic until the user installs other snaps if the gadget/core came preinstalled.

But yes I agree that 2. might be a simpler option, there are too many behaviours tied up and things we might change with the hook we have and the use case is too narrow to add a new hook I think.

Had a good chat with @niemeyer, the plan is to have a general mechanism for the root user on the system to have a voice about configuration defaults for snaps before seeding (first time snapd starts at all) or before the snap is installed, this is similar to how the defaults stanza in the gadget works for the brand.

The plan is to support having files under /var/lib/snapd/seed/config/*.yaml, they would need to be non-world writable, each file would have the format:

defaults:
    <snap id>:
        <key>: <value>

the default configuration used at seeding or install for a snap would be equivalent to appling the stanzas for the snap (matching by snap id), first from gadget.yaml and then from the files under /var/lib/snapd/seed/config/ processed in lexicographical order by file name.

This is quite consistent with the preexisting mechanism. Now concretely for the original specific use case cloud-init would make sure to write – before snapd starts – a file /var/lib/snapd/seed/config/cloud-init.yaml with content like:

defaults:
  99T7MUlRhtI3U0QFgl5mXXESAiSwt776:  # snap-id of core
    proxy.cloud-placement:
       cloud-name: CLOUD-NAME
       region: REGION
       availability-zone: AZ

@pedronis Thank for the summary. Looking good!

The only thing worth talking about further is the position for these specific configuration options. “proxy” doesn’t feel like a good root for information such as cloud-name, region, etc.

Yes, that’s why I wrote “like”, current key is a strawman.

@niemeyer makes the statement “It would be nice to not special case the functionality to cloud-init” above. In the same way that snappy does not want to have specific knowledge of cloud-init, cloud-init would prefer to not have specific knowledge of snappy.

Specifically, from cloud-init’s perspective, it writes a json formatted file in /run/cloud-init/ that any consumer can read. I did suggest that we’re not entirely opposed to specifically handling this bit of information for snappy, but that gives cloud-init maintenance burden in the future should snappy ever change its interfaces. Cloud-init would also probably provide some way for the user to disable this behavior, or provide their own static information…

I’m not entirely opposed to all this, but it honestly seems simple enough for snappy to consume a json formatted file in /run if it is present. Cloud-init promises to keep the format of the file. That puts snappy entirely in control of its own future, rather than potentially requiring changes in another piece of software at some point in the future.

As I wrote elsewhere, afaict, the writing could be done after a quick check from snap_config in cloud-init which is already snapd specific afaiu (it would need to run on classic too though).

If we introduce in snapd both the general mechanism (to be clear the general mechanism is equivalent to a bunch of snap set calls and is not tied to just cloud-init or just this kind of information) and the cloud specific keys we would also need to promise to keep them working.

I let @niemeyer chime in more.

would/do ‘snap set’ calls work before snapd is started?

no, in the sense that they would start snapd and then there’s a potential race with the first refresh (that’s touched in my point 4. in the original discussion )

@pedronis It might be easier to do the whole thing on our end instead of coordinating, as @smoser points out, and put the plan of the pre-seeding configuration on the shelf until we need it for something else (it’s still a good idea).

For cloud-init, we could just read its status (or result?) file a single time early during the seeding routine, and translate it into the relevant configuration options for core.

@smoser Where can we find complete documentation about these files? I couldn’t find references to which provider and region the machine is in, etc.

I just noticed that snap_config is not part of cloud-init init, so it happens too late unless it would be split or moved earlier.

@pedronis, you’re right it woudl be too late. snap_config is probably better suited to be run later in boot, as it will do snap install and things. better to have that happen as more of the system is up. At least that is what we’ve ended up doing for apt.

note that we’re epxecting to improve/replace the snap config sometime soon here.

@niemeyer the data thre is new and will get documented more as we go.
That function will make its way back to 16.04 in a cloud-init SRU in the next month or so.
I’ll update this post with link to the MP for documentation as it comes.

We can’t wait for the system to be up to decide whether we are in a cloud or not, because snapd will start to do actions that need to take into account where it is (local mirrors, etc).

About the details, without knowing exactly how it looks and what data is available, it’s a bit hard to take the conversation forward. We don’t even know if it will satisfy the needs at stake or if we’ll need to come up with something else.

From what I understood looking at cloud-init the data details varies by cloud (the basic terminology is shared though in the Datasource interface in cloud-init) but is the same data (region, availability-zone) that is used to pick in-cloud apt mirrors, so I think it should satisfy the needs. What is recent is the json file on disk capturing this info.

Here are a couple of examples of what will show up on various clouds
EC2: https://paste.ubuntu.com/26368359/
GCE: https://paste.ubuntu.com/26165085/
Azure: https://pastebin.ubuntu.com/26075842/
OpenStack: https://pastebin.ubuntu.com/26084548/
lxc: http://paste.ubuntu.com/26368388/

1 Like

Chatted again with @niemeyer,

in the end snapd will read at seeding (first time it starts) /run/cloud-init/instance-data.json if present and will reflect the relevant data from v1 under a cloud namespace in the core configuration.

A variant of option 1.

I opened:

https://github.com/snapcore/snapd/pull/4582

along what we discussed

this then uses the information to pass it further along:

https://github.com/snapcore/snapd/pull/4599

this has landed and should be in 2.32.