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.TreeMap; import org.apache.log4j.Logger; import org.openslx.bwlp.thrift.iface.OperatingSystem; import org.openslx.bwlp.thrift.iface.Virtualizer; import org.openslx.thrifthelper.TConst; import org.openslx.util.vm.QemuConfig.Header; import static org.openslx.util.vm.QemuConfig.Header.MACHINE; class QemuDDAccelMeta { public final boolean isPresent; public QemuDDAccelMeta(boolean present) { isPresent = present; } } class QemuHWVersionMeta { public final int version; public QemuHWVersionMeta(int vers) { version = vers; } } class QemuEthernetDevTypeMeta { public final String value; public QemuEthernetDevTypeMeta(String val) { value = val; } } class QemuSoundCardMeta { public final boolean isPresent; public final String value; public QemuSoundCardMeta(boolean present, String val) { isPresent = present; value = val; } } public final class QemuMetaData extends VmMetaData { private final Map arguments = new HashMap<>(); //to remove at the end. easier // the above map's elements will take the place of in the config string private QemuConfig config; private String setup; private TreeMap option; private static final Logger LOGGER = Logger.getLogger(QemuMetaData.class); private static final Virtualizer virtualizer = new Virtualizer(TConst.VIRT_QEMU, "QEMU-KVM"); private int cdromCounter = 0; private int driveCounter = 0; private int floppyCounter = 0; public static enum EthernetType { NAT("qnet1"), BRIDGED("qnet0"), HOST_ONLY("qnet2"); public final String vmnet; private EthernetType(String vnet) { this.vmnet = vnet; } } public QemuMetaData(List osList, File config) { super(osList); this.config = new QemuConfig(config); init(); } public QemuMetaData(List osList, byte[] vmContent, int length) throws IOException, UnsupportedVirtualizerFormatException { super(osList); this.config = new QemuConfig(vmContent, length); init(); } public void init() { registerVirtualHW(); displayName = config.getDisplayName(); setOs(config.getOsName()); isMachineSnapshot = config.isMachineSnapshot(); config.setHdds(); for (HardDisk hardDisk : config.getHdds()) { hdds.add(hardDisk); } } @Override public byte[] getFilteredDefinitionArray() { return config.toString(false).getBytes(StandardCharsets.UTF_8); } @Override public byte[] getDefinitionArray() { return config.toString(true).getBytes(StandardCharsets.UTF_8); } @Override public void applySettingsForLocalEdit() { //nothing for VmWare } @Override public boolean addHddTemplate(File diskImage, String hddMode, String redoDir) { option = new TreeMap<>(); String bus = "anychipset"; DriveBusType busType = DriveBusType.IDE; //drive option = config.get("[drive \"disk0\"]"); if (option != null) { option.replace("file", "\"" + diskImage.getAbsolutePath() + "\""); bus = option.get("if"); } switch (bus) { case "ide": busType = DriveBusType.IDE; break; case "scsi": busType = DriveBusType.SCSI; break; case "sata": //not available for Qemu. Others : sd, mtd, floppy, pflash, virtio break; default: break; } //device option = config.get("[dev0]"); hdds.add(new HardDisk(option.get("driver"), busType, diskImage.getAbsolutePath())); return true; } @Override public boolean addHddTemplate(String diskImagePath, String hddMode, String redoDir) { option = new TreeMap<>(); //drive option.put("file", "\"" + diskImagePath + "\""); option.put("if", "\"scsi\""); String status = (isMachineSnapshot == true ? "on" : "off"); option.put("snapshot", "\"" + status + "\""); config.set("[drive \"drive" + driveCounter + "\"]", option); //device option.put("drive", "\"drive" + driveCounter + "\""); option.put("driver", "scsi-hd"); config.set("[device]", option); hdds.add(new HardDisk("anychipset", DriveBusType.IDE, diskImagePath)); driveCounter++; return true; } @Override public boolean addDefaultNat() { //No arguments needed, default on nat. But cannot receive return true; } @Override public void setOs(String vendorOsId) { setOs(TConst.VIRT_QEMU, vendorOsId); } @Override public boolean addDisplayName(String name) { option = new TreeMap<>(); option.put("guest", "\"" + name + "\""); config.set("[name]", option); return true; } @Override public boolean addRam(int mem) { option = new TreeMap<>(); option.put("size", "\"" + mem + "\""); config.set("[memory]", option); return true; } @Override public void addFloppy(int index, String image, boolean readOnly) { option = new TreeMap<>(); if (readOnly) { option.put("readonly", "\"on\""); } else { option.put("readonly", "\"off\""); } option.put("if", "\"floppy\""); option.put("file", image); config.set("[drive \"floppy" + floppyCounter + "\"]", option); floppyCounter++; } @Override public boolean addCdrom(String image) { option = new TreeMap<>(); option.put("media", "\"cdrom\""); option.put("file", image); config.set("[drive \"cdrom" + cdromCounter + "\"]", option); cdromCounter++; return true; } @Override public boolean addCpuCoreCount(int nrOfCores) { option = new TreeMap<>(); option.put("cpus", "\"" + nrOfCores + "\""); config.set("[smp-opts]", option); return true; } @Override public void setSoundCard(VmMetaData.SoundCardType type) { //Not possible will be set as comment in config file } @Override public VmMetaData.SoundCardType getSoundCard() { //not possible to set just write comment VmMetaData.SoundCardType soundcard = null; return soundcard; } @Override public void setDDAcceleration(VmMetaData.DDAcceleration type) { //Not really used by qemu. TODO: } @Override public VmMetaData.DDAcceleration getDDAcceleration() { return DDAcceleration.OFF; } @Override public void setHWVersion(VmMetaData.HWVersion type) { //nothing... } @Override public VmMetaData.HWVersion getHWVersion() { return VmMetaData.HWVersion.DEFAULT; } @Override public void setEthernetDevType(int cardIndex, VmMetaData.EthernetDevType type) { QemuEthernetDevTypeMeta dev = networkCards.get(type); option = new TreeMap<>(); option.put("driver", "\"" + dev.value + "\""); option.put("netdev", "\"net" + cardIndex + "\""); config.set("[device]", option); } @Override public VmMetaData.EthernetDevType getEthernetDevType(int cardIndex) { QemuEthernetDevTypeMeta ethernetDevTypeMeta = null; for (String key : config.get().keySet()) { if (key.equals("[dev" + cardIndex + "]")) {//wont work dev0 if (config.get(key).get("netdev").equals("\"net" + cardIndex + "\"")) { String devs = config.get(key).get("driver"); for (EthernetDevType type : VmMetaData.EthernetDevType.values()) { ethernetDevTypeMeta = networkCards.get(type); if (ethernetDevTypeMeta == null) { continue; } if (devs.equals(ethernetDevTypeMeta.value)) { return type; } } } } } return EthernetDevType.AUTO; } @Override public boolean addEthernet(VmMetaData.EtherType type) { boolean ret = false; int index = 0; for (;; ++index) { TreeMap dev = config.get("[dev" + index + "]"); if (dev == null) { break; } else { if (dev.get("netdev") == null) { break; } } } switch (type) { case NAT: //netdev option = new TreeMap<>(); option.put("br", "nat1"); option.put("type", "bridge"); config.set("[netdev \"net" + index + "\"]", option); //device option = new TreeMap<>(); break; case BRIDGED: option = new TreeMap<>(); option.put("br", "'br0'"); option.put("type", "'bridge'"); config.set("[netdev \"net" + index + "\"]", option); break; case HOST_ONLY: //Dont know how to do it... break; default: // Should not come to this... break; } return ret; } @Override public Virtualizer getVirtualizer() { return virtualizer; } @Override public void enableUsb(boolean enabled) { option = new TreeMap<>(); if (enabled) { option.put("usb", "\"on\""); } else { option.put("usb", "\"off\""); } config.set(MACHINE.value(), option); } @Override public boolean disableSuspend() { return false; } @Override public void registerVirtualHW() { soundCards.put(VmMetaData.SoundCardType.NONE, new QemuSoundCardMeta(false, null)); soundCards.put(VmMetaData.SoundCardType.DEFAULT, new QemuSoundCardMeta(true, "ich6")); soundCards.put(VmMetaData.SoundCardType.AC, new QemuSoundCardMeta(true, "ac97")); soundCards.put(VmMetaData.SoundCardType.ES, new QemuSoundCardMeta(true, "es1370")); soundCards.put(VmMetaData.SoundCardType.SOUND_BLASTER, new QemuSoundCardMeta(true, "sb16")); ddacc.put(DDAcceleration.OFF, new QemuDDAccelMeta(false)); ddacc.put(DDAcceleration.ON, new QemuDDAccelMeta(true)); hwversion.put(HWVersion.DEFAULT, new QemuHWVersionMeta(0)); networkCards.put(EthernetDevType.VIRTIO, new QemuEthernetDevTypeMeta("virtio-net-pci")); networkCards.put(EthernetDevType.E1000, new QemuEthernetDevTypeMeta("e1000")); networkCards.put(EthernetDevType.PCNET32, new QemuEthernetDevTypeMeta("pcnet")); networkCards.put(EthernetDevType.RTL8139, new QemuEthernetDevTypeMeta("rtl8139")); } }