nexus-client
Introduction
nexus-client is the client component of the Nexus project, a VDI (Virtual Desktop Infrastructure) written from scratch in Go and based on Linux/KVM + QEMU.
Components
The full project, nexus_vdi, is made of three software components:
-
nexus-server: the server program (backend) that runs on a server.
- Exposes a REST API to manage VMs and users
-
nexus-client: the client or end-user program to manage VMs, users and templates.
- The client uses REST messages to communicate with
nexus-server
- The client can be run from anywhere (locally or remotely) as long as it can communicate with
nexus-server
- Two clients have been developed so far:
-
nexush
: an interactive command line client, similar to a shell. It is the most user-friendly way to interact withnexus-server
, but it is not suited for scripting. -
nexus-cli
: a collection of commands particularly suited to scripting and automated operations. - Both clients offer the same features, functionalities and syntax. A nice touch is that commands support regular expressions allowing many VMs to be created/started/stopped/destroyed/etc. at once.
-
- Both clients feature an "vmattach" command which lets users interact with their VM's desktop.
- this feature requires
remote-viewer
which is part of the virt-viewer project
- this feature requires
- The client uses REST messages to communicate with
- nexus-exam: a minimalistic graphical client used during live exams. It doesn't feature any option and only allows a student to connect to a running VM.
Access control
Access control is implemented through capabilities. Capabilities define what users can or cannot do. They are divided into two categories:
- User capabilities: define user access control; these are stored in the user metadata
- VM access capabilities: define access to VMs; these are stored in the VM metadata
User capabilities
USER_CREATE
USER_DESTROY
USER_SET_CAPS
USER_LIST
VM_CREATE
VM_DESTROY_ANY
VM_EDIT_ANY
VM_START_ANY
VM_STOP_ANY
VM_LIST_ANY
VM_READFS_ANY
VM_WRITEFS_ANY
VM_SET_ACCESS
TPL_CREATE
TPL_DESTROY
TPL_DESTROY_ANY
TPL_LIST
TPL_LIST_ANY
VM access capabilities
When a user creates a VM, she automatically gets all VM access capabilities:
VM_SET_ACCESS
VM_DESTROY
VM_EDIT
VM_START
VM_STOP
VM_LIST
VM_READFS
VM_WRITEFS
No other users get any access to the created VM. However, the VM owner can add any access type to any users they like.
QEMU Guest Agent
To be available, certain features require a dedicated service, QEMU Guest Agent, to be running in the VM's guest OS. This is the case of the vmshutdown
command which gracefully shutdowns a VM. This command won't work otherwise.
On a Ubuntu/Debian system, the qemu-guest-agent
service can be installed with:
sudo apt-get install qemu-guest-agent
Consequently, it is highly recommended to install it in all templates as it gives you more features and control over the VMs.
nexush
nexush
is a nexus-client in the form of a single executable file featuring the commands listed below.
Most commands support regular expressions (regex) in order to perform actions on multiple VMs and templates at once.
Welcome to nexush, the nexus shell.
Type: "help" for help on commands
"ls" to list files in current directory
"ls dir" to list files in dir
"quit" to quit nexush
nexush> help
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
refresh Obtains a new access token.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
whoami Displays the current user's details.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
passwd Updates the current user's password.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
userlist Lists users (regex).
Requires USER_LIST user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
useradd Adds a user.
Requires USER_CREATE user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
userdel Deletes one or more users.
Requires USER_DESTROY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
usersetcaps Sets a user's capabilities.
Requires USER_SET_CAPS user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmlist Lists VMs that can be listed (regex).
Requires VM_LIST VM access capability or VM_LIST_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmliststart Lists VMs that can be started (regex).
Requires VM_START VM access capability or VM_START_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmlistattach Lists VMs that can be attached to (regex).
Requires VM_LIST VM access capability or VM_LIST_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmliststop Lists VMs that can be stopped or shutdown (regex).
Requires VM_STOP VM access capability or VM_STOP_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmlistedit Lists VMs that can be edited (regex).
Requires VM_EDIT VM access capability or VM_EDIT_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmlisteditaccess Lists VMs that can have their VM access edited (regex).
Requires VM_SET_ACCESS user capability and VM_SET_ACCESS VM access capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmlistdel Lists VMs that can be deleted (regex).
Requires VM_DESTROY VM access capability or VM_DESTROY_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmlistexportdir List VMs that can have a directory exported (regex).
Requires VM_READFS VM access capability or VM_READFS_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmcred2pdf Creates a PDF with the credentials required to attach to running VMs (regex).
Requires VM_LIST VM access capability or VM_LIST_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmstart Starts one or more VMs (regex).
Requires VM_START VM access capability or VM_START_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmstop Stops by force one or more VMs (regex).
Requires VM_STOP VM access capability or VM_STOP_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmshutdown Gracefully shutdowns one or more VMs (regex).
Requires VM_STOP VM access capability or VM_STOP_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmattach Attaches to one or more VMs in order to use their desktop environment (regex).
Requires VM_LIST VM access capability or VM_LIST_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmcreate Creates one or more VMs (regex).
Requires VM_CREATE user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmedit Edits one or more VMs' properties: name, cpus, ram or nic (regex).
Requires VM_EDIT VM access capability or VM_EDIT_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmdel Deletes one or more VMs (regex).
Requires VM_DESTROY VM access capability or VM_DESTROY_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmsetaccess Sets a user's VM access in one or more VMs (regex).
Requires VM_SET_ACCESS user capability and VM_SET_ACCESS VM access capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmdelaccess Deletes a user's VM access in one or more VMs (regex).
Requires VM_SET_ACCESS user capability and VM_SET_ACCESS VM access capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
vmexportdir Exports one or more VMs' directory into one or more tar archives.
Creates one archive per VM (regex).
Requires VM_READFS VM access capability or VM_READFS_ANY user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
tpllist Lists available templates (regex).
Requires TPL_LIST or TPL_LIST_ANY user capabilities.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
tplcreate Creates a template from an existing VM.
Requires TPL_CREATE user capability.
―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
tpldel Deletes one or more templates (regex).
Requires TPL_DESTROY or TPL_DESTROY_ANY user capabilities.
Note that when attached to a VM's desktop (vmattach
command), ctrl+F12 toggles between fullscreen/non-fullscreen modes.
nexus-cli
nexus-cli
is another nexus-client in the form of a single executable file featuring pretty much the exact same commands as nexush
. Therefore we won't list them here.
Building nexush and nexus-cli
nexush
and nexus-cli
source codes must be obtained from the following git repository (using ssh key-pair authentication):
git clone ssh://git@ssh.hesge.ch:10572/flg_projects/nexus_vdi/nexus-client.git nexus-client.git
If you didn't set up a public key in your gitlab account, then you can obtain the sources through https with:
git clone https://gitedu.hesge.ch/flg_projects/nexus_vdi/nexus-client.git nexus-client.git
Building nexush
To build the nexush
executable, go into nexus-client.git/src/nexush
and run:
go build .
To build a statically linked, stripped and compressed version of nexush
, run:
CGO_ENABLED=0 go build -a -ldflags '-w -extldflags "-static"'
strip -s nexush
upx nexush
Building nexus-cli
To build the nexus-cli
executable, do exactly the same as with nexush
but replace every instance of nexush
with nexus-cli
.
Running nexush and nexus-cli
Both nexush
and nexus-cli
require two environment variables:
-
NEXUS_SERVER
: specifies the Nexus server to connect to along the port number. -
NEXUS_CERT
: specifies the path to the public certificate required for encrypted communication (TLS) with the Nexus server.
Example of variables initialization:
export NEXUS_SERVER=192.168.1.25:1077
export NEXUS_CERT=/home/janedoe/nexus-ca-cert.pem
nexush usage examples
Launch nexush
and log in as user janedoe@nexus.org
(note that you will be prompted for your password):
./nexush janedoe@nexus.org
Display available commands:
help
Display the help for the vmcreate
command:
vmcreate
Display information about the currently logged-on user:
whoami
List all users:
userlist .
List users matching the "jane" pattern:
userlist jane
Add new user lukeskywalker@force.net
with a list of capabilities:
useradd lukeskywalker@force.org Luke Skywalker maytheforcebewithyou USER_CREATE USER_DESTROY USER_LIST USER_SET_CAPS VM_CREATE
List all listable VMs:
vmlist .
List all listable VMs with more details ("long output"):
vmlist -l .
List listable VMs matching the "ubuntu" pattern:
vmlist ubuntu
List listable VMs matching the "ubuntu" pattern and also the VM with ID 6713ce26-941e-4d95-8e92-6b71d44bf75a
:
vmlist ubuntu 6713ce26-941e-4d95-8e92-6b71d44bf75a
List all VMs that can be started:
vmliststart .
Start VM 6713ce26-941e-4d95-8e92-6b71d44bf75a
:
vmstart 6713ce26-941e-4d95-8e92-6b71d44bf75a
Start VMs matching the "exam ISC_433 PCO" pattern:
vmstart "exam ISC_433 PCO"
List all VMs that can be attached to:
vmlistattach .
Attach to VM 6713ce26-941e-4d95-8e92-6b71d44bf75a
and all VMs matching the pattern "zorglub":
vmattach 6713ce26-941e-4d95-8e92-6b71d44bf75a zorglub
List all VMs that can be shutdowned or stopped:
vmliststop .
Shutdown VMs matching the "exam ISC_433 PCO" pattern (for this to work, qemu-guest-agent
must be running in the VM's guest OS!):
vmshutdown "exam ISC_433 PCO"
Stop by force VM 6713ce26-941e-4d95-8e92-6b71d44bf75a
:
vmstop 6713ce26-941e-4d95-8e92-6b71d44bf75a
Create a VM named "Doom", based on the fbccb584-9ea6-40f7-926d-dabf3970525e
(Doom) template, with 4 CPUs, 4GB RAM, and a network interface with NAT translation:
vmcreate Doom 4 4096 user fbccb584-9ea6-40f7-926d-dabf3970525e
Create 50 VMs with the base name "ISC_433 Exam" based on the 6713ce26-941e-4d95-8e92-6b71d44bf75a
template, with 2 CPUs, 2GB RAM, and no network interface:
vmcreate "ISC_433 Exam" 2 2048 none 6713ce26-941e-4d95-8e92-6b71d44bf75a 50
It takes about 30 seconds and 11MB of disk space to create these 50 VMs. They will have the following names:
ISC_433 Exam [1]
ISC_433 Exam [2]
...
ISC_433 Exam [50]
List all VMs that can be edited:
vmlistedit .
Edit VM 6713ce26-941e-4d95-8e92-6b71d44bf75a
by changing its name to "Tagada VM", changing it to 1 CPU and no network interface (none
):
vmedit 6713ce26-941e-4d95-8e92-6b71d44bf75a name="Tagada VM" cpus=1 nic=none
Edit VMs matching the "PCO lab2" pattern by changing their CPU to 1 core and a network interface with NAT translation (user
):
vmedit "PCO lab2" cpus=1 nic=user
List all VMs that can be deleted:
vmlistdel .
Delete VM 6713ce26-941e-4d95-8e92-6b71d44bf75a
:
vmdel 6713ce26-941e-4d95-8e92-6b71d44bf75a
Delete VMs matching the "exam ISC_433 PCO" pattern:
vmdel "exam ISC_433 PCO"
List all VMs that can have their access edited:
vmlisteditaccess .
Set the VM access for VM 89649fe3-4940-4b77-929e-50903789cd87
with: VM_LIST
and VM_DESTROY
for user student@nexus.org
:
vmsetaccess 89649fe3-4940-4b77-929e-50903789cd87 student@nexus.org VM_LIST VM_DESTROY
Set VM access for VMs matching the "alpine" pattern with: VM_START
and VM_STOP
for user student@nexus.org
:
vmsetaccess alpine student@nexus.org VM_START VM_STOP
Remove VM access for student@nexus.org
from VM 89649fe3-4940-4b77-929e-50903789cd87
:
vmdelaccess 89649fe3-4940-4b77-929e-50903789cd87 student@nexus.org
Remove VM access for student@nexus.org
from VMs matching the "lab2" pattern:
vmdelaccess lab2 student@nexus.org
Generate exam_vms.pdf
with the credentials required to connect to all running VMs matching "exam prog sys":
vmcred2pdf "exam prog sys" output.pdf
Extract and download the /home
directory of all VMs matching "exam prog sys" (each directory is saved in a .tar
archive named after the VM's ID):
vmlistexportdir "exam prog sys" /home
List all available templates:
tpllist .
List templates matching the "ubuntu" pattern:
tpllist ubuntu
Create a new public
template, named "Xubuntu 22.04 + golang toolchain" based on VM 89649fe3-4940-4b77-929e-50903789cd87
(public
templates are accessible to everyone while private
templates are only accessible to their creators):
tpllist 89649fe3-4940-4b77-929e-50903789cd87 "Xubuntu 22.04 + golang toolchain" public
Delete template d164992b-741e-46db-b71b-27087f2123f5
:
tpldel d164992b-741e-46db-b71b-27087f2123f5
Delete all templates matching the "test" pattern:
tpldel test
Quit nexush
:
quit
nexus-cli usage examples
Given nexus-cli
offers the same VM, user and template commands as nexush
, we only show a handful of examples here.
List available commands:
./nexus-cli
Authentify user janedoe@nexus.org
and obtain an access token:
export NEXUS_TOKEN=`./nexus-cli login janedoe@nexus.org pipomolo`
Start VM 6713ce26-941e-4d95-8e92-6b71d44bf75a
:
vmstart 6713ce26-941e-4d95-8e92-6b71d44bf75a
nexus-exam
Compiling nexus-exam
Get the source code with:
git clone ssh://git@ssh.hesge.ch:10572/flg_projects/nexus_vdi/nexus-client.git
To build the nexus-exam
executable, run:
go build .
Unfortunately, nexus-exam
cannot be built statically (on Ubuntu 20.04 and 22.04 at least) as some static libraries are missing.
Running nexus-exam
nexus-exam
requires two environment variables:
-
NEXUS_SERVER
: specifies the Nexus server to connect to. -
NEXUS_CERT
: specifies the path to the public certificate required for encrypted communication (TLS) with the Nexus server.
Example of variables initialization:
export NEXUS_SERVER=192.168.1.25
export NEXUS_CERT=/home/janedoe/nexus-ca-cert.pem
Below is a screenshot of nexus-exam
's graphical interface:
Tutorial: creating a live exam with nexush
Let's say you want to create an exam for the class "ISC_433_PCO". Let's assume 50 students are enrolled in the class.
First, you need to create the VM that will be used by the students during the exam. Typically, this VM will contain the exam environment (compilers, editors, tools, etc.) along the description of the exam, for instance as a PDF on the desktop.
-
First, authenticate onto the nexus server (make sure the
NEXUS_SERVER
andNEXUS_CERT
environment variables are properly initialized):export NEXUS_SERVER=192.168.1.25:1077 export NEXUS_CERT=/home/janedoe/nexus-ca-cert.pem ./nexush janedoe@nexus.org
After entering your password, you should see:
janedoe@nexus.org's password: Welcome to nexush, the nexus shell. Type: "help" for help on commands "ls" to list files in current directory "ls dir" to list files in dir "quit" or "exit" to quit nexush nexush>
-
List available templates and choose the one you wish to use for your exam VM:
tpllist .
This command displays the templates you can use:
Debian 11 xfce | 29d9dd54-e001-4920-a9a8-4446d6c7d877 | public Fedora 36 gnome | 4913a2bb-edfe-4dfe-af53-38197a44523b | public Manjaro 21 xfce | a7867c1e-9369-41f7-a09d-af8c1401538f | public Ubuntu 22.04 | 79964f07-42e6-41ae-b62b-2a23d18192fd | public Xubuntu 22.04 | d164992b-741e-46db-b71b-27087f2123f5 | public
Let's assume template
d164992b-741e-46db-b71b-27087f2123f5
(Xubuntu_22.04), is the one you would like to use. -
Create the VM based on the chosen template. Let's say you want the VM to be named "Exam ProgSys Oct2022" and you want it to have 2 CPUs, 3GB RAM and access to the Internet (for now):
vmcreate "Exam ProgSys Oct2022" 2 3000 user d164992b-741e-46db-b71b-27087f2123f5
This command displays the name and ID of the created VM(s):
Created VM "Exam ProgSys Oct2022" | e81f5481-f2e3-491d-9d22-a0247092ce9e
-
Now that the VM is created, you need to start it, connect to it, and configure it to fit your needs. First, start it by starting any VM mathing the following expression (you can also start it by specifying its VM ID):
vmstart "exam progsys"
This command displays the name of the started VM(s):
Started VM "Exam ProgSys Oct2022"
-
Attach to the VM in order to configure it to your needs (you can also attach to it by specifying its VM ID):
vmattach "exam progsys"
-
Configure the VM to suit your needs, by:
- upgrading the system with
sudo apt-get update && apt-get upgrade
- installing the QEMU Guest Agent with
sudo apt-get install qemu-guest-agent
(so you will be able to use thevmshutdown
command) - installing the applications, compilers, tools, editors, etc. that are required for the exam
- copying to the desktop the file describing the exam's objectives Once done, you can shutdown the VM.
- upgrading the system with
-
Now that the VM is ready for the exam, create a template from it. The template must be
private
as we don't want anyone else to access it. Let's choose "Exam ProgSys Oct2022" as the template name (template creation takes several minutes, the larger the VM, the longer). The first argument is the VM ID (as displayed when the VM was created earlier):tplcreate e81f5481-f2e3-491d-9d22-a0247092ce9e "Exam ProgSys Oct2022" private
This command displays details about the newly created template:
{ "id": "bc8b32e9-dab1-41e6-9de1-deda5e3444c6", "name": "Exam ProgSys Oct2022", "owner": "janedoe@nexus.org", "access": "private" }
-
You can now create the VMs for your 30 students using your new template (ID
bc8b32e9-dab1-41e6-9de1-deda5e3444c6
). Let's say the base name for the 30 VMs to create is "Live Exam ProgSys Oct2022". You want the VMs to have: 2 CPUs, 3GB RAM and no network interface to prevent any fraud. Create a CSV file, saystudents.csv
with the names of your 30 students, one per line. Then, create the 30 VMs with:vmcreate "Live Exam ProgSys Oct2022" 2 3000 none bc8b32e9-dab1-41e6-9de1-deda5e3444c6 students.csv
This command displays each VM created:
Created VM "Live Exam ProgSys Oct2022 [Alia Friedman]" | 74d8b83d-f59e-4129-bf68-af574968cf48 Created VM "Live Exam ProgSys Oct2022 [Aria Doyle]" | f3047faa-2f15-4f47-b79f-9acc19751b6c Created VM "Live Exam ProgSys Oct2022 [Avah Coffey]" | 3ebd56a2-2c1e-416c-9847-f80ee3efa1c1 Created VM "Live Exam ProgSys Oct2022 [Briley Brady]" | 245fc5b2-b192-4b41-80be-2d39b5a2cef2 Created VM "Live Exam ProgSys Oct2022 [Brooklyn Sweeney]" | a9bafd7e-28f0-4f37-8b90-5e3c82d4bbc5 Created VM "Live Exam ProgSys Oct2022 [Cornelius Simmons]" | 40edb2b1-b4e9-4928-9dea-316ed834bf07 Created VM "Live Exam ProgSys Oct2022 [Donovan Heath]" | 8ae5c9cd-16f3-4e02-a940-e4209a6d7010 Created VM "Live Exam ProgSys Oct2022 [Ella Webster]" | 7d16f88f-afb1-4633-a646-57a9c87411d5 ...
-
The day of the exam, you'll have to start the 30 VMs and generate a PDF with the credentials required to connect to each VM. To start the 30 VMs, run:
vmstart "live exam progsys"
This command displays each VM started:
Started VM "Live Exam ProgSys Oct2022 [Alia Friedman]" Started VM "Live Exam ProgSys Oct2022 [Aria Doyle]" Started VM "Live Exam ProgSys Oct2022 [Avah Coffey]" Started VM "Live Exam ProgSys Oct2022 [Briley Brady]" Started VM "Live Exam ProgSys Oct2022 [Brooklyn Sweeney]" Started VM "Live Exam ProgSys Oct2022 [Cornelius Simmons]" Started VM "Live Exam ProgSys Oct2022 [Donovan Heath]" Started VM "Live Exam ProgSys Oct2022 [Ella Webster]" ...
-
Finally, to produce the PDF file,
creds.pdf
, with all credentials required to attach to each VM, run:vmcred2pdf "live exam progsys" creds.pdf
This command displays that file was written successfully:
creds.pdf written successfully.
-
You can now print the PDF above, cut each line and give each student the strip of paper for their VM. Once a student has completed their exam, they shutdown their VM and give you the strip of paper back. Note that you can also shutdown the VM yourself with
nexus-cli vmshutdown
(provided the guest OS is runningqemu-guest-agent
). You can also force a VM to be stopped withnexus-cli vmstop
although it's not recommended as it might corrupt the VM's filesystem. -
To correct the students' exams, simply download the relevant files to your computer using
vmexportdir
. As an example, the command below extracts and downloads the/home
directory of all VMs matching "Live Exam ProgSys" (each directory is saved in a.tar
archive named after the VM's name):vmexportdir "live exam progsys" /home
This command displays each exported file tree:
Successfully exported /home from VM "Live Exam ProgSys Oct2022 [Alia Friedman]" into Live Exam ProgSys Oct2022 [Alia Friedman].tar Successfully exported /home from VM "Live Exam ProgSys Oct2022 [Aria Doyle]" into Live Exam ProgSys Oct2022 [Aria Doyle].tar Successfully exported /home from VM "Live Exam ProgSys Oct2022 [Avah Coffey]" into Live Exam ProgSys Oct2022 [Avah Coffey].tar Successfully exported /home from VM "Live Exam ProgSys Oct2022 [Briley Brady]" into Live Exam ProgSys Oct2022 [Briley Brady].tar Successfully exported /home from VM "Live Exam ProgSys Oct2022 [Brooklyn Sweeney]" into Live Exam ProgSys Oct2022 [Brooklyn Sweeney].tar Successfully exported /home from VM "Live Exam ProgSys Oct2022 [Cornelius Simmons]" into Live Exam ProgSys Oct2022 [Cornelius Simmons].tar Successfully exported /home from VM "Live Exam ProgSys Oct2022 [Donovan Heath]" into Live Exam ProgSys Oct2022 [Donovan Heath].tar Successfully exported /home from VM "Live Exam ProgSys Oct2022 [Ella Webster]" into Live Exam ProgSys Oct2022 [Ella Webster].tar ...