package org.openslx.dozmod.gui.wizard; import java.awt.Window; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import javax.swing.JOptionPane; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.thrift.TException; import org.openslx.bwlp.thrift.iface.ImageBaseWrite; import org.openslx.bwlp.thrift.iface.ImageVersionWrite; 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.QuitNotification; import org.openslx.dozmod.gui.helper.UiFeedback; import org.openslx.dozmod.gui.wizard.page.ContainerUploadPage; import org.openslx.dozmod.gui.wizard.page.ImageCustomPermissionPage; import org.openslx.dozmod.gui.wizard.page.ImageMetaDataPage; import org.openslx.dozmod.gui.wizard.page.ImageOvfConversionPage; import org.openslx.dozmod.gui.wizard.page.ImageTypePage; import org.openslx.dozmod.gui.wizard.page.ImageUploadPage; import org.openslx.dozmod.gui.wizard.page.ImageUploadSummaryPage; import org.openslx.dozmod.model.ContainerDefinition; 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.UploadInitiator.GotUploadTokenCallback; import org.openslx.dozmod.thrift.WrappedException; import org.openslx.sat.thrift.version.Feature; import org.openslx.thrifthelper.ThriftManager; import org.openslx.util.QuickTimer; import org.openslx.util.QuickTimer.Task; import org.openslx.virtualization.configuration.VirtualizationConfigurationDocker; public class ImageCreationWizard extends Wizard implements UiFeedback, QuitNotification { /** * Version for serialization. */ private static final long serialVersionUID = -353405234601306343L; private final static Logger LOGGER = LogManager.getLogger(ImageCreationWizard.class); private UploadWizardState state = new UploadWizardState(); private ContainerDefinition containerDefinition = new ContainerDefinition(); private List currentPages = new ArrayList<>(); private boolean baseWritten = false; private boolean permissionsWritten = false; /** * Wizard for creating or editing an image * * @param parent whether to create new or edit existing image */ public ImageCreationWizard(Window parent) { super(parent); state.defaultPermissions = Session.getSatelliteConfig().defaultImagePermissions; if (Session.hasFeature(Feature.DOCKER_CONTAINER)) { addPage(new ImageTypePage(this)); } else { doVmCreation(); } } /** * Adding Pages to the Wizard to create a virtual machine */ public void doVmCreation() { cleanCurrent(); state.imageUploadPage = new ImageUploadPage(this, state, null); currentPages.add(state.imageUploadPage); currentPages.add(new ImageMetaDataPage(this, state)); currentPages.add(new ImageCustomPermissionPage(this, state)); addPages(); state.conversionPage = new ImageOvfConversionPage(this, state); addOutOfOrderPage(state.conversionPage); } /** * Adding Pages to the Wizard to define a docker image */ public void doDockerCreation() { cleanCurrent(); currentPages.add(new ContainerUploadPage(this, state, containerDefinition)); currentPages.add(new ImageMetaDataPage(this, state, containerDefinition)); currentPages.add(new ImageCustomPermissionPage(this, state)); addPages(); } private void addPages() { for (WizardPage i : currentPages) { addPage(i); } } private void cleanCurrent() { if (!currentPages.isEmpty()) { removePages(currentPages); currentPages = new ArrayList(); } } @Override public String getWindowTitle() { return I18n.WIZARD.getString("ImageCreation.Wizard.title"); } @Override public boolean wantFinish() { // TODO copy/paste from ContainerUploadPage.wantNextOrFinish() // In order for settings for a container to be recorded in the ImageMetaDataPage for the ContainerDefinition, // the UploadInitiator was only allowed to be created here. // TODO maybe also for VM-Images this is suitable if (state.virtualizationConfig instanceof VirtualizationConfigurationDocker) { // 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(); } // since we only started the upload and created a "blank" image entry // we can here do all the sanity checks on the fields of UploadWizardState // and react accordingly. // check state if (!isStateValid()) { // TODO: Show what went wrong Gui.showMessageBox(this, I18n.WIZARD.getString("ImageCreation.Message.error.stateInvalid"), MessageType.ERROR, null, null); return false; } // push image base to satellite if (!baseWritten) { try { ThriftActions.updateImageBase(state.uuid, imageBaseWriteFromState()); } catch (TException e) { ThriftError.showMessage(null, LOGGER, e, I18n.WIZARD.getString("ImageCreation.Message.error.baseNotWritten")); return false; } baseWritten = true; } // push permissions to satellite if we have custom permissions if (!permissionsWritten) { if (state.permissionMap != null && !state.permissionMap.isEmpty()) { try { ThriftActions.writeImagePermissions(state.uuid, state.permissionMap); } catch (TException e) { Gui.showMessageBox(this, I18n.WIZARD.getString("ImageCreation.Message.error.permissionsNotWritten"), MessageType.ERROR, null, null); ThriftActions.deleteImageBase(JOptionPane.getFrameForComponent(this), state.uuid); return false; } } permissionsWritten = true; } state.upload.startUpload(new GotUploadTokenCallback() { @Override public void fire() { // push version data try { ThriftActions.updateImageVersion(state.upload.getToken(), new ImageVersionWrite(state.isRestricted)); } catch (TException e) { if (state.isRestricted) { Gui.showMessageBox(null, I18n.WIZARD.getString("ImageCreation.Message.error.updateImageVersionFailed"), MessageType.WARNING, LOGGER, e); } } } }); return true; } @Override public WizardPage performFinish() { return new ImageUploadSummaryPage(this, state, true); } /** * Checks the validity of the state * * @return true if we have all the needed information in the state, false * otherwise */ private boolean isStateValid() { // debug purposes if (state.name == null || state.name.isEmpty()) { LOGGER.error("No name set in state!"); return false; } if (state.description == null || state.description.isEmpty()) { LOGGER.error("No description set in state!"); return false; } if (state.descriptionFile == null) { LOGGER.error("No description file set in state!"); return false; } else { if (!state.descriptionFile.canRead()) { LOGGER.error(state.descriptionFile.getAbsolutePath() + " cannot be read!"); return false; } } if (state.diskFile == null) { LOGGER.error("No disk file set in state!"); return false; } else { if (!state.diskFile.canRead()) { LOGGER.error(state.diskFile.getAbsolutePath() + " cannot be read!"); return false; } } if (state.selectedOs == null) { LOGGER.error("No OS set in state!"); return false; } if (!state.selectedOs.isSetOsId()) { LOGGER.error("OS has no id: " + state.selectedOs.toString()); return false; } if (state.virtualizationConfig == null) { LOGGER.error("No vm meta data set in state!"); return false; } if (state.defaultPermissions == null) { LOGGER.error("No permissions set in state!"); return false; } if (state.shareMode == null) { LOGGER.error("No share mode set in state!"); return false; } if (state.uuid == null) { LOGGER.error("No uuid set in state!"); return false; } return true; } private ImageBaseWrite imageBaseWriteFromState() { // build imageBaseWrite return new ImageBaseWrite(state.name, state.description, state.selectedOs.getOsId(), state.virtualizationConfig.getVirtualizer().getId(), state.isTemplate, state.defaultPermissions, state.shareMode); } @Override protected final void doPrevious() { if (outOfOrderPage != null) { outOfOrderPage = null; returnAfterOutOfOrderPage(state.imageUploadPage, state.conversionPage); } else { super.doPrevious(); } } @Override public final void doNext() { if (outOfOrderPage != null) { outOfOrderPage = null; returnAfterOutOfOrderPage(state.imageUploadPage, state.conversionPage); } else { super.doNext(); } } @Override protected boolean onCancelRequest() { if (state.uuid == null) return true; // Allow closing - nothing in progress boolean confirmed = Gui.showMessageBox(this, I18n.WIZARD.getString("ImageCreation.Message.yesNo.cancelRequest"), MessageType.QUESTION_YESNO, null, null); if (confirmed) { QuickTimer.scheduleOnce(new Task() { @Override public void fire() { if (state.upload != null) { state.upload.cancelError("Cancelled through aborting wizard"); } // As we're creating a new VM, delete base image aswell try { ThriftManager.getSatClient().deleteImageBase(Session.getSatelliteToken(), state.uuid); } catch (TException e) { LOGGER.debug("Error canceling upload on sat: ", e); } } }); } return confirmed; } @Override public boolean wantConfirmQuit() { return state.uuid != null; } @Override public void escapePressed() { doCancel(); } @Override public void onApplicationQuit() { if (state != null && state.upload != null) { state.upload.cancelError("Application quit (via ImageCreationWizard)"); } } @Override protected void doCleanup() { state = null; containerDefinition = null; currentPages.clear(); } }