summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2015-09-02 20:58:12 +0200
committerSimon Rettberg2015-09-02 20:58:12 +0200
commitf0fa87c6e946e3f48c847a0993d70d398da46c58 (patch)
tree079ca63e931632e8bfbf6ede294f03e4930e6cd3
parent[client] Add vm wrapper skeleton (for local vmx generation) (diff)
downloadtutor-module-f0fa87c6e946e3f48c847a0993d70d398da46c58.tar.gz
tutor-module-f0fa87c6e946e3f48c847a0993d70d398da46c58.tar.xz
tutor-module-f0fa87c6e946e3f48c847a0993d70d398da46c58.zip
[client] Generate VMX on download
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/filetransfer/DownloadTask.java12
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ImageDetailsWindow.java2
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ImageListWindow.java2
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LectureDetailsWindow.java2
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/thrift/ThriftActions.java104
-rw-r--r--dozentenmodul/src/main/java/org/openslx/dozmod/util/VmWrapper.java68
6 files changed, 118 insertions, 72 deletions
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/filetransfer/DownloadTask.java b/dozentenmodul/src/main/java/org/openslx/dozmod/filetransfer/DownloadTask.java
index 713c16c8..ba236c58 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/filetransfer/DownloadTask.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/filetransfer/DownloadTask.java
@@ -134,18 +134,6 @@ public class DownloadTask extends TransferTask {
boolean ret = downloader.download(cb, cb);
if (!ret) {
consecutiveInitFails.incrementAndGet();
- } else {
- // remove the temporary '.partial' marking an incomplete download
- String tmpFilePath = localFile.getAbsolutePath();
- if (tmpFilePath.endsWith(".partial")) {
- // strip the .partial from the filename
- String newFilePath = tmpFilePath.substring(0, tmpFilePath.lastIndexOf(".partial"));
- if (!localFile.renameTo(new File(newFilePath))) {
- // TODO handle
- LOGGER.error("Could not rename '" + tmpFilePath + "' to '" + newFilePath + "'");
- }
- }
-
}
if (cb.current != null) {
chunks.markFailed(cb.current);
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ImageDetailsWindow.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ImageDetailsWindow.java
index 951e6532..ac0e1790 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ImageDetailsWindow.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ImageDetailsWindow.java
@@ -318,7 +318,7 @@ public class ImageDetailsWindow extends ImageDetailsWindowLayout implements UiFe
return;
}
ThriftActions.initDownload(JOptionPane.getFrameForComponent(this), selected.versionId,
- image.imageName, image.virtId, selected.fileSize, null);
+ image.imageName, image.virtId, image.osId, selected.fileSize, null);
}
/**
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ImageListWindow.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ImageListWindow.java
index 08dc9279..4a97080c 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ImageListWindow.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/ImageListWindow.java
@@ -272,7 +272,7 @@ public class ImageListWindow extends ImageListWindowLayout implements DownloadCa
return;
downloadButton.setEnabled(false);
ThriftActions.initDownload(JOptionPane.getFrameForComponent(this), image.latestVersionId,
- image.imageName, image.virtId, image.fileSize, this);
+ image.imageName, image.virtId, image.osId, image.fileSize, this);
}
/**
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LectureDetailsWindow.java b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LectureDetailsWindow.java
index 551f1cd3..fa9de2a6 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LectureDetailsWindow.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LectureDetailsWindow.java
@@ -351,7 +351,7 @@ public class LectureDetailsWindow extends LectureDetailsWindowLayout implements
return;
}
ThriftActions.initDownload(JOptionPane.getFrameForComponent(this), lecture.imageVersionId,
- image.imageName, image.virtId, versionSize, new DownloadCallback() {
+ image.imageName, image.virtId, image.osId, versionSize, new DownloadCallback() {
@Override
public void downloadInitialized(boolean success) {
if (!success) {
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/ThriftActions.java b/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/ThriftActions.java
index dc1ce2df..6c1d1a58 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/ThriftActions.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/thrift/ThriftActions.java
@@ -27,6 +27,7 @@ import org.openslx.bwlp.thrift.iface.SatelliteServer.Client;
import org.openslx.bwlp.thrift.iface.TAuthorizationException;
import org.openslx.bwlp.thrift.iface.TInvocationException;
import org.openslx.bwlp.thrift.iface.TransferInformation;
+import org.openslx.bwlp.thrift.iface.TransferState;
import org.openslx.bwlp.thrift.iface.UserInfo;
import org.openslx.bwlp.thrift.iface.WhoamiInfo;
import org.openslx.dozmod.App;
@@ -35,6 +36,8 @@ import org.openslx.dozmod.Config.SavedSession;
import org.openslx.dozmod.authentication.Authenticator.AuthenticationData;
import org.openslx.dozmod.filetransfer.AsyncHashGenerator;
import org.openslx.dozmod.filetransfer.DownloadTask;
+import org.openslx.dozmod.filetransfer.TransferEvent;
+import org.openslx.dozmod.filetransfer.TransferEventListener;
import org.openslx.dozmod.filetransfer.UploadTask;
import org.openslx.dozmod.gui.GraphicalCertHandler;
import org.openslx.dozmod.gui.Gui;
@@ -42,11 +45,15 @@ import org.openslx.dozmod.gui.MainWindow;
import org.openslx.dozmod.gui.helper.MessageType;
import org.openslx.dozmod.gui.helper.QFileChooser;
import org.openslx.dozmod.util.FormatHelper;
+import org.openslx.dozmod.util.VmWrapper;
+import org.openslx.dozmod.util.VmWrapper.MetaDataMissingException;
import org.openslx.sat.thrift.version.Version;
import org.openslx.thrifthelper.ThriftManager;
import org.openslx.util.QuickTimer;
import org.openslx.util.QuickTimer.Task;
import org.openslx.util.Util;
+import org.openslx.util.vm.DiskImage;
+import org.openslx.util.vm.DiskImage.UnknownImageFormatException;
public class ThriftActions {
@@ -382,7 +389,7 @@ public class ThriftActions {
* the GUI
*/
public static void initDownload(final Frame frame, final String imageVersionId, final String imageName,
- final String virtualizerId, final long imageSize, final DownloadCallback callback) {
+ final String virtualizerId, final int osId, final long imageSize, final DownloadCallback callback) {
// TODO: Return value? Callback?
QFileChooser fc = new QFileChooser(Config.getDownloadPath(), true);
fc.setDialogTitle("Bitte wählen Sie einen Speicherort");
@@ -396,10 +403,11 @@ public class ThriftActions {
final File destDir = new File(selected, generateDirname(imageName, imageVersionId));
destDir.getAbsoluteFile().mkdirs();
- final File diskFile = new File(destDir.getAbsolutePath(), generateFilename(imageName, virtualizerId));
+ final File tmpDiskFile = new File(destDir.getAbsolutePath(), VmWrapper.generateFilename(imageName,
+ null) + ".part");
- if (diskFile.exists()) {
- boolean ret = Gui.showMessageBox(frame, "Datei '" + diskFile.getAbsolutePath()
+ if (tmpDiskFile.exists()) {
+ boolean ret = Gui.showMessageBox(frame, "Datei '" + tmpDiskFile.getAbsolutePath()
+ "' existiert bereits, wollen Sie sie überschreiben?", MessageType.QUESTION_YESNO,
LOGGER, null);
if (!ret) {
@@ -409,7 +417,7 @@ public class ThriftActions {
return;
}
// delete it
- if (!diskFile.delete() && diskFile.exists()) {
+ if (!tmpDiskFile.delete() && tmpDiskFile.exists()) {
Gui.showMessageBox(frame, "Datei konnte nicht überschrieben werden!", MessageType.ERROR,
LOGGER, null);
if (callback != null)
@@ -429,22 +437,10 @@ public class ThriftActions {
return;
}
- // valid path, try to create temp file
- final File tmpFile = new File(diskFile.getAbsolutePath() + ".partial");
- try {
- tmpFile.createNewFile();
- } catch (IOException e) {
- Gui.showMessageBox(frame, "Kann die Datei\n" + tmpFile.getAbsolutePath() + "\nnicht erzeugen.",
- MessageType.ERROR, LOGGER, e);
- if (callback != null)
- callback.downloadInitialized(false);
- return;
- }
-
QuickTimer.scheduleOnce(new Task() {
@Override
public void fire() {
- TransferInformation transInf;
+ final TransferInformation transInf;
try {
transInf = ThriftManager.getSatClient().requestDownload(Session.getSatelliteToken(),
imageVersionId);
@@ -458,7 +454,7 @@ public class ThriftActions {
final DownloadTask dlTask;
try {
dlTask = new DownloadTask(Session.getSatelliteAddress(), transInf.getPlainPort(),
- transInf.getToken(), tmpFile, imageSize, null);
+ transInf.getToken(), tmpDiskFile, imageSize, null);
} catch (FileNotFoundException e) {
Gui.asyncMessageBox(
"Konnte Download nicht vorbereiten: Der gewählte Zielort ist nicht beschreibbar",
@@ -467,15 +463,58 @@ public class ThriftActions {
callback.downloadInitialized(false);
return;
}
- new Thread(dlTask).start();
+
+ dlTask.addListener(new TransferEventListener() {
+ @Override
+ public void update(TransferEvent event) {
+ if (event.state != TransferState.FINISHED)
+ return;
+ DiskImage diskImage = null;
+ String ext = virtualizerId;
+ try {
+ diskImage = new DiskImage(tmpDiskFile);
+ } catch (IOException | UnknownImageFormatException e) {
+ LOGGER.warn("Could not open downloaded image for analyze step", e);
+ }
+ if (diskImage != null) {
+ if (diskImage.format != null) {
+ ext = diskImage.format.extension;
+ }
+ if (diskImage.isCompressed) {
+ Gui.asyncMessageBox("Die heruntergeladene VM '" + imageName + "' ist ein"
+ + "\nkomprimiertes Abbild. Sie müssen das Abbild dekomprimieren,"
+ + "\nbevor Sie es verändern können."
+ + "\n\n(TODO: Hinweis vmware disk tools)", MessageType.WARNING, null,
+ null); // TODO
+ }
+ }
+ File destImage = new File(destDir.getAbsolutePath(), VmWrapper.generateFilename(
+ imageName, ext));
+ destImage.delete();
+ if (!tmpDiskFile.renameTo(destImage)) {
+ destImage = tmpDiskFile; // Must be Windows...
+ }
+ try {
+ VmWrapper.wrapVm(destImage, imageName, transInf.getMachineDescription(),
+ virtualizerId, osId);
+ } catch (MetaDataMissingException | IOException e) {
+ Gui.asyncMessageBox(
+ "Zur heruntergeladenen VM konnte keine vmx-Datei angelegt werden."
+ + "\nSie können versuchen, das Abbild manuell in den VMWare-Player zu importieren.",
+ MessageType.WARNING, LOGGER, e);
+ }
+ }
+ });
Gui.asyncExec(new Runnable() {
@Override
public void run() {
- MainWindow.addDownload(imageName, diskFile.getName(), dlTask);
+ MainWindow.addDownload(imageName, tmpDiskFile.getName(), dlTask);
}
});
+ new Thread(dlTask).start();
+
Config.setDownloadPath(destDir.getParentFile().getAbsolutePath());
if (callback != null)
callback.downloadInitialized(true);
@@ -492,29 +531,6 @@ public class ThriftActions {
return fileName;
}
- /**
- * Generates a filename based on the given imageName and with the proper
- * extension depending on the virtualizer
- *
- * @param imageName
- * @param virtualizerId
- * @return the generated name as String
- */
- private static String generateFilename(String imageName, String virtualizerId) {
- String fileName = imageName.replaceAll("[^a-zA-Z0-9_\\.\\-]+", "_");
- if (fileName.length() > 50) {
- fileName = fileName.substring(0, 50);
- }
- if ("vmware".equals(virtualizerId)) {
- fileName += ".vmdk";
- } else if ("virtualbox".equals(virtualizerId)) {
- fileName += ".vdi";
- } else {
- fileName += ".img";
- }
- return fileName;
- }
-
/* *******************************************************************************
*
* IMAGE METADATA
diff --git a/dozentenmodul/src/main/java/org/openslx/dozmod/util/VmWrapper.java b/dozentenmodul/src/main/java/org/openslx/dozmod/util/VmWrapper.java
index dcd5ce01..3663a0ad 100644
--- a/dozentenmodul/src/main/java/org/openslx/dozmod/util/VmWrapper.java
+++ b/dozentenmodul/src/main/java/org/openslx/dozmod/util/VmWrapper.java
@@ -1,34 +1,76 @@
package org.openslx.dozmod.util;
import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
+import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;
import org.openslx.bwlp.thrift.iface.OperatingSystem;
-import org.openslx.bwlp.thrift.iface.Virtualizer;
import org.openslx.dozmod.thrift.cache.MetaDataCache;
-import org.openslx.util.vm.DiskImage;
-import org.openslx.util.vm.DiskImage.UnknownImageFormatException;
import org.openslx.util.vm.VmwareMetaData;
public class VmWrapper {
private static final Logger LOGGER = Logger.getLogger(VmWrapper.class);
- public static void wrapVm(File diskFile, byte[] machineDescription, Virtualizer virtualizer,
- OperatingSystem os) throws MetaDataMissingException {
- VmwareMetaData vmwareConfig = new VmwareMetaData(MetaDataCache.getOperatingSystems(),
- machineDescription, machineDescription.length);
+ public static void wrapVm(File diskFile, String imageName, byte[] machineDescription,
+ String virtualizerId, int osId) throws MetaDataMissingException, IOException {
+ // TODO This is very vmware specific, but should support others too some day
+ if (!diskFile.exists())
+ throw new FileNotFoundException("Disk file " + diskFile.getAbsolutePath() + " does not exist");
+ // Handle machine description to generate *.vmx
+ VmwareMetaData vmwareConfig = null;
+ if (machineDescription == null) {
+ // TODO: Generate fallback vmx
+ return;
+ } else {
+ vmwareConfig = new VmwareMetaData(MetaDataCache.getOperatingSystems(), machineDescription,
+ machineDescription.length);
+ }
+ // Append disk & NAT
if (!vmwareConfig.addEthernetNat() || !vmwareConfig.addHddTemplate(diskFile.getName())) {
throw new MetaDataMissingException();
}
- DiskImage diskImage;
- try {
- diskImage = new DiskImage(diskFile);
- } catch (IOException | UnknownImageFormatException e) {
- LOGGER.debug("Cannot open disk file '" + diskFile.getName() + "' for reading", e);
- diskImage = null;
+ // The guestOS should be in the vmx, but the user could have changed it by editing
+ // the image via the GUI. Those changes are not written back to the stored vmx
+ if (virtualizerId != null && osId != 0) {
+ OperatingSystem os = MetaDataCache.getOsById(osId);
+ if (os != null && os.virtualizerOsId != null) {
+ String virtOsId = os.virtualizerOsId.get(virtualizerId);
+ if (virtOsId != null) {
+ vmwareConfig.setOs(virtOsId);
+ }
+ }
+ }
+ File vmxFile = new File(diskFile.getAbsolutePath() + ".vmx");
+ vmxFile.delete();
+ FileUtils.writeByteArrayToFile(vmxFile, vmwareConfig.getFilteredDefinitionArray());
+ }
+
+ /**
+ * Generates a filename based on the given imageName and with the proper
+ * extension depending on the virtualizer
+ *
+ * @param imageName
+ * @param virtualizerId
+ * @return the generated name as String
+ */
+ public static String generateFilename(String imageName, String virtualizerId) {
+ String fileName = imageName.replaceAll("[^a-zA-Z0-9_\\.\\-]+", "_");
+ if (fileName.length() > 50) {
+ fileName = fileName.substring(0, 50);
+ }
+ if (virtualizerId == null) {
+ fileName += ".img";
+ } else if ("vmware".equals(virtualizerId)) {
+ fileName += ".vmdk";
+ } else if ("virtualbox".equals(virtualizerId)) {
+ fileName += ".vdi";
+ } else {
+ fileName += "." + virtualizerId;
}
+ return fileName;
}
public static class MetaDataMissingException extends Exception {