summaryrefslogblamecommitdiffstats
path: root/dozentenmodul/src/main/java/org/openslx/dozmod/gui/wizard/page/ImageUploadPage.java
blob: 44ae307f7c57dbe66e1bfc2d3b07acad13ae637a (plain) (tree)
1
2
3
4
5
6
7
8
9

                                           



                                     
                    
                                     
                              
                           
                           
                      
 
                                
                               

                                                       
                                           

                                           
                                                      
                                                 
                                   
                                 
                                  
                                          
                                                 
                                                  
                                            
                                                                  
                                                  
                                         
                                               


                                                  
                                                     
                                            
                                              
                                       
                                                                                  


                                                                                                   


                                                             

                                                                                     

                                                                                      
 


                                  

                                                            




                                                                           
                                                                                         
 
                                        
                                               
                                                      
 
                                                                 

                                                                                                         
                                                                                       
                                                                                                                 
                                                                                       
                                                                                                     
 



                                                                                      
 

                                                                                  
                              
                                       
                                         
                                               
                                                   
 

                                                               
                                                              
                                                                                         

                                                                                                     
 
                                   
                                                                          
                                 
                                                                    
                                              
                         
                   
 
                                                                  
                                 

                                                                

                                                      
                   


                                                                                          




                                                                                                  
                        


                                                                                              
                 
                                                 
         
 
                                    
                                                                                  

                                                     
                                                     
                                                     

                                                                       
                                                              
                 
                                                              
                                                     

                                                             
                                                                              
                                                            
                                                                                         
                                                             

                                                                                   
                         
                 
 

                                                            
 































                                                                                                                                             
                                 
                         

                 
                                                                          
                               
                                                   
         
 


                                                                      

                                                                                                          
                                        

                                                     
                                                                               





                                                                        
                                            
                                                       

                                         


                                                                                                     


                                               
 
                     
                                                                                            
                                                                                                                                        
                                         


                                                                                                                             


                                               
 

                                                                                
                                                                                                                                            

                                                                                                                           
                                                                                                                      



                                               
                                                                                                     
                                                                 
                                                                                                                                                      
                                                                                                                         
                                                          


                                               
                                                                       
                                                                                                                                 



                                                                                                                      

                                                                                                                


                                               
 
                                                                           
                                                                        
                                                                                                                           



                                               
                                        
                                                                                                                                    

                                               
                                              
                 
 


                                                                      
                                                                             

                                                                                          
                 
                

                                                    


                                                                                   

                                                                         
                                                           
                                                   

                                                                                                                    


                                               

                                                                                                                       

                                               
                                                


                                                                                                                            
                                                                                  

                                               
                 

                                                                                                           

                                                                                                           
                                                                                    





                                                                                                                                      
 
                                           
                                                                                            

                                                                                                               
                                                                                                                      


                                               
                                             
                                           
                                                                                                                                              
                                                                         
                                                                                                                        



                                               











                                                                                                                                                

                                                
                                             
 
                                            
                                                                                  
                                                                  
                                                                                        
                                                                                                  
                         
                 

                                                                               
                                                             
                                                        
                                      
                                                                                          
                                      

         




                                                                
                                                                                                                         




                                                                                
           
                                                                                  
                         
           



                                                                                       
           

                                                                                       
           
           

                                              
 


                                                                                                
                                                                                                                   


                                     


                                                                                      
                                                                                                           

                                                 
                                            



                                                                                                                           


                                                                    


                                                                    
                 

                                                                                           

                                           
                                                                                              
                                                                                                                           



                                                                                                     

                                                                                                                       
                                                                              
                                             
                         
                 

                                            
                            
 
         



                                      

                                                                                               


                                                                   
 
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.FilenameFilter;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.List;

import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileNameExtensionFilter;

