summaryrefslogblamecommitdiffstats
path: root/src/main/java/org/openslx/util/vm/VmwareMetaData.java
blob: 1c84a72e879b267cf6c17305d1010b20c5465973 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14

                            
                    
                           









                                                     
                                                 
                             
                                                    
 
                                                
 
                                                                                    
 
                                                                                           
 

                                                                                                         
 

                                                                   
 

                                          

                              





                                                                                                                                        




                                                                      



                                                                                   
                       

         



                                                                                          
                                       

         


                                                                            
                 
                                                                                          
                                                         

                               
                                                    
                                                                           

                                                                  
                                                
                                         
                                                                                            
                                                                  
                                                    
                                                                
                                                                                                                   

                                                              
                                                                       
                                                               
                                                                               
                                                                
                                                                               

                                                                
                                                                                                    

                         
 
                                         




                                                                                

                         

         

                                                            
         
 


                                                                       

         
                                                                        
                                                               
                                           


                                                                




                                       
                                                           

                                                 

                               
                                                     
                                            

                               


                                                                                                      


                 


                                                                                                            
                                                      
                                                             
                 
                                                               
                                              


                                                                                 




                                                              

                                                                  
                                              
                                                                  
                 
                                                              
                                                  
                                                                   
                                                

                                                                     

                 
 
                 
                                                                                       


                                                           


                                                                                                                    

                                     
                                                             
                              
                              

                                          
                                                            




                                                           


                                                                         


                              
                                                                               


                                     









                                                                     

                            
 
                 
                                                                                             

                                 


                                                                                                                    

                                     
                                                             
                              
                              
                         
                                          
                                                            
                              
                          
                                                           
                          
                                           


                                                                         
                         
                              
                        
                                                                               

                                     
                      









                                                                     
                            

         


                                                               


                            
                                                       
                              

                                                                                

                                      
                                                

         
                                                                  
                                                  






                                                                        



                            
 
                                                                          
                                              






                                                                      
                        















                                                                                                        
                                        


                                                                                         





                                            
 

                                                           
         
 

                                                  

         

                                                        

                            
 

                                                    


                            

                                                              


                            


                                                   


                 

                                                                                     

         

                                                                                      

         
                 
                                             
                                   

         
                                     




                                                
                                          



                                                                                              
                                         




                                                                                                
                                          

                                                                                                    

         

                                                                      


                                          
                                                   



                                          
                 


                                                                

         
                 

                                                                           

         

                                            


                



                                                                                                                   




                                                
                                                                                    





                                                 



                                                                        
                        
                                                          


                 

                                                                                          

                                                  



                                                                           




                                                    


                         

                                                  



                                                
                                                                       




                                                 

                                                                       

         

                                                   
                                                 
                        
                                                  
                 


                                   








                                                                                                                                                                        



                                                
                                                           




                                                 

                                                                          

         



                                                                                      

                                           
                 
                                      


                                  


                                                                                                                                



                                                
                                                                     




                                                 


                                                                                        
                        
                                                                              


                 


                                                                                 
 

                                                                               


                                                    
                 
                                            
         
 
                 
                               
                                                  
 
         

                 
                                                       


                                                  
 
package org.openslx.util.vm;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;
import org.openslx.bwlp.thrift.iface.OperatingSystem;
import org.openslx.bwlp.thrift.iface.Virtualizer;
import org.openslx.util.Util;
import org.openslx.util.vm.VmwareConfig.ConfigEntry;

public class VmwareMetaData extends VmMetaData {

	private static final Logger LOGGER = Logger.getLogger(VmwareMetaData.class);

	private static final Virtualizer virtualizer = new Virtualizer("vmware", "VMware");

	private static final Pattern hddKey = Pattern.compile("^(ide\\d|scsi\\d|sata\\d):?(\\d)?\\.(.*)",
			Pattern.CASE_INSENSITIVE);

	// Lowercase list of allowed settings for upload (as regex)
	private static final Pattern[] whitelist;

	private final VmwareConfig config;

