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<QemuSoundCardMeta, QemuDDAccelMeta, QemuHWVersionMeta, QemuEthernetDevTypeMeta> {
private final Map<String, String> arguments = new HashMap<>(); //to remove at the end. easier
// the above map's elements will take the place of <args> in the config string
private QemuConfig config;
private String setup;
private TreeMap<String, String> 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<OperatingSystem> osList, File config) {
super(osList);
this.config = new QemuConfig(config);
init();
}
public QemuMetaData(List<OperatingSystem> 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<String, String> 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"));
}
}