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

                                           
                                       

                                           
                                                      
                                 
                                  
                                          
                                                 

                                                        
                                            
                                                                      
                                                    
                                                  
                                   
                                                     
                                              
                                                                                  

                     

                                        
                                          



                                     
                           

                               
 
                                                                    
 


                                                                                                       




                                                                          
                                                                                      
 
                                              
                                                     
                                                        
 




                                                                        
                                                                                  
                              
                                                                     
                                   
 
                                    

                                     

                                                               
 


                       
                                                                                   
                                                                                      
                                                            

                              

                                                 
 

                                                                            
                                                                
                                                                       
 

                                                               
                                                                   
                                                              
 
 






                                                                                       
 
                                                               


                       





                                                                          



                                                                        
                             










                                                                               

                                                                                         


                                                   
 











                                                                                       





                                                                                         


                                                                               
                         
                   
 


                                                                              


                         
                                                 

         
                                           





                                                                                  


                                                                                                                


                               


                                                            


                                                 





                                                                                  






                                                                          




                                                                             

                                             
 
                                                       
                                   

         

















                                                                                            
 


                                                     
                                                                                                                    
                                           

         
                                          
 

                                              




                                                                                                                  
                                
                                                                                                 
                                                                                                                

                                             
                                                                                             


                                                                                                                         


                                                                                             
                                                                                                                      


                                             
                                    
                                                                                               
                                                                                                                      






                                                   
                 
 
                                                                                         
                                                                                                           
                                     
                 

                            
 
                                                                                
 
                                                                                                               
                                                                                            
 

                                                                         
                                                                                      
                                                        
                              
                                      

                                                                                                    
                                                               
                              
                                    

                                                                                                        

                                                               
                                    

                                                                         
                              
                 
                                                                        

         


                                                                                  
              



                                                                                       
              

                                                                                       
           
                                                        
                                                                          
 


                                                 
                                                                    
                                                                                                                           







                                                                    
                                                                  
                 






















                                                                                                                                   
                            
         
 


                                                                  
 


                                                                     
                                                                              





                                                          




                                                                         
                                                                                                





                                                          
 
package org.openslx.dozmod.gui.wizard.page;

