Using symlinks for flexibility and robustness

While working on upgrading from 1.4, it proved easier to switch from between versions if the content of /etc/ were provided by symlinking from /etc/ to the target directory.

For example, the content of Volumio is normally housed under /var/www/:

  1. I pulled the git content into /home/earl/volumio/.
  2. For each file in /etc/ that is shadowed in volumio/_OS_SETTINGS/, create a symlink in /etc/ to that file. See the list below.
  3. Create a symlink from /home/volumio to volumio/_OS_SETTINGS/home/volumio/.
  4. Create a symlink from /var/www/ to /home/earl/volumio/.
  5. Leave /boot/cmdline.txt unlinked because it crosses a file system.

Some benefits of doing this:

  • For the most part, versions can be switched (eg git checkout) without having to copy files to /etc/.
  • Versions can be deployed side-by-side and compared easily. For example I left 1.4 installed in /var/www-1.4 and switched between the different versions by adjusting /var/www to point to either www-1.4 or /home/earl/volumio/.

I think there is one other significant benefit, and that is to make updating more robust. For example, here is one possibility:

  1. Download the update into /var/www-1.5/ (or whatever the new version is).
  2. Deploy new symlinks into /etc/ pointing them into /var/www/.
  3. Change the symlink from /var/www to point to www-1.5: ln -sfn www-1.5 /var/www

The key idea here is that the switch to the new version is done as an atomic operation in the final step ©, and that preparation for that final step is done as a sequence of restartable steps beforehand.

The remain some issues:

  • Totally new files in /etc/. Perform step (b) and those symlinks will point at non-existent files in /var/www-1.4 (or whatever the previous version is).
  • Replacing existing files in /etc/. This is trickier. I think the best approach would be to have a pre-upgrade step that copies /var/www/ into /var/www-tmp/. Copy the files in /etc/ that will be replaced into /var/www-tmp/. Create symlink (atomically) /var/www to point to www-tmp. Then for each replacement, create a corresponding symlink in /etc/ to /var/www. At this point the symlinks are in place, but they point at pre-existing content. Once the pre-upgrade step is complete, perform the upgrade steps (a) to ©.
  • Removing content in /etc/. After performing upgrade steps (a) to ©, these symlinks in /etc/ will not be resolvable in /var/www-1.5 because this content no longer exists. As a post-upgrade step, remove the corresponding symlinks in /etc/ which point to content in /var/www which no longer exists.

etc/fstab_raspberry -> ../var/www/_OS_SETTINGS/etc/fstab_raspberry etc/init.d/boot.localfs-tmp -> ../../var/www/_OS_SETTINGS/etc/init.d/boot.localfs-tmp etc/init.d/transientlog -> ../../var/www/_OS_SETTINGS/etc/init.d/transientlog etc/init.d/upmpdcli -> ../../var/www/_OS_SETTINGS/etc/init.d/upmpdcli etc/minidlna.conf -> ../var/www/_OS_SETTINGS/etc/minidlna.conf etc/motd -> ../var/www/_OS_SETTINGS/etc/motd etc/nginx/nginx.conf -> ../../var/www/_OS_SETTINGS/etc/nginx/nginx.conf etc/php5/cli/php.ini -> ../../../var/www/_OS_SETTINGS/etc/php5/cli/php.ini etc/php5/fpm/php-fpm.conf -> ../../../var/www/_OS_SETTINGS/etc/php5/fpm/php-fpm.conf etc/php5/fpm/php.ini -> ../../../var/www/_OS_SETTINGS/etc/php5/fpm/php.ini etc/php5/fpm/pool.d/command.conf -> ../../../../var/www/_OS_SETTINGS/etc/php5/fpm/pool.d/command.conf etc/php5/fpm/pool.d/db.conf -> ../../../../var/www/_OS_SETTINGS/etc/php5/fpm/pool.d/db.conf etc/php5/fpm/pool.d/display.conf -> ../../../../var/www/_OS_SETTINGS/etc/php5/fpm/pool.d/display.conf etc/php5/mods-available/apc.ini -> ../../../var/www/_OS_SETTINGS/etc/php5/mods-available/apc.ini etc/rc.local -> ../var/www/_OS_SETTINGS/etc/rc.local etc/samba/smb.conf -> ../../var/www/_OS_SETTINGS/etc/samba/smb.conf etc/upmpdcli.conf -> ../var/www/_OS_SETTINGS/etc/upmpdcli.conf etc/usbmount -> ../var/www/_OS_SETTINGS/etc/usbmount

Agree: I also personally created a sym-link for /var/www to another place (/home/pi/webui) , because I think the “www” folder should not automatically be the GIT root. Some files stored on GIT don’t have to be exposed on a web server (and that’s why some weeks ago a special rule has been made in nginx.conf, to exclude OS_SETTINGS)