Snap layouts

Thanks for the quick feedback, here are the requested details:

  1. $SNAP/api/Gemfile and $SNAP/api/Gemfile.lock were present during snap creation, but the override-build script of the Rails part renames them to Gemfile_installed Gemfile.lock_installed. I verified that they are not present in the final snap.
  2. Both:

On classic Ubuntu Desktop (snap built with LXD container)

snap   2.35.2
snapd  2.35.2
series 16
ubuntu 18.04
kernel 4.150-36-generic

on Ubuntu Core device:

snap    2.35.2
snapd   2.35.2
series  16
kernel  4.4.0-1098-raspi2
  1. Clean install – or rather attempting to install, since it aborts the installation because of said error. I made sure that no previous versions were installed during the installation attempt.

I’m looking at reproducing this with the new details right now.

EDIT: I failed reproducing this. Here is what I tried. I used snapd 2.35.4 from Ubuntu Cosmic:

snap    2.35.4+18.10
snapd   2.35.4+18.10
series  16
ubuntu  18.10
kernel  4.18.0-8-generic

There I created an application with the following definition:

name: app
version: 1
apps:
    app:
        command: bin/app
layout:
    $SNAP/api/tmp:
        bind: $SNAP_DATA/rails/tmp
    $SNAP/api/log:
        bind: $SNAP_DATA/rails/log
    $SNAP/api/vendor:
        bind: $SNAP_DATA/rails/vendor
    $SNAP/api/Gemfile:
        bind-file: $SNAP_DATA/rails/Gemfile
    $SNAP/api/Gemfile.lock:
        bind-file: $SNAP_DATA/rails/Gemfile.lock

I made a dummy bin/app shell script that just prints ok. Apart from bin/app and meta/snap.yaml there were no other files present in the snap.

Running the application I get ok and a working layout. I can then run snap run --shell app to explore the environment.

zyga@fyke:$ snap run --shell app
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

zyga@fyke:$ cd $SNAP
zyga@fyke:/snap/app/x1$ find
.
./api
./api/vendor
./api/tmp
./api/log
./api/Gemfile
./api/Gemfile.lock
./meta
./meta/snap.yaml
./bin
./bin/app

Looking at $SNAP_DATA, I see:

zyga@fyke:/snap/app/x1$ cd $SNAP_DATA
zyga@fyke:/var/snap/app/x1$ find
.
./rails
./rails/Gemfile.lock
./rails/tmp
./rails/Gemfile
./rails/vendor
./rails/log

Lastly I can inspect the mount namespace but this requires more privileges so I leave the confined shell (exit) and inspect the mount namespace using the nsenter command.

zyga@fyke:/var/snap/app/x1$ exit
exit

zyga@fyke:$ sudo nsenter -m/run/snapd/ns/app.mnt
root@fyke:/# cat /proc/self/mountinfo | tail -n 6
2130 2257 0:56 / /snap/app/x1/api rw,relatime - tmpfs tmpfs rw,mode=775,uid=1000,gid=1000
2067 2130 8:1 /var/snap/app/x1/rails/Gemfile.lock /snap/app/x1/api/Gemfile.lock rw,relatime master:1 - ext4 /dev/sda1 rw,errors=remount-ro
2131 2130 8:1 /var/snap/app/x1/rails/Gemfile /snap/app/x1/api/Gemfile rw,relatime master:1 - ext4 /dev/sda1 rw,errors=remount-ro
2132 2130 8:1 /var/snap/app/x1/rails/log /snap/app/x1/api/log rw,relatime master:1 - ext4 /dev/sda1 rw,errors=remount-ro
2133 2130 8:1 /var/snap/app/x1/rails/tmp /snap/app/x1/api/tmp rw,relatime master:1 - ext4 /dev/sda1 rw,errors=remount-ro
2134 2130 8:1 /var/snap/app/x1/rails/vendor /snap/app/x1/api/vendor rw,relatime master:1 - ext4 /dev/sda1 rw,errors=remount-ro

