Autopkgtest Virtualisation Service Interface
============================================

The virtualisation server provides a single executable program which is
used by the tester core to request virtualisation facilities.

The server has the following states:

Closed
    there is no particular testbed. This is the initial state.

Open
    the testbed is running and can be communicated with (and, if
    applicable, is not being used by any other concurrent test run)

Note that these are the states of the server, in the tester core to
server protocol. The actual testbed will probably have more states,
including for example Closed, Open (and therefore busy), Modified,
Broken, etc. Ideally the virtualisation server will prevent multiple
concurrent uses of the same testbed; the tester core is allowed to
assume that either its caller or the virtualisation server will ensure
that it has exclusive use of the testbed.

The server program speaks a protocol on its stdin/stdout. The protocol
is line-based. In the future other ways of invoking the server may be
defined; the current server should of course reject such invocations.

Initial response from virtualization server after starting is ``ok``.
This response is also the response from any of the commands listed
below, unless otherwise specified.

Command: capabilities
---------------------

Response, for example:

::

    ok gnomovision-server revert ...

where the words after ``ok`` are features that not all servers support.
Valid in all states.

Currently defined capabilities:

downtmp-host=\ *path*
    If the testbed has the ability of setting up a shared directory with
    the host, this gives the host directory path of the "downtmp"
    directory as reported by the virt server's ``hook_downtmp()``
    function. This makes copying files in and out much more efficient.

isolation-container
    The testbed runs in a Linux cgroup/container (nspawn, LXC, docker,
    etc.) and thus tests have full control over starting services and
    opening network ports.

isolation-machine
    The testbed runs in a complete (virtual or real) machine on its own
    (qemu or bare metal) and thus tests have full control over starting
    services, opening network ports, interacting with the kernel (e. g.
    modprobe), rebooting, and accessing hardware.

reboot
    The testbed supports (re)booting, to pick up updated kernels and/or
    init system scripts from ``--setup-commands``, or from explicit
    reboot requests from tests.

revert
    The ``revert`` command is supported. The base semantics are that the
    following aspects of the testbed are reverted:

    - the set of installed packages
    - the contents of the root filesystem, BUT
    - *not* the contents of ``/home``
    - *not* the contents of ``/tmp``
    - *not* the set of running processes

    The testbed will actually revert when it is closed. If this feature
    is not mentioned then changes to the testbed are persistent (so
    destructive tests should not be performed).

revert-full-system
    The ``revert`` and ``close`` commands will completely revert the
    testbed to the state after ``open``. This reversion is done with
    some kind of virtualisation, and includes (without limitation) the
    contents of all the testbed filesystems, its running processes,
    network configuration, etc.

root-on-testbed
    Commands run through ``print-execute-command`` will be run as root
    on the testbed, and copyup/copydown will have full access to the
    filesystem. Unless this capability is advertised, root access is not
    (or may not be) available.

suggested-normal-user=\ *username*
    The caller is advised that *username* would be a good user to use
    for running tests (and doing other operations) when root is not
    required. The advertised account will exist on the testbed already.
    Several ``suggested-normal-user=`` capabilities (with distinct user
    names) may be advertised in which case more than one such user is
    available.

    In testbeds without ``isolation-machine`` or
    ``isolation-container``, the the testbed promises that this user
    does not run any untrusted code.  So it is OK for the root user
    inside the testbed to complete trust this user (by, for example,
    running code in files owned by this user).

    This is only meaningful if ``root-on-testbed`` is also advertised.

Command: open
-------------

Response:

::

    ok testbed-scratchspace

State: Closed to Open

Checks that the testbed is present and reserves it (waiting for other
uses of the testbed to finish first, if necessary).
``testbed-scratchspace`` is a pathname on the testbed which can be used
freely by the test scripts and which is valid until the next ``close``,
``revert``, or ``quit``.

In testbeds with ``isolation-machine`` or ``isolation-container``
capability, the scratchspace directory is world-writeable.
(This must be taken into account if the caller intends to impose
security boundaries within the testbed; but, such a situation would be
highly unusual for tests.)

In testbeds without such isolation, the directory is mode 755,
and owned by the testbed user; therefore, with the ``root-on-testbed``
capability, it is not writeable by the ``suggested-normal-user``.
If desired, the caller should use ``chown`` to change the ownership,
or create a suitable subdirectory.

