package org.openslx.dozmod.gui.wizard.page; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.List; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.filechooser.FileNameExtensionFilter; import org.apache.log4j.Logger; import org.openslx.bwlp.thrift.iface.ImageDetailsRead; import org.openslx.bwlp.thrift.iface.Virtualizer; import org.openslx.dozmod.Branding; import org.openslx.dozmod.Config; import org.openslx.dozmod.gui.Gui; import org.openslx.dozmod.gui.helper.MessageType; import org.openslx.dozmod.gui.helper.QFileChooser; import org.openslx.dozmod.gui.wizard.Wizard; import org.openslx.dozmod.gui.wizard.layout.ImageUploadPageLayout; import org.openslx.dozmod.state.UploadWizardState; import org.openslx.dozmod.thrift.Session; import org.openslx.dozmod.thrift.ThriftActions; import org.openslx.dozmod.thrift.ThriftError; import org.openslx.dozmod.thrift.UploadInitiator; import org.openslx.dozmod.thrift.WrappedException; import org.openslx.dozmod.thrift.cache.MetaDataCache; import org.openslx.sat.thrift.version.Feature; import org.openslx.thrifthelper.TConst; import org.openslx.util.vm.DiskImage; import org.openslx.util.vm.DiskImage.UnknownImageFormatException; import org.openslx.util.vm.VmMetaData; import org.openslx.util.vm.VmMetaData.HardDisk; import org.openslx.util.vm.VmwareMetaData; /** * Page for uploading a new image. */ @SuppressWarnings("serial") public class ImageUploadPage extends ImageUploadPageLayout { private final static Logger LOGGER = Logger.getLogger(ImageUploadPage.class); private UploadWizardState state; private String lastDetectedName = null; private ImageDetailsRead existingImage = null; private final FileNameExtensionFilter allSupportedFilter; private final FileNameExtensionFilter vmxFilter = new FileNameExtensionFilter("VMware Virtual Machine", "vmx"); private final FileNameExtensionFilter vboxFilter = new FileNameExtensionFilter( "VirtualBox Virtual Machine", "vbox"); public ImageUploadPage(Wizard wizard, UploadWizardState uploadWizardState, final ImageDetailsRead existingImage) { super(wizard); setPageComplete(false); this.canComeBack = false; this.state = uploadWizardState; this.existingImage = existingImage; lblImageName.setVisible(existingImage == null); txtImageName.setVisible(existingImage == null); txtInfoText.setVisible(existingImage == null); // show the licensed software checkbox since we are uploading new version chkLicenseRestricted.setVisible(existingImage != null); chkLicenseRestricted.setSelected(existingImage != null); // TODO selected by default? // Browse for *.vmx btnBrowseForImage.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { browseForVm(); } }); txtImageFile.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 1) browseForVm(); } }); // initialize allSupportedFilter depending on whether multiple hypervisors // are supported or not if (Session.hasFeature(Feature.MULTIPLE_HYPERVISORS)) { allSupportedFilter = new FileNameExtensionFilter("All Supported", "vmx", "vbox"); } else { allSupportedFilter = new FileNameExtensionFilter("All Supported", "vmx"); } btnBrowseForImage.requestFocus(); } private void browseForVm() { QFileChooser fc = new QFileChooser(Config.getUploadPath(), false); fc.setAcceptAllFileFilterUsed(false); fc.addChoosableFileFilter(vmxFilter); if (Session.hasFeature(Feature.MULTIPLE_HYPERVISORS)) { fc.addChoosableFileFilter(vboxFilter); } fc.addChoosableFileFilter(allSupportedFilter); fc.setFileFilter(allSupportedFilter); // differentiate between existing and new VMs if (existingImage != null) { if (existingImage.virtId.equals(TConst.VIRT_VMWARE)) { fc.setFileFilter(vmxFilter); } else if (existingImage.virtId.equals(TConst.VIRT_VIRTUALBOX)) { fc.setFileFilter(vboxFilter); } } int action = fc.showOpenDialog(getDialog()); File file = fc.getSelectedFile(); if (action != JFileChooser.APPROVE_OPTION || file == null) return; vmSelected(file.getAbsoluteFile()); } private void vmSelected(File file) { Config.setUploadPath(file.getParent()); txtImageFile.setText(""); txtImageName.setText(""); try { // gets the metadata object of the selected VM depending on its type state.meta = VmMetaData.getInstance(MetaDataCache.getOperatingSystems(), file); } catch (IOException e) { Gui.showMessageBox(this, "Konnte " + file.getPath() + " nicht lesen", MessageType.ERROR, LOGGER, e); setPageComplete(false); return; } if (state.meta == null || state.meta.getDisplayName() == null) { setErrorMessage("Ungültige Konfigurationsdatei ausgewählt!"); setPageComplete(false); return; } final String fileformat = state.meta.getVirtualizer().virtName; // bail if multiple hypervisors are not supported if (!(state.meta instanceof VmwareMetaData) && !Session.hasFeature(Feature.MULTIPLE_HYPERVISORS)) { setErrorMessage("Der Hypervisor der gewählten VM (" + fileformat + ") wird vom aktuellen Satellitenserver nicht unterstützt."); setPageComplete(false); return; } // check if the user somehow changed the type of the VM if (existingImage != null && !existingImage.virtId.equals(state.meta.getVirtualizer().virtId)) { Virtualizer existingImageVirtualizer = MetaDataCache.getVirtualizerById(existingImage.virtId); String existingImageVirtualizerName = ""; if (existingImageVirtualizer != null) existingImageVirtualizerName = existingImageVirtualizer.virtName; setErrorMessage("Neue Versionen müssen vom Typ " + existingImageVirtualizerName + " sein."); setPageComplete(false); return; } List hdds = state.meta.getHdds(); if (hdds.size() == 0 || hdds.get(0).diskImage == null) { setErrorMessage("Die gewählte " + fileformat + "-Datei enthält keine virtuelle Festplatte!"); setPageComplete(false); return; } if (hdds.size() > 1) { setErrorMessage( "Die gewählte " + fileformat + "-Datei enthält mehr als eine virtuelle Festplatte!"); setPageComplete(false); return; // Allow to continue!? } // now check the disk files File vmDiskFileInfo = new File(hdds.get(0).diskImage); if (!vmDiskFileInfo.isAbsolute()) { // it's relative, compose path using the vmx location File vmBaseDirectory = file.getParentFile(); vmDiskFileInfo = new File(vmBaseDirectory, hdds.get(0).diskImage); } DiskImage diskImage; try { diskImage = new DiskImage(vmDiskFileInfo); } catch (FileNotFoundException e) { setErrorMessage("'" + vmDiskFileInfo.getName() + "' kann nicht gefunden werden!"); setPageComplete(false); return; } catch (IOException e) { setErrorMessage("'" + vmDiskFileInfo.getName() + "' kann nicht gelesen werden!"); setPageComplete(false); return; } catch (UnknownImageFormatException e) { setErrorMessage("'" + vmDiskFileInfo.getName() + "' hat unbekanntes Dateiformat!"); LOGGER.debug("Selected disk file has unknown format.", e); setPageComplete(false); return; } // Warn user about snapshot if (diskImage.isSnapshot || state.meta.isMachineSnapshot()) { Gui.showMessageBox("Von der ausgewählten VM wurde ein Snapshot erstellt. In diesem Zustand kann\n" + "die VM leider nicht ins " + Branding.getServiceName() + "-System geladen werden. Bitte konsolidieren Sie zunächst\n" + "den Snapshot und versuchen Sie es erneut.", MessageType.WARNING, null, null); setErrorMessage("Die gewählte VM befindet sich im Snapshot-Zustand."); setPageComplete(false); return; } if (!diskImage.isStandalone) { Gui.showMessageBox("Die zu dieser VM gehörige Virtuelle Festplatte ist im Format '" + diskImage.subFormat + "'.\n" + "Dieses Format wird von " + Branding.getApplicationName() + " nicht unterstützt. Bitte konvertieren Sie die VM\n" + "in das Format 'monolithicSparse'.", MessageType.WARNING, null, null); setErrorMessage("Die VMDK Datei der VM hat ein inkompatibles Format"); setPageComplete(false); return; } // everything seems fine so far state.diskFile = vmDiskFileInfo; state.descriptionFile = file; if (existingImage == null) { // User didn't enter a name yet or didn't change it -> set String imageName = txtImageName.getText(); if (imageName.isEmpty() || imageName.equals(lastDetectedName)) { txtImageName.setText(state.meta.getDisplayName()); } } lastDetectedName = state.meta.getDisplayName(); state.detectedOs = state.meta.getOs(); txtImageFile.setText(file.getAbsolutePath()); // let the user know the upload is ready setErrorMessage(null); setDescription("Sie können jetzt den Upload starten."); setPageComplete(true); } private boolean askCancelLockFile(String... lockFiles) { for (String lockFile : lockFiles) { File file = new File(lockFile); if (!file.exists()) continue; return !Gui.showMessageBox(this, "Die gewählte VM scheint noch in Verwendung zu sein. Bitte fahren Sie die VM\n" + "vor dem Hochladen herunter und schließen Sie den VMware Player, ansonsten\n" + "kann die VM nach dem Hochladen beschädigt sein.\n\n" + "Möchten Sie diese Warnung ignorieren und trotzdem fortfahren?\n" + "(Sie sollten sich sicher sein, was sie tun, wenn Sie hier 'Ja' wählen)", MessageType.QUESTION_YESNO, null, null); } return false; } /** * This function starts the image creation process. It is triggered by the * "Next" button. * * Depending on the state, it will first try to get a UUID for the new image * by calling createImage() of the thrift API. If a UUID is received, it * will request an upload with requestImageVersionUpload(). If granted, it * will finally start a thread for the UploadTask. * * Then a callback to the Gui is executed where we can process the upload * state and give the user feedback about it. * */ @Override protected boolean wantNextOrFinish() { // Check for vmware player lock files - warn user if found, might corrupt upload if (askCancelLockFile(state.descriptionFile.getAbsolutePath() + ".lck", state.diskFile.getAbsolutePath() + ".lck")) { setErrorMessage("Die gewählte VM wird noch verwendet"); return false; } // are we creating a new image? then either: // get the image name either auto filled by VmwareMetaData or by user // get the image name from the image we are uploading a new version of state.name = existingImage != null ? existingImage.getImageName() : txtImageName.getText(); // -- create image to get uuid -- if (existingImage == null) { if (state.uuid == null) { state.uuid = ThriftActions.createImage(JOptionPane.getFrameForComponent(this), state.name); if (state.uuid == null) return false; txtImageName.setEnabled(false); btnBrowseForImage.setEnabled(false); txtImageFile.setEnabled(false); } } else { state.uuid = existingImage.getImageBaseId(); } // Create upload initiator that will manage requesting a token, hashing the // file, connecting for upload... if (state.upload == null) { try { state.upload = new UploadInitiator(state.uuid, state.diskFile, state.meta.getFilteredDefinition()); } catch (WrappedException e) { ThriftError.showMessage(this, LOGGER, e.exception, e.displayMessage); return false; } catch (IOException e) { Gui.showMessageBox(this, "Upload-Initialisierung fehlgeschlagen", MessageType.ERROR, LOGGER, e); return false; } } // Start the hash check now state.upload.startHashing(); return true; } }