import org.apache.commons.io.FileUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.openslx.bwlp.thrift.iface.ImageDetailsRead;
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.helper.TextChangeListener;
import org.openslx.dozmod.gui.wizard.Wizard;
import org.openslx.dozmod.gui.wizard.layout.ContainerUploadPageLayout;
import org.openslx.dozmod.model.ContainerDefinition;
import org.openslx.dozmod.state.UploadWizardState;
import org.openslx.dozmod.thrift.*;
import org.openslx.dozmod.thrift.cache.MetaDataCache;
import org.openslx.dozmod.util.ContainerUtils;
import org.openslx.virtualization.configuration.VirtualizationConfigurationDocker;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileFilter;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ContainerUploadPage extends ContainerUploadPageLayout {

	// TODO: Add a Instruction for the new Container-Feature in bwLehrpool.
	// TODO: Add link to instructions for Docker-Intetragtion at https://www.bwlehrpool.de/doku.php

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

	private final Logger LOGGER = LogManager.getLogger(ContainerUploadPage.class);

	private final UploadWizardState state;
	private final ImageDetailsRead existingImage;
	private ContainerDefinition containerDefinition;

	/**
	 * Page for uploading an Container Image
	 *
	 * @param wizard The wizard dialog in which this page is active.
	 */
	public ContainerUploadPage(Wizard wizard, final UploadWizardState state) {
		super(wizard);
		this.containerDefinition = new ContainerDefinition();
		this.state = state;

		canComeBack = false;
		existingImage = null;

		// HACK set dummy os
		state.selectedOs = MetaDataCache.getOsById(18);

		init();
	}

	// This constructor is used in case the user wants do upload a new version.
	public ContainerUploadPage(Wizard wizard, UploadWizardState uploadWizardState,
			ImageDetailsRead imageDetailsRead) {
		super(wizard);

		state = uploadWizardState;
		existingImage = imageDetailsRead;

		containerDefinition = ContainerUtils.getContainerDefinition(
				Session.getSatelliteToken(),
				imageDetailsRead.getImageName(),
				imageDetailsRead.getLatestVersionId());

		lblImageName.setEnabled(existingImage == null);
		txtImageName.setEnabled(existingImage == null);
		txtImageName.setText(existingImage.getImageName());
		txtInfoText.setVisible(existingImage == null);


		state.name = imageDetailsRead.imageName;
		state.defaultPermissions = imageDetailsRead.getDefaultPermissions();
		state.description = imageDetailsRead.getDescription();
		state.detectedOs = MetaDataCache.getOsById(imageDetailsRead.getOsId());
		state.selectedOs = MetaDataCache.getOsById(imageDetailsRead.getOsId());
		state.tags = imageDetailsRead.getTags();
		state.defaultPermissions = imageDetailsRead.getUserPermissions();

		state.uuid = imageDetailsRead.getImageBaseId();
		init();
	}

	public ContainerUploadPage(Wizard wizard, UploadWizardState state,
			ContainerDefinition containerDefinition) {
		this(wizard, state);
		this.containerDefinition = containerDefinition;
	}

	/**
	 * register for each user input control the proper action/method
	 * TODO ugly ... 
	 */
	private void init() {
		this.txtImageFile.addActionListener(new ActionListener() {
			@Override public void actionPerformed(ActionEvent e) {
				browseFile();
			}
		});
		this.btnBrowseForImage.addActionListener(new ActionListener() {
			@Override public void actionPerformed(ActionEvent e) {
				browseFile();
			}
		});

		txtImageName.getDocument().addDocumentListener(new TextChangeListener() {
			@Override public void changed() {
				reactOnUserInput();
			}
		});

		tpInput.addChangeListener(new ChangeListener() {
			@Override public void stateChanged(ChangeEvent e) {
				reactOnUserInput();
			}
		});

		txtGitRepo.getDocument().addDocumentListener(new TextChangeListener() {
			@Override public void changed() {
				reactOnUserInput();
			}
		});

		txtImageRepo.getDocument().addDocumentListener(new TextChangeListener() {
			@Override public void changed() {
				reactOnUserInput();
			}
		});

		this.btnBrowseImageTar.addActionListener(new ActionListener() {
			@Override public void actionPerformed(ActionEvent e) {
				browseImageTarFile();
			}
		});

		this.txtImageTar.addActionListener(new ActionListener() {
			@Override public void actionPerformed(ActionEvent e) {
				browseImageTarFile();
			}
		});

		btnBrowseForImage.requestFocus();
	}

	private void browseImageTarFile() {
		QFileChooser fc = new QFileChooser(Config.getUploadPath(), false);
		fc.setAcceptAllFileFilterUsed(false);
		fc.addChoosableFileFilter(new ContainerImageFileFiler());

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

		if (action != JFileChooser.APPROVE_OPTION || file == null || !ContainerUtils.isValidTar(file)) {
			txtImageTar.setText("");
			return;
		}

		txtImageTar.setText(file.getAbsolutePath());
		Config.setUploadPath(file.getParent());
		reactOnUserInput();
		LOGGER.info("Tar File selected");
	}

	private void browseFile() {

		QFileChooser fc = new QFileChooser(Config.getUploadPath(), false);
		fc.setAcceptAllFileFilterUsed(false);
		fc.addChoosableFileFilter(new DockerfileFilter());

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

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

		txtImageFile.setText(file.getAbsolutePath());

		if (existingImage == null)
			txtImageName.setText(file.getParentFile().getName());
		else
			txtImageName.setText(existingImage.getImageName());

		state.descriptionFile = file;

		Config.setUploadPath(file.getParent());
		reactOnUserInput();
	}

	private File getDummyFile() {
		String configDir = Config.getPath();
		File zeroFile = new File(configDir, "ZERO-FILE");
		// create a temp file with dummy content,
		// because vmchooser relies on an existing image after choosing a lecture.
		// TODO change behavior in vmchooser to allow start lectures without images.
		try {
			if (!zeroFile.exists()) {
				zeroFile.createNewFile();
				FileUtils.writeStringToFile(zeroFile, "ZERO\n", "UTF-8");
			}
		} catch (IOException e) {
			e.printStackTrace();
			LOGGER.error("Could not create a dummy file.", e);
		}
		LOGGER.info("Use dummy file");
		return zeroFile;
	}

	private void reactOnUserInput() {
		boolean completed = checkUserInput();
		if (completed)
			setDescription(I18n.PAGE.getString("ContainerUploadPage.Description.ContainerDefFinished"));
		setPageComplete(completed);
	}

	private boolean checkUserInput() {

		switch (getCurrentContext()) {
		case IMAGE_REPOSITORY:
			if (txtImageRepo.getText() == null || txtImageRepo.getText().isEmpty()) {
				setWarningMessage(I18n.PAGE.getString("ContainerUploadPage.Warning.NoImageRepo"));
				return false;
			}
			break;
		case DOCKERFILE:
			if (txtImageFile.getText() == null || txtImageFile.getText().isEmpty()) {
				setWarningMessage(I18n.PAGE.getString("ContainerUploadPage.Warning.NoReceipt"));
				return false;
			}
			if (!ContainerDefinition.isValidDockerfile(txtImageFile.getText())) {
				setWarningMessage(I18n.PAGE.getString("ContainerUploadPage.Warning.NoValidDockerfiler"));
				return false;
			}
			break;
		case GIT_REPOSITORY:
			if (txtGitRepo.getText() == null || txtGitRepo.getText().isEmpty()) {
				setWarningMessage(I18n.PAGE.getString("ContainerUploadPage.Warning.NoGitRepository"));
				return false;
			}
			break;
		case DOCKER_ARCHIVE:
			if (txtImageTar.getText() == null || txtImageTar.getText().isEmpty()) {
				setWarningMessage(I18n.PAGE.getString("ContainerUploadPage.Warning.NoDockerArchive"));
				return false;
			}
			break;

		default:
			// The case is not provided
			return false;
		}

		if (txtImageName.getText() == null || txtImageName.getText().isEmpty()) {
			setWarningMessage(I18n.PAGE.getString("ContainerUploadPage.Warning.NoProperName"));
			return false;
		}
		return true;
	}

	private VirtualizationConfigurationDocker createVirtualizationConfig() {

		containerDefinition.getContainerMeta().setContainerImageContext(getCurrentContext().ordinal());
		containerDefinition.getContainerMeta().setImageName(txtImageName.getText());

		switch (containerDefinition.getContainerImageContext()) {
		case DOCKERFILE:
			containerDefinition.setContainerRecipe(state.descriptionFile);
			state.diskFile = getDummyFile();
			break;
		case IMAGE_REPOSITORY:
			containerDefinition.getContainerMeta().setImageRepo(txtImageRepo.getText());
			state.diskFile = getDummyFile();
			state.descriptionFile = getDummyFile();
			break;
		case GIT_REPOSITORY:
			containerDefinition.getContainerMeta().setBuildContextUrl(txtGitRepo.getText());
			state.diskFile = getDummyFile();
			state.descriptionFile = getDummyFile();
			break;
		case DOCKER_ARCHIVE:
			state.diskFile = new File(txtImageTar.getText());
			state.descriptionFile = getDummyFile();
			break;
		}
		return containerDefinition.createVirtualizationConfig();
	}

	/**
	 * This function starts the image creation process. It is triggered by the
	 * "Next" button.
	 * <p>
	 * 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.
	 * <p>
	 * 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() {
		state.virtualizationConfig = createVirtualizationConfig();

		// -- create image to get uuid --
		if (existingImage == null) {
			if (state.uuid == null) {
				state.name = txtImageName.getText();
				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();
			state.name = existingImage.getImageName();
		}

		// TODO copy/paste from ImageCreationWizard.wantFinish()
		// Do this only if the user wants to upload a new image version!
		if (existingImage != null) {
			// 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;
	}

	private static class DockerfileFilter extends FileFilter {

		@Override public boolean accept(File f) {

			Pattern p = Pattern.compile("[Dd]ockerfile");
			Matcher m = p.matcher(f.getName());

			return (f.isFile() && m.matches()) || f.isDirectory();
		}

		@Override public String getDescription() {
			return "Dockerfile";
		}
	}

	private static class ContainerImageFileFiler extends FileFilter {

		@Override public boolean accept(File f) {

			return (f.isFile() && f.toString().endsWith(".tar")) || f.isDirectory();
		}

		@Override public String getDescription() {
			return "Container Image (.tar)";
		}
	}
}