	// Init static members
	static {
		String[] list = { "^guestos", "^uuid\\.bios", "^config\\.version", "^ehci\\.", "^mks\\.enable3d",
				"^virtualhw\\.", "^sound\\.", "\\.pcislotnumber$", "^pcibridge", "\\.virtualdev$", "^tools\\.syncTime$",
				"^time\\.synchronize", "^bios\\.bootDelay", "^rtc\\.", "^xhci\\." };
		whitelist = new Pattern[list.length];
		for (int i = 0; i < list.length; ++i) {
			whitelist[i] = Pattern.compile(list[i].toLowerCase());
		}
	}

	private final Map<String, Controller> disks = new HashMap<>();

	public VmwareMetaData(List<OperatingSystem> osList, File file)
			throws IOException, UnsupportedVirtualizerFormatException {
		super(osList);
		this.config = new VmwareConfig(file);
		init();
	}

	public VmwareMetaData(List<OperatingSystem> osList, byte[] vmxContent, int length)
			throws UnsupportedVirtualizerFormatException {
		super(osList);
		this.config = new VmwareConfig(vmxContent, length); // still unfiltered
		init(); // now filtered
	}

	private void init() {
		for (Entry<String, ConfigEntry> entry : config.entrySet()) {
			handleLoadEntry(entry);
		}
		// if we find this tag, we already went through the hdd's - so we're done.
		if (config.get("#SLX_HDD_BUS") != null) {
			return;
		}
		// Now find the HDDs and add to list
		for (Entry<String, Controller> cEntry : disks.entrySet()) {
			Controller controller = cEntry.getValue();
			String controllerType = cEntry.getKey();
			if (!controller.present)
				continue;
			for (Entry<String, Device> dEntry : controller.devices.entrySet()) {
				Device device = dEntry.getValue();
				if (!device.present)
					continue; // Not present
				if (device.deviceType != null && !device.deviceType.toLowerCase().endsWith("disk"))
					continue; // Not a HDD
				DriveBusType bus = null;
				if (controllerType.startsWith("ide")) {
					bus = DriveBusType.IDE;
				} else if (controllerType.startsWith("scsi")) {
					bus = DriveBusType.SCSI;
				} else if (controllerType.startsWith("sata")) {
					bus = DriveBusType.SATA;
				}
				hdds.add(new HardDisk(controller.virtualDev, bus, device.filename));
			}
		}

		// Add HDD to cleaned vmx
		if (!hdds.isEmpty()) {
			HardDisk hdd = hdds.get(0);
			addFiltered("#SLX_HDD_BUS", hdd.bus.toString());
			if (hdd.chipsetDriver != null) {
				addFiltered("#SLX_HDD_CHIP", hdd.chipsetDriver);
			}
		}
	}

	private void addFiltered(String key, String value) {
		config.set(key, value).filtered(true);
	}

	private boolean isSetAndTrue(String key) {
		String value = config.get(key);
		return value != null && value.equalsIgnoreCase("true");
	}

	private void handleLoadEntry(Entry<String, ConfigEntry> entry) {
		String lowerKey = entry.getKey().toLowerCase();
		// Cleaned vmx construction
		for (Pattern exp : whitelist) {
			if (exp.matcher(lowerKey).find()) {
				entry.getValue().filtered(true);
				break;
			}
		}
		//
		// Dig Usable meta data
		String value = entry.getValue().getValue();
		if (lowerKey.equals("guestos")) {
			setOs("vmware", value);
			return;
		}
		if (lowerKey.equals("displayname")) {
			displayName = value;
			return;
		}
		Matcher hdd = hddKey.matcher(entry.getKey());
		if (hdd.find()) {
			handleHddEntry(hdd.group(1).toLowerCase(), hdd.group(2), hdd.group(3), value);
		}
	}

	private void handleHddEntry(String controllerStr, String deviceStr, String property, String value) {
		Controller controller = disks.get(controllerStr);
		if (controller == null) {
			controller = new Controller();
			disks.put(controllerStr, controller);
		}
		if (deviceStr == null || deviceStr.isEmpty()) {
			// Controller property
			if (property.equalsIgnoreCase("present")) {
				controller.present = Boolean.parseBoolean(value);
			} else if (property.equalsIgnoreCase("virtualDev")) {
				controller.virtualDev = value;
			}
			return;
		}
		// Device property
		Device device = controller.devices.get(deviceStr);
		if (device == null) {
			device = new Device();
			controller.devices.put(deviceStr, device);
		}
		if (property.equalsIgnoreCase("deviceType")) {
			device.deviceType = value;
		} else if (property.equalsIgnoreCase("filename")) {
			device.filename = value;
		} else if (property.equalsIgnoreCase("present")) {
			device.present = Boolean.parseBoolean(value);
		}
	}

