Cannot refresh from store over local install

Working with a developer of an application which stores a bunch of data locally. He’s been working on a snap locally and has now uploaded a snap to the edge channel.

So to install from edge, we can snap install foo --edge but snap tells us the application is already installed, and offers snap refresh --help as a next step.

So now if I ```snap refresh foo --edge" to replace my local install version with the store version, I get this:

error: snap "foo" is local

Why? Why does snap not just ‘do the right thing’ which is replace the local install with the one from edge, as requested?

1 Like

As a workaround, can you try: snap download foo --edge && snap ack foo_*.assert && snap install foo_*.snap ?

1 Like

That worked, thanks @mvo. Is it planned to allow a seamless move from local to store application?
(such as you might apt install something over a dpkg installed deb).

@popey I think it makes sense to have something like snap refresh foo maybe with: error: snap "foo" is local, try snap refresh --from-local foo ? Let’s see if @niemeyer agrees and if so this should be straightforward.

1 Like

Indeed, it makes perfect sense to be able to go back into fully signed snaps from the store after going out of them. The term “local” feels a bit too vague here, though. It’s not just a local snap… it’s a custom and unknown snap that the store has never seen, and this operation may easily go wrong because of that, in ways that are unrelated to the actual snap being installed.

How about snap refresh --amend? This gives a bit of that feeling of “getting it right on track”, which also implies a bit like it can go wrong because it’s not the correct workflow.

@Chipaca @pedronis @facundobatista I remember we discussed not sending the “epoch” to the store because the store will always have the revision at hand and be able to tell internally, but here is a case where it won’t. Feels like we should send the epoch, at least in this case.

That wording seems fine to me. The case where I ran into this was as one of the developers of a snap testing out some changes before pushing them to the store, and in that case pretty much any option naming is just fine as long as it exists, but since there are other possible cases it does seem worth the wordsmithing.

For the record, in case anyone else runs into this: in my case I was working with a private snap, where snap download doesn’t work (bug 1661436, more or less), so I couldn’t quite use the workaround that @mvo recommended. However, this approach worked:

snap info --verbose foo.snap
curl -H 'Accept: application/x.ubuntu.assertion' https://assertions.ubuntu.com/v1/assertions/snap-revision/<sha3-384 from previous command>
curl -H 'Accept: application/x.ubuntu.assertion' https://assertions.ubuntu.com/v1/assertions/snap-declaration/16/<snap-id from previous command>
curl -H 'Accept: application/x.ubuntu.assertion' https://assertions.ubuntu.com/v1/assertions/account/<publisher-id from previous command>
curl -H 'Accept: application/x.ubuntu.assertion' https://assertions.ubuntu.com/v1/assertions/account-key/<sign-key-sha3-384 from previous command>

Now assemble the output of those four curl commands in reverse order with a blank line between each, and you have the .assert file that you can feed to snap ack.

We should fix the download command too. We’ve been encountering too many edges related to the fact the download command doesn’t follow the usual workflow that snapd follows when downloading snaps. The reason why it works differently is to enable the snap download command to be used even when snapd is not around, but the advantage of not having a completely separate way of doing this is quickly proving secondary to the ill effects of the different workflow.

this works for me:

snap info $snap_to_replace

Get the revision number of the release you want to use, then…

sudo snap refresh --revision=$revision_from_above $snap_to_replace

Edit: The previous version of this post stated the following which was wrong:

sudo snap revert --revision=$revision_from_above $snap_to_replace

The revert command only works if you have the version you want to install already in the local system, and even when it does work it’s a very different operation. You’re literally reverting into it, including data replacement by what was in use at the time that revision was used. That’s different from install or refresh.

That might be how it’s supposed to work, but that is incorrect, because it will let you revert to any revision in the store. (Edit: testing this I appear to be mistaken, but I’ve definitely done this in the situation below)

For example, I’ve reverted to releases that had long since disappeared because I’d built and installed more than 3 times locally causing any store-released revisions to be removed.

Edit: Aah, refresh lets you specify a revision, so maybe I used that?

Further edit, yes I believe I’m thinking of snap refresh --revision=$revision $snapname is what I used. Sorry for the confusion in my previous messaging :slight_smile:

That won’t revert the data, but it will only work if you are the publisher of that snap or if you have the revision locally. It doesn’t work with arbitrary revisions.

Thansk for the suggestion. I pushed a first PR to https://github.com/snapcore/snapd/pull/4356 - it does not send the epoch yet though.

As discussed on IRC, we’ll add an optional epoch field on the items in the install list (which is the best fit in this locally-installed case, and for the Store side, it even has almost the same semantic of “give me a snap for the first time”).

This (optional) epoch field would just mean an additional restriction when deciding the snap’s particular revision.

Its format is a dict holding two keys, read and write, each being a list of integers.

Just to be explicit, as the snap is included in the “install” list, it shouldn’t be included in the given context (note that snapd misses lot of information to put it there).