I have multiple snap applications which use configuration files to determine where to find files that the snap needs to run. These configuration files are used from services which are expected to be normally running and as such, successfully stopped and started for refreshes. The issue I have is that these configuration files need to know where certain files/directories are, and we use various $SNAP_DATA, $SNAP, etc. based file paths in these configuration files, as the configuration files don’t understand environment variables nor do they understand relative paths. So on initial install, we use sed/jq/etc. to automatically populate these values in the configuration file during the install hook so the services startup properly. The problem I have is that these values are then invalid after a snap refresh, because the value of environment variables such as $SNAP, $SNAP_DATA directly contain the revision number rather than use the current symlink.
I’m wondering:
Is it safe to specify these configuration values as current instead of the specific revision number as currently used?
If it is safe, is there a good reason not to change future snapd versions to just make $SNAP, $SNAP_DATA, etc. use the current symlink by default? Right now we can strip off the revision number and replace it with current but it would be nice to not have to do that.
What’s the recommended best practice for handling this situation? Should I reprocess the configuration files to use the updated value of $SNAP_DATA with the new revision number on every refresh? If so, what’s the best way to know what the previous revision number is? (the reason we need to know what the previous revision is that a user could also manually change the configuration values to point somewhere else the snap has permission to write to, say the home folder, removable-media, etc. and in this case we don’t want to overwrite it, so we need to see if the current value of those configuration items in the post-refresh hook matches what was set automatically for the previous revision - only then if it matches what we automatically set would we re-set the value to the new value for the next revision)
Also note that one reason it’s not desirable to use $SNAP_DATA with the current symlink is that running containers with overlayfs mounts with a target directory that has a symlink in it’s path causes weird kernel bugs. See https://github.com/opencontainers/runc/issues/586 for more details. However this is a small use case affecting a minimal number of snaps (i.e. greengrass and docker). Are there perhaps other issues with mounts that snapd performs using these variables that necessitate using the revision number explicitly?
We are aware of this problem (or rather, of this family of problems), and resolving them is the ultimate goal of @zyga-snapd’s Refresh App Awareness work.
In the meantime,
yes, use current in any and all config, rather than the revisioned versions.
it’s not safe, but we’ll be changing them once it is (safe does not imply works-everywhere, as per the corner cases you mention, but there isn’t one that works everywhere and it seems having current in the variables is the least surprising)
snapd doesn’t tell you the last revision (and it’d be tricky to do). You’ve got three options, all on your side right now:
use current in the config and then do realpath before using the values,
interpolate $SNAP_ variables in your config, or
have a configure hook and use it to retrieve the last revision and store the current one
the last one, which involves rewriting the config every revision change, sounds really messy to me but if you can’t change your code per the other two might be your only one. The configure hook doesn’t need to do anything; it’s just there so snapctl set lastrev="$SNAP_REVISION" works (and after you’ve done that, snapctl get lastrev would work).
As long as your apps that write to $SNAP_DATA are daemons, all the above should work without issue today. The real problem is with non-daemon apps which today might be alive straddling a refresh, where their security profiles point to one directory and current (or $SNAP_DATA) would point to another.
I interpret this statement as saying that at some point in time $SNAP_DATA, etc. will change to using current directly, is that accurate?
I hadn’t realized the configure hook runs on every snap refresh as well as install… One question I’m having with using snapctl set is if there’s a situation where a snap could be reverted after the configure hook runs for the next revision and then processes the failed revision change? I don’t think this is an issue because when the snap is reverted it would have the previous revision’s $SNAP_DATA saved, so as long as:
we keep the config files in $SNAP_DATA and not a shared directory such as $SNAP_COMMON
we only update the files in $SNAP_DATA using what’s in snapctl get during the post-refresh hook
I think (?) we should be fine. (though your suggestion is always welcome)
One thing I do think would be nice to see is a thorough document explaining what happens when a revert happens, in terms of hooks run, files copied, etc. (it seems no hooks are run and no files are copied, just current is updated?) There’s a fair amount of things I’ve read across the forum and elsewhere but for example there’s nothing in docs.snapcraft.io that would be easily accessibly by users.
This is the case for almost all of the situations I’ve been involved with so that’s fine with us.