import org.apache.commons.io.FilenameUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.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.I18n;
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.dozmod.util.FormatHelper;
import org.openslx.sat.thrift.version.Feature;
import org.openslx.thrifthelper.TConst;
import org.openslx.virtualization.configuration.VirtualizationConfigurationVmware;
import org.openslx.virtualization.configuration.data.ConfigurationDataDozModClientToDozModServer;
import org.openslx.virtualization.configuration.logic.ConfigurationLogicDozModClientToDozModServer;
import org.openslx.virtualization.configuration.transformation.TransformationException;
import org.openslx.virtualization.disk.DiskImage;
import org.openslx.virtualization.disk.DiskImageException;
import org.openslx.virtualization.disk.DiskImage.ImageFormat;
import org.openslx.virtualization.configuration.VirtualizationConfiguration;
import org.openslx.virtualization.configuration.VirtualizationConfiguration.HardDisk;
import org.openslx.virtualization.configuration.VirtualizationConfigurationQemu;
import org.openslx.virtualization.configuration.VirtualizationConfigurationVirtualBox;

/**
 * Page for uploading a new image.
 */
public class ImageUploadPage extends ImageUploadPageLayout {

	/**
	 * Version for serialization.
	 */
	private static final long serialVersionUID = -2974001512014608455L;

	private final static Logger LOGGER = LogManager.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", VirtualizationConfigurationVmware.FILE_NAME_EXTENSION);
	private final FileNameExtensionFilter vboxFilter = new FileNameExtensionFilter(
			"VirtualBox Virtual Machine", VirtualizationConfigurationVirtualBox.FILE_NAME_EXTENSION);
	private final FileNameExtensionFilter qemuFilter = new FileNameExtensionFilter(
			"QEMU Virtual Machine", VirtualizationConfigurationQemu.FILE_NAME_EXTENSION);

