
Welcome to decal.

This is currently a research project into alternative ways to
using different development environments.

The end goal is this

 a) Allow multiple development environments to coexist on
    a host (workstation) that provide a specific set of
    packages (eg a specific version of ruby/gcc/python etc)
    without affecting the host system, OR any other users.

 b) Allow a user to create image "layers" as a different (and
    hopefully more convenient) way of packaging applications
    and content.

Both of these rely on the (ab)use of container technology, like
Linux kernel namespaces.

For now, there is only a tool for the second of two scenarios above.
It's called "decal":

  A decal (/ˈdiːkæl/, US also /dɪˈkæl/, CA /ˈdɛkəl/) or
  transfer is a plastic, cloth, paper, or ceramic substrate that
  has printed on it a pattern or image that can be moved to another
  surface upon contact, usually with the aid of heat or water.

Here's how it works:

1. Decal runs a command in a subprocess, with a file system
   namespace that consists of several layers

     - the root file system, in readonly mode (currently, this
       is always the host root FS, ie "/")

     - a FS overlay to which any modifications made by the
       command will be saved

     - most "regular" file systems that the user may require,
       mounted r/w in the same location as in the host FS

   In other words, your process continues to see all NFS mounts,
   a mounted /home volume, etc. If you type "make install"
   in your favorite project (as root), this will appear to install
   your files in their proper locations. However, the host
   file system will not be modified; instead, all modifications
   will be recorded in the overlay instead.

   For example, you can run it like this:

     decal zypper install python-setuptools

   This will run zypper inside the virtual environment, and
   all files from the python-setuptools will wind up inside
   the overlay (as well as all modifications to the RPM
   database).

2. When the subcommand exits, the entire setup is torn down
   again, including any temporary file systems and directories
   created during the setup phase.
   
   In order to retain the changes recorded in the overlay,
   you have two choices. You can explicitly specify an
   overlay directory via the --overlay option; this directory
   must be empty when you start - and it will contain all
   changes when done.

   Alternatively, you can specify a post-processing command
   using the --post-process option.



Stacking extra layers

You can insert additional layers between your root and your
top-most overlay, simply by specifying the --add-layer option.

A layer is simply a directory containing two subdirectories,
fs and work, respectively. The "work" subdirectory should be
empty (and should stay empty). The "fs" subdirectory contains the
actual directory tree you want to overlay on top of your file
system.

In order to add files, simply drop them into this hierarchy
in the appropriate place.

In order to hide files that exist in your root fs, you can
create special whiteout files. A whiteout file is a character
device with major/minor 0, and permissions 000. So, assume you want
to make all python stuff disappear in your environment; you could
achieve this by something like this:

  for dir in /usr/lib*/python*; do
  	mknod --mode 000 $layer/fs/$dir c 0 0
  done

Note that this only hides the directories; entries for all
python packages will still appear in the rpm database. So,
the slightly better way would be to first create a layer
that hides anything you want to hide, and then use it to
set up a clean development environment on top:

  mkdir -p $my_layers/hide-stuff/{fs,work}
  decal --overlay $my_layers/hide-stuff
  # zypper remove python-base
  # exit

  decal --add-layer $my_layers/hide-stuff ...
  # rpm -qa | grep ^python-'
  (shows nothing)



Protecting subvolumes of your root fs

On SUSE, when the root FS resides on a btrfs, there will be lots of
subvolumes (eg for /var/log, etc) - and all of them are actual mount
points. If we do not do anything, these mounts will not show up in
the container (because you have to re-mount them to the container
explicitly). However, you do not want them to be modifiable from the
container either. Neither do you want to mount them read-only, because
then the user would run into unexpected errors.

To work around this, the tool creates additional overlay mounts that
make these subvolumes appear in the container, with all modifications
going to the main overlay. So if, for example, your application
writes to a log file in /var/log, that change will show up in
$overlay/var/log - but not in the host file system.


Unix sockets in the container environment

Currently, /var/run is not exposed to the container environment, as this
would create too much havoc with the host system (eg packages installed
or removed in the container would try to talk to systemd from their
pre/post scripts).

In particular, UNIX sockets that have been created in the host file
system cannot be connected to from the container environment.
