Next steps for dotnet-sdk snap

Hello store team,

I’m part of the Toolchains squad (Foundations Team @ Canonical) and one of the maintainers of the .NET packages on Ubuntu. We will also take ownership of the .NET snaps and start maintaining them soon (dotnet-sdk and dotnet-runtime-*).

We’ve been working on a revamped version of a .NET snap meant to replace the current dotnet-sdk snap and fix some issues customers have been coming across over the years. With that, I’d like to open a communication channel with you all to ask a few questions and understand the best path forward when transitioning from the old snap to the new one.

New dotnet snap

We’d like the new snap to be called simply dotnet. I’ve already been told that renaming snaps isn’t possible so we’re trying to come up with a nice strategy towards transitioning to this new snap while breaking as few customers as possible (ideally, none).

For context, the dotnet-sdk snap currently holds the dotnet alias.

I have a few options in mind which I’d like some feedback on:

Option 1: Create dotnet snap without releasing alias

The idea here is that we’d be able to register dotnet even if dotnet-sdk holds the dotnet alias. Is this possible?

If so, the steps forward would be to:

  1. Release new snap under the dotnet registration in the latest/stable channel.
  2. Sunset old dotnet-sdk snap after a couple months to allow users time to manually transition to the new one (uninstalling the old one and installing the new one).

Option 2: Remove dotnet alias from old snap before releasing new one

If option 1 is a non-possibility, the steps we’d take towards transitioning to the new snap would be to:

  1. Release new snap under current dotnet-sdk registration in the latest/preview channel to allow current users to test it out and file bugs.
  2. After some time, remove the dotnet alias from the dotnet-sdk snap and register + publish the new dotnet snap. At this point, users installing dotnet-sdk would need to manually alias it to properly use the dotnet command. The question is: what happens to users who already have the dotnet-sdk snap installed when the alias is released in the back-end?
  3. Sunset the old dotnet-sdk snap.

Again, we’ve started working with snaps just recently and are still not fully aware of the possibilities, so thank you for taking the time to review this. We appreciate any feedback you all can give us on what the best path forward could be.

I’m just some guy from the internet, not the internal team, but I have some potentially interesting feedback that you may find handy. Or it’s the ramblings of a mad man. You decide!

Further down is a mad suggestion.

Also, unrelated I was trying to debug what’s going on with the existing snap, then realised I am on an arm64 machine and the build that’s published for arm64 is very old (2020) and broken.

alan@asimo:~$ snap info dotnet-sdk
name:      dotnet-sdk
summary:   Develop high performance applications in less time, on any platform.
publisher: Microsoft .NET Core (dotnetcore✓)
store-url: https://snapcraft.io/dotnet-sdk
contact:   https://dot.net/core
license:   unset
description: |
  .NET Core is the modular and high performance implementation of .NET for creating web applications
  and services that run on Windows, Linux and Mac. It is open source and it can share the same code
  with .NET Framework and Xamarin apps.
  
  .NET Core is a .NET Foundation project. https://dotnetfoundation.org/
commands:
  - dotnet-sdk.dotnet
snap-id:      uHc4y9lWxyqYfxsqcr4xILzAai4L1BHs
tracking:     5.0/edge
refresh-date: today at 20:00 BST
channels:
  5.0/stable:    –                                               
  5.0/candidate: –                                               
  5.0/beta:      –                                               
  5.0/edge:      5.0.100-preview.3.20216.6 2020-04-21 (79) 127MB classic
installed:       5.0.100-preview.3.20216.6            (79) 127MB classic

So, number one, I’d unpublish that.

Now, I’m slightly annoyed with myself for wasting 10 minutes on that, but that’s very much a “me problem”.

(ok, sshing over to an amd64 box)

My theory is you can actually test what happens if there was a dotnet snap and a dotnet-sdk yourself on a developer workstation.

My theory is you could snap install the one called ‘dotnet-sdk’ in the store, then locally modify a build, to make a ‘dotnet’ snap on your workstation, install that, and see what happens.

So, let’s do that…

$ snap info dotnet-sdk
name:      dotnet-sdk
summary:   Develop high performance applications in less time, on any platform.
publisher: Microsoft .NET Core (dotnetcore✓)
store-url: https://snapcraft.io/dotnet-sdk
contact:   https://dot.net/core
license:   MIT
description: |
  .NET Core is the modular and high performance implementation of .NET for creating web applications
  and services that run on Windows, Linux and Mac. It is open source and it can share the same code
  with .NET Framework and Xamarin apps.
  
  .NET Core is a .NET Foundation project. https://dotnetfoundation.org/
