summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManuel Bentele2021-06-25 14:23:19 +0200
committerManuel Bentele2021-06-25 14:23:19 +0200
commitc820bd818c488fb2ab14d51afa4d241b762d2fc6 (patch)
tree5f0c364c10820219ca418e6436c425074afc35e0
parent[debug-report-bwlp] add blkid output (diff)
parent[libvirt] Enforce libvirt UIDs/GIDs to not collide with LDAP UIDs/GIDs (diff)
downloadmltk-c820bd818c488fb2ab14d51afa4d241b762d2fc6.tar.gz
mltk-c820bd818c488fb2ab14d51afa4d241b762d2fc6.tar.xz
mltk-c820bd818c488fb2ab14d51afa4d241b762d2fc6.zip
Merge branch 'feature/qemu-integration'
-rw-r--r--core/modules/libvirt-users/module.build43
-rw-r--r--core/modules/libvirt-users/module.conf5
-rwxr-xr-xcore/modules/libvirt/data/addon-init6
l---------core/modules/libvirt/data/etc/libvirt/qemu/networks/autostart/br0.xml1
l---------core/modules/libvirt/data/etc/libvirt/qemu/networks/autostart/nat1.xml1
l---------core/modules/libvirt/data/etc/libvirt/qemu/networks/autostart/vsw2.xml1
-rw-r--r--core/modules/libvirt/data/etc/libvirt/qemu/networks/br0.xml6
-rw-r--r--core/modules/libvirt/data/etc/libvirt/qemu/networks/nat1.xml6
-rw-r--r--core/modules/libvirt/data/etc/libvirt/qemu/networks/vsw2.xml6
-rw-r--r--core/modules/libvirt/module.build14
-rw-r--r--core/modules/libvirt/module.conf9
-rw-r--r--core/modules/libvirt/module.conf.debian14
-rw-r--r--core/modules/libvirt/module.conf.ubuntu14
-rw-r--r--core/modules/openjdk-8-jre-headless/module.build13
-rw-r--r--core/modules/openjdk-8-jre-headless/module.conf5
-rw-r--r--core/modules/openjdk-8-jre-headless/module.conf.ubuntu9
-rwxr-xr-xcore/modules/qemu/data/addon-init4
l---------core/modules/qemu/data/etc/systemd/system/graphical.target.wants/qemu.service1
-rw-r--r--core/modules/qemu/data/etc/systemd/system/qemu.service11
-rwxr-xr-xcore/modules/qemu/data/opt/openslx/scripts/systemd-qemu_env46
-rw-r--r--core/modules/qemu/data/opt/openslx/vmchooser/plugins/qemu/run-virt.include53
-rw-r--r--core/modules/qemu/module.build26
-rw-r--r--core/modules/qemu/module.conf10
-rw-r--r--core/modules/qemu/module.conf.ubuntu17
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/.gitignore15
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/pom.xml179
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/App.java285
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgs.java511
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgsException.java25
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericCpu.java57
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskCdromDevices.java110
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskFloppyDevices.java104
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskStorageDevices.java102
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericFileSystemDevices.java107
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericInterfaceDevices.java101
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericMemory.java59
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericName.java57
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericParallelDevices.java97
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericUuid.java53
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuArchitecture.java261
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGpuPassthroughNvidia.java232
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuSerialDevices.java117
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/virtualization/LibvirtHypervisorQemu.java63
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/Viewer.java118
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerException.java35
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerLookingGlassClient.java105
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerUtils.java65
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerVirtManager.java75
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerVirtViewer.java97
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/virtualization/LibvirtHypervisor.java209
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/virtualization/LibvirtHypervisorException.java25
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/virtualization/LibvirtVirtualMachine.java150
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/virtualization/LibvirtVirtualMachineException.java25
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/AppTest.java202
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgsTest.java752
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericCpuTest.java49
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskCdromDevicesTest.java65
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskFloppyDevicesTest.java66
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskStorageDevicesTest.java62
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericFileSystemDevicesTest.java66
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericInterfaceDevicesTest.java63
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericMemoryTest.java50
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericNameTest.java45
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericParallelDevicesTest.java58
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericUuidTest.java43
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuArchitectureTest.java105
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGpuPassthroughNvidiaTest.java134
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuSerialDevicesTest.java74
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationTestResources.java17
-rw-r--r--core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationTestUtils.java119
-rwxr-xr-xcore/modules/qemukvm/data/addon-init8
-rw-r--r--core/modules/qemukvm/data/etc/qemu/bridge.conf6
l---------core/modules/qemukvm/data/etc/systemd/system/graphical.target.wants/qemukvm.service1
-rw-r--r--core/modules/qemukvm/data/etc/systemd/system/qemukvm.service9
-rw-r--r--core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/README1
-rw-r--r--core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/includes/determine_hardware_limitations.inc89
-rw-r--r--core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/includes/log_config_summary.inc35
-rw-r--r--core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/includes/setup_network.inc56
-rw-r--r--core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/includes/setup_rw_layer.inc25
-rw-r--r--core/modules/qemukvm/module.build18
-rw-r--r--core/modules/qemukvm/module.conf5
-rw-r--r--core/modules/qemukvm/module.conf.debian15
-rw-r--r--core/modules/qemukvm/module.conf.ubuntu15
l---------core/targets/qemu/libvirt1
l---------core/targets/qemu/libvirt-users1
l---------core/targets/qemu/openjdk-8-jre-headless1
l---------core/targets/qemu/qemu1
l---------core/targets/qemukvm/qemukvm1
88 files changed, 5734 insertions, 284 deletions
diff --git a/core/modules/libvirt-users/module.build b/core/modules/libvirt-users/module.build
new file mode 100644
index 00000000..cab41b98
--- /dev/null
+++ b/core/modules/libvirt-users/module.build
@@ -0,0 +1,43 @@
+#!/bin/bash
+fetch_source() {
+ :
+}
+
+build() {
+ :
+}
+
+post_copy() {
+ # Create libvirt users before installing libvirt packages since the
+ # libvirt DEB package hook script will create system users with an
+ # UID/GID greater or equal than 1000. Those default libvirt UIDs/GIDs
+ # are not allowed since they will collide with LDAP UIDs/GIDs.
+
+ # add system groups to run libvirt
+ if ! getent group libvirt-qemu >/dev/null; then
+ addgroup --quiet --system libvirt-qemu
+ fi
+
+ if ! getent group kvm >/dev/null; then
+ addgroup --quiet --system kvm
+ fi
+
+ # add system user libvirt runs qemu/kvm instances with
+ if ! getent passwd libvirt-qemu >/dev/null; then
+ adduser --quiet \
+ --system \
+ --ingroup kvm \
+ --quiet \
+ --disabled-login \
+ --disabled-password \
+ --home /var/lib/libvirt \
+ --no-create-home \
+ --gecos "Libvirt Qemu" \
+ libvirt-qemu
+ fi
+
+ # add libvirt system user to the libvirt system group
+ if ! getent group libvirt-qemu >/dev/null; then
+ adduser --quiet libvirt-qemu libvirt-qemu
+ fi
+}
diff --git a/core/modules/libvirt-users/module.conf b/core/modules/libvirt-users/module.conf
new file mode 100644
index 00000000..668ddf88
--- /dev/null
+++ b/core/modules/libvirt-users/module.conf
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+REQUIRED_BINARIES=""
+REQUIRED_LIBRARIES=""
+REQUIRED_DIRECTORIES=""
diff --git a/core/modules/libvirt/data/addon-init b/core/modules/libvirt/data/addon-init
new file mode 100755
index 00000000..131a03f7
--- /dev/null
+++ b/core/modules/libvirt/data/addon-init
@@ -0,0 +1,6 @@
+#!/bin/ash
+
+# register and start libvirt services
+systemctl daemon-reload
+systemctl start libvirtd.service
+systemctl start libvirt-guests.service
diff --git a/core/modules/libvirt/data/etc/libvirt/qemu/networks/autostart/br0.xml b/core/modules/libvirt/data/etc/libvirt/qemu/networks/autostart/br0.xml
new file mode 120000
index 00000000..e31f4a71
--- /dev/null
+++ b/core/modules/libvirt/data/etc/libvirt/qemu/networks/autostart/br0.xml
@@ -0,0 +1 @@
+../br0.xml \ No newline at end of file
diff --git a/core/modules/libvirt/data/etc/libvirt/qemu/networks/autostart/nat1.xml b/core/modules/libvirt/data/etc/libvirt/qemu/networks/autostart/nat1.xml
new file mode 120000
index 00000000..9e35bd99
--- /dev/null
+++ b/core/modules/libvirt/data/etc/libvirt/qemu/networks/autostart/nat1.xml
@@ -0,0 +1 @@
+../nat1.xml \ No newline at end of file
diff --git a/core/modules/libvirt/data/etc/libvirt/qemu/networks/autostart/vsw2.xml b/core/modules/libvirt/data/etc/libvirt/qemu/networks/autostart/vsw2.xml
new file mode 120000
index 00000000..1600f8a6
--- /dev/null
+++ b/core/modules/libvirt/data/etc/libvirt/qemu/networks/autostart/vsw2.xml
@@ -0,0 +1 @@
+../vsw2.xml \ No newline at end of file
diff --git a/core/modules/libvirt/data/etc/libvirt/qemu/networks/br0.xml b/core/modules/libvirt/data/etc/libvirt/qemu/networks/br0.xml
new file mode 100644
index 00000000..14acd6ec
--- /dev/null
+++ b/core/modules/libvirt/data/etc/libvirt/qemu/networks/br0.xml
@@ -0,0 +1,6 @@
+<network ipv6='no'>
+ <name>br0</name>
+ <forward mode='bridge'/>
+ <bridge name='br0'/>
+ <dns enable="no"/>
+</network>
diff --git a/core/modules/libvirt/data/etc/libvirt/qemu/networks/nat1.xml b/core/modules/libvirt/data/etc/libvirt/qemu/networks/nat1.xml
new file mode 100644
index 00000000..689b3640
--- /dev/null
+++ b/core/modules/libvirt/data/etc/libvirt/qemu/networks/nat1.xml
@@ -0,0 +1,6 @@
+<network ipv6='no'>
+ <name>nat1</name>
+ <forward mode='bridge'/>
+ <bridge name='nat1'/>
+ <dns enable="no"/>
+</network>
diff --git a/core/modules/libvirt/data/etc/libvirt/qemu/networks/vsw2.xml b/core/modules/libvirt/data/etc/libvirt/qemu/networks/vsw2.xml
new file mode 100644
index 00000000..a2c43fea
--- /dev/null
+++ b/core/modules/libvirt/data/etc/libvirt/qemu/networks/vsw2.xml
@@ -0,0 +1,6 @@
+<network ipv6='no'>
+ <name>vsw2</name>
+ <forward mode='bridge'/>
+ <bridge name='vsw2'/>
+ <dns enable="no"/>
+</network>
diff --git a/core/modules/libvirt/module.build b/core/modules/libvirt/module.build
new file mode 100644
index 00000000..dd868159
--- /dev/null
+++ b/core/modules/libvirt/module.build
@@ -0,0 +1,14 @@
+#!/bin/bash
+fetch_source() {
+ :
+}
+
+build() {
+ :
+}
+
+post_copy() {
+ # remove default network configuration
+ rm "${MODULE_BUILD_DIR}/etc/libvirt/qemu/networks/default.xml"
+ rm "${MODULE_BUILD_DIR}/etc/libvirt/qemu/networks/autostart/default.xml"
+}
diff --git a/core/modules/libvirt/module.conf b/core/modules/libvirt/module.conf
new file mode 100644
index 00000000..d67344f7
--- /dev/null
+++ b/core/modules/libvirt/module.conf
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+REQUIRED_MODULES="
+ libvirt-users
+"
+
+REQUIRED_BINARIES=""
+REQUIRED_LIBRARIES=""
+REQUIRED_DIRECTORIES=""
diff --git a/core/modules/libvirt/module.conf.debian b/core/modules/libvirt/module.conf.debian
new file mode 100644
index 00000000..84be983c
--- /dev/null
+++ b/core/modules/libvirt/module.conf.debian
@@ -0,0 +1,14 @@
+#!/bin/bash
+REQUIRED_INSTALLED_PACKAGES="
+ libvirt-daemon-system
+ libvirt-daemon
+ libvirt-clients
+ ebtables
+"
+
+REQUIRED_CONTENT_PACKAGES="
+ libvirt-daemon-system
+ libvirt-daemon
+ libvirt-clients
+ ebtables
+"
diff --git a/core/modules/libvirt/module.conf.ubuntu b/core/modules/libvirt/module.conf.ubuntu
new file mode 100644
index 00000000..84be983c
--- /dev/null
+++ b/core/modules/libvirt/module.conf.ubuntu
@@ -0,0 +1,14 @@
+#!/bin/bash
+REQUIRED_INSTALLED_PACKAGES="
+ libvirt-daemon-system
+ libvirt-daemon
+ libvirt-clients
+ ebtables
+"
+
+REQUIRED_CONTENT_PACKAGES="
+ libvirt-daemon-system
+ libvirt-daemon
+ libvirt-clients
+ ebtables
+"
diff --git a/core/modules/openjdk-8-jre-headless/module.build b/core/modules/openjdk-8-jre-headless/module.build
new file mode 100644
index 00000000..61fd9a57
--- /dev/null
+++ b/core/modules/openjdk-8-jre-headless/module.build
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+fetch_source() {
+ :
+}
+
+build() {
+ :
+}
+
+post_copy() {
+ :
+}
diff --git a/core/modules/openjdk-8-jre-headless/module.conf b/core/modules/openjdk-8-jre-headless/module.conf
new file mode 100644
index 00000000..668ddf88
--- /dev/null
+++ b/core/modules/openjdk-8-jre-headless/module.conf
@@ -0,0 +1,5 @@
+#!/bin/bash
+
+REQUIRED_BINARIES=""
+REQUIRED_LIBRARIES=""
+REQUIRED_DIRECTORIES=""
diff --git a/core/modules/openjdk-8-jre-headless/module.conf.ubuntu b/core/modules/openjdk-8-jre-headless/module.conf.ubuntu
new file mode 100644
index 00000000..aa99a07c
--- /dev/null
+++ b/core/modules/openjdk-8-jre-headless/module.conf.ubuntu
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+REQUIRED_INSTALLED_PACKAGES="
+ openjdk-8-jre-headless
+"
+
+REQUIRED_CONTENT_PACKAGES="
+ openjdk-8-jre-headless
+" \ No newline at end of file
diff --git a/core/modules/qemu/data/addon-init b/core/modules/qemu/data/addon-init
new file mode 100755
index 00000000..c7c96ae4
--- /dev/null
+++ b/core/modules/qemu/data/addon-init
@@ -0,0 +1,4 @@
+#!/bin/ash
+
+systemctl daemon-reload
+systemctl start qemu.service
diff --git a/core/modules/qemu/data/etc/systemd/system/graphical.target.wants/qemu.service b/core/modules/qemu/data/etc/systemd/system/graphical.target.wants/qemu.service
new file mode 120000
index 00000000..a301779d
--- /dev/null
+++ b/core/modules/qemu/data/etc/systemd/system/graphical.target.wants/qemu.service
@@ -0,0 +1 @@
+../qemu.service \ No newline at end of file
diff --git a/core/modules/qemu/data/etc/systemd/system/qemu.service b/core/modules/qemu/data/etc/systemd/system/qemu.service
new file mode 100644
index 00000000..7a1d3b4d
--- /dev/null
+++ b/core/modules/qemu/data/etc/systemd/system/qemu.service
@@ -0,0 +1,11 @@
+[Unit]
+Description=Sets up the QEMU hypervisor
+Requires=run-virt-env.service
+Requires=libvirtd.service
+After=run-virt-env.service
+After=libvirtd.service
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+ExecStart=/opt/openslx/scripts/systemd-qemu_env start
diff --git a/core/modules/qemu/data/opt/openslx/scripts/systemd-qemu_env b/core/modules/qemu/data/opt/openslx/scripts/systemd-qemu_env
new file mode 100755
index 00000000..3355b7a0
--- /dev/null
+++ b/core/modules/qemu/data/opt/openslx/scripts/systemd-qemu_env
@@ -0,0 +1,46 @@
+#!/bin/bash
+# -----------------------------------------------------------------------------
+#
+# Copyright (c) 2017..2021 bwLehrpool-Projektteam
+#
+# This program/file is free software distributed under the GPL version 2.
+# See https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
+#
+# If you have any feedback please consult https://bwlehrpool.de and
+# send your feedback to bwlehrpool@hs-offenburg.de.
+#
+# General information about bwLehrpool can be found at https://bwlehrpool.de
+#
+# -----------------------------------------------------------------------------
+# systemd-qemu_env
+# - This is the preparation script for the configuration of QEMU on Linux.
+################################################################################
+
+#
+# load general KVM module
+#
+modprobe "kvm" || slxlog "qemu" "Could not load 'kvm' kernel modul!"
+
+#
+# load CPU specific KVM implementation
+#
+virt=$(egrep -m1 -w '^flags[[:blank:]]*:' /proc/cpuinfo | egrep -wo '(vmx|svm)') || true
+
+if [ "${virt}" = "vmx" ]; then
+ kmod="kvm_intel"
+elif [ "${virt}" = "svm" ]; then
+ kmod="kvm_amd"
+else
+ slxlog "qemu" "CPU does not support KVM extensions!"
+ exit 1
+fi
+
+modprobe "${kmod}" || slxlog "qemu" "Could not load '${kmod}' kernel modul!"
+
+#
+# check that the KVM exposed device exists
+#
+if [ ! -e /dev/kvm ]; then
+ slxlog "qemu" "/dev/kvm not found! Missing kvm kernel module(s)?"
+ exit 1
+fi
diff --git a/core/modules/qemu/data/opt/openslx/vmchooser/plugins/qemu/run-virt.include b/core/modules/qemu/data/opt/openslx/vmchooser/plugins/qemu/run-virt.include
new file mode 100644
index 00000000..b7e43df9
--- /dev/null
+++ b/core/modules/qemu/data/opt/openslx/vmchooser/plugins/qemu/run-virt.include
@@ -0,0 +1,53 @@
+# -----------------------------------------------------------------------------
+#
+# Copyright (c) 2009..2021 bwLehrpool-Projektteam
+#
+# This program/file is free software distributed under the GPL version 2.
+# See https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
+#
+# If you have any feedback please consult https://bwlehrpool.de and
+# send your feedback to bwlehrpool@hs-offenburg.de.
+#
+# General information about bwLehrpool can be found at https://bwlehrpool.de
+#
+# -----------------------------------------------------------------------------
+# run-virt.include
+# - qemu plugin for vmchooser run-virt
+################################################################################
+
+# BASH_SOURCE[0] contains the file being sourced, namely this one
+declare -rg QEMU_PLUGIN_DIR="$(dirname "${BASH_SOURCE[0]}")"
+declare -rg QEMU_INCLUDE_DIR="${QEMU_PLUGIN_DIR}/includes"
+
+# Define which features the QEMU plugin supports
+declare -rg PLUGIN_FEATURES="firewall printer usb slxfloppy sound netshares"
+
+run_plugin() {
+ # write finalized config to temporary folder for debugging purposes
+ local vm_final_run_file="/tmp/qemu-last-config.xml"
+
+ # call the Libvirt Java tool to finalize configuration and start VM
+ declare -rg VIRTCMD="java -jar /opt/openslx/share/java/runvirt-plugin-qemu.jar"
+
+ isset DEBUG && VIRTCMDOPTS+=( "-debug" "${DEBUG}" )
+ isset VM_CLEANNAME && VIRTCMDOPTS+=( "-vmname" "${VM_CLEANNAME}" )
+ isset VM_DISPLAYNAME && VIRTCMDOPTS+=( "-vmdsplname" "${VM_DISPLAYNAME}" )
+ isset VM_OS_TYPE && VIRTCMDOPTS+=( "-vmos" "${VM_OS_TYPE}" )
+ isset VM_RUN_FILE && VIRTCMDOPTS+=( "-vmcfginp" "${VM_RUN_FILE}" )
+ isset vm_final_run_file && VIRTCMDOPTS+=( "-vmcfgout" "${vm_final_run_file}" )
+ isset IMGUUID && VIRTCMDOPTS+=( "-vmuuid" "${IMGUUID}" )
+ isset CPU_CORES && VIRTCMDOPTS+=( "-vmncpus" "${CPU_CORES}" )
+ isset VM_MEM && VIRTCMDOPTS+=( "-vmmem" "${VM_MEM}" )
+ isset VM_MAC_ADDR && VIRTCMDOPTS+=( "-vmmac0" "${VM_MAC_ADDR}" )
+ isset VM_DISKFILE_RO && VIRTCMDOPTS+=( "-vmhdd0" "${VM_DISKFILE_RO}" )
+ isset FLOPPY_0 && VIRTCMDOPTS+=( "-vmfloppy0" "${FLOPPY_0}" )
+ isset SLX_FLOPPY_IMG && VIRTCMDOPTS+=( "-vmfloppy1" "${SLX_FLOPPY_IMG}" )
+ isset CDROM_0 && VIRTCMDOPTS+=( "-vmcdrom0" "${CDROM_0}" )
+ isset CDROM_1 && VIRTCMDOPTS+=( "-vmcdrom1" "${CDROM_1}" )
+ isset SERIAL0 && VIRTCMDOPTS+=( "-vmserial0" "${SERIAL0}" )
+ isset PARALLEL0 && VIRTCMDOPTS+=( "-vmparallel0" "${PARALLEL0}" )
+ isset HOME_SHARE_PATH && VIRTCMDOPTS+=( "-vmfssrc0" "${HOME_SHARE_PATH}" )
+ isset HOME_SHARE_NAME && VIRTCMDOPTS+=( "-vmfstgt0" "${HOME_SHARE_NAME}" )
+ isset COMMON_SHARE_PATH && VIRTCMDOPTS+=( "-vmfssrc1" "${COMMON_SHARE_PATH}" )
+ isset COMMON_SHARE_NAME && VIRTCMDOPTS+=( "-vmfstgt1" "${COMMON_SHARE_NAME}" )
+}
diff --git a/core/modules/qemu/module.build b/core/modules/qemu/module.build
new file mode 100644
index 00000000..4d86de96
--- /dev/null
+++ b/core/modules/qemu/module.build
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+fetch_source() {
+ # copy qemu runvirt plugin source to working directory
+ local src_dir="${MODULE_DIR}/runvirt-plugin-qemu"
+ local dst_dir="${MODULE_WORK_DIR}/src"
+ mkdir -p "${dst_dir}" || perror "Could not create source folder for qemu runvirt plugin!"
+ cp -r "${src_dir}" "${dst_dir}" || perror "Could not copy source files for qemu runvirt plugin!"
+}
+
+build() {
+ # build qemu runvirt plugin
+ local build_dir="${MODULE_WORK_DIR}/src/runvirt-plugin-qemu"
+ mvn -f "${build_dir}" clean package || perror "Could not build runvirt-plugin-qemu with Maven!"
+
+ # install qemu runvirt plugin
+ local build_artifact_filename="runvirt-plugin-qemu-1.0-SNAPSHOT.jar"
+ local install_dir="${MODULE_BUILD_DIR}/opt/openslx/share/java"
+ local install_filename="runvirt-plugin-qemu.jar"
+ mkdir -p "${install_dir}"
+ cp "${build_dir}/target/${build_artifact_filename}" "${install_dir}/${install_filename}" || perror "Could not install runvirt-plugin-qemu!"
+}
+
+post_copy() {
+ :
+}
diff --git a/core/modules/qemu/module.conf b/core/modules/qemu/module.conf
new file mode 100644
index 00000000..c1cdf05d
--- /dev/null
+++ b/core/modules/qemu/module.conf
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+REQUIRED_MODULES="
+ libvirt
+ openjdk-8-jre-headless
+"
+
+REQUIRED_BINARIES=""
+REQUIRED_LIBRARIES=""
+REQUIRED_DIRECTORIES=""
diff --git a/core/modules/qemu/module.conf.ubuntu b/core/modules/qemu/module.conf.ubuntu
new file mode 100644
index 00000000..3b1089e0
--- /dev/null
+++ b/core/modules/qemu/module.conf.ubuntu
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+REQUIRED_INSTALLED_PACKAGES="
+ maven
+ openjdk-8-jdk-headless
+"
+
+REQUIRED_CONTENT_PACKAGES="
+ qemu
+ qemu-kvm
+ qemu-system-common
+ qemu-system-arm
+ qemu-system-x86
+ qemu-utils
+ seabios
+ ovmf
+"
diff --git a/core/modules/qemu/runvirt-plugin-qemu/.gitignore b/core/modules/qemu/runvirt-plugin-qemu/.gitignore
new file mode 100644
index 00000000..9c74211c
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/.gitignore
@@ -0,0 +1,15 @@
+/testing
+/.settings
+/.project
+/.classpath
+/target
+/gen-java
+*~
+!src/
+!test/
+*.swp
+
+# Ignore IntelliJ Project Files
+/.idea
+*.iml
+/bin/
diff --git a/core/modules/qemu/runvirt-plugin-qemu/pom.xml b/core/modules/qemu/runvirt-plugin-qemu/pom.xml
new file mode 100644
index 00000000..d8bb9743
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/pom.xml
@@ -0,0 +1,179 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.openslx.runvirt.plugin.qemu</groupId>
+ <artifactId>runvirt-plugin-qemu</artifactId>
+ <version>1.0-SNAPSHOT</version>
+
+ <name>runvirt-plugin-qemu</name>
+ <url>https://git.openslx.org/openslx-ng/mltk.git/</url>
+
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <maven.compiler.source>1.8</maven.compiler.source>
+ <maven.compiler.target>1.8</maven.compiler.target>
+ </properties>
+
+ <repositories>
+ <repository>
+ <id>mltk-repo-snapshot</id>
+ <url>http://mltk-services.ruf.uni-freiburg.de:8081/nexus/content/repositories/snapshots/</url>
+ <releases>
+ <enabled>false</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ <updatePolicy>always</updatePolicy>
+ </snapshots>
+ </repository>
+ <repository>
+ <id>mltk-repo-release</id>
+ <url>http://mltk-services.ruf.uni-freiburg.de:8081/nexus/content/repositories/releases/</url>
+ <releases>
+ <enabled>true</enabled>
+ <updatePolicy>always</updatePolicy>
+ </releases>
+ <snapshots>
+ <enabled>false</enabled>
+ </snapshots>
+ </repository>
+ </repositories>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-api</artifactId>
+ <version>5.7.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.junit.jupiter</groupId>
+ <artifactId>junit-jupiter-engine</artifactId>
+ <version>5.7.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-cli</groupId>
+ <artifactId>commons-cli</artifactId>
+ <version>1.4</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-exec</artifactId>
+ <version>1.3</version>
+ </dependency>
+ <dependency>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>[1.2.10,1.2.20]</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-log4j12</artifactId>
+ <version>1.7.25</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.ginsberg</groupId>
+ <artifactId>junit5-system-exit</artifactId>
+ <version>1.0.0</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.libvirt</groupId>
+ <artifactId>libvirt</artifactId>
+ <version>0.5.2</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>net.java.dev.jna</groupId>
+ <artifactId>jna</artifactId>
+ <version>4.2.2</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.openslx.bwlp</groupId>
+ <artifactId>master-sync-shared</artifactId>
+ <version>1.1-SNAPSHOT</version>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.openslx.bwlp</groupId>
+ <artifactId>master-sync-shared</artifactId>
+ <version>1.1-SNAPSHOT</version>
+ <classifier>tests</classifier>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-clean-plugin</artifactId>
+ <version>3.1.0</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>3.0.2</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.8.0</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.22.1</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>2.22.1</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <descriptorRefs>
+ <descriptorRef>jar-with-dependencies</descriptorRef>
+ </descriptorRefs>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-install-plugin</artifactId>
+ <version>2.5.2</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-deploy-plugin</artifactId>
+ <version>2.8.2</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-site-plugin</artifactId>
+ <version>3.7.1</version>
+ </plugin>
+ <plugin>
+ <artifactId>maven-project-info-reports-plugin</artifactId>
+ <version>3.0.0</version>
+ </plugin>
+ </plugins>
+ <testResources>
+ <testResource>
+ <directory>${basedir}/src/test/resources</directory>
+ <includes>
+ <include>libvirt/xml/*</include>
+ </includes>
+ </testResource>
+ </testResources>
+ </build>
+</project>
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/App.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/App.java
new file mode 100644
index 00000000..5ea7b720
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/App.java
@@ -0,0 +1,285 @@
+package org.openslx.runvirt.plugin.qemu;
+
+import java.io.File;
+import java.util.Arrays;
+
+import org.apache.log4j.BasicConfigurator;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.xml.LibvirtXmlDocumentException;
+import org.openslx.libvirt.xml.LibvirtXmlSerializationException;
+import org.openslx.libvirt.xml.LibvirtXmlValidationException;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs.CmdLnOption;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgsException;
+import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericCpu;
+import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericDiskCdromDevices;
+import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericDiskFloppyDevices;
+import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericDiskStorageDevices;
+import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericFileSystemDevices;
+import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericInterfaceDevices;
+import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericMemory;
+import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericName;
+import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericParallelDevices;
+import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuSerialDevices;
+import org.openslx.runvirt.plugin.qemu.configuration.TransformationGenericUuid;
+import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuArchitecture;
+import org.openslx.runvirt.plugin.qemu.configuration.TransformationSpecificQemuGpuPassthroughNvidia;
+import org.openslx.runvirt.plugin.qemu.virtualization.LibvirtHypervisorQemu;
+import org.openslx.runvirt.plugin.qemu.virtualization.LibvirtHypervisorQemu.QemuSessionType;
+import org.openslx.runvirt.viewer.Viewer;
+import org.openslx.runvirt.viewer.ViewerException;
+import org.openslx.runvirt.viewer.ViewerLookingGlassClient;
+import org.openslx.runvirt.viewer.ViewerVirtManager;
+import org.openslx.runvirt.viewer.ViewerVirtViewer;
+import org.openslx.runvirt.virtualization.LibvirtHypervisor;
+import org.openslx.runvirt.virtualization.LibvirtHypervisorException;
+import org.openslx.runvirt.virtualization.LibvirtVirtualMachine;
+import org.openslx.runvirt.virtualization.LibvirtVirtualMachineException;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+import org.openslx.virtualization.configuration.transformation.TransformationManager;
+
+/**
+ * Run-virt QEMU plugin (command line tool) to finalize a Libvirt domain XML configuration.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class App
+{
+ /**
+ * Stores name of the run-virt QEMU plugin (command line tool).
+ */
+ public static final String APP_NAME = "run-virt QEMU plugin";
+
+ /**
+ * Stores description of the run-virt QEMU plugin (command line tool).
+ */
+ public static final String APP_DESC = "Finalize a Libvirt VM (domain XML) configuration and manage the VM.";
+
+ /**
+ * Stores additional information for the run-virt QEMU plugin (command line tool).
+ */
+ public static final String APP_INFO = "The " + APP_NAME + " is part of the bwLehrpool infrastructure.";
+
+ /**
+ * Instance of a logger to log messages.
+ */
+ private static final Logger LOGGER = LogManager.getLogger( App.class );
+
+ /**
+ * Entry point of the run-virt QEMU plugin (command line tool).
+ *
+ * @param args command line arguments passed to the run-virt QEMU plugin (command line tool).
+ */
+ public static void main( String[] args )
+ {
+ // initialize logging
+ BasicConfigurator.configure();
+
+ // parse command line arguments
+ CommandLineArgs cmdLn = new CommandLineArgs();
+
+ try {
+ cmdLn.parseCmdLnArgs( args );
+ } catch ( CommandLineArgsException e ) {
+ LOGGER.error( "Parsing of command line arguments failed: " + e.getLocalizedMessage() );
+ App.printUsage( cmdLn );
+ System.exit( 1 );
+ }
+
+ // show help if 'help' command line option is set
+ if ( cmdLn.isHelpAquired() ) {
+ App.printUsage( cmdLn );
+ System.exit( 0 );
+ }
+
+ // print command line arguments for debugging purposes
+ App.printCmdLnArgs( cmdLn );
+
+ // create connection to the QEMU hypervisor via Libvirt
+ LibvirtHypervisor hypervisor = null;
+ try {
+ hypervisor = new LibvirtHypervisorQemu( QemuSessionType.LOCAL_USER_SESSION );
+ } catch ( LibvirtHypervisorException e ) {
+ LOGGER.error( "Failed to connect to the QEMU virtualizer (Libvirt daemon): " + e.getLocalizedMessage() );
+ System.exit( 2 );
+ }
+
+ // read Libvirt XML domain configuration template
+ final String xmlInputFileName = cmdLn.getVmCfgInpFileName();
+ Domain config = null;
+ try {
+ final File xmlInputFile = new File( xmlInputFileName );
+ config = new Domain( xmlInputFile );
+ } catch ( LibvirtXmlDocumentException | LibvirtXmlSerializationException | LibvirtXmlValidationException e ) {
+ LOGGER.error( "Failed to read VM input configuration file: " + e.getLocalizedMessage() );
+ hypervisor.close();
+ System.exit( 3 );
+ }
+
+ // create transformation manager to finalize VM configuration
+ final TransformationManager<Domain, CommandLineArgs> transformationManager;
+ transformationManager = new TransformationManager<Domain, CommandLineArgs>( config, cmdLn );
+
+ // register necessary transformations to finalize configuration template
+ transformationManager.register( new TransformationGenericName(), true );
+ transformationManager.register( new TransformationGenericUuid(), true );
+ transformationManager.register( new TransformationGenericCpu(), true );
+ transformationManager.register( new TransformationGenericMemory(), true );
+ transformationManager.register( new TransformationGenericDiskStorageDevices(), true );
+ transformationManager.register( new TransformationGenericDiskCdromDevices(), true );
+ transformationManager.register( new TransformationGenericDiskFloppyDevices(), true );
+ transformationManager.register( new TransformationGenericInterfaceDevices(), true );
+ transformationManager.register( new TransformationGenericParallelDevices(), true );
+ transformationManager.register( new TransformationGenericFileSystemDevices(), true );
+
+ // register QEMU specific transformations to finalize configuration template
+ if ( hypervisor instanceof LibvirtHypervisorQemu ) {
+ final LibvirtHypervisorQemu hypervisorQemu = LibvirtHypervisorQemu.class.cast( hypervisor );
+
+ transformationManager.register( new TransformationSpecificQemuArchitecture( hypervisorQemu ), true );
+ transformationManager.register( new TransformationSpecificQemuSerialDevices( hypervisorQemu ), true );
+ transformationManager.register( new TransformationSpecificQemuGpuPassthroughNvidia( hypervisorQemu ), false );
+ }
+
+ // finalize Libvirt VM configuration template
+ try {
+ transformationManager.transform();
+ } catch ( TransformationException e ) {
+ LOGGER.error( "Failed to finalize VM configuration file: " + e.getLocalizedMessage() );
+ hypervisor.close();
+ System.exit( 4 );
+ }
+
+ // write finalized configuration to file if output file is specified
+ final String xmlOutputFileName = cmdLn.getVmCfgOutFileName();
+ if ( xmlOutputFileName != null && !xmlOutputFileName.isEmpty() ) {
+ try {
+ final File xmlOutputFile = new File( xmlOutputFileName );
+ config.toXml( xmlOutputFile );
+ } catch ( LibvirtXmlSerializationException e ) {
+ LOGGER.error( "Failed to write VM output configuration file: " + e.getLocalizedMessage() );
+ hypervisor.close();
+ System.exit( 5 );
+ }
+ }
+
+ // define Libvirt VM from finalized configuration
+ LibvirtVirtualMachine vm = null;
+ try {
+ vm = hypervisor.registerVm( config );
+ } catch ( LibvirtHypervisorException e ) {
+ LOGGER.error( "Failed to define VM from configuration file: " + e.getLocalizedMessage() );
+ hypervisor.close();
+ System.exit( 6 );
+ }
+
+ // start defined Libvirt VM
+ try {
+ vm.start();
+ } catch ( LibvirtVirtualMachineException e ) {
+ LOGGER.error( "Failed to start defined VM: " + e.getLocalizedMessage() );
+ hypervisor.close();
+ System.exit( 7 );
+ }
+
+ // create specific viewer to display Libvirt VM
+ final Viewer vmViewer;
+ if ( cmdLn.isNvidiaGpuPassthroughEnabled() ) {
+ // viewer for GPU passthrough (framebuffer access) is required
+ vmViewer = new ViewerLookingGlassClient( vm, hypervisor, cmdLn.isDebugEnabled() );
+ } else {
+ // viewer for non-GPU passthrough (no framebuffer access) is required
+ if ( cmdLn.isDebugEnabled() ) {
+ // create specific Virtual Machine Manager viewer if debug mode is enabled
+ vmViewer = new ViewerVirtManager( vm, hypervisor );
+ } else {
+ // create Virtual Viewer if debug mode is disabled
+ vmViewer = new ViewerVirtViewer( vm, hypervisor );
+ }
+ }
+
+ // display Libvirt VM with the specific viewer on the screen
+ try {
+ vmViewer.display();
+ } catch ( ViewerException e ) {
+ LOGGER.error( "Failed to display VM: " + e.getLocalizedMessage() );
+ hypervisor.close();
+ System.exit( 8 );
+ }
+
+ // undefine VM after usage
+ try {
+ hypervisor.deregisterVm( vm );
+ } catch ( LibvirtHypervisorException | LibvirtVirtualMachineException e ) {
+ LOGGER.error( "Failed to undefine VM: " + e.getLocalizedMessage() );
+ hypervisor.close();
+ System.exit( 9 );
+ }
+
+ // close connection to hypervisor
+ hypervisor.close();
+
+ // return with successful exit code
+ System.exit( 0 );
+ }
+
+ /**
+ * Helper utility to print the run-virt QEMU plugin help text.
+ *
+ * @param cmdLn parsed command line arguments.
+ */
+ public static void printUsage( CommandLineArgs cmdLn )
+ {
+ final String newLine = System.lineSeparator();
+ final String fullAppDesc = newLine + App.APP_DESC + newLine + newLine;
+ final String fullAppInfo = newLine + App.APP_INFO;
+
+ cmdLn.printHelp( App.APP_NAME, fullAppDesc, fullAppInfo );
+ }
+
+ /**
+ * Helper utility to log the run-virt QEMU plugin's submitted command line arguments.
+ *
+ * @param cmdLn parsed command line arguments.
+ *
+ * @implNote This method is intended to be used for debugging purposes.
+ */
+ public static void printCmdLnArgs( CommandLineArgs cmdLn )
+ {
+ // determine length of longest command line option
+ int longOptionLengthMax = 0;
+
+ for ( CmdLnOption option : CmdLnOption.values() ) {
+ // store length of current long option
+ final int longOptionLength = option.getLongOption().length();
+
+ // if length is longer than every length before, store this length as longest length
+ if ( longOptionLength > longOptionLengthMax ) {
+ longOptionLengthMax = longOptionLength;
+ }
+ }
+
+ LOGGER.debug( "Command line arguments: --------------" );
+
+ for ( CmdLnOption option : CmdLnOption.values() ) {
+ final String paddedLongOption = String.format( "%-" + longOptionLengthMax + "s", option.getLongOption() );
+ String[] longOptionArguments;
+
+ // only request and log argument if option has an command line argument
+ if ( option.getNumArguments() > 0 ) {
+ longOptionArguments = cmdLn.getArguments( option );
+
+ if ( longOptionArguments == null ) {
+ longOptionArguments = new String[] { "no argument specified" };
+ }
+ } else {
+ longOptionArguments = new String[] { "option has no argument" };
+ }
+
+ LOGGER.debug( "\t" + paddedLongOption + ": " + Arrays.toString( longOptionArguments ) );
+ }
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgs.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgs.java
new file mode 100644
index 00000000..589dd197
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgs.java
@@ -0,0 +1,511 @@
+package org.openslx.runvirt.plugin.qemu.cmdln;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.CommandLineParser;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+
+/**
+ * Command line argument parser for the run-virt QEMU plugin (command line tool).
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class CommandLineArgs
+{
+ /**
+ * Parser for parsing command line arguments.
+ */
+ private CommandLineParser cmdLnParser = null;
+
+ /**
+ * Stores specified command line options.
+ */
+ private Options cmdLnOptions = null;
+
+ /**
+ * Stores the parsed command line arguments.
+ */
+ private CommandLine cmdLn = null;
+
+ /**
+ * Creates a new command line argument parser for the run-virt QEMU plugin.
+ *
+ * @implNote Please call {@link CommandLineArgs#parseCmdLnArgs(String[])} manually after
+ * obtaining the command line argument parser from this method.
+ */
+ public CommandLineArgs()
+ {
+ this.createCmdLnParser();
+ this.createCmdLnOptions();
+ }
+
+ /**
+ * Creates a new command line argument parser for the run-virt QEMU plugin and parses the command
+ * line arguments.
+ *
+ * @param args command line arguments submitted to the application.
+ *
+ * @throws CommandLineArgsException parsing of command line arguments failed.
+ */
+ public CommandLineArgs( String[] args ) throws CommandLineArgsException
+ {
+ this();
+ this.parseCmdLnArgs( args );
+ }
+
+ /**
+ * Creates a new parser and empty command line options for parsing command line arguments.
+ */
+ private void createCmdLnParser()
+ {
+ this.cmdLnParser = new DefaultParser();
+ this.cmdLnOptions = new Options();
+ }
+
+ /**
+ * Creates command line options specified by {@link CmdLnOption}.
+ */
+ private void createCmdLnOptions()
+ {
+ for ( CmdLnOption option : CmdLnOption.values() ) {
+ final Option cmdlnOption;
+
+ final boolean hasArg = ( option.getNumArguments() > 0 ) ? true : false;
+ cmdlnOption = new Option( option.getShortOption(), option.getLongOption(), hasArg, option.getDescription() );
+ cmdlnOption.setValueSeparator( ',' );
+ cmdlnOption.setArgs( option.getNumArguments() );
+
+ this.cmdLnOptions.addOption( cmdlnOption );
+ }
+ }
+
+ /**
+ * Prints command line help for the current application.
+ *
+ * @param appName name of the current application.
+ * @param header header for the command line help.
+ * @param footer footer for the command line help.
+ */
+ public void printHelp( String appName, String header, String footer )
+ {
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.setLeftPadding( 2 );
+ formatter.printHelp( appName, header, this.cmdLnOptions, footer, true );
+ }
+
+ /**
+ * Parses command line arguments from a given argument {@link String}.
+ *
+ * @param args command line arguments submitted to the application.
+ *
+ * @throws CommandLineArgsException parsing of command line arguments failed.
+ */
+ public void parseCmdLnArgs( String[] args ) throws CommandLineArgsException
+ {
+ try {
+ this.cmdLn = this.cmdLnParser.parse( this.cmdLnOptions, args );
+ } catch ( ParseException e ) {
+ throw new CommandLineArgsException( e.getLocalizedMessage() );
+ }
+ }
+
+ /**
+ * Returns the parsed argument of the specified command line option.
+ *
+ * @param cmdLnOption command line option for that the parsed argument should be returned.
+ * @return parsed argument of the command line option.
+ */
+ public String getArgument( CmdLnOption cmdLnOption )
+ {
+ return this.cmdLn.getOptionValue( cmdLnOption.getShortOption() );
+ }
+
+ /**
+ * Returns the parsed arguments of the specified command line option.
+ *
+ * @param cmdLnOption command line option for that the parsed arguments should be returned.
+ * @return parsed argument of the command line option.
+ */
+ public String[] getArguments( CmdLnOption cmdLnOption )
+ {
+ return this.cmdLn.getOptionValues( cmdLnOption.getShortOption() );
+ }
+
+ /**
+ * Returns the presence of the command line option {@link CmdLnOption#HELP}.
+ *
+ * @return presence of the command line option {@link CmdLnOption#HELP}.
+ */
+ public boolean isHelpAquired()
+ {
+ return this.cmdLn.hasOption( CmdLnOption.HELP.getShortOption() );
+ }
+
+ /**
+ * Returns the state of the command line option {@link CmdLnOption#DEBUG}.
+ *
+ * @return state of the command line option {@link CmdLnOption#DEBUG}.
+ */
+ public boolean isDebugEnabled()
+ {
+ final String debugArg = this.getArgument( CmdLnOption.DEBUG );
+ return ( "true".equals( debugArg ) ) ? true : false;
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_CFGINP}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_CFGINP}.
+ */
+ public String getVmCfgInpFileName()
+ {
+ return this.getArgument( CmdLnOption.VM_CFGINP );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_CFGOUT}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_CFGOUT}.
+ */
+ public String getVmCfgOutFileName()
+ {
+ return this.getArgument( CmdLnOption.VM_CFGOUT );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_NAME}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_NAME}.
+ */
+ public String getVmName()
+ {
+ return this.getArgument( CmdLnOption.VM_NAME );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_UUID}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_UUID}.
+ */
+ public String getVmUuid()
+ {
+ return this.getArgument( CmdLnOption.VM_UUID );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_DSPLNAME}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_DSPLNAME}.
+ */
+ public String getVmDisplayName()
+ {
+ return this.getArgument( CmdLnOption.VM_DSPLNAME );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_OS}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_OS}.
+ */
+ public String getVmOperatingSystem()
+ {
+ return this.getArgument( CmdLnOption.VM_OS );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_NCPUS}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_NCPUS}.
+ */
+ public int getVmNumCpus()
+ {
+ final String numCpuArg = this.getArgument( CmdLnOption.VM_NCPUS );
+ int numCpus = 0;
+
+ if ( numCpuArg != null ) {
+ numCpus = Integer.parseInt( numCpuArg );
+ }
+
+ return numCpus;
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_MEM}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_MEM}.
+ */
+ public String getVmMemory()
+ {
+ return this.getArgument( CmdLnOption.VM_MEM );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_HDD0}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_HDD0}.
+ */
+ public String getVmDiskFileNameHDD0()
+ {
+ return this.getArgument( CmdLnOption.VM_HDD0 );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_FLOPPY0}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_FLOPPY0}.
+ */
+ public String getVmDiskFileNameFloppy0()
+ {
+ return this.getArgument( CmdLnOption.VM_FLOPPY0 );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_FLOPPY1}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_FLOPPY1}.
+ */
+ public String getVmDiskFileNameFloppy1()
+ {
+ return this.getArgument( CmdLnOption.VM_FLOPPY1 );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_CDROM0}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_CDROM0}.
+ */
+ public String getVmDiskFileNameCdrom0()
+ {
+ return this.getArgument( CmdLnOption.VM_CDROM0 );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_CDROM1}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_CDROM1}.
+ */
+ public String getVmDiskFileNameCdrom1()
+ {
+ return this.getArgument( CmdLnOption.VM_CDROM1 );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_PARALLEL0}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_SERIAL0}.
+ */
+ public String getVmDeviceParallel0()
+ {
+ return this.getArgument( CmdLnOption.VM_PARALLEL0 );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_SERIAL0}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_SERIAL0}.
+ */
+ public String getVmDeviceSerial0()
+ {
+ return this.getArgument( CmdLnOption.VM_SERIAL0 );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_MAC0}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_MAC0}.
+ */
+ public String getVmMacAddress0()
+ {
+ return this.getArgument( CmdLnOption.VM_MAC0 );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_FSSRC0}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_FSSRC0}.
+ */
+ public String getVmFsSrc0()
+ {
+ return this.getArgument( CmdLnOption.VM_FSSRC0 );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_FSTGT0}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_FSTGT0}.
+ */
+ public String getVmFsTgt0()
+ {
+ return this.getArgument( CmdLnOption.VM_FSTGT0 );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_FSSRC1}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_FSSRC1}.
+ */
+ public String getVmFsSrc1()
+ {
+ return this.getArgument( CmdLnOption.VM_FSSRC1 );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_FSTGT1}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_FSTGT1}.
+ */
+ public String getVmFsTgt1()
+ {
+ return this.getArgument( CmdLnOption.VM_FSTGT1 );
+ }
+
+ /**
+ * Returns the argument of the command line option {@link CmdLnOption#VM_NVGPUIDS0}.
+ *
+ * @return argument of the command line option {@link CmdLnOption#VM_NVGPUIDS0}.
+ */
+ public List<String> getVmNvGpuIds0()
+ {
+ final String[] nvidiaPciIdsRaw = this.getArguments( CmdLnOption.VM_NVGPUIDS0 );
+ final ArrayList<String> nvidiaPciIds;
+
+ if ( nvidiaPciIdsRaw == null || nvidiaPciIdsRaw.length <= 0 ) {
+ nvidiaPciIds = new ArrayList<String>();
+ } else {
+ nvidiaPciIds = new ArrayList<String>( Arrays.asList( nvidiaPciIdsRaw ) );
+ }
+
+ return nvidiaPciIds;
+ }
+
+ /**
+ * Returns the state whether a passthrough of a NVIDIA GPU is required.
+ *
+ * @return state whether a passthrough of a NVIDIA GPU is required.
+ */
+ public boolean isNvidiaGpuPassthroughEnabled()
+ {
+ return this.getVmNvGpuIds0().size() > 0;
+ }
+
+ /**
+ * Command line options for the run-virt QEMU plugin (command line tool).
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+ public enum CmdLnOption
+ {
+ // @formatter:off
+ HELP ( 'h', "help", 0, "" ),
+ DEBUG ( 'b', "debug", 1, "Enable or disable debug mode" ),
+ VM_CFGINP ( 'i', "vmcfginp", 1, "File name of an existing and filtered Libvirt domain XML configuration file" ),
+ VM_CFGOUT ( 'o', "vmcfgout", 1, "File name to output a finalized Libvirt domain XML configuration file" ),
+ VM_NAME ( 'n', "vmname", 1, "Name for the virtual machine" ),
+ VM_UUID ( 'u', "vmuuid", 1, "UUID for the virtual machine" ),
+ VM_DSPLNAME ( 'd', "vmdsplname", 1, "Display name for the virtual machine" ),
+ VM_OS ( 's', "vmos", 1, "Operating system running in the virtual machine" ),
+ VM_NCPUS ( 'c', "vmncpus", 1, "Number of virtual CPUs for the virtual machine" ),
+ VM_MEM ( 'm', "vmmem", 1, "Amount of memory for the virtual machine" ),
+ VM_HDD0 ( 'r', "vmhdd0", 1, "Disk image for the first HDD device" ),
+ VM_FLOPPY0 ( 'f', "vmfloppy0", 1, "Disk image for the first floppy drive" ),
+ VM_FLOPPY1 ( 'g', "vmfloppy1", 1, "Disk image for the second floppy drive" ),
+ VM_CDROM0 ( 'k', "vmcdrom0", 1, "Disk image for the first CDROM drive" ),
+ VM_CDROM1 ( 'l', "vmcdrom1", 1, "Disk image for the second CDROM drive" ),
+ VM_PARALLEL0( 'p', "vmparallel0", 1, "Device for the first parallel port interface" ),
+ VM_SERIAL0 ( 'q', "vmserial0", 1, "Device for the first serial port interface" ),
+ VM_MAC0 ( 'a', "vmmac0", 1, "MAC address for the first network interface" ),
+ VM_FSSRC0 ( 't', "vmfssrc0", 1, "Source directory for first file system passthrough (shared folder)" ),
+ VM_FSTGT0 ( 'e', "vmfstgt0", 1, "Target directory for first file system passthrough (shared folder)" ),
+ VM_FSSRC1 ( 'v', "vmfssrc1", 1, "Source directory for second file system passthrough (shared folder)" ),
+ VM_FSTGT1 ( 'w', "vmfstgt1", 1, "Target directory for second file system passthrough (shared folder)" ),
+ VM_NVGPUIDS0( 'y', "vmnvgpuids0", 2, "PCI device description and address for passthrough of the first Nvidia GPU. " +
+ "The argument follow the pattern: " +
+ "\"<VENDOR ID>:<PRODUCT ID>,<PCI DOMAIN>:<PCI DEVICE>:<PCI DEVICE>.<PCI FUNCTION>\"" );
+ // @formatter:on
+
+ /**
+ * Stores the {@link Character} of the short command line option.
+ */
+ private final char shortOption;
+
+ /**
+ * Stores the {@link String} of the long command line option.
+ */
+ private final String longOption;
+
+ /**
+ * Stores the number of arguments for the command line option.
+ */
+ private final int numArguments;
+
+ /**
+ * Stores the textual description of the command line option.
+ */
+ private final String description;
+
+ /**
+ * Creates a new command line option for the run-virt QEMU plugin (command line tool).
+ *
+ * @param shortOption {@link Character} for the short command line option.
+ * @param longOption {@link String} for the long command line option.
+ * @param numArguments number of arguments for the command line option.
+ * @param description textual description of the command line option.
+ */
+ CmdLnOption( char shortOption, String longOption, int numArguments, String description )
+ {
+ this.shortOption = shortOption;
+ this.longOption = longOption;
+ this.numArguments = numArguments;
+ this.description = description;
+ }
+
+ /**
+ * Returns the {@link Character} of the short command line option.
+ *
+ * @return {@link Character} of the short command line option.
+ */
+ public String getShortOption()
+ {
+ return Character.toString( this.shortOption );
+ }
+
+ /**
+ * Returns the {@link String} of the long command line option.
+ *
+ * @return {@link String} of the long command line option.
+ */
+ public String getLongOption()
+ {
+ return this.longOption;
+ }
+
+ /**
+ * Returns the number of arguments for the command line option.
+ *
+ * @return number of arguments for the command line option.
+ */
+ public int getNumArguments()
+ {
+ return this.numArguments;
+ }
+
+ /**
+ * Returns the textual description of the command line option.
+ *
+ * @return textual description of the command line option.
+ */
+ public String getDescription()
+ {
+ return this.description;
+ }
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgsException.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgsException.java
new file mode 100644
index 00000000..a327b813
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgsException.java
@@ -0,0 +1,25 @@
+package org.openslx.runvirt.plugin.qemu.cmdln;
+
+/**
+ * An exception during the parsing of command line arguments.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class CommandLineArgsException extends Exception
+{
+ /**
+ * Version number for serialization.
+ */
+ private static final long serialVersionUID = 8371924151602194406L;
+
+ /**
+ * Creates an command line argument parsing exception including an error message.
+ *
+ * @param errorMsg message to describe a specific parsing error.
+ */
+ public CommandLineArgsException( String errorMsg )
+ {
+ super( errorMsg );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericCpu.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericCpu.java
new file mode 100644
index 00000000..9d9237c7
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericCpu.java
@@ -0,0 +1,57 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.Domain.CpuCheck;
+import org.openslx.libvirt.domain.Domain.CpuMode;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+import org.openslx.virtualization.configuration.transformation.TransformationGeneric;
+
+/**
+ * Generic CPU transformation for Libvirt/QEMU virtualization configurations.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class TransformationGenericCpu extends TransformationGeneric<Domain, CommandLineArgs>
+{
+ /**
+ * Name of the configuration transformation.
+ */
+ private static final String NAME = "CPU [number of cores, mode, ...]";
+
+ /**
+ * Creates a new generic CPU transformation for Libvirt/QEMU virtualization configurations.
+ */
+ public TransformationGenericCpu()
+ {
+ super( TransformationGenericCpu.NAME );
+ }
+
+ /**
+ * Validates a virtualization configuration and input arguments for this transformation.
+ *
+ * @param config virtualization configuration for the validation.
+ * @param args input arguments for the validation.
+ * @throws TransformationException validation has failed.
+ */
+ private void validateInputs( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ if ( config == null || args == null ) {
+ throw new TransformationException( "Virtualization configuration or input arguments are missing!" );
+ } else if ( args.getVmNumCpus() < 1 ) {
+ throw new TransformationException( "Invalid number of CPUs specified! Expected a number n > 0!" );
+ }
+ }
+
+ @Override
+ public void transform( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ // validate configuration and input arguments
+ this.validateInputs( config, args );
+
+ config.setVCpu( args.getVmNumCpus() );
+ config.setCpuMode( CpuMode.HOST_PASSTHROUGH );
+ config.setCpuCheck( CpuCheck.PARTIAL );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskCdromDevices.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskCdromDevices.java
new file mode 100644
index 00000000..643c40ed
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskCdromDevices.java
@@ -0,0 +1,110 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import java.util.ArrayList;
+
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.Disk.BusType;
+import org.openslx.libvirt.domain.device.Disk.StorageType;
+import org.openslx.libvirt.domain.device.DiskCdrom;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.VirtualizationConfigurationQemuUtils;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+import org.openslx.virtualization.configuration.transformation.TransformationGeneric;
+
+/**
+ * Generic CDROM drive transformation for Libvirt/QEMU virtualization configurations.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class TransformationGenericDiskCdromDevices extends TransformationGeneric<Domain, CommandLineArgs>
+{
+ /**
+ * Name of the configuration transformation.
+ */
+ private static final String NAME = "Disk CDROM devices";
+
+ /**
+ * Creates a new generic CDROM drive transformation for Libvirt/QEMU virtualization
+ * configurations.
+ */
+ public TransformationGenericDiskCdromDevices()
+ {
+ super( TransformationGenericDiskCdromDevices.NAME );
+ }
+
+ /**
+ * Validates a virtualization configuration and input arguments for this transformation.
+ *
+ * @param config virtualization configuration for the validation.
+ * @param args input arguments for the validation.
+ * @throws TransformationException validation has failed.
+ */
+ private void validateInputs( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ if ( config == null || args == null ) {
+ throw new TransformationException( "Virtualization configuration or input arguments are missing!" );
+ }
+ }
+
+ /**
+ * Transforms a CDROM drive in a virtualization configuration selected by its {@code index}.
+ *
+ * @param config virtualization configuration for the transformation.
+ * @param fileName name of the image file for the CDROM drive.
+ * @param index number of the CDROM drive in the virtualization configuration that is selected.
+ * @throws TransformationException transformation has failed.
+ */
+ private void transformDiskCdromDevice( Domain config, String fileName, int index ) throws TransformationException
+ {
+ final ArrayList<DiskCdrom> devices = config.getDiskCdromDevices();
+ final DiskCdrom disk = VirtualizationConfigurationQemuUtils.getArrayIndex( devices, index );
+
+ if ( disk == null ) {
+ if ( fileName != null ) {
+ // CDROM drive does not exist, so create new CDROM drive
+ final DiskCdrom newDisk = config.addDiskCdromDevice();
+ newDisk.setBusType( BusType.SATA );
+ String targetDevName = VirtualizationConfigurationQemuUtils.createAlphabeticalDeviceName( "sd", index );
+ newDisk.setTargetDevice( targetDevName );
+
+ if ( fileName.isEmpty() ) {
+ // remove storage source if empty string is specified to emulate an empty CDROM drive
+ newDisk.removeStorage();
+ } else {
+ // set disk image file as storage source of the disk CDROM drive
+ newDisk.setStorage( StorageType.FILE, fileName );
+ }
+ }
+ } else {
+ // CDROM drive exists, so update existing CDROM drive
+ if ( fileName == null ) {
+ // remove disk storage device if disk image file name is not set
+ disk.remove();
+ } else if ( fileName.isEmpty() ) {
+ // remove storage source if empty string is specified to emulate an empty CDROM drive
+ disk.removeStorage();
+ } else {
+ // set disk image file as storage source of the disk CDROM drive
+ disk.setStorage( StorageType.FILE, fileName );
+ }
+ }
+ }
+
+ @Override
+ public void transform( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ // validate configuration and input arguments
+ this.validateInputs( config, args );
+
+ // alter CDROM drives
+ this.transformDiskCdromDevice( config, args.getVmDiskFileNameCdrom0(), 0 );
+ this.transformDiskCdromDevice( config, args.getVmDiskFileNameCdrom1(), 1 );
+
+ // remove all additional disk CDROM devices
+ final ArrayList<DiskCdrom> devices = config.getDiskCdromDevices();
+ for ( int i = 2; i < devices.size(); i++ ) {
+ devices.get( i ).remove();
+ }
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskFloppyDevices.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskFloppyDevices.java
new file mode 100644
index 00000000..fe3d3c34
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskFloppyDevices.java
@@ -0,0 +1,104 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import java.util.ArrayList;
+
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.Disk.BusType;
+import org.openslx.libvirt.domain.device.Disk.StorageType;
+import org.openslx.libvirt.domain.device.DiskFloppy;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.VirtualizationConfigurationQemuUtils;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+import org.openslx.virtualization.configuration.transformation.TransformationGeneric;
+
+/**
+ * Generic floppy drive transformation for Libvirt/QEMU virtualization configurations.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class TransformationGenericDiskFloppyDevices extends TransformationGeneric<Domain, CommandLineArgs>
+{
+ /**
+ * Name of the configuration transformation.
+ */
+ private static final String NAME = "Disk floppy devices";
+
+ /**
+ * Creates a new floppy drive transformation for Libvirt/QEMU virtualization configurations.
+ */
+ public TransformationGenericDiskFloppyDevices()
+ {
+ super( TransformationGenericDiskFloppyDevices.NAME );
+ }
+
+ /**
+ * Validates a virtualization configuration and input arguments for this transformation.
+ *
+ * @param config virtualization configuration for the validation.
+ * @param args input arguments for the validation.
+ * @throws TransformationException validation has failed.
+ */
+ private void validateInputs( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ if ( config == null || args == null ) {
+ throw new TransformationException( "Virtualization configuration or input arguments are missing!" );
+ }
+ }
+
+ /**
+ * Transforms a floppy drive in a virtualization configuration selected by its {@code index}.
+ *
+ * @param config virtualization configuration for the transformation.
+ * @param fileName name of the image file for the floppy drive.
+ * @param index number of the floppy drive in the virtualization configuration that is selected.
+ * @throws TransformationException transformation has failed.
+ */
+ private void transformDiskFloppyDevice( Domain config, String fileName, int index ) throws TransformationException
+ {
+ final ArrayList<DiskFloppy> devices = config.getDiskFloppyDevices();
+ final DiskFloppy disk = VirtualizationConfigurationQemuUtils.getArrayIndex( devices, index );
+
+ if ( disk == null ) {
+ if ( fileName != null ) {
+ // floppy device does not exist, so create new floppy device
+ final DiskFloppy newDisk = config.addDiskFloppyDevice();
+ newDisk.setBusType( BusType.FDC );
+ String targetDevName = VirtualizationConfigurationQemuUtils.createAlphabeticalDeviceName( "fd", index );
+ newDisk.setTargetDevice( targetDevName );
+
+ if ( fileName.isEmpty() ) {
+ newDisk.removeStorage();
+ } else {
+ newDisk.setStorage( StorageType.FILE, fileName );
+ }
+ }
+ } else {
+ // floppy device exists, so update existing floppy device
+ if ( fileName == null ) {
+ disk.remove();
+ } else if ( fileName.isEmpty() ) {
+ disk.removeStorage();
+ } else {
+ disk.setStorage( StorageType.FILE, fileName );
+ }
+ }
+ }
+
+ @Override
+ public void transform( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ // validate configuration and input arguments
+ this.validateInputs( config, args );
+
+ // alter floppy drives
+ this.transformDiskFloppyDevice( config, args.getVmDiskFileNameFloppy0(), 0 );
+ this.transformDiskFloppyDevice( config, args.getVmDiskFileNameFloppy1(), 1 );
+
+ // remove all additional disk storage devices
+ final ArrayList<DiskFloppy> devices = config.getDiskFloppyDevices();
+ for ( int i = 2; i < devices.size(); i++ ) {
+ devices.get( i ).remove();
+ }
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskStorageDevices.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskStorageDevices.java
new file mode 100644
index 00000000..9bd1edbb
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskStorageDevices.java
@@ -0,0 +1,102 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import java.util.ArrayList;
+
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.Disk.BusType;
+import org.openslx.libvirt.domain.device.Disk.StorageType;
+import org.openslx.libvirt.domain.device.DiskFloppy;
+import org.openslx.libvirt.domain.device.DiskStorage;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.VirtualizationConfigurationQemuUtils;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+import org.openslx.virtualization.configuration.transformation.TransformationGeneric;
+
+/**
+ * Generic storage device (HDD, SSD, ...) transformation for Libvirt/QEMU virtualization
+ * configurations.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class TransformationGenericDiskStorageDevices extends TransformationGeneric<Domain, CommandLineArgs>
+{
+ /**
+ * Name of the configuration transformation.
+ */
+ private static final String NAME = "Disk storage devices [HDD, SSD, ...]";
+
+ /**
+ * Creates a new storage device (HDD, SSD, ...) transformation for Libvirt/QEMU virtualization
+ * configurations.
+ */
+ public TransformationGenericDiskStorageDevices()
+ {
+ super( TransformationGenericDiskStorageDevices.NAME );
+ }
+
+ /**
+ * Validates a virtualization configuration and input arguments for this transformation.
+ *
+ * @param config virtualization configuration for the validation.
+ * @param args input arguments for the validation.
+ * @throws TransformationException validation has failed.
+ */
+ private void validateInputs( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ if ( config == null || args == null ) {
+ throw new TransformationException( "Virtualization configuration or input arguments are missing!" );
+ }
+ }
+
+ /**
+ * Transforms a storage device in a virtualization configuration selected by its {@code index}.
+ *
+ * @param config virtualization configuration for the transformation.
+ * @param fileName name of the image file for the storage device.
+ * @param index number of the storage device in the virtualization configuration that is
+ * selected.
+ * @throws TransformationException transformation has failed.
+ */
+ private void transformDiskStorageDevice( Domain config, String fileName, int index ) throws TransformationException
+ {
+ final ArrayList<DiskStorage> devices = config.getDiskStorageDevices();
+ final DiskStorage disk = VirtualizationConfigurationQemuUtils.getArrayIndex( devices, index );
+
+ if ( disk == null ) {
+ if ( fileName != null && !fileName.isEmpty() ) {
+ // storage device does not exist, so create new storage device
+ final DiskFloppy newDisk = config.addDiskFloppyDevice();
+ newDisk.setBusType( BusType.VIRTIO );
+ String targetDevName = VirtualizationConfigurationQemuUtils.createAlphabeticalDeviceName( "vd", index );
+ newDisk.setTargetDevice( targetDevName );
+ newDisk.setStorage( StorageType.FILE, fileName );
+ }
+ } else {
+ // storage device exists, so update existing storage device
+ if ( fileName == null || fileName.isEmpty() ) {
+ // remove disk storage device if disk image file name is not set
+ disk.remove();
+ } else {
+ // set image file of disk storage if disk storage device is available
+ disk.setStorage( StorageType.FILE, fileName );
+ }
+ }
+ }
+
+ @Override
+ public void transform( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ // validate configuration and input arguments
+ this.validateInputs( config, args );
+
+ // alter storage device
+ this.transformDiskStorageDevice( config, args.getVmDiskFileNameHDD0(), 0 );
+
+ // remove all additional disk storage devices
+ final ArrayList<DiskStorage> devices = config.getDiskStorageDevices();
+ for ( int i = 1; i < devices.size(); i++ ) {
+ devices.get( i ).remove();
+ }
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericFileSystemDevices.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericFileSystemDevices.java
new file mode 100644
index 00000000..a4f77b0d
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericFileSystemDevices.java
@@ -0,0 +1,107 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import java.util.ArrayList;
+
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.FileSystem;
+import org.openslx.libvirt.domain.device.FileSystem.AccessMode;
+import org.openslx.libvirt.domain.device.FileSystem.Type;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.VirtualizationConfigurationQemuUtils;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+import org.openslx.virtualization.configuration.transformation.TransformationGeneric;
+
+/**
+ * Generic file system device (shared folder) transformation for Libvirt/QEMU virtualization
+ * configurations.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class TransformationGenericFileSystemDevices extends TransformationGeneric<Domain, CommandLineArgs>
+{
+ /**
+ * Name of the configuration transformation.
+ */
+ private static final String NAME = "File system devices";
+
+ /**
+ * Creates a new file system device (shared folder) transformation for Libvirt/QEMU
+ * virtualization configurations.
+ */
+ public TransformationGenericFileSystemDevices()
+ {
+ super( TransformationGenericFileSystemDevices.NAME );
+ }
+
+ /**
+ * Validates a virtualization configuration and input arguments for this transformation.
+ *
+ * @param config virtualization configuration for the validation.
+ * @param args input arguments for the validation.
+ * @throws TransformationException validation has failed.
+ */
+ private void validateInputs( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ if ( config == null || args == null ) {
+ throw new TransformationException( "Virtualization configuration or input arguments are missing!" );
+ }
+ }
+
+ /**
+ * Transforms a storage device in a virtualization configuration selected by its {@code index}.
+ *
+ * @param config virtualization configuration for the transformation.
+ * @param source path of the file system source on a host system.
+ * @param target path of the file system destination in a virtualization guest.
+ * @param index number of the file system device in the virtualization configuration that is
+ * selected.
+ * @throws TransformationException transformation has failed.
+ */
+ private void transformFileSystemDevice( Domain config, String source, String target, int index )
+ throws TransformationException
+ {
+ final ArrayList<FileSystem> devices = config.getFileSystemDevices();
+ final FileSystem fileSystem = VirtualizationConfigurationQemuUtils.getArrayIndex( devices, index );
+
+ if ( fileSystem == null ) {
+ // check if file system device source directory is specified
+ if ( source != null && !source.isEmpty() && target != null && !target.isEmpty() ) {
+ // file system device does not exist, so create new file system device
+ final FileSystem newFileSystem = config.addFileSystemDevice();
+ newFileSystem.setType( Type.MOUNT );
+ newFileSystem.setAccessMode( AccessMode.MAPPED );
+ newFileSystem.setSource( source );
+ newFileSystem.setTarget( target );
+ }
+ } else {
+ if ( source == null || source.isEmpty() || target == null || target.isEmpty() ) {
+ // remove file system device since device source or target is not specified
+ fileSystem.remove();
+ } else {
+ // change type, access mode, source and target of existing file system device
+ fileSystem.setType( Type.MOUNT );
+ fileSystem.setAccessMode( AccessMode.MAPPED );
+ fileSystem.setSource( source );
+ fileSystem.setTarget( target );
+ }
+ }
+ }
+
+ @Override
+ public void transform( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ // validate configuration and input arguments
+ this.validateInputs( config, args );
+
+ // alter file system devices
+ this.transformFileSystemDevice( config, args.getVmFsSrc0(), args.getVmFsTgt0(), 0 );
+ this.transformFileSystemDevice( config, args.getVmFsSrc1(), args.getVmFsTgt1(), 1 );
+
+ // remove all additional file system devices
+ final ArrayList<FileSystem> devices = config.getFileSystemDevices();
+ for ( int i = 2; i < devices.size(); i++ ) {
+ devices.get( i ).remove();
+ }
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericInterfaceDevices.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericInterfaceDevices.java
new file mode 100644
index 00000000..6cf12ce2
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericInterfaceDevices.java
@@ -0,0 +1,101 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import java.util.ArrayList;
+
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.Interface;
+import org.openslx.libvirt.domain.device.InterfaceBridge;
+import org.openslx.libvirt.domain.device.Interface.Model;
+import org.openslx.libvirt.domain.device.Interface.Type;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.VirtualizationConfigurationQemu;
+import org.openslx.virtualization.configuration.VirtualizationConfigurationQemuUtils;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+import org.openslx.virtualization.configuration.transformation.TransformationGeneric;
+
+/**
+ * Generic network interface transformation for Libvirt/QEMU virtualization configurations.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class TransformationGenericInterfaceDevices extends TransformationGeneric<Domain, CommandLineArgs>
+{
+ /**
+ * Name of the configuration transformation.
+ */
+ private static final String NAME = "Network interface devices";
+
+ /**
+ * Creates a new network interface transformation for Libvirt/QEMU virtualization configurations.
+ */
+ public TransformationGenericInterfaceDevices()
+ {
+ super( TransformationGenericInterfaceDevices.NAME );
+ }
+
+ /**
+ * Validates a virtualization configuration and input arguments for this transformation.
+ *
+ * @param config virtualization configuration for the validation.
+ * @param args input arguments for the validation.
+ * @throws TransformationException validation has failed.
+ */
+ private void validateInputs( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ if ( config == null || args == null ) {
+ throw new TransformationException( "Virtualization configuration or input arguments are missing!" );
+ }
+ }
+
+ /**
+ * Transforms a network interface in a virtualization configuration selected by its
+ * {@code index}.
+ *
+ * @param config virtualization configuration for the transformation.
+ * @param macAddress MAC address for the network interface.
+ * @param index number of the network interface in the virtualization configuration that is
+ * selected.
+ * @throws TransformationException transformation has failed.
+ */
+ private void transformInterfaceDevice( Domain config, String macAddress, int index ) throws TransformationException
+ {
+ final ArrayList<Interface> devices = config.getInterfaceDevices();
+ final Interface device = VirtualizationConfigurationQemuUtils.getArrayIndex( devices, index );
+
+ if ( device == null ) {
+ if ( macAddress != null && !macAddress.isEmpty() ) {
+ // create network interface if it does not exists
+ final InterfaceBridge newDevice = config.addInterfaceBridgeDevice();
+ newDevice.setType( Type.BRIDGE );
+ newDevice.setModel( Model.VIRTIO );
+ newDevice.setMacAddress( macAddress );
+ newDevice.setSource( VirtualizationConfigurationQemu.NETWORK_BRIDGE_NAT_DEFAULT );
+ }
+ } else {
+ if ( macAddress == null || macAddress.isEmpty() ) {
+ // remove network interface device if MAC address is not set
+ device.remove();
+ } else {
+ // set MAC address of network interface device if network interface device is available
+ device.setMacAddress( macAddress );
+ }
+ }
+ }
+
+ @Override
+ public void transform( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ // validate configuration and input arguments
+ this.validateInputs( config, args );
+
+ // alter network interface
+ this.transformInterfaceDevice( config, args.getVmMacAddress0(), 0 );
+
+ // remove all additional disk storage devices
+ final ArrayList<Interface> devices = config.getInterfaceDevices();
+ for ( int i = 1; i < devices.size(); i++ ) {
+ devices.get( i ).remove();
+ }
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericMemory.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericMemory.java
new file mode 100644
index 00000000..fce373f7
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericMemory.java
@@ -0,0 +1,59 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import java.math.BigInteger;
+
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.DomainUtils;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+import org.openslx.virtualization.configuration.transformation.TransformationGeneric;
+
+/**
+ * Generic memory transformation for Libvirt/QEMU virtualization configurations.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class TransformationGenericMemory extends TransformationGeneric<Domain, CommandLineArgs>
+{
+ /**
+ * Name of the configuration transformation.
+ */
+ private static final String NAME = "Memory [normal, current (balloning)]";
+
+ /**
+ * Creates a new memory transformation for Libvirt/QEMU virtualization configurations.
+ */
+ public TransformationGenericMemory()
+ {
+ super( TransformationGenericMemory.NAME );
+ }
+
+ /**
+ * Validates a virtualization configuration and input arguments for this transformation.
+ *
+ * @param config virtualization configuration for the validation.
+ * @param args input arguments for the validation.
+ * @throws TransformationException validation has failed.
+ */
+ private void validateInputs( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ if ( config == null || args == null ) {
+ throw new TransformationException( "Virtualization configuration or input arguments are missing!" );
+ } else if ( args.getVmMemory() == null || args.getVmMemory().isEmpty() ) {
+ throw new TransformationException( "Amount of memory in MiB is not specified!" );
+ }
+ }
+
+ @Override
+ public void transform( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ // validate configuration and input arguments
+ this.validateInputs( config, args );
+
+ BigInteger memory = DomainUtils.decodeMemory( args.getVmMemory(), "MiB" );
+
+ config.setMemory( memory );
+ config.setCurrentMemory( memory );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericName.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericName.java
new file mode 100644
index 00000000..b96793d5
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericName.java
@@ -0,0 +1,57 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+import org.openslx.virtualization.configuration.transformation.TransformationGeneric;
+
+/**
+ * Generic name transformation for Libvirt/QEMU virtualization configurations.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class TransformationGenericName extends TransformationGeneric<Domain, CommandLineArgs>
+{
+ /**
+ * Name of the configuration transformation.
+ */
+ private static final String NAME = "Name [(display) name]";
+
+ /**
+ * Creates a new name transformation for Libvirt/QEMU virtualization configurations.
+ */
+ public TransformationGenericName()
+ {
+ super( TransformationGenericName.NAME );
+ }
+
+ /**
+ * Validates a virtualization configuration and input arguments for this transformation.
+ *
+ * @param config virtualization configuration for the validation.
+ * @param args input arguments for the validation.
+ * @throws TransformationException validation has failed.
+ */
+ private void validateInputs( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ if ( config == null || args == null ) {
+ throw new TransformationException( "Virtualization configuration or input arguments are missing!" );
+ } else if ( args.getVmName() == null || args.getVmName().isEmpty() ) {
+ throw new TransformationException( "Name is not specified!" );
+ } else if ( args.getVmDisplayName() == null || args.getVmDisplayName().isEmpty() ) {
+ throw new TransformationException( "Display name is not specified!" );
+ }
+ }
+
+ @Override
+ public void transform( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ // validate configuration and input arguments
+ this.validateInputs( config, args );
+
+ // alter names in the configuration
+ config.setName( args.getVmName() );
+ config.setTitle( args.getVmDisplayName() );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericParallelDevices.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericParallelDevices.java
new file mode 100644
index 00000000..08d43ef0
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericParallelDevices.java
@@ -0,0 +1,97 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import java.util.ArrayList;
+
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.Parallel;
+import org.openslx.libvirt.domain.device.Parallel.Type;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.VirtualizationConfigurationQemuUtils;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+import org.openslx.virtualization.configuration.transformation.TransformationGeneric;
+
+/**
+ * Generic parallel device transformation for Libvirt/QEMU virtualization configurations.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class TransformationGenericParallelDevices extends TransformationGeneric<Domain, CommandLineArgs>
+{
+ /**
+ * Name of the configuration transformation.
+ */
+ private static final String NAME = "Parallel devices";
+
+ /**
+ * Creates a new parallel device transformation for Libvirt/QEMU virtualization configurations.
+ */
+ public TransformationGenericParallelDevices()
+ {
+ super( TransformationGenericParallelDevices.NAME );
+ }
+
+ /**
+ * Validates a virtualization configuration and input arguments for this transformation.
+ *
+ * @param config virtualization configuration for the validation.
+ * @param args input arguments for the validation.
+ * @throws TransformationException validation has failed.
+ */
+ private void validateInputs( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ if ( config == null || args == null ) {
+ throw new TransformationException( "Virtualization configuration or input arguments are missing!" );
+ }
+ }
+
+ /**
+ * Transforms a parallel device in a virtualization configuration selected by its {@code index}.
+ *
+ * @param config virtualization configuration for the transformation.
+ * @param fileName path to the parallel device file on the host system.
+ * @param index number of the parallel device in the virtualization configuration that is
+ * selected.
+ * @throws TransformationException transformation has failed.
+ */
+ private void transformParallelDevice( Domain config, String fileName, int index ) throws TransformationException
+ {
+ final ArrayList<Parallel> devices = config.getParallelDevices();
+ final Parallel device = VirtualizationConfigurationQemuUtils.getArrayIndex( devices, index );
+
+ if ( device == null ) {
+ // check if device file name is specified
+ if ( fileName != null ) {
+ // parallel port device does not exist, so create new parallel port device
+ final Parallel newDevice = config.addParallelDevice();
+ newDevice.setType( Type.DEV );
+ newDevice.setSource( fileName );
+ }
+ } else {
+ if ( fileName == null || fileName.isEmpty() ) {
+ // remove device since device file is not specified
+ device.remove();
+ } else {
+ // change type and source of existing parallel port device
+ device.setType( Type.DEV );
+ device.setSource( fileName );
+ }
+ }
+ }
+
+ @Override
+ public void transform( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ // validate configuration and input arguments
+ this.validateInputs( config, args );
+
+ // alter parallel device
+ this.transformParallelDevice( config, args.getVmDeviceParallel0(), 0 );
+
+ // remove all additional parallel devices
+ final ArrayList<Parallel> devices = config.getParallelDevices();
+ for ( int i = 1; i < devices.size(); i++ ) {
+ devices.get( i ).remove();
+ }
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericUuid.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericUuid.java
new file mode 100644
index 00000000..43fb6412
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericUuid.java
@@ -0,0 +1,53 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+import org.openslx.virtualization.configuration.transformation.TransformationGeneric;
+
+/**
+ * Generic UUID transformation for Libvirt/QEMU virtualization configurations.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class TransformationGenericUuid extends TransformationGeneric<Domain, CommandLineArgs>
+{
+ /**
+ * Name of the configuration transformation.
+ */
+ private static final String NAME = "UUID";
+
+ /**
+ * Creates a new UUID transformation for Libvirt/QEMU virtualization configurations.
+ */
+ public TransformationGenericUuid()
+ {
+ super( TransformationGenericUuid.NAME );
+ }
+
+ /**
+ * Validates a virtualization configuration and input arguments for this transformation.
+ *
+ * @param config virtualization configuration for the validation.
+ * @param args input arguments for the validation.
+ * @throws TransformationException validation has failed.
+ */
+ private void validateInputs( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ if ( config == null || args == null ) {
+ throw new TransformationException( "Virtualization configuration or input arguments are missing!" );
+ } else if ( args.getVmUuid() == null || args.getVmUuid().isEmpty() ) {
+ throw new TransformationException( "UUID is not specified!" );
+ }
+ }
+
+ @Override
+ public void transform( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ // validate configuration and input arguments
+ this.validateInputs( config, args );
+
+ config.setUuid( args.getVmUuid() );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuArchitecture.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuArchitecture.java
new file mode 100644
index 00000000..a51c829d
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuArchitecture.java
@@ -0,0 +1,261 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openslx.libvirt.capabilities.Capabilities;
+import org.openslx.libvirt.capabilities.guest.Guest;
+import org.openslx.libvirt.capabilities.guest.Machine;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.Domain.OsType;
+import org.openslx.libvirt.domain.Domain.Type;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.runvirt.plugin.qemu.virtualization.LibvirtHypervisorQemu;
+import org.openslx.runvirt.virtualization.LibvirtHypervisorException;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+import org.openslx.virtualization.configuration.transformation.TransformationSpecific;
+
+/**
+ * Specific architecture transformation for Libvirt/QEMU virtualization configurations.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class TransformationSpecificQemuArchitecture
+ extends TransformationSpecific<Domain, CommandLineArgs, LibvirtHypervisorQemu>
+{
+ /**
+ * Name of the configuration transformation.
+ */
+ private static final String NAME = "QEMU Architecture [CPU architecture, machine type, ...]";
+
+ /**
+ * Creates a new architecture transformation for Libvirt/QEMU virtualization configurations.
+ *
+ * @param hypervisor Libvirt/QEMU hypervisor.
+ */
+ public TransformationSpecificQemuArchitecture( LibvirtHypervisorQemu virtualizer )
+ {
+ super( TransformationSpecificQemuArchitecture.NAME, virtualizer );
+ }
+
+ /**
+ * Validates a virtualization configuration and input arguments for this transformation.
+ *
+ * @param config virtualization configuration for the validation.
+ * @param args input arguments for the validation.
+ * @throws TransformationException validation has failed.
+ */
+ private void validateInputs( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ if ( config == null ) {
+ throw new TransformationException( "Virtualization configuration is missing!" );
+ }
+ }
+
+ /**
+ * Queries and returns the capabilities of the Libvirt/QEMU hypervisor.
+ *
+ * @return capabilities of the Libvirt/QEMU hypervisor.
+ * @throws TransformationException failed to query and return the capabilities of the
+ * Libvirt/QEMU hypervisor.
+ */
+ protected Capabilities getCapabilities() throws TransformationException
+ {
+ final Capabilities capabilities;
+
+ try {
+ capabilities = this.getVirtualizer().getCapabilites();
+ } catch ( LibvirtHypervisorException e ) {
+ final String errorMsg = new String(
+ "Failed to retrieve host capabilities from QEMU virtualizer: " + e.getLocalizedMessage() );
+ throw new TransformationException( errorMsg );
+ }
+
+ return capabilities;
+ }
+
+ /**
+ * Returns a guest capability of the hypervisor's host system based on a given target
+ * architecture name.
+ *
+ * @param architectureName target architecture of the guest that is returned
+ * @return guest capability of the hypervisor's host system with target architecture name.
+ * @throws TransformationException failed to return guest capability of the hypervisor's host.
+ */
+ private Guest getTargetGuestFromArchName( String architectureName ) throws TransformationException
+ {
+ final List<Guest> guests = this.getCapabilities().getGuests();
+ Guest targetGuest = null;
+
+ if ( architectureName == null ) {
+ return targetGuest;
+ }
+
+ for ( Guest guest : guests ) {
+ final String guestArchitectureName = guest.getArchName();
+ if ( architectureName.equals( guestArchitectureName ) ) {
+ targetGuest = guest;
+ break;
+ }
+ }
+
+ return targetGuest;
+ }
+
+ /**
+ * Returns the target machine description of a host system's guest capability based on a given
+ * target machine name.
+ *
+ * @param guest guest capability of a host system.
+ * @param machineName name of the machine description.
+ * @return target machine description of a host system's guest capability.
+ * @throws TransformationException failed to return the target machine description of a host
+ * system's guest capabilities.
+ */
+ private Machine getTargetMachineFromGuest( Guest guest, String machineName ) throws TransformationException
+ {
+ final List<Machine> machines = guest.getArchMachines();
+ Machine targetMachine = null;
+
+ if ( machineName == null ) {
+ return targetMachine;
+ }
+
+ for ( Machine machine : machines ) {
+ if ( machineName.equals( machine.getName() ) ) {
+ targetMachine = machine;
+ break;
+ }
+ }
+
+ return targetMachine;
+ }
+
+ /**
+ * Returns the canonical names of a target machine description of a host system's guest
+ * capability.
+ *
+ * @param guest guest capability of a host system.
+ * @return canonical names of a target machine description of a host system's guest capability.
+ * @throws TransformationException failed to return the canonical names of a target machine
+ * description of a host system's guest capability
+ */
+ private List<String> getCanonicalNamesFromTargetMachines( Guest guest ) throws TransformationException
+ {
+ final List<Machine> machines = guest.getArchMachines();
+ final List<String> canonicalNames = new ArrayList<String>();
+
+ for ( Machine machine : machines ) {
+ final String canonicalName = machine.getCanonicalMachine();
+ if ( canonicalName != null ) {
+ canonicalNames.add( canonicalName );
+ }
+ }
+
+ return canonicalNames;
+ }
+
+ @Override
+ public void transform( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ // validate configuration and input arguments
+ this.validateInputs( config, args );
+
+ // get source architecture, machine- and OS type
+ final String sourceArchitectureName = config.getOsArch();
+ final String sourceMachine = config.getOsMachine();
+ final OsType sourceOsType = config.getOsType();
+ final Type sourceDomainType = config.getType();
+
+ // check if source architecture is supported by one of the hypervisor's guests
+ Guest targetGuest = null;
+ if ( sourceArchitectureName == null ) {
+ final String errorMsg = new String( "Source architecture is not specified!" );
+ throw new TransformationException( errorMsg );
+ } else {
+ targetGuest = this.getTargetGuestFromArchName( sourceArchitectureName );
+ if ( targetGuest == null ) {
+ final String errorMsg = new String( "Source architecture is not supported by the virtualizer!" );
+ throw new TransformationException( errorMsg );
+ }
+ }
+
+ // check if source machine is supported by the hypervisor
+ Machine targetMachine = null;
+ if ( sourceMachine == null ) {
+ final String errorMsg = new String( "Source machine type is not specified!" );
+ throw new TransformationException( errorMsg );
+ } else {
+ // get all possible machine type for supported source architecture
+ targetMachine = this.getTargetMachineFromGuest( targetGuest, sourceMachine );
+
+ if ( targetMachine == null ) {
+ // source machine is not directly supported by the hypervisor
+ // check if up- or downgraded version of the chipset is supported by the hypervisor
+ List<String> targetMachineCanonicalNames = this.getCanonicalNamesFromTargetMachines( targetGuest );
+
+ // retrieve overwrite chipset name from canonical machine names
+ String sourceMachineOverwrite = null;
+ for ( String targetMachineCanonicalName : targetMachineCanonicalNames ) {
+ if ( sourceMachine.contains( targetMachineCanonicalName ) ) {
+ sourceMachineOverwrite = targetMachineCanonicalName;
+ break;
+ }
+ }
+
+ // if overwrite available, patch the machine type
+ if ( sourceMachineOverwrite != null ) {
+ config.setOsMachine( sourceMachineOverwrite );
+ } else {
+ final String errorMsg = new String( "Source machine type is not supported by the virtualizer!" );
+ throw new TransformationException( errorMsg );
+ }
+ }
+ }
+
+ // check if source OS type is supported by the hypervisor's architecture
+ if ( sourceOsType == null ) {
+ final String errorMsg = new String( "OS type is not specified!" );
+ throw new TransformationException( errorMsg );
+ } else {
+ if ( !sourceOsType.toString().equals( targetGuest.getOsType().toString() ) ) {
+ final String errorMsg = new String( "OS type is not supported by the virtualizer!" );
+ throw new TransformationException( errorMsg );
+ }
+ }
+
+ // check if source domain type is supported by the hypervisor's architecture
+ Type targetDomainType = null;
+ if ( sourceDomainType == null ) {
+ final String errorMsg = new String( "Source domain type is not specified!" );
+ throw new TransformationException( errorMsg );
+ } else {
+ final List<org.openslx.libvirt.capabilities.guest.Domain> targetDomains = targetGuest.getArchDomains();
+
+ // retrieve supported domain type
+ for ( org.openslx.libvirt.capabilities.guest.Domain domain : targetDomains ) {
+ final Type domainType = domain.getType();
+ if ( domainType == sourceDomainType ) {
+ targetDomainType = domainType;
+ break;
+ }
+ }
+
+ // check supported domain type
+ if ( targetDomainType == null ) {
+ final String errorMsg = new String( "Source domain type is not supported by the virtualizer!" );
+ throw new TransformationException( errorMsg );
+ }
+ }
+
+ // patch path of QEMU emulator binary
+ final String archEmulator = targetGuest.getArchEmulator();
+ if ( archEmulator == null ) {
+ final String errorMsg = new String( "Emulation of source architecture is not supported by the virtualizer!" );
+ throw new TransformationException( errorMsg );
+ } else {
+ config.setDevicesEmulator( targetGuest.getArchEmulator() );
+ }
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGpuPassthroughNvidia.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGpuPassthroughNvidia.java
new file mode 100644
index 00000000..a22bf027
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGpuPassthroughNvidia.java
@@ -0,0 +1,232 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openslx.libvirt.capabilities.Capabilities;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.HostdevPci;
+import org.openslx.libvirt.domain.device.HostdevPciDeviceAddress;
+import org.openslx.libvirt.domain.device.HostdevPciDeviceDescription;
+import org.openslx.libvirt.domain.device.Shmem;
+import org.openslx.libvirt.domain.device.Video;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.runvirt.plugin.qemu.virtualization.LibvirtHypervisorQemu;
+import org.openslx.runvirt.virtualization.LibvirtHypervisorException;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+import org.openslx.virtualization.configuration.transformation.TransformationSpecific;
+
+/**
+ * Specific Nvidia GPU passthrough transformation for Libvirt/QEMU virtualization configurations.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class TransformationSpecificQemuGpuPassthroughNvidia
+ extends TransformationSpecific<Domain, CommandLineArgs, LibvirtHypervisorQemu>
+{
+ /**
+ * Name of the configuration transformation.
+ */
+ private static final String NAME = "QEMU GPU passthrough [Nvidia]";
+
+ /**
+ * Vendor identifier of PCI devices from Nvidia.
+ */
+ private static final int NVIDIA_PCI_VENDOR_ID = 0x10de;
+
+ /**
+ * Vendor identifier of the Hyper-V enlightenment for hypervisor shadowing.
+ */
+ public static final String HYPERV_VENDOR_ID = "62776c706277";
+
+ /**
+ * Maximum width in pixel of the GPU passthrough rendered display.
+ */
+ private static final long MAX_DISPLAY_WIDTH = 2560;
+
+ /**
+ * Maximum height in pixel of the GPU passthrough rendered display.
+ */
+ private static final long MAX_DISPLAY_HEIGHT = 1440;
+
+ /**
+ * Reserved memory for framebuffer meta data of the Looking Glass shared memory device in MiB.
+ */
+ private static final long RESERVED_MEMORY_FRAMEBUFFER = 10;
+
+ /**
+ * Creates a new Nvidia GPU passthrough transformation for Libvirt/QEMU virtualization
+ * configurations.
+ *
+ * @param hypervisor Libvirt/QEMU hypervisor.
+ */
+ public TransformationSpecificQemuGpuPassthroughNvidia( LibvirtHypervisorQemu hypervisor )
+ {
+ super( TransformationSpecificQemuGpuPassthroughNvidia.NAME, hypervisor );
+ }
+
+ /**
+ * Validates a PCI device description and address of a PCI device from a Nvidia GPU and parses
+ * the validated PCI device addresses.
+ *
+ * @param pciIds textual PCI device description and address to be validated.
+ *
+ * @return list of validated and parsed PCI device addresses for a NVIDIA GPU passthrough.
+ *
+ * @throws TransformationException validation of PCI device description and address failed.
+ */
+ private static List<HostdevPciDeviceAddress> validateParseNvidiaPciIds( List<String> pciIds )
+ throws TransformationException
+ {
+ final List<HostdevPciDeviceAddress> parsedPciAddresses = new ArrayList<HostdevPciDeviceAddress>();
+
+ if ( pciIds != null && pciIds.size() > 0 ) {
+ // abort if arguments do not follow the pattern:
+ //
+ // [0]: <VENDOR ID 0>:<DEVICE ID 0>
+ // [1]: <PCI DOMAIN 0>:<PCI BUS 0>:<PCI DEVICE 0>.<PCI FUNCTION 0>
+ // [2]: <VENDOR ID 1>:<DEVICE ID 1>
+ // [3]: <PCI DOMAIN 1>:<PCI BUS 1>:<PCI DEVICE 1>.<PCI FUNCTION 1>
+ // ...
+ //
+ if ( pciIds.size() % 2 != 0 ) {
+ throw new TransformationException(
+ "Arguments of PCI IDs are not follow the pattern for a GPU passthrough!" );
+ }
+
+ // parse PCI device description and PCI device address
+ for ( int i = 0; i < pciIds.size(); i += 2 ) {
+ // parse vendor and device ID
+ HostdevPciDeviceDescription deviceDescription = null;
+ try {
+ deviceDescription = HostdevPciDeviceDescription.valueOf( pciIds.get( i ) );
+ } catch ( IllegalArgumentException e ) {
+ throw new TransformationException( "Invalid vendor or device ID of the PCI device description!" );
+ }
+
+ // validate vendor ID
+ final int vendorId = deviceDescription.getVendorId();
+ if ( TransformationSpecificQemuGpuPassthroughNvidia.NVIDIA_PCI_VENDOR_ID != vendorId ) {
+ final String errorMsg = "Vendor ID '" + vendorId + "' of the PCI device is not from Nvidia!";
+ throw new TransformationException( errorMsg );
+ }
+
+ // parse PCI domain, PCI bus, PCI device and PCI function
+ final HostdevPciDeviceAddress parsedPciAddress = HostdevPciDeviceAddress.valueOf( pciIds.get( i + 1 ) );
+ if ( parsedPciAddress != null ) {
+ parsedPciAddresses.add( parsedPciAddress );
+ }
+ }
+ }
+
+ return parsedPciAddresses;
+ }
+
+ /**
+ * Validates a virtualization configuration and input arguments for this transformation.
+ *
+ * @param config virtualization configuration for the validation.
+ * @param args input arguments for the validation.
+ * @throws TransformationException validation has failed.
+ */
+ private void validateInputs( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ if ( config == null || args == null ) {
+ throw new TransformationException( "Virtualization configuration or input arguments are missing!" );
+ }
+
+ TransformationSpecificQemuGpuPassthroughNvidia.validateParseNvidiaPciIds( args.getVmNvGpuIds0() );
+ }
+
+ /**
+ * Queries and returns the capabilities of the Libvirt/QEMU hypervisor.
+ *
+ * @return capabilities of the Libvirt/QEMU hypervisor.
+ * @throws TransformationException failed to query and return the capabilities of the
+ * Libvirt/QEMU hypervisor.
+ */
+ protected Capabilities getCapabilities() throws TransformationException
+ {
+ Capabilities capabilities = null;
+
+ try {
+ capabilities = this.getVirtualizer().getCapabilites();
+ } catch ( LibvirtHypervisorException e ) {
+ final String errorMsg = new String(
+ "Failed to retrieve host capabilities from QEMU virtualizer: " + e.getLocalizedMessage() );
+ throw new TransformationException( errorMsg );
+ }
+
+ return capabilities;
+ }
+
+ private static BigInteger roundToNearestPowerOf2( BigInteger value )
+ {
+ BigInteger k = BigInteger.valueOf( 1 );
+
+ while ( k.compareTo( value ) == -1 ) {
+ k = k.multiply( BigInteger.valueOf( 2 ) );
+ }
+
+ return k;
+ }
+
+ /**
+ * Calculates the framebuffer memory size for the Looking Glass shared memory device.
+ *
+ * @return framebuffer memory size in bytes for the Looking Glass shared memory device.
+ */
+ private static BigInteger calculateFramebufferSize()
+ {
+ final long totalBytesFramebuffer = MAX_DISPLAY_WIDTH * MAX_DISPLAY_HEIGHT * 4 * 2;
+ final long totalBytesReserved = RESERVED_MEMORY_FRAMEBUFFER * 1048576;
+
+ // round sum of total memory in bytes to nearest power of two
+ return roundToNearestPowerOf2( BigInteger.valueOf( totalBytesFramebuffer + totalBytesReserved ) );
+ }
+
+ @Override
+ public void transform( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ // validate configuration and input arguments
+ this.validateInputs( config, args );
+
+ // check if passthrough of Nvidia GPU takes place
+ if ( args.isNvidiaGpuPassthroughEnabled() ) {
+ // validate submitted PCI IDs
+ final List<HostdevPciDeviceAddress> pciDeviceAddresses = TransformationSpecificQemuGpuPassthroughNvidia
+ .validateParseNvidiaPciIds( args.getVmNvGpuIds0() );
+
+ // check if IOMMU support is available on the host
+ if ( !this.getCapabilities().hasHostIommuSupport() ) {
+ final String errorMsg = "IOMMU support is not available on the hypervisor but required for GPU passthrough!";
+ throw new TransformationException( errorMsg );
+ }
+
+ // passthrough PCI devices of the GPU
+ for ( final HostdevPciDeviceAddress pciDeviceAddress : pciDeviceAddresses ) {
+ final HostdevPci pciDevice = config.addHostdevPciDevice();
+ pciDevice.setManaged( true );
+ pciDevice.setSource( pciDeviceAddress );
+ }
+
+ // add shared memory device for Looking Glass
+ final Shmem shmemDevice = config.addShmemDevice();
+ shmemDevice.setName( "looking-glass" );
+ shmemDevice.setModel( Shmem.Model.IVSHMEM_PLAIN );
+ shmemDevice.setSize( TransformationSpecificQemuGpuPassthroughNvidia.calculateFramebufferSize() );
+
+ // enable hypervisor shadowing to avoid error code 43 of Nvidia drivers in virtual machines
+ config.setFeatureHypervVendorIdValue( TransformationSpecificQemuGpuPassthroughNvidia.HYPERV_VENDOR_ID );
+ config.setFeatureHypervVendorIdState( true );
+ config.setFeatureKvmHiddenState( true );
+
+ // disable all software video devices by disable them
+ for ( Video videoDevice : config.getVideoDevices() ) {
+ videoDevice.disable();
+ }
+ }
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuSerialDevices.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuSerialDevices.java
new file mode 100644
index 00000000..30f60289
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuSerialDevices.java
@@ -0,0 +1,117 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import java.util.ArrayList;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.Serial.Type;
+import org.openslx.libvirt.domain.device.Serial;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.runvirt.plugin.qemu.virtualization.LibvirtHypervisorQemu;
+import org.openslx.virtualization.configuration.VirtualizationConfigurationQemuUtils;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+import org.openslx.virtualization.configuration.transformation.TransformationSpecific;
+
+/**
+ * Specific serial device transformation for Libvirt/QEMU virtualization configurations.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class TransformationSpecificQemuSerialDevices
+ extends TransformationSpecific<Domain, CommandLineArgs, LibvirtHypervisorQemu>
+{
+ /**
+ * Name of the configuration transformation.
+ */
+ private static final String NAME = "Serial devices";
+
+ /**
+ * Creates a new serial device transformation for Libvirt/QEMU virtualization configurations.
+ *
+ * @param hypervisor Libvirt/QEMU hypervisor.
+ */
+ public TransformationSpecificQemuSerialDevices( LibvirtHypervisorQemu hypervisor )
+ {
+ super( TransformationSpecificQemuSerialDevices.NAME, hypervisor );
+ }
+
+ /**
+ * Validates a virtualization configuration and input arguments for this transformation.
+ *
+ * @param config virtualization configuration for the validation.
+ * @param args input arguments for the validation.
+ * @throws TransformationException validation has failed.
+ */
+ private void validateInputs( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ if ( config == null || args == null ) {
+ throw new TransformationException( "Virtualization configuration or input arguments are missing!" );
+ }
+ }
+
+ /**
+ * Returns all serial devices from a virtualization configuration that link to a host system's
+ * serial device.
+ *
+ * @param config virtualization configuration.
+ * @return all serial devices that link to a host system's serial device.
+ */
+ private ArrayList<Serial> getSerialDevDevices( Domain config )
+ {
+ final ArrayList<Serial> devices = config.getSerialDevices();
+ final Predicate<Serial> byDeviceTypeDev = device -> device.getType() == Type.DEV;
+
+ return devices.stream().filter( byDeviceTypeDev ).collect( Collectors.toCollection( ArrayList::new ) );
+ }
+
+ /**
+ * Transforms a serial device in a virtualization configuration selected by its {@code index}.
+ *
+ * @param config virtualization configuration for the transformation.
+ * @param fileName path to the serial device file on the host system.
+ * @param index number of the serial device in the virtualization configuration that is selected.
+ * @throws TransformationException transformation has failed.
+ */
+ private void transformSerialDevice( Domain config, String fileName, int index ) throws TransformationException
+ {
+ final ArrayList<Serial> devices = this.getSerialDevDevices( config );
+ final Serial device = VirtualizationConfigurationQemuUtils.getArrayIndex( devices, index );
+
+ if ( device == null ) {
+ // check if device file name is specified
+ if ( fileName != null && !fileName.isEmpty() ) {
+ // serial port device is not available, so create new serial port device
+ final Serial newDevice = config.addSerialDevice();
+ newDevice.setType( Type.DEV );
+ newDevice.setSource( fileName );
+ }
+ } else {
+ if ( fileName == null || fileName.isEmpty() ) {
+ // remove serial port device if device file name is not set
+ device.remove();
+ } else {
+ // set type and source of existing serial port device
+ device.setType( Type.DEV );
+ device.setSource( fileName );
+ }
+ }
+ }
+
+ @Override
+ public void transform( Domain config, CommandLineArgs args ) throws TransformationException
+ {
+ // validate configuration and input arguments
+ this.validateInputs( config, args );
+
+ // alter serial device
+ this.transformSerialDevice( config, args.getVmDeviceSerial0(), 0 );
+
+ // remove all additional serial devices
+ final ArrayList<Serial> devices = this.getSerialDevDevices( config );
+ for ( int i = 1; i < devices.size(); i++ ) {
+ devices.get( i ).remove();
+ }
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/virtualization/LibvirtHypervisorQemu.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/virtualization/LibvirtHypervisorQemu.java
new file mode 100644
index 00000000..34cf33cf
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/plugin/qemu/virtualization/LibvirtHypervisorQemu.java
@@ -0,0 +1,63 @@
+package org.openslx.runvirt.plugin.qemu.virtualization;
+
+import org.openslx.runvirt.virtualization.LibvirtHypervisor;
+import org.openslx.runvirt.virtualization.LibvirtHypervisorException;
+
+/**
+ * Representation of the Libvirt QEMU hypervisor backend.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class LibvirtHypervisorQemu extends LibvirtHypervisor
+{
+ /**
+ * Creates a new Libvirt QEMU hypervisor backend and connects to the specified backend.
+ *
+ * @param type session type of the connection to the Libvirt QEMU hypervisor backend.
+ * @throws LibvirtHypervisorException failed to connect to the Libvirt QEMU hypervisor backend.
+ */
+ public LibvirtHypervisorQemu( QemuSessionType type ) throws LibvirtHypervisorException
+ {
+ super( type.getConnectionUri() );
+ }
+
+ /**
+ * Type of Libvirt QEMU hypervisor backend session.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+ public enum QemuSessionType
+ {
+ // @formatter:off
+ LOCAL_SYSTEM_SESSION( "qemu:///system" ),
+ LOCAL_USER_SESSION ( "qemu:///session" );
+ // @formatter:on
+
+ /**
+ * Connection URI of the QEMU session type.
+ */
+ private final String connectionUri;
+
+ /**
+ * Creates a new QEMU session type.
+ *
+ * @param connectionUri URI for the connection of the session.
+ */
+ QemuSessionType( String connectionUri )
+ {
+ this.connectionUri = connectionUri;
+ }
+
+ /**
+ * Returns the URI of the connection for the session.
+ *
+ * @return URI of the connection for the session.
+ */
+ public String getConnectionUri()
+ {
+ return this.connectionUri;
+ }
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/Viewer.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/Viewer.java
new file mode 100644
index 00000000..d23a9e11
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/Viewer.java
@@ -0,0 +1,118 @@
+package org.openslx.runvirt.viewer;
+
+import org.openslx.runvirt.virtualization.LibvirtHypervisor;
+import org.openslx.runvirt.virtualization.LibvirtVirtualMachine;
+import org.openslx.virtualization.Version;
+
+/**
+ * Representation of an viewer for virtual machines running on a host system.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public abstract class Viewer
+{
+ /**
+ * Name of the viewer.
+ */
+ private final String name;
+
+ /**
+ * Number of supported displays by the viewer.
+ */
+ private final int numSupportedDisplays;
+
+ /**
+ * The virtual machine to display.
+ */
+ private final LibvirtVirtualMachine machine;
+
+ /**
+ * Remote (hypervisor) endpoint for the viewer to connect to.
+ */
+ private final LibvirtHypervisor hypervisor;
+
+ /**
+ * Creates a new viewer for a Libvirt virtual machine running on a Libvirt hypervisor.
+ *
+ * @param name textual name of the viewer.
+ * @param numSupportedDisplays number of supported displays by the viewer.
+ * @param machine virtual machine to display.
+ * @param hypervisor remote (hypervisor) endpoint for the viewer to connect to.
+ */
+ public Viewer( String name, int numSupportedDisplays, LibvirtVirtualMachine machine, LibvirtHypervisor hypervisor )
+ {
+ this.name = name;
+ this.numSupportedDisplays = numSupportedDisplays;
+ this.machine = machine;
+ this.hypervisor = hypervisor;
+ }
+
+ /**
+ * Returns the name of the viewer.
+ *
+ * @return name of the viewer.
+ */
+ public String getName()
+ {
+ return this.name;
+ }
+
+ /**
+ * Returns the number of supported displays by the viewer.
+ *
+ * @return number of supported displays by the viewer.
+ */
+ public int getNumberOfSupportedDisplays()
+ {
+ return this.numSupportedDisplays;
+ }
+
+ /**
+ * Returns the virtual machine to display.
+ *
+ * @return virtual machine to display.
+ */
+ public LibvirtVirtualMachine getMachine()
+ {
+ return this.machine;
+ }
+
+ /**
+ * Returns the remote (hypervisor) endpoint for the viewer to connect to.
+ *
+ * @return remote (hypervisor) endpoint for the viewer to connect to.
+ */
+ public LibvirtHypervisor getHypervisor()
+ {
+ return this.hypervisor;
+ }
+
+ /**
+ * Displays all virtual machine's displays.
+ *
+ * @throws ViewerException failed to display all displays of a virtual machine.
+ *
+ * @apiNote A call to this method blocks until the implemented {@link #render()} process
+ * terminates.
+ */
+ public void display() throws ViewerException
+ {
+ this.render();
+ }
+
+ /**
+ * Returns the version of the viewer.
+ *
+ * @return version of the viewer.
+ * @throws ViewerException failed to get version of the viewer.
+ */
+ public abstract Version getVersion() throws ViewerException;
+
+ /**
+ * Renders the content of all displays from the virtual machine.
+ *
+ * @throws ViewerException failed to render all displays of a virtual machine.
+ */
+ protected abstract void render() throws ViewerException;
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerException.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerException.java
new file mode 100644
index 00000000..0c178375
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerException.java
@@ -0,0 +1,35 @@
+package org.openslx.runvirt.viewer;
+
+/**
+ * An exception of a viewer error during displaying all displays of a virtual machine.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class ViewerException extends Exception
+{
+ /**
+ * Version for serialization.
+ */
+ private static final long serialVersionUID = 161091514643380414L;
+
+ /**
+ * Creates a new viewer exception including an error message.
+ *
+ * @param errorMsg message to describe a specific viewer error.
+ */
+ public ViewerException( String errorMsg )
+ {
+ super( errorMsg );
+ }
+
+ /**
+ * Creates a new viewer exception by a copy of an existing viewer exception.
+ *
+ * @param e existing viewer exception.
+ */
+ public ViewerException( ViewerException e )
+ {
+ super( e );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerLookingGlassClient.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerLookingGlassClient.java
new file mode 100644
index 00000000..cea9ccd8
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerLookingGlassClient.java
@@ -0,0 +1,105 @@
+package org.openslx.runvirt.viewer;
+
+import org.openslx.runvirt.virtualization.LibvirtHypervisor;
+import org.openslx.runvirt.virtualization.LibvirtVirtualMachine;
+import org.openslx.virtualization.Version;
+
+/**
+ * Looking Glass Client to view the exposed framebuffer (through a shared memory) of a virtual
+ * machine running the Looking Glass Host application.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class ViewerLookingGlassClient extends Viewer
+{
+ /**
+ * Name of the Looking Glass Client program.
+ */
+ private final static String NAME = "looking-glass-client";
+
+ /**
+ * Maximum number of supported displays by the Looking Glass Client.
+ */
+ private final static int NUM_SUPPORTED_DISPLAYS = 1;
+
+ /**
+ * File name of the shared memory file to receive display content from the Looking Glass Host.
+ */
+ private final static String SHARED_MEMORY_FILENAME = "/dev/shm/looking-glass";
+
+ /**
+ * State whether showing debug information during virtual machine rendering or not.
+ */
+ private final boolean debug;
+
+ /**
+ * Creates a new Looking Glass Client for a Libvirt virtual machine running on a Libvirt
+ * hypervisor.
+ *
+ * @param machine virtual machine to display.
+ * @param hypervisor remote (hypervisor) endpoint for the viewer to connect to.
+ */
+ public ViewerLookingGlassClient( LibvirtVirtualMachine machine, LibvirtHypervisor hypervisor )
+ {
+ this( machine, hypervisor, false );
+ }
+
+ /**
+ * Creates a new Looking Glass Client for a Libvirt virtual machine running on a Libvirt
+ * hypervisor.
+ *
+ * @param machine virtual machine to display.
+ * @param hypervisor remote (hypervisor) endpoint for the viewer to connect to.
+ * @param debug state whether showing debug information during virtual machine rendering or not.
+ */
+ public ViewerLookingGlassClient( LibvirtVirtualMachine machine, LibvirtHypervisor hypervisor, boolean debug )
+ {
+ super( ViewerLookingGlassClient.NAME, ViewerLookingGlassClient.NUM_SUPPORTED_DISPLAYS, machine, hypervisor );
+
+ this.debug = debug;
+ }
+
+ /**
+ * Returns the state whether showing debug information during virtual machine rendering or not.
+ *
+ * @return state whether showing debug information during virtual machine rendering or not.
+ */
+ public boolean isDebugEnabled()
+ {
+ return this.debug;
+ }
+
+ @Override
+ public Version getVersion() throws ViewerException
+ {
+ return null;
+ }
+
+ @Override
+ public void render() throws ViewerException
+ {
+ // execute viewer process with arguments:
+ // in non-debug mode:
+ // "looking-glass-client app:shmFile=<SHARED-MEM-FILE> win:fullScreen=yes spice:enable=yes win:alerts=no"
+ // in debug mode:
+ // "looking-glass-client app:shmFile=<SHARED-MEM-FILE> win:fullScreen=yes spice:enable=yes win:alerts=yes win:showFPS=yes"
+ final String[] viewerParameters;
+ if ( this.isDebugEnabled() ) {
+ viewerParameters = new String[] {
+ "app:shmFile=" + ViewerLookingGlassClient.SHARED_MEMORY_FILENAME,
+ "win:fullScreen=yes",
+ "spice:enable=yes",
+ "win:alerts=no" };
+ } else {
+ viewerParameters = new String[] {
+ "app:shmFile=" + ViewerLookingGlassClient.SHARED_MEMORY_FILENAME,
+ "win:fullScreen=yes",
+ "spice:enable=yes",
+ "win:alerts=yes",
+ "win:showFPS=yes" };
+ }
+
+ ViewerUtils.executeViewer( ViewerLookingGlassClient.NAME, viewerParameters );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerUtils.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerUtils.java
new file mode 100644
index 00000000..1ed5947a
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerUtils.java
@@ -0,0 +1,65 @@
+package org.openslx.runvirt.viewer;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.commons.exec.CommandLine;
+import org.apache.commons.exec.DefaultExecutor;
+import org.apache.commons.exec.PumpStreamHandler;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.output.ByteArrayOutputStream;
+
+/**
+ * Utils for viewing displays of virtual machines.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class ViewerUtils
+{
+ /**
+ * Synchronously executes a viewer program specified by a command line call.
+ * <p>
+ * The command line call of the viewer program consists of the program name and an optional list
+ * of submitted command line arguments for the viewer program. The result of the executed viewer
+ * program from the standard output is returned after the program has exited.
+ *
+ * @param viewerProgram name of the viewer program.
+ * @param viewerArguments optional command line arguments for the viewer program.
+ * @return result of the executed viewer program from the standard output.
+ * @throws ViewerException failed to execute the viewer program.
+ */
+ @SuppressWarnings( "deprecation" )
+ public static String executeViewer( String viewerProgram, String[] viewerArguments ) throws ViewerException
+ {
+ final CommandLine viewerCommandLine = new CommandLine( viewerProgram );
+ final DefaultExecutor viewerExecutor = new DefaultExecutor();
+
+ // prepare viewer command to execute
+ viewerCommandLine.addArguments( viewerArguments );
+
+ // set up temporary working directory for the viewer process
+ viewerExecutor.setWorkingDirectory( FileUtils.getTempDirectory() );
+
+ // set expected exit value of the viewer process indicating a successful operation
+ viewerExecutor.setExitValue( 0 );
+
+ // set up output stream handler to retrieve the content from the viewer's standard output
+ final ByteArrayOutputStream viewerOutputStream = new ByteArrayOutputStream();
+ final PumpStreamHandler viewerOutputStreamHandler = new PumpStreamHandler( viewerOutputStream );
+ viewerExecutor.setStreamHandler( viewerOutputStreamHandler );
+
+ // execute the viewer command as blocking process
+ try {
+ viewerExecutor.execute( viewerCommandLine );
+ } catch ( IOException e ) {
+ throw new ViewerException( "Failed to execute '" + viewerProgram + "': " + e.getLocalizedMessage() );
+ }
+
+ final String viewerOuput = viewerOutputStream.toString( StandardCharsets.UTF_8 );
+ IOUtils.closeQuietly( viewerOutputStream );
+
+ return viewerOuput;
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerVirtManager.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerVirtManager.java
new file mode 100644
index 00000000..1848d975
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerVirtManager.java
@@ -0,0 +1,75 @@
+package org.openslx.runvirt.viewer;
+
+import org.openslx.runvirt.virtualization.LibvirtHypervisor;
+import org.openslx.runvirt.virtualization.LibvirtHypervisorException;
+import org.openslx.runvirt.virtualization.LibvirtVirtualMachine;
+import org.openslx.virtualization.Version;
+
+/**
+ * Virtual Machine Manager (virt-manager) to control and view a display of a virtual machine.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class ViewerVirtManager extends Viewer
+{
+ /**
+ * Name of the Virtual Machine Manager program.
+ */
+ private final static String NAME = "virt-manager";
+
+ /**
+ * Maximum number of supported displays by the Virtual Machine Manager.
+ */
+ private final static int NUM_SUPPORTED_DISPLAYS = 1;
+
+ /**
+ * Creates a new Virtual Machine Manager for a virtual machine running on a hypervisor.
+ *
+ * @param machine virtual machine to display.
+ * @param hypervisor remote (hypervisor) endpoint for the viewer to connect to.
+ */
+ public ViewerVirtManager( LibvirtVirtualMachine machine, LibvirtHypervisor hypervisor )
+ {
+ super( ViewerVirtManager.NAME, ViewerVirtManager.NUM_SUPPORTED_DISPLAYS, machine, hypervisor );
+ }
+
+ @Override
+ public Version getVersion() throws ViewerException
+ {
+ // execute viewer process with arguments:
+ // "virt-manager --version"
+ final String versionOutput = ViewerUtils.executeViewer( ViewerVirtManager.NAME,
+ new String[] { "--version" } );
+
+ return Version.valueOf( versionOutput );
+ }
+
+ @Override
+ public void render() throws ViewerException
+ {
+ String connectionUri = null;
+ String machineUuid = null;
+
+ // get URI of the hypervisor connection and UUID of the machine
+ try {
+ connectionUri = this.getHypervisor().getConnectionUri();
+ machineUuid = this.getMachine().getConfiguration().getUuid();
+ } catch ( LibvirtHypervisorException e ) {
+ throw new ViewerException(
+ "Failed to retrieve the URI of the hypervisor backend or the UUID of the machine to display: "
+ + e.getLocalizedMessage() );
+ }
+
+ // check if URI of the hypervisor connection and UUID of the machine is specified, otherwise abort
+ if ( connectionUri == null || connectionUri.isEmpty() || machineUuid == null || machineUuid.isEmpty() ) {
+ throw new ViewerException(
+ "The URI of the hypervisor backend or the UUID of the machine to display is missing!" );
+ }
+
+ // execute viewer process with arguments:
+ // "virt-viewer --connect=<URI> --show-domain-console <DOMAIN-UUID>"
+ ViewerUtils.executeViewer( ViewerVirtManager.NAME,
+ new String[] { "--connect=" + connectionUri, "--show-domain-console", machineUuid } );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerVirtViewer.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerVirtViewer.java
new file mode 100644
index 00000000..8f6e9481
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/viewer/ViewerVirtViewer.java
@@ -0,0 +1,97 @@
+package org.openslx.runvirt.viewer;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.openslx.runvirt.virtualization.LibvirtHypervisor;
+import org.openslx.runvirt.virtualization.LibvirtHypervisorException;
+import org.openslx.runvirt.virtualization.LibvirtVirtualMachine;
+import org.openslx.virtualization.Version;
+
+/**
+ * Virtual Viewer (virt-viewer) to view one or several displays of a virtual machine.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class ViewerVirtViewer extends Viewer
+{
+ /**
+ * Name of the Virtual Machine Manager program.
+ */
+ private final static String NAME = "virt-viewer";
+
+ /**
+ * Maximum number of supported displays by the Virtual Viewer.
+ */
+ private final static int NUM_SUPPORTED_DISPLAYS = Integer.MAX_VALUE;
+
+ /**
+ * Creates a new Virtual Viewer for a Libvirt virtual machine running on a Libvirt hypervisor.
+ *
+ * @param machine virtual machine to display.
+ * @param hypervisor remote (hypervisor) endpoint for the viewer to connect to.
+ */
+ public ViewerVirtViewer( LibvirtVirtualMachine machine, LibvirtHypervisor hypervisor )
+ {
+ super( ViewerVirtViewer.NAME, ViewerVirtViewer.NUM_SUPPORTED_DISPLAYS, machine, hypervisor );
+ }
+
+ @Override
+ public Version getVersion() throws ViewerException
+ {
+ final Version version;
+
+ // execute viewer process with arguments:
+ // "virt-viewer --version"
+ final String versionOutput = ViewerUtils.executeViewer( ViewerVirtViewer.NAME,
+ new String[] { "--version" } );
+
+ if ( versionOutput == null ) {
+ version = null;
+ } else {
+ // parse version from the viewer's process output
+ final Pattern viewerVersionPattern = Pattern.compile( "(\\d+).(\\d+)" );
+ final Matcher viewerVersionMatcher = viewerVersionPattern.matcher( versionOutput );
+
+ // check if version pattern was found
+ if ( viewerVersionMatcher.find() ) {
+ final short major = Short.valueOf( viewerVersionMatcher.group( 1 ) );
+ final short minor = Short.valueOf( viewerVersionMatcher.group( 2 ) );
+ version = new Version( major, minor );
+ } else {
+ version = null;
+ }
+ }
+
+ return version;
+ }
+
+ @Override
+ public void render() throws ViewerException
+ {
+ String connectionUri = null;
+ String machineUuid = null;
+
+ // get URI of the hypervisor connection and UUID of the machine
+ try {
+ connectionUri = this.getHypervisor().getConnectionUri();
+ machineUuid = this.getMachine().getConfiguration().getUuid();
+ } catch ( LibvirtHypervisorException e ) {
+ throw new ViewerException(
+ "Failed to retrieve the URI of the hypervisor backend or the UUID of the machine to display: "
+ + e.getLocalizedMessage() );
+ }
+
+ // check if URI of the hypervisor connection and UUID of the machine is specified, otherwise abort
+ if ( connectionUri == null || connectionUri.isEmpty() || machineUuid == null || machineUuid.isEmpty() ) {
+ throw new ViewerException(
+ "The URI of the hypervisor backend or the UUID of the machine to display is missing!" );
+ }
+
+ // execute viewer process with arguments:
+ // "virt-viewer --full-screen --reconnect --wait --attach --connect=<URI> --domain-name -- <DOMAIN-UUID>"
+ ViewerUtils.executeViewer( ViewerVirtViewer.NAME, new String[] { "--full-screen", "--reconnect", "--wait",
+ "--attach", "--connect=" + connectionUri, "--uuid", "--", machineUuid } );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/virtualization/LibvirtHypervisor.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/virtualization/LibvirtHypervisor.java
new file mode 100644
index 00000000..757fc706
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/virtualization/LibvirtHypervisor.java
@@ -0,0 +1,209 @@
+package org.openslx.runvirt.virtualization;
+
+import java.io.Closeable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.libvirt.Connect;
+import org.libvirt.LibvirtException;
+import org.openslx.libvirt.capabilities.Capabilities;
+import org.openslx.libvirt.xml.LibvirtXmlDocumentException;
+import org.openslx.libvirt.xml.LibvirtXmlSerializationException;
+import org.openslx.libvirt.xml.LibvirtXmlValidationException;
+import org.openslx.virtualization.Version;
+
+/**
+ * Representation of a Libvirt hypervisor backend (e.g. QEMU or VMware).
+ * <p>
+ * The representation allows to connect to a running Libvirt service and query the host system's
+ * capabilities or manage virtual machines.
+ *
+ * @implNote This class is the abstract representation to implement various Libvirt hypervisor
+ * backends using inheritance.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public abstract class LibvirtHypervisor implements Closeable
+{
+ /**
+ * Connection to a Libvirt hypervisor backend.
+ */
+ protected Connect hypervisor = null;
+
+ /**
+ * List of registered machines on the Libvirt hypervisor backend.
+ */
+ private List<LibvirtVirtualMachine> machines;
+
+ /**
+ * Creates a new Libvirt hypervisor backend specified by an URI and connects to the specified
+ * backend.
+ *
+ * @param connectionUri URI of a specific Libvirt hypervisor backend.
+ * @throws LibvirtHypervisorException failed to connect to the specified Libvirt hypervisor
+ * backend.
+ */
+ public LibvirtHypervisor( String connectionUri ) throws LibvirtHypervisorException
+ {
+ this.connect( connectionUri );
+ this.machines = new ArrayList<LibvirtVirtualMachine>();
+ }
+
+ /**
+ * Connects to the Libvirt hypervisor backend specified by an URI.
+ *
+ * @param connectionUri URI of a specific Libvirt hypervisor backend.
+ * @throws LibvirtHypervisorException failed to connect to the specified Libvirt hypervisor
+ * backend.
+ */
+ protected void connect( String connectionUri ) throws LibvirtHypervisorException
+ {
+ try {
+ this.hypervisor = new Connect( connectionUri );
+ } catch ( LibvirtException e ) {
+ throw new LibvirtHypervisorException( e.getLocalizedMessage() );
+ }
+ }
+
+ /**
+ * Returns the URI of the connection to the Libvirt hypervisor backend.
+ *
+ * @return URI of the connection to the hypervisor.
+ * @throws LibvirtHypervisorException failed to return the connection URI of the Libvirt
+ * hypervisor backend.
+ */
+ public String getConnectionUri() throws LibvirtHypervisorException
+ {
+ String connectionUri = null;
+
+ try {
+ connectionUri = this.hypervisor.getURI();
+ } catch ( LibvirtException e ) {
+ throw new LibvirtHypervisorException( e.getLocalizedMessage() );
+ }
+
+ return connectionUri;
+ }
+
+ /**
+ * Returns the queried Libvirt hypervisor's host system capabilities.
+ *
+ * @return queried Libvirt hypervisor's host system capabilities.
+ * @throws LibvirtHypervisorException failed to query and return the Libvirt hypervisor's host
+ * system capabilities.
+ */
+ public Capabilities getCapabilites() throws LibvirtHypervisorException
+ {
+ Capabilities hypervisorCapabilities = null;
+
+ try {
+ final String hypervisorCapabilitiesString = this.hypervisor.getCapabilities();
+ hypervisorCapabilities = new Capabilities( hypervisorCapabilitiesString );
+ } catch ( LibvirtException | LibvirtXmlDocumentException | LibvirtXmlSerializationException
+ | LibvirtXmlValidationException e ) {
+ throw new LibvirtHypervisorException( e.getLocalizedMessage() );
+ }
+
+ return hypervisorCapabilities;
+ }
+
+ /**
+ * Returns the version of the Libvirt hypervisor backend.
+ *
+ * @return version of the Libvirt hypervisor backend.
+ * @throws LibvirtHypervisorException failed to get the version of the Libvirt hypervisor
+ * backend.
+ */
+ public Version getVersion() throws LibvirtHypervisorException
+ {
+ long hypervisorVersionRaw = 0;
+ Version hypervisorVersion = null;
+
+ try {
+ hypervisorVersionRaw = this.hypervisor.getVersion();
+ } catch ( LibvirtException e ) {
+ throw new LibvirtHypervisorException( e.getLocalizedMessage() );
+ }
+
+ if ( hypervisorVersionRaw > 0 ) {
+ final short major = Long.valueOf( hypervisorVersionRaw / Long.valueOf( 1000000 ) ).shortValue();
+ hypervisorVersionRaw %= Long.valueOf( 1000000 );
+ final short minor = Long.valueOf( hypervisorVersionRaw / Long.valueOf( 1000 ) ).shortValue();
+ hypervisorVersion = new Version( major, minor );
+ }
+
+ return hypervisorVersion;
+ }
+
+ /**
+ * Register a virtual machine by the Libvirt hypervisor based on a virtualization configuration.
+ *
+ * @param vmConfiguration virtualization configuration for the virtual machine.
+ * @return instance of the registered and defined virtual machine.
+ * @throws LibvirtHypervisorException failed to register and define virtual machine.
+ */
+ public LibvirtVirtualMachine registerVm( org.openslx.libvirt.domain.Domain vmConfiguration )
+ throws LibvirtHypervisorException
+ {
+ final String xmlVmConfiguration = vmConfiguration.toString();
+ org.libvirt.Domain internalConfiguration = null;
+
+ try {
+ internalConfiguration = this.hypervisor.domainDefineXML( xmlVmConfiguration );
+ } catch ( LibvirtException e ) {
+ throw new LibvirtHypervisorException( e.getLocalizedMessage() );
+ }
+
+ final LibvirtVirtualMachine vm = new LibvirtVirtualMachine( internalConfiguration, vmConfiguration );
+ this.machines.add( vm );
+
+ return vm;
+ }
+
+ /**
+ * Deregisters an already registered virtual machine by the Libvirt hypervisor.
+ *
+ * @param vm virtual machine that should be deregistered
+ * @throws LibvirtHypervisorException failed to deregister virtual machine by the Libvirt
+ * hypervisor.
+ * @throws LibvirtVirtualMachineException failed to check and stop the virtual machine.
+ */
+ public void deregisterVm( LibvirtVirtualMachine vm )
+ throws LibvirtHypervisorException, LibvirtVirtualMachineException
+ {
+ // stop virtual machine if machine is running
+ if ( vm.isRunning() ) {
+ vm.stop();
+ }
+
+ // deregister and remove virtual machine from hypervisor
+ try {
+ vm.getLibvirtDomain().undefine();
+ } catch ( LibvirtException e ) {
+ throw new LibvirtHypervisorException( e.getLocalizedMessage() );
+ }
+
+ this.machines.remove( vm );
+ }
+
+ @Override
+ public void close()
+ {
+ // deregister all VMs defined on the hypervisor
+ for ( LibvirtVirtualMachine vm : this.machines ) {
+ try {
+ this.deregisterVm( vm );
+ } catch ( LibvirtHypervisorException | LibvirtVirtualMachineException e ) {
+ e.printStackTrace();
+ }
+ }
+
+ // close connection to the hypervisor
+ try {
+ this.hypervisor.close();
+ } catch ( LibvirtException e ) {
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/virtualization/LibvirtHypervisorException.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/virtualization/LibvirtHypervisorException.java
new file mode 100644
index 00000000..64ae6b20
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/virtualization/LibvirtHypervisorException.java
@@ -0,0 +1,25 @@
+package org.openslx.runvirt.virtualization;
+
+/**
+ * An exception of a Libvirt hypervisor error during acquiring the hypervisor's functionality.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class LibvirtHypervisorException extends Exception
+{
+ /**
+ * Version for serialization.
+ */
+ private static final long serialVersionUID = -3631452625806770209L;
+
+ /**
+ * Creates a Libvirt hypervisor exception including an error message.
+ *
+ * @param errorMsg message to describe a specific Libvirt hypervisor error.
+ */
+ LibvirtHypervisorException( String errorMsg )
+ {
+ super( errorMsg );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/virtualization/LibvirtVirtualMachine.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/virtualization/LibvirtVirtualMachine.java
new file mode 100644
index 00000000..3bcec2f8
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/virtualization/LibvirtVirtualMachine.java
@@ -0,0 +1,150 @@
+package org.openslx.runvirt.virtualization;
+
+import org.libvirt.Domain;
+import org.libvirt.LibvirtException;
+
+/**
+ * Representation of a Libvirt virtual machine.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class LibvirtVirtualMachine
+{
+ /**
+ * Internal Libvirt virtualization configuration of the virtual machine.
+ */
+ private Domain domain;
+
+ /**
+ * Libvirt virtualization configuration of the virtual machine.
+ */
+ private org.openslx.libvirt.domain.Domain configuration;
+
+ /**
+ * Creates a new Libvirt virtual machine specified by a virtualization configuration.
+ *
+ * @param internalConfiguration internal Libvirt virtualization configuration to specify the
+ * Libvirt virtual machine.
+ * @param configuration Libvirt virtualization configuration to specify the Libvirt virtual
+ * machine.
+ */
+ LibvirtVirtualMachine( Domain internalConfiguration, org.openslx.libvirt.domain.Domain configuration )
+ {
+ this.domain = internalConfiguration;
+ this.configuration = configuration;
+ }
+
+ /**
+ * Returns the internal Libvirt virtualization configuration of the Libvirt virtual machine.
+ *
+ * @return internal Libvirt virtualization configuration of the Libvirt virtual machine.
+ */
+ Domain getLibvirtDomain()
+ {
+ return this.domain;
+ }
+
+ /**
+ * Returns the Libvirt virtualization configuration of the Libvirt virtual machine.
+ *
+ * @return Libvirt virtualization configuration of the Libvirt virtual machine.
+ */
+ public org.openslx.libvirt.domain.Domain getConfiguration()
+ {
+ return this.configuration;
+ }
+
+ /**
+ * Checks if the Libvirt virtual machine is running.
+ *
+ * @return state of the Libvirt virtual machine whether it is running or not.
+ * @throws LibvirtVirtualMachineException failed to check if Libvirt machine is running or not.
+ */
+ public boolean isRunning() throws LibvirtVirtualMachineException
+ {
+ int state = 0;
+
+ try {
+ state = this.domain.isActive();
+ } catch ( LibvirtException e ) {
+ throw new LibvirtVirtualMachineException( e.getLocalizedMessage() );
+ }
+
+ return ( state == 0 ) ? false : true;
+ }
+
+ /**
+ * Starts the Libvirt virtual machine.
+ *
+ * @throws LibvirtVirtualMachineException failed to start the Libvirt virtual machine.
+ */
+ public void start() throws LibvirtVirtualMachineException
+ {
+ if ( !this.isRunning() ) {
+ try {
+ this.domain.create();
+ } catch ( LibvirtException e ) {
+ throw new LibvirtVirtualMachineException( e.getLocalizedMessage() );
+ }
+ }
+ }
+
+ /**
+ * Stops the Libvirt virtual machine.
+ *
+ * @throws LibvirtVirtualMachineException failed to stop the Libvirt virtual machine.
+ */
+ public void stop() throws LibvirtVirtualMachineException
+ {
+ if ( this.isRunning() ) {
+ try {
+ this.domain.shutdown();
+ } catch ( LibvirtException e ) {
+ throw new LibvirtVirtualMachineException( e.getLocalizedMessage() );
+ }
+ }
+ }
+
+ /**
+ * Suspends the Libvirt virtual machine.
+ *
+ * @throws LibvirtVirtualMachineException failed to suspend the Libvirt virtual machine.
+ */
+ public void suspend() throws LibvirtVirtualMachineException
+ {
+ try {
+ this.domain.suspend();
+ } catch ( LibvirtException e ) {
+ throw new LibvirtVirtualMachineException( e.getLocalizedMessage() );
+ }
+ }
+
+ /**
+ * Resumes the Libvirt virtual machine.
+ *
+ * @throws LibvirtVirtualMachineException faild to resume the Libvirt virtual machine.
+ */
+ public void resume() throws LibvirtVirtualMachineException
+ {
+ try {
+ this.domain.resume();
+ } catch ( LibvirtException e ) {
+ throw new LibvirtVirtualMachineException( e.getLocalizedMessage() );
+ }
+ }
+
+ /**
+ * Reboot the Libvirt virtual machine.
+ *
+ * @throws LibvirtVirtualMachineException failed to reboot the Libvirt virtual machine.
+ */
+ public void reboot() throws LibvirtVirtualMachineException
+ {
+ try {
+ this.domain.reboot( 0 );
+ } catch ( LibvirtException e ) {
+ throw new LibvirtVirtualMachineException( e.getLocalizedMessage() );
+ }
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/virtualization/LibvirtVirtualMachineException.java b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/virtualization/LibvirtVirtualMachineException.java
new file mode 100644
index 00000000..dd490be3
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/main/java/org/openslx/runvirt/virtualization/LibvirtVirtualMachineException.java
@@ -0,0 +1,25 @@
+package org.openslx.runvirt.virtualization;
+
+/**
+ * An exception of a Libvirt virtual machine error during controlling the virtual machine.
+ *
+ * @author Manuel Bentele
+ * @version 1.0
+ */
+public class LibvirtVirtualMachineException extends Exception
+{
+ /**
+ * Version for serialization.
+ */
+ private static final long serialVersionUID = -5371327391243047616L;
+
+ /**
+ * Creates a Libvirt virtual machine exception including an error message.
+ *
+ * @param errorMsg message to describe a specific Libvirt virtual machine error.
+ */
+ public LibvirtVirtualMachineException( String errorMsg )
+ {
+ super( errorMsg );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/AppTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/AppTest.java
new file mode 100644
index 00000000..d0eef82a
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/AppTest.java
@@ -0,0 +1,202 @@
+package org.openslx.runvirt.plugin.qemu;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs.CmdLnOption;
+
+import com.ginsberg.junit.exit.ExpectSystemExit;
+import com.ginsberg.junit.exit.ExpectSystemExitWithStatus;
+
+public class AppTest
+{
+ @BeforeAll
+ private static void setUp()
+ {
+ // disable logging with log4j
+ LogManager.getRootLogger().setLevel( Level.OFF );
+ }
+
+ @Nested
+ public class CmdLnTest
+ {
+ private final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ private final ByteArrayOutputStream err = new ByteArrayOutputStream();
+
+ private void setUp()
+ {
+ // redirect output and error stream content
+ System.setOut( new PrintStream( this.out ) );
+ System.setErr( new PrintStream( this.err ) );
+ }
+
+ @Test
+ @DisplayName( "Test ouput of correct 'help' command line option (short version)" )
+ @ExpectSystemExit
+ public void testCmdLnOptionHelpShortCorrect()
+ {
+ String[] argsShortHelpOptionCorrect = { "-" + CmdLnOption.HELP.getShortOption() };
+
+ this.setUp();
+
+ // test correct usage of the short help option
+ try {
+ App.main( argsShortHelpOptionCorrect );
+ } catch ( Exception e ) {
+ // do nothing and check output afterwards
+ }
+
+ final String shortHelpOptionCorrectOutput = new String( this.out.toString() );
+ final String shortHelpOptionCorrectErrOutput = new String( this.err.toString() );
+ assertTrue( shortHelpOptionCorrectOutput.contains( "usage" ) );
+ assertTrue( shortHelpOptionCorrectOutput.contains( App.APP_NAME ) );
+ assertTrue( shortHelpOptionCorrectOutput.contains( App.APP_INFO ) );
+ assertTrue( shortHelpOptionCorrectOutput.contains( App.APP_DESC ) );
+
+ // test that no error was logged and output is available
+ assertEquals( 2503, shortHelpOptionCorrectOutput.length() );
+ assertEquals( 0, shortHelpOptionCorrectErrOutput.length() );
+ }
+
+ @Test
+ @DisplayName( "Test ouput of correct 'help' command line option (long version)" )
+ @ExpectSystemExit
+ public void testCmdLnOptionHelpLongCorrect()
+ {
+ String[] argsLongHelpOptionCorrect = { "--" + CmdLnOption.HELP.getLongOption() };
+
+ this.setUp();
+
+ // test correct usage of the long help option
+ try {
+ App.main( argsLongHelpOptionCorrect );
+ } catch ( Exception e ) {
+ // do nothing and check output afterwards
+ }
+
+ final String longHelpOptionCorrectOutput = this.out.toString();
+ final String longHelpOptionCorrectErrOutput = this.err.toString();
+ assertTrue( longHelpOptionCorrectOutput.contains( "usage" ) );
+ assertTrue( longHelpOptionCorrectOutput.contains( App.APP_NAME ) );
+ assertTrue( longHelpOptionCorrectOutput.contains( App.APP_INFO ) );
+ assertTrue( longHelpOptionCorrectOutput.contains( App.APP_DESC ) );
+
+ // test that no error was logged and output is available
+ assertEquals( 2503, longHelpOptionCorrectOutput.length() );
+ assertEquals( 0, longHelpOptionCorrectErrOutput.length() );
+ }
+
+ @Test
+ @DisplayName( "Test ouput of incorrect 'help' command line option (short version)" )
+ @ExpectSystemExit
+ public void testCmdLnOptionHelpShortIncorrect()
+ {
+ String[] argsShortHelpOptionIncorrect = { "---" + CmdLnOption.HELP.getShortOption() };
+
+ this.setUp();
+
+ // test incorrect usage of the short help option
+ try {
+ App.main( argsShortHelpOptionIncorrect );
+ } catch ( Exception e ) {
+ // do nothing and check output afterwards
+ }
+
+ final String shortHelpOptionIncorrectOutput = this.out.toString();
+ final String shortHelpOptionIncorrectErrOutput = this.err.toString();
+ assertTrue( shortHelpOptionIncorrectOutput.contains( "usage" ) );
+ assertTrue( shortHelpOptionIncorrectOutput.contains( App.APP_NAME ) );
+ assertTrue( shortHelpOptionIncorrectOutput.contains( App.APP_INFO ) );
+ assertTrue( shortHelpOptionIncorrectOutput.contains( App.APP_DESC ) );
+
+ // test that error was logged and output is available
+ assertEquals( 2503, shortHelpOptionIncorrectOutput.length() );
+ assertEquals( 0, shortHelpOptionIncorrectErrOutput.length() );
+ }
+
+ @Test
+ @DisplayName( "Test ouput of incorrect 'help' command line option (long version)" )
+ @ExpectSystemExit
+ public void testCmdLnOptionHelpLongIncorrect()
+ {
+ String[] argsLongHelpOptionIncorrect = { "---" + CmdLnOption.HELP.getLongOption() };
+
+ this.setUp();
+
+ // test incorrect usage of the long help option
+ try {
+ App.main( argsLongHelpOptionIncorrect );
+ } catch ( Exception e ) {
+ // do nothing and check output afterwards
+ }
+
+ final String longHelpOptionIncorrectOutput = this.out.toString();
+ final String longHelpOptionIncorrectErrOutput = this.err.toString();
+ assertTrue( longHelpOptionIncorrectOutput.contains( "usage" ) );
+ assertTrue( longHelpOptionIncorrectOutput.contains( App.APP_NAME ) );
+ assertTrue( longHelpOptionIncorrectOutput.contains( App.APP_INFO ) );
+ assertTrue( longHelpOptionIncorrectOutput.contains( App.APP_DESC ) );
+
+ // test that error was logged and output is available
+ assertEquals( 2503, longHelpOptionIncorrectOutput.length() );
+ assertEquals( 0, longHelpOptionIncorrectErrOutput.length() );
+ }
+
+ @Test
+ @DisplayName( "Test exit status of application invoked with correct 'help' command line option (short version)" )
+ @ExpectSystemExitWithStatus( 0 )
+ public void testCmdLnOptionHelpShortCorrectExit()
+ {
+ String[] argsShortHelpOptionCorrect = { "-" + CmdLnOption.HELP.getShortOption() };
+
+ this.setUp();
+
+ App.main( argsShortHelpOptionCorrect );
+ }
+
+ @Test
+ @DisplayName( "Test exit status of application invoked with correct 'help' command line option (long version)" )
+ @ExpectSystemExitWithStatus( 0 )
+ public void testCmdLnOptionHelpLongCorrectExit()
+ {
+ String[] argsLongHelpOptionCorrect = { "--" + CmdLnOption.HELP.getLongOption() };
+
+ this.setUp();
+
+ App.main( argsLongHelpOptionCorrect );
+ }
+
+ @Test
+ @DisplayName( "Test exit status of application invoked with incorrect 'help' command line option (short version)" )
+ @ExpectSystemExitWithStatus( 1 )
+ public void testCmdLnOptionHelpShortIncorrectExit()
+ {
+ String[] argsShortHelpOptionCorrect = { "---" + CmdLnOption.HELP.getShortOption() };
+
+ this.setUp();
+
+ App.main( argsShortHelpOptionCorrect );
+ }
+
+ @Test
+ @DisplayName( "Test exit status of application invoked with incorrect 'help' command line option (long version)" )
+ @ExpectSystemExitWithStatus( 1 )
+ public void testCmdLnOptionHelpLongIncorrectExit()
+ {
+ String[] argsLongHelpOptionCorrect = { "---" + CmdLnOption.HELP.getLongOption() };
+
+ this.setUp();
+
+ App.main( argsLongHelpOptionCorrect );
+ }
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgsTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgsTest.java
new file mode 100644
index 00000000..77522bd6
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/cmdln/CommandLineArgsTest.java
@@ -0,0 +1,752 @@
+package org.openslx.runvirt.plugin.qemu.cmdln;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.File;
+import java.util.List;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs.CmdLnOption;
+
+public class CommandLineArgsTest
+{
+ // @formatter:off
+ public static final String CMDLN_PREFIX_OPTION_SHORT = "-";
+ public static final String CMDLN_PREFIX_OPTION_LONG = "--";
+
+ private static final String CMDLN_TEST_DEBUG_OFF = "false";
+ private static final String CMDLN_TEST_DEBUG_ON = "true";
+ private static final String CMDLN_TEST_NAME = "test";
+ private static final String CMDLN_TEST_FILENAME = System.getProperty( "user.dir" ) + File.separator + CMDLN_TEST_NAME;
+ private static final String CMDLN_TEST_UUID = "c9570672-cbae-4cbd-801a-881b281b8d79";
+ private static final String CMDLN_TEST_OS = "Windows 10 (x64)";
+ private static final int CMDLN_TEST_NCPUS = 4;
+ private static final String CMDLN_TEST_MEM = "1024";
+ private static final String CMDLN_TEST_PARPORT = "/dev/parport0";
+ private static final String CMDLN_TEST_SERPORT = "/dev/ttyS0";
+ private static final String CMDLN_TEST_MAC = "02:42:8e:77:1b:e6";
+ private static final String CMDLN_TEST_NVGPU_DESC = "10de:0ff9";
+ private static final String CMDLN_TEST_NVGPU_ADDR = "0000:00:01.0";
+ // @formatter:on
+
+ @Test
+ @DisplayName( "Test the parsing of wrong command line options" )
+ public void testCmdlnOptionsIncorrect()
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + "hello",
+ "world argument",
+ CMDLN_PREFIX_OPTION_LONG + "info",
+ "description"
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs();
+
+ assertThrows( CommandLineArgsException.class, () -> cmdLn.parseCmdLnArgs( args ) );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the help command line option (short version)" )
+ public void testCmdlnOptionHelpShort() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.HELP.getShortOption()
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertTrue( cmdLn.isHelpAquired() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the help command line option (long version)" )
+ public void testCmdlnOptionHelpLong() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.HELP.getLongOption()
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertTrue( cmdLn.isHelpAquired() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the enabled debug command line option (short version)" )
+ public void testCmdlnOptionDebugEnabledShort() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.DEBUG.getShortOption(),
+ CMDLN_TEST_DEBUG_ON
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertTrue( cmdLn.isDebugEnabled() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the enabled debug command line option (long version)" )
+ public void testCmdlnOptionDebugEnabledLong() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.DEBUG.getLongOption(),
+ CMDLN_TEST_DEBUG_ON
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertTrue( cmdLn.isDebugEnabled() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the disabled debug command line option (short version)" )
+ public void testCmdlnOptionDebugDisabledShort() throws CommandLineArgsException
+ {
+ final String[] argsDebugOff = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.DEBUG.getShortOption(),
+ CMDLN_TEST_DEBUG_OFF
+ };
+
+ final String[] argsDebugMissing = {};
+
+ CommandLineArgs cmdLnDebugOff = new CommandLineArgs( argsDebugOff );
+ CommandLineArgs cmdLnDebugMissing = new CommandLineArgs( argsDebugMissing );
+
+ assertFalse( cmdLnDebugOff.isDebugEnabled() );
+ assertFalse( cmdLnDebugMissing.isDebugEnabled() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the disabled debug command line option (long version)" )
+ public void testCmdlnOptionDebugDisabledLong() throws CommandLineArgsException
+ {
+ final String[] argsDebugOff = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.DEBUG.getLongOption(),
+ CMDLN_TEST_DEBUG_OFF
+ };
+
+ final String[] argsDebugMissing = {};
+
+ CommandLineArgs cmdLnDebugOff = new CommandLineArgs( argsDebugOff );
+ CommandLineArgs cmdLnDebugMissing = new CommandLineArgs( argsDebugMissing );
+
+ assertFalse( cmdLnDebugOff.isDebugEnabled() );
+ assertFalse( cmdLnDebugMissing.isDebugEnabled() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM configuration input command line option (short version)" )
+ public void testCmdlnOptionVmCfgInpShort() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_CFGINP.getShortOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getVmCfgInpFileName() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM configuration input command line option (long version)" )
+ public void testCmdlnOptionVmCfgInpLong() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_CFGINP.getLongOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getVmCfgInpFileName() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM configuration output command line option (short version)" )
+ public void testCmdlnOptionVmCfgOutShort() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_CFGOUT.getShortOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getVmCfgOutFileName() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM configuration output command line option (long version)" )
+ public void testCmdlnOptionVmCfgOutLong() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_CFGOUT.getLongOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getVmCfgOutFileName() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM name command line option (short version)" )
+ public void testCmdlnOptionVmNameShort() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_NAME.getShortOption(),
+ CMDLN_TEST_NAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_NAME, cmdLn.getVmName() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM name command line option (long version)" )
+ public void testCmdlnOptionVmNameLong() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_NAME.getLongOption(),
+ CMDLN_TEST_NAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_NAME, cmdLn.getVmName() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM UUID command line option (short version)" )
+ public void testCmdlnOptionVmUuidShort() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_UUID.getShortOption(),
+ CMDLN_TEST_UUID
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_UUID, cmdLn.getVmUuid() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM UUID command line option (long version)" )
+ public void testCmdlnOptionVmUuidLong() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_UUID.getLongOption(),
+ CMDLN_TEST_UUID
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_UUID, cmdLn.getVmUuid() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM display name command line option (short version)" )
+ public void testCmdlnOptionVmDsplNameShort() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_DSPLNAME.getShortOption(),
+ CMDLN_TEST_NAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_NAME, cmdLn.getVmDisplayName() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM display name command line option (long version)" )
+ public void testCmdlnOptionVmDsplNameLong() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_DSPLNAME.getLongOption(),
+ CMDLN_TEST_NAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_NAME, cmdLn.getVmDisplayName() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM OS command line option (short version)" )
+ public void testCmdlnOptionVmOsShort() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_OS.getShortOption(),
+ CMDLN_TEST_OS
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_OS, cmdLn.getVmOperatingSystem() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM OS command line option (long version)" )
+ public void testCmdlnOptionVmOsLong() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_OS.getLongOption(),
+ CMDLN_TEST_OS
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_OS, cmdLn.getVmOperatingSystem() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM CPU number command line option (short version)" )
+ public void testCmdlnOptionVmNCpusShort() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_NCPUS.getShortOption(),
+ Integer.toString( CMDLN_TEST_NCPUS )
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_NCPUS, cmdLn.getVmNumCpus() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM CPU number command line option (long version)" )
+ public void testCmdlnOptionVmNCpusLong() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_NCPUS.getLongOption(),
+ Integer.toString( CMDLN_TEST_NCPUS )
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_NCPUS, cmdLn.getVmNumCpus() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM memory command line option (short version)" )
+ public void testCmdlnOptionVmMemShort() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_MEM.getShortOption(),
+ CMDLN_TEST_MEM
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_MEM, cmdLn.getVmMemory() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM memory command line option (long version)" )
+ public void testCmdlnOptionVmMemLong() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_MEM.getLongOption(),
+ CMDLN_TEST_MEM
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_MEM, cmdLn.getVmMemory() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM first HDD disk image command line option (short version)" )
+ public void testCmdlnOptionVmHdd0Short() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_HDD0.getShortOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getVmDiskFileNameHDD0() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM first HDD disk image command line option (long version)" )
+ public void testCmdlnOptionVmHdd0Long() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_HDD0.getLongOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getVmDiskFileNameHDD0() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM first floppy disk image command line option (short version)" )
+ public void testCmdlnOptionVmFloppy0Short() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_FLOPPY0.getShortOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getVmDiskFileNameFloppy0() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM first floppy disk image command line option (long version)" )
+ public void testCmdlnOptionVmFloppy0Long() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_FLOPPY0.getLongOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getVmDiskFileNameFloppy0() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM second floppy disk image command line option (short version)" )
+ public void testCmdlnOptionVmFloppy1Short() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_FLOPPY1.getShortOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getVmDiskFileNameFloppy1() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM second floppy disk image command line option (long version)" )
+ public void testCmdlnOptionVmFloppy1Long() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_FLOPPY1.getLongOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getVmDiskFileNameFloppy1() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM first CDROM disk image command line option (short version)" )
+ public void testCmdlnOptionVmCdrom0Short() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_CDROM0.getShortOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getVmDiskFileNameCdrom0() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM first CDROM disk image command line option (long version)" )
+ public void testCmdlnOptionVmCdrom0Long() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_CDROM0.getLongOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getVmDiskFileNameCdrom0() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM second CDROM disk image command line option (short version)" )
+ public void testCmdlnOptionVmCdrom1Short() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_CDROM1.getShortOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getVmDiskFileNameCdrom1() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM second CDROM disk image command line option (long version)" )
+ public void testCmdlnOptionVmCdrom1Long() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_CDROM1.getLongOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getVmDiskFileNameCdrom1() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM first parallel interface command line option (short version)" )
+ public void testCmdlnOptionVmParallel0Short() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_PARALLEL0.getShortOption(),
+ CMDLN_TEST_PARPORT
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_PARPORT, cmdLn.getVmDeviceParallel0() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM first parallel interface command line option (long version)" )
+ public void testCmdlnOptionVmParallel0Long() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_PARALLEL0.getLongOption(),
+ CMDLN_TEST_PARPORT
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_PARPORT, cmdLn.getVmDeviceParallel0() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM first serial interface command line option (short version)" )
+ public void testCmdlnOptionVmSerial0Short() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_SERIAL0.getShortOption(),
+ CMDLN_TEST_SERPORT
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_SERPORT, cmdLn.getVmDeviceSerial0() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM first serial interface command line option (long version)" )
+ public void testCmdlnOptionVmSerial0Long() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_SERIAL0.getLongOption(),
+ CMDLN_TEST_SERPORT
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_SERPORT, cmdLn.getVmDeviceSerial0() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM first network interface MAC command line option (short version)" )
+ public void testCmdlnOptionVmMac0Short() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_MAC0.getShortOption(),
+ CMDLN_TEST_MAC
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_MAC, cmdLn.getVmMacAddress0() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM first network interface MAC command line option (long version)" )
+ public void testCmdlnOptionVmMac0Long() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_MAC0.getLongOption(),
+ CMDLN_TEST_MAC
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_MAC, cmdLn.getVmMacAddress0() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM first file system source command line option (short version)" )
+ public void testCmdlnOptionVmFsSrc0Short() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_FSSRC0.getShortOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getVmFsSrc0() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM first file system source command line option (long version)" )
+ public void testCmdlnOptionVmFsSrc0Long() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_FSSRC0.getLongOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getVmFsSrc0() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM first file system target command line option (short version)" )
+ public void testCmdlnOptionVmFsTgt0Short() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_FSTGT0.getShortOption(),
+ CMDLN_TEST_NAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_NAME, cmdLn.getVmFsTgt0() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM first file system target command line option (long version)" )
+ public void testCmdlnOptionVmFsTgt0Long() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_FSTGT0.getLongOption(),
+ CMDLN_TEST_NAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_NAME, cmdLn.getVmFsTgt0() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM second file system source command line option (short version)" )
+ public void testCmdlnOptionVmFsSrc1Short() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_FSSRC1.getShortOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getVmFsSrc1() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM second file system source command line option (long version)" )
+ public void testCmdlnOptionVmFsSrc1Long() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_FSSRC1.getLongOption(),
+ CMDLN_TEST_FILENAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_FILENAME, cmdLn.getVmFsSrc1() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM second file system target command line option (short version)" )
+ public void testCmdlnOptionVmFsTgt1Short() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_FSTGT1.getShortOption(),
+ CMDLN_TEST_NAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_NAME, cmdLn.getVmFsTgt1() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of the VM second file system target command line option (long version)" )
+ public void testCmdlnOptionVmFsTgt1Long() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_FSTGT1.getLongOption(),
+ CMDLN_TEST_NAME
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ assertEquals( CMDLN_TEST_NAME, cmdLn.getVmFsTgt1() );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of NVIDIA PCI IDs command line option for the first GPU passthrough (short version)" )
+ public void testCmdlnOptionVmNvGpuIds0Short() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_SHORT + CmdLnOption.VM_NVGPUIDS0.getShortOption(),
+ CMDLN_TEST_NVGPU_DESC, CMDLN_TEST_NVGPU_ADDR
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ final List<String> nvidiaGpuIds = cmdLn.getVmNvGpuIds0();
+ assertEquals( 2, nvidiaGpuIds.size() );
+ assertEquals( CMDLN_TEST_NVGPU_DESC, nvidiaGpuIds.get( 0 ) );
+ assertEquals( CMDLN_TEST_NVGPU_ADDR, nvidiaGpuIds.get( 1 ) );
+ }
+
+ @Test
+ @DisplayName( "Test the parsing of NVIDIA PCI IDs command line option for the first GPU passthrough (long version)" )
+ public void testCmdlnOptionVmNvGpuIds0Long() throws CommandLineArgsException
+ {
+ final String[] args = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_NVGPUIDS0.getLongOption(),
+ CMDLN_TEST_NVGPU_DESC, CMDLN_TEST_NVGPU_ADDR
+ };
+
+ CommandLineArgs cmdLn = new CommandLineArgs( args );
+
+ final List<String> nvidiaGpuIds = cmdLn.getVmNvGpuIds0();
+ assertEquals( 2, nvidiaGpuIds.size() );
+ assertEquals( CMDLN_TEST_NVGPU_DESC, nvidiaGpuIds.get( 0 ) );
+ assertEquals( CMDLN_TEST_NVGPU_ADDR, nvidiaGpuIds.get( 1 ) );
+ }
+
+ @Test
+ @DisplayName( "Test whether a NVIDIA GPU passthrough is enabled" )
+ public void testIsNvidiaGpuPassthroughEnabled() throws CommandLineArgsException
+ {
+ final String[] args1 = {
+ CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_NVGPUIDS0.getLongOption(),
+ CMDLN_TEST_NVGPU_DESC, CMDLN_TEST_NVGPU_ADDR
+ };
+ final String[] args2 = {};
+
+ CommandLineArgs cmdLn1 = new CommandLineArgs( args1 );
+ CommandLineArgs cmdLn2 = new CommandLineArgs( args2 );
+
+ assertTrue( cmdLn1.isNvidiaGpuPassthroughEnabled() );
+ assertFalse( cmdLn2.isNvidiaGpuPassthroughEnabled() );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericCpuTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericCpuTest.java
new file mode 100644
index 00000000..d88857a6
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericCpuTest.java
@@ -0,0 +1,49 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.Domain.CpuCheck;
+import org.openslx.libvirt.domain.Domain.CpuMode;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+
+public class TransformationGenericCpuTest
+{
+ @Test
+ @DisplayName( "Test transformation of VM CPU configuration" )
+ public void testTransformationGenericCpu() throws TransformationException
+ {
+ final TransformationGenericCpu transformation = new TransformationGenericCpu();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getDefaultCmdLnArgs();
+
+ assertNotEquals( Integer.parseInt( TransformationTestUtils.DEFAULT_VM_NCPUS ), config.getVCpu() );
+ assertNotEquals( CpuMode.HOST_PASSTHROUGH, config.getCpuMode() );
+ assertEquals( CpuCheck.PARTIAL, config.getCpuCheck() );
+
+ transformation.transform( config, args );
+
+ assertEquals( Integer.parseInt( TransformationTestUtils.DEFAULT_VM_NCPUS ), config.getVCpu() );
+ assertEquals( CpuMode.HOST_PASSTHROUGH, config.getCpuMode() );
+ assertEquals( CpuCheck.PARTIAL, config.getCpuCheck() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+
+ @Test
+ @DisplayName( "Test transformation of VM CPU configuration with unspecified input data" )
+ public void testTransformationGenericCpuNoData() throws TransformationException
+ {
+ final TransformationGenericCpu transformation = new TransformationGenericCpu();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getEmptyCmdLnArgs();
+
+ assertThrows( TransformationException.class, () -> transformation.transform( config, args ) );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskCdromDevicesTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskCdromDevicesTest.java
new file mode 100644
index 00000000..73b37c36
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskCdromDevicesTest.java
@@ -0,0 +1,65 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+
+import java.util.ArrayList;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.Disk.StorageType;
+import org.openslx.libvirt.domain.device.DiskCdrom;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+
+public class TransformationGenericDiskCdromDevicesTest
+{
+ @Test
+ @DisplayName( "Test transformation of VM disk CDROM devices configuration with specified input data" )
+ public void testTransformationGenericDiskCdromDevices() throws TransformationException
+ {
+ final TransformationGenericDiskCdromDevices transformation = new TransformationGenericDiskCdromDevices();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getDefaultCmdLnArgs();
+
+ final ArrayList<DiskCdrom> devicesBeforeTransformation = config.getDiskCdromDevices();
+ assertEquals( 1, devicesBeforeTransformation.size() );
+ final DiskCdrom cdromDeviceBeforeTransformation = devicesBeforeTransformation.get( 0 );
+ assertEquals( StorageType.FILE, cdromDeviceBeforeTransformation.getStorageType() );
+ assertNotEquals( TransformationTestUtils.DEFAULT_VM_CDROM0, cdromDeviceBeforeTransformation.getStorageSource() );
+
+ transformation.transform( config, args );
+
+ final ArrayList<DiskCdrom> devicesAfterTransformation = config.getDiskCdromDevices();
+ assertEquals( 2, devicesAfterTransformation.size() );
+ final DiskCdrom cdromDevice1AfterTransformation = devicesAfterTransformation.get( 0 );
+ final DiskCdrom cdromDevice2AfterTransformation = devicesAfterTransformation.get( 1 );
+ assertEquals( StorageType.FILE, cdromDevice1AfterTransformation.getStorageType() );
+ assertEquals( TransformationTestUtils.DEFAULT_VM_CDROM0, cdromDevice1AfterTransformation.getStorageSource() );
+ assertEquals( StorageType.FILE, cdromDevice2AfterTransformation.getStorageType() );
+ assertEquals( TransformationTestUtils.DEFAULT_VM_CDROM1, cdromDevice2AfterTransformation.getStorageSource() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+
+ @Test
+ @DisplayName( "Test transformation of VM disk CDROM devices configuration with unspecified input data" )
+ public void testTransformationGenericDiskCdromDevicesNoData() throws TransformationException
+ {
+ final TransformationGenericDiskCdromDevices transformation = new TransformationGenericDiskCdromDevices();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getEmptyCmdLnArgs();
+
+ final ArrayList<DiskCdrom> devicesBeforeTransformation = config.getDiskCdromDevices();
+ assertEquals( 1, devicesBeforeTransformation.size() );
+
+ transformation.transform( config, args );
+
+ final ArrayList<DiskCdrom> devicesAfterTransformation = config.getDiskCdromDevices();
+ assertEquals( 0, devicesAfterTransformation.size() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskFloppyDevicesTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskFloppyDevicesTest.java
new file mode 100644
index 00000000..3969e168
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskFloppyDevicesTest.java
@@ -0,0 +1,66 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+
+import java.util.ArrayList;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.Disk.StorageType;
+import org.openslx.libvirt.domain.device.DiskFloppy;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+
+public class TransformationGenericDiskFloppyDevicesTest
+{
+ @Test
+ @DisplayName( "Test transformation of VM disk floppy devices configuration with specified input data" )
+ public void testTransformationGenericDiskFloppyDevices() throws TransformationException
+ {
+ final TransformationGenericDiskFloppyDevices transformation = new TransformationGenericDiskFloppyDevices();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getDefaultCmdLnArgs();
+
+ final ArrayList<DiskFloppy> devicesBeforeTransformation = config.getDiskFloppyDevices();
+ assertEquals( 1, devicesBeforeTransformation.size() );
+ final DiskFloppy floppyDeviceBeforeTransformation = devicesBeforeTransformation.get( 0 );
+ assertEquals( StorageType.FILE, floppyDeviceBeforeTransformation.getStorageType() );
+ assertNotEquals( TransformationTestUtils.DEFAULT_VM_FLOPPY0,
+ floppyDeviceBeforeTransformation.getStorageSource() );
+
+ transformation.transform( config, args );
+
+ final ArrayList<DiskFloppy> devicesAfterTransformation = config.getDiskFloppyDevices();
+ assertEquals( 2, devicesAfterTransformation.size() );
+ final DiskFloppy floppyDevice1AfterTransformation = devicesAfterTransformation.get( 0 );
+ final DiskFloppy floppyDevice2AfterTransformation = devicesAfterTransformation.get( 1 );
+ assertEquals( StorageType.FILE, floppyDevice1AfterTransformation.getStorageType() );
+ assertEquals( TransformationTestUtils.DEFAULT_VM_FLOPPY0, floppyDevice1AfterTransformation.getStorageSource() );
+ assertEquals( StorageType.FILE, floppyDevice2AfterTransformation.getStorageType() );
+ assertEquals( TransformationTestUtils.DEFAULT_VM_FLOPPY1, floppyDevice2AfterTransformation.getStorageSource() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+
+ @Test
+ @DisplayName( "Test transformation of VM disk floppy devices configuration with unspecified input data" )
+ public void testTransformationGenericDiskFloppyDevicesNoData() throws TransformationException
+ {
+ final TransformationGenericDiskFloppyDevices transformation = new TransformationGenericDiskFloppyDevices();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getEmptyCmdLnArgs();
+
+ final ArrayList<DiskFloppy> devicesBeforeTransformation = config.getDiskFloppyDevices();
+ assertEquals( 1, devicesBeforeTransformation.size() );
+
+ transformation.transform( config, args );
+
+ final ArrayList<DiskFloppy> devicesAfterTransformation = config.getDiskFloppyDevices();
+ assertEquals( 0, devicesAfterTransformation.size() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskStorageDevicesTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskStorageDevicesTest.java
new file mode 100644
index 00000000..8b52b90b
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericDiskStorageDevicesTest.java
@@ -0,0 +1,62 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+
+import java.util.ArrayList;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.Disk.StorageType;
+import org.openslx.libvirt.domain.device.DiskStorage;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+
+public class TransformationGenericDiskStorageDevicesTest
+{
+ @Test
+ @DisplayName( "Test transformation of VM disk storage devices configuration with specified input data" )
+ public void testTransformationGenericDiskStorageDevices() throws TransformationException
+ {
+ final TransformationGenericDiskStorageDevices transformation = new TransformationGenericDiskStorageDevices();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getDefaultCmdLnArgs();
+
+ final ArrayList<DiskStorage> devicesBeforeTransformation = config.getDiskStorageDevices();
+ assertEquals( 1, devicesBeforeTransformation.size() );
+ final DiskStorage diskDeviceBeforeTransformation = devicesBeforeTransformation.get( 0 );
+ assertNotEquals( StorageType.FILE, diskDeviceBeforeTransformation.getStorageType() );
+ assertNotEquals( TransformationTestUtils.DEFAULT_VM_HDD0, diskDeviceBeforeTransformation.getStorageSource() );
+
+ transformation.transform( config, args );
+
+ final ArrayList<DiskStorage> devicesAfterTransformation = config.getDiskStorageDevices();
+ assertEquals( 1, devicesAfterTransformation.size() );
+ final DiskStorage diskDeviceAfterTransformation = devicesAfterTransformation.get( 0 );
+ assertEquals( StorageType.FILE, diskDeviceAfterTransformation.getStorageType() );
+ assertEquals( TransformationTestUtils.DEFAULT_VM_HDD0, diskDeviceAfterTransformation.getStorageSource() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+
+ @Test
+ @DisplayName( "Test transformation of VM disk storage devices configuration with unspecified input data" )
+ public void testTransformationGenericDiskStorageDevicesNoData() throws TransformationException
+ {
+ final TransformationGenericDiskStorageDevices transformation = new TransformationGenericDiskStorageDevices();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getEmptyCmdLnArgs();
+
+ final ArrayList<DiskStorage> devicesBeforeTransformation = config.getDiskStorageDevices();
+ assertEquals( 1, devicesBeforeTransformation.size() );
+
+ transformation.transform( config, args );
+
+ final ArrayList<DiskStorage> devicesAfterTransformation = config.getDiskStorageDevices();
+ assertEquals( 0, devicesAfterTransformation.size() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericFileSystemDevicesTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericFileSystemDevicesTest.java
new file mode 100644
index 00000000..7605f778
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericFileSystemDevicesTest.java
@@ -0,0 +1,66 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.ArrayList;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.FileSystem;
+import org.openslx.libvirt.domain.device.FileSystem.AccessMode;
+import org.openslx.libvirt.domain.device.FileSystem.Type;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+
+public class TransformationGenericFileSystemDevicesTest
+{
+ @Test
+ @DisplayName( "Test transformation of VM file system devices configuration with specified input data" )
+ public void testTransformationGenericFileSystemDevices() throws TransformationException
+ {
+ final TransformationGenericFileSystemDevices transformation = new TransformationGenericFileSystemDevices();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getDefaultCmdLnArgs();
+
+ final ArrayList<FileSystem> devicesBeforeTransformation = config.getFileSystemDevices();
+ assertEquals( 0, devicesBeforeTransformation.size() );
+
+ transformation.transform( config, args );
+
+ final ArrayList<FileSystem> devicesAfterTransformation = config.getFileSystemDevices();
+ assertEquals( 2, devicesAfterTransformation.size() );
+ final FileSystem fs1AfterTransformation = devicesAfterTransformation.get( 0 );
+ final FileSystem fs2AfterTransformation = devicesAfterTransformation.get( 1 );
+ assertEquals( Type.MOUNT, fs1AfterTransformation.getType() );
+ assertEquals( AccessMode.MAPPED, fs1AfterTransformation.getAccessMode() );
+ assertEquals( TransformationTestUtils.DEFAULT_VM_FSSRC0, fs1AfterTransformation.getSource() );
+ assertEquals( TransformationTestUtils.DEFAULT_VM_FSTGT0, fs1AfterTransformation.getTarget() );
+ assertEquals( Type.MOUNT, fs2AfterTransformation.getType() );
+ assertEquals( AccessMode.MAPPED, fs2AfterTransformation.getAccessMode() );
+ assertEquals( TransformationTestUtils.DEFAULT_VM_FSSRC1, fs2AfterTransformation.getSource() );
+ assertEquals( TransformationTestUtils.DEFAULT_VM_FSTGT1, fs2AfterTransformation.getTarget() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+
+ @Test
+ @DisplayName( "Test transformation of VM file system devices configuration with unspecified input data" )
+ public void testTransformationGenericFileSystemDevicesNoData() throws TransformationException
+ {
+ final TransformationGenericFileSystemDevices transformation = new TransformationGenericFileSystemDevices();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getEmptyCmdLnArgs();
+
+ final ArrayList<FileSystem> devicesBeforeTransformation = config.getFileSystemDevices();
+ assertEquals( 0, devicesBeforeTransformation.size() );
+
+ transformation.transform( config, args );
+
+ final ArrayList<FileSystem> devicesAfterTransformation = config.getFileSystemDevices();
+ assertEquals( 0, devicesAfterTransformation.size() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericInterfaceDevicesTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericInterfaceDevicesTest.java
new file mode 100644
index 00000000..e4632784
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericInterfaceDevicesTest.java
@@ -0,0 +1,63 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.ArrayList;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.Interface;
+import org.openslx.libvirt.domain.device.Interface.Model;
+import org.openslx.libvirt.domain.device.Interface.Type;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.VirtualizationConfigurationQemu;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+
+public class TransformationGenericInterfaceDevicesTest
+{
+ @Test
+ @DisplayName( "Test transformation of VM network interface devices configuration with specified input data" )
+ public void testTransformationGenericInterfaceDevices() throws TransformationException
+ {
+ final TransformationGenericInterfaceDevices transformation = new TransformationGenericInterfaceDevices();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getDefaultCmdLnArgs();
+
+ final ArrayList<Interface> devicesBeforeTransformation = config.getInterfaceDevices();
+ assertEquals( 1, devicesBeforeTransformation.size() );
+
+ transformation.transform( config, args );
+
+ final ArrayList<Interface> devicesAfterTransformation = config.getInterfaceDevices();
+ assertEquals( 1, devicesAfterTransformation.size() );
+ final Interface interfaceAfterTransformation = devicesAfterTransformation.get( 0 );
+ assertEquals( Type.BRIDGE, interfaceAfterTransformation.getType() );
+ assertEquals( Model.VIRTIO, interfaceAfterTransformation.getModel() );
+ assertEquals( TransformationTestUtils.DEFAULT_VM_MAC0, interfaceAfterTransformation.getMacAddress() );
+ assertEquals( VirtualizationConfigurationQemu.NETWORK_BRIDGE_NAT_DEFAULT,
+ interfaceAfterTransformation.getSource() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+
+ @Test
+ @DisplayName( "Test transformation of VM network interface devices configuration with unspecified input data" )
+ public void testTransformationGenericInterfaceDevicesNoData() throws TransformationException
+ {
+ final TransformationGenericInterfaceDevices transformation = new TransformationGenericInterfaceDevices();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getEmptyCmdLnArgs();
+
+ final ArrayList<Interface> devicesBeforeTransformation = config.getInterfaceDevices();
+ assertEquals( 1, devicesBeforeTransformation.size() );
+
+ transformation.transform( config, args );
+
+ final ArrayList<Interface> devicesAfterTransformation = config.getInterfaceDevices();
+ assertEquals( 0, devicesAfterTransformation.size() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericMemoryTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericMemoryTest.java
new file mode 100644
index 00000000..a93e26a5
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericMemoryTest.java
@@ -0,0 +1,50 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.math.BigInteger;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.DomainUtils;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+
+public class TransformationGenericMemoryTest
+{
+ @Test
+ @DisplayName( "Test transformation of VM memory configuration" )
+ public void testTransformationGenericMemory() throws TransformationException
+ {
+ final TransformationGenericMemory transformation = new TransformationGenericMemory();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getDefaultCmdLnArgs();
+
+ final BigInteger defaultMemory = DomainUtils.decodeMemory( TransformationTestUtils.DEFAULT_VM_MEM, "MiB" );
+
+ assertNotEquals( defaultMemory.toString(), config.getMemory().toString() );
+ assertNotEquals( defaultMemory.toString(), config.getCurrentMemory().toString() );
+
+ transformation.transform( config, args );
+
+ assertEquals( defaultMemory.toString(), config.getMemory().toString() );
+ assertEquals( defaultMemory.toString(), config.getCurrentMemory().toString() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+
+ @Test
+ @DisplayName( "Test transformation of VM memory configuration with unspecified input data" )
+ public void testTransformationGenericMemoryNoData() throws TransformationException
+ {
+ final TransformationGenericMemory transformation = new TransformationGenericMemory();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getEmptyCmdLnArgs();
+
+ assertThrows( TransformationException.class, () -> transformation.transform( config, args ) );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericNameTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericNameTest.java
new file mode 100644
index 00000000..ca272801
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericNameTest.java
@@ -0,0 +1,45 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+
+public class TransformationGenericNameTest
+{
+ @Test
+ @DisplayName( "Test transformation of VM (display) name configuration" )
+ public void testTransformationGenericName() throws TransformationException
+ {
+ final TransformationGenericName transformation = new TransformationGenericName();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getDefaultCmdLnArgs();
+
+ assertNotEquals( TransformationTestUtils.DEFAULT_VM_NAME, config.getName() );
+ assertNotEquals( TransformationTestUtils.DEFAULT_VM_DSPLNAME, config.getTitle() );
+
+ transformation.transform( config, args );
+
+ assertEquals( TransformationTestUtils.DEFAULT_VM_NAME, config.getName() );
+ assertEquals( TransformationTestUtils.DEFAULT_VM_DSPLNAME, config.getTitle() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+
+ @Test
+ @DisplayName( "Test transformation of VM (display) name configuration with unspecified input data" )
+ public void testTransformationGenericNameNoData() throws TransformationException
+ {
+ final TransformationGenericName transformation = new TransformationGenericName();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getEmptyCmdLnArgs();
+
+ assertThrows( TransformationException.class, () -> transformation.transform( config, args ) );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericParallelDevicesTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericParallelDevicesTest.java
new file mode 100644
index 00000000..9402b59a
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericParallelDevicesTest.java
@@ -0,0 +1,58 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.ArrayList;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.Parallel;
+import org.openslx.libvirt.domain.device.Parallel.Type;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+
+public class TransformationGenericParallelDevicesTest
+{
+ @Test
+ @DisplayName( "Test transformation of VM parallel devices configuration with specified input data" )
+ public void testTransformationGenericParallelDevices() throws TransformationException
+ {
+ final TransformationGenericParallelDevices transformation = new TransformationGenericParallelDevices();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getDefaultCmdLnArgs();
+
+ final ArrayList<Parallel> devicesBeforeTransformation = config.getParallelDevices();
+ assertEquals( 0, devicesBeforeTransformation.size() );
+
+ transformation.transform( config, args );
+
+ final ArrayList<Parallel> devicesAfterTransformation = config.getParallelDevices();
+ assertEquals( 1, devicesAfterTransformation.size() );
+ final Parallel parallelDeviceAfterTransformation = devicesAfterTransformation.get( 0 );
+ assertEquals( Type.DEV, parallelDeviceAfterTransformation.getType() );
+ assertEquals( TransformationTestUtils.DEFAULT_VM_PARALLEL0, parallelDeviceAfterTransformation.getSource() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+
+ @Test
+ @DisplayName( "Test transformation of VM parallel devices configuration with unspecified input data" )
+ public void testTransformationGenericParallelDevicesNoData() throws TransformationException
+ {
+ final TransformationGenericParallelDevices transformation = new TransformationGenericParallelDevices();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getEmptyCmdLnArgs();
+
+ final ArrayList<Parallel> devicesBeforeTransformation = config.getParallelDevices();
+ assertEquals( 0, devicesBeforeTransformation.size() );
+
+ transformation.transform( config, args );
+
+ final ArrayList<Parallel> devicesAfterTransformation = config.getParallelDevices();
+ assertEquals( 0, devicesAfterTransformation.size() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericUuidTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericUuidTest.java
new file mode 100644
index 00000000..03534d8e
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationGenericUuidTest.java
@@ -0,0 +1,43 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+
+public class TransformationGenericUuidTest
+{
+ @Test
+ @DisplayName( "Test transformation of VM UUID configuration" )
+ public void testTransformationGenericUuid() throws TransformationException
+ {
+ final TransformationGenericUuid transformation = new TransformationGenericUuid();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getDefaultCmdLnArgs();
+
+ assertNotEquals( TransformationTestUtils.DEFAULT_VM_UUID, config.getUuid() );
+
+ transformation.transform( config, args );
+
+ assertEquals( TransformationTestUtils.DEFAULT_VM_UUID, config.getUuid() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+
+ @Test
+ @DisplayName( "Test transformation of VM UUID configuration with unspecified input data" )
+ public void testTransformationGenericUuidNoData() throws TransformationException
+ {
+ final TransformationGenericUuid transformation = new TransformationGenericUuid();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getEmptyCmdLnArgs();
+
+ assertThrows( TransformationException.class, () -> transformation.transform( config, args ) );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuArchitectureTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuArchitectureTest.java
new file mode 100644
index 00000000..86186247
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuArchitectureTest.java
@@ -0,0 +1,105 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.InputStream;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.openslx.libvirt.capabilities.Capabilities;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.Domain.OsType;
+import org.openslx.libvirt.domain.Domain.Type;
+import org.openslx.libvirt.xml.LibvirtXmlDocumentException;
+import org.openslx.libvirt.xml.LibvirtXmlSerializationException;
+import org.openslx.libvirt.xml.LibvirtXmlTestResources;
+import org.openslx.libvirt.xml.LibvirtXmlValidationException;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+
+class TransformationSpecificQemuArchitectureStub extends TransformationSpecificQemuArchitecture
+{
+ final String capabilityFileName;
+
+ public TransformationSpecificQemuArchitectureStub( String capabilityFileName )
+ {
+ super( null );
+
+ this.capabilityFileName = capabilityFileName;
+ }
+
+ @Override
+ protected Capabilities getCapabilities() throws TransformationException
+ {
+ final InputStream capabilityContent = LibvirtXmlTestResources.getLibvirtXmlStream( this.capabilityFileName );
+ Capabilities capabilites = null;
+
+ try {
+ capabilites = new Capabilities( capabilityContent );
+ } catch ( LibvirtXmlDocumentException | LibvirtXmlSerializationException | LibvirtXmlValidationException e ) {
+ fail( "Could not create stub for getCapabilities(): " + e.getLocalizedMessage() );
+ }
+
+ return capabilites;
+ }
+}
+
+public class TransformationSpecificQemuArchitectureTest
+{
+ @Test
+ @DisplayName( "Test transformation of VM architecture configuration if KVM required and available" )
+ public void testTransformationSpecificQemuArchitectureKvm() throws TransformationException
+ {
+ final TransformationSpecificQemuArchitectureStub transformation;
+ transformation = new TransformationSpecificQemuArchitectureStub( "qemu-kvm_capabilities_default.xml" );
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+
+ assertEquals( Type.KVM, config.getType() );
+ assertEquals( "x86_64", config.getOsArch() );
+ assertEquals( "pc-q35-5.1", config.getOsMachine() );
+ assertEquals( OsType.HVM, config.getOsType() );
+
+ transformation.transform( config, null );
+
+ assertEquals( Type.KVM, config.getType() );
+ assertEquals( "x86_64", config.getOsArch() );
+ assertEquals( "pc-q35-5.1", config.getOsMachine() );
+ assertEquals( OsType.HVM, config.getOsType() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+
+ @Test
+ @DisplayName( "Test transformation of VM architecture configuration if KVM required but not available" )
+ public void testTransformationSpecificQemuArchitectureNoKvm() throws TransformationException
+ {
+ final TransformationSpecificQemuArchitectureStub transformation;
+ transformation = new TransformationSpecificQemuArchitectureStub( "qemu-kvm_capabilities_no-kvm.xml" );
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+
+ assertEquals( Type.KVM, config.getType() );
+ assertEquals( "x86_64", config.getOsArch() );
+ assertEquals( "pc-q35-5.1", config.getOsMachine() );
+ assertEquals( OsType.HVM, config.getOsType() );
+
+ assertThrows( TransformationException.class, () -> transformation.transform( config, null ) );
+ }
+
+ @Test
+ @DisplayName( "Test transformation of VM architecture configuration if version is not supported (machine version too new)" )
+ public void testTransformationSpecificQemuArchitectureMachineVersionDowngrade() throws TransformationException
+ {
+ final TransformationSpecificQemuArchitectureStub transformation;
+ transformation = new TransformationSpecificQemuArchitectureStub( "qemu-kvm_capabilities_old-version.xml" );
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+
+ assertEquals( Type.KVM, config.getType() );
+ assertEquals( "x86_64", config.getOsArch() );
+ assertEquals( "pc-q35-5.1", config.getOsMachine() );
+ assertEquals( OsType.HVM, config.getOsType() );
+
+ assertThrows( TransformationException.class, () -> transformation.transform( config, null ) );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGpuPassthroughNvidiaTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGpuPassthroughNvidiaTest.java
new file mode 100644
index 00000000..8f50b7df
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuGpuPassthroughNvidiaTest.java
@@ -0,0 +1,134 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import java.io.InputStream;
+import java.math.BigInteger;
+import java.util.List;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.openslx.libvirt.capabilities.Capabilities;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.HostdevPci;
+import org.openslx.libvirt.domain.device.HostdevPciDeviceAddress;
+import org.openslx.libvirt.domain.device.Shmem;
+import org.openslx.libvirt.domain.device.Video;
+import org.openslx.libvirt.xml.LibvirtXmlDocumentException;
+import org.openslx.libvirt.xml.LibvirtXmlSerializationException;
+import org.openslx.libvirt.xml.LibvirtXmlTestResources;
+import org.openslx.libvirt.xml.LibvirtXmlValidationException;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+
+class TransformationSpecificQemuGpuPassthroughNvidiaStub extends TransformationSpecificQemuGpuPassthroughNvidia
+{
+ final String capabilityFileName;
+
+ public TransformationSpecificQemuGpuPassthroughNvidiaStub( String capabilityFileName )
+ {
+ super( null );
+
+ this.capabilityFileName = capabilityFileName;
+ }
+
+ @Override
+ protected Capabilities getCapabilities() throws TransformationException
+ {
+ final InputStream capabilityContent = LibvirtXmlTestResources.getLibvirtXmlStream( this.capabilityFileName );
+ Capabilities capabilites = null;
+
+ try {
+ capabilites = new Capabilities( capabilityContent );
+ } catch ( LibvirtXmlDocumentException | LibvirtXmlSerializationException | LibvirtXmlValidationException e ) {
+ fail( "Could not create stub for getCapabilities(): " + e.getLocalizedMessage() );
+ }
+
+ return capabilites;
+ }
+}
+
+public class TransformationSpecificQemuGpuPassthroughNvidiaTest
+{
+ @Test
+ @DisplayName( "Test transformation of VM GPU passthrough configuration if NVIDIA GPU passthrouh is required" )
+ public void testTransformationSpecificQemuGpuPassthroughNvidia() throws TransformationException
+ {
+ final TransformationSpecificQemuGpuPassthroughNvidiaStub transformation;
+ transformation = new TransformationSpecificQemuGpuPassthroughNvidiaStub( "qemu-kvm_capabilities_default.xml" );
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getDefaultCmdLnArgs();
+
+ transformation.transform( config, args );
+
+ final List<HostdevPci> pciDevices = config.getHostdevPciDevices();
+ assertNotNull( pciDevices );
+ assertEquals( 1, pciDevices.size() );
+
+ final HostdevPci pciDevice = pciDevices.get( 0 );
+ assertTrue( pciDevice.isManaged() );
+ assertEquals( HostdevPciDeviceAddress.valueOf( TransformationTestUtils.DEFAULT_VM_GPU0_ADDR ),
+ pciDevice.getSource() );
+
+ final List<Shmem> shmemDevices = config.getShmemDevices();
+ assertNotNull( shmemDevices );
+ assertEquals( 1, shmemDevices.size() );
+
+ final Shmem shmemDevice = shmemDevices.get( 0 );
+ assertEquals( "looking-glass", shmemDevice.getName() );
+ assertEquals( Shmem.Model.IVSHMEM_PLAIN, shmemDevice.getModel() );
+ assertEquals( BigInteger.valueOf( 67108864 ).toString(), shmemDevice.getSize().toString() );
+
+ assertEquals( TransformationSpecificQemuGpuPassthroughNvidia.HYPERV_VENDOR_ID,
+ config.getFeatureHypervVendorIdValue() );
+ assertTrue( config.isFeatureHypervVendorIdStateOn() );
+ assertTrue( config.isFeatureKvmHiddenStateOn() );
+
+ final List<Video> videoDevices = config.getVideoDevices();
+ assertNotNull( videoDevices );
+ for ( final Video videoDevice : videoDevices ) {
+ assertEquals( Video.Model.NONE, videoDevice.getModel() );
+ }
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+
+ @Test
+ @DisplayName( "Test transformation of VM GPU passthrough configuration if NVIDIA GPU passthrouh is not specified" )
+ public void testTransformationSpecificQemuGpuPassthroughNvidiaNoGpu() throws TransformationException
+ {
+ final TransformationSpecificQemuGpuPassthroughNvidiaStub transformation;
+ transformation = new TransformationSpecificQemuGpuPassthroughNvidiaStub( "qemu-kvm_capabilities_default.xml" );
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getEmptyCmdLnArgs();
+
+ transformation.transform( config, args );
+
+ final List<HostdevPci> pciDevices = config.getHostdevPciDevices();
+ assertNotNull( pciDevices );
+ assertEquals( 0, pciDevices.size() );
+
+ final List<Shmem> shmemDevices = config.getShmemDevices();
+ assertNotNull( shmemDevices );
+ assertEquals( 0, shmemDevices.size() );
+
+ assertNotEquals( TransformationSpecificQemuGpuPassthroughNvidia.HYPERV_VENDOR_ID,
+ config.getFeatureHypervVendorIdValue() );
+ assertFalse( config.isFeatureHypervVendorIdStateOn() );
+ assertFalse( config.isFeatureKvmHiddenStateOn() );
+
+ final List<Video> videoDevices = config.getVideoDevices();
+ assertNotNull( videoDevices );
+ for ( final Video videoDevice : videoDevices ) {
+ assertNotEquals( Video.Model.NONE, videoDevice.getModel() );
+ }
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuSerialDevicesTest.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuSerialDevicesTest.java
new file mode 100644
index 00000000..6beada8d
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationSpecificQemuSerialDevicesTest.java
@@ -0,0 +1,74 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.ArrayList;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.domain.device.Serial;
+import org.openslx.libvirt.domain.device.Serial.Type;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.virtualization.configuration.transformation.TransformationException;
+
+class TransformationSpecificQemuSerialDevicesStub extends TransformationSpecificQemuSerialDevices
+{
+ public TransformationSpecificQemuSerialDevicesStub()
+ {
+ super( null );
+ }
+}
+
+public class TransformationSpecificQemuSerialDevicesTest
+{
+ @Test
+ @DisplayName( "Test transformation of VM serial devices configuration with specified input data" )
+ public void testTransformationGenericSerialDevices() throws TransformationException
+ {
+ final TransformationSpecificQemuSerialDevicesStub transformation = new TransformationSpecificQemuSerialDevicesStub();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getDefaultCmdLnArgs();
+
+ final ArrayList<Serial> devicesBeforeTransformation = config.getSerialDevices();
+ assertEquals( 1, devicesBeforeTransformation.size() );
+ final Serial serialDeviceBeforeTransformation = devicesBeforeTransformation.get( 0 );
+ assertEquals( Type.PTY, serialDeviceBeforeTransformation.getType() );
+
+ transformation.transform( config, args );
+
+ final ArrayList<Serial> devicesAfterTransformation = config.getSerialDevices();
+ assertEquals( 2, devicesAfterTransformation.size() );
+ final Serial serialDevice1AfterTransformation = devicesAfterTransformation.get( 0 );
+ assertEquals( Type.PTY, serialDevice1AfterTransformation.getType() );
+ final Serial serialDevice2AfterTransformation = devicesAfterTransformation.get( 1 );
+ assertEquals( Type.DEV, serialDevice2AfterTransformation.getType() );
+ assertEquals( TransformationTestUtils.DEFAULT_VM_SERIAL0, serialDevice2AfterTransformation.getSource() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+
+ @Test
+ @DisplayName( "Test transformation of VM serial devices configuration with unspecified input data" )
+ public void testTransformationGenericSerialDevicesNoData() throws TransformationException
+ {
+ final TransformationSpecificQemuSerialDevicesStub transformation = new TransformationSpecificQemuSerialDevicesStub();
+ final Domain config = TransformationTestUtils.getDefaultDomain();
+ final CommandLineArgs args = TransformationTestUtils.getEmptyCmdLnArgs();
+
+ final ArrayList<Serial> devicesBeforeTransformation = config.getSerialDevices();
+ assertEquals( 1, devicesBeforeTransformation.size() );
+ final Serial serialDeviceBeforeTransformation = devicesBeforeTransformation.get( 0 );
+ assertEquals( Type.PTY, serialDeviceBeforeTransformation.getType() );
+
+ transformation.transform( config, args );
+
+ final ArrayList<Serial> devicesAfterTransformation = config.getSerialDevices();
+ assertEquals( 1, devicesAfterTransformation.size() );
+ final Serial serialDeviceAfterTransformation = devicesBeforeTransformation.get( 0 );
+ assertEquals( Type.PTY, serialDeviceAfterTransformation.getType() );
+
+ assertDoesNotThrow( () -> config.validateXml() );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationTestResources.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationTestResources.java
new file mode 100644
index 00000000..b04685f9
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationTestResources.java
@@ -0,0 +1,17 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import java.io.File;
+import java.net.URL;
+
+public class TransformationTestResources
+{
+ private static final String LIBVIRT_PREFIX_PATH = File.separator + "libvirt";
+ private static final String LIBVIRT_PREFIX_PATH_XML = LIBVIRT_PREFIX_PATH + File.separator + "xml";
+
+ public static File getLibvirtXmlFile( String libvirtXmlFileName )
+ {
+ String libvirtXmlPath = TransformationTestResources.LIBVIRT_PREFIX_PATH_XML + File.separator + libvirtXmlFileName;
+ URL libvirtXml = TransformationTestResources.class.getResource( libvirtXmlPath );
+ return new File( libvirtXml.getFile() );
+ }
+}
diff --git a/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationTestUtils.java b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationTestUtils.java
new file mode 100644
index 00000000..597fd8d6
--- /dev/null
+++ b/core/modules/qemu/runvirt-plugin-qemu/src/test/java/org/openslx/runvirt/plugin/qemu/configuration/TransformationTestUtils.java
@@ -0,0 +1,119 @@
+package org.openslx.runvirt.plugin.qemu.configuration;
+
+import static org.junit.jupiter.api.Assertions.fail;
+
+import org.openslx.libvirt.domain.Domain;
+import org.openslx.libvirt.xml.LibvirtXmlDocumentException;
+import org.openslx.libvirt.xml.LibvirtXmlSerializationException;
+import org.openslx.libvirt.xml.LibvirtXmlTestResources;
+import org.openslx.libvirt.xml.LibvirtXmlValidationException;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgs.CmdLnOption;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgsException;
+import org.openslx.runvirt.plugin.qemu.cmdln.CommandLineArgsTest;
+
+public class TransformationTestUtils
+{
+ // @formatter:off
+ public static final String DEFAULT_VM_NAME = "archlinux";
+ public static final String DEFAULT_VM_UUID = "4ec504d5-5eac-482f-a344-dbf1dd4956c8";
+ public static final String DEFAULT_VM_DSPLNAME = "Archlinux";
+ public static final String DEFAULT_VM_OS = "Windows 10 (x64)";
+ public static final String DEFAULT_VM_NCPUS = "16";
+ public static final String DEFAULT_VM_MEM = "1024";
+ public static final String DEFAULT_VM_HDD0 = "/mnt/vm/windows.qcow2";
+ public static final String DEFAULT_VM_FLOPPY0 = "/mnt/vm/floppy0.qcow2";
+ public static final String DEFAULT_VM_FLOPPY1 = "/mnt/vm/floppy1.qcow2";
+ public static final String DEFAULT_VM_CDROM0 = "/dev/sr0";
+ public static final String DEFAULT_VM_CDROM1 = "/mnt/vm/cdrom1.qcow2";
+ public static final String DEFAULT_VM_PARALLEL0 = "/dev/parport0";
+ public static final String DEFAULT_VM_SERIAL0 = "/dev/ttyS0";
+ public static final String DEFAULT_VM_MAC0 = "ca:06:29:84:f0:6d";
+ public static final String DEFAULT_VM_FSSRC0 = "/mnt/shared/folder0";
+ public static final String DEFAULT_VM_FSTGT0 = "folder0";
+ public static final String DEFAULT_VM_FSSRC1 = "/mnt/shared/folder1";
+ public static final String DEFAULT_VM_FSTGT1 = "folder1";
+ public static final String DEFAULT_VM_GPU0_DESC = "10de:1d01";
+ public static final String DEFAULT_VM_GPU0_ADDR = "0000:00:02.0";
+ public static final String DEFAULT_VM_NVGPUIDS0 = DEFAULT_VM_GPU0_DESC + "," + DEFAULT_VM_GPU0_ADDR;
+ // @formatter:on
+
+ private static final String[] DEFAULT_CMDLN_ARGS = {
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_NAME.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_NAME,
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_UUID.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_UUID,
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_DSPLNAME.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_DSPLNAME,
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_OS.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_OS,
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_NCPUS.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_NCPUS,
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_MEM.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_MEM,
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_HDD0.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_HDD0,
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_FLOPPY0.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_FLOPPY0,
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_FLOPPY1.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_FLOPPY1,
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_CDROM0.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_CDROM0,
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_CDROM1.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_CDROM1,
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_PARALLEL0.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_PARALLEL0,
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_SERIAL0.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_SERIAL0,
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_MAC0.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_MAC0,
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_FSSRC0.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_FSSRC0,
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_FSTGT0.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_FSTGT0,
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_FSSRC1.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_FSSRC1,
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_FSTGT1.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_FSTGT1,
+ CommandLineArgsTest.CMDLN_PREFIX_OPTION_LONG + CmdLnOption.VM_NVGPUIDS0.getLongOption(),
+ TransformationTestUtils.DEFAULT_VM_NVGPUIDS0
+ };
+
+ private static CommandLineArgs getCmdLnArgs( String[] args )
+ {
+ final CommandLineArgs cmdLnArgs = new CommandLineArgs();
+
+ try {
+ cmdLnArgs.parseCmdLnArgs( args );
+ } catch ( CommandLineArgsException e ) {
+ fail( e.getLocalizedMessage() );
+ }
+
+ return cmdLnArgs;
+ }
+
+ public static CommandLineArgs getDefaultCmdLnArgs()
+ {
+ return TransformationTestUtils.getCmdLnArgs( TransformationTestUtils.DEFAULT_CMDLN_ARGS );
+ }
+
+ public static CommandLineArgs getEmptyCmdLnArgs()
+ {
+ return TransformationTestUtils.getCmdLnArgs( new String[] {} );
+ }
+
+ public static Domain getDefaultDomain()
+ {
+ Domain domain = null;
+
+ try {
+ domain = new Domain( LibvirtXmlTestResources
+ .getLibvirtXmlStream( "qemu-kvm_default-ubuntu-20-04-vm_transform-non-persistent.xml" ) );
+ } catch ( LibvirtXmlDocumentException | LibvirtXmlSerializationException | LibvirtXmlValidationException e ) {
+ fail( "Cannot prepare requested Libvirt domain XML file from the resources folder: "
+ + e.getLocalizedMessage() );
+ }
+
+ return domain;
+ }
+}
diff --git a/core/modules/qemukvm/data/addon-init b/core/modules/qemukvm/data/addon-init
deleted file mode 100755
index cccc1e8a..00000000
--- a/core/modules/qemukvm/data/addon-init
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/ash
-
-systemctl daemon-reload
-systemctl start qemukvm.service
-
-# this seems to be necessary due to the misbehaviour of udevd
-# in view of the undetected ENV dev_type
-systemctl restart systemd-udevd
diff --git a/core/modules/qemukvm/data/etc/qemu/bridge.conf b/core/modules/qemukvm/data/etc/qemu/bridge.conf
deleted file mode 100644
index b8478434..00000000
--- a/core/modules/qemukvm/data/etc/qemu/bridge.conf
+++ /dev/null
@@ -1,6 +0,0 @@
-# These needs to be compatible with the
-# bridge's names generated by
-# /opt/openslx/scripts/systemd-run_virt_env
-allow br0
-allow nat1
-allow vsw2
diff --git a/core/modules/qemukvm/data/etc/systemd/system/graphical.target.wants/qemukvm.service b/core/modules/qemukvm/data/etc/systemd/system/graphical.target.wants/qemukvm.service
deleted file mode 120000
index 89d8afbf..00000000
--- a/core/modules/qemukvm/data/etc/systemd/system/graphical.target.wants/qemukvm.service
+++ /dev/null
@@ -1 +0,0 @@
-../qemukvm.service \ No newline at end of file
diff --git a/core/modules/qemukvm/data/etc/systemd/system/qemukvm.service b/core/modules/qemukvm/data/etc/systemd/system/qemukvm.service
deleted file mode 100644
index f1f3dec6..00000000
--- a/core/modules/qemukvm/data/etc/systemd/system/qemukvm.service
+++ /dev/null
@@ -1,9 +0,0 @@
-[Unit]
-Description=Sets up the virtual box environment
-Requires=run-virt-env.service
-After=run-virt-env.service
-
-[Service]
-Type=oneshot
-RemainAfterExit=yes
-ExecStart=/opt/openslx/scripts/systemd-qemukvm_env start
diff --git a/core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/README b/core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/README
deleted file mode 100644
index 549d0037..00000000
--- a/core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/README
+++ /dev/null
@@ -1 +0,0 @@
-Not tested since refactoring! (January 2017)
diff --git a/core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/includes/determine_hardware_limitations.inc b/core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/includes/determine_hardware_limitations.inc
deleted file mode 100644
index dd83b587..00000000
--- a/core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/includes/determine_hardware_limitations.inc
+++ /dev/null
@@ -1,89 +0,0 @@
-##################################################################
-# qemu/kvm include: determine virtual hardware based on guest OS #
-##################################################################
-
-set_vm_hw_limits() {
- # FIXME when we have better metadata for qemu
- if isempty VM_OS_TYPE; then
- writelog "VM_OS_TYPE is empty! This should have been parsed from the XML file"
- EXIT_TYPE="user" EXIT_REASON="Konnte Gastbetriebsystems der virtuellen Maschine nicht ermitteln!" cleanexit 1
- fi
-
- # define global hardware-related variables
- declare -g MAXMEM="9999999"
- declare -g MAXCORES="4"
- declare -g SOUND_DEV="es1370"
-
- # determine if we need a 32bit or 64bit machine
- # FIXME depending on the guest OS for now
- # (sadly does not support all the exotic OSs the
- # the world has even seen like vmware plugin :<)
- local bits=64
- case "${VM_OS_TYPE}" in
- beos*)
- bits=32
- SOUND_DEV="sb16"
- ;;
- win3*|win*3*|Win*3*)
- bits=32
- SOUND_DEV="sb16"
- MAXMEM=32
- ;;
- win95*|Win*95)
- bits=32
- MAXMEM=96
- ;;
- win98)
- bits=32
- MAXMEM=256
- ;;
- winme*|windowsme*)
- bits=32
- SOUND_DEV="ac97"
- MAXMEM=384
- ;;
- winxp*64|windowsxp*64)
- SOUND_DEV="ac97"
- ;;
- windows7|windows8|windows9)
- SOUND_DEV="ac97"
- MAXMEM="8000"
- MAXCORES="4"
- ;;
- windows7-64|windows8-64|windows9-64)
- SOUND_DEV="ac97"
- MAXMEM="32000"
- MAXCORES="8"
- ;;
- *64)
- MAXMEM="16000"
- MAXCORES="4"
- ;;
- *)
- bits=32
- MAXMEM="8000"
- MAXCORES="1"
- ;;
- esac
- declare -g VIRTCMD
- if [ "$bits" = 32 ]; then
- declare -rg VIRTCMD="qemu-system-i386"
- VIRTCMDOPTS+=( "-machine" "accel=tcg" ) # TODO: 32bit VMs can't use kvm!?
- else # 64 bit
- declare -rg VIRTCMD="qemu-system-x86_64"
- VIRTCMDOPTS+=( "-machine" "accel=kvm" )
- fi
-
-
- # check for allocated cores
- declare -g CPU_CORES="${HW_THREADS:-1}"
- declare -rg HOST_CORE_COUNT="${CPU_CORES}"
- [ "${CPU_CORES}" -gt "${MAXCORES}" ] && CPU_CORES="${MAXCORES}"
-
- # check if memory set by the generic run-virt is above the threshold
- [ "${VM_MEM}" -gt "${MAXMEM}" ] && VM_MEM="${MAXMEM}"
- return 0
-}
-
-## MAIN ##
-call_post_source set_vm_hw_limits
diff --git a/core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/includes/log_config_summary.inc b/core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/includes/log_config_summary.inc
deleted file mode 100644
index 6b4b279f..00000000
--- a/core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/includes/log_config_summary.inc
+++ /dev/null
@@ -1,35 +0,0 @@
-##################################################
-# Include: Print vm config summary into log file #
-##################################################
-
-log_config_summary() {
- writelog "Directories:"
- writelog "\tTMPDIR:\t\t\t$TMPDIR"
- writelog "Disk image:"
- writelog "\tSource disk:\t\t$VM_DISKFILE_RO"
- if [ -e "${VM_DISKFILE_RW}" ]; then
- writelog "\tDisk mode:\t\twritable"
- writelog "\tRW-Layer:\t\t$VM_DISKFILE_RW"
- else
- writelog "\tDisk mode:\t\tread-only"
- fi
-
- writelog "Virtual Hardware:"
- writelog "\tvCPU cores:\t\t${CPU_CORES}"
- writelog "\tGuest RAM:\t\t${VM_MEM} MB"
-
- # echo nur wenn HOST_MEM_REMAINING gesetzt
- if isset HOST_MEM_REMAINING; then
- writelog "\tHost RAM:\t\t${HOST_MEM_REMAINING} MB"
- fi
- writelog "\tMAC address:\t\t${VM_MAC_ADDR}"
- writelog "\tNetwork card:\t\t${NIC_MODEL}"
- writelog "\tNetwork kind:\t\t${NETWORK_MODE}"
- writelog "\tCD-ROM1:\t${CDROM_0}"
- writelog "\tCD-ROM2:\t${CDROM_1}"
- writelog "\tFloppy_A:\t${FLOPPY_0}"
- writelog "\tFloppy_B:\t${SLX_FLOPPY_IMG}"
- #writelog "\tShared Folders 'home':\t/home/${USER}"
-}
-
-call_post_source log_config_summary
diff --git a/core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/includes/setup_network.inc b/core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/includes/setup_network.inc
deleted file mode 100644
index 73fb2518..00000000
--- a/core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/includes/setup_network.inc
+++ /dev/null
@@ -1,56 +0,0 @@
-###################################
-# qemu/kvm include: Network setup #
-###################################
-# This now makes use of the qemu's bridge helper
-# which creates a tap device and adds it to the
-# bridge corresponding to the network type
-# TODO configurable network type
-setup_network() {
- # list available models with:
- # qemu-system-x86_64 -net nic,model=?
- # e.g. as of 2.0.0:
- # ne2k_pci,i82551,i82557b,i82559er,rtl8139,e1000,pcnet,virtio
- declare -rg NIC_MODEL="e1000"
-
- # add MAC address and network card model
- VIRTCMDOPTS+=( "-device" "${NIC_MODEL},mac=${VM_MAC_ADDR},netdev=guestnet0" )
-
- # TODO support different network kinds for lectures in bwlehrpool-suite, just NAT for now
- declare -g NETWORK_MODE="nat"
-
- # detect if qemu's bridge helper binary is available
- declare -g QEMU_BRIDGE_HELPER=
- for HELPER_PATH in /usr/lib/qemu-bridge-helper /usr/local/libexec/qemu-bridge-helper; do
- if [ -x "${HELPER_PATH}" ] && [ -u "${HELPER_PATH}" ]; then
- QEMU_BRIDGE_HELPER="${HELPER_PATH}"
- readonly QEMU_BRIDGE_HELPER
- break
- fi
- done
- if isempty QEMU_BRIDGE_HELPER; then
- writelog "Could not find qemu-bridge-helper on this machine. Setting network mode to user."
- # Even though falling back to creating tap devices ourselves, we should instead
- # garantee the existance of qemu's helper on minilinux build time.
- # qemu's user network mode allows tcp/udp connections in a nat-fashion and
- # it allows access to the web which seems suffisant for a fallback.
- NETWORK_MODE="user"
- fi
-
- case "${NETWORK_MODE}" in
- nat*)
- VIRTCMDOPTS+=( "-netdev" "bridge,br=nat1,id=guestnet0,helper=${QEMU_BRIDGE_HELPER}" )
- ;;
- bridge*)
- VIRTCMDOPTS+=( "-netdev" "bridge,br=br0,id=guestnet0,helper=${QEMU_BRIDGE_HELPER}" )
- ;;
- host*)
- VIRTCMDOPTS+=( "-netdev" "bridge,br=vsw2,id=guestnet0,helper=${QEMU_BRIDGE_HELPER}" )
- ;;
- user*|*)
- VIRTCMDOPTS+=( "-netdev" "user,id=guestnet0" )
- ;;
- esac
-}
-
-## MAIN ##
-call_post_source setup_network
diff --git a/core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/includes/setup_rw_layer.inc b/core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/includes/setup_rw_layer.inc
deleted file mode 100644
index 32637e5d..00000000
--- a/core/modules/qemukvm/data/opt/openslx/vmchooser/plugins/qemukvm/includes/setup_rw_layer.inc
+++ /dev/null
@@ -1,25 +0,0 @@
-
-setup_rw_layer() {
- if isempty VM_DISKFILE_RO; then
- writelog "No source diskfile found! This should be specified in the given XML file. Is it valid?"
- EXIT_TYPE="user" EXIT_REASON="Keine virtuelle Festplatte zu dieser Veranstaltung angegeben!" cleanexit 1
- fi
-
- # setup qcow2 backing file for that disk file
- writelog "Creating backing file for '${VM_DISKFILE_RO}'..."
- # TODO: WTF? This is fucked up, VM_DISKFILE_RW is set if we want to run in persistent mode,
- # this plugin shouldn't mess around with it....
- declare -rg VM_DISKFILE_RW="${TMPDIR}/$(basename ${VM_DISKFILE_RO}).qcow2"
- if qemu-img create -f qcow2 -b "${VM_DISKFILE_RO}" "${VM_DISKFILE_RW}"; then
- # all good, use it as main disk drive
- # TODO: determine the proper type of controller to use, ideally virtio?
- VIRTCMDOPTS+=("-drive" "if=virtio,format=qcow2,file=${VM_DISKFILE_RW}" )
- else
- writelog "Error creating backing file for '${VM_DISKFILE_RO}'"
- # TODO use -snapshot as fallback, test it!
- # How is this supposed to even work without a disk?
- VIRTCMDOPTS+=( "-snapshot" )
- fi
-}
-
-call_post_source setup_rw_layer
diff --git a/core/modules/qemukvm/module.build b/core/modules/qemukvm/module.build
deleted file mode 100644
index f2a0df9e..00000000
--- a/core/modules/qemukvm/module.build
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-fetch_source() {
- :
-}
-
-build() {
- COPYLIST="list_dpkg_output"
- [ -e "$COPYLIST" ] && rm "$COPYLIST"
- list_packet_files >> "$COPYLIST"
-
-
- tarcopy "$(cat "${COPYLIST}" | sort -u)" "${MODULE_BUILD_DIR}"
-}
-
-post_copy() {
- # qemu-bridge-helper needs suid to be called within run-virt
- find ${TARGET_BUILD_DIR} -type f -executable -name "*qemu-bridge-helper*" -exec chmod u+s {} \;
-}
diff --git a/core/modules/qemukvm/module.conf b/core/modules/qemukvm/module.conf
deleted file mode 100644
index 0cf394cf..00000000
--- a/core/modules/qemukvm/module.conf
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/bash
-REQUIRED_MODULES=""
-REQUIRED_DIRECTORIES="
- /
-"
diff --git a/core/modules/qemukvm/module.conf.debian b/core/modules/qemukvm/module.conf.debian
deleted file mode 100644
index 4773a871..00000000
--- a/core/modules/qemukvm/module.conf.debian
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-REQUIRED_INSTALLED_PACKAGES="
- qemu
- qemu-kvm
-"
-
-REQUIRED_CONTENT_PACKAGES="
- qemu
- qemu-kvm
- qemu-system-common
- qemu-system-x86
- qemu-user
- qemu-utils
- seabios
-"
diff --git a/core/modules/qemukvm/module.conf.ubuntu b/core/modules/qemukvm/module.conf.ubuntu
deleted file mode 100644
index 4773a871..00000000
--- a/core/modules/qemukvm/module.conf.ubuntu
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/bash
-REQUIRED_INSTALLED_PACKAGES="
- qemu
- qemu-kvm
-"
-
-REQUIRED_CONTENT_PACKAGES="
- qemu
- qemu-kvm
- qemu-system-common
- qemu-system-x86
- qemu-user
- qemu-utils
- seabios
-"
diff --git a/core/targets/qemu/libvirt b/core/targets/qemu/libvirt
new file mode 120000
index 00000000..3e853b08
--- /dev/null
+++ b/core/targets/qemu/libvirt
@@ -0,0 +1 @@
+../../modules/libvirt \ No newline at end of file
diff --git a/core/targets/qemu/libvirt-users b/core/targets/qemu/libvirt-users
new file mode 120000
index 00000000..6f799d72
--- /dev/null
+++ b/core/targets/qemu/libvirt-users
@@ -0,0 +1 @@
+../../modules/libvirt-users \ No newline at end of file
diff --git a/core/targets/qemu/openjdk-8-jre-headless b/core/targets/qemu/openjdk-8-jre-headless
new file mode 120000
index 00000000..b899a6a4
--- /dev/null
+++ b/core/targets/qemu/openjdk-8-jre-headless
@@ -0,0 +1 @@
+../../modules/openjdk-8-jre-headless/ \ No newline at end of file
diff --git a/core/targets/qemu/qemu b/core/targets/qemu/qemu
new file mode 120000
index 00000000..bb8ffc08
--- /dev/null
+++ b/core/targets/qemu/qemu
@@ -0,0 +1 @@
+../../modules/qemu \ No newline at end of file
diff --git a/core/targets/qemukvm/qemukvm b/core/targets/qemukvm/qemukvm
deleted file mode 120000
index e8e7d1b3..00000000
--- a/core/targets/qemukvm/qemukvm
+++ /dev/null
@@ -1 +0,0 @@
-../../modules/qemukvm \ No newline at end of file