From 2a2c15fd614d6156406d7791330bd7a82a38b86b Mon Sep 17 00:00:00 2001 From: Manuel Bentele Date: Tue, 20 Apr 2021 13:58:37 +0200 Subject: [client,server] Encapsulate transformation logic for virtualization configurations --- .../dozmod/gui/wizard/ImageCreationWizard.java | 2 +- .../dozmod/gui/wizard/page/ImageUploadPage.java | 20 +++- .../java/org/openslx/dozmod/util/ImageWrapper.java | 3 +- .../java/org/openslx/dozmod/util/VmWrapper.java | 122 +++++++-------------- .../bwlp/sat/database/mappers/DbLecture.java | 45 ++++---- 5 files changed, 85 insertions(+), 107 deletions(-) diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/ImageCreationWizard.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/ImageCreationWizard.java index 5d3cdd6b..a51b2163 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/ImageCreationWizard.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/ImageCreationWizard.java @@ -228,7 +228,7 @@ public class ImageCreationWizard extends Wizard private ImageBaseWrite imageBaseWriteFromState() { // build imageBaseWrite return new ImageBaseWrite(state.name, state.description, state.selectedOs.getOsId(), - state.virtualizationConfig.getVirtualizer().getVirtId(), state.isTemplate, state.defaultPermissions, + state.virtualizationConfig.getVirtualizer().getId(), state.isTemplate, state.defaultPermissions, state.shareMode); } diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/ImageUploadPage.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/ImageUploadPage.java index 4bb47d36..35704f21 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/ImageUploadPage.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/ImageUploadPage.java @@ -36,6 +36,9 @@ import org.openslx.dozmod.thrift.cache.MetaDataCache; import org.openslx.sat.thrift.version.Feature; import org.openslx.thrifthelper.TConst; import org.openslx.virtualization.configuration.VirtualizationConfigurationVmware; +import org.openslx.virtualization.configuration.data.ConfigurationDataDozModClientToDozModServer; +import org.openslx.virtualization.configuration.logic.ConfigurationLogicDozModClientToDozModServer; +import org.openslx.virtualization.configuration.transformation.TransformationException; import org.openslx.virtualization.configuration.VirtualizationConfiguration; import org.openslx.virtualization.configuration.VirtualizationConfiguration.HardDisk; import org.openslx.vm.disk.DiskImage; @@ -203,6 +206,7 @@ public class ImageUploadPage extends ImageUploadPageLayout { askForConversion(file); return; } + try { // gets the metadata object of the selected VM depending on its type state.virtualizationConfig = VirtualizationConfiguration.getInstance(MetaDataCache.getOperatingSystems(), file); @@ -214,22 +218,26 @@ public class ImageUploadPage extends ImageUploadPageLayout { return; } - if (state.virtualizationConfig == null || state.virtualizationConfig.getDisplayName() == null) { + final ConfigurationLogicDozModClientToDozModServer uploadLogic = new ConfigurationLogicDozModClientToDozModServer(); + try { + // transforms (filters) the virtualization configuration + uploadLogic.apply( state.virtualizationConfig, new ConfigurationDataDozModClientToDozModServer() ); + } catch (TransformationException e) { setErrorMessage(I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.invalidConfigFile")); setPageComplete(false); return; } - final String fileformat = state.virtualizationConfig.getVirtualizer().virtName; + final String virtualizerName = state.virtualizationConfig.getVirtualizer().getName(); // bail if multiple hypervisors are not supported if (!(state.virtualizationConfig instanceof VirtualizationConfigurationVmware) && !Session.hasFeature(Feature.MULTIPLE_HYPERVISORS)) { setErrorMessage(I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.hypervisorNotSupported", - fileformat)); + virtualizerName)); setPageComplete(false); return; } // check if the user somehow changed the type of the VM - if (existingImage != null && !existingImage.virtId.equals(state.virtualizationConfig.getVirtualizer().virtId)) { + if (existingImage != null && !existingImage.virtId.equals(state.virtualizationConfig.getVirtualizer().getId())) { Virtualizer existingImageVirtualizer = MetaDataCache.getVirtualizerById(existingImage.virtId); String existingImageVirtualizerName = ""; if (existingImageVirtualizer != null) @@ -242,13 +250,13 @@ public class ImageUploadPage extends ImageUploadPageLayout { List hdds = state.virtualizationConfig.getHdds(); if (hdds.size() == 0 || hdds.get(0).diskImage == null) { - setErrorMessage(I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.noHDD", fileformat)); + setErrorMessage(I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.noHDD", virtualizerName)); setPageComplete(false); return; } if (hdds.size() > 1) { setErrorMessage( - I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.moreThanOneHDD", fileformat)); + I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.moreThanOneHDD", virtualizerName)); setPageComplete(false); return; // Allow to continue!? diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/util/ImageWrapper.java b/dozentenmodul/src/main/java/org/openslx/dozmod/util/ImageWrapper.java index 8891bbac..988284cf 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/util/ImageWrapper.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/util/ImageWrapper.java @@ -7,6 +7,7 @@ import org.openslx.dozmod.gui.helper.I18n; import org.openslx.dozmod.gui.helper.MessageType; import org.openslx.dozmod.model.ContainerDefinition; import org.openslx.thrifthelper.TConst; +import org.openslx.virtualization.configuration.VirtualizationConfigurationException; import org.openslx.vm.disk.DiskImage; import org.openslx.vm.disk.DiskImageException; @@ -95,7 +96,7 @@ public class ImageWrapper { try { VmWrapper.wrapVm(destImage, imageName, virtualizerConfig, virtualizerId, osId, diskImage); - } catch (VmWrapper.MetaDataMissingException | IOException e) { + } catch (VirtualizationConfigurationException | IOException e) { Gui.asyncMessageBox(I18n.THRIFT.getString("ThriftActions.Message.warning.couldNotWrapVM"), MessageType.WARNING, LOGGER, e); } diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/util/VmWrapper.java b/dozentenmodul/src/main/java/org/openslx/dozmod/util/VmWrapper.java index ee5e259e..f8721e98 100644 --- a/dozentenmodul/src/main/java/org/openslx/dozmod/util/VmWrapper.java +++ b/dozentenmodul/src/main/java/org/openslx/dozmod/util/VmWrapper.java @@ -1,7 +1,6 @@ package org.openslx.dozmod.util; import java.io.File; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -17,6 +16,7 @@ import javax.management.ObjectName; import javax.management.ReflectionException; import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.log4j.Logger; import org.openslx.bwlp.thrift.iface.OperatingSystem; @@ -24,13 +24,15 @@ import org.openslx.dozmod.gui.Gui; import org.openslx.dozmod.gui.helper.MessageType; import org.openslx.dozmod.thrift.cache.MetaDataCache; import org.openslx.thrifthelper.TConst; -import org.openslx.virtualization.configuration.VirtualizationConfigurationQemu; -import org.openslx.virtualization.configuration.VirtualizationConfigurationVirtualBox; import org.openslx.virtualization.configuration.VirtualizationConfigurationVmware; +import org.openslx.virtualization.configuration.logic.ConfigurationLogicDozModServerToDozModClient; +import org.openslx.virtualization.configuration.transformation.TransformationException; import org.openslx.virtualization.configuration.VirtualizationConfiguration; -import org.openslx.virtualization.configuration.VirtualizationConfiguration.UsbSpeed; +import org.openslx.virtualization.configuration.VirtualizationConfigurationException; +import org.openslx.virtualization.configuration.data.ConfigurationDataDozModServerToDozModClient; import org.openslx.vm.disk.DiskImage; import org.openslx.vm.disk.DiskImageException; +import org.openslx.vm.disk.DiskImageUtils; import org.openslx.vm.disk.DiskImageVmdk; public class VmWrapper { @@ -38,110 +40,74 @@ public class VmWrapper { private static final Logger LOGGER = Logger.getLogger(VmWrapper.class); public static void wrapVm(File diskFile, String imageName, byte[] machineDescription, - String virtualizerId, int osId, DiskImage diskImageInfo) throws MetaDataMissingException, + String virtualizerId, int osId, DiskImage diskImageInfo) throws VirtualizationConfigurationException, IOException { - if (!diskFile.exists()) - throw new FileNotFoundException("Disk file " + diskFile.getAbsolutePath() + " does not exist"); - if (machineDescription == null || machineDescription.length < 10) { - if (!TConst.VIRT_VMWARE.equals(virtualizerId)) { - throw new MetaDataMissingException(); - } - - if (diskImageInfo instanceof DiskImageVmdk) { + // check if virtualization configuration is missing + if (machineDescription == null) { + // configuration is not available + if (TConst.VIRT_VMWARE.equals(virtualizerId) && diskImageInfo instanceof DiskImageVmdk) { + // get fallback VMX if virtualizer is VMware with VMDK disk image final DiskImageVmdk vmdkImageInfo = DiskImageVmdk.class.cast( diskImageInfo ); try { machineDescription = VmWrapper.getFallbackVmx(vmdkImageInfo); } catch (DiskImageException e) { - throw new MetaDataMissingException(); + throw new VirtualizationConfigurationException("Can not get fallback VMX configuration!"); } } else { - throw new MetaDataMissingException(); + // there is no way to reconstruct a configuration for other virtualizer + throw new VirtualizationConfigurationException("Virtualization configuration is missing!"); } } - // Handle machine description to generate configuration file - VirtualizationConfiguration virtualizationConfig = VirtualizationConfiguration - .getInstance(MetaDataCache.getOperatingSystems(), machineDescription, machineDescription.length); - // Append disk & NAT - if (!virtualizationConfig.addDefaultNat() || !virtualizationConfig.addHddTemplate(diskFile, null, null)) { - throw new MetaDataMissingException(); + // get guest operating system if possible + OperatingSystem guestOs = null; + if (osId != 0) { + guestOs = MetaDataCache.getOsById(osId); } - // The guestOS should be in the virtualization configuration, but the user could have changed it - // by editing - // the image via the GUI. Those changes are not written back to the - // stored virtualization configuration - int osMaxMemMb = 0; - if (virtualizerId != null && osId != 0) { - OperatingSystem os = MetaDataCache.getOsById(osId); - if (os != null && os.virtualizerOsId != null) { - String virtOsId = os.virtualizerOsId.get(virtualizerId); - if (virtOsId != null) { - virtualizationConfig.setOs(virtOsId); - } - if (os.maxMemMb > 0) { - osMaxMemMb = os.maxMemMb; - } - } - } - virtualizationConfig.addDisplayName(imageName); - int mem = getMainMemoryMb() / 2 - 512; - if (mem < 1024) { - mem = 1024; - } - if (osMaxMemMb > 0 && mem > osMaxMemMb) { - mem = osMaxMemMb; - } - virtualizationConfig.addCpuCoreCount(1); - virtualizationConfig.addRam((mem / 4) * 4); - virtualizationConfig.addFloppy(0, null, true); - virtualizationConfig.addFloppy(1, null, true); - virtualizationConfig.addCdrom(""); // ISO-Based with no disk in drive - virtualizationConfig.addCdrom(null); // Autodetect real drive - if (virtualizationConfig.getMaxUsbSpeed() != UsbSpeed.USB3_0) { - virtualizationConfig.setMaxUsbSpeed(UsbSpeed.USB2_0); - } - virtualizationConfig.applySettingsForLocalEdit(); + // handle machine description to generate configuration file + final VirtualizationConfiguration virtualizationConfig = VirtualizationConfiguration + .getInstance(MetaDataCache.getOperatingSystems(), machineDescription, machineDescription.length); - // Output vm - String base = diskFile.getAbsolutePath(); - int dot = base.lastIndexOf('.'); - if (dot > 0) { - base = base.substring(0, dot); + // transform virtualization configuration for local editing + final ConfigurationLogicDozModServerToDozModClient downloadLogic = new ConfigurationLogicDozModServerToDozModClient(); + try { + downloadLogic.apply( virtualizationConfig, new ConfigurationDataDozModServerToDozModClient( imageName, + diskFile, guestOs, virtualizerId, getMainMemoryMb() ) ); + } catch ( TransformationException e ) { + throw new VirtualizationConfigurationException( e.getLocalizedMessage() ); } - String fileType = null; + // save BIOS if virtualizer is VMware if (virtualizationConfig instanceof VirtualizationConfigurationVmware) { - fileType = ".vmx"; - // Copy BIOS with both floppies enabled try { FileOutputStream output = new FileOutputStream(new File(diskFile.getAbsoluteFile().getParentFile(), "nvram")); InputStream input = ResourceLoader.getStream("/data/nvram"); IOUtils.copy(input, output); + input.close(); + output.close(); } catch (Exception e) { Gui.asyncMessageBox("Konnte das BIOS für die VM nicht kopieren", MessageType.ERROR, LOGGER, e); } - - } else if (virtualizationConfig instanceof VirtualizationConfigurationVirtualBox) { - fileType = ".vbox"; - } else if (virtualizationConfig instanceof VirtualizationConfigurationQemu) { - fileType = ".xml"; - } - if (fileType == null) { - LOGGER.warn("file type somehow unclear; application could stop working here!"); } - File vmFile = new File(base + fileType); + // save virtualization configuration as file to disk + final String baseFileName = FilenameUtils.removeExtension( diskFile.getAbsolutePath() ); + final String fileNameExtension = virtualizationConfig.getFileNameExtension(); + final File vmFile = new File(baseFileName + fileNameExtension); + + // delete original virtualization configuration file vmFile.delete(); + // actually write virtualization configuration to disk FileUtils.writeByteArrayToFile(vmFile, virtualizationConfig.getFilteredDefinitionArray()); } private static byte[] getFallbackVmx(DiskImageVmdk diskImageInfo) throws IOException, DiskImageException { - String vmx = ResourceLoader.getTextFile("/txt/vmx_template"); - return vmx.replace("%VM_HW_VERSION%", Integer.toString(diskImageInfo.getHwVersion())).getBytes( - StandardCharsets.UTF_8); + final String vmx = ResourceLoader.getTextFile("/txt/vmx_template"); + final short hwVersion = DiskImageUtils.versionToMajor(diskImageInfo.getHwVersion()); + return vmx.replace("%VM_HW_VERSION%", Short.toString(hwVersion)).getBytes(StandardCharsets.UTF_8); } /** @@ -165,10 +131,6 @@ public class VmWrapper { return fileName; } - public static class MetaDataMissingException extends Exception { - private static final long serialVersionUID = -7842986428831219758L; - } - private static int getMainMemoryMb() { MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); Object attribute; diff --git a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbLecture.java b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbLecture.java index 48915664..8701a722 100644 --- a/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbLecture.java +++ b/dozentenmodulserver/src/main/java/org/openslx/bwlp/sat/database/mappers/DbLecture.java @@ -31,7 +31,9 @@ import org.openslx.bwlp.thrift.iface.UserInfo; import org.openslx.util.Json; import org.openslx.util.Util; import org.openslx.virtualization.configuration.VirtualizationConfiguration; -import org.openslx.virtualization.configuration.VirtualizationConfiguration.UsbSpeed; +import org.openslx.virtualization.configuration.data.ConfigurationDataDozModServerToStatelessClient; +import org.openslx.virtualization.configuration.logic.ConfigurationLogicDozModServerToStatelessClient; +import org.openslx.virtualization.configuration.transformation.TransformationException; import com.google.gson.JsonParseException; @@ -555,10 +557,7 @@ public class DbLecture { TNotFoundException { LaunchData retval = new LaunchData(); byte[] config; - String lectureName; - String osKeyword; - boolean usbAccess; - VirtualizationConfiguration virtualizationConfig = null; + try (MysqlConnection connection = Database.getConnection()) { // Get required data about lecture and used image MysqlStatement stmt = connection.prepareStatement("SELECT" @@ -575,23 +574,40 @@ public class DbLecture { || rs.getLong("endtime") < now) { throw new TNotFoundException(); } + config = rs.getBytes("virtualizerconfig"); if (config == null) { return null; } + + final String lectureName = rs.getString("lecturename"); + final String osKeyword = rs.getString("virtoskeyword"); + final boolean usbAccess = rs.getBoolean("hasusbaccess"); + + // prepare virtualization configuration as part of the launch data + VirtualizationConfiguration virtualizationConfig = null; try { virtualizationConfig = VirtualizationConfiguration.getInstance(OperatingSystemList.get(), config, config.length); } catch (Exception e) { - LOGGER.error("virtualization config could not be initialized", e); + LOGGER.error("Virtualization configuration could not be initialized", e); return null; } - lectureName = rs.getString("lecturename"); - osKeyword = rs.getString("virtoskeyword"); - usbAccess = rs.getBoolean("hasusbaccess"); + + // modify virtualization configuration + try { + final ConfigurationLogicDozModServerToStatelessClient downloadLogic = new ConfigurationLogicDozModServerToStatelessClient(); + downloadLogic.apply(virtualizationConfig, + new ConfigurationDataDozModServerToStatelessClient(lectureName, osKeyword, usbAccess)); + } catch (TransformationException e) { + LOGGER.error("Virtualization configuration could not be modified", e); + return null; + } + retval.virtualizationConfig = virtualizationConfig; retval.legacyRunScript = rs.getString("runscript"); retval.netShares = DbLectureNetshare.getCombinedForLecture(connection, lectureId); retval.runScript = DbRunScript.getRunScriptsForLaunch(connection, lectureId, rs.getInt("osid")); + // Everything worked so far, update statistics counters MysqlStatement upStmt = connection.prepareStatement("UPDATE" + " lecture SET lastused = UNIX_TIMESTAMP(), usecount = usecount + 1" @@ -603,16 +619,7 @@ public class DbLecture { LOGGER.error("Query failed in DbLecture.getClientLaunchData()", e); throw e; } - virtualizationConfig.addDisplayName(lectureName); - if (osKeyword != null) { - virtualizationConfig.setOs(osKeyword); - } - virtualizationConfig.addHddTemplate("%VM_DISK_PATH%", "%VM_DISK_MODE%", "%VM_DISK_REDOLOGDIR%"); - virtualizationConfig.addEthernet(VirtualizationConfiguration.EtherType.NAT); // TODO: Use config - if (!usbAccess) { - virtualizationConfig.setMaxUsbSpeed(UsbSpeed.NONE); - } - virtualizationConfig.tweakForNonPersistent(); + return retval; } -- cgit v1.2.3-55-g7522