snap-id: uHc4y9lWxyqYfxsqcr4xILzAai4L1BHs
channels:
  latest/stable:    8.0.204               2024-04-09 (241) 293MB classic
  latest/candidate: ↑                                            
  latest/beta:      8.0.100-rc.1.23455.8  2023-09-12 (222) 285MB classic
  latest/edge:      ↑                                            
  lts/stable:       8.0.204               2024-04-09 (241) 293MB classic
  lts/candidate:    ↑                                            
  lts/beta:         ↑                                            
  lts/edge:         ↑                                            
  8.0/stable:       8.0.204               2024-04-09 (241) 293MB classic
  8.0/candidate:    ↑                                            
  8.0/beta:         8.0.100-rc.2.23502.2  2023-10-10 (225) 285MB classic
  8.0/edge:         ↑                                            
  7.0/stable:       7.0.408               2024-04-09 (242) 289MB classic
  7.0/candidate:    ↑                                            
  7.0/beta:         7.0.100-rc.2.22477.23 2022-10-11 (182) 266MB classic
  7.0/edge:         ↑                                            
  6.0/stable:       6.0.421               2024-04-09 (240) 265MB classic
  6.0/candidate:    ↑                                            
  6.0/beta:         ↑                                            
  6.0/edge:         ↑                                            
  5.0/stable:       5.0.408               2022-05-10 (167) 139MB classic
  5.0/candidate:    ↑                                            
  5.0/beta:         ↑                                            
  5.0/edge:         ↑                                            
  3.1/stable:       3.1.426               2022-12-13 (189) 213MB classic
  3.1/candidate:    ↑                                            
  3.1/beta:         ↑                                            
  3.1/edge:         ↑                                            
  2.1/stable:       2.1.818               2021-08-19 (139) 245MB classic
  2.1/candidate:    ↑                                            
  2.1/beta:         ↑                                            
  2.1/edge:         ↑      

Ok, that’s more like it!

Let’s install it. I’ll pick an older version, so we can ‘simulate’ a ‘future upgrade’ in a bit.

$ snap install dotnet-sdk --channel=7.0/stable --classic
dotnet-sdk (7.0/stable) 7.0.408 from Microsoft .NET Core (dotnetcore✓) installed

Does it have a dotnet command/alias?

$ snap info dotnet-sdk | grep -A 1 ^commands
commands:
  - dotnet-sdk.dotnet
$  snap aliases
Command                      Alias            Notes
dotnet-sdk.dotnet            dotnet           -

Does it work?

$ which dotnet
/snap/bin/dotnet
$ dotnet --version
7.0.408

Ok, good, let’s download a different version and modify it.

$ mkdir dn
$ cd dn
$ snap download dotnet-sdk --channel=8.0/stable
Fetching snap "dotnet-sdk"
Fetching assertions for "dotnet-sdk"
Install the snap with:
   snap ack dotnet-sdk_241.assert
   snap install dotnet-sdk_241.snap

We can unpack it…

$ unsquashfs dotnet-sdk_241.snap 
Parallel unsquashfs: Using 8 processors
9150 inodes (15793 blocks) to write

[=======================================\] 24943/24943 100%

created 8879 files
created 1162 directories
created 271 symlinks
created 0 devices
created 0 fifos
created 0 sockets
created 0 hardlinks

Let’s change the name of the snap from dotnet-sdk to dotnet. This will automagically make this snap have the dotnet ‘alias’ given the name of the command, and the name of the snap are the same.

$ cat squashfs-root/meta/snap.yaml 
name: dotnet-sdk
version: 8.0.204
summary: Cross-Platform .NET Core SDK
description: '.NET Core SDK. https://dot.net/core.

  '
apps:
  dotnet:
    command: dotnet
architectures:
- amd64
base: core20
confinement: classic
grade: stable

$ sed -i 's|-sdk||' squashfs-root/meta/snap.yaml
$ grep sdk squashfs-root/meta/snap.yaml

Now, let’s pack it back up as a snap.

$ snap pack ./squashfs-root
built: dotnet_8.0.204_amd64.snap

Ok, let’s install that.

$ snap install ./dotnet_8.0.204_amd64.snap --dangerous --classic
error: cannot install snap file: snap "dotnet" command namespace conflicts with alias "dotnet" for
       "dotnet-sdk" snap

Boom! Explosions, fire, brimstone, end of the world.

Even if you could have aliases in both snaps, it’s not possible to have them both installed.

There’s your answer. :smiley:

Now, what you do about this, is the interesting question. Migrations from one snap to another are always a bit manky to be honest. I would take the ‘nudge’ approach. You could add a simple ‘echo’ in the wrapper that launches dotnet-sdk.dotnet to inform the user. Maybe echo a URL, or if you’re feeling brutal, use xdg-open to launch a browser to a URL containing documentation.

Mad idea zone…

