package org.openslx.dozmod.util;
import java.io.File;
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.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.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.virtualization.configuration.VirtualizationConfiguration;
import org.openslx.virtualization.configuration.VirtualizationConfigurationException;
import org.openslx.virtualization.configuration.VirtualizationConfigurationQemu;
import org.openslx.virtualization.configuration.VirtualizationConfigurationVmware;
import org.openslx.virtualization.configuration.data.ConfigurationDataDozModServerToDozModClient;
import org.openslx.virtualization.configuration.logic.ConfigurationLogicDozModServerToDozModClient;
import org.openslx.virtualization.configuration.transformation.TransformationException;
import org.openslx.virtualization.disk.DiskImage;
import org.openslx.virtualization.disk.DiskImageException;
import org.openslx.virtualization.disk.DiskImageVmdk;
public class VmWrapper {
private static final Logger LOGGER = LogManager.getLogger(VmWrapper.class);
public static void wrapVm(File diskFile, String imageName, byte[] machineDescription,
String virtualizerId, int osId, DiskImage diskImageInfo) throws VirtualizationConfigurationException,
IOException {
// 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 VirtualizationConfigurationException("Can not get fallback VMX configuration!");
}
} else {
// there is no way to reconstruct a configuration for other virtualizer
throw new VirtualizationConfigurationException("Virtualization configuration is missing!");
}
}
// get guest operating system if possible
OperatingSystem guestOs = null;
if (osId != 0) {
guestOs = MetaDataCache.getOsById(osId);
}
// handle machine description to generate configuration file
final VirtualizationConfiguration virtualizationConfig = VirtualizationConfiguration
.getInstance(MetaDataCache.getOperatingSystems(), machineDescription, machineDescription.length);
// transform virtualization configuration for local editing
byte[] configuration = null;
try {
final ConfigurationLogicDozModServerToDozModClient downloadLogic = new ConfigurationLogicDozModServerToDozModClient();
downloadLogic.apply( virtualizationConfig, new ConfigurationDataDozModServerToDozModClient( imageName,
diskFile, guestOs, virtualizerId, getMainMemoryMb() ) );
configuration = virtualizationConfig.getConfigurationAsByteArray();
} catch ( TransformationException e ) {
throw new VirtualizationConfigurationException( e.getLocalizedMessage() );
}
// save BIOS if virtualizer is VMware
if (virtualizationConfig instanceof VirtualizationConfigurationVmware) {
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 VirtualizationConfigurationQemu && OsHelper.isLinux() ) {
try {
final VirtualizationConfigurationQemu virtualizationConfigQemu = VirtualizationConfigurationQemu.class
.cast( virtualizationConfig );
virtualizationConfigQemu.transformOsLoader();
} catch ( VirtualizationConfigurationException | ClassCastException e ) {
Gui.asyncMessageBox( "Konnte das BIOS für die VM nicht anpassen", MessageType.ERROR, LOGGER, e );
}
}
// 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, configuration);
}
private static byte[] getFallbackVmx(DiskImageVmdk diskImageInfo) throws IOException, DiskImageException {
final String vmx = ResourceLoader.getTextFile("/txt/vmx_template");
final short hwVersion = diskImageInfo.getHwVersion().getMajor();
return vmx.replace("%VM_HW_VERSION%", Short.toString(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;
}
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;
}
}
}