	@Override
	public boolean addHddTemplate(File diskImage, String hddMode, String redoDir) {
		String diskImagePath = diskImage.getName();
		DriveBusType bus;
		try {
			bus = DriveBusType.valueOf(config.get("#SLX_HDD_BUS"));
		} catch (Exception e) {
			LOGGER.warn("Unknown bus type: " + config.get("#SLX_HDD_BUS") + ". Cannot add hdd config.");
			return false;
		}
		String chipset = config.get("#SLX_HDD_CHIP");
		String prefix;
		switch (bus) {
		case IDE:
			prefix = "ide0:0";
			addFiltered("ide0.present", "TRUE");
			break;
		case SATA:
			// Cannot happen?... use lsisas1068
		case SCSI:
			prefix = "scsi0:0";
			addFiltered("scsi0.present", "TRUE");
			if (chipset != null) {
				addFiltered("scsi0.virtualDev", chipset);
			}
			break;
		default:
			LOGGER.warn("Unknown HDD bus type: " + bus.toString());
			return false;
		}
		// Gen
		addFiltered(prefix + ".present", "TRUE");
		addFiltered(prefix + ".deviceType", "disk");
		addFiltered(prefix + ".fileName", diskImagePath);
		if (hddMode != null) {
			addFiltered(prefix + ".mode", hddMode);
			addFiltered(prefix + ".redo", "");
			addFiltered(prefix + ".redoLogDir", redoDir);
		}
		config.remove("#SLX_HDD_BUS");
		config.remove("#SLX_HDD_CHIP");
		return true;
	}

	@Override
	public boolean addHddTemplate(String diskImagePath, String hddMode, String redoDir) {
		DriveBusType bus;
		try {
			bus = DriveBusType.valueOf(config.get("#SLX_HDD_BUS"));
		} catch (Exception e) {
			LOGGER.warn("Unknown bus type: " + config.get("#SLX_HDD_BUS") + ". Cannot add hdd config.");
			return false;
		}
		String chipset = config.get("#SLX_HDD_CHIP");
		String prefix;
		switch (bus) {
		case IDE:
			prefix = "ide0:0";
			addFiltered("ide0.present", "TRUE");
			break;
		case SATA:
			// Cannot happen?... use lsisas1068
		case SCSI:
			prefix = "scsi0:0";
			addFiltered("scsi0.present", "TRUE");
			if (chipset != null) {
				addFiltered("scsi0.virtualDev", chipset);
			}
			break;
		default:
			LOGGER.warn("Unknown HDD bus type: " + bus.toString());
			return false;
		}
		// Gen
		addFiltered(prefix + ".present", "TRUE");
		addFiltered(prefix + ".deviceType", "disk");
		addFiltered(prefix + ".fileName", diskImagePath);
		if (hddMode != null) {
			addFiltered(prefix + ".mode", hddMode);
			addFiltered(prefix + ".redo", "");
			addFiltered(prefix + ".redoLogDir", redoDir);
		}
		config.remove("#SLX_HDD_BUS");
		config.remove("#SLX_HDD_CHIP");
		return true;
	}

	public boolean addDefaultNat() {
		addFiltered("ethernet0.present", "TRUE");
		addFiltered("ethernet0.connectionType", "nat");
		return true;
	}

	public boolean addEthernet(EthernetType type) {
		int index = 0;
		for (;; ++index) {
			if (config.get("ethernet" + index + ".present") == null)
				break;
		}
		return addEthernet(index, type);
	}

	public boolean addEthernet(int index, EthernetType type) {
		String ether = "ethernet" + index;
		addFiltered(ether + ".present", "TRUE");
		addFiltered(ether + ".connectionType", "custom");
		addFiltered(ether + ".vnet", type.vmnet);
		if (config.get(ether + ".virtualDev") == null) {
			String dev = config.get("ethernet0.virtualDev");
			if (dev != null) {
				addFiltered(ether + ".virtualDev", dev);
			}
		}
		return true;
	}