Has someone on the store team explicitly stated that you cannot have a snap called dotnet published in the store (not installed in parallel) while you have another snap (dotnet-sdk) which has the dotnet alias? (so-called ‘option 1’).

The documentation doesn’t appear to imply that.

There’s possibly a further option.

I don’t know what the userbase (weekly active devices) of the dotnet-sdk is, nor how often they use it, but in my experience you won’t get everyone migrated in two months. You often find tons of people install snaps and then don’t use them, so they will show up in the store metrics, but won’t see blog posts, announcements or the like.

We have had people keep stuff installed, because they’re not active users of the package, for a very, very long time.

One thing that I suspect people will frown upon is to actively fix the problem from inside the snap.

So from inside the dotnet-sdk snap you could (potentially, if allowed by The Powers That Be) do something brutal like display a messgae, which would appear on the developer workstation, or in logs, if it’s in CI. This could tell the user to ‘snap remove dotnet-sdk; snap install dotnet’.

The dotnet-sdk snap, and presumably the dotnet snap is classic though, so you could (if allowed) detect an interactive shell and prompt the user ‘fix this (y/n)’ then do the ‘snap unalias dotnet-sdk.dotnet ; snap install dotnet ; snap remove dotnet-sdk’.

Something like a shell script wrapper around the dotnet binary, inside the dotnet-sdk snap which does the above.

If you published that before the dotnet snap is promoted, it would enable people to migrate early rather than be surprised.

(if allowed)

2 Likes

On this point, I had ~15k users of Joplin desktop under one package name years ago, tried to migrate the package name over to one without my name in it; and I’ve been uploading two versions ever since.

It’s down to about 1.5k users 3 years later, but because the application synchronises data remotely in often backwards incompatible ways, I’m forced to keep updating it. It’s not a massive burden, ultimately I just do as Alan shows above and force the package name to match the expectations on an otherwise bit for bit identical release, but that’s 15K users on an app that’s not likely to be embedded into CI scripts worldwide, and the new snap package has more than 15k users, so we could say 90% of people will migrate within a “reasonable” time frame but some people are definitely taking advantage of 10 years of Ubuntu Pro or just like the logo being in their desktop unused. And reasonable is more on the scale of years than weeks.

What I did do to accelerate its eventual demise is ask the store team to register a new track that I never publish to, and set that track as default. Users with it installed already continue to get updates, but users who try reinstall it will be told there’s not a published release and struggle to figure out the CI invocation to get “latest” when it isn’t default. Similarly, the snap’s unlisted, so the AppStore won’t help you either! This seemed to help a lot (the snap name did get in some blog posts) but is probably much more suited for Dotnet because you guys will really struggle to eliminate those old references on the internet being massively bigger.

It definitely helped accelerate the death, but I’m guessing these 1.5k users could easily last another 2 years yet, making that entire transition take easily 5 years.

Might be one to consider for your use case. You’ll never get everyone off the snap but you don’t necessarily need to remove it entirely so soon if you can prevent new users from using it.

Thank you, @popey for taking the time to make such a thorough investigation! For what it’s worth, I’m not expecting both snaps to be co-installable in a machine, that would be non-ideal anyway. My hopes are that they can, at least, coexist in the snap store in a way that allows us to make some transition efforts to inform people about the new Snap – through blog posts, deprecation notices in the store listing, and echo-based nudging (like you suggested) – before yanking the old one from the store.

No. As of right now, I can’t register a dotnet snap in the store. It says that “Another publisher already registered dotnet .” But let’s say that I’m hoping for a way around that in the store back-end, since the name is currently simply an alias (not sure if there’s a hard namespace conflict there). If there is no way around it, then ‘Option 2’ it is.

What would happen after the two-month-ish transition period, to your and @James-Carroll’s point, is that the old snap would stop getting the monthly .NET updates and we would setup informative notices about the existence of the new snap. So, we are not too worried about getting everyone to transition within that time-frame, we are just making extra sure that current processes that rely on the old snap don’t break in the interim (thus the importance of ‘Option 1’). Also, I really like the empty track suggestion!

Now, how long it would take until we completely remove the old snap from the store is probably a future conversation. I guess I should make it clearer that “sunsetting” in that oversimplified roadmap I posted simply means “we won’t ship updates to this from this point forward”.

Thanks for all the input so far! :smile:

Did you consider just taking over the old snap and release new versions unde the old existing name ?

Yeah. The issue is that the old snap name is called dotnet-sdk and the new snap will contain an embedded installation manager that allows one to install only the Runtime or the Runtime + SDK (or even multiple major versions of these, e.g. .NET 6 and .NET 8 runtimes for servers that run multiple services targeting different .NET versions), so we believe that’s not a very descriptive name anymore.

Which is why we want to call the new one just dotnet.