Risk only channel requests vs pinned/default tracks

For core 18 support we added the ability to pin tracks in the model assertion, operations specifying only a risk (stable, candidate, beta, edge) for channel always fail for the snaps with a such a pinned track which is less than ideal. This is because right now those channels are always translated to “latest/”.

We plan also to introduce the concept of an optional default track (at store level) for snaps that can be different from the implied “latest” track. In that case is natural to make the risk only channel mean the risk within the default track.

But from recent discussions is not to big of step from there to also translate (locally) the risk only channels to pinned track + risk so to make --stable etc work again for snaps with a pinned tracked from the model assertion.

I’ve installed lxd via snap install --channel=3.0/edge lxd. This is the info

tracking:     3.0/edge
refresh-date: today at 10:49 CET
channels:
  stable:        3.9         2019-01-18 (9919) 54MB -
  candidate:     3.9         2019-01-18 (9919) 54MB -
  beta:          ↑                                  
  edge:          git-d676734 2019-01-21 (9956) 54MB -
  3.0/stable:    3.0.3       2018-11-26 (9663) 53MB -
  3.0/candidate: 3.0.3       2019-01-19 (9942) 53MB -
  3.0/beta:      ↑                                  
  3.0/edge:      git-18c9b88 2019-01-19 (9940) 53MB -
  2.0/stable:    2.0.11      2018-07-30 (8023) 28MB -
  2.0/candidate: 2.0.11      2018-07-27 (8023) 28MB -
  2.0/beta:      ↑                                  
  2.0/edge:      git-c7c4cc8 2018-10-19 (9257) 26MB -
installed:       git-18c9b88            (9940) 53MB -
$ snap list |grep lxd
lxd                          git-18c9b88          9940  3.0/edge  canonical*    -

Then, refreshing with --stable switches the track:

$ snap refresh --stable lxd
lxd 3.9 from Canonical✓ refreshed
$ snap list |grep lxd               
lxd                          3.9                  9919  stable    canonical*    -

So the lxd ended up switching from 3.0 to 3.9, which may have not been the intention when the command was called.

There is a relevant bug report, regarding switching kernels, on a device with model assertion with pinned kernel/gadget tracks. The relevant ticket is here: https://bugs.launchpad.net/snapd/+bug/1805473 To recap from the ticket, refreshing the kernel with one of the risk-only switches issues a confusing error:

$ sudo snap refresh --stable pi-kernel
error: cannot refresh "pi-kernel": cannot switch from kernel track "18-pi3" as specified for the
       (device) model to "stable"

Note that there is potential API breakage to consider. A request to refresh from stable actually meant latest/stable.

I’m playing with the heuristic to automatically pick the right track. So far, using the current track iff none is provided in the request seems to work as expected. I was initially confused with how we use/hide latest/ in the code, but I think I have it under control now. WIth lxd snap:

# lxd stable is installed
$ snap refresh --channel=3.0/stable lxd
lxd (3.0/stable) 3.0.3 from Canonical✓ refreshed
# implicit track
$ snap refresh --edge lxd
lxd (3.0/edge) git-18c9b88 from Canonical✓ refreshed
# explicit, 'latest' track
$ snap refresh --channel=latest/edge lxd
lxd (edge) git-d676734 from Canonical✓ refreshed

Using latest/<risk> channel does not feel super obvious or discoverable. Perhaps we could consider adding --latest to the command line (eg. snap refresh --latest --stable lxd).

Maybe but the current plan is not the change that behavior, --stable is about the default track not just risk, otherwise the same command means different things in very similar contexts

I may have misunderstood how --stable et al. are supposed to work with default track then or maybe I’m just missing another piece of the puzzle.

From what I have gathered, passing channel: "<wanted-risk>" through snapd API, with a snap tracking foo/<some-risk> channel, was supposed to ask for foo/<wanted-risk> instead of latest/<wanted-risk>. In the case of lxd, when the local snap is tracking 3.0/stable, requesting channel: "edge" over snapd API, actually ends up asking "3.0/edge" from the store, because the track is already set to 3.0.

Does that mean that the client should always send <track>/<risk> to make the request unambiguous? In this particular case, snap refresh --stable, ought to send channel: "latest/stable" instead of channel: "stable", like it does now. Then if you really want to switch the risk within current track, one should use snap refresh --channel=<risk>.

Let’s sync up on IRC.

Talked this over in a f2f. The agreement is to focus on pinned tracks, that are specified in the model assertion.

This is being addressed by:

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