	public void addFloppy(int index, String image, boolean readOnly) {
		String pre = "floppy" + index;
		addFiltered(pre + ".present", "TRUE");
		if (image == null) {
			addFiltered(pre + ".startConnected", "FALSE");
			addFiltered(pre + ".fileType", "device");
			config.remove(pre + ".fileName");
			config.remove(pre + ".readonly");
			addFiltered(pre + ".autodetect", "TRUE");
		} else {
			addFiltered(pre + ".startConnected", "TRUE");
			addFiltered(pre + ".fileType", "file");
			addFiltered(pre + ".fileName", image);
			addFiltered(pre + ".readonly", vmBoolean(readOnly));
			config.remove(pre + ".autodetect");
		}
	}

	public boolean addCdrom(String image) {
		for (String port : new String[] { "ide0:0", "ide0:1", "ide1:0", "ide1:1", "scsi0:1" }) {
			if (!isSetAndTrue(port + ".present")) {
				addFiltered(port + ".present", "TRUE");
				if (image == null) {
					addFiltered(port + ".autodetect", "TRUE");
					addFiltered(port + ".deviceType", "cdrom-raw");
					config.remove(port + ".fileName");
				} else {
					config.remove(port + ".autodetect");
					addFiltered(port + ".deviceType", "cdrom-image");
					addFiltered(port + ".fileName", image);
				}
				return true;
			}
		}
		return false;
	}

	private static String vmBoolean(boolean var) {
		return Boolean.toString(var).toUpperCase();
	}

	private static String vmInteger(int val) {
		return Integer.toString(val);
	}

	public boolean disableSuspend() {
		addFiltered("suspend.disabled", "TRUE");
		return true;
	}

	public boolean addDisplayName(String name) {
		addFiltered("displayName", name);
		return true;
	}

	public boolean addRam(int mem) {
		addFiltered("memsize", Integer.toString(mem));
		return true;
	}

	public void setOs(String vendorOsId) {
		addFiltered("guestOS", vendorOsId);
		setOs("vmware", vendorOsId);
	}

	@Override
	public byte[] getFilteredDefinitionArray() {
		return config.toString(true, false).getBytes(StandardCharsets.UTF_8);
	}

	public byte[] getDefinitionArray() {
		return config.toString(false, false).getBytes(StandardCharsets.UTF_8);
	}

	@Override
	public Virtualizer getVirtualizer() {
		return virtualizer;
	}

	private static class Device {
		public boolean present = false;
		public String deviceType = null;
		public String filename = null;

		@Override
		public String toString() {
			return filename + " is " + deviceType + " (present: " + present + ")";
		}
	}

	private static class Controller {
		public boolean present = true; // Seems to be implicit, seen at least for IDE...
		public String virtualDev = null;
		Map<String, Device> devices = new HashMap<>();

		@Override
		public String toString() {
			return virtualDev + " is (present: " + present + "): " + devices.toString();
		}
	}

	public static enum EthernetType {
		NAT("vmnet1"), BRIDGED("vmnet0"), HOST_ONLY("vmnet2");

		public final String vmnet;

		private EthernetType(String vnet) {
			this.vmnet = vnet;
		}
	}

	@Override
	public void enableUsb(boolean enabled) {
		addFiltered("usb.present", vmBoolean(enabled));
		addFiltered("ehci.present", vmBoolean(enabled));
	}

	@Override
	public void applySettingsForLocalEdit() {
		addFiltered("gui.applyHostDisplayScalingToGuest", "FALSE");
	}

	public String getValue(String key) {
		return config.get(key);
	}

	// SOUND
	public static enum SoundCardType {
		NONE(false, null, "None"), DEFAULT(true, null, "(default)"), SOUND_BLASTER(true, "sb16",
				"Sound Blaster 16"), ES(true, "es1371",
						"ES 1371"), HD_AUDIO(true, "hdaudio", "Intel Integrated HD Audio");

		public final boolean isPresent;
		public final String value;
		public final String displayName;

		private SoundCardType(boolean present, String value, String dName) {
			this.isPresent = present;
			this.value = value;
			this.displayName = dName;
		}
	}

