diff options
author | Simon Rettberg | 2015-09-02 20:58:12 +0200 |
---|---|---|
committer | Simon Rettberg | 2015-09-02 20:58:12 +0200 |
commit | f0fa87c6e946e3f48c847a0993d70d398da46c58 (patch) | |
tree | 079ca63e931632e8bfbf6ede294f03e4930e6cd3 | |
parent | [client] Add vm wrapper skeleton (for local vmx generation) (diff) | |
download | tutor-module-f0fa87c6e946e3f48c847a0993d70d398da46c58.tar.gz tutor-module-f0fa87c6e946e3f48c847a0993d70d398da46c58.tar.xz tutor-module-f0fa87c6e946e3f48c847a0993d70d398da46c58.zip |
[client] Generate VMX on download
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 { |