(In autopkgtest 5.47 and earlier this directory was always mode 1777,
like ``/tmp``.  This was a security vulnerability in non-isolating
virt environments, and overly restrictive in isolating ones.)

Command: revert
---------------

Response:

::

    ok testbed-scratchspace

State: Open, remains Open

Restores the testbed, undoing all of the changes made so far. Only
available if the ``revert`` capability is advertised. If possible, the
testbed's set of running processes will also be restored to the initial
state.

Command: reboot
---------------

Response:

::

    ok testbed-scratchspace

State: Open, remains Open

Reboots the testbed, without reverting any changes to the files. Only
available if the ``reboot`` capability is advertised.

Command: close
--------------

Response:

::

    ok

State: Open to Closed

Stops the testbed and undoes filesystem changes (if ``revert`` is
advertised).

Command: print-execute-command
------------------------------

Response:

::

    ok program,arg,arg... [keyword-info ...]

Prints a command that can be executed by the caller to run a command on
the testbed.

The program has the following properties:

-  The caller is expected to url-decode ``program`` and each ``arg``,
   append the command to be run on the testbed, and call ``execve()`` on
   the resulting argv list.
-  That command might need to convert the argument list into a shell
   string with appropriate quoting if it implements the execute command
   with programs that take shell commands instead of argv lists, like
   ssh.
-  The testbed program's stdin, stdout and stderr will be plumbed
   through to the stdin, stdout and stderr passed to ``program``; this
   may involve fd passing, or indirection via pipes or sockets. The
   testbed program may not assume that the descriptors it receives are
   seekable even if the originals are.
-  It is not defined whether other file descriptors, environment
   variables, and process properties in general, are inherited by the
   testbed command.
-  ``program`` may exit as soon as the testbed command does, or it may
   wait until every copy of the stdout and stderr descriptors passed to
   the testbed command have been closed on the testbed.
-  ``program``'s exit status will be that of the testbed command if the
   latter exits with a value from 0..125. If the testbed command dies
   due to a signal, then either (i) ``program`` will exit with the
   signal number with 128 added, or (ii) ``program`` will die with the
   same signal (although it may fail to dump core even if the testbed
   program did), or (iii) ``program`` will fail. If ``program`` fails it
   will exit 254 or 255; of course ``program`` may die to a some signals
   other than because the testbed program died with the same signal.
-  The caller may run several of these at once, subject to limitation of
   resources (e. g. file descriptors or processes)
-  The behaviour if a command is running when the testbed is closed or
   reverted is not defined. However, if the testbed advertises
   ``revert`` then after the testbed is closed or reverted any such
   ``program`` invocation will not have any further effect on the
   testbed.
-  Sending ``program`` signals in an attempt to terminate it may not
   terminate all of the relevant processes and may not have any effect
   on the testbed.
-  The behaviour if no testbed command is specified (i. e., if just the
   specified ``program`` and ``arg``\ s is passed to exec) is not
   defined.
-  Currently no ``keyword-info``\ s are defined; they work the same way
   as capabilities in that unrecognised ones should be ignored by the
   caller.

The response is only valid between ``open`` and the next subsequent
``close``, ``revert`` or ``quit``. Using it at other times has undefined
behaviour.

To decode a print-execute-command response, and quote it for pasting
into a shell (for manual testing), paste the response into this:

::

   perl -MURI::Escape -ne '$|=1; s{^ok }{}; s/,/\0/g; print uri_unescape $_;' | jq -jrR '. / "\u0000" | @sh + "\n"'

Commands: copyup/copydown
-------------------------

Command:

::

    copydown host-path testbed-path
    copyup testbed-path host-path

Response:

::

    ok

Either

1. Both paths end in ``/``, in which case the source must be an existing
   directory.

2. Neither path ends in ``/``, in which case the source must be an
   existing file.

Both filenames are URL-encoded.

Command: quit
-------------

Response:

::

    ok

The server exits with status 0, after closing the testbed if applicable.

Command: shell
--------------

Response: one of

::

    ok
    not supported by virt server

Runs a shell in the testbed (as root, if available), while the testbed
is open. This is intended for interactively debugging problems with
tests. The virt server has to provide a ``hook_shell()`` function for
this, otherwise this command is not supported.

On any error including signals to the server or EOF on stdin the testbed
is unreserved and restored to its original state (ie, closed), and the
server will print a message to stderr (unless it is dying with a
signal).

..  vim: ft=rst tw=72