As you can see /snap/app/x1/api is a tmpfs populated with the objects from $SNAP_DATA (in this case /var/snap/app/x1/).

Can you tell me what I am missing in this test?

1 Like

(Very belated answer, but fortunately I left this browser tab open :smile: )

Thank you for this extensive test! The only difference is that in my snap, $SNAP/api is an existing directory created during snap creation – and that my snap has an install hook attempting to do stuff in the directories that I specified in layouts.

Short version: The bug sat in front of my computer :smile: I misread the docs about nested paths in bind-mounts and added mkdir commands to my install hook at some point. I previously used the $SNAP_DATA/rails_{$folder} version, but then switched to $SNAP_DATA/rails/$folder – and added an mkdir $SNAP_DATA/rails/$folder, which then tried to overwrite the bind-mount.

Takeaway: Maybe the error message could be clearer, but not a fault of layouts.

Woot, that’s great to know. The up side is that 2.36 ships with layouts enabled and that nested directory limitation lifted now. Please try edge again and see if you can simplify your snapcraft.yaml now. I also heard that snapcraft will support layouts directly (CC @kyrofa to confirm please) so that the passthrough section can go away.

Yessir, but only in edge right now, it’ll be in the next stable release (but only if using bases).

1 Like

@zyga, @degville this should probably be mentioned and linked to from The snap format

I’ve just added this to The snap format document. Thanks!

1 Like

Just wanted to give feedback that layouts have been working fine for me since 2.36 and switching to snapcraft v3 was seamless in that regard. I have had the passthrough wrapper active because I’m using launchpad for ARM builds and when I last checked, those builders didn’t have layouts enabled by default.

One minor hiccup that might be related to layouts: My snap’s install hook performs some tasks in the writable mounted directories. If the hook fails (because I had a thinko or something was missing), any attempt to reinstall a newer, fixed revision of the same snap will throw an error during the install hook that the layout mount at /var/snap/my-snap/current/some/subdir does not exist. Once I reboot, the error goes away and I can install the fixed revision just fine.

@tobias, is your issue similar to the one I encountered here: Snapd 2.37.1 refresh broke layouts snap remove/install ?

It would be interesting to see if you have a similar issue with the mount point showing up with //deleted at the end. You could try logging to $HOME the output of cat /proc/self/mountinfo during the hook.

@ijohnson The snap does not get installed when install fails, so I can’t really look inside the snap. I’ll see if I can throw together a test case that’s triggered on-demand after installation.

Interesting, please file a bug. It seems that on failed install we don’t discard any namespaces we have created.

Done: https://bugs.launchpad.net/snapcraft/+bug/1815722

Nice edits, really appreciated!

I wonder if this feature is compatible with the SNAPCRAFT_ARCH_TRIPLET variable?

Too lazy to verify it myself :expressionless:

I wonder what’s the usecase of symlink ?

Not everything has to be a bind mount. A symlink is much more lightweight way to relocate something.

1 Like

One of my snaps that uses layouts suddenly gets rejected on automatic review in the store:

invalid source mount: '$SNAP/api/tmp'(should be a legal path and not start with: /boot, /dev, /home, /lib/firmware, /lib/modules, /lost+found, /media, /proc, /run, /sys, /tmp, /var/lib/snapd, /var/snap lint-snap-v2_layout_target ($SNAP/api/tmp)

full review output

As you can see in the snapcraft.yaml source, I’m mapping $SNAP/some/path to $SNAP_DATA/some/path. The application running in $SNAP/api expects everything to exist beneath its root directory, but some of those have to be writable. The previous snap revisions (last one built on 2019-07-04) went through review just fine. I tried with and without the passthrough wrapper, so I presume that the store gained layout linting in the meantime.

Is this expected? What can I do to have my snap pass review again?

It did. I’ll take a look and respond via the store review process.

Ok, as you probably saw, I approved these. The fix is in master and I’ve requested a store pull.

1 Like

Thank you for the fast response + fix + approvals, much appreciated!

Is there a repo/status page where I can see if the fix has been deployed, so that I don’t push revisions until this passes again?