package org.openslx.util.vm;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import org.apache.log4j.Logger;
import static org.openslx.util.vm.QemuConfig.Header.*;
import org.openslx.util.vm.VmMetaData.DriveBusType;
public final class QemuConfig {
private static final Logger LOGGER = Logger.getLogger(QemuConfig.class);
private Map<String, TreeMap<String, String>> entries = new LinkedHashMap<>();
private String osName = new String();
private ArrayList<VmMetaData.HardDisk> hddsArray = new ArrayList<>();
// BOOT("netdev", "net0") -> toString -> "[netdev "net0"]"
public static enum Header {
BOOT("[boot-opts]", "asd"), DEV("[dev"), DEVICE("[device]"), DRIVE("[drive"),
MACHINE("[machine]"), MEMORY("[memory]"), NAME("[name]"),
NETDEV("[netdev "), SMP("[smp-opts]");
private final String header;
private Header(String header. String id){
this.header = header;
}
public String value(){
return this.header;
}
}
public QemuConfig(byte[] vmContent, int length) {
//transform byte[] to arralist sorted
ArrayList<String> result;
BufferedReader stream = null;
try {
stream = new BufferedReader(
new InputStreamReader(
new ByteArrayInputStream(vmContent, 0, length), StandardCharsets.ISO_8859_1));
result = new ArrayList<>();
String line;
while ((line = stream.readLine()) != null) {
if (line.startsWith("#") == false) {
if (line.isEmpty() == false) {
if (line.contains(DEV.value())) {
result.add(DEVICE.value());
} else {
result.add(line.trim());
}
}
}
}
stream.close();
stream = null;
} catch (IOException e) {
result = null;
} finally {
if (stream != null) {
try {
stream.close();
stream = null;
} catch (IOException ioe2) {
}
}
}
init(result);
}
public QemuConfig(File configFile) {
//Transform file into byte[]/arraylist
ArrayList<String> result;
BufferedReader stream = null;
try {
stream = new BufferedReader(
new InputStreamReader(
new FileInputStream(configFile), StandardCharsets.ISO_8859_1));
result = new ArrayList<>();
String line;
while ((line = stream.readLine()) != null) {
if (line.startsWith("#") == false) {
if (line.isEmpty() == false) {
result.add(line.trim());
}
}
}
stream.close();
stream = null;
} catch (IOException e) {
result = null;
} finally {
if (stream != null) {
try {
stream.close();
stream = null;
} catch (IOException ioe2) {
}
}
}
init(result);
}
public void init(ArrayList<String> lines) {
int index = -1;
int nbDev = 0;
Device dev;
TreeMap<String, String> options = new TreeMap<>();
if (lines != null) {
for (String option : lines) {
if (option.startsWith("[")) { //key only
if (option.equals(Header.DEVICE.value())) {
dev = new Device();
dev.setName(DEV.value()+ nbDev + "]");
option = dev.getName();
nbDev++;
}
entries.put(option, null);
options = new TreeMap();
index++;
} else if (index == -1) {
// In case file doesnt begin with header
LOGGER.error("This config file is invalid. Check syntax. Must begin with [...]");
} else {
// adding value to key
String[] opt = option.split("=");
options.put(opt[0].trim(), opt[1].trim());
entries.keySet();
String key = (String) entries.keySet().toArray()[index];
entries.put(key, options);
}
}
}
}
public TreeMap<String, String> get(String key) {
TreeMap<String, String> value = null;
if (entries.containsKey(key)) {
value = entries.get(key);
}
return value; //value of key
}
public void set(String key, TreeMap value) {
entries.put(key, value);
}
public TreeMap<String, TreeMap<String, String>> get() {
return (TreeMap<String, TreeMap<String, String>>) entries;
}
public String getDisplayName() {
String result = "";
if (entries.containsKey(NAME.value())) {
result = (String) entries.get(NAME.value()).get("guest");
result = result.replace("\"", "");
}
return result;
}
public boolean isMachineSnapshot() {
boolean isSnapshot = false;
String[] idDrive = null;
for (String key : entries.keySet()) {
if (key.contains(DRIVE.value())) {
idDrive = key.split("\"");
}
}
String active = entries.get(DRIVE.value()+" \"" + idDrive[1] + "\"]").get("snapshot");
active = active.replace("\"", "");
if (active != null && active.equals("on")) {
isSnapshot = true;
}
return isSnapshot;
}
public void setOsName() {
//It is not defined in config file. Using dummy name. Will be set in combo box later
osName = "QemuOS";
}
public String getOsName() {
return osName;
}
public void setHdds() {
String[] idDrive = null;
String filename = null;
DriveBusType bus = null;
String controllerDevice = null;
for (String entry : entries.keySet()) {
if (entry.contains(DRIVE.value())) {
idDrive = entry.split("\"");
//Get Path
filename = entries.get(entry).get("file");
filename = filename.replace("\"", "");
if (filename == null) {
LOGGER.error("Please make sure your harddrive has a path");
}
//Bus Type
String busType = entries.get(entry).get("if");
busType = busType.replace("\"", "");
if (busType == null) {
LOGGER.error("Please make sure your harddrive has a bus");
} else {
switch (busType) {
case "ide":
bus = DriveBusType.IDE;
break;
case "scsi":
bus = DriveBusType.SCSI;
break;
case "sata":
//not available for Qemu. Others : sd, mtd, floppy, pflash, virtio
break;
default:
break;
}
}
}
if (entry.contains(DEV.value())) {
String drive = entries.get(entry).get("drive");
drive = drive.replace("\"", "");
if (drive != null && drive.equals(idDrive[1])) {
controllerDevice = entries.get(entry).get("driver");
}
}
if ((bus != null) && (filename != null) && (controllerDevice != null)) {
hddsArray.add(new VmMetaData.HardDisk(controllerDevice, bus, filename));
idDrive = null;
filename = null;
bus = null;
controllerDevice = null;
}
}
}
public ArrayList<VmMetaData.HardDisk> getHdds() {
return hddsArray;
}
public String toString(boolean filtered) {
StringBuilder sb = new StringBuilder(300);
LinkedHashMap<String, TreeMap<String, String>> sortedArray = null;
if (filtered) {
sortedArray = new LinkedHashMap<>();
for (Map.Entry<String, TreeMap<String, String>> entry : entries.entrySet()) {
if ((entry.getKey().equals(NAME.value())) || (entry.getKey().contains(DRIVE.value())) || entry.getKey().contains(DEV.value())) {
sortedArray.put(entry.getKey(), entry.getValue());
}
}
}
for (Map.Entry<String, TreeMap<String, String>> entry : sortedArray == null ? entries.entrySet() : sortedArray.entrySet()) {
String header = entry.getKey();
if (header.contains(DEV.value())) {
header = DEVICE.value();
}
sb.append(header + "\n");
TreeMap<String, String> values = entry.getValue();
for (String key : values.keySet()) {
String value = values.get(key);
sb.append(" " + key + " = " + value + "\n");
}
}
LOGGER.debug(sb);
return sb.toString();
}
public static class Device {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}