This document discusses the designs and technical details of `qvm-template`, a template manager application proposed in the 2020 Google Summer of Code program.
The goals of the project is to design a new mechanism for TemplateVM distribution and a unified tool for template management.
However, tracking inherently dynamic VM images with a package manager suited for static files creates some challenges.
For example, users may accidentally update the images, overriding local changes ([#996], [#1647]).
(Or in the case of [#2061], want to specifically override the changes.)
Other operations that work well on normal VMs are also somewhat inconsistent on RPM-managed templates.
This includes actions such as renaming ([#839]), removal ([#5509]) and backup/restore ([#1385], [#1453], [discussion thread 1], [discussion thread 2]).
In turn, this creates inconveniences and confusion for users ([#1403], [#4518]).
Also, the usage of RPM packages meant that installing a template results in arbitrary code execution, which is not ideal.
Besides distribution, users may also wish to have an integrated template management application ([#2062], [#2064], [#2534], [#3040]), as opposed to the situation where multiple programs are required for different purposes, e.g., `qubes-dom0-update`, `dnf`, `qvm-remove`, `qubes-manager`.
To tackle these issues, `qvm-template` is created.
It strives to provide not only a better mechanism for handling template installation but also a consistent user-facing interface to deal with template management.
The template manager needs to keep metadata of installed templates such as versions and origin.
This data can be stored via `qvm-features` to keep things consistent when, e.g., `qvm-remove` is used.
Besides, backups are also more easily handled this way.
Also, the fields can serve as an indicator of whether a template is installed by `qvm-template`.
### Fields ###
Most of the fields should be fairly self-explanatory.
-`template-name`
- Note that this field needs to be consistent with the template name to be considered valid.
-`template-epoch`
-`template-version`
-`template-release`
-`template-reponame`
-`template-buildtime`
-`template-install-date`
- The times are in ISO 8601 format, and can be parsed in Python with `datetime.datetime.fromisoformat()`.
-`template-licence`
-`template-url`
-`template-summary`
-`template-description`
- Note that the newlines in this field are converted to `|` to work better with existing tools like `qvm-features`.
-`menu-items`
-`default-menu-items`
-`netvm-menu-items`
- The `*menu-items` entries store the contents of `var/lib/qubes/vm-templates/${template_name}/whitelisted-appmenus.list`, `var/lib/qubes/vm-templates/${template_name}/vm-whitelisted-appmenus.list`, `var/lib/qubes/vm-templates/${template_name}/netvm-whitelisted-appmenus.list` respectively.
- Note that newlines are converted to spaces, again for it to work better with existing tools.
This should not cause ambiguity as [the FreeDesktop specifications](freedesktop-spec) forbid spaces from the names of desktop files.
In other words, the input consists of two parts separated by the line `---`.
The first part contains some arguments and `package-file-spec` that indicates the pattern to be queried or downloaded.
The following arguments are allowed:
-`--enablerepo=<repoid>`
-`--disablerepo=<repoid>`
-`--repoid=<repoid>`
-`--releasever=<release>`
-`--refresh`
where the usage is identical to that of DNF.
For the exact definition of `package-file-spec`, refer to the DNF documentation.
The second part contains the repository configurations in `yum.repos.d` format.
### Output ###
`qubes.TemplateSearch` prints each package in `%{name}|%{epoch}|%{version}|%{release}|%{reponame}|%{downloadsize}|%{buildtime}|%{license}|%{url}|%{summary}|%{description}|` format to standard output, separated by newlines.
Note that there is a `|` at the end of the line.
This is because `%{description}` may contain newlines, and doing so allows us to split the entries by `|\n`.
(As we are using `dnf repoquery --qf`, we are unable to escape the newlines in advance.)
`qubes.TemplateDownload`, on the other hand, directly outputs the downloaded content to standard output.
Machine-readable Output
-----------------------
The commands `qvm-template list` and `qvm-template info` provide machine-readable output in both pipe(`|`)-separated and JSON format.
See the `qvm-template` man page for details.
Interactions with Existing Tools
--------------------------------
### `qvm-remove` ###
Should work straightforwardly.
### Renaming / Cloning ###
A template is treated as non-manager-installed once renamed or cloned.
However, relevant metadata in the VM features is still retained for future extension and to serve as a hint for the user.
Further Reading
---------------
Initial Google Summer of Code (2020) project proposal: