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; import java.lang.management.ManagementFactory; import java.nio.charset.StandardCharsets; import javax.management.AttributeNotFoundException; import javax.management.InstanceNotFoundException; import javax.management.MBeanException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.ObjectName; import javax.management.ReflectionException; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.log4j.Logger; import org.openslx.bwlp.thrift.iface.OperatingSystem; 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.util.vm.DiskImage; import org.openslx.util.vm.QemuMetaData; import org.openslx.util.vm.VboxMetaData; import org.openslx.util.vm.VmMetaData; import org.openslx.util.vm.VmMetaData.UsbSpeed; import org.openslx.util.vm.VmwareMetaData; 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, 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(); } machineDescription = getFallbackVmx(diskImageInfo); } // Handle machine description to generate configuration file VmMetaData vmMeta = VmMetaData.getInstance(MetaDataCache.getOperatingSystems(), machineDescription, machineDescription.length); // Append disk & NAT if (!vmMeta.addDefaultNat() || !vmMeta.addHddTemplate(diskFile, null, null)) { throw new MetaDataMissingException(); } // The guestOS should be in the vmx, but the user could have changed it // by editing // the image via the GUI. Those changes are not written back to the // stored vmx 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) { vmMeta.setOs(virtOsId); } if (os.maxMemMb > 0) { osMaxMemMb = os.maxMemMb; } } } vmMeta.addDisplayName(imageName); int mem = getMainMemoryMb() / 2 - 512; if (mem < 1024) { mem = 1024; } if (osMaxMemMb > 0 && mem > osMaxMemMb) { mem = osMaxMemMb; } vmMeta.addCpuCoreCount(1); vmMeta.addRam((mem / 4) * 4); vmMeta.addFloppy(0, null, true); vmMeta.addFloppy(1, null, true); vmMeta.addCdrom(""); // ISO-Based with no disk in drive vmMeta.addCdrom(null); // Autodetect real drive if (vmMeta.getMaxUsbSpeed() != UsbSpeed.USB3_0) { vmMeta.setMaxUsbSpeed(UsbSpeed.USB2_0); } vmMeta.applySettingsForLocalEdit(); // Output vm String base = diskFile.getAbsolutePath(); int dot = base.lastIndexOf('.'); if (dot > 0) { base = base.substring(0, dot); } String fileType = null; if (vmMeta instanceof VmwareMetaData) { 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); } catch (Exception e) { Gui.asyncMessageBox("Konnte das BIOS für die VM nicht kopieren", MessageType.ERROR, LOGGER, e); } } else if (vmMeta instanceof VboxMetaData) { fileType = ".vbox"; } else if (vmMeta instanceof QemuMetaData) { fileType = "_startCommand.txt"; } if (fileType == null) { LOGGER.warn("file type somehow unclear; application could stop working here!"); } File vmFile = new File(base + fileType); vmFile.delete(); // actually write vmx to disk FileUtils.writeByteArrayToFile(vmFile, vmMeta.getFilteredDefinitionArray()); } private static byte[] getFallbackVmx(DiskImage diskImageInfo) throws IOException { String vmx = ResourceLoader.getTextFile("/txt/vmx_template"); return vmx.replace("%VM_HW_VERSION%", Integer.toString(diskImageInfo.hwVersion)).getBytes( StandardCharsets.UTF_8); } /** * Generates a filename based on the given imageName and with the proper * extension. The given imageName is sanitized and shortened. * * @param imageName desired basename of image file * @param extension desired extension * @return the generated name */ public static String generateFilename(String imageName, String extension) { String fileName = imageName.replaceAll("[^a-zA-Z0-9_\\.\\-]+", "_"); if (fileName.length() > 50) { fileName = fileName.substring(0, 50); } if (extension == null || extension.isEmpty()) { fileName += ".img"; } else { fileName += "." + extension; } return fileName; } public static class MetaDataMissingException extends Exception { private static final long serialVersionUID = -7842986428831219758L; } private static int getMainMemoryMb() { MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); Object attribute; try { attribute = mBeanServer.getAttribute(new ObjectName("java.lang", "type", "OperatingSystem"), "TotalPhysicalMemorySize"); } catch (AttributeNotFoundException | InstanceNotFoundException | MalformedObjectNameException | MBeanException | ReflectionException e) { return -1; } try { return (int) (Long.parseLong(attribute.toString()) / (1024 * 1024)); } catch (Exception e) { return -1; } } }