Snapd channel information

I’m trying to understand the channel information as returned by snapd to help document it and make an appropriate API in snapd-glib.

If I do a GET /v2/find?q=moon-buggy I get the following (unrelated fields omitted):

{
  "channel": "beta",           // Is this deprecated for channels["latest/stable"].channel?
  "channels": {
    "latest/stable": {
      "revision": "12",
      "confinement": "strict",
      "version": "1.0.51.11",
      "channel": "stable",     // Is this better known as "risk"?
      "epoch": "0",            // This is essentially an integer?
      "size": 90112
    }
  },
  "confinement": "strict",     // Is this deprecated for channels["latest/stable"].confinement?
  "download-size": 90112,      // Is this deprecated for channels["latest/stable"].size?
  "revision": "12",            // Is this deprecated for channels["latest/stable"].revision?
  "version": "1.0.51.11"       // Is this deprecated for channels["latest/stable"].version?
}

Questions:

  1. Are the top-level fields channel / confinement / download-size / revision / version obsolete now we have channels? Should the snapd-glib API for this be marked as deprecated?
  2. Is the channel field the risk field from https://snapcraft.io/docs/reference/channels? Would it be better exposed in the snapd-glib API as snapd_channel_get_risk()?
  3. Is the channel (risk) field an enumeration, i.e. only the values stable, candidate, beta and edge are allowed?
  4. For an installed snap, how do we know what channel track we are following? No fields seem to refer to “latest/stable”? What happens if we have “latest/stable” and “xenial/stable”?
  5. The epoch is passed as a string but the validation code suggests only integer values are allowed. Should I expose it as a string or any integer in the snapd-glib API?

Bonus question:
Why does moon-buggy show the channel as beta when then there is no channel that provides beta…

  1. These fields are all completely independent, which perhaps means I don’t understand the question.
  2. The risk level is just one of the components in a channel name. We have details on that terminology documented.
  3. No, there are custom components. The doc explains that in detail too.
  4. Track is another component of a channel name (also in doc). The “channel” field is what tells the channel currently being tracked.
  5. I suggest exposing it as a string too, so the code remains generic, and our validation code accepts strings as well, where appropriate. The background of that curious choice is that we need a revision for local snaps that does not clash with real revisions. Those are monotonically incremented, and prefixed by an “x”.

Bonus response: “beta” is a channel. Clients can track any current channel, even if it is closed. When a channel is closed the client falls back onto the channel offering less risk, until a snap is found, or stable is reached.

For example, if a client is tracking beta but the only snap that exists is in stable, it will get that. If a snap is released on the candidate channel of that snap, the client will get that instead, even if there is a stable snap (more risk, closer to beta). If a snap is then released on the beta channel, it will get that because that’s exactly what it asked for (even if there was something in candidate or stable). If something is then released on edge, it will ignore it. Too much risk considering a beta was requested.

That’s tersely represented in snap info:

% snap info moon-buggy
name:      moon-buggy
(...)
channels:                   
  stable:    1.0.51.11 (12) 90kB -
  candidate: ↑                   
  beta:      ↑                   
  edge:      ↑

That may sound a bit confusing, but it represents reality well. When we ask for a beta version of the software, we only want to use that beta until the beta is older than the more recent candidate or stable version of it.

For example, would a client ever have use for the download-size field if it understands the contents of channels?

i.e. currently you might have:

snap = snapd_client_find_sync (client, SNAPD_FIND_FLAGS_MATCH_NAME, "moon-buggy", NULL, NULL, NULL);
g_printerr ("download size is %u bytes\n", snapd_snap_get_download_size (snap));

should we expect a client instead to do:

snap = snapd_client_find_sync (client, SNAPD_FIND_FLAGS_MATCH_NAME, "moon-buggy", NULL, NULL, NULL);
channels = snapd_snap_get_channels (snap);
g_printerr ("download size is %u bytes\n", snapd_channel_get_size (channels[0]));

And consider snapd_snap_get_download_size to be deprecated API?

If I pass through the channel field in channels then the API terminology gets confusing:

snap = snapd_client_find_sync (client, SNAPD_FIND_FLAGS_MATCH_NAME, “moon-buggy”, NULL, NULL, NULL);
channels = snapd_snap_get_channels (snap);
g_printerr (“risk = %s”, snapd_channel_get_channel (channels[0]));

I’m wondering if it’s better exposed as snapd_channel_get_risk () or similar.

As per the link a “channel” is made up of three parts track/risk/branch, so using the term channel to just return the risk component seems wrong.

Now we have more complex channel names (track/risk/branch) the docs seem to say there are only four allowed names for risks. For example, could I make a channel called latest/foo?

The channel field only shows the risk of the channel being tracked right? It doesn’t seem to have the full channel name (track/risk/branch).

I understand the fallback behaviour (which is quite nice). I’m just wondering why the store is reporting moon-buggy as using a beta channel. Is this something that was configured store-side? Does that imply that installing this snap will by default install from latest/beta (falling back to latest/stable in this case)?

It’s not deprecated, and you may not be able to find those details in the channel list in some cases. In particular, the branch part of the channel is not exposed in the map, so you’ll never find those there, but may find at the top-level when channel is properly set into a channel including a branch name.

No, that is really a channel, not the risk alone. The case you picked up is confusing because “latest” is the default track, so it may be omitted.

The question and the response are about channels in general, rather than just the risk levels. We have four pre-defined risk levels today, and only those may be used at the moment. Still, I would suggest handling the channel name as a string and as a token on itself, as you’ll be aligned with snapd and the store and will have less trouble with breaking code.

No, it should show the full channel.

It’s snapd that is reporting that beta is currently being tracked locally, not the store.

If this is the case then this is a little bit confusing to be returned from GET /v2/find; this field would make sense returned from GET /v2/snaps. Note the field is set even when the snap is not installed.

In the particular case of the download size? Even if they’re not deprecated I figure I should document them as aliases to the values returned in channels (otherwise an API user might think they have different meanings).

OK, then should I use the channel field for the return value of snapd_channel_get_name ()? I was using the key in the channels dictionary for the name (it seems they are the same except the key is the full explicit channel name, and channel is the abbreviated name).

If you’re offering an update onto what’s being tracked at the moment, then pick the top-level items. That’s a plain “refresh” in terms of the snap command, perhaps even an automated one. If the dialog is offering channels to shift towards, then the natural fit is the content inside the channels map.

Yeah, that’s the proper field for that.