	public void setSoundCard(SoundCardType type) {
		addFiltered("sound.present", vmBoolean(type.isPresent));
		if (type.value != null) {
			addFiltered("sound.virtualDev", type.value);
		} else {
			config.remove("sound.virtualDev");
		}
	}

	public SoundCardType getSoundCard() {
		if (!isSetAndTrue("sound.present") || !isSetAndTrue("sound.autodetect")) {
			return SoundCardType.NONE;
		}
		String current = config.get("sound.virtualDev");
		if (current != null) {
			for (SoundCardType type : SoundCardType.values()) {
				if (current.equals(type.value)) {
					return type;
				}
			}
		}
		return SoundCardType.DEFAULT;
	}

	// 3DAcceleration
	public static enum DDAcceleration {
		OFF(false, "Off"), ON(true, "On");

		public final boolean isPresent;
		public final String displayName;

		private DDAcceleration(boolean present, String dName) {
			this.isPresent = present;
			this.displayName = dName;
		}
	}

	public void setDDAcceleration(DDAcceleration type) {
		addFiltered("mks.enable3d", vmBoolean(type.isPresent));
	}

	public DDAcceleration getDDAcceleration() {
		if (isSetAndTrue("mks.enable3d")) {
			return DDAcceleration.ON;
		} else {
			return DDAcceleration.OFF;
		}
	}

	// Virtual hardware version
	public static enum HWVersion {
		NONE(0, "(invalid)"), THREE(3, "  3 (Workstation 4/5, Player 1)"), FOUR(4,
				"  4 (Workstation 4/5, Player 1/2, Fusion 1)"), SIX(6, "  6 (Workstation 6)"), SEVEN(7,
						"  7 (Workstation 6.5/7, Player 3, Fusion 2/3)"), EIGHT(8,
								"  8 (Workstation 8, Player/Fusion 4)"), NINE(9,
										"  9 (Workstation 9, Player/Fusion 5)"), TEN(10,
												"10 (Workstation 10, Player/Fusion 6)"), ELEVEN(11,
														"11 (Workstation 11, Player/Fusion 7)"), TWELVE(12,
																"12 (Workstation/Player 12, Fusion 8)");

		public final int version;
		public final String displayName;

		private HWVersion(int vers, String dName) {
			this.version = vers;
			this.displayName = dName;
		}
	}

	public void setHWVersion(HWVersion type) {
		addFiltered("virtualHW.version", vmInteger(type.version));
	}

	public HWVersion getHWVersion() {
		int currentValue = Util.parseInt(config.get("virtualHW.version"), -1);
		for (HWVersion ver : HWVersion.values()) {
			if (currentValue == ver.version) {
				return ver;
			}
		}
		return HWVersion.NONE;
	}

	// Virtual network adapter
	public static enum EthernetDevType {
		AUTO(null, "(default)"), PCNET32("vlance", "AMD PCnet32"), E1000("e1000", "Intel E1000 (PCI)"), E1000E("e1000e",
				"Intel E1000e (PCI-Express)"), VMXNET("vmxnet", "VMXnet"), VMXNET3("vmxnet3", "VMXnet 3");

		public final String value;
		public final String displayName;

		private EthernetDevType(String value, String dName) {
			this.value = value;
			this.displayName = dName;
		}
	}

	public void setEthernetDevType(int cardIndex, EthernetDevType type) {
		if (type.value != null) {
			addFiltered("ethernet" + cardIndex + ".virtualDev", type.value);
		} else {
			config.remove("ethernet" + cardIndex + ".virtualDev");
		}
	}

	public EthernetDevType getEthernetDevType(int cardIndex) {
		String temp = config.get("ethernet" + cardIndex + ".virtualDev");
		if (temp != null) {

			for (EthernetDevType type : EthernetDevType.values()) {
				if (temp.equals(type.value)) {
					return type;
				}
			}
		}
		return EthernetDevType.AUTO;
	}

	@Override
	public void reWrite() {
		// TODO Auto-generated method stub

	}

	@Override
	public boolean addCpuCoreCount(int nrOfCores) {
		// TODO Auto-generated method stub
		return false;
	}
}