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<WizardPage> 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<WizardPage>();
}
}
@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();
}
}