The scripts in this directory are experimental and are used to create testenvs
in separate linux namespaces. This avoids the need for socket-wrapper.

What are Namespaces
===================
Namespaces allow the kernel to segregate its system resources (files, CPU,
etc), so that different processes only see the set of resources they are
allowed to use. There are several different types of namespace: network,
user, process, file, IPC, and so on.

Key points to grasp are:
* Each type of namespace gets managed separately by the kernel, i.e. process
namespaces are managed separately to network namespaces, which are separate
to user namespaces. These scripts give each testenv its own network namespace,
but otherwise they all still share the same user/process/etc namespace.
(In future, we may want to give each testenv its own process and user
namespace, to better mimic a production DC).
* Namespaces are created using the 'unshare' utility. The new selftest
namespaces are anonymous/nameless, and so the different namespaces are
identified by the PID of the processes running within the namespace
(typically samba).
* Linux supports nesting namespaces within namespaces. In this case, each
testenv DC has its own network namespace, which is a child of the overarching
selftest namespace (which itself is a child of whatever namespace you run
'make test' from - usually this would be the root namespace).

How does it work?
=================
Normally when 'make test' is run, every testenv uses a 10.53.57.x IP address
and socket-wrapper passes the packets between them.

With namespaces, we also use 10.53.57.x IP addresses but have the packets pass through
the kernel's IP stack normally, as it forwards them between namespaces.

We use veth interfaces for this. veth is a type of virtual interface supported
by the kernel. veth interfaces come in pairs, and act as a tunnel - any packets
sent on a veth interface simply end up as received packets on the pair veth
interface.

We create a new veth interface pair for each testenv, and use them to connect
up the namespaces. One end of the veth pair is added to the main selftest
namespace, and the other end is added to a new namespace that we'll run
samba in. E.g.

selftest.pl  veth21-br ------------------------ veth21 samba (ad_dc_ntvfs)
             10.53.57.11                          10.53.57.21
 Namespace 1                                       Namespace 2

However, we need to run multiple different testenvs and have them talk to
each other. So to do this, we need a bridge interface ('selftest0') to connect
up the namespaces, which essentially just acts as a hub. So connecting together
multiple testenvs looks more like this:

selftest.pl     +-- veth21-br ------------------------ veth21 samba (ad_dc_ntvfs)
                |                                      10.53.57.21
    selftest0 --+                                        Namespace 2
    10.53.57.11   |
                +-- veth22-br ------------------------ veth22 samba (vampire_dc)
                                                       10.53.57.22
 Namespace 1                                             Namespace 3      

The veth interfaces are named vethX and vethX-br, where X is the
SOCKET_WRAPPER_DEFAULT_IFACE for the testenv. The vethX-br interface is always
added to the selftest0 bridge interface. 

How do I use it?
================
To use namespaces instead of socket-wrapper, just add 'USE_NAMESPACES=1' to the
make command, e.g.

To run the 'quick' test cases using namespaces:
USE_NAMESPACES=1 make test TESTS=quick

To setup an ad_dc testenv using namespaces:
USE_NAMESPACES=1 SELFTEST_TESTENV=ad_dc make testenv

You can connect secondary shells to the namespace your testenv is running in.
The command to do this is a little complicated, so a helper 'nsenter.sh' script
gets autogenerated when the testenv is created. E.g. to connect to the testenv
that the ad_dc is running in, use:
./st/ad_dc/nsenter.sh

This script also sets up the shell with all the same $SERVER/$USERNAME/etc
variables that you normally get in xterm.

To run the ad-dc-backup autobuild job using namespaces:
USE_NAMESPACES=1 script/autobuild.py samba-ad-dc-backup --verbose --nocleanup \
 --keeplogs --tail --testbase /tmp/samba-testbase

Using the customdc testenv, you can basically now essentially your own
light-weight samba VM. E.g.
MY_BACKUP=/home/$USER/samba-backup-prod-domain.tar.bz2
USE_NAMESPACES=1 BACKUP_FILE=$MY_BACKUP SELFTEST_TESTENV=customdc make testenv

You can then talk to that DC in any other shell by using
./st/customdc/nsenter.sh which enters the DC's network namespace (with
all the $SERVER/etc env variables defined).

How to join VMs to the testenv
----------------------------------------
I haven't tried this (beyond basic IP connectivity), but using namespaces it
should now be possible to connect a Windows VM to a Samba testenv.

1. Work out the main selftest.pl namespace PID manually, e.g.
SELFTEST_PID= ps waux | grep selftest.pl

2. Create a new veth to bridge between the selftest namespace and your PC's
default namespace:
sudo ip link add dev testenv-veth0 type veth peer name testenv-veth1

3. Move one end of the veth tunnel into the selftest namespace:
sudo ip link set testenv-veth1 netns $SELFTEST_PID

4. Configure the veth end in the default namespace to be in the same subnet
as the selftest network:
sudo ip link set dev testenv-veth0 up
sudo ip addr add 10.53.57.63/24 dev testenv-veth0

5. Enter the selftest namespace, bring that end of the pipe up, and add it to
to the main selftest0 bridge (that connects all the DCs together). We also need
to add a default route from selftest back to your PC's default namespace.
nsenter -t $SELFTEST_PID --net --user --preserve-credentials
ip link set dev testenv-veth1 up
ip link set testenv-veth1 master selftest0
ip route add default via 10.53.57.63
logout

Your Windows VM and samba testenv should now be able to talk to each
other over IP!

6. The other step is to get DNS working. You probably need to add dns_hub
(10.53.57.64) as a nameserver (at least on your Windows VM).

This should work for using RSAT tools on samba, or joining Windows to Samba
(depending on the schema version). Joining samba to Windows is a bit more
tricky, as the namespaces are tied to the *running* samba process.

What you'd probably want to do is run the join command to the windows VM
outside of testenv, create an offline backup-file of the resulting DB, and
then plug that backup-file into the customdc testenv. (And then follow the
above veth/bridge steps to join samba to the VM).

Note that the namespace disappears once you stop the testenv, so you'd
need to do the above steps with creating the veth interface every time
you restarted the testenv.

Known limitations
=================
- When running a testenv, sometimes xterm can fail to startup, due to a
  permissions problem with /dev/pts. This seems to be a particular problem
  with the 'none' testenv.
  A short-term work-around is to use a terminal that doesn't try to access
  /dev/pts, e.g. just use bash as the terminal:
  TERMINAL=bash TERMINAL_ARGS='--norc' USE_NAMESPACES=1 \
    SELFTEST_TESTENV=none make testenv
- Some test cases rely on socket-wrapper, so will fail when run using
  namespaces.
- Currently USE_NAMESPACES maps you (i.e. $USER) to root in the new namespace.
  This means any test cases that rely on being a non-root user will fail (i.e.
  anything that fails under 'sudo make test' will also fail with namespaces).
- Namespaces should work within docker, but currently the 'unshare' system
  call is disallowed on the gitlab CI runners.