	private final FileNameExtensionFilter ovfFilter = new FileNameExtensionFilter(
			"OVF Virtual Machine Format", "ovf");
	private final FileNameExtensionFilter ovaFilter = new FileNameExtensionFilter(
			"OVA Virtual Machine Format", "ova");

	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",
					VirtualizationConfigurationVmware.FILE_NAME_EXTENSION,
					VirtualizationConfigurationVirtualBox.FILE_NAME_EXTENSION,
					VirtualizationConfigurationQemu.FILE_NAME_EXTENSION,
					"ovf", "ova");
		} else {
			allSupportedFilter = new FileNameExtensionFilter("All Supported", 
					VirtualizationConfigurationVmware.FILE_NAME_EXTENSION,
					"ovf", "ova");
		}
		btnBrowseForImage.requestFocus();
	}

	private void browseForVm() {
		QFileChooser fc = new QFileChooser(Config.getUploadPath(), false);
		fc.setAcceptAllFileFilterUsed(false);
		fc.addChoosableFileFilter(vmxFilter);
		fc.addChoosableFileFilter(ovfFilter);
		fc.addChoosableFileFilter(ovaFilter);
		if (Session.hasFeature(Feature.MULTIPLE_HYPERVISORS)) {
			fc.addChoosableFileFilter(vboxFilter);
			fc.addChoosableFileFilter(qemuFilter);
		}
		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);
			} else if (existingImage.virtId.equals(TConst.VIRT_QEMU)) {
				fc.setFileFilter(qemuFilter);
			}
		}

		int action = fc.showOpenDialog(getDialog());
		File file = fc.getSelectedFile();

		if (action == JFileChooser.APPROVE_OPTION) {
			// If the vm was exported via vmware fusion on macos it might be
			// a vmwarevm which is a directory containing the vm files within.
			if (file != null && file.isDirectory()) {
				try {
					File[] vmxfiles = file.listFiles(new FilenameFilter() {
						public boolean accept(File dir, String filename) {
							return filename.endsWith(".vmx");
						}
					});

					// There should be only one vmx file in the directory
					if (vmxfiles.length < 1) {
						// TODO translate
						Gui.showMessageBox(this,
								I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.noVmxInDir"),
								MessageType.ERROR, LOGGER, null);
						return;
					} else if (vmxfiles.length >= 2) {
						Gui.showMessageBox(this,
								I18n.PAGE.getString(
										"ImageUpload.WizardPage.errorMessage.multipleVmxInDirFound"),
								MessageType.ERROR, LOGGER, null);
					}
					if (vmxfiles[0] != null && vmxfiles[0].isFile())
						file = vmxfiles[0];
				} catch (Exception e) {
					Gui.showMessageBox(this,
							I18n.PAGE.getString(
									"ImageUpload.WizardPage.errorMessage.errorWhileSearchingForVmx"),
							MessageType.ERROR, LOGGER, e);
					return;
				}
			}
		}

		if (action != JFileChooser.APPROVE_OPTION || file == null)
			return;
		vmSelected(file.getAbsoluteFile());
	}

	private void askForConversion(File file) {
		int dialogButton = JOptionPane.YES_NO_OPTION;
		int dialogResult = JOptionPane.showConfirmDialog(this,
				I18n.PAGE.getString("ImageUpload.WizardPage.dialog.OvfOvaDetected"),
				I18n.PAGE.getString("ImageUpload.WizardPage.dialog.title"), dialogButton);
		if (dialogResult == 0) {
			state.descriptionFile = file;
			setErrorMessage(null);
			setDescription("Bitte starten Sie die Konvertierung.");
			wizard.showOutOfOrderPage(state.conversionPage);
		} else {
			setPageComplete(false);
		}
	}

	private void vmSelected(File file) {
		Config.setUploadPath(file.getParent());
		txtImageFile.setText("");
		txtImageName.setText("");
		// ask to convert OVA and OVF files
		String fileExtension = FilenameUtils.getExtension(file.getAbsolutePath());
		if (fileExtension.equalsIgnoreCase("ova") || fileExtension.equalsIgnoreCase("ovf")) {
			askForConversion(file);
			return;
		}

		try {
			// gets the metadata object of the selected VM depending on its type
			state.virtualizationConfig = VirtualizationConfiguration.getInstance(MetaDataCache.getOperatingSystems(), file);
		} catch (IOException e) {
			Gui.showMessageBox(this,
					I18n.PAGE.getString("ImageUpload.Message.error.couldNotGetMetadata", file.getPath()),
					MessageType.ERROR, LOGGER, e);
			setPageComplete(false);
			return;
		}

		try {
			// transforms (filters) the virtualization configuration
			final ConfigurationLogicDozModClientToDozModServer uploadLogic = new ConfigurationLogicDozModClientToDozModServer();
			uploadLogic.apply( state.virtualizationConfig, new ConfigurationDataDozModClientToDozModServer() );
		} catch (TransformationException e) {
			setErrorMessage(I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.invalidConfigFile"));
			setPageComplete(false);
			return;
		}

		final String virtualizerName = state.virtualizationConfig.getVirtualizer().getName();
		// bail if multiple hypervisors are not supported
		if (!(state.virtualizationConfig instanceof VirtualizationConfigurationVmware) && !Session.hasFeature(Feature.MULTIPLE_HYPERVISORS)) {
			setErrorMessage(I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.hypervisorNotSupported",
					virtualizerName));
			setPageComplete(false);
			return;
		}
		// check if the user somehow changed the type of the VM
		if (existingImage != null && !existingImage.virtId.equals(state.virtualizationConfig.getVirtualizer().getId())) {
			Virtualizer existingImageVirtualizer = MetaDataCache.getVirtualizerById(existingImage.virtId);
			String existingImageVirtualizerName = "<error>";
			if (existingImageVirtualizer != null)
				existingImageVirtualizerName = existingImageVirtualizer.virtName;
			setErrorMessage(I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.VMTypeChanged",
					existingImageVirtualizerName));
			setPageComplete(false);
			return;
		}

		List<HardDisk> hdds = state.virtualizationConfig.getHdds();
		if (hdds.size() == 0 || hdds.get(0).diskImage == null) {
			setErrorMessage(I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.noHDD", virtualizerName));
			setPageComplete(false);
			return;
		}
		if (hdds.size() > 1) {
			setErrorMessage(
					I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.moreThanOneHDD", virtualizerName));
			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);
		}
		
		final boolean diskImageIsSnapshot;
		final boolean diskImageIsStandalone;
		final ImageFormat diskFormat;
		
		try (DiskImage diskImage = DiskImage.newInstance(vmDiskFileInfo)) {
			diskImageIsSnapshot = diskImage.isSnapshot();
			diskImageIsStandalone = diskImage.isStandalone();
			diskFormat = diskImage.getFormat();
		} catch (FileNotFoundException e) {
			setErrorMessage(I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.diskImageNotFound",
					vmDiskFileInfo.getName()));
			setPageComplete(false);
			return;
		} catch (IOException e) {
			setErrorMessage(I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.diskImageNotReadable",
					vmDiskFileInfo.getName()));
			setPageComplete(false);
			return;
		} catch (DiskImageException e) {
			setErrorMessage(
					I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.diskImageHasUnknownFormat",
							vmDiskFileInfo.getName()));
			LOGGER.debug("Selected disk file has unknown format.", e);
			setPageComplete(false);
			return;
		}
		
		// check if disk image format is supported by the hypervisor's supported disk image formats
		final List<ImageFormat> supportedImageFormats = state.virtualizationConfig.getVirtualizer()
				.getSupportedImageFormats();
		if (!diskFormat.isSupportedbyVirtualizer( supportedImageFormats )) {
			Gui.showMessageBox(I18n.PAGE.getString("ImageUpload.Message.warning.diskImageNotSupportedByHypervisor",
					Branding.getServiceName()), MessageType.WARNING, null, null);
			setErrorMessage(I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.diskImageNotSupportedByHypervisor"));
			setPageComplete(false);
			return;
		}

		// Warn user about snapshot
		if (diskImageIsSnapshot || state.virtualizationConfig.isMachineSnapshot()) {
			Gui.showMessageBox(I18n.PAGE.getString("ImageUpload.Message.warning.diskImageSnapshot",
					Branding.getServiceName()), MessageType.WARNING, null, null);
			setErrorMessage(I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.diskImageSnapshot"));
			setPageComplete(false);
			return;
		}
		if (!diskImageIsStandalone) {
			Gui.showMessageBox(
					I18n.PAGE.getString("ImageUpload.Message.warning.diskImageStandalone", Branding.getApplicationName()),
					MessageType.WARNING, null, null);
			setErrorMessage(I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.diskImageStandalone"));
			setPageComplete(false);
			return;
		}

		// Check imposed size limit by server
		long maxSize = Session.getSatelliteConfig().vmSizeLimit;
		if (maxSize > 0 && maxSize < vmDiskFileInfo.length()) {
			Gui.showMessageBox(
					I18n.PAGE.getString("ImageUpload.Message.warning.diskImageTooBig",
							FormatHelper.bytes(maxSize, false), FormatHelper.bytes(vmDiskFileInfo.length(), false)),
					MessageType.WARNING, null, null);
			setErrorMessage(I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.diskImageTooBig"));
			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.virtualizationConfig.getDisplayName());
			}
		}
		lastDetectedName = state.virtualizationConfig.getDisplayName();
		state.detectedOs = state.virtualizationConfig.getOs();
		txtImageFile.setText(file.getAbsolutePath());
		// let the user know the upload is ready
		setErrorMessage(null);
		setDescription(I18n.PAGE.getString("ImageUpload.WizardPage.description"));
		setPageComplete(true);
	}

	private boolean askCancelLockFile(String... lockFiles) {
		for (String lockFile : lockFiles) {
			File file = new File(lockFile);
			if (!file.exists())
				continue;
			return !Gui.showMessageBox(this, I18n.PAGE.getString("ImageUpload.Message.yesNo.cancelLockFile"),
					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(I18n.PAGE.getString("ImageUpload.WizardPage.errorMessage.cancelLockFile"));
			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,
						ByteBuffer.wrap(state.virtualizationConfig.getConfigurationAsByteArray()));
			} catch (WrappedException e) {
				ThriftError.showMessage(this, LOGGER, e.exception, e.displayMessage);
				return false;
			} catch (IOException e) {
				Gui.showMessageBox(this,
						I18n.PAGE.getString("ImageUpload.Message.error.uploadInitiatorFailed"),
						MessageType.ERROR, LOGGER, e);
				return false;
			}
		}
		// Start the hash check now
		state.upload.startHashing();
		return true;

	}

	@Override
	protected void onPageEnter() {
		super.onPageEnter();
		// When entering from the conversion page the user probably wants to upload the
		// new vmx file
		if (state.convertedDescriptionFile != null)
			vmSelected(state.convertedDescriptionFile);
	}
}