Virtual machine internals
=========================

Overview
--------

The virtual machine runs Alpine linux installed with LVM on LUKS disk encryption. The installation steps are loosely based on the official walkthrough on `LVM on LUKS <https://wiki.alpinelinux.org/wiki/LVM_on_LUKS>`_ Alpine wiki page.

Alpine linux is minimalistic linux distribution using *musl c* library (as opposed to *glibc*) and OpenRC init system. By default, the distro aims to be strictly POSIX-compliant. The main set of utilities is based on ``busybox``, however the full-featured variants of any well-known linux utilities can be installed. Installation of any package is done via APK (*Alpine Package Keeper*) which is the Alpine-native package manager. Package repository can be browsed on `pkgs.alpinelinux.org <https://pkgs.alpinelinux.org/packages>`_.

Disk partitioning
-----------------

By default, the VM is created with 300 MB hard drive divided into two partitions. The first partition is 50 MB in size and serves as ``/boot`` partition for *EXTLINUX* bootloader. The second partition with 250 MB in size serves as physical volume for encryption. The encrypted LUKS volume spans over the whole partition and is called ``system``. This volume is part of ``vg0`` LVM volume group. On this volume group, logical volume named ``root`` formatted as ext4 is created spanning over the whole ~250 MB and mounted as ``/``.

Such small initial size of the VM is needed to minimize the size of virtual appliance export as it forces the ext4 to cram all it needs to write to that 250 MB range and overwrite freed space if needed. Once the initial installation is done, the VM disk can be extended to any larger size. Somewhere between 40 and 80 GB is plenty for the start. VM is then immediately exported as virtual appliance (OVA) without any subsequent runs.

There is a script ``/sbin/extend-disk`` which is called by ``vmtty`` (see Pseudoterminal_) which compares the total size of the virtual disk device with size allocated by the filesystems. If the size differs and the device is more that 10 MB larger, the script triggers adjustment on all filesystem levels (i.e. LUKS volume, LVM physical volume, LVM logical volume and the ext4 filesystem). A password for LUKS encryption is requested to be input by the user. In case the virtual disk is larger by 4 GB or more and the swap volume doesn't exist yet, the script automatically creates it. All the steps are expected to happen at least once, on the first run when the user imports and starts the virtual appliance.

The final filesystem layout is expected to look as follows:

.. code-block:: text

    spotter:~# lsblk -o name,fstype,size,mountpoint
    NAME           FSTYPE      SIZE MOUNTPOINT
    sda                         80G
    ├─sda1         ext4         50M /boot
    └─sda2         crypto_LUKS  80G
      └─system     LVM2_member  80G
        ├─vg0-root ext4         76G /
        └─vg0-swap swap          4G

Pseudoterminal
--------------

There is a customized terminal executable ``/sbin/vmtty``, which is spawned and handled via ``getty`` on VM startup. The purpose of the terminal is to execute the ``extend-disk`` script described above and display contents of ``/etc/issue``. The terminal does not allow login and servers solely for informative purposes. The content of ``/etc/issue`` is initially the Alpine default, but it is populated by VMMgr via ``vmmgr rebuild-issue`` every time the terminal process is spawned.

Traditionally, there are several pseudoterminals spawned on linux machines, including one listening on serial port. SpotterVM disables all terminals. All interaction is expected to be done via VMMgr, however VMMgr allows to add SSH key for root access, so if the need arises, the root console can be obtained.

Since the primary usage is expected to be in Central Europe, the terminal is expected to support fonts with diacritics. This is achieved by reconfiguration of ``consolefont`` to specifically support ``ISO 8859-2`` and enabling unicode support in OpenRC.

Web server
----------

By default, the only access to any VM features is available only through VMMgr, which runs as a standalone WSGI application. All access passes through *nginx* web server which serves as reverse proxy. See `VMMgr internals <vmmgr-internals.html#nginx-configuration>`_ for more detail on the